@songsid/agend 2.2.0 → 2.2.5

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 (447) 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 +10 -0
  80. package/dist/daemon.js +327 -31
  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 +100 -8
  122. package/dist/locale.js.map +1 -1
  123. package/dist/ls-attach-resolve.d.ts +95 -0
  124. package/dist/ls-attach-resolve.js +174 -0
  125. package/dist/ls-attach-resolve.js.map +1 -0
  126. package/dist/memory-hogs.d.ts +27 -0
  127. package/dist/memory-hogs.js +124 -0
  128. package/dist/memory-hogs.js.map +1 -0
  129. package/dist/needs-you-hub.d.ts +4 -0
  130. package/dist/needs-you-hub.js +31 -6
  131. package/dist/needs-you-hub.js.map +1 -1
  132. package/dist/needs-you.d.ts +1 -13
  133. package/dist/needs-you.js +3 -37
  134. package/dist/needs-you.js.map +1 -1
  135. package/dist/outbound-handlers.d.ts +15 -0
  136. package/dist/outbound-handlers.js +152 -11
  137. package/dist/outbound-handlers.js.map +1 -1
  138. package/dist/outbound-schemas.d.ts +228 -4
  139. package/dist/outbound-schemas.js +147 -1
  140. package/dist/outbound-schemas.js.map +1 -1
  141. package/dist/public-web-gateway.js +21 -1
  142. package/dist/public-web-gateway.js.map +1 -1
  143. package/dist/public-web-link.d.ts +9 -0
  144. package/dist/public-web-link.js +8 -0
  145. package/dist/public-web-link.js.map +1 -1
  146. package/dist/quickstart-api.d.ts +10 -1
  147. package/dist/quickstart-api.js +12 -4
  148. package/dist/quickstart-api.js.map +1 -1
  149. package/dist/reply-buttons-controller.d.ts +4 -0
  150. package/dist/reply-buttons-controller.js +2 -2
  151. package/dist/reply-buttons-controller.js.map +1 -1
  152. package/dist/repo-worktree-guard.d.ts +36 -0
  153. package/dist/repo-worktree-guard.js +143 -0
  154. package/dist/repo-worktree-guard.js.map +1 -0
  155. package/dist/restart-progress.d.ts +65 -1
  156. package/dist/restart-progress.js +236 -10
  157. package/dist/restart-progress.js.map +1 -1
  158. package/dist/rollout-index.d.ts +5 -0
  159. package/dist/rollout-index.js +26 -5
  160. package/dist/rollout-index.js.map +1 -1
  161. package/dist/scheduler/scheduler.d.ts +70 -1
  162. package/dist/scheduler/scheduler.js +256 -17
  163. package/dist/scheduler/scheduler.js.map +1 -1
  164. package/dist/service-installer.d.ts +2 -1
  165. package/dist/service-installer.js +18 -3
  166. package/dist/service-installer.js.map +1 -1
  167. package/dist/settings-api.d.ts +23 -0
  168. package/dist/settings-api.js +233 -2
  169. package/dist/settings-api.js.map +1 -1
  170. package/dist/settings-change.js +112 -0
  171. package/dist/settings-change.js.map +1 -1
  172. package/dist/settings-effect.js +32 -2
  173. package/dist/settings-effect.js.map +1 -1
  174. package/dist/settings-http-confirmation.js +5 -0
  175. package/dist/settings-http-confirmation.js.map +1 -1
  176. package/dist/tmux-manager.d.ts +5 -0
  177. package/dist/tmux-manager.js +16 -0
  178. package/dist/tmux-manager.js.map +1 -1
  179. package/dist/tool-permissions.d.ts +4 -6
  180. package/dist/tool-permissions.js +100 -2
  181. package/dist/tool-permissions.js.map +1 -1
  182. package/dist/topic-commands.d.ts +17 -7
  183. package/dist/topic-commands.js +39 -21
  184. package/dist/topic-commands.js.map +1 -1
  185. package/dist/topic-link.d.ts +128 -0
  186. package/dist/topic-link.js +269 -0
  187. package/dist/topic-link.js.map +1 -0
  188. package/dist/types.d.ts +61 -1
  189. package/dist/ui/app-effects.js +245 -0
  190. package/dist/ui/chat-ambient.js +307 -0
  191. package/dist/ui/chat-effect-posters.js +42 -0
  192. package/dist/ui/chat-effects.js +160 -0
  193. package/dist/ui/chat-live-replies.js +58 -0
  194. package/dist/ui/chat-render.js +25 -7
  195. package/dist/ui/chat-store.js +41 -13
  196. package/dist/ui/chat-strings.js +86 -2
  197. package/dist/ui/chat-thread.js +204 -37
  198. package/dist/ui/chat-tour.js +1 -1
  199. package/dist/ui/effect-trial-controller.js +124 -0
  200. package/dist/ui/effect-trial-offer.js +31 -0
  201. package/dist/ui/effect-trial-panel.js +40 -0
  202. package/dist/ui/fleet-cache.js +23 -1
  203. package/dist/ui/fleet-canvas-layout.js +111 -0
  204. package/dist/ui/fleet-canvas.js +525 -0
  205. package/dist/ui/fleet-org.js +27 -12
  206. package/dist/ui/fleet-traffic.js +343 -0
  207. package/dist/ui/fleet-usage.js +401 -0
  208. package/dist/ui/image-lightbox.js +1 -1
  209. package/dist/ui/panel-chat.js +252 -58
  210. package/dist/ui/panel-details.js +20 -6
  211. package/dist/ui/panel-fleet.js +45 -19
  212. package/dist/ui/panel-log.js +6 -6
  213. package/dist/ui/panel-needs.js +3 -3
  214. package/dist/ui/panel-settings.js +58 -13
  215. package/dist/ui/preview-panel.js +25 -9
  216. package/dist/ui/preview.js +3 -2
  217. package/dist/ui/settings-appearance.js +349 -0
  218. package/dist/ui/settings-catalog.js +92 -0
  219. package/dist/ui/settings-dialogs.js +40 -12
  220. package/dist/ui/settings-effects.js +202 -0
  221. package/dist/ui/settings-guests.js +117 -0
  222. package/dist/ui/settings-learn.js +25 -0
  223. package/dist/ui/settings-model.js +15 -6
  224. package/dist/ui/settings-mods.js +271 -0
  225. package/dist/ui/settings-owner-effects.js +80 -0
  226. package/dist/ui/settings-strings.js +335 -10
  227. package/dist/ui/settings-web-authority.js +91 -0
  228. package/dist/ui/shared/agend-auth.js +28 -4
  229. package/dist/ui/shared/agent-widget.js +248 -0
  230. package/dist/ui/shared/app-i18n.js +6 -2
  231. package/dist/ui/shared/app-prefs.js +34 -13
  232. package/dist/ui/shared/app-route.js +42 -2
  233. package/dist/ui/shared/app-session.js +3 -1
  234. package/dist/ui/shared/app-shell.js +119 -41
  235. package/dist/ui/shared/app-store.js +28 -1
  236. package/dist/ui/shared/app-stream.js +14 -7
  237. package/dist/ui/shared/app-themes.js +206 -0
  238. package/dist/ui/shared/app.css +566 -5
  239. package/dist/ui/shared/app.js +23 -10
  240. package/dist/ui/shared/card-strings.js +32 -0
  241. package/dist/ui/shared/effect-app-runtime.js +297 -0
  242. package/dist/ui/shared/effect-baseline.js +64 -0
  243. package/dist/ui/shared/effect-chat-runtime.js +167 -0
  244. package/dist/ui/shared/effect-cursor.js +125 -0
  245. package/dist/ui/shared/effect-frame.js +146 -0
  246. package/dist/ui/shared/effect-geometry.js +137 -0
  247. package/dist/ui/shared/effect-host-style.js +10 -0
  248. package/dist/ui/shared/effect-owner-regions.js +74 -0
  249. package/dist/ui/shared/effect-owner-source.js +122 -0
  250. package/dist/ui/shared/effect-policy.js +151 -0
  251. package/dist/ui/shared/effect-poster-reader.js +98 -0
  252. package/dist/ui/shared/effect-posters.js +117 -0
  253. package/dist/ui/shared/effect-profiler.js +184 -0
  254. package/dist/ui/shared/effect-profiles.js +65 -0
  255. package/dist/ui/shared/effect-registry.js +543 -0
  256. package/dist/ui/shared/effect-runtime-loader.js +234 -0
  257. package/dist/ui/shared/effect-safety.js +153 -0
  258. package/dist/ui/shared/effect-stock-snapshot.js +43 -0
  259. package/dist/ui/shared/effect-stock-trust.js +217 -0
  260. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  261. package/dist/ui/shared/effect-trial-source.js +103 -0
  262. package/dist/ui/shared/effect-trial-stage.js +170 -0
  263. package/dist/ui/shared/effect-trial.css +40 -0
  264. package/dist/ui/shared/fx-motion.js +67 -0
  265. package/dist/ui/shared/header-tools.js +1 -1
  266. package/dist/ui/shared/identity-card.js +273 -0
  267. package/dist/ui/shared/identity-color.js +261 -0
  268. package/dist/ui/shared/instance-nav.js +215 -41
  269. package/dist/ui/shared/owner-css.js +250 -0
  270. package/dist/ui/shared/owner-effect-prefs.js +117 -0
  271. package/dist/ui/shared/panel-view.js +103 -10
  272. package/dist/ui/shared/signin.js +2 -0
  273. package/dist/ui/shared/tokens.css +9 -3
  274. package/dist/ui/shared/ui-dialog.js +1 -1
  275. package/dist/ui/shared/ui-icons.js +3 -0
  276. package/dist/ui/shared/ui-menu.js +1 -1
  277. package/dist/ui/shared/ui-toast.js +1 -1
  278. package/dist/ui/shared/usage-dialog.js +22 -2
  279. package/dist/ui/shared/view-strings.js +98 -2
  280. package/dist/ui/shared/web-authorize.js +151 -0
  281. package/dist/ui/signin.html +1 -0
  282. package/dist/ui/web-terminal/terminal.css +4 -4
  283. package/dist/usage/providers.d.ts +28 -0
  284. package/dist/usage/providers.js +126 -36
  285. package/dist/usage/providers.js.map +1 -1
  286. package/dist/usage-report.d.ts +158 -0
  287. package/dist/usage-report.js +226 -0
  288. package/dist/usage-report.js.map +1 -0
  289. package/dist/usage-rollup.d.ts +51 -0
  290. package/dist/usage-rollup.js +168 -0
  291. package/dist/usage-rollup.js.map +1 -0
  292. package/dist/view-api.d.ts +68 -0
  293. package/dist/view-api.js +249 -8
  294. package/dist/view-api.js.map +1 -1
  295. package/dist/web-ambient.d.ts +72 -0
  296. package/dist/web-ambient.js +161 -0
  297. package/dist/web-ambient.js.map +1 -0
  298. package/dist/web-api.d.ts +117 -7
  299. package/dist/web-api.js +1283 -70
  300. package/dist/web-api.js.map +1 -1
  301. package/dist/web-appearance-limits.d.ts +82 -0
  302. package/dist/web-appearance-limits.js +83 -0
  303. package/dist/web-appearance-limits.js.map +1 -0
  304. package/dist/web-appearance-policy.d.ts +64 -0
  305. package/dist/web-appearance-policy.js +87 -0
  306. package/dist/web-appearance-policy.js.map +1 -0
  307. package/dist/web-appearance-tools.d.ts +53 -0
  308. package/dist/web-appearance-tools.js +124 -0
  309. package/dist/web-appearance-tools.js.map +1 -0
  310. package/dist/web-appearance-view.d.ts +124 -0
  311. package/dist/web-appearance-view.js +278 -0
  312. package/dist/web-appearance-view.js.map +1 -0
  313. package/dist/web-appearance.d.ts +93 -0
  314. package/dist/web-appearance.js +373 -0
  315. package/dist/web-appearance.js.map +1 -0
  316. package/dist/web-asset-parts.d.ts +93 -0
  317. package/dist/web-asset-parts.js +133 -0
  318. package/dist/web-asset-parts.js.map +1 -0
  319. package/dist/web-auth.js +20 -2
  320. package/dist/web-auth.js.map +1 -1
  321. package/dist/web-card.d.ts +110 -0
  322. package/dist/web-card.js +266 -0
  323. package/dist/web-card.js.map +1 -0
  324. package/dist/web-channel-echo.d.ts +7 -1
  325. package/dist/web-channel-echo.js +6 -2
  326. package/dist/web-channel-echo.js.map +1 -1
  327. package/dist/web-chat-history.d.ts +63 -0
  328. package/dist/web-chat-history.js +109 -6
  329. package/dist/web-chat-history.js.map +1 -1
  330. package/dist/web-commands.d.ts +1 -0
  331. package/dist/web-effect-bootstrap.d.ts +12 -0
  332. package/dist/web-effect-bootstrap.js +49 -0
  333. package/dist/web-effect-bootstrap.js.map +1 -0
  334. package/dist/web-effect-bundle.d.ts +28 -0
  335. package/dist/web-effect-bundle.js +171 -0
  336. package/dist/web-effect-bundle.js.map +1 -0
  337. package/dist/web-effect-canonical.d.ts +8 -0
  338. package/dist/web-effect-canonical.js +27 -0
  339. package/dist/web-effect-canonical.js.map +1 -0
  340. package/dist/web-effect-library.d.ts +114 -0
  341. package/dist/web-effect-library.js +530 -0
  342. package/dist/web-effect-library.js.map +1 -0
  343. package/dist/web-effect-playback.d.ts +30 -0
  344. package/dist/web-effect-playback.js +71 -0
  345. package/dist/web-effect-playback.js.map +1 -0
  346. package/dist/web-effect-poster.d.ts +8 -0
  347. package/dist/web-effect-poster.js +52 -0
  348. package/dist/web-effect-poster.js.map +1 -0
  349. package/dist/web-effect-profiles.d.ts +118 -0
  350. package/dist/web-effect-profiles.js +180 -0
  351. package/dist/web-effect-profiles.js.map +1 -0
  352. package/dist/web-effect-service.d.ts +93 -0
  353. package/dist/web-effect-service.js +335 -0
  354. package/dist/web-effect-service.js.map +1 -0
  355. package/dist/web-effect-tools.d.ts +48 -0
  356. package/dist/web-effect-tools.js +129 -0
  357. package/dist/web-effect-tools.js.map +1 -0
  358. package/dist/web-effect-trials.d.ts +86 -0
  359. package/dist/web-effect-trials.js +204 -0
  360. package/dist/web-effect-trials.js.map +1 -0
  361. package/dist/web-effect-upload.d.ts +27 -0
  362. package/dist/web-effect-upload.js +185 -0
  363. package/dist/web-effect-upload.js.map +1 -0
  364. package/dist/web-effect-worker.d.ts +8 -0
  365. package/dist/web-effect-worker.js +170 -0
  366. package/dist/web-effect-worker.js.map +1 -0
  367. package/dist/web-effect.d.ts +103 -0
  368. package/dist/web-effect.js +153 -0
  369. package/dist/web-effect.js.map +1 -0
  370. package/dist/web-guest-access.d.ts +125 -0
  371. package/dist/web-guest-access.js +234 -0
  372. package/dist/web-guest-access.js.map +1 -0
  373. package/dist/web-guest-rooms.d.ts +82 -0
  374. package/dist/web-guest-rooms.js +135 -0
  375. package/dist/web-guest-rooms.js.map +1 -0
  376. package/dist/web-identity-color.d.ts +87 -0
  377. package/dist/web-identity-color.js +209 -0
  378. package/dist/web-identity-color.js.map +1 -0
  379. package/dist/web-identity-palette.d.ts +113 -0
  380. package/dist/web-identity-palette.js +84 -0
  381. package/dist/web-identity-palette.js.map +1 -0
  382. package/dist/web-image-meta.d.ts +38 -0
  383. package/dist/web-image-meta.js +262 -0
  384. package/dist/web-image-meta.js.map +1 -0
  385. package/dist/web-login.d.ts +47 -0
  386. package/dist/web-login.js +115 -0
  387. package/dist/web-login.js.map +1 -1
  388. package/dist/web-mod-agent.d.ts +50 -0
  389. package/dist/web-mod-agent.js +207 -0
  390. package/dist/web-mod-agent.js.map +1 -0
  391. package/dist/web-mod-bundle.d.ts +157 -0
  392. package/dist/web-mod-bundle.js +529 -0
  393. package/dist/web-mod-bundle.js.map +1 -0
  394. package/dist/web-mod-export.d.ts +68 -0
  395. package/dist/web-mod-export.js +100 -0
  396. package/dist/web-mod-export.js.map +1 -0
  397. package/dist/web-mod-store.d.ts +289 -0
  398. package/dist/web-mod-store.js +638 -0
  399. package/dist/web-mod-store.js.map +1 -0
  400. package/dist/web-org.d.ts +3 -3
  401. package/dist/web-org.js +11 -17
  402. package/dist/web-org.js.map +1 -1
  403. package/dist/web-owner-css-store.d.ts +222 -0
  404. package/dist/web-owner-css-store.js +440 -0
  405. package/dist/web-owner-css-store.js.map +1 -0
  406. package/dist/web-owner-css.d.ts +58 -0
  407. package/dist/web-owner-css.js +552 -0
  408. package/dist/web-owner-css.js.map +1 -0
  409. package/dist/web-prefs.d.ts +62 -0
  410. package/dist/web-prefs.js +232 -36
  411. package/dist/web-prefs.js.map +1 -1
  412. package/dist/web-preview.d.ts +15 -3
  413. package/dist/web-preview.js +28 -9
  414. package/dist/web-preview.js.map +1 -1
  415. package/dist/web-returning-device.d.ts +41 -0
  416. package/dist/web-returning-device.js +57 -5
  417. package/dist/web-returning-device.js.map +1 -1
  418. package/dist/web-session-authorization.d.ts +132 -0
  419. package/dist/web-session-authorization.js +193 -0
  420. package/dist/web-session-authorization.js.map +1 -0
  421. package/dist/web-session.d.ts +70 -10
  422. package/dist/web-session.js +137 -22
  423. package/dist/web-session.js.map +1 -1
  424. package/dist/web-settings-patch.d.ts +67 -2
  425. package/dist/web-settings-patch.js +196 -1
  426. package/dist/web-settings-patch.js.map +1 -1
  427. package/dist/web-settings-tools.d.ts +89 -0
  428. package/dist/web-settings-tools.js +273 -0
  429. package/dist/web-settings-tools.js.map +1 -0
  430. package/dist/web-shell-routes.d.ts +2 -2
  431. package/dist/web-shell-routes.js +2 -2
  432. package/dist/web-shell-routes.js.map +1 -1
  433. package/dist/web-theme-store.d.ts +257 -0
  434. package/dist/web-theme-store.js +627 -0
  435. package/dist/web-theme-store.js.map +1 -0
  436. package/dist/web-theme.d.ts +123 -0
  437. package/dist/web-theme.js +416 -0
  438. package/dist/web-theme.js.map +1 -0
  439. package/dist/web-upload.d.ts +13 -0
  440. package/dist/web-upload.js +39 -3
  441. package/dist/web-upload.js.map +1 -1
  442. package/dist/web-widget.d.ts +72 -0
  443. package/dist/web-widget.js +245 -0
  444. package/dist/web-widget.js.map +1 -0
  445. package/dist/workflow-templates/default.md +1 -1
  446. package/package.json +1 -1
  447. package/templates/systemd.service.ejs +8 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * #1629 r4.1 Q3 (b): the identity card's upload limits are fleet configuration (`web.appearance`), under hard bounds
3
+ * no configuration passes. r4's numbers are the defaults. A value outside its bound is clamped and said so (the config
4
+ * validator's warnings: `agend doctor`, the fleet log at startup, Settings); one out-of-range number never stops the
5
+ * fleet. A limit applies to new uploads only: nothing stored is ever checked again or deleted because a limit moved.
6
+ */
7
+ export interface CardPictureLimit {
8
+ maxWidth: number;
9
+ maxHeight: number;
10
+ maxBytes: number;
11
+ }
12
+ export interface AppearanceLimits {
13
+ portrait: CardPictureLimit;
14
+ banner: CardPictureLimit;
15
+ /** Card and theme pictures an instance's agent may hold (r1 §4, r4 §1). */
16
+ quota: {
17
+ files: number;
18
+ bytes: number;
19
+ };
20
+ }
21
+ export interface AppearanceLimitsConfig {
22
+ portrait?: {
23
+ max_width?: number;
24
+ max_height?: number;
25
+ max_kib?: number;
26
+ };
27
+ banner?: {
28
+ max_width?: number;
29
+ max_height?: number;
30
+ max_kib?: number;
31
+ };
32
+ instance_quota?: {
33
+ files?: number;
34
+ mib?: number;
35
+ };
36
+ }
37
+ /** r4 §1's numbers, in `web.appearance`'s own units. */
38
+ export declare const APPEARANCE_DEFAULTS: {
39
+ readonly portrait: {
40
+ readonly max_width: 1024;
41
+ readonly max_height: 1536;
42
+ readonly max_kib: 1536;
43
+ };
44
+ readonly banner: {
45
+ readonly max_width: 1600;
46
+ readonly max_height: 600;
47
+ readonly max_kib: 768;
48
+ };
49
+ readonly instance_quota: {
50
+ readonly files: 8;
51
+ readonly mib: 4;
52
+ };
53
+ };
54
+ /** [floor, ceiling] per setting (r4.1 Q3 (b)). */
55
+ export declare const APPEARANCE_BOUNDS: {
56
+ readonly portrait: {
57
+ readonly max_width: readonly [64, 2048];
58
+ readonly max_height: readonly [64, 3072];
59
+ readonly max_kib: readonly [32, 4096];
60
+ };
61
+ readonly banner: {
62
+ readonly max_width: readonly [64, 3200];
63
+ readonly max_height: readonly [64, 1200];
64
+ readonly max_kib: readonly [32, 2048];
65
+ };
66
+ readonly instance_quota: {
67
+ readonly files: readonly [2, 16];
68
+ readonly mib: readonly [1, 16];
69
+ };
70
+ };
71
+ export interface LimitWarning {
72
+ path: string;
73
+ message: string;
74
+ }
75
+ /**
76
+ * The limits in force for `config` (the fleet's `web.appearance`, possibly absent or malformed), and why any value
77
+ * differs from what was written. Unknown keys and wrong types are warned about and their defaults used.
78
+ */
79
+ export declare function effectiveAppearanceLimits(config: unknown): {
80
+ limits: AppearanceLimits;
81
+ warnings: LimitWarning[];
82
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * #1629 r4.1 Q3 (b): the identity card's upload limits are fleet configuration (`web.appearance`), under hard bounds
3
+ * no configuration passes. r4's numbers are the defaults. A value outside its bound is clamped and said so (the config
4
+ * validator's warnings: `agend doctor`, the fleet log at startup, Settings); one out-of-range number never stops the
5
+ * fleet. A limit applies to new uploads only: nothing stored is ever checked again or deleted because a limit moved.
6
+ */
7
+ const KIB = 1024, MIB = 1024 * 1024;
8
+ /** r4 §1's numbers, in `web.appearance`'s own units. */
9
+ export const APPEARANCE_DEFAULTS = {
10
+ portrait: { max_width: 1024, max_height: 1536, max_kib: 1536 },
11
+ banner: { max_width: 1600, max_height: 600, max_kib: 768 },
12
+ instance_quota: { files: 8, mib: 4 },
13
+ };
14
+ /** [floor, ceiling] per setting (r4.1 Q3 (b)). */
15
+ export const APPEARANCE_BOUNDS = {
16
+ portrait: { max_width: [64, 2048], max_height: [64, 3072], max_kib: [32, 4096] },
17
+ banner: { max_width: [64, 3200], max_height: [64, 1200], max_kib: [32, 2048] },
18
+ instance_quota: { files: [2, 16], mib: [1, 16] },
19
+ };
20
+ /**
21
+ * The limits in force for `config` (the fleet's `web.appearance`, possibly absent or malformed), and why any value
22
+ * differs from what was written. Unknown keys and wrong types are warned about and their defaults used.
23
+ */
24
+ export function effectiveAppearanceLimits(config) {
25
+ const warnings = [];
26
+ const root = isObj(config) ? config : {};
27
+ if (config !== undefined && config !== null && !isObj(config))
28
+ warnings.push({ path: "web.appearance", message: "must be a mapping — the defaults are used" });
29
+ for (const k of Object.keys(root))
30
+ if (!Object.hasOwn(APPEARANCE_DEFAULTS, k))
31
+ warnings.push({ path: `web.appearance.${k}`, message: `unknown key (known: ${Object.keys(APPEARANCE_DEFAULTS).join(", ")}) — ignored` });
32
+ const read = (group) => {
33
+ const defaults = APPEARANCE_DEFAULTS[group];
34
+ const bounds = APPEARANCE_BOUNDS[group];
35
+ const raw = Object.hasOwn(root, group) ? root[group] : undefined;
36
+ const given = isObj(raw) ? raw : {};
37
+ if (raw !== undefined && !isObj(raw))
38
+ warnings.push({ path: `web.appearance.${group}`, message: "must be a mapping — the defaults are used" });
39
+ for (const k of Object.keys(given))
40
+ if (!Object.hasOwn(defaults, k))
41
+ warnings.push({ path: `web.appearance.${group}.${k}`, message: `unknown key (known: ${Object.keys(defaults).join(", ")}) — ignored` });
42
+ const out = {};
43
+ for (const [k, def] of Object.entries(defaults)) {
44
+ const path = `web.appearance.${group}.${k}`;
45
+ const v = Object.hasOwn(given, k) ? given[k] : undefined;
46
+ if (v === undefined) {
47
+ out[k] = def;
48
+ continue;
49
+ }
50
+ if (typeof v !== "number" || !Number.isInteger(v)) {
51
+ warnings.push({ path, message: `must be a whole number — the default ${def} is used` });
52
+ out[k] = def;
53
+ continue;
54
+ }
55
+ const [floor, ceiling] = bounds[k];
56
+ if (v < floor) {
57
+ warnings.push({ path, message: `${v} is below the floor ${floor} — ${floor} is used` });
58
+ out[k] = floor;
59
+ continue;
60
+ }
61
+ if (v > ceiling) {
62
+ warnings.push({ path, message: `${v} is above the ceiling ${ceiling} — ${ceiling} is used` });
63
+ out[k] = ceiling;
64
+ continue;
65
+ }
66
+ out[k] = v;
67
+ }
68
+ return out;
69
+ };
70
+ const p = read("portrait"), b = read("banner"), q = read("instance_quota");
71
+ return {
72
+ limits: {
73
+ portrait: { maxWidth: p.max_width, maxHeight: p.max_height, maxBytes: p.max_kib * KIB },
74
+ banner: { maxWidth: b.max_width, maxHeight: b.max_height, maxBytes: b.max_kib * KIB },
75
+ quota: { files: q.files, bytes: q.mib * MIB },
76
+ },
77
+ warnings,
78
+ };
79
+ }
80
+ function isObj(v) {
81
+ return typeof v === "object" && v !== null && !Array.isArray(v);
82
+ }
83
+ //# sourceMappingURL=web-appearance-limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-appearance-limits.js","sourceRoot":"","sources":["../src/web-appearance-limits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * #1629: the one rate limiter for every agent appearance write — theme, effect, widget and mod (r2 (c), r4) — and the
3
+ * fleet-wide switch. Shared by the theme tools (B1) and the effect tools (B2): one budget per instance, not one each.
4
+ *
5
+ * - change: at least 30 s between accepted changes and at most 10 in a rolling hour (set_web_theme, apply/remove of an
6
+ * effect or widget, an agent's own reset);
7
+ * - uploads (theme pictures, effects, proposed mods) are not counted: the user removed that limit (2026-10-18). What an
8
+ * upload may be is still bounded — each file's size and dimensions, an agent's picture quota, a mod's and an effect's
9
+ * own caps — and the switch and a person's lock still refuse it;
10
+ * - data: a placed widget's new values (r4-4) — at least 10 s apart and at most 180 in a rolling hour, a budget of its
11
+ * own, so a widget showing progress never spends the theme's changes.
12
+ *
13
+ * Only accepted calls count: a handler asks `check` before it validates, and `record`s only after its write is on
14
+ * disk, all in one synchronous stretch (a refused or invalid call, or a failed write, costs nothing). The clock is
15
+ * monotonic, so a wall-clock jump neither opens nor closes the window; a fleet restart clears it (documented).
16
+ * The human's reset, lock and removals are never limited.
17
+ */
18
+ export type AppearanceBucket = "change" | "data";
19
+ export declare const APPEARANCE_LIMITS: {
20
+ readonly changeGapMs: 30000;
21
+ readonly changesPerHour: 10;
22
+ readonly dataGapMs: 10000;
23
+ readonly dataPerHour: 180;
24
+ };
25
+ export type LimitVerdict = {
26
+ ok: true;
27
+ } | {
28
+ ok: false;
29
+ error: "rate_limited";
30
+ retry_after_s: number;
31
+ };
32
+ export declare class AppearanceLimiter {
33
+ private readonly now;
34
+ private readonly limits;
35
+ private readonly changes;
36
+ private readonly data;
37
+ constructor(now?: () => number, limits?: {
38
+ readonly changeGapMs: 30000;
39
+ readonly changesPerHour: 10;
40
+ readonly dataGapMs: 10000;
41
+ readonly dataPerHour: 180;
42
+ });
43
+ private recent;
44
+ private waitMs;
45
+ /** Would these buckets admit a call now? Changes nothing. */
46
+ check(instance: string, buckets: readonly AppearanceBucket[]): LimitVerdict;
47
+ /** Count an accepted call — only after its write succeeded. */
48
+ record(instance: string, buckets: readonly AppearanceBucket[]): void;
49
+ /** What an agent sees in get_web_theme (and B2's tools): what is left, and when the next change may come. */
50
+ remaining(instance: string): {
51
+ changes: number;
52
+ retry_after_s: number;
53
+ widget_data: number;
54
+ widget_data_retry_after_s: number;
55
+ };
56
+ /** An instance removed: its counters go with it. */
57
+ forget(instance: string): void;
58
+ }
59
+ /** `web.themes.agent_edit` (default true): false turns every agent appearance write off, fleet-wide; stored choices stay. */
60
+ export declare function agentAppearanceEditAllowed(web: {
61
+ themes?: {
62
+ agent_edit?: boolean;
63
+ };
64
+ } | undefined | null): boolean;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * #1629: the one rate limiter for every agent appearance write — theme, effect, widget and mod (r2 (c), r4) — and the
3
+ * fleet-wide switch. Shared by the theme tools (B1) and the effect tools (B2): one budget per instance, not one each.
4
+ *
5
+ * - change: at least 30 s between accepted changes and at most 10 in a rolling hour (set_web_theme, apply/remove of an
6
+ * effect or widget, an agent's own reset);
7
+ * - uploads (theme pictures, effects, proposed mods) are not counted: the user removed that limit (2026-10-18). What an
8
+ * upload may be is still bounded — each file's size and dimensions, an agent's picture quota, a mod's and an effect's
9
+ * own caps — and the switch and a person's lock still refuse it;
10
+ * - data: a placed widget's new values (r4-4) — at least 10 s apart and at most 180 in a rolling hour, a budget of its
11
+ * own, so a widget showing progress never spends the theme's changes.
12
+ *
13
+ * Only accepted calls count: a handler asks `check` before it validates, and `record`s only after its write is on
14
+ * disk, all in one synchronous stretch (a refused or invalid call, or a failed write, costs nothing). The clock is
15
+ * monotonic, so a wall-clock jump neither opens nor closes the window; a fleet restart clears it (documented).
16
+ * The human's reset, lock and removals are never limited.
17
+ */
18
+ export const APPEARANCE_LIMITS = { changeGapMs: 30_000, changesPerHour: 10, dataGapMs: 10_000, dataPerHour: 180 };
19
+ const HOUR_MS = 60 * 60 * 1000;
20
+ export class AppearanceLimiter {
21
+ now;
22
+ limits;
23
+ changes = new Map();
24
+ data = new Map();
25
+ constructor(now = () => performance.now(), limits = APPEARANCE_LIMITS) {
26
+ this.now = now;
27
+ this.limits = limits;
28
+ }
29
+ recent(map, instance, now) {
30
+ const kept = (map.get(instance) ?? []).filter(t => now - t < HOUR_MS);
31
+ if (kept.length)
32
+ map.set(instance, kept);
33
+ else
34
+ map.delete(instance);
35
+ return kept;
36
+ }
37
+ waitMs(instance, buckets, now) {
38
+ const waits = [];
39
+ if (buckets.includes("change")) {
40
+ const c = this.recent(this.changes, instance, now);
41
+ const last = c.at(-1);
42
+ if (last !== undefined && now - last < this.limits.changeGapMs)
43
+ waits.push(this.limits.changeGapMs - (now - last));
44
+ if (c.length >= this.limits.changesPerHour)
45
+ waits.push(HOUR_MS - (now - c[0]));
46
+ }
47
+ if (buckets.includes("data")) {
48
+ const d = this.recent(this.data, instance, now);
49
+ const last = d.at(-1);
50
+ if (last !== undefined && now - last < this.limits.dataGapMs)
51
+ waits.push(this.limits.dataGapMs - (now - last));
52
+ if (d.length >= this.limits.dataPerHour)
53
+ waits.push(HOUR_MS - (now - d[0]));
54
+ }
55
+ return waits.length ? Math.max(...waits) : 0;
56
+ }
57
+ /** Would these buckets admit a call now? Changes nothing. */
58
+ check(instance, buckets) {
59
+ const wait = this.waitMs(instance, buckets, this.now());
60
+ return wait > 0 ? { ok: false, error: "rate_limited", retry_after_s: Math.ceil(wait / 1000) } : { ok: true };
61
+ }
62
+ /** Count an accepted call — only after its write succeeded. */
63
+ record(instance, buckets) {
64
+ const now = this.now();
65
+ if (buckets.includes("change"))
66
+ this.changes.set(instance, [...this.recent(this.changes, instance, now), now]);
67
+ if (buckets.includes("data"))
68
+ this.data.set(instance, [...this.recent(this.data, instance, now), now]);
69
+ }
70
+ /** What an agent sees in get_web_theme (and B2's tools): what is left, and when the next change may come. */
71
+ remaining(instance) {
72
+ const now = this.now();
73
+ return {
74
+ changes: Math.max(0, this.limits.changesPerHour - this.recent(this.changes, instance, now).length),
75
+ retry_after_s: Math.ceil(this.waitMs(instance, ["change"], now) / 1000),
76
+ widget_data: Math.max(0, this.limits.dataPerHour - this.recent(this.data, instance, now).length),
77
+ widget_data_retry_after_s: Math.ceil(this.waitMs(instance, ["data"], now) / 1000),
78
+ };
79
+ }
80
+ /** An instance removed: its counters go with it. */
81
+ forget(instance) { this.changes.delete(instance); this.data.delete(instance); }
82
+ }
83
+ /** `web.themes.agent_edit` (default true): false turns every agent appearance write off, fleet-wide; stored choices stay. */
84
+ export function agentAppearanceEditAllowed(web) {
85
+ return web?.themes?.agent_edit !== false;
86
+ }
87
+ //# sourceMappingURL=web-appearance-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-appearance-policy.js","sourceRoot":"","sources":["../src/web-appearance-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { type AppearanceInput, type FrameEntry } from "./web-appearance-view.js";
2
+ import type { ResolvedCard } from "./web-card.js";
3
+ import type { Theme } from "./web-theme.js";
4
+ type Picture = {
5
+ bytes: Buffer;
6
+ mime: string;
7
+ } | null;
8
+ export interface AppearanceDeps {
9
+ frame(name: string): FrameEntry;
10
+ theme(name: string): {
11
+ theme: Theme;
12
+ locked: boolean;
13
+ widgets?: AppearanceInput["widgets"];
14
+ ambient?: AppearanceInput["ambient"];
15
+ glyphAsset?: (id: string) => Picture;
16
+ };
17
+ card(name: string): ResolvedCard;
18
+ /** The resolved card's picture for a slot (the person's, else the agent's). */
19
+ cardPicture(name: string, slot: "portrait" | "banner"): Picture;
20
+ themeAsset(name: string, id: string): Picture;
21
+ profileAvatar(name: string): Picture;
22
+ botAvatar(name: string, key: string): Picture;
23
+ /** get_web_theme's agent_edit and limits (one source for both tools). */
24
+ themeAnswer(name: string): {
25
+ agent_edit?: unknown;
26
+ limits?: unknown;
27
+ };
28
+ /** #1958: the host's identity-colour settings (web prefs color.show / color.off), for the colour view. */
29
+ effects?(name: string): AppearanceInput["effects"];
30
+ colorPrefs?(): {
31
+ show?: unknown;
32
+ off?: boolean;
33
+ };
34
+ clock?: () => number;
35
+ }
36
+ /** A preview whose files (base64) fit one message is sent whole; a larger one is fetched in parts. */
37
+ export declare const PREVIEW_INLINE_BYTES: number;
38
+ export declare const PREVIEW_IDLE_MS = 60000;
39
+ export declare class AppearanceTools {
40
+ private readonly deps;
41
+ private readonly previews;
42
+ constructor(deps: AppearanceDeps);
43
+ private now;
44
+ private input;
45
+ /** The face drawn, as bytes of this instance's: the theme's picture, the person's upload, or its own bot's. */
46
+ private avatar;
47
+ handle(name: string, tool: string, args: Record<string, unknown>): Record<string, unknown>;
48
+ /** One part of the caller's own preview in progress (its id, a file it holds, an index in range, not gone stale). */
49
+ private part;
50
+ /** An instance was removed. */
51
+ forget(name: string): void;
52
+ }
53
+ export {};
@@ -0,0 +1,124 @@
1
+ /**
2
+ * #1629 r4 §1: get_web_appearance and preview_web_appearance, on the fleet's side. Both read only the caller's own
3
+ * record (no target), through resolvers the fleet passes in — the status frame's entry, the theme, the card, this
4
+ * instance's pictures. The preview's files are bytes for the daemon or the CLI to write in the agent's working
5
+ * directory (the fleet never names a path); a preview larger than one message is handed over in parts.
6
+ */
7
+ import { createHash, randomBytes } from "node:crypto";
8
+ import { appearanceView, PICTURE_ROLES, pictureFileName, previewSvg } from "./web-appearance-view.js";
9
+ import { ASSET_PART_BYTES } from "./web-asset-parts.js";
10
+ import { imageSize, sniffMedia } from "./web-image-meta.js";
11
+ /** A preview whose files (base64) fit one message is sent whole; a larger one is fetched in parts. */
12
+ export const PREVIEW_INLINE_BYTES = 600 * 1024;
13
+ export const PREVIEW_IDLE_MS = 60_000;
14
+ /** A glyph picture's side file type (the glyph slot's kinds). */
15
+ const GLYPH_EXT = { "image/png": "png", "image/webp": "webp", "image/gif": "gif" };
16
+ const MODES = ["light", "dark"];
17
+ export class AppearanceTools {
18
+ deps;
19
+ previews = new Map();
20
+ constructor(deps) {
21
+ this.deps = deps;
22
+ }
23
+ now() { return (this.deps.clock ?? (() => performance.now()))(); }
24
+ input(name) {
25
+ const entry = this.deps.frame(name);
26
+ const t = this.deps.theme(name);
27
+ const answer = this.deps.themeAnswer(name);
28
+ return { entry, theme: t.theme, card: this.deps.card(name), locked: t.locked, agentEdit: answer.agent_edit !== false, limits: (answer.limits ?? {}), widgets: t.widgets, ambient: t.ambient,
29
+ effects: this.deps.effects?.(name) ?? [], colorPrefs: this.deps.colorPrefs?.() ?? {} };
30
+ }
31
+ /** The face drawn, as bytes of this instance's: the theme's picture, the person's upload, or its own bot's. */
32
+ avatar(name, input) {
33
+ const e = input.entry;
34
+ if (e.theme_avatar?.kind === "image" && input.theme.avatar)
35
+ return this.deps.themeAsset(name, input.theme.avatar);
36
+ const src = e.avatar?.kind === "image" ? e.avatar.src ?? "" : "";
37
+ if (src.startsWith("/ui/img/avatar/"))
38
+ return this.deps.profileAvatar(name);
39
+ const bot = /^\/ui\/img\/bot\/([^/?#]+)/.exec(src);
40
+ if (bot) {
41
+ try {
42
+ return this.deps.botAvatar(name, decodeURIComponent(bot[1]));
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ handle(name, tool, args) {
51
+ const now = this.now();
52
+ for (const [k, b] of this.previews)
53
+ if (now - b.last > PREVIEW_IDLE_MS)
54
+ this.previews.delete(k); // nothing stale stays
55
+ if (tool === "get_web_appearance")
56
+ return appearanceView(this.input(name));
57
+ if (tool !== "preview_web_appearance")
58
+ return { error: "unknown_tool" };
59
+ if (args.part !== undefined)
60
+ return this.part(name, args.part, now);
61
+ const modes = args.modes === undefined ? MODES : args.modes;
62
+ if (!Array.isArray(modes) || !modes.length || modes.length > 2 || !modes.every(m => m === "light" || m === "dark") || new Set(modes).size !== modes.length) {
63
+ return { error: "modes", message: "modes: light and/or dark" };
64
+ }
65
+ const input = this.input(name);
66
+ const bytes = {
67
+ avatar: this.avatar(name, input),
68
+ portrait: input.card.portrait ? this.deps.cardPicture(name, "portrait") : null,
69
+ banner: input.card.banner ? this.deps.cardPicture(name, "banner") : null,
70
+ background: input.theme.background ? this.deps.themeAsset(name, input.theme.background.image) : null,
71
+ };
72
+ // Each picture is its own file next to the SVGs (#1890 review: inside, they outgrew what an agent's Read takes).
73
+ const names = {};
74
+ const files = [];
75
+ const add = (fileName, data) => files.push({ name: fileName, data, sha256: createHash("sha256").update(data).digest("hex") });
76
+ for (const role of PICTURE_ROLES) {
77
+ const p = bytes[role], fileName = p ? pictureFileName(role, p.mime) : null;
78
+ names[role] = fileName;
79
+ if (p && fileName)
80
+ add(fileName, p.bytes);
81
+ }
82
+ // #2086: the banner's own size, so the preview crops it at its focus exactly as the page does.
83
+ const bannerKind = bytes.banner ? sniffMedia(bytes.banner.bytes) : null;
84
+ const bannerSize = bytes.banner && bannerKind ? imageSize(bytes.banner.bytes, bannerKind) : null;
85
+ // #2117: the looping ambient's glyph pictures, glyph1… next to the SVGs.
86
+ const glyphPics = {};
87
+ const glyphOf = this.deps.theme(name).glyphAsset;
88
+ for (const g of input.ambient?.loop?.spec.glyphs ?? []) {
89
+ if (typeof g === "string" || glyphPics[g.asset] || !glyphOf)
90
+ continue;
91
+ const p = glyphOf(g.asset), ext = p ? GLYPH_EXT[p.mime] : undefined;
92
+ if (!p || !ext)
93
+ continue;
94
+ const fileName = `glyph${Object.keys(glyphPics).length + 1}.${ext}`;
95
+ glyphPics[g.asset] = fileName;
96
+ add(fileName, p.bytes);
97
+ }
98
+ for (const mode of modes)
99
+ add(`${mode}.svg`, Buffer.from(previewSvg(input, mode, names, bannerSize, glyphPics), "utf8"));
100
+ const total = files.reduce((n, f) => n + f.data.length, 0);
101
+ if (total <= PREVIEW_INLINE_BYTES)
102
+ return { files: files.map(f => ({ name: f.name, data_b64: f.data.toString("base64") })) };
103
+ const built = { id: randomBytes(8).toString("hex"), files, last: now };
104
+ this.previews.set(name, built); // one per instance: a new preview replaces it
105
+ return { preview: built.id, files: files.map(f => ({ name: f.name, bytes: f.data.length, sha256: f.sha256, parts: Math.ceil(f.data.length / ASSET_PART_BYTES) })) };
106
+ }
107
+ /** One part of the caller's own preview in progress (its id, a file it holds, an index in range, not gone stale). */
108
+ part(name, raw, now) {
109
+ const p = raw;
110
+ const b = this.previews.get(name);
111
+ if (!p || typeof p !== "object" || !b || p.preview !== b.id)
112
+ return { error: "preview", message: "No such preview: ask for it again." };
113
+ const f = b.files.find(x => x.name === p.name);
114
+ const count = f ? Math.ceil(f.data.length / ASSET_PART_BYTES) : 0;
115
+ if (!f || !Number.isSafeInteger(p.index) || p.index < 0 || p.index >= count)
116
+ return { error: "part", message: "No such part." };
117
+ b.last = now; // a preview being fetched stays while it is
118
+ const i = p.index;
119
+ return { data_b64: f.data.subarray(i * ASSET_PART_BYTES, (i + 1) * ASSET_PART_BYTES).toString("base64") };
120
+ }
121
+ /** An instance was removed. */
122
+ forget(name) { this.previews.delete(name); }
123
+ }
124
+ //# sourceMappingURL=web-appearance-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-appearance-tools.js","sourceRoot":"","sources":["../src/web-appearance-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * #1629 r4 §1: the agent's read-only view of how it appears on the dashboard — `get_web_appearance` (what the page
3
+ * draws now, resolved exactly as the status frame resolves it) and `preview_web_appearance` (an SVG per mode, built
4
+ * from the page's own layout numbers). Pure: the fleet passes in what it already resolved; nothing here reads a file,
5
+ * a path or another instance.
6
+ *
7
+ * The SVG names only this instance's pictures, as side files next to it (`avatar.png`, …: #1890 review — an SVG with a
8
+ * picture inside outgrew what an agent's Read takes); text is XML-escaped; colours are checked again; fonts are generic
9
+ * families. No browser, no live session, no other instance's content.
10
+ */
11
+ import { type AmbientKind, type AmbientSpec } from "./web-ambient.js";
12
+ import { type IdentityColorSource, type IdentityColorTiers, type Placement, type PlacementSource, type PlacementTiers } from "./web-identity-color.js";
13
+ import { type Palette, type Theme, type ThemeMode } from "./web-theme.js";
14
+ import type { ResolvedCard } from "./web-card.js";
15
+ export type AvatarSource = "profile" | "theme" | "bot" | "emoji" | "initial";
16
+ /** The status frame's entry for one instance (getUiStatus): the fields the page draws a face and a ring from. */
17
+ export interface FrameEntry {
18
+ name: string;
19
+ display_name?: string;
20
+ avatar?: {
21
+ kind: string;
22
+ src?: string;
23
+ text?: string;
24
+ alt?: string;
25
+ };
26
+ accent?: string;
27
+ theme_avatar?: {
28
+ kind: string;
29
+ src?: string;
30
+ };
31
+ theme_accent?: string;
32
+ /** #1958: the identity colour's tiers and its placements' (getUiStatus). */
33
+ color?: IdentityColorTiers;
34
+ color_show?: PlacementTiers;
35
+ }
36
+ /**
37
+ * #1958: the identity colour drawn for this instance while agents' themes are shown, where it comes from, its value on
38
+ * a light and a dark page, where it shows (and whose choice that is), and whether the host turned colours off — what
39
+ * the agent needs to know: a person's choice wins over its own (theme.identity), field by field.
40
+ */
41
+ export declare function resolvedIdentityColor(e: FrameEntry, host?: {
42
+ show?: unknown;
43
+ off?: boolean;
44
+ }): {
45
+ color: string;
46
+ source: IdentityColorSource;
47
+ light: string;
48
+ dark: string;
49
+ show: Placement[];
50
+ show_source: PlacementSource;
51
+ off: boolean;
52
+ };
53
+ /** The face the page draws while agents' themes are shown (the default), and where it comes from. */
54
+ export declare function resolvedAvatar(e: FrameEntry): {
55
+ source: AvatarSource;
56
+ url?: string;
57
+ text?: string;
58
+ };
59
+ /** The ring the page draws round a picture face: the theme's colour, else an own bot's; none for an emoji or initial. */
60
+ export declare function resolvedRing(e: FrameEntry): {
61
+ color: string;
62
+ source: "theme" | "bot";
63
+ } | null;
64
+ /** The effective look per mode: the palette over the token defaults, and the fixed choices. */
65
+ export declare function effectiveTheme(theme: Theme): Record<ThemeMode, Required<Palette> & {
66
+ font: string;
67
+ bubbleRadius: number;
68
+ bubbleBorder: string;
69
+ }>;
70
+ export interface AppearanceInput {
71
+ entry: FrameEntry;
72
+ theme: Theme;
73
+ card: ResolvedCard;
74
+ locked: boolean;
75
+ agentEdit: boolean;
76
+ limits: Record<string, unknown>;
77
+ /** #1958: the host's identity-colour settings (color.show / color.off). */
78
+ colorPrefs?: {
79
+ show?: unknown;
80
+ off?: boolean;
81
+ };
82
+ /** r4-4: its placed widgets, by slot. */
83
+ effects?: Array<{
84
+ id: string;
85
+ by: string;
86
+ params?: Record<string, unknown>;
87
+ playback: Record<string, unknown>;
88
+ }>;
89
+ widgets?: Partial<Record<"chat_header" | "details", {
90
+ spec: unknown;
91
+ data: unknown;
92
+ by: string;
93
+ }>>;
94
+ /** #2117: its ambients, by kind. */
95
+ ambient?: Partial<Record<AmbientKind, {
96
+ spec: AmbientSpec;
97
+ by: string;
98
+ }>>;
99
+ }
100
+ /** get_web_appearance: current placements and untrusted recent playback observations. */
101
+ export declare function appearanceView(i: AppearanceInput): Record<string, unknown>;
102
+ /**
103
+ * Wrap `text` (its own line breaks kept) to `maxPx` at `size`, at most `maxLines` lines; what does not fit ends the last
104
+ * line with "…". Latin text breaks at a space when one is on the line; CJK breaks anywhere. Never splits a grapheme.
105
+ */
106
+ export declare function fitLines(text: string, maxPx: number, size: number, maxLines: number): string[];
107
+ export declare const PREVIEW_BANNER: {
108
+ readonly aspect: 3;
109
+ readonly min: 140;
110
+ readonly max: 240;
111
+ };
112
+ export declare const PICTURE_ROLES: readonly ["avatar", "portrait", "banner", "background"];
113
+ export type PictureRole = typeof PICTURE_ROLES[number];
114
+ /** This instance's pictures by role, as the side files' names (null: none). */
115
+ export type PreviewPictures = Record<PictureRole, string | null>;
116
+ /** A side file's name for a picture of this role and type, or null for a type no page shows. */
117
+ export declare function pictureFileName(role: PictureRole, mime: string): string | null;
118
+ /** Every name a preview writes: an SVG per mode, and the pictures it names. */
119
+ export declare const PREVIEW_FILE: RegExp;
120
+ /** One mode's SVG. Every picture is one of `pics` (this instance's), inline; nothing else is referenced. */
121
+ export declare function previewSvg(i: AppearanceInput, mode: ThemeMode, pics: PreviewPictures, bannerSize?: {
122
+ width: number;
123
+ height: number;
124
+ } | null, glyphPics?: Readonly<Record<string, string>>): string;