@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,157 @@
1
+ import type { AppearanceLimits } from "./web-appearance-limits.js";
2
+ import { type MediaKind } from "./web-image-meta.js";
3
+ import { type Theme } from "./web-theme.js";
4
+ import { type AmbientKind, type AmbientSpec } from "./web-ambient.js";
5
+ import { type WidgetData, type WidgetSlot, type WidgetSpec } from "./web-widget.js";
6
+ export declare const MOD_FORMAT = "agend-mod";
7
+ export declare const MOD_MAX_BYTES: number;
8
+ export declare const MOD_MAX_FILES = 128;
9
+ export declare const MOD_MAX_EFFECTS = 8;
10
+ /** A path inside a bundle: lowercase, no leading dot or slash, no `..` segment, no empty segment. */
11
+ export declare const MOD_PATH: RegExp;
12
+ export interface ModProblem {
13
+ path: string;
14
+ problem: string;
15
+ }
16
+ export interface ModManifest {
17
+ name: string;
18
+ version: string;
19
+ title: string;
20
+ description?: string;
21
+ author?: string;
22
+ requires?: {
23
+ agend: string;
24
+ };
25
+ contents: {
26
+ theme?: string;
27
+ identity?: string;
28
+ widgets?: Partial<Record<WidgetSlot, string>>;
29
+ /** #2117: `{ loop?, click? }`, each a set_web_ambient spec whose glyph pictures are `{ asset: <path in the bundle> }`. */
30
+ ambient?: string;
31
+ effects?: string[];
32
+ ownerCss?: {
33
+ css: string;
34
+ assets?: string[];
35
+ };
36
+ };
37
+ }
38
+ /** An effect entry's files (relative to its directory), as the effect runtime's checker takes them. */
39
+ export type EffectFiles = ReadonlyMap<string, Uint8Array>;
40
+ /** What the plan shows of an effect entry (the runtime's checker says it). */
41
+ export interface EffectSummary {
42
+ id: string;
43
+ title: string;
44
+ bytes: number;
45
+ regions: string[];
46
+ wants: string[];
47
+ params: string[];
48
+ }
49
+ /**
50
+ * The effect runtime's side, as the bundle needs it (CW1, Sol's B2): the pure entry checker and param resolver. Null
51
+ * while this fleet has no effect runtime: a bundle with effects is then refused (effects_unavailable).
52
+ */
53
+ export interface ModEffectChecker {
54
+ check(files: EffectFiles): {
55
+ ok: true;
56
+ summary: EffectSummary;
57
+ manifest: unknown;
58
+ } | {
59
+ ok: false;
60
+ problems: ModProblem[];
61
+ };
62
+ /** Resolve a placement's overrides against the entry's params: the non-default ones, or refused. */
63
+ params(manifest: unknown, overrides: unknown): {
64
+ ok: true;
65
+ overrides: Record<string, unknown>;
66
+ } | {
67
+ ok: false;
68
+ error: string;
69
+ };
70
+ }
71
+ export interface ModPicture {
72
+ path: string;
73
+ slot: "background" | "avatar" | "glyph";
74
+ id: string;
75
+ kind: MediaKind;
76
+ kept: Uint8Array;
77
+ }
78
+ export interface CheckedMod {
79
+ id: string;
80
+ manifest: ModManifest;
81
+ /** The raw file's size. */
82
+ bytes: number;
83
+ theme?: {
84
+ theme: Theme;
85
+ pictures: ModPicture[];
86
+ effects: Array<{
87
+ effect: string;
88
+ params: Record<string, unknown>;
89
+ }>;
90
+ };
91
+ identity?: {
92
+ tagline?: string;
93
+ bio?: string;
94
+ };
95
+ widgets: Partial<Record<WidgetSlot, {
96
+ spec: WidgetSpec;
97
+ data: WidgetData;
98
+ }>>;
99
+ /** #2117: the ambients (one per kind) and the glyph pictures they name. */
100
+ ambient?: {
101
+ specs: Partial<Record<AmbientKind, AmbientSpec>>;
102
+ pictures: ModPicture[];
103
+ };
104
+ effects: Array<{
105
+ path: string;
106
+ files: EffectFiles;
107
+ summary: EffectSummary;
108
+ manifest: unknown;
109
+ }>;
110
+ ownerCss?: {
111
+ text: string;
112
+ assets: Array<{
113
+ path: string;
114
+ id: string;
115
+ kind: MediaKind;
116
+ kept: Uint8Array;
117
+ }>;
118
+ };
119
+ }
120
+ export interface ModContext {
121
+ /** The running AgEnD version (`requires.agend` is checked against it); null: unknown, a `requires` is refused. */
122
+ agendVersion: string | null;
123
+ limits: AppearanceLimits;
124
+ effects: ModEffectChecker | null;
125
+ /**
126
+ * #2017: whether a theme's placements must name effects that play in chat. On for a new import or proposal (the
127
+ * default); off when an installed mod's file is read again — what was installed before the rule stays as it was.
128
+ */
129
+ placementRegions?: boolean;
130
+ }
131
+ /** Stable JSON: keys sorted at every level. */
132
+ export declare function canonicalJson(v: unknown): string;
133
+ /** A bundle's identity: the first 32 hex of the sha256 of its canonical manifest and sorted [path, sha256] list. */
134
+ export declare function modBundleId(manifest: unknown, files: Iterable<[string, string]>): string;
135
+ /**
136
+ * Parse and check a whole bundle. `text` is the file as uploaded (UTF-8 JSON). All or nothing: the first problems are
137
+ * returned (at most 20), and nothing in a refused bundle is ever used.
138
+ */
139
+ export declare function checkModBundle(text: string, ctx: ModContext): {
140
+ ok: true;
141
+ mod: CheckedMod;
142
+ } | {
143
+ ok: false;
144
+ problems: ModProblem[];
145
+ };
146
+ /** A file's entry for a bundle being built (export). */
147
+ export declare function modFile(bytes: Uint8Array): {
148
+ sha256: string;
149
+ b64: string;
150
+ };
151
+ /** The extension a picture or CSS asset is exported under. */
152
+ export declare function modAssetName(base: string, kind: MediaKind): string;
153
+ /**
154
+ * The effect runtime's checker (CW1: Sol's src/web-effect-bundle.ts and src/web-effect.ts) as a bundle uses it. Used
155
+ * once the fleet has an effect library to install into; until then the fleet passes null and effects are refused.
156
+ */
157
+ export declare function cw1EffectChecker(): ModEffectChecker;
@@ -0,0 +1,529 @@
1
+ /**
2
+ * #1629 r4 §4 (option A): a mod bundle — one JSON file, `<name>-<version>.agendmod.json`, at most 8 MiB, that carries a
3
+ * look: a theme (with its pictures), identity defaults (a card's tagline and bio — never card pictures), widget specs
4
+ * with their values, effect entries (CW1: Sol's runtime validates them), and a person's own CSS (with its assets).
5
+ * No zip: no extraction, no symlinks, no paths outside the file.
6
+ *
7
+ * Checking is pure and whole: closed schemas everywhere; every path matches MOD_PATH with no `..`; every file's sha256
8
+ * matches its bytes and every file is named by exactly one part; each part goes through its own validator (the theme's
9
+ * checkTheme and picture checks, web-widget.ts, the owner-CSS checker, the effect entry checker). Nothing is written
10
+ * here. The bundle's identity is the hash of its canonical manifest and file list — `version` is for people.
11
+ */
12
+ import { createHash } from "node:crypto";
13
+ import { compareVersions } from "./agent-whats-new.js";
14
+ import { checkEffectEntry } from "./web-effect-bundle.js";
15
+ import { resolveEffectParams } from "./web-effect.js";
16
+ import { checkOwnerCss, OWNER_CSS_MAX_BYTES } from "./web-owner-css.js";
17
+ import { MEDIA_EXT, sniffMedia, stripMetadata } from "./web-image-meta.js";
18
+ import { canonicalBio, canonicalTagline, canonicalText, checkTheme } from "./web-theme.js";
19
+ import { GLYPH_ASSET_LIMIT, prepareThemeAsset } from "./web-theme-store.js";
20
+ import { AMBIENT_KINDS, ambientKind, checkAmbient } from "./web-ambient.js";
21
+ import { checkWidgetData, checkWidgetSpec, WIDGET_SLOTS } from "./web-widget.js";
22
+ export const MOD_FORMAT = "agend-mod";
23
+ export const MOD_MAX_BYTES = 8 * 1024 * 1024;
24
+ export const MOD_MAX_FILES = 128;
25
+ export const MOD_MAX_EFFECTS = 8;
26
+ /** A path inside a bundle: lowercase, no leading dot or slash, no `..` segment, no empty segment. */
27
+ export const MOD_PATH = /^[a-z0-9][a-z0-9._/-]{0,127}$/;
28
+ const SLUG = /^[a-z0-9][a-z0-9-]{0,63}$/;
29
+ const SEMVER = /^(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})\.(0|[1-9]\d{0,5})$/;
30
+ const SHA256 = /^[0-9a-f]{64}$/;
31
+ const B64 = /^[A-Za-z0-9+/]*={0,2}$/;
32
+ /** Owner-CSS assets a bundle may carry (the owner-CSS store's own kinds). */
33
+ const CSS_ASSET_KINDS = new Set(["png", "jpeg", "webp", "gif", "woff2"]);
34
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;
35
+ const sha256 = (b) => createHash("sha256").update(b).digest("hex");
36
+ const hash32 = (b) => sha256(b).slice(0, 32);
37
+ const utf8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false });
38
+ function pathOk(p) {
39
+ return typeof p === "string" && MOD_PATH.test(p) && !p.split("/").some(seg => seg === "" || seg === "." || seg === "..") && !p.endsWith("/");
40
+ }
41
+ /** Stable JSON: keys sorted at every level. */
42
+ export function canonicalJson(v) {
43
+ const norm = (x) => Array.isArray(x) ? x.map(norm)
44
+ : x !== null && typeof x === "object" ? Object.fromEntries(Object.keys(x).sort().map(k => [k, norm(x[k])])) : x;
45
+ return JSON.stringify(norm(v));
46
+ }
47
+ /** A bundle's identity: the first 32 hex of the sha256 of its canonical manifest and sorted [path, sha256] list. */
48
+ export function modBundleId(manifest, files) {
49
+ const list = [...files].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
50
+ return sha256(canonicalJson({ manifest, files: list })).slice(0, 32);
51
+ }
52
+ function checkManifest(raw, ctx, bad) {
53
+ if (!isObj(raw)) {
54
+ bad("manifest", "an object");
55
+ return null;
56
+ }
57
+ const known = ["name", "version", "title", "description", "author", "requires", "contents"];
58
+ for (const k of Object.keys(raw))
59
+ if (!known.includes(k))
60
+ bad(`manifest.${k}`, "unknown key");
61
+ const m = {};
62
+ if (typeof raw.name === "string" && SLUG.test(raw.name))
63
+ m.name = raw.name;
64
+ else
65
+ bad("manifest.name", "a-z, 0-9 and - (1..64)");
66
+ if (typeof raw.version === "string" && SEMVER.test(raw.version))
67
+ m.version = raw.version;
68
+ else
69
+ bad("manifest.version", "MAJOR.MINOR.PATCH");
70
+ const title = canonicalText(raw.title, 1, 60);
71
+ if (title === null)
72
+ bad("manifest.title", "1..60 characters on one line");
73
+ else
74
+ m.title = title;
75
+ for (const [k, max] of [["description", 280], ["author", 60]]) {
76
+ if (raw[k] === undefined)
77
+ continue;
78
+ const t = canonicalText(raw[k], 1, max);
79
+ if (t === null)
80
+ bad(`manifest.${k}`, `1..${max} characters on one line`);
81
+ else
82
+ m[k] = t;
83
+ }
84
+ if (raw.requires !== undefined) {
85
+ const r = raw.requires;
86
+ const want = isObj(r) && Object.keys(r).length === 1 && typeof r.agend === "string" ? r.agend : null;
87
+ const min = want ? /^>=(\d+\.\d+\.\d+(?:-[0-9A-Za-z.]+)?)$/.exec(want) : null;
88
+ if (!min)
89
+ bad("manifest.requires", "{ agend: \">=MAJOR.MINOR.PATCH\" }");
90
+ else {
91
+ const cmp = ctx.agendVersion ? compareVersions(ctx.agendVersion, min[1]) : null;
92
+ if (cmp === null || cmp < 0)
93
+ bad("manifest.requires", `needs AgEnD ${want}; this fleet runs ${ctx.agendVersion ?? "an unknown version"}`);
94
+ else
95
+ m.requires = { agend: want };
96
+ }
97
+ }
98
+ const c = raw.contents;
99
+ if (!isObj(c)) {
100
+ bad("manifest.contents", "an object");
101
+ return null;
102
+ }
103
+ for (const k of Object.keys(c))
104
+ if (!["theme", "identity", "widgets", "ambient", "effects", "ownerCss"].includes(k))
105
+ bad(`manifest.contents.${k}`, "unknown key");
106
+ const contents = {};
107
+ for (const k of ["theme", "identity", "ambient"])
108
+ if (c[k] !== undefined) {
109
+ if (pathOk(c[k]))
110
+ contents[k] = c[k];
111
+ else
112
+ bad(`manifest.contents.${k}`, "a path in the bundle");
113
+ }
114
+ if (c.widgets !== undefined) {
115
+ if (!isObj(c.widgets))
116
+ bad("manifest.contents.widgets", "{ chat_header?, details?, sidebar? }");
117
+ else {
118
+ const w = {};
119
+ for (const [slot, p] of Object.entries(c.widgets)) {
120
+ if (!WIDGET_SLOTS.includes(slot))
121
+ bad(`manifest.contents.widgets.${slot}`, "chat_header, details or sidebar");
122
+ else if (!pathOk(p))
123
+ bad(`manifest.contents.widgets.${slot}`, "a path in the bundle");
124
+ else
125
+ w[slot] = p;
126
+ }
127
+ contents.widgets = w;
128
+ }
129
+ }
130
+ if (c.effects !== undefined) {
131
+ if (!Array.isArray(c.effects) || c.effects.length > MOD_MAX_EFFECTS || new Set(c.effects).size !== c.effects.length || !c.effects.every(pathOk))
132
+ bad("manifest.contents.effects", `at most ${MOD_MAX_EFFECTS} distinct directory paths`);
133
+ else
134
+ contents.effects = c.effects;
135
+ }
136
+ if (c.ownerCss !== undefined) {
137
+ const o = c.ownerCss;
138
+ if (!isObj(o) || Object.keys(o).some(k => k !== "css" && k !== "assets") || !pathOk(o.css) || (o.assets !== undefined && (!Array.isArray(o.assets) || !o.assets.every(pathOk) || new Set(o.assets).size !== o.assets.length)))
139
+ bad("manifest.contents.ownerCss", "{ css: path, assets?: [path] }");
140
+ else
141
+ contents.ownerCss = { css: o.css, ...(o.assets ? { assets: o.assets } : {}) };
142
+ }
143
+ if (!Object.keys(contents).length)
144
+ bad("manifest.contents", "names nothing");
145
+ m.contents = contents;
146
+ return m;
147
+ }
148
+ /**
149
+ * Parse and check a whole bundle. `text` is the file as uploaded (UTF-8 JSON). All or nothing: the first problems are
150
+ * returned (at most 20), and nothing in a refused bundle is ever used.
151
+ */
152
+ export function checkModBundle(text, ctx) {
153
+ const problems = [];
154
+ const bad = (path, problem) => { if (problems.length < 20)
155
+ problems.push({ path, problem }); };
156
+ const fail = () => ({ ok: false, problems });
157
+ const size = Buffer.byteLength(text, "utf8");
158
+ if (size > MOD_MAX_BYTES) {
159
+ bad("", `at most ${MOD_MAX_BYTES / 1024 / 1024} MiB`);
160
+ return fail();
161
+ }
162
+ let doc;
163
+ try {
164
+ doc = JSON.parse(text);
165
+ }
166
+ catch {
167
+ bad("", "not JSON");
168
+ return fail();
169
+ }
170
+ if (!isObj(doc)) {
171
+ bad("", "an object { format, v, manifest, files }");
172
+ return fail();
173
+ }
174
+ for (const k of Object.keys(doc))
175
+ if (!["format", "v", "manifest", "files"].includes(k))
176
+ bad(k, "unknown key");
177
+ if (doc.format !== MOD_FORMAT)
178
+ bad("format", `must be "${MOD_FORMAT}"`);
179
+ if (doc.v !== 1)
180
+ bad("v", "must be 1");
181
+ const manifest = checkManifest(doc.manifest, ctx, bad);
182
+ // Every file: a good path, its bytes, its sha256.
183
+ const files = new Map();
184
+ const shas = new Map();
185
+ if (!isObj(doc.files))
186
+ bad("files", "an object { path: { sha256, b64 } }");
187
+ else {
188
+ const entries = Object.entries(doc.files);
189
+ if (entries.length > MOD_MAX_FILES)
190
+ bad("files", `at most ${MOD_MAX_FILES}`);
191
+ else
192
+ for (const [p, f] of entries) {
193
+ if (!pathOk(p)) {
194
+ bad(`files.${String(p).slice(0, 80)}`, "a lowercase path: a-z 0-9 . _ - /, no .. or empty segment");
195
+ continue;
196
+ }
197
+ if (!isObj(f) || Object.keys(f).length !== 2 || typeof f.sha256 !== "string" || !SHA256.test(f.sha256) || typeof f.b64 !== "string" || !B64.test(f.b64) || f.b64.length % 4 !== 0) {
198
+ bad(`files.${p}`, "{ sha256, b64 }");
199
+ continue;
200
+ }
201
+ const bytes = Buffer.from(f.b64, "base64");
202
+ if (sha256(bytes) !== f.sha256) {
203
+ bad(`files.${p}`, "sha256 does not match its bytes");
204
+ continue;
205
+ }
206
+ files.set(p, bytes);
207
+ shas.set(p, f.sha256);
208
+ }
209
+ // A path that is both a file and a directory prefix of another would be two things.
210
+ for (const p of files.keys())
211
+ if ([...files.keys()].some(q => q.startsWith(`${p}/`)))
212
+ bad(`files.${p}`, "both a file and a directory");
213
+ }
214
+ if (problems.length || !manifest)
215
+ return fail();
216
+ const used = new Set();
217
+ const take = (p, where) => {
218
+ const b = files.get(p);
219
+ if (!b) {
220
+ bad(where, `no file ${p}`);
221
+ return null;
222
+ }
223
+ if (used.has(p)) {
224
+ bad(where, `${p} is already used by another part`);
225
+ return null;
226
+ }
227
+ used.add(p);
228
+ return b;
229
+ };
230
+ const json = (p, where) => {
231
+ const b = take(p, where);
232
+ if (!b)
233
+ return undefined;
234
+ try {
235
+ return JSON.parse(utf8.decode(b));
236
+ }
237
+ catch {
238
+ bad(where, `${p}: not UTF-8 JSON`);
239
+ return undefined;
240
+ }
241
+ };
242
+ const mod = { id: modBundleId(manifest, shas), manifest, bytes: size, widgets: {}, effects: [] };
243
+ const c = manifest.contents;
244
+ // Effects first: the theme's placements name them.
245
+ const effectPaths = new Set(c.effects ?? []);
246
+ if (c.effects?.length) {
247
+ if (!ctx.effects)
248
+ bad("manifest.contents.effects", "effects_unavailable: this fleet has no effect runtime yet");
249
+ else
250
+ for (const dir of c.effects) {
251
+ const entry = new Map();
252
+ for (const [p, b] of files)
253
+ if (p.startsWith(`${dir}/`)) {
254
+ entry.set(p.slice(dir.length + 1), b);
255
+ used.add(p);
256
+ }
257
+ if (!entry.size) {
258
+ bad(`effects.${dir}`, "no files under it");
259
+ continue;
260
+ }
261
+ const r = ctx.effects.check(entry);
262
+ if (!r.ok) {
263
+ for (const q of r.problems)
264
+ bad(`effects.${dir}/${q.path}`, q.problem);
265
+ continue;
266
+ }
267
+ mod.effects.push({ path: dir, files: entry, summary: r.summary, manifest: r.manifest });
268
+ }
269
+ }
270
+ if (c.theme) {
271
+ const raw = json(c.theme, "manifest.contents.theme");
272
+ if (raw !== undefined) {
273
+ if (!isObj(raw))
274
+ bad("theme", "an object");
275
+ else {
276
+ const { effects: placed, ...look } = raw;
277
+ if (look.card !== undefined)
278
+ bad("theme.card", "a card travels as identity (tagline, bio) — never in the theme, and its pictures never in a bundle");
279
+ // Pictures are named by path in a bundle: each is checked as an upload to its slot, then named by its id.
280
+ const pictures = [];
281
+ const picture = (p, slot, where) => {
282
+ if (!pathOk(p)) {
283
+ bad(where, "a path in the bundle");
284
+ return null;
285
+ }
286
+ const b = take(p, where);
287
+ if (!b)
288
+ return null;
289
+ const r = prepareThemeAsset(slot, b, ctx.limits);
290
+ if (!r.ok) {
291
+ bad(where, `${r.error}${r.detail ? `: ${r.detail}` : ""}`);
292
+ return null;
293
+ }
294
+ if (pictures.some(x => x.id === r.id)) {
295
+ bad(where, "the same picture as another slot's: a picture holds one slot");
296
+ return null;
297
+ }
298
+ pictures.push({ path: p, slot, id: r.id, kind: r.kind, kept: r.kept });
299
+ return r.id;
300
+ };
301
+ const input = { ...look };
302
+ if (isObj(look.background)) {
303
+ const id = picture(look.background.image, "background", "theme.background.image");
304
+ if (id)
305
+ input.background = { ...look.background, image: id };
306
+ }
307
+ if (look.avatar !== undefined) {
308
+ const id = picture(look.avatar, "avatar", "theme.avatar");
309
+ if (id)
310
+ input.avatar = id;
311
+ }
312
+ const checked = checkTheme(input, { assets: new Set(pictures.map(p => p.id)) });
313
+ if (!checked.ok)
314
+ for (const e of checked.errors)
315
+ bad(`theme.${e.path}`, e.problem);
316
+ const effects = [];
317
+ if (placed !== undefined) {
318
+ if (!Array.isArray(placed) || placed.length > 2)
319
+ bad("theme.effects", "at most 2 [{ effect, params? }]");
320
+ else
321
+ placed.forEach((p, i) => {
322
+ const where = `theme.effects.${i}`;
323
+ if (!isObj(p) || Object.keys(p).some(k => k !== "effect" && k !== "params") || typeof p.effect !== "string") {
324
+ bad(where, "{ effect: path, params? }");
325
+ return;
326
+ }
327
+ if (!effectPaths.has(p.effect)) {
328
+ bad(where, `${p.effect} is not one of this bundle's effects`);
329
+ return;
330
+ }
331
+ const entry = mod.effects.find(e => e.path === p.effect);
332
+ if (!entry || !ctx.effects)
333
+ return; // its own problem is reported already
334
+ // #2017: a chat placement needs an effect that plays in chat. A non-chat effect may still come as a library
335
+ // entry (contents.effects) without being placed.
336
+ if (ctx.placementRegions !== false && !entry.summary.regions.includes("chat")) {
337
+ bad(where, `effect_region: ${p.effect}'s regions do not include chat`);
338
+ return;
339
+ }
340
+ const r = ctx.effects.params(entry.manifest, p.params ?? {});
341
+ if (!r.ok) {
342
+ bad(`${where}.params`, r.error);
343
+ return;
344
+ }
345
+ if (effects.some(e => e.effect === p.effect)) {
346
+ bad(where, "placed twice");
347
+ return;
348
+ }
349
+ effects.push({ effect: p.effect, params: r.overrides });
350
+ });
351
+ }
352
+ if (checked.ok)
353
+ mod.theme = { theme: checked.theme, pictures, effects };
354
+ }
355
+ }
356
+ }
357
+ if (c.identity) {
358
+ const raw = json(c.identity, "manifest.contents.identity");
359
+ if (raw !== undefined) {
360
+ if (!isObj(raw) || Object.keys(raw).some(k => k !== "tagline" && k !== "bio") || !Object.keys(raw).length)
361
+ bad("identity", "{ tagline?, bio? }");
362
+ else {
363
+ const id = {};
364
+ if (raw.tagline !== undefined) {
365
+ const t = canonicalTagline(raw.tagline);
366
+ if (t === null)
367
+ bad("identity.tagline", "one line, 1..60 characters");
368
+ else
369
+ id.tagline = t;
370
+ }
371
+ if (raw.bio !== undefined) {
372
+ const t = canonicalBio(raw.bio);
373
+ if (t === null)
374
+ bad("identity.bio", "1..280 characters, at most 3 line breaks");
375
+ else
376
+ id.bio = t;
377
+ }
378
+ mod.identity = id;
379
+ }
380
+ }
381
+ }
382
+ for (const [slot, p] of Object.entries(c.widgets ?? {})) {
383
+ const raw = json(p, `manifest.contents.widgets.${slot}`);
384
+ if (raw === undefined)
385
+ continue;
386
+ if (!isObj(raw) || Object.keys(raw).length !== 2 || !("spec" in raw) || !("data" in raw)) {
387
+ bad(`widgets.${slot}`, "{ spec, data }");
388
+ continue;
389
+ }
390
+ const spec = checkWidgetSpec(raw.spec, slot);
391
+ if (!spec.ok) {
392
+ for (const e of spec.errors)
393
+ bad(`widgets.${slot}.${e.path}`, e.problem);
394
+ continue;
395
+ }
396
+ const data = checkWidgetData(raw.data, spec.value);
397
+ if (!data.ok) {
398
+ for (const e of data.errors)
399
+ bad(`widgets.${slot}.${e.path}`, e.problem);
400
+ continue;
401
+ }
402
+ mod.widgets[slot] = { spec: spec.value, data: { ...data.value } };
403
+ }
404
+ // #2117: the ambients, their glyph pictures named by path (each checked as an upload to the glyph slot).
405
+ if (c.ambient) {
406
+ const raw = json(c.ambient, "manifest.contents.ambient");
407
+ if (raw !== undefined) {
408
+ if (!isObj(raw) || !Object.keys(raw).length || Object.keys(raw).some(k => !AMBIENT_KINDS.includes(k)))
409
+ bad("ambient", "{ loop?, click? }");
410
+ else {
411
+ const pictures = [];
412
+ const specs = {};
413
+ for (const kind of AMBIENT_KINDS) {
414
+ const s = raw[kind];
415
+ if (s === undefined)
416
+ continue;
417
+ if (!isObj(s)) {
418
+ bad(`ambient.${kind}`, "a set_web_ambient spec");
419
+ continue;
420
+ }
421
+ const glyphs = Array.isArray(s.glyphs) ? s.glyphs.map((g, i) => {
422
+ if (!isObj(g))
423
+ return g;
424
+ const where = `ambient.${kind}.glyphs.${i}.asset`;
425
+ if (Object.keys(g).length !== 1 || !pathOk(g.asset)) {
426
+ bad(where, "a path in the bundle");
427
+ return g;
428
+ }
429
+ const had = pictures.find(p => p.path === g.asset);
430
+ if (had)
431
+ return { asset: had.id };
432
+ const b = take(g.asset, where);
433
+ if (!b)
434
+ return g;
435
+ const r = prepareThemeAsset("glyph", b, ctx.limits);
436
+ if (!r.ok) {
437
+ bad(where, `${r.error}${r.detail ? `: ${r.detail}` : ""}`);
438
+ return g;
439
+ }
440
+ pictures.push({ path: g.asset, slot: "glyph", id: r.id, kind: r.kind, kept: r.kept });
441
+ return { asset: r.id };
442
+ }) : s.glyphs;
443
+ const checked = checkAmbient({ ...s, glyphs }, { glyphAsset: id => pictures.some(p => p.id === id) });
444
+ if (!checked.ok) {
445
+ for (const e of checked.errors)
446
+ bad(`ambient.${kind}.${e.path}`, e.problem);
447
+ continue;
448
+ }
449
+ if (ambientKind(checked.value.preset) !== kind) {
450
+ bad(`ambient.${kind}.preset`, kind === "click" ? "burst-on-click" : "fall, rise or twinkle");
451
+ continue;
452
+ }
453
+ specs[kind] = checked.value;
454
+ }
455
+ if (pictures.length > GLYPH_ASSET_LIMIT.files)
456
+ bad("ambient", `at most ${GLYPH_ASSET_LIMIT.files} glyph pictures`);
457
+ else if (Object.keys(specs).length)
458
+ mod.ambient = { specs, pictures };
459
+ }
460
+ }
461
+ }
462
+ if (c.ownerCss) {
463
+ const assets = [];
464
+ for (const p of c.ownerCss.assets ?? []) {
465
+ const b = take(p, `ownerCss.assets.${p}`);
466
+ if (!b)
467
+ continue;
468
+ const kind = sniffMedia(b);
469
+ const kept = kind && CSS_ASSET_KINDS.has(kind) ? stripMetadata(b, kind) : null;
470
+ if (!kind || !kept) {
471
+ bad(`ownerCss.assets.${p}`, "png, webp, jpeg, gif or woff2");
472
+ continue;
473
+ }
474
+ assets.push({ path: p, id: hash32(kept), kind, kept });
475
+ }
476
+ const cssBytes = take(c.ownerCss.css, "manifest.contents.ownerCss.css");
477
+ if (cssBytes) {
478
+ let text = null;
479
+ try {
480
+ text = utf8.decode(cssBytes);
481
+ }
482
+ catch {
483
+ bad("ownerCss.css", "not UTF-8");
484
+ }
485
+ if (text !== null) {
486
+ if (cssBytes.length > OWNER_CSS_MAX_BYTES)
487
+ bad("ownerCss.css", `at most ${OWNER_CSS_MAX_BYTES / 1024} KiB`);
488
+ else {
489
+ // url("asset:<id>") names one of the bundle's CSS assets by the id it will have (the hash of its kept bytes).
490
+ const checked = checkOwnerCss(text, new Set(assets.map(a => a.id)));
491
+ if (!checked.ok)
492
+ bad("ownerCss.css", `${checked.error.problem}${checked.error.detail ? `: ${checked.error.detail}` : ""}`);
493
+ else
494
+ mod.ownerCss = { text, assets };
495
+ }
496
+ }
497
+ }
498
+ }
499
+ for (const p of files.keys())
500
+ if (!used.has(p))
501
+ bad(`files.${p}`, "not used by any part");
502
+ return problems.length ? fail() : { ok: true, mod };
503
+ }
504
+ /** A file's entry for a bundle being built (export). */
505
+ export function modFile(bytes) {
506
+ return { sha256: sha256(bytes), b64: Buffer.from(bytes).toString("base64") };
507
+ }
508
+ /** The extension a picture or CSS asset is exported under. */
509
+ export function modAssetName(base, kind) { return `${base}.${MEDIA_EXT[kind]}`; }
510
+ /**
511
+ * The effect runtime's checker (CW1: Sol's src/web-effect-bundle.ts and src/web-effect.ts) as a bundle uses it. Used
512
+ * once the fleet has an effect library to install into; until then the fleet passes null and effects are refused.
513
+ */
514
+ export function cw1EffectChecker() {
515
+ return {
516
+ check(files) {
517
+ const r = checkEffectEntry(files);
518
+ if (!r.ok)
519
+ return { ok: false, problems: r.problems };
520
+ const m = r.manifest;
521
+ return { ok: true, manifest: m, summary: { id: r.id, title: m.title, bytes: r.bytes, regions: [...m.regions], wants: [...m.wants], params: Object.keys(m.params ?? {}) } };
522
+ },
523
+ params(manifest, overrides) {
524
+ const r = resolveEffectParams(manifest, overrides);
525
+ return r.ok ? { ok: true, overrides: { ...r.overrides } } : { ok: false, error: r.error };
526
+ },
527
+ };
528
+ }
529
+ //# sourceMappingURL=web-mod-bundle.js.map