@songsid/agend 2.2.1 → 2.2.6

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 (455) 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 +34 -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-client-retirement.d.ts +5 -0
  61. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  62. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  63. package/dist/channel/adapters/discord.d.ts +11 -0
  64. package/dist/channel/adapters/discord.js +66 -6
  65. package/dist/channel/adapters/discord.js.map +1 -1
  66. package/dist/channel/adapters/telegram.d.ts +8 -1
  67. package/dist/channel/adapters/telegram.js +74 -4
  68. package/dist/channel/adapters/telegram.js.map +1 -1
  69. package/dist/channel/mcp-tools.js +48 -2
  70. package/dist/channel/mcp-tools.js.map +1 -1
  71. package/dist/channel/types.d.ts +21 -0
  72. package/dist/classic-channel-manager.d.ts +10 -5
  73. package/dist/classic-channel-manager.js +12 -9
  74. package/dist/classic-channel-manager.js.map +1 -1
  75. package/dist/cli.js +142 -110
  76. package/dist/cli.js.map +1 -1
  77. package/dist/config-validator.js +119 -4
  78. package/dist/config-validator.js.map +1 -1
  79. package/dist/daemon.d.ts +8 -0
  80. package/dist/daemon.js +298 -22
  81. package/dist/daemon.js.map +1 -1
  82. package/dist/decision-list.d.ts +25 -0
  83. package/dist/decision-list.js +30 -0
  84. package/dist/decision-list.js.map +1 -0
  85. package/dist/delivery-outbox.d.ts +10 -0
  86. package/dist/delivery-outbox.js +12 -1
  87. package/dist/delivery-outbox.js.map +1 -1
  88. package/dist/fleet-context.d.ts +15 -0
  89. package/dist/fleet-manager.d.ts +514 -12
  90. package/dist/fleet-manager.js +1885 -163
  91. package/dist/fleet-manager.js.map +1 -1
  92. package/dist/fleet-process-handlers.d.ts +18 -0
  93. package/dist/fleet-process-handlers.js +69 -0
  94. package/dist/fleet-process-handlers.js.map +1 -0
  95. package/dist/fleet-traffic.d.ts +74 -0
  96. package/dist/fleet-traffic.js +196 -0
  97. package/dist/fleet-traffic.js.map +1 -0
  98. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  99. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  100. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  101. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  102. package/dist/general-knowledge/skills/web-appearance/SKILL.md +492 -0
  103. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +482 -0
  104. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  105. package/dist/human-delivery-receipts.d.ts +24 -1
  106. package/dist/human-delivery-receipts.js +64 -11
  107. package/dist/human-delivery-receipts.js.map +1 -1
  108. package/dist/instance-avatar.js +3 -0
  109. package/dist/instance-avatar.js.map +1 -1
  110. package/dist/instance-config-impact.js +6 -1
  111. package/dist/instance-config-impact.js.map +1 -1
  112. package/dist/instance-lifecycle.d.ts +2 -0
  113. package/dist/instance-lifecycle.js +20 -10
  114. package/dist/instance-lifecycle.js.map +1 -1
  115. package/dist/instance-names.d.ts +4 -0
  116. package/dist/instance-names.js +12 -0
  117. package/dist/instance-names.js.map +1 -0
  118. package/dist/instructions.d.ts +12 -1
  119. package/dist/instructions.js +13 -2
  120. package/dist/instructions.js.map +1 -1
  121. package/dist/locale.js +118 -10
  122. package/dist/locale.js.map +1 -1
  123. package/dist/login-controller.js +35 -2
  124. package/dist/login-controller.js.map +1 -1
  125. package/dist/ls-attach-resolve.d.ts +95 -0
  126. package/dist/ls-attach-resolve.js +174 -0
  127. package/dist/ls-attach-resolve.js.map +1 -0
  128. package/dist/memory-hogs.d.ts +27 -0
  129. package/dist/memory-hogs.js +124 -0
  130. package/dist/memory-hogs.js.map +1 -0
  131. package/dist/needs-you-hub.d.ts +4 -0
  132. package/dist/needs-you-hub.js +31 -6
  133. package/dist/needs-you-hub.js.map +1 -1
  134. package/dist/needs-you.d.ts +1 -13
  135. package/dist/needs-you.js +3 -37
  136. package/dist/needs-you.js.map +1 -1
  137. package/dist/outbound-handlers.d.ts +15 -0
  138. package/dist/outbound-handlers.js +152 -11
  139. package/dist/outbound-handlers.js.map +1 -1
  140. package/dist/outbound-schemas.d.ts +228 -4
  141. package/dist/outbound-schemas.js +147 -1
  142. package/dist/outbound-schemas.js.map +1 -1
  143. package/dist/public-web-gateway.js +21 -1
  144. package/dist/public-web-gateway.js.map +1 -1
  145. package/dist/public-web-link.d.ts +9 -0
  146. package/dist/public-web-link.js +8 -0
  147. package/dist/public-web-link.js.map +1 -1
  148. package/dist/quickstart-api.d.ts +10 -1
  149. package/dist/quickstart-api.js +12 -4
  150. package/dist/quickstart-api.js.map +1 -1
  151. package/dist/reply-buttons-controller.d.ts +4 -0
  152. package/dist/reply-buttons-controller.js +2 -2
  153. package/dist/reply-buttons-controller.js.map +1 -1
  154. package/dist/repo-worktree-guard.d.ts +36 -0
  155. package/dist/repo-worktree-guard.js +143 -0
  156. package/dist/repo-worktree-guard.js.map +1 -0
  157. package/dist/restart-progress.d.ts +65 -1
  158. package/dist/restart-progress.js +236 -10
  159. package/dist/restart-progress.js.map +1 -1
  160. package/dist/rollout-index.d.ts +5 -0
  161. package/dist/rollout-index.js +26 -5
  162. package/dist/rollout-index.js.map +1 -1
  163. package/dist/scheduler/scheduler.d.ts +70 -1
  164. package/dist/scheduler/scheduler.js +256 -17
  165. package/dist/scheduler/scheduler.js.map +1 -1
  166. package/dist/service-installer.d.ts +2 -1
  167. package/dist/service-installer.js +18 -3
  168. package/dist/service-installer.js.map +1 -1
  169. package/dist/settings-api.d.ts +23 -0
  170. package/dist/settings-api.js +233 -2
  171. package/dist/settings-api.js.map +1 -1
  172. package/dist/settings-change.js +112 -0
  173. package/dist/settings-change.js.map +1 -1
  174. package/dist/settings-effect.js +32 -2
  175. package/dist/settings-effect.js.map +1 -1
  176. package/dist/settings-http-confirmation.js +5 -0
  177. package/dist/settings-http-confirmation.js.map +1 -1
  178. package/dist/tmux-manager.d.ts +5 -0
  179. package/dist/tmux-manager.js +16 -0
  180. package/dist/tmux-manager.js.map +1 -1
  181. package/dist/tool-permissions.d.ts +4 -6
  182. package/dist/tool-permissions.js +100 -2
  183. package/dist/tool-permissions.js.map +1 -1
  184. package/dist/topic-commands.d.ts +17 -7
  185. package/dist/topic-commands.js +39 -21
  186. package/dist/topic-commands.js.map +1 -1
  187. package/dist/topic-link.d.ts +128 -0
  188. package/dist/topic-link.js +269 -0
  189. package/dist/topic-link.js.map +1 -0
  190. package/dist/tunnel/cloudflared.js +37 -2
  191. package/dist/tunnel/cloudflared.js.map +1 -1
  192. package/dist/tunnel/types.d.ts +3 -1
  193. package/dist/tunnel/types.js.map +1 -1
  194. package/dist/types.d.ts +61 -1
  195. package/dist/ui/app-effects.js +245 -0
  196. package/dist/ui/chat-ambient.js +307 -0
  197. package/dist/ui/chat-effect-posters.js +42 -0
  198. package/dist/ui/chat-effects.js +160 -0
  199. package/dist/ui/chat-live-replies.js +58 -0
  200. package/dist/ui/chat-render.js +25 -7
  201. package/dist/ui/chat-store.js +41 -13
  202. package/dist/ui/chat-strings.js +86 -2
  203. package/dist/ui/chat-thread.js +204 -37
  204. package/dist/ui/chat-tour.js +1 -1
  205. package/dist/ui/effect-trial-controller.js +124 -0
  206. package/dist/ui/effect-trial-offer.js +31 -0
  207. package/dist/ui/effect-trial-panel.js +40 -0
  208. package/dist/ui/fleet-cache.js +23 -1
  209. package/dist/ui/fleet-canvas-layout.js +111 -0
  210. package/dist/ui/fleet-canvas.js +525 -0
  211. package/dist/ui/fleet-org.js +27 -12
  212. package/dist/ui/fleet-traffic.js +343 -0
  213. package/dist/ui/fleet-usage.js +401 -0
  214. package/dist/ui/image-lightbox.js +1 -1
  215. package/dist/ui/panel-chat.js +252 -58
  216. package/dist/ui/panel-details.js +20 -6
  217. package/dist/ui/panel-fleet.js +45 -19
  218. package/dist/ui/panel-log.js +6 -6
  219. package/dist/ui/panel-needs.js +3 -3
  220. package/dist/ui/panel-settings.js +58 -13
  221. package/dist/ui/preview-panel.js +25 -9
  222. package/dist/ui/preview.js +3 -2
  223. package/dist/ui/settings-appearance.js +349 -0
  224. package/dist/ui/settings-catalog.js +92 -0
  225. package/dist/ui/settings-dialogs.js +40 -12
  226. package/dist/ui/settings-effects.js +202 -0
  227. package/dist/ui/settings-guests.js +117 -0
  228. package/dist/ui/settings-learn.js +25 -0
  229. package/dist/ui/settings-model.js +15 -6
  230. package/dist/ui/settings-mods.js +271 -0
  231. package/dist/ui/settings-owner-effects.js +80 -0
  232. package/dist/ui/settings-strings.js +335 -10
  233. package/dist/ui/settings-web-authority.js +91 -0
  234. package/dist/ui/shared/agend-auth.js +28 -4
  235. package/dist/ui/shared/agent-widget.js +248 -0
  236. package/dist/ui/shared/app-i18n.js +6 -2
  237. package/dist/ui/shared/app-prefs.js +34 -13
  238. package/dist/ui/shared/app-route.js +42 -2
  239. package/dist/ui/shared/app-session.js +3 -1
  240. package/dist/ui/shared/app-shell.js +119 -41
  241. package/dist/ui/shared/app-store.js +28 -1
  242. package/dist/ui/shared/app-stream.js +14 -7
  243. package/dist/ui/shared/app-themes.js +206 -0
  244. package/dist/ui/shared/app.css +566 -5
  245. package/dist/ui/shared/app.js +23 -10
  246. package/dist/ui/shared/card-strings.js +32 -0
  247. package/dist/ui/shared/effect-app-runtime.js +297 -0
  248. package/dist/ui/shared/effect-baseline.js +64 -0
  249. package/dist/ui/shared/effect-chat-runtime.js +167 -0
  250. package/dist/ui/shared/effect-cursor.js +125 -0
  251. package/dist/ui/shared/effect-frame.js +146 -0
  252. package/dist/ui/shared/effect-geometry.js +137 -0
  253. package/dist/ui/shared/effect-host-style.js +10 -0
  254. package/dist/ui/shared/effect-owner-regions.js +74 -0
  255. package/dist/ui/shared/effect-owner-source.js +122 -0
  256. package/dist/ui/shared/effect-policy.js +151 -0
  257. package/dist/ui/shared/effect-poster-reader.js +98 -0
  258. package/dist/ui/shared/effect-posters.js +117 -0
  259. package/dist/ui/shared/effect-profiler.js +184 -0
  260. package/dist/ui/shared/effect-profiles.js +65 -0
  261. package/dist/ui/shared/effect-registry.js +543 -0
  262. package/dist/ui/shared/effect-runtime-loader.js +234 -0
  263. package/dist/ui/shared/effect-safety.js +153 -0
  264. package/dist/ui/shared/effect-stock-snapshot.js +43 -0
  265. package/dist/ui/shared/effect-stock-trust.js +217 -0
  266. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  267. package/dist/ui/shared/effect-trial-source.js +103 -0
  268. package/dist/ui/shared/effect-trial-stage.js +170 -0
  269. package/dist/ui/shared/effect-trial.css +40 -0
  270. package/dist/ui/shared/fx-motion.js +67 -0
  271. package/dist/ui/shared/header-tools.js +1 -1
  272. package/dist/ui/shared/identity-card.js +273 -0
  273. package/dist/ui/shared/identity-color.js +261 -0
  274. package/dist/ui/shared/instance-nav.js +215 -41
  275. package/dist/ui/shared/owner-css.js +250 -0
  276. package/dist/ui/shared/owner-effect-prefs.js +117 -0
  277. package/dist/ui/shared/panel-view.js +103 -10
  278. package/dist/ui/shared/signin.js +2 -0
  279. package/dist/ui/shared/tokens.css +9 -3
  280. package/dist/ui/shared/ui-dialog.js +1 -1
  281. package/dist/ui/shared/ui-icons.js +3 -0
  282. package/dist/ui/shared/ui-menu.js +1 -1
  283. package/dist/ui/shared/ui-toast.js +1 -1
  284. package/dist/ui/shared/usage-dialog.js +22 -2
  285. package/dist/ui/shared/view-strings.js +98 -2
  286. package/dist/ui/shared/web-authorize.js +151 -0
  287. package/dist/ui/signin.html +1 -0
  288. package/dist/ui/web-terminal/terminal.css +4 -4
  289. package/dist/usage/providers.d.ts +28 -0
  290. package/dist/usage/providers.js +126 -36
  291. package/dist/usage/providers.js.map +1 -1
  292. package/dist/usage-report.d.ts +158 -0
  293. package/dist/usage-report.js +226 -0
  294. package/dist/usage-report.js.map +1 -0
  295. package/dist/usage-rollup.d.ts +51 -0
  296. package/dist/usage-rollup.js +168 -0
  297. package/dist/usage-rollup.js.map +1 -0
  298. package/dist/view-api.d.ts +68 -0
  299. package/dist/view-api.js +249 -8
  300. package/dist/view-api.js.map +1 -1
  301. package/dist/web-ambient.d.ts +72 -0
  302. package/dist/web-ambient.js +161 -0
  303. package/dist/web-ambient.js.map +1 -0
  304. package/dist/web-api.d.ts +117 -7
  305. package/dist/web-api.js +1283 -70
  306. package/dist/web-api.js.map +1 -1
  307. package/dist/web-appearance-limits.d.ts +82 -0
  308. package/dist/web-appearance-limits.js +83 -0
  309. package/dist/web-appearance-limits.js.map +1 -0
  310. package/dist/web-appearance-policy.d.ts +64 -0
  311. package/dist/web-appearance-policy.js +87 -0
  312. package/dist/web-appearance-policy.js.map +1 -0
  313. package/dist/web-appearance-tools.d.ts +53 -0
  314. package/dist/web-appearance-tools.js +124 -0
  315. package/dist/web-appearance-tools.js.map +1 -0
  316. package/dist/web-appearance-view.d.ts +124 -0
  317. package/dist/web-appearance-view.js +278 -0
  318. package/dist/web-appearance-view.js.map +1 -0
  319. package/dist/web-appearance.d.ts +93 -0
  320. package/dist/web-appearance.js +373 -0
  321. package/dist/web-appearance.js.map +1 -0
  322. package/dist/web-asset-parts.d.ts +93 -0
  323. package/dist/web-asset-parts.js +133 -0
  324. package/dist/web-asset-parts.js.map +1 -0
  325. package/dist/web-auth.js +20 -2
  326. package/dist/web-auth.js.map +1 -1
  327. package/dist/web-card.d.ts +110 -0
  328. package/dist/web-card.js +266 -0
  329. package/dist/web-card.js.map +1 -0
  330. package/dist/web-channel-echo.d.ts +7 -1
  331. package/dist/web-channel-echo.js +6 -2
  332. package/dist/web-channel-echo.js.map +1 -1
  333. package/dist/web-chat-history.d.ts +63 -0
  334. package/dist/web-chat-history.js +109 -6
  335. package/dist/web-chat-history.js.map +1 -1
  336. package/dist/web-commands.d.ts +1 -0
  337. package/dist/web-effect-bootstrap.d.ts +12 -0
  338. package/dist/web-effect-bootstrap.js +49 -0
  339. package/dist/web-effect-bootstrap.js.map +1 -0
  340. package/dist/web-effect-bundle.d.ts +28 -0
  341. package/dist/web-effect-bundle.js +171 -0
  342. package/dist/web-effect-bundle.js.map +1 -0
  343. package/dist/web-effect-canonical.d.ts +8 -0
  344. package/dist/web-effect-canonical.js +27 -0
  345. package/dist/web-effect-canonical.js.map +1 -0
  346. package/dist/web-effect-library.d.ts +114 -0
  347. package/dist/web-effect-library.js +530 -0
  348. package/dist/web-effect-library.js.map +1 -0
  349. package/dist/web-effect-playback.d.ts +30 -0
  350. package/dist/web-effect-playback.js +71 -0
  351. package/dist/web-effect-playback.js.map +1 -0
  352. package/dist/web-effect-poster.d.ts +8 -0
  353. package/dist/web-effect-poster.js +52 -0
  354. package/dist/web-effect-poster.js.map +1 -0
  355. package/dist/web-effect-profiles.d.ts +118 -0
  356. package/dist/web-effect-profiles.js +180 -0
  357. package/dist/web-effect-profiles.js.map +1 -0
  358. package/dist/web-effect-service.d.ts +93 -0
  359. package/dist/web-effect-service.js +335 -0
  360. package/dist/web-effect-service.js.map +1 -0
  361. package/dist/web-effect-tools.d.ts +48 -0
  362. package/dist/web-effect-tools.js +129 -0
  363. package/dist/web-effect-tools.js.map +1 -0
  364. package/dist/web-effect-trials.d.ts +86 -0
  365. package/dist/web-effect-trials.js +204 -0
  366. package/dist/web-effect-trials.js.map +1 -0
  367. package/dist/web-effect-upload.d.ts +27 -0
  368. package/dist/web-effect-upload.js +185 -0
  369. package/dist/web-effect-upload.js.map +1 -0
  370. package/dist/web-effect-worker.d.ts +8 -0
  371. package/dist/web-effect-worker.js +170 -0
  372. package/dist/web-effect-worker.js.map +1 -0
  373. package/dist/web-effect.d.ts +103 -0
  374. package/dist/web-effect.js +153 -0
  375. package/dist/web-effect.js.map +1 -0
  376. package/dist/web-guest-access.d.ts +125 -0
  377. package/dist/web-guest-access.js +234 -0
  378. package/dist/web-guest-access.js.map +1 -0
  379. package/dist/web-guest-rooms.d.ts +82 -0
  380. package/dist/web-guest-rooms.js +135 -0
  381. package/dist/web-guest-rooms.js.map +1 -0
  382. package/dist/web-identity-color.d.ts +87 -0
  383. package/dist/web-identity-color.js +209 -0
  384. package/dist/web-identity-color.js.map +1 -0
  385. package/dist/web-identity-palette.d.ts +113 -0
  386. package/dist/web-identity-palette.js +84 -0
  387. package/dist/web-identity-palette.js.map +1 -0
  388. package/dist/web-image-meta.d.ts +38 -0
  389. package/dist/web-image-meta.js +262 -0
  390. package/dist/web-image-meta.js.map +1 -0
  391. package/dist/web-login.d.ts +47 -0
  392. package/dist/web-login.js +115 -0
  393. package/dist/web-login.js.map +1 -1
  394. package/dist/web-mod-agent.d.ts +50 -0
  395. package/dist/web-mod-agent.js +207 -0
  396. package/dist/web-mod-agent.js.map +1 -0
  397. package/dist/web-mod-bundle.d.ts +157 -0
  398. package/dist/web-mod-bundle.js +529 -0
  399. package/dist/web-mod-bundle.js.map +1 -0
  400. package/dist/web-mod-export.d.ts +68 -0
  401. package/dist/web-mod-export.js +100 -0
  402. package/dist/web-mod-export.js.map +1 -0
  403. package/dist/web-mod-store.d.ts +289 -0
  404. package/dist/web-mod-store.js +638 -0
  405. package/dist/web-mod-store.js.map +1 -0
  406. package/dist/web-org.d.ts +3 -3
  407. package/dist/web-org.js +11 -17
  408. package/dist/web-org.js.map +1 -1
  409. package/dist/web-owner-css-store.d.ts +222 -0
  410. package/dist/web-owner-css-store.js +440 -0
  411. package/dist/web-owner-css-store.js.map +1 -0
  412. package/dist/web-owner-css.d.ts +58 -0
  413. package/dist/web-owner-css.js +552 -0
  414. package/dist/web-owner-css.js.map +1 -0
  415. package/dist/web-prefs.d.ts +62 -0
  416. package/dist/web-prefs.js +232 -36
  417. package/dist/web-prefs.js.map +1 -1
  418. package/dist/web-preview.d.ts +15 -3
  419. package/dist/web-preview.js +28 -9
  420. package/dist/web-preview.js.map +1 -1
  421. package/dist/web-returning-device.d.ts +41 -0
  422. package/dist/web-returning-device.js +57 -5
  423. package/dist/web-returning-device.js.map +1 -1
  424. package/dist/web-session-authorization.d.ts +132 -0
  425. package/dist/web-session-authorization.js +193 -0
  426. package/dist/web-session-authorization.js.map +1 -0
  427. package/dist/web-session.d.ts +70 -10
  428. package/dist/web-session.js +137 -22
  429. package/dist/web-session.js.map +1 -1
  430. package/dist/web-settings-patch.d.ts +67 -2
  431. package/dist/web-settings-patch.js +196 -1
  432. package/dist/web-settings-patch.js.map +1 -1
  433. package/dist/web-settings-tools.d.ts +89 -0
  434. package/dist/web-settings-tools.js +273 -0
  435. package/dist/web-settings-tools.js.map +1 -0
  436. package/dist/web-shell-routes.d.ts +2 -2
  437. package/dist/web-shell-routes.js +2 -2
  438. package/dist/web-shell-routes.js.map +1 -1
  439. package/dist/web-terminal-http.js +15 -2
  440. package/dist/web-terminal-http.js.map +1 -1
  441. package/dist/web-theme-store.d.ts +257 -0
  442. package/dist/web-theme-store.js +627 -0
  443. package/dist/web-theme-store.js.map +1 -0
  444. package/dist/web-theme.d.ts +123 -0
  445. package/dist/web-theme.js +416 -0
  446. package/dist/web-theme.js.map +1 -0
  447. package/dist/web-upload.d.ts +13 -0
  448. package/dist/web-upload.js +39 -3
  449. package/dist/web-upload.js.map +1 -1
  450. package/dist/web-widget.d.ts +72 -0
  451. package/dist/web-widget.js +245 -0
  452. package/dist/web-widget.js.map +1 -0
  453. package/dist/workflow-templates/default.md +1 -1
  454. package/package.json +1 -1
  455. package/templates/systemd.service.ejs +8 -0
@@ -0,0 +1,125 @@
1
+ /** #1629: host-owned static cursor controller; no product startup, metadata reader, Worker or frame. */
2
+ import { effectHostStyle } from "./effect-host-style.js";
3
+ import { checkStaticEffectCursor } from "./effect-runtime-loader.js";
4
+ const owners = new WeakMap(), ATTRIBUTE = "data-agend-effect-cursor";
5
+ let serial = 0;
6
+ const finite = n => typeof n === "number" && Number.isFinite(n) && n >= 0;
7
+ function selection(value) {
8
+ try {
9
+ if (!value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return null;
10
+ const fields = Object.getOwnPropertyDescriptors(value);
11
+ if (Reflect.ownKeys(fields).length !== 3 || !["id", "generation", "hotspot"].every(k => fields[k] && Object.hasOwn(fields[k], "value"))) return null;
12
+ const { id, generation, hotspot } = value;
13
+ if (typeof id !== "string" || !/^[a-f0-9]{32}$/.test(id) || !Number.isSafeInteger(generation) || generation < 0 || !Array.isArray(hotspot) || Object.getPrototypeOf(hotspot) !== Array.prototype) return null;
14
+ const entries = Object.getOwnPropertyDescriptors(hotspot);
15
+ if (Reflect.ownKeys(entries).length !== 3 || entries.length?.value !== 2 || ![0, 1].every(k => entries[k] && Object.hasOwn(entries[k], "value") && Number.isInteger(entries[k].value) && entries[k].value >= 0 && entries[k].value <= 63)) return null;
16
+ return Object.freeze({ id, generation, hotspot: Object.freeze([entries[0].value, entries[1].value]) });
17
+ } catch { return null; }
18
+ }
19
+ function cursorMatches(value, url, hotspot) {
20
+ const m = typeof value === "string" && /^url\((["']?)(blob:[^"'()\s]+)\1\)\s+(\d+)\s+(\d+),\s*auto$/.exec(value);
21
+ return !!m && m[2] === url && Number(m[3]) === hotspot[0] && Number(m[4]) === hotspot[1];
22
+ }
23
+ /** readImage must be the existing shared loader's settled cursor operation. enabled is a host gate, never effect data. */
24
+ export function createEffectCursor({ window: host, current, readImage, onChange = () => {} } = {}) {
25
+ const unavailable = { ok: false, update() {}, snapshot: () => ({ status: "unavailable", id: null }), dispose() {} };
26
+ if (!host?.document || owners.has(host) || ![current, readImage, onChange, host.getComputedStyle, host.Blob, host.URL?.createObjectURL, host.URL?.revokeObjectURL, host.AbortController, host.setTimeout, host.clearTimeout, host.performance?.now].every(x => typeof x === "function")) return unavailable;
27
+ const token = {}; owners.set(host, token);
28
+ const doc = host.document; let dead = false, previous = null, wanted = null, pending = null, active = null, blocked = null, generation = 0, checking = false, notifying = false, status = "off";
29
+ const safe = fn => { try { return fn(); } catch { return null; } };
30
+ const release = () => { if (dead && !pending && owners.get(host) === token) owners.delete(host); };
31
+ function alive() {
32
+ if (dead || checking) return false;
33
+ checking = true; const value = safe(() => current() === true && host.document === doc); checking = false;
34
+ return !dead && value === true;
35
+ }
36
+ function now() {
37
+ const value = safe(() => host.performance.now());
38
+ if (!finite(value) || previous !== null && value < previous) { dispose(); return null; }
39
+ previous = value; return value;
40
+ }
41
+ function target() {
42
+ const all = doc.querySelectorAll("#app > .shell"), el = all.length === 1 ? all[0] : null;
43
+ return el?.ownerDocument === doc && el.isConnected === true ? el : null;
44
+ }
45
+ function remove(row) {
46
+ if (!row) return;
47
+ // Removing our exact attribute disarms even a stylesheet whose CSSOM has become unreadable.
48
+ safe(() => { if (row.element.getAttribute(ATTRIBUTE) === row.token) row.element.removeAttribute(ATTRIBUTE); });
49
+ safe(() => row.rule?.style.removeProperty("cursor"));
50
+ safe(() => { const at = [...row.sheet.cssRules].indexOf(row.rule); if (at >= 0) row.sheet.deleteRule(at); });
51
+ if (row.url) { safe(() => host.URL.revokeObjectURL(row.url)); row.url = null; }
52
+ }
53
+ function clear() { const old = active; active = null; remove(old); }
54
+ function tell() { if (dead || notifying) return; notifying = true; try { safe(() => onChange(snapshot())); } finally { notifying = false; } }
55
+ function snapshot() { return Object.freeze({ status: dead ? "unavailable" : status, id: wanted?.selection.id ?? null }); }
56
+ function dispose() {
57
+ if (dead) return; dead = true; generation++; wanted = null; clear();
58
+ if (pending) { safe(() => pending.controller.abort()); remove(pending); }
59
+ safe(() => host.removeEventListener?.("pagehide", dispose)); release();
60
+ }
61
+ if (!alive() || now() === null || !effectHostStyle(host)) { dispose(); return unavailable; }
62
+ safe(() => host.addEventListener?.("pagehide", dispose));
63
+ function valid(op) {
64
+ if (!alive() || pending !== op || op.generation !== generation || op.controller.signal.aborted || wanted !== op.wanted) return false;
65
+ const t = now();
66
+ return t !== null && t >= op.began && t - op.began < 10000 && target() === op.element && effectHostStyle(host) === op.sheet;
67
+ }
68
+ function fail(op) {
69
+ if (!dead && pending === op && generation === op.generation && wanted === op.wanted) { blocked = wanted; status = "unavailable"; tell(); }
70
+ }
71
+ async function load(op) {
72
+ try {
73
+ if (!valid(op)) return;
74
+ const bytes = await readImage(op.wanted.selection, op.controller.signal);
75
+ if (!valid(op)) return;
76
+ const checked = checkStaticEffectCursor(bytes); if (!checked) { fail(op); return; }
77
+ const view = new DataView(checked.buffer, checked.byteOffset, checked.byteLength), width = view.getUint32(16), height = view.getUint32(20);
78
+ if (op.wanted.selection.hotspot.some((v, n) => v >= (n === 0 ? width : height))) { fail(op); return; }
79
+ op.url = host.URL.createObjectURL(new host.Blob([checked], { type: "image/png" }));
80
+ const url = new URL(op.url); if (url.protocol !== "blob:" || url.origin !== host.location.origin || !/^blob:[^"'()\s\\]+$/.test(op.url)) { fail(op); return; }
81
+ const image = doc.createElement("img"); image.alt = ""; image.src = op.url; op.image = image;
82
+ if (typeof image.decode !== "function") { fail(op); return; }
83
+ await image.decode();
84
+ if (!valid(op)) return;
85
+ if (image.naturalWidth !== width || image.naturalHeight !== height) { fail(op); return; }
86
+ if (op.element.hasAttribute(ATTRIBUTE)) { fail(op); return; }
87
+ op.token = `agend-effect-cursor-${++serial}`;
88
+ const index = op.sheet.insertRule(`#app > .shell[${ATTRIBUTE}="${op.token}"]{}`, op.sheet.cssRules.length); op.rule = op.sheet.cssRules[index];
89
+ const hotspot = op.wanted.selection.hotspot, value = `url("${op.url}") ${hotspot[0]} ${hotspot[1]}, auto`;
90
+ op.rule.style.setProperty("cursor", value); op.element.setAttribute(ATTRIBUTE, op.token);
91
+ if (!valid(op) || !cursorMatches(op.rule.style.getPropertyValue("cursor"), op.url, hotspot) || !cursorMatches(host.getComputedStyle(op.element).cursor, op.url, hotspot)) { fail(op); return; }
92
+ active = op; status = "running"; tell();
93
+ } catch { fail(op); }
94
+ finally {
95
+ safe(() => host.clearTimeout(op.timer));
96
+ if (active !== op) remove(op);
97
+ if (pending === op) { pending = null; if (!dead && wanted === op.wanted && !active && blocked !== wanted) { blocked = wanted; status = "unavailable"; tell(); } }
98
+ release(); if (!dead) start();
99
+ }
100
+ }
101
+ function start() {
102
+ if (!alive() || pending || active || !wanted || blocked === wanted) return;
103
+ const began = now(), element = safe(target), sheet = effectHostStyle(host);
104
+ if (began === null || !element || !sheet || element.hasAttribute(ATTRIBUTE)) { blocked = wanted; status = "unavailable"; tell(); return; }
105
+ const op = { wanted, generation, began, element, sheet, controller: new host.AbortController(), url: null, rule: null, token: null, timer: null }; pending = op; status = "loading";
106
+ op.timer = host.setTimeout(() => { if (pending !== op) return; op.controller.abort(); remove(op); fail(op); }, 10000);
107
+ tell(); void load(op);
108
+ }
109
+ function update(value, enabled) {
110
+ if (!alive() || now() === null) { dispose(); return; }
111
+ const next = enabled === true ? selection(value) : null;
112
+ const same = !!next && wanted && next.id === wanted.selection.id && next.generation === wanted.selection.generation && next.hotspot.every((n, i) => n === wanted.selection.hotspot[i]);
113
+ if (!same) {
114
+ generation++; wanted = next ? { selection: next } : null; blocked = null; clear();
115
+ if (pending) { safe(() => pending.controller.abort()); remove(pending); }
116
+ status = next ? "loading" : "off";
117
+ }
118
+ if (active) {
119
+ const row = active;
120
+ if (safe(target) !== row.element || effectHostStyle(host) !== row.sheet || row.element.getAttribute(ATTRIBUTE) !== row.token || !cursorMatches(safe(() => host.getComputedStyle(row.element).cursor), row.url, row.wanted.selection.hotspot)) { clear(); blocked = wanted; status = "unavailable"; }
121
+ }
122
+ start(); tell();
123
+ }
124
+ return { ok: true, update, snapshot, dispose };
125
+ }
@@ -0,0 +1,146 @@
1
+ /** #1629: parent-owned Canvas Worker transport; the Chat adapter owns product admission. */
2
+ import { maySendEffectEvent } from "./effect-policy.js";
3
+ const plain = v => !!v && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
4
+ const exact = (v, keys) => plain(v) && Object.keys(v).sort().join(",") === keys.slice().sort().join(",");
5
+ const finite = v => typeof v === "number" && Number.isFinite(v);
6
+ const bytes = v => new TextEncoder().encode(v).byteLength;
7
+
8
+ /** Snapshot only host-validated code, primitives and raster bytes; no HTML or DOM interface exists. */
9
+ function snapshotRender(raw) {
10
+ if (!exact(raw, ["code", "params", "instance", "width", "height", "dpr", "assets", "wants"]) || typeof raw.code !== "string" || !plain(raw.params) || !Array.isArray(raw.assets) || raw.assets.length > 16 || !Array.isArray(raw.wants) || Array.from(raw.wants).some(v => !["pointer", "state", "reply", "mention", "theme"].includes(v)) || new Set(raw.wants).size !== raw.wants.length) return null;
11
+ if (raw.instance !== null && (typeof raw.instance !== "string" || raw.instance.length < 1 || raw.instance.length > 128)) return null;
12
+ if (!Number.isInteger(raw.width) || raw.width < 1 || raw.width > 4096 || !Number.isInteger(raw.height) || raw.height < 1 || raw.height > 4096 || raw.width * raw.height > 8388608 || !finite(raw.dpr) || raw.dpr < 0.5 || raw.dpr > 3) return null;
13
+ const params = Object.create(null), keys = Object.keys(raw.params);
14
+ if (keys.length > 16) return null;
15
+ for (const key of keys) {
16
+ const value = raw.params[key];
17
+ if (!/^[a-z][a-z0-9_]{0,31}$/.test(key) || !(typeof value === "boolean" || finite(value) || typeof value === "string" && value.length <= 128)) return null;
18
+ params[key] = value;
19
+ }
20
+ let total = bytes(raw.code) + bytes(JSON.stringify(params));
21
+ if (total > 1048576) return null;
22
+ const assets = [], names = new Set();
23
+ for (const a of raw.assets) {
24
+ if (!exact(a, ["name", "mime", "bytes"]) || typeof a.name !== "string" || !/^assets\/[a-z0-9][a-z0-9_-]{0,63}\.(?:png|jpe?g|webp|gif)$/.test(a.name) || names.has(a.name) || !["image/png", "image/jpeg", "image/webp", "image/gif"].includes(a.mime) || !(a.bytes instanceof Uint8Array)) return null;
25
+ total += a.bytes.byteLength;
26
+ if (total > 1048576) return null;
27
+ names.add(a.name);
28
+ assets.push({ name: a.name, mime: a.mime, bytes: new Uint8Array(a.bytes) });
29
+ }
30
+ return { code: raw.code, params: { ...params }, instance: raw.instance, width: raw.width, height: raw.height, dpr: raw.dpr, assets, wants: [...raw.wants] };
31
+ }
32
+
33
+ /** Listener transport only; this does not grant HTML-preview or ordinary-effect consent. */
34
+ export function effectTransportReady(host, origin, boot) {
35
+ try {
36
+ const target = new URL(origin), page = new URL(host.location.origin);
37
+ return origin === target.origin && ["http:", "https:"].includes(target.protocol) && ["http:", "https:"].includes(page.protocol)
38
+ && target.origin !== page.origin && !(page.protocol === "https:" && target.protocol !== "https:") && typeof boot === "string" && /^[0-9a-f]{32}$/.test(boot);
39
+ } catch { return false; }
40
+ }
41
+
42
+ /** #2118: same URL origin, opaque realm. This helper does not alter product admission or HTML preview consent. */
43
+ export function effectBootstrapReady(host, origin, boot) {
44
+ try {
45
+ const target = new URL(origin), page = new URL(host.location.origin);
46
+ return origin === target.origin && target.origin === page.origin && ["http:", "https:"].includes(target.protocol)
47
+ && typeof boot === "string" && /^[0-9a-f]{32}$/.test(boot);
48
+ } catch { return false; }
49
+ }
50
+
51
+ /**
52
+ * All options come from the host, never from an agent event or manifest origin. The registry supplies an admitted
53
+ * root and geometry in a later integration. This primitive alone does not implement caps, clipping or profiling.
54
+ */
55
+ export function createEffectFrame(options = {}) { return ownedEffectFrame(options, false); }
56
+
57
+ /** Product transport: the same-listener trusted document still has an opaque sandboxed realm. */
58
+ export function createOpaqueEffectFrame(options = {}) { return ownedEffectFrame(options, true); }
59
+
60
+ function ownedEffectFrame({ window: host, root, origin, boot, render, clock = () => performance.now(), onReady = () => {}, onRemove = () => {} } = {}, sameListener) {
61
+ if (!(sameListener ? effectBootstrapReady : effectTransportReady)(host, origin, boot)) return { ok: false, reason: sameListener ? "bootstrap_unknown" : "preview_unknown" };
62
+ const payload = snapshotRender(render);
63
+ if (!payload || !host || !root || root.ownerDocument !== host.document || typeof root.append !== "function" || typeof host.MessageChannel !== "function" || typeof clock !== "function" || typeof onReady !== "function" || typeof onRemove !== "function") return { ok: false, reason: "unsupported" };
64
+ let mounted;
65
+ try { mounted = clock(); } catch { return { ok: false, reason: "clock_unavailable" }; }
66
+ if (!finite(mounted) || mounted < 0) return { ok: false, reason: "clock_unavailable" };
67
+ const frame = host.document.createElement("iframe");
68
+ frame.setAttribute("sandbox", "allow-scripts");
69
+ frame.setAttribute("tabindex", "-1");
70
+ frame.setAttribute("aria-hidden", "true");
71
+ frame.setAttribute("referrerpolicy", "no-referrer");
72
+ frame.className = "agend-effect-frame";
73
+ let removed = false, ready = false, transferred = false, loads = 0, channel = null, timer = null, last = mounted;
74
+ const time = () => {
75
+ let now; try { now = clock(); } catch { return null; }
76
+ if (!finite(now) || now < last) return null;
77
+ last = now; return now;
78
+ };
79
+ const state = () => ({ ready, removed, loads });
80
+ const remove = reason => {
81
+ if (removed) return;
82
+ removed = true;
83
+ host.removeEventListener("message", hello);
84
+ frame.removeEventListener("load", load);
85
+ if (timer !== null) host.clearTimeout(timer);
86
+ if (channel) {
87
+ channel.port1.removeEventListener("message", portReady);
88
+ try { channel.port1.close(); } catch { /* already detached */ }
89
+ try { channel.port2.close(); } catch { /* already transferred */ }
90
+ }
91
+ frame.remove();
92
+ try { onRemove(reason); } catch { /* host callback cannot revive a removed frame */ }
93
+ };
94
+ const load = () => { loads++; if (loads > 1) remove("navigation"); };
95
+ const current = () => {
96
+ if (removed) return false;
97
+ if (frame.parentNode !== root || frame.isConnected !== true) { remove("detached"); return false; }
98
+ const now = time();
99
+ if (now === null) { remove("clock_unavailable"); return false; }
100
+ if (!ready && now - mounted >= 10000) { remove("startup_timeout"); return false; }
101
+ return true;
102
+ };
103
+ const portReady = event => {
104
+ if (removed || ready) return;
105
+ let data; try { data = event.data; } catch { return; }
106
+ if (!exact(data, ["type"]) || data.type !== "ready") return;
107
+ if (!current()) return;
108
+ ready = true;
109
+ host.clearTimeout(timer); timer = null;
110
+ channel.port1.removeEventListener("message", portReady);
111
+ try { onReady(); } catch { remove("host_callback"); }
112
+ };
113
+ const hello = event => {
114
+ if (removed || transferred) return;
115
+ let data; try { data = event.data; } catch { return; }
116
+ // Opaque sandbox messages have origin null. Only this exact WindowProxy and boot may receive the private port.
117
+ if (event.source !== frame.contentWindow || event.origin !== "null" || event.ports?.length || !exact(data, ["v", "type", "ch", "boot"]) || data.v !== 1 || data.type !== "ready" || data.ch !== null || data.boot !== boot) return;
118
+ if (!current()) return;
119
+ transferred = true;
120
+ host.removeEventListener("message", hello);
121
+ try {
122
+ channel = new host.MessageChannel();
123
+ channel.port1.addEventListener("message", portReady);
124
+ channel.port1.start();
125
+ const nonce = new Uint8Array(16); host.crypto.getRandomValues(nonce);
126
+ const ch = Array.from(nonce, b => b.toString(16).padStart(2, "0")).join("");
127
+ const { wants, ...message } = payload;
128
+ // '*' is required for the opaque destination; the source WindowProxy was checked immediately above.
129
+ frame.contentWindow.postMessage({ v: 1, type: "render", ch, ...message }, "*", [channel.port2]);
130
+ } catch { remove("transport"); }
131
+ };
132
+ const deadline = () => {
133
+ if (!current() || ready) return;
134
+ timer = host.setTimeout(deadline, Math.max(1, 10000 - (last - mounted)));
135
+ };
136
+ host.addEventListener("message", hello);
137
+ frame.addEventListener("load", load);
138
+ timer = host.setTimeout(deadline, 10000);
139
+ try { frame.src = origin + (sameListener ? "/effect-bootstrap" : "/effect"); root.append(frame); } catch { remove("mount_failed"); }
140
+ return { ok: true, element: frame, state, remove,
141
+ send(event) {
142
+ if (!ready || !current() || !maySendEffectEvent(event, { instance: payload.instance, wants: payload.wants })) return false;
143
+ try { channel.port1.postMessage(event); return true; } catch { remove("transport"); return false; }
144
+ },
145
+ };
146
+ }
@@ -0,0 +1,137 @@
1
+ /** #1629: host-only fixed viewport geometry and trust holes through the already-loaded, fixed same-origin app stylesheet. No inline attributes. */
2
+ import { effectHostStyle } from "./effect-host-style.js";
3
+ import { effectTrustClip } from "./effect-policy.js";
4
+ import { effectStockSnapshot, effectStockAllows } from "./effect-stock-snapshot.js";
5
+ let serial = 0;
6
+ // Native CSSOM canonicalizes SVG command whitespace. Compare bounded tokens, never whitespace-stripped digits.
7
+ function sameClip(expected, written) {
8
+ if (expected === "none") return written === "none";
9
+ const tokens = value => {
10
+ if (typeof value !== "string" || value.length > 100000) return null;
11
+ const m = /^path\(\s*evenodd\s*,\s*["']([^"']*)["']\s*\)$/.exec(value);
12
+ if (!m) return null;
13
+ const out = [], rest = m[1].replace(/[MHVZ]|-?\d+(?:\.\d+)?/g, token => { out.push(/[MHVZ]/.test(token) ? token : Number(token)); return ""; });
14
+ return /^[\s,]*$/.test(rest) ? JSON.stringify(out) : null;
15
+ };
16
+ const a = tokens(expected), b = tokens(written);
17
+ return a !== null && a === b;
18
+ }
19
+ const number = n => typeof n === "number" && Number.isFinite(n) && Math.abs(n) <= 1e7;
20
+ /** A fixed frame must share viewport axes. Unknown transformed/filter/contained ancestors fail closed. */
21
+ export function hostEffectSpace(host, element) {
22
+ try {
23
+ if (element?.ownerDocument !== host.document || element.isConnected !== true || typeof host.getComputedStyle !== "function") return false;
24
+ let el = element, seen = 0;
25
+ while (el) {
26
+ if (++seen > 128 || el.ownerDocument !== host.document) return false;
27
+ const s = host.getComputedStyle(el);
28
+ for (const key of ["transform", "perspective", "filter", "backdropFilter", "rotate", "scale", "translate", "offsetPath"]) if (s[key] !== undefined && s[key] !== "" && s[key] !== "none") return false;
29
+ if (s.contain !== "none" || s.willChange !== "auto" || s.contentVisibility !== undefined && s.contentVisibility !== "" && s.contentVisibility !== "visible" || s.zoom !== undefined && !["", "normal", "1"].includes(s.zoom)) return false;
30
+ if (el === host.document.documentElement) return true;
31
+ el = el.parentElement;
32
+ }
33
+ return false;
34
+ } catch { return false; }
35
+ }
36
+ export function hostEffectRect(element) {
37
+ try {
38
+ if (element?.isConnected !== true) return null;
39
+ const r = element.getBoundingClientRect();
40
+ if (![r.x, r.y, r.width, r.height].every(number) || r.width < 1 || r.height < 1) return null;
41
+ const x = Math.floor(r.x), y = Math.floor(r.y), width = Math.ceil(r.x + r.width) - x, height = Math.ceil(r.y + r.height) - y;
42
+ return width <= 4096 && height <= 4096 && width * height <= 8388608 ? { x, y, width, height } : null;
43
+ } catch { return null; }
44
+ }
45
+ export function createEffectGeometry({ window: host } = {}) {
46
+ let sheet;
47
+ try {
48
+ if (!host?.document || host.CSS?.supports("clip-path", 'path(evenodd, "M0 0H1V1H0Z")') !== true) return { ok: false, reason: "geometry_unsupported" };
49
+ sheet = effectHostStyle(host); if (!sheet) throw Error("app stylesheet unavailable");
50
+ } catch { return { ok: false, reason: "geometry_unsupported" }; }
51
+ const bound = new Set(); let disposed = false;
52
+ function bind(frame, { layer, by } = {}) {
53
+ if (disposed || !hostEffectSpace(host, frame) || !["front", "behind"].includes(layer) || !frame.classList) {
54
+ // The caller must also close its factory handle. Never leave its own rejected frame painting.
55
+ if (frame?.ownerDocument === host.document && typeof frame.remove === "function") frame.remove();
56
+ return { ok: false, reason: "geometry_unknown" };
57
+ }
58
+ const token = `agend-effect-geometry-${++serial}`;
59
+ let rule;
60
+ try {
61
+ const at = sheet.insertRule(`.${token}{}`, sheet.cssRules.length); rule = sheet.cssRules[at];
62
+ if (!rule?.style) throw Error("rule unavailable");
63
+ for (const [key, value] of Object.entries({ position: "fixed", border: "0px", margin: "0px", padding: "0px", "pointer-events": "none", "z-index": layer === "front" ? "20" : "0", opacity: layer === "front" && by !== "human" ? "0.85" : "1", visibility: "hidden", "background-color": "transparent", "box-sizing": "border-box", "box-shadow": "none", outline: "none", transition: "none", animation: "none", "min-width": "0px", "min-height": "0px", "max-width": "none", "max-height": "none" })) rule.style.setProperty(key, value, "important");
64
+ frame.classList.add(token);
65
+ // Binding is accepted BEFORE the first sync/ready. Prove its initial hidden state before the caller may yield.
66
+ if (host.getComputedStyle(frame).visibility !== "hidden") throw Error("initial hiding cascade lost");
67
+ } catch {
68
+ try { const at = [...sheet.cssRules].indexOf(rule); if (at >= 0) sheet.deleteRule(at); } catch { /* cleanup cannot precede physical refusal */ }
69
+ try { frame.classList.remove(token); } catch { /* the refused frame will not remain in the document */ }
70
+ frame.remove();
71
+ return { ok: false, reason: "geometry_unknown" };
72
+ }
73
+ let dead = false, shown = false;
74
+ const hide = () => {
75
+ shown = false;
76
+ try {
77
+ rule.style.setProperty("visibility", "hidden", "important");
78
+ if (frame.isConnected === true && host.getComputedStyle(frame).visibility !== "hidden") { frame.remove(); return false; }
79
+ return true;
80
+ } catch { frame.remove(); return false; }
81
+ };
82
+ const handle = { ok: true, hide,
83
+ /** Same-turn host paint snapshot is mandatory, including behind/human placements. No DOM fallback. */
84
+ sync(rect, stock) {
85
+ const refuse = () => { hide(); return false; };
86
+ const proof = effectStockSnapshot(stock);
87
+ if (!effectStockAllows(proof, { layer, by })) return refuse();
88
+ if (dead || disposed || !hostEffectSpace(host, frame) || !rect || ![rect.x, rect.y, rect.width, rect.height].every(number) || ![rect.x, rect.y, rect.width, rect.height].every(Number.isInteger) || rect.width < 1 || rect.height < 1 || rect.width > 4096 || rect.height > 4096 || rect.width * rect.height > 8388608) return refuse();
89
+ let path = "none";
90
+ if (layer === "front" && by !== "human") {
91
+ const clipped = effectTrustClip(rect, proof.rects);
92
+ if (!clipped.ok) return refuse();
93
+ path = clipped.path;
94
+ }
95
+
96
+ try {
97
+ const matches = visibility => {
98
+ const style = host.getComputedStyle(frame), actual = frame.getBoundingClientRect();
99
+ return style.position === "fixed" && style.pointerEvents === "none" && style.visibility === visibility
100
+ && style.opacity === (layer === "front" && by !== "human" ? "0.85" : "1") && style.zIndex === (layer === "front" ? "20" : "0")
101
+ && sameClip(path, rule.style.getPropertyValue("clip-path")) && sameClip(path, style.clipPath)
102
+ && ["x", "y", "width", "height"].every(key => number(actual[key]) && Math.abs(actual[key] - rect[key]) < 0.02)
103
+ && frame.isConnected === true && frame.ownerDocument === host.document;
104
+ };
105
+ // A fresh proof and actual viewport/clip are still checked every frame. Rewriting an
106
+ // already verified presentation makes WebKit repeatedly invalidate the iframe's paint.
107
+ if (shown && matches("visible")) return true;
108
+ // Changed or unproven geometry is hidden before writes and verified before reveal.
109
+ if (!hide()) return false;
110
+ for (const key of ["x", "y", "width", "height"]) rule.style.setProperty(key === "x" ? "left" : key === "y" ? "top" : key, `${rect[key]}px`, "important");
111
+ rule.style.setProperty("clip-path", path, "important");
112
+ if (!sameClip(path, rule.style.getPropertyValue("clip-path"))) return false;
113
+ // The stylesheet can lose the cascade to another host rule. Verify the actual viewport and clip
114
+ // before revealing: holes expressed in planned coordinates cannot protect a transformed frame.
115
+ if (!matches("hidden")) return false;
116
+ rule.style.setProperty("visibility", "visible", "important");
117
+ shown = true;
118
+ return true;
119
+ } catch { hide(); return false; }
120
+ },
121
+ remove() {
122
+ if (dead) return; dead = true; hide(); bound.delete(handle);
123
+ if (frame.isConnected === true) frame.remove();
124
+ try { frame.classList.remove(token); const at = [...sheet.cssRules].indexOf(rule); if (at >= 0) sheet.deleteRule(at); } catch { frame.remove(); }
125
+ },
126
+ };
127
+ bound.add(handle); return handle;
128
+ }
129
+ return { ok: true, bind,
130
+ hide() { for (const h of bound) h.hide(); },
131
+ dispose() {
132
+ if (disposed) return; disposed = true;
133
+ for (const h of [...bound]) h.remove();
134
+ // The host link and its other rules remain intact. Each binding removed only its own rule.
135
+ },
136
+ };
137
+ }
@@ -0,0 +1,10 @@
1
+ /** Fixed same-origin host stylesheet only. No new sheet, inline style, owner CSS or supplied URL. */
2
+ export function effectHostStyle(host) {
3
+ try {
4
+ const link = host?.document?.querySelector('link[rel="stylesheet"][href="/assets/app.css"]');
5
+ const href = new URL("/assets/app.css", host.location.origin).href;
6
+ if (!link || link.tagName !== "LINK" || link.ownerDocument !== host.document || link.isConnected !== true || link.disabled !== false || !link.sheet || link.sheet.ownerNode !== link || link.sheet.href !== href || link.sheet.disabled !== false) return null;
7
+ const sheet = link.sheet;
8
+ return typeof sheet.insertRule === "function" && typeof sheet.deleteRule === "function" && sheet.cssRules ? sheet : null;
9
+ } catch { return null; }
10
+ }
@@ -0,0 +1,74 @@
1
+ /** #1629: host-only personal region targets on the currently proven stock shell. No selection, code or frame authority. */
2
+ import { createEffectGeometry, hostEffectRect, hostEffectSpace } from "./effect-geometry.js";
3
+ import { effectStockSnapshot } from "./effect-stock-snapshot.js";
4
+ const finite = n => typeof n === "number" && Number.isFinite(n);
5
+ function viewport(host) {
6
+ const width = host.innerWidth, height = host.innerHeight;
7
+ return [width, height].every(n => Number.isInteger(n) && n >= 1 && n <= 4096) && width * height <= 8388608 ? { x: 0, y: 0, width, height } : null;
8
+ }
9
+ /** An anchored box uses edge padding; center ignores the offset. Oversized boxes shrink within that padding. */
10
+ export function ownerEffectBoxRect(box, size) {
11
+ try {
12
+ if (!box || ![Object.prototype, null].includes(Object.getPrototypeOf(box))) return null;
13
+ const fields = Object.getOwnPropertyDescriptors(box), keys = Reflect.ownKeys(fields);
14
+ if (keys.length !== 4 || !["anchor", "width", "height", "offset"].every(k => fields[k] && Object.hasOwn(fields[k], "value"))) return null;
15
+ const b = Object.fromEntries(Object.entries(fields).map(([k, d]) => [k, d.value]));
16
+ if (!["top-left", "top-right", "bottom-left", "bottom-right", "center"].includes(b.anchor) || ![b.width, b.height].every(n => Number.isInteger(n) && n >= 32 && n <= 480) || !Number.isInteger(b.offset) || b.offset < 0 || b.offset > 64 || !size || ![size.width, size.height].every(n => Number.isInteger(n) && n >= 1 && n <= 4096) || size.width * size.height > 8388608) return null;
17
+ const pad = b.anchor === "center" ? 0 : b.offset, width = Math.min(b.width, size.width - pad * 2), height = Math.min(b.height, size.height - pad * 2);
18
+ if (width < 1 || height < 1) return null;
19
+ const x = b.anchor === "center" ? Math.floor((size.width - width) / 2) : b.anchor.endsWith("right") ? size.width - pad - width : pad;
20
+ const y = b.anchor === "center" ? Math.floor((size.height - height) / 2) : b.anchor.startsWith("bottom") ? size.height - pad - height : pad;
21
+ return { x, y, width, height };
22
+ } catch { return null; }
23
+ }
24
+ /** Caller supplies the authenticated lease and fresh stock proof. Header/sidebar are real stock elements;
25
+ * page/box are empty hidden host DOM references, never author DOM. They consume no frame/cap slot.
26
+ * A null result requires removing that descriptor; this primitive cannot retire a caller-owned effect frame. */
27
+ export function createOwnerEffectRegions({ window: host, current, factories = {} } = {}) {
28
+ let dead = false, root = null, geometry = null;
29
+ const targets = new Map();
30
+ const dispose = () => { if (dead) return; dead = true; geometry?.dispose?.(); root?.remove(); targets.clear(); };
31
+ const refuse = () => { for (const row of targets.values()) row.binding.hide(); return null; };
32
+ const unavailable = () => ({ ok: false, dispose });
33
+ const alive = () => { if (dead) return false; const valid = current() === true; return !dead && valid && host.document.body.dataset.mode === "full"; };
34
+ try {
35
+ if (!host?.document || typeof current !== "function" || typeof host.getComputedStyle !== "function" || !alive()) return unavailable();
36
+ root = host.document.createElement("div"); root.className = "agend-effect-layer"; host.document.body.append(root);
37
+ geometry = (factories.geometry ?? createEffectGeometry)({ window: host }); if (!geometry.ok) { dispose(); return unavailable(); }
38
+ } catch { dispose(); return unavailable(); }
39
+ function panel() {
40
+ const nodes = host.document.querySelectorAll(".main > .panel"); if (nodes.length !== 1) return null;
41
+ const el = nodes[0], kind = el.getAttribute("data-effect-panel");
42
+ return kind === null ? el.classList.contains("p-chat") ? el : null
43
+ : ["fleet", "needs", "settings", "view", "log", "details"].includes(kind) && el.classList.contains(`p-${kind}`) ? el : null;
44
+ }
45
+ function resolve(slot, box, stock) {
46
+ try {
47
+ if (!alive() || !effectStockSnapshot(stock)) return refuse();
48
+ const surface = panel(), size = viewport(host); if (!surface || !size) return refuse();
49
+ if (slot === "fx.header" || slot === "fx.sidebar") {
50
+ const selector = slot === "fx.header" ? ".main > .panel > .panel-head[data-trust=header]" : ".shell > .sidebar";
51
+ const nodes = host.document.querySelectorAll(selector); if (nodes.length !== 1) return null;
52
+ const el = nodes[0], s = host.getComputedStyle(el), rect = hostEffectRect(el);
53
+ return alive() && panel() === surface && s.display !== "none" && s.visibility === "visible" && hostEffectSpace(host, el) && rect && rect.x + rect.width > 0 && rect.y + rect.height > 0 && rect.x < size.width && rect.y < size.height ? el : null;
54
+ }
55
+ if (!["fx.page", "fx.box"].includes(slot)) return null;
56
+ const rect = slot === "fx.page" ? size : ownerEffectBoxRect(box, size); if (!rect) return refuse();
57
+ let row = targets.get(slot);
58
+ if (!row) {
59
+ const element = host.document.createElement("div"); element.className = "agend-owner-effect-target"; element.setAttribute("aria-hidden", "true"); root.append(element);
60
+ const binding = geometry.bind(element, { layer: "behind", by: "human" });
61
+ if (!binding.ok) { element.remove(); return null; }
62
+ row = { element, binding }; targets.set(slot, row);
63
+ }
64
+ // Empty reference only: the synchronous existing hidden-first verification is followed by hide before yielding.
65
+ // The future registry owns the actual effect's layer/provenance/caps and independent fresh paint check.
66
+ if (!row.binding.sync(rect, stock)) { row.binding.remove(); targets.delete(slot); return null; }
67
+ row.binding.hide();
68
+ const actual = hostEffectRect(row.element);
69
+ if (!alive() || panel() !== surface || row.element.isConnected !== true || host.getComputedStyle(row.element).visibility !== "hidden" || !actual || !["x", "y", "width", "height"].every(k => finite(actual[k]) && actual[k] === rect[k])) { row.binding.remove(); targets.delete(slot); return null; }
70
+ return row.element;
71
+ } catch { return refuse(); }
72
+ }
73
+ return { ok: true, root, resolve, dispose };
74
+ }
@@ -0,0 +1,122 @@
1
+ /** #1629: host-only personal contribution model. No fetch, timer, DOM creation, registry or playback. */
2
+ import { checkEffectOwnerSlots } from "./effect-runtime-loader.js";
3
+ import { effectStockSnapshot } from "./effect-stock-snapshot.js";
4
+ const SLOTS = ["fx.page", "fx.header", "fx.sidebar", "fx.box"], ALL_SLOTS = [...SLOTS, "fx.cursor"];
5
+
6
+ /** The app supplies its one loader/metadata scheduler, lifetime and fixed stock target resolver. */
7
+ export function createOwnerEffectSource({ current, readMetadata, readResource, resolveTarget, stock, onChange = () => {}, onUnavailable = () => {} } = {}) {
8
+ let dead = false, generation = 0, serial = 0, metadata = null, error = null, active = null, rev = -1, checking = false, cursor = null;
9
+ const bySlot = new Map(), byKey = new Map(), paused = new Map(), failed = new Map();
10
+ const safe = fn => { try { return fn(); } catch { return null; } };
11
+ function alive() {
12
+ if (dead || checking) return false;
13
+ const before = generation; checking = true;
14
+ let value; try { value = current() === true; } catch { value = false; } finally { checking = false; }
15
+ return !dead && before === generation && value;
16
+ }
17
+ const fresh = (body, gen) => alive() && generation === gen && metadata === body;
18
+ function drop(slot) { const b = bySlot.get(slot); if (b) byKey.delete(b.key); bySlot.delete(slot); }
19
+ function clear() { bySlot.clear(); byKey.clear(); }
20
+ const notify = () => { if (alive()) safe(onChange); };
21
+ function dispose() { if (dead) return; dead = true; generation++; metadata = null; cursor = null; clear(); paused.clear(); failed.clear(); }
22
+ const unavailable = { ok: false, dispose };
23
+ if (![current, readMetadata, readResource, resolveTarget, stock, onChange, onUnavailable].every(x => typeof x === "function")) return unavailable;
24
+ function row(slot) { return alive() && SLOTS.includes(slot) ? metadata?.slots[slot] ?? null : null; }
25
+ function bindingCurrent(b) {
26
+ if (!b || !alive() || generation !== b.generation || bySlot.get(b.slot) !== b || byKey.get(b.key) !== b || failed.get(b.slot) === b.id) return false;
27
+ const selected = metadata?.slots[b.slot];
28
+ return selected?.status === "available" && selected.id === b.id && b.element.isConnected === true && !dead && generation === b.generation;
29
+ }
30
+ function cursorSelection() {
31
+ const body = metadata, gen = generation;
32
+ if (!alive() || !body || error) return null;
33
+ const selected = body.slots["fx.cursor"];
34
+ if (selected.status !== "available" || failed.get("fx.cursor") === selected.id || !selected.manifest.cursor) return null;
35
+ if (!cursor || cursor.id !== selected.id || cursor.generation !== gen) cursor = Object.freeze({ id: selected.id, generation: gen, hotspot: Object.freeze([...selected.manifest.cursor.hotspot]) });
36
+ return fresh(body, gen) && failed.get("fx.cursor") !== selected.id ? cursor : null;
37
+ }
38
+ function cursorCurrent(value) {
39
+ try {
40
+ const expected = cursorSelection(); if (!expected || !value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return false;
41
+ const d = Object.getOwnPropertyDescriptors(value);
42
+ if (Reflect.ownKeys(d).length !== 3 || !["id", "generation", "hotspot"].every(k => d[k] && Object.hasOwn(d[k], "value")) || d.id.value !== expected.id || d.generation.value !== expected.generation) return false;
43
+ const a = d.hotspot.value; if (!Array.isArray(a) || Object.getPrototypeOf(a) !== Array.prototype) return false;
44
+ const h = Object.getOwnPropertyDescriptors(a);
45
+ return Reflect.ownKeys(h).length === 3 && h.length.value === 2 && [0, 1].every(k => h[k] && Object.hasOwn(h[k], "value") && h[k].value === expected.hotspot[k]) && cursorSelection() === expected;
46
+ } catch { return false; }
47
+ }
48
+ function refuse(b) {
49
+ if (!bindingCurrent(b)) return;
50
+ failed.set(b.slot, b.id); drop(b.slot); notify();
51
+ if (!dead && generation === b.generation && failed.get(b.slot) === b.id && metadata?.slots[b.slot]?.id === b.id) safe(() => onUnavailable(b.slot, b.id));
52
+ }
53
+ return { ok: true, cursorSelection, cursorCurrent,
54
+ refuseCursor(value) {
55
+ const own = cursorSelection(); if (!own || !cursorCurrent(value)) return;
56
+ failed.set("fx.cursor", own.id); notify();
57
+ if (!dead && generation === own.generation && failed.get("fx.cursor") === own.id && metadata?.slots["fx.cursor"]?.id === own.id) safe(() => onUnavailable("fx.cursor", own.id));
58
+ },
59
+ needsMetadata() { return alive() && metadata === null && error === null; },
60
+ invalidate() { if (dead) return; generation++; metadata = null; cursor = null; error = null; clear(); failed.clear(); notify(); },
61
+ async read(signal) {
62
+ if (!alive() || metadata !== null || error !== null || active || signal?.aborted) return false;
63
+ const op = { generation }; active = op;
64
+ const valid = () => alive() && generation === op.generation && active === op && !signal?.aborted;
65
+ try {
66
+ const answer = await readMetadata(signal); if (!valid()) return false;
67
+ const next = checkEffectOwnerSlots(answer);
68
+ if (!next || next.rev < rev) { error = next ? "stale" : "unreadable"; clear(); notify(); return false; }
69
+ rev = next.rev; metadata = next;
70
+ for (const [slot, id] of paused) if (next.slots[slot]?.id !== id) paused.delete(slot);
71
+ notify(); return valid() && metadata === next;
72
+ } catch { if (valid()) { error = "unreadable"; clear(); notify(); } return false; }
73
+ finally { if (active === op) active = null; }
74
+ },
75
+ descriptors() {
76
+ if (!alive() || !metadata || error) return [];
77
+ const body = metadata, gen = generation;
78
+ // #2188: the stock snapshot walks the whole page (thousands of computed styles). With no slot holding an effect
79
+ // that could play, there is nothing for it to admit: skipped — every page change (a status, a chat switch) ran it.
80
+ if (!SLOTS.some(slot => body.slots[slot]?.status === "available" && failed.get(slot) !== body.slots[slot].id)) {
81
+ for (const slot of SLOTS) drop(slot);
82
+ return [];
83
+ }
84
+ const proof = safe(() => effectStockSnapshot(stock()));
85
+ if (!fresh(body, gen)) return [];
86
+ if (!proof) { clear(); return []; }
87
+ const result = [];
88
+ for (const slot of SLOTS) {
89
+ const selected = body.slots[slot];
90
+ if (selected.status !== "available" || failed.get(slot) === selected.id) { drop(slot); continue; }
91
+ const element = safe(() => resolveTarget(slot, selected.manifest, proof));
92
+ if (!fresh(body, gen)) return [];
93
+ if (!element || element.isConnected !== true) { drop(slot); continue; }
94
+ let b = bySlot.get(slot);
95
+ if (!b || b.id !== selected.id || b.element !== element || b.generation !== gen) {
96
+ drop(slot); b = Object.freeze({ kind: "owner", slot, id: selected.id, key: `owner:${++serial}:${slot}:${selected.id}`, generation: gen, element });
97
+ bySlot.set(slot, b); byKey.set(b.key, b);
98
+ }
99
+ result.push({ key: b.key, id: b.id, by: "human", region: slot.slice(3), layer: selected.manifest.layer, order: 0, paused: paused.get(slot) === b.id, visible: true, instance: null, element });
100
+ }
101
+ return fresh(body, gen) ? result : [];
102
+ },
103
+ binding(key, id) { const b = byKey.get(key); return b?.id === id && bindingCurrent(b) ? b : null; },
104
+ slotBinding(slot) { const b = bySlot.get(slot); return bindingCurrent(b) ? b : null; },
105
+ current: bindingCurrent,
106
+ async load(b, signal) {
107
+ if (!bindingCurrent(b) || signal?.aborted) return null;
108
+ let value; try { value = await readResource({ id: b.id, slot: b.slot }, signal); } catch { value = null; }
109
+ if (!bindingCurrent(b) || signal?.aborted) return null;
110
+ if (!value) { refuse(b); return null; }
111
+ return value;
112
+ },
113
+ pause(slot) { const selected = row(slot); if (selected?.status !== "available") return false; paused.set(slot, selected.id); notify(); return true; },
114
+ unpause(slot) { const selected = row(slot); if (selected?.status !== "available") return false; paused.delete(slot); notify(); return true; },
115
+ snapshot() {
116
+ const live = alive();
117
+ return { error: live ? error : null, rev, loading: live && metadata === null && error === null,
118
+ slots: Object.fromEntries(ALL_SLOTS.map(slot => { const selected = live ? metadata?.slots[slot] : null; return [slot, selected ? failed.get(slot) === selected.id ? { status: "unavailable", id: selected.id } : selected : { status: "unknown", id: null }]; })) };
119
+ },
120
+ dispose,
121
+ };
122
+ }