@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
@@ -14,7 +14,8 @@ register("settings", {
14
14
  publicTtl: "Public link minutes (1–480)",
15
15
  publicProtocol: "Tunnel protocol",
16
16
  webEcho: "Web echo",
17
- webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms are excluded.",
17
+ webEchoHint: "Copies web messages to the bound Telegram or Discord topic. ClassicBot rooms follow it unless a room sets its own.",
18
+ webUsagePublic: "Usage report over the public link", webUsagePublicHint: "Fleet → Usage (up to 400 days of each agent's tokens, requests, messages and API-equivalent amounts) is offered over the temporary public link too. Off by default; guests never see it. Applies at once.",
18
19
  webLogTab: "Log tab: each agent's steps", webLogTabHint: "Shows each instance's prompts, replies, tool calls and results, and fleet events in its Log tab, read from its own transcript only while the tab is open. Secret values are masked. Also over the public link. Turning it on waits for a fleet admin's confirmation.",
19
20
  general: "General Settings",
20
21
  advanced: "Advanced",
@@ -88,7 +89,6 @@ register("settings", {
88
89
  wake: "Wake",
89
90
  accessMode: "Access mode",
90
91
  affected: "Affected instances",
91
- webEchoGroupConfirm: "This looks like a group channel: enabling posts every web message to this instance where all channel members can read it. Enable web echo?",
92
92
  language: "Language (bot replies)",
93
93
  defaultBackend: "Default backend",
94
94
  defaultModel: "Default model",
@@ -131,6 +131,7 @@ register("settings", {
131
131
  applyPartial: "Some changes failed",
132
132
  applyClose: "Close",
133
133
  settingsButton: "Settings",
134
+ connRetryNow: "Retry now", connRetryQueued: "Connection retry requested.", connRetryFailed: "Could not retry this connection. Check its status and try again.",
134
135
  modalDone: "Stage change",
135
136
  wizardButton: "Setup wizard",
136
137
  wizardTitle: "Set up AgEnD",
@@ -204,6 +205,9 @@ register("settings", {
204
205
  changesApplied: "Changes applied. AgEnD is reconciling affected Agents.",
205
206
  reviewChanges: "Review changes",
206
207
  backendUnavailable: "{0} (removed — choose another backend)",
208
+ backendNotInstalled: "not installed", backendNotSignedIn: "not signed in (use /login)", backendTooOld: "needs {0} or newer", backendUnchecked: "not checked yet",
209
+ modelNotListed: "current — not in this CLI's list", modelOther: "Other…", modelOtherLabel: "Model name", modelOtherPlaceholder: "a model name this CLI accepts",
210
+ modelNone: "— none —", inheritValue: "inherit ({0})", modelCliDefault: "the CLI's own default",
207
211
  readyApply: "Ready to apply",
208
212
  copied: "Copied",
209
213
  expectedMapping: "expected a mapping",
@@ -222,7 +226,7 @@ register("settings", {
222
226
  staggerWarning: "Very low values can cause startup spikes",
223
227
  sec_device: "Preferences", syncedTitle: "Synced across your devices", syncedLead: "Changes here apply on every device where you are signed in.",
224
228
  profileTitle: "Your name",
225
- profileLeadBound: "Agents see your web messages as the Discord or Telegram account your sign-in code was sent to: its id, and its name unless you choose another here. It follows you to every device you sign in on. It is for recognition only: it grants nothing.",
229
+ profileLeadBound: "Agents see your web messages as the Discord or Telegram account your sign-in code was sent to: its id, and its name unless you choose another here. It follows you to every device you sign in on. Agents do your ordinary requests as you; a release, anything destructive, spending, secrets or passing your authority on needs this browser authorized, or your confirm in Discord or Telegram.",
226
230
  profileLeadUnbound: "This browser was not signed in with a code sent to your Discord or Telegram account, so agents see your web messages as \"web-user\" (or the name you set here). Sign in with a code from /web to be recognised as your account.",
227
231
  profileName: "Name", profileHelp: "Agents see: {0} · id {1}", profileSave: "Save", profileClear: "Use web-user", profileUseAccount: "Use {0}",
228
232
  profileSaved: "Agents now see you as {0}", profileFailed: "Could not save the name",
@@ -288,6 +292,132 @@ register("settings", {
288
292
  accessTitle: "Access",
289
293
  webChat: "Web chat",
290
294
  sec_web: "Web",
295
+ // #1629 r4 §3: Settings → Appearance (owner CSS).
296
+ sec_appearance: "Web appearance",
297
+ groupLook: "Look", groupLayout: "Your layout", groupCss: "Styles you write", groupMods: "Add-ons", groupAdvanced: "Advanced", learnMore: "Learn more: {0}",
298
+ colorTitle: "Identity colours", colorLead: "One agent's colour: its ⋯ menu → Colour…",
299
+ colorPlaces: "Where colours show", colorSample: "Sample agent", colorOff: "Turn off colours",
300
+ colorOffLead: "Colours people picked are kept.",
301
+ restoreTitle: "Restore defaults", restoreLead: "Puts this host's look back to the defaults. Asks first.",
302
+ restoreConfirm: "Resets, for this host: showing agents' themes and effects, the card size and each card's own size, your sidebar widget, where colours show, and colours off. Also turns your custom CSS off (its versions are kept) and its switch on this device. Kept: the colours people picked for agents, installed mods, uploaded effects and the card limits.",
303
+ restoreGo: "Restore defaults", restoreDone: "Appearance settings are back to their defaults.", restoreCssFailed: "The settings are back to their defaults, but your custom CSS could not be turned off: {0}",
304
+ cardSizeTitle: "Identity cards",
305
+ cardSizeLead: "A card's own S / M / L overrides this.",
306
+ cardLimitsTitle: "Identity card upload limits",
307
+ cardLimitsLead: "Empty = the default. Raising a limit needs an admin's OK.",
308
+ cardLimitsUnavailable: "Only a signed-in admin can change these.",
309
+ cardLimit_portrait_max_width: "Portrait width (px)", cardLimit_portrait_max_height: "Portrait height (px)", cardLimit_portrait_max_kib: "Portrait size (KiB)",
310
+ cardLimit_banner_max_width: "Banner width (px)", cardLimit_banner_max_height: "Banner height (px)", cardLimit_banner_max_kib: "Banner size (KiB)",
311
+ cardLimit_instance_quota_files: "Pictures per agent", cardLimit_instance_quota_mib: "Picture space per agent (MiB)",
312
+ cardLimitInForce: "In force: {0} (allowed {1}–{2})",
313
+ cardLimitsWhole: "Each limit is a whole number, or empty for the default.",
314
+ cardLimitsNoChange: "Nothing changed.",
315
+ cardLimitsSave: "Save limits",
316
+ cardLimitsSaved: "Saved.",
317
+ cardLimitsFailed: "Not saved: {0}",
318
+ themesTitle: "Agents' themes",
319
+ themesShow: "Show agents' themes, effects and widgets",
320
+ themesShowLead: "When off, every chat looks the same.",
321
+ themesFollowMotion: "Effects: follow the system's reduced-motion setting",
322
+ themesFollowMotionLead: "This device only: effects stay still while the system reduces motion.",
323
+ themesSafeMode: "This page was opened with ?safe=1: agents' themes are not shown on it.",
324
+ widgetTitle: "Your sidebar widget",
325
+ widgetLead: "A small panel under your agent list, written as JSON.",
326
+ widgetNotJson: "Not JSON.",
327
+ widgetSave: "Save widget",
328
+ widgetSaved: "Sidebar widget saved.",
329
+ widgetExample: "Start from an example",
330
+ widgetRemove: "Remove widget",
331
+ widgetRemoved: "Sidebar widget removed.",
332
+ modsTitle: "Mods",
333
+ modsLead: "Only the parts you tick are applied.",
334
+ modsLoadFailed: "Couldn't load the installed mods. Reload the page to try again.",
335
+ modsNone: "No mods installed.",
336
+ modChoose: "Import a mod file…",
337
+ modPlan: "What this mod would change",
338
+ modAuthor: "By {0} (unverified)",
339
+ modSizeId: "{0} · id {1}",
340
+ modAlready: "already installed",
341
+ modReplace: "Replace the installed version {0}",
342
+ modPartTheme: "Theme (colours, font, pictures)",
343
+ modPartIdentity: "Card text (tagline and bio)",
344
+ modPartAmbient: "Ambient effect (falling, rising, twinkling or click glyphs)",
345
+ modPartWidget_chat_header: "Chat header widget",
346
+ modPartWidget_details: "Details page widget",
347
+ modPartWidget_sidebar: "Your sidebar widget",
348
+ modPartEffect: "Effect: {0}",
349
+ modPartCss: "Custom CSS (on your screens only)",
350
+ modCssWarn: "Custom CSS from this file — read it before turning it on.",
351
+ modCssAssets: "{0} files for it ({1})",
352
+ modAccent: "Accent", modFont: "Font", modPictures: "{0} pictures ({1})", modPlaces: "places {0} effects",
353
+ modColorsLight: "Light colours", modColorsDark: "Dark colours", modBubble: "Bubbles", modWorkingLabel: "Working label",
354
+ modBackground: "Background picture", modBackgroundFit: "Background fit and opacity", modAvatar: "Picture (face)",
355
+ modPlacesEffect: "Places effect", modAllFields: "Every field, as it will be applied",
356
+ modStageGone: "That import was replaced or ran out of time. Showing what is staged now.",
357
+ modRegions: "draws on: {0}", modWants: "hears: {0}",
358
+ modTarget: "Apply to",
359
+ modTargetPick: "Choose an agent…",
360
+ modTargetNeeded: "Choose the agent this look goes to.",
361
+ modAppliedTo: "applied to {0}",
362
+ modInstall: "Install",
363
+ modCancel: "Cancel",
364
+ modInstalled: "Installed {0}.",
365
+ modFailed: "Not done: {0}",
366
+ modDownload: "Download",
367
+ modUninstall: "Uninstall",
368
+ modUninstallConfirm: "Uninstall {0}? Its effects leave your library unless something still uses them. What it applied stays.",
369
+ modUninstalled: "Uninstalled {0}.",
370
+ modExport: "Export a mod",
371
+ modExportLead: "Save what's in force now as a mod file.",
372
+ modExportInstance: "Agent",
373
+ modExportName: "Name (a-z, 0-9, -)",
374
+ modExportVersion: "Version",
375
+ modExportTitle: "Title",
376
+ modExportGo: "Download the file",
377
+ modExportOmitted: "{0} effect(s) placed there are someone else's and were left out: only your own and shared effects travel.",
378
+ modProposals: "Proposed by agents",
379
+ modProposedBy: "{0} proposes",
380
+ modReview: "Review",
381
+ modDismiss: "Dismiss",
382
+ cssTitle: "Custom CSS (yours only)",
383
+ cssLead: "Applies to your screens only.",
384
+ cssLoadFailed: "Couldn't load your custom CSS. Reload the page to try again.",
385
+ cssPublicLink: "Custom CSS isn't available on a temporary public link.",
386
+ cssInForce: "In force: {0}",
387
+ cssOnTrial: "On trial: {0}. Choose Keep, or it reverts.",
388
+ cssNone: "No custom CSS in force.",
389
+ cssSave: "Save and try",
390
+ cssTrying: "Custom CSS saved. Look around, then choose Keep within 15 seconds.",
391
+ cssOff: "Turn off (all devices)",
392
+ cssVersions: "Earlier versions ({0})",
393
+ cssCurrent: "in force",
394
+ cssRestore: "Use this",
395
+ cssAssets: "Assets",
396
+ cssAssetsLead: "{0} of {1} files, {2} in total (at most 1 MiB in all).",
397
+ cssAssetAdd: "Add a picture or font",
398
+ cssAssetCopy: "Copy reference",
399
+ cssCopied: "Copied {0}",
400
+ cssAssetRemove: "Remove",
401
+ cssDeviceTitle: "On this device",
402
+ cssDeviceOff: "Turn off custom CSS on this device",
403
+ cssSafe: "Something hidden? Add ?safe=1 to the address.",
404
+ cssError_at_rule: "Not saved: {0} isn't allowed.",
405
+ cssError_url: "Not saved: the only url() allowed is url(\"asset:<id>\") for a file in Assets.",
406
+ cssError_unknown_asset: "Not saved: there's no asset {0}. Add it under Assets first.",
407
+ cssError_function: "Not saved: {0} isn't allowed.",
408
+ cssError_property: "Not saved: {0} isn't allowed.",
409
+ cssError_script_scheme: "Not saved: javascript: and vbscript: aren't allowed.",
410
+ cssError_too_large: "Not saved: custom CSS can be at most 64 KiB.",
411
+ cssError_malformed: "Not saved: a string or url() isn't closed.",
412
+ cssError_nul: "Not saved: the text contains a NUL character.",
413
+ cssError_unserialisable: "Not saved: the CSS couldn't be read back safely.",
414
+ cssError_asset_type: "Not added: only PNG, WebP, JPEG, GIF or WOFF2 files are allowed.",
415
+ cssError_asset_unreadable: "Not added: the file couldn't be read.",
416
+ cssError_asset_quota: "Not added: Assets hold at most 16 files and 1 MiB in total.",
417
+ cssError_asset_in_use: "Not removed: a saved version still uses it.",
418
+ cssError_owner_css_read_only: "This sign-in can view but not change custom CSS.",
419
+ cssError_owner_css_needs_a_signed_in_person: "Sign in in the browser to change custom CSS.",
420
+ cssError_other: "Not saved ({0}).",
291
421
  webLead: "How the web dashboard behaves. A change that loosens access (longer sessions, the browser terminal back on or for longer, the public link) waits for a fleet admin to confirm it in chat (General topic) or on the host; one that tightens it applies at once.",
292
422
  webPublicRefused: "Web settings can't be changed over a temporary public link. Open the dashboard at its own address to change them.",
293
423
  webSessionTitle: "Sign-in sessions",
@@ -303,6 +433,28 @@ register("settings", {
303
433
  webTerminalTtl: "Terminal session minutes (1–20)",
304
434
  webTerminalTtlRange: "Must be a whole number from 1 to 20",
305
435
  webReadOnlyTitle: "Set in fleet.yaml",
436
+ guestsTitle: "Guests", guestsReview: "Review guest changes",
437
+ guestsHint: "People who are not admins can sign in to the web as guests: they send /web where they already chat and get a code privately. A guest sees only the agents they can already use in chat, and their messages are recognition only.",
438
+ guestsEnabled: "Guest sign-in", guestsEnabledHint: "Off: no one can sign in as a guest, and every guest session ends. Turning it on waits for a fleet admin's confirmation.",
439
+ guestsChat: "Guests may chat", guestsChatHint: "Off: guests can read their agents' chats but not send, attach, click a reply's buttons or press Cancel.",
440
+ guestsOpenFor: "Agents for guests of {0} ({1})", guestsOpenHint: "This connection is open to everyone, so it has no list of people: its guests reach only the agents you tick here (none by default). Adding agents waits for a fleet admin's confirmation.",
441
+ guestsList: "Guest accounts", guestsNone: "No guest has signed in yet.", guestsLoadFailed: "The guest list could not be loaded.",
442
+ guestFacts: "Agents: {0} · Sessions: {1} · Remembered browsers: {2}", guestLastActive: "Last active {0}", guestNotSignedIn: "Not signed in now",
443
+ guestNotNarrowed: "Reaches every agent they can use in chat.", guestNarrowedTo: "Narrowed to: {0}", guestNothing: "nothing",
444
+ guestNarrow: "Narrow", guestNotReachable: "(no longer reachable)", guestReachesNothing: "This account reaches no agent from chat right now, so there is nothing to narrow.", guestNarrowLift: "Remove narrowing", guestNarrowHint: "Tick what this guest may still reach. Narrowing only takes away (it applies at once); widening or removing it waits for a fleet admin's confirmation.",
445
+ guestSignOut: "Sign out", guestSignOutTitle: "Sign out this guest?", guestSignOutConfirm: "{0}'s guest sessions end now, their sign-in code stops working and their browsers are forgotten. They can sign in again with /web while guest sign-in is on.",
446
+ guestSignedOut: "{0} is signed out.", guestSignedOutNotDurable: "{0} is signed out for now, but it could not be saved: a restart may bring their sessions back.", guestSignOutFailed: "That did not work — try again.",
447
+ vaTitle: "Web authority", vaReview: "Review web authority changes",
448
+ vaHint: "Whether a signed-in fleet admin's web messages carry their own account's authority, recorded in each message's delivery receipt. A session signed in with a code sent privately to that account, on the dashboard reached directly, is authorized once from Discord or Telegram; the public link and guests never are. Agents do an admin's ordinary web requests either way; a release, anything destructive, spending, secrets or passing authority on needs this.",
449
+ vaLoadFailed: "Web authority could not be loaded.",
450
+ vaEnabled: "Web messages carry authority", vaEnabledHint: "On by default: a session carries authority only once its account confirms it from Discord or Telegram. Off: no web message carries authority, and any already given reads as none at once; authority given before it was turned off never comes back.",
451
+ vaStuckOff: "Web authority is off for now: its state could not be saved on this computer (see the fleet log). It comes back on by itself once it can be.",
452
+ vaLoopbackOnly: "Only this computer can authorize", vaLoopbackOnlyHint: "On: only a browser on this computer qualifies, not one on your network or tailnet, and authority already given from elsewhere reads as none. Turning it off again doesn't bring that back.",
453
+ vaLanWarning: "The dashboard also answers to {0} (web.allowed_hosts). Anyone who reaches it there with a stolen sign-in could give authority in your name. Turn on \"Only this computer can authorize\" unless you trust everyone who can reach it.",
454
+ vaHours: "An authorization lasts (hours, {0}–{1})", vaHoursRange: "Must be a number from 1 to 48",
455
+ vaSessionsTitle: "Authorized sessions", vaSessionsNone: "No session is authorized now.", vaSessionUntil: "Authorized {0} · until {1}",
456
+ vaRevoke: "Revoke web authority", vaRevokeTitle: "Revoke all web authority?", vaRevokeConfirm: "Every authority given from the web so far reads as none from now on, and every session's authorization ends. Nobody is signed out: a session carries authority again once it is authorized again.",
457
+ vaRevoked: "Web authority given so far is revoked.", vaRevokedNotDurable: "Revoked for now, but it could not be saved: web authority stays off until it can be, and a restart before then undoes the revocation.", vaRevokeFailed: "That did not work — try again.",
306
458
  webReadOnlyLead: "Read-only here: these decide what the dashboard listens on and exposes. Edit fleet.yaml, then run agend reload (web.preview_port and web.preview_origin take a restart of AgEnD).",
307
459
  notSet: "not set (default)",
308
460
  defaultsTitle: "Defaults",
@@ -351,7 +503,19 @@ register("settings", {
351
503
  discardOnLeave: "Discard {0} pending changes?",
352
504
  applyBusyLocal: "An Apply is still running — wait for it to finish.",
353
505
  applyStepFailed: "Stopped at a change: {0}. The changes after it were not applied; they are staged again.",
354
- stepWaiting: "Waiting for confirmation in chat",
506
+ applyError_unsupported_sensitive_effect: "it changes a setting the confirmation cannot show safely, so nothing was changed",
507
+ applyError_confirmation_diff_too_large: "it is too large to confirm at once; apply fewer changes at a time",
508
+ applyError_session_required: "your sign-in ended; sign in again and apply",
509
+ applyError_admin_required: "only a fleet admin can confirm it",
510
+ applyError_settings_changed: "the settings changed meanwhile; review and apply again",
511
+ applyError_request_no_longer_current: "the settings changed meanwhile; review and apply again",
512
+ applyError_too_many_pending_changes: "too many changes are waiting for confirmation; confirm or withdraw some first",
513
+ applyError_fleet_unavailable: "the fleet is not running",
514
+ applyError_invalid_settings_effect: "the result would not be a valid configuration",
515
+ applyError_settings_confirmation_unavailable: "its confirmation could not be set up; try again",
516
+ applyError_failed: "the server could not apply it",
517
+ applyErrorOther: "the server refused it ({0})",
518
+ stepWaiting: "Waiting for confirmation",
355
519
  stepSkipped: "Not applied",
356
520
  viaRestart: "(restart)",
357
521
  format: "Format",
@@ -368,7 +532,6 @@ register("settings", {
368
532
  discordUserPlaceholder: "your Discord user id",
369
533
  telegramUserPlaceholder: "your Telegram user id",
370
534
  bindingApplyButton: "Rebind",
371
- webEchoEnable: "Turn on web echo",
372
535
  help1: "Agents: each agent's settings, Start/Stop, Pause/Wake, and New agent.",
373
536
  help2: "Connections: who may use each bot, its binding, its status emojis, a new token; and provider API keys.",
374
537
  help3: "ClassicBot: each room's backend, model and options.",
@@ -412,7 +575,8 @@ register("settings", {
412
575
  publicTtl: "公開連結分鐘數(1–480)",
413
576
  publicProtocol: "Tunnel 協定",
414
577
  webEcho: "Web 同步",
415
- webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題,不包含 ClassicBot 群組。",
578
+ webEchoHint: "將網頁訊息複製到綁定的 Telegram 或 Discord 主題。ClassicBot 聊天室也照這個設定,除非該聊天室另外設定。",
579
+ webUsagePublic: "透過公開連結提供用量報告", webUsagePublicHint: "Fleet → 用量(最多 400 天、每個 agent 的 token、請求、訊息與依牌價換算的 API 等值)也會透過臨時公開連結提供。預設關閉;訪客一律看不到。變更立即生效。",
416
580
  webLogTab: "紀錄分頁:每個 agent 的步驟", webLogTabHint: "在每個 instance 的「紀錄」分頁顯示提示、回覆、工具呼叫與結果,以及 fleet 事件;只在分頁開著時從它自己的對話紀錄讀取。機密值會遮蔽。公開連結也看得到。開啟需 fleet admin 確認。",
417
581
  general: "一般設定",
418
582
  advanced: "進階",
@@ -461,7 +625,6 @@ register("settings", {
461
625
  wake: "喚醒",
462
626
  accessMode: "存取模式",
463
627
  affected: "受影響 instances",
464
- webEchoGroupConfirm: "這看起來是群組頻道:開啟後,這個 instance 的每則 web 訊息都會貼到所有頻道成員看得到的地方。確定要開啟 web echo?",
465
628
  language: "語言(bot 回覆)",
466
629
  defaultBackend: "預設後端",
467
630
  defaultModel: "預設模型",
@@ -504,6 +667,7 @@ register("settings", {
504
667
  applyPartial: "有部分變更失敗",
505
668
  applyClose: "關閉",
506
669
  settingsButton: "設定",
670
+ connRetryNow: "立即重試", connRetryQueued: "已要求重新連線。", connRetryFailed: "無法重試此連線,請檢查狀態後再試。",
507
671
  modalDone: "加入待套用",
508
672
  wizardButton: "設定精靈",
509
673
  wizardTitle: "設定 AgEnD",
@@ -577,6 +741,9 @@ register("settings", {
577
741
  changesApplied: "變更已套用,AgEnD 正在協調受影響的 Agent。",
578
742
  reviewChanges: "檢查變更",
579
743
  backendUnavailable: "{0}(已移除,請選擇其他 backend)",
744
+ backendNotInstalled: "未安裝", backendNotSignedIn: "未登入(請用 /login)", backendTooOld: "需要 {0} 以上版本", backendUnchecked: "尚未檢查",
745
+ modelNotListed: "目前使用中 — 不在這個 CLI 的清單裡", modelOther: "其他…", modelOtherLabel: "模型名稱", modelOtherPlaceholder: "這個 CLI 接受的模型名稱",
746
+ modelNone: "— 無 —", inheritValue: "沿用({0})", modelCliDefault: "CLI 自己的預設",
580
747
  readyApply: "可套用變更",
581
748
  copied: "已複製",
582
749
  expectedMapping: "預期為 mapping",
@@ -595,7 +762,7 @@ register("settings", {
595
762
  staggerWarning: "數值太低可能造成啟動尖峰",
596
763
  sec_device: "偏好設定", syncedTitle: "在你所有的裝置同步", syncedLead: "這裡的變更會套用到你登入的每一台裝置。",
597
764
  profileTitle: "你的名字",
598
- profileLeadBound: "agent 會把你從網頁送出的訊息,認成收到登入驗證碼的那個 Discord 或 Telegram 帳號:用它的 id,名字也用它的,除非你在這裡另外取名。它會跟著你到每一台登入的裝置。這只用來辨認,不代表任何權限。",
765
+ profileLeadBound: "agent 會把你從網頁送出的訊息,認成收到登入驗證碼的那個 Discord 或 Telegram 帳號:用它的 id,名字也用它的,除非你在這裡另外取名。它會跟著你到每一台登入的裝置。一般的請求,agent 會當作是你本人提出的;發布、破壞性操作、花費、密鑰,或把你的授權交給別人,則要先授權這個瀏覽器,或在 Discord、Telegram 上確認。",
599
766
  profileLeadUnbound: "這個瀏覽器不是用私訊到你 Discord 或 Telegram 帳號的驗證碼登入的,所以 agent 會把你的網頁訊息看成「web-user」(或你在這裡設定的名字)。用 /web 的驗證碼登入,就能被認成你的帳號。",
600
767
  profileName: "名字", profileHelp: "agent 看到:{0} · id {1}", profileSave: "儲存", profileClear: "改回 web-user", profileUseAccount: "改用 {0}",
601
768
  profileSaved: "agent 現在會看到你是 {0}", profileFailed: "無法儲存名字",
@@ -661,6 +828,131 @@ register("settings", {
661
828
  accessTitle: "存取",
662
829
  webChat: "網頁聊天",
663
830
  sec_web: "網頁",
831
+ sec_appearance: "網頁外觀",
832
+ groupLook: "外觀", groupLayout: "你的版面", groupCss: "自己寫的樣式", groupMods: "擴充", groupAdvanced: "進階", learnMore: "了解更多:{0}",
833
+ colorTitle: "識別色", colorLead: "單一 agent 的顏色:⋯ 選單 → 顏色…",
834
+ colorPlaces: "顏色顯示的位置", colorSample: "範例 agent", colorOff: "關閉顏色",
835
+ colorOffLead: "已挑選的顏色會保留。",
836
+ restoreTitle: "還原預設值", restoreLead: "把這台主機的外觀改回預設值,會先詢問。",
837
+ restoreConfirm: "會重設這台主機的:是否顯示 agent 的主題與效果、卡片大小與各張卡片自己的大小、你的側欄小工具、顏色顯示的位置、是否關閉顏色;也會關閉你的自訂 CSS(版本會保留)與這台裝置上的 CSS 開關。不變:有人替 agent 挑的顏色、已安裝的 mod、上傳的效果與卡片上限。",
838
+ restoreGo: "還原預設值", restoreDone: "外觀設定已改回預設值。", restoreCssFailed: "設定已改回預設值,但無法關閉你的自訂 CSS:{0}",
839
+ cardSizeTitle: "身分卡",
840
+ cardSizeLead: "卡片上的 小/中/大 可單獨設定。",
841
+ cardLimitsTitle: "身分卡上傳限制",
842
+ cardLimitsLead: "留空=預設值。調高上限需管理員確認。",
843
+ cardLimitsUnavailable: "只有已登入的管理者能修改。",
844
+ cardLimit_portrait_max_width: "肖像寬度(px)", cardLimit_portrait_max_height: "肖像高度(px)", cardLimit_portrait_max_kib: "肖像大小(KiB)",
845
+ cardLimit_banner_max_width: "橫幅寬度(px)", cardLimit_banner_max_height: "橫幅高度(px)", cardLimit_banner_max_kib: "橫幅大小(KiB)",
846
+ cardLimit_instance_quota_files: "每個 agent 的圖片數", cardLimit_instance_quota_mib: "每個 agent 的圖片空間(MiB)",
847
+ cardLimitInForce: "實際生效:{0}(允許 {1}–{2})",
848
+ cardLimitsWhole: "每個限制須為整數,或留空使用預設值。",
849
+ cardLimitsNoChange: "沒有變更。",
850
+ cardLimitsSave: "儲存限制",
851
+ cardLimitsSaved: "已儲存。",
852
+ cardLimitsFailed: "未儲存:{0}",
853
+ themesTitle: "Agent 的主題",
854
+ themesShow: "顯示 agent 的主題、效果與小工具",
855
+ themesShowLead: "關閉時每個聊天看起來都一樣。",
856
+ themesFollowMotion: "效果:跟隨系統的「減少動態效果」設定",
857
+ themesFollowMotionLead: "只套用於這台裝置:系統減少動態效果時,效果保持靜止。",
858
+ themesSafeMode: "這個頁面是用 ?safe=1 開啟的:不顯示 agent 的主題。",
859
+ widgetTitle: "你的側邊欄小工具",
860
+ widgetLead: "agent 清單下方的小面板,用 JSON 撰寫。",
861
+ widgetNotJson: "不是 JSON。",
862
+ widgetSave: "儲存小工具",
863
+ widgetSaved: "已儲存側邊欄小工具。",
864
+ widgetExample: "從範例開始",
865
+ widgetRemove: "移除小工具",
866
+ widgetRemoved: "已移除側邊欄小工具。",
867
+ modsTitle: "Mod",
868
+ modsLead: "只套用你勾選的部分。",
869
+ modsLoadFailed: "無法載入已安裝的 mod。請重新載入頁面再試一次。",
870
+ modsNone: "尚未安裝任何 mod。",
871
+ modChoose: "匯入 mod 檔案…",
872
+ modPlan: "這個 mod 會變更的內容",
873
+ modAuthor: "作者:{0}(未經驗證)",
874
+ modSizeId: "{0} · id {1}",
875
+ modAlready: "已安裝",
876
+ modReplace: "取代已安裝的 {0} 版",
877
+ modPartTheme: "主題(顏色、字型、圖片)",
878
+ modPartIdentity: "身分卡文字(標語與簡介)",
879
+ modPartAmbient: "環境效果(飄落、上升、閃爍或點擊符號)",
880
+ modPartWidget_chat_header: "聊天標頭小工具",
881
+ modPartWidget_details: "詳細資料頁小工具",
882
+ modPartWidget_sidebar: "你的側邊欄小工具",
883
+ modPartEffect: "效果:{0}",
884
+ modPartCss: "自訂 CSS(只套用在你的畫面)",
885
+ modCssWarn: "這是檔案裡的自訂 CSS——開啟前請先讀過。",
886
+ modCssAssets: "附帶 {0} 個檔案({1})",
887
+ modAccent: "強調色", modFont: "字型", modPictures: "{0} 張圖片({1})", modPlaces: "放置 {0} 個效果",
888
+ modColorsLight: "淺色模式顏色", modColorsDark: "深色模式顏色", modBubble: "對話泡泡", modWorkingLabel: "工作中文字",
889
+ modBackground: "背景圖片", modBackgroundFit: "背景填滿方式與不透明度", modAvatar: "圖片(頭像)",
890
+ modPlacesEffect: "放置效果", modAllFields: "所有欄位(套用時的樣子)",
891
+ modStageGone: "那次匯入已被取代或已逾時。以下顯示目前暫存的內容。",
892
+ modRegions: "繪製於:{0}", modWants: "接收:{0}",
893
+ modTarget: "套用到",
894
+ modTargetPick: "選擇一個 agent…",
895
+ modTargetNeeded: "請選擇這套外觀要套用到哪個 agent。",
896
+ modAppliedTo: "套用於 {0}",
897
+ modInstall: "安裝",
898
+ modCancel: "取消",
899
+ modInstalled: "已安裝 {0}。",
900
+ modFailed: "未完成:{0}",
901
+ modDownload: "下載",
902
+ modUninstall: "解除安裝",
903
+ modUninstallConfirm: "要解除安裝 {0} 嗎?它的效果會離開你的效果庫,除非還有東西在使用。它已套用的外觀會保留。",
904
+ modUninstalled: "已解除安裝 {0}。",
905
+ modExport: "匯出 mod",
906
+ modExportLead: "把目前生效的外觀存成 mod 檔。",
907
+ modExportInstance: "Agent",
908
+ modExportName: "名稱(a-z、0-9、-)",
909
+ modExportVersion: "版本",
910
+ modExportTitle: "標題",
911
+ modExportGo: "下載檔案",
912
+ modExportOmitted: "有 {0} 個放在那裡的效果屬於別人,已略過:只有你自己的和共用的效果會被帶走。",
913
+ modProposals: "Agent 提議的 mod",
914
+ modProposedBy: "{0} 提議",
915
+ modReview: "檢視",
916
+ modDismiss: "略過",
917
+ cssTitle: "自訂 CSS(只套用在你自己)",
918
+ cssLead: "只套用在你的畫面。",
919
+ cssLoadFailed: "無法載入你的自訂 CSS。請重新整理頁面再試一次。",
920
+ cssPublicLink: "臨時公開連結無法使用自訂 CSS。",
921
+ cssInForce: "使用中:{0}",
922
+ cssOnTrial: "試用中:{0}。請按「保留」,否則會還原。",
923
+ cssNone: "目前沒有使用自訂 CSS。",
924
+ cssSave: "儲存並試用",
925
+ cssTrying: "已儲存自訂 CSS。請到各頁看看,15 秒內按「保留」。",
926
+ cssOff: "關閉(所有裝置)",
927
+ cssVersions: "先前的版本({0})",
928
+ cssCurrent: "使用中",
929
+ cssRestore: "改用這版",
930
+ cssAssets: "資源",
931
+ cssAssetsLead: "{0} / {1} 個檔案,合計 {2}(全部合計最多 1 MiB)。",
932
+ cssAssetAdd: "加入圖片或字型",
933
+ cssAssetCopy: "複製引用",
934
+ cssCopied: "已複製 {0}",
935
+ cssAssetRemove: "移除",
936
+ cssDeviceTitle: "這台裝置",
937
+ cssDeviceOff: "在這台裝置關閉自訂 CSS",
938
+ cssSafe: "畫面被藏起來?在網址後加上 ?safe=1。",
939
+ cssError_at_rule: "未儲存:不允許使用 {0}。",
940
+ cssError_url: "未儲存:url() 只能用 url(\"asset:<id>\") 引用「資源」裡的檔案。",
941
+ cssError_unknown_asset: "未儲存:找不到資源 {0}。請先在「資源」加入它。",
942
+ cssError_function: "未儲存:不允許使用 {0}。",
943
+ cssError_property: "未儲存:不允許使用 {0}。",
944
+ cssError_script_scheme: "未儲存:不允許使用 javascript: 和 vbscript:。",
945
+ cssError_too_large: "未儲存:自訂 CSS 最多 64 KiB。",
946
+ cssError_malformed: "未儲存:有字串或 url() 沒有結束。",
947
+ cssError_nul: "未儲存:內容含有 NUL 字元。",
948
+ cssError_unserialisable: "未儲存:這份 CSS 無法安全地重新輸出。",
949
+ cssError_asset_type: "未加入:只接受 PNG、WebP、JPEG、GIF 或 WOFF2 檔案。",
950
+ cssError_asset_unreadable: "未加入:無法讀取這個檔案。",
951
+ cssError_asset_quota: "未加入:資源最多 16 個檔案、合計 1 MiB。",
952
+ cssError_asset_in_use: "未移除:仍有已儲存的版本在使用它。",
953
+ cssError_owner_css_read_only: "這個登入只能檢視、不能變更自訂 CSS。",
954
+ cssError_owner_css_needs_a_signed_in_person: "請在瀏覽器登入後再變更自訂 CSS。",
955
+ cssError_other: "未儲存({0})。",
664
956
  webLead: "網頁儀表板的行為。放寬存取的變更(延長 session、重新開啟或延長瀏覽器終端機、公開連結)需要 fleet admin 在聊天(General topic)或主機上確認;收緊的變更會立即套用。",
665
957
  webPublicRefused: "無法透過臨時公開連結變更網頁設定。請從儀表板本身的網址開啟後再變更。",
666
958
  webSessionTitle: "登入 session",
@@ -676,6 +968,28 @@ register("settings", {
676
968
  webTerminalTtl: "終端機 session 分鐘數(1–20)",
677
969
  webTerminalTtlRange: "必須是 1 到 20 之間的整數",
678
970
  webReadOnlyTitle: "在 fleet.yaml 設定",
971
+ guestsTitle: "訪客", guestsReview: "檢視訪客變更",
972
+ guestsHint: "不是管理者的人可以用訪客身分登入網頁:在他本來就能聊天的地方傳 /web,就會私下收到登入碼。訪客只會看到在聊天中本來就能用的 agent,他的訊息僅供辨識。",
973
+ guestsEnabled: "訪客登入", guestsEnabledHint: "關閉:沒有人能以訪客登入,所有訪客 session 都會結束。開啟需 fleet admin 確認。",
974
+ guestsChat: "訪客可以聊天", guestsChatHint: "關閉:訪客可以讀他的 agent 的聊天,但不能送訊息、附加檔案、按回覆的按鈕或按取消。",
975
+ guestsOpenFor: "{0}({1})訪客可用的 agent", guestsOpenHint: "這個連線對所有人開放,沒有人員名單:它的訪客只能用你在這裡勾選的 agent(預設沒有)。新增 agent 需 fleet admin 確認。",
976
+ guestsList: "訪客帳號", guestsNone: "還沒有訪客登入過。", guestsLoadFailed: "無法載入訪客清單。",
977
+ guestFacts: "agent:{0} · session:{1} · 記住的瀏覽器:{2}", guestLastActive: "最後使用 {0}", guestNotSignedIn: "目前未登入",
978
+ guestNotNarrowed: "可用他在聊天中能用的所有 agent。", guestNarrowedTo: "已縮小為:{0}", guestNothing: "無",
979
+ guestNarrow: "縮小範圍", guestNotReachable: "(已無法使用)", guestReachesNothing: "這個帳號目前在聊天中沒有能用的 agent,沒有可以縮小的範圍。", guestNarrowLift: "取消縮小", guestNarrowHint: "勾選這位訪客仍可使用的 agent。縮小只會拿走權限(立即生效);放寬或取消縮小需 fleet admin 確認。",
980
+ guestSignOut: "登出", guestSignOutTitle: "登出這位訪客?", guestSignOutConfirm: "{0} 的訪客 session 會立即結束,登入碼失效,記住的瀏覽器也會被忘記。訪客登入開啟期間,他可以再傳 /web 登入。",
981
+ guestSignedOut: "已登出 {0}。", guestSignedOutNotDurable: "已暫時登出 {0},但無法保存:重新啟動後他的 session 可能會恢復。", guestSignOutFailed: "沒有成功,請再試一次。",
982
+ vaTitle: "網頁授權", vaReview: "檢視網頁授權變更",
983
+ vaHint: "已登入的 fleet 管理者從網頁送出的訊息,是否帶有他本人帳號的授權,記錄在每則訊息的送達收據中。用私下傳給該帳號的登入碼、透過直接連線的 dashboard 登入的 session,要在 Discord 或 Telegram 上授權一次;公開連結與訪客一律不行。一般的網頁請求,agent 本來就會照做;發布、破壞性操作、花費、密鑰,或把授權交給別人,則需要它。",
984
+ vaLoadFailed: "無法載入網頁授權。",
985
+ vaEnabled: "網頁訊息帶有授權", vaEnabledHint: "預設開啟:session 要等它的帳號在 Discord 或 Telegram 上確認後才帶有授權。關閉:網頁訊息都不帶授權,已給出的授權立即視為無;關閉前給出的授權不會恢復。",
986
+ vaStuckOff: "網頁授權目前是關閉的:它的狀態無法存到這台電腦上(請看 fleet 紀錄)。可以存入後會自動恢復。",
987
+ vaLoopbackOnly: "只有這台電腦可以授權", vaLoopbackOnlyHint: "開啟:只有這台電腦上的瀏覽器符合,網路或 tailnet 上的不算,之前從其他地方給出的授權視為無。再關掉也不會讓那些授權恢復。",
988
+ vaLanWarning: "dashboard 也接受 {0} 的連線(web.allowed_hosts)。任何人只要從那裡連上、又拿到被盜的登入,就能以你的名義給出授權。除非你信任所有能連到那裡的人,否則請開啟「只有這台電腦可以授權」。",
989
+ vaHours: "一次授權的有效期(小時,{0}–{1})", vaHoursRange: "必須是 1 到 48 之間的數字",
990
+ vaSessionsTitle: "已授權的 session", vaSessionsNone: "目前沒有已授權的 session。", vaSessionUntil: "{0} 授權 · 到 {1}",
991
+ vaRevoke: "撤銷網頁授權", vaRevokeTitle: "撤銷所有網頁授權?", vaRevokeConfirm: "到目前為止從網頁給出的授權,從現在起都視為無,所有 session 的授權也會結束。不會登出任何人:session 再授權一次後,送出的訊息會再帶有授權。",
992
+ vaRevoked: "已撤銷到目前為止的網頁授權。", vaRevokedNotDurable: "已暫時撤銷,但無法保存:在可以保存之前網頁授權會保持關閉,而在那之前重新啟動會讓這次撤銷失效。", vaRevokeFailed: "沒有成功,請再試一次。",
679
993
  webReadOnlyLead: "這裡僅供檢視:這些設定決定儀表板監聽和公開的內容。請編輯 fleet.yaml 後執行 agend reload(web.preview_port 與 web.preview_origin 需要重新啟動 AgEnD)。",
680
994
  notSet: "未設定(預設)",
681
995
  defaultsTitle: "預設值",
@@ -724,7 +1038,19 @@ register("settings", {
724
1038
  discardOnLeave: "要捨棄 {0} 項尚未套用的變更嗎?",
725
1039
  applyBusyLocal: "還有一次套用在進行中——請等它完成。",
726
1040
  applyStepFailed: "在某項變更停下:{0}。之後的變更沒有套用,已重新暫存。",
727
- stepWaiting: "等待在聊天中確認",
1041
+ applyError_unsupported_sensitive_effect: "它改到的設定無法在確認中安全顯示,所以什麼都沒有改",
1042
+ applyError_confirmation_diff_too_large: "一次要確認的內容太多;請分幾次套用",
1043
+ applyError_session_required: "你的登入已經結束;請重新登入再套用",
1044
+ applyError_admin_required: "只有 fleet 管理者能確認它",
1045
+ applyError_settings_changed: "設定在這期間被改過了;請檢查後再套用一次",
1046
+ applyError_request_no_longer_current: "設定在這期間被改過了;請檢查後再套用一次",
1047
+ applyError_too_many_pending_changes: "等待確認的變更太多;請先確認或撤回一些",
1048
+ applyError_fleet_unavailable: "fleet 沒有在執行",
1049
+ applyError_invalid_settings_effect: "改完的結果不是有效的設定",
1050
+ applyError_settings_confirmation_unavailable: "無法建立它的確認;請再試一次",
1051
+ applyError_failed: "伺服器無法套用它",
1052
+ applyErrorOther: "伺服器拒絕了它({0})",
1053
+ stepWaiting: "等待確認",
728
1054
  stepSkipped: "未套用",
729
1055
  viaRestart: "(重新啟動)",
730
1056
  format: "格式",
@@ -741,7 +1067,6 @@ register("settings", {
741
1067
  discordUserPlaceholder: "你的 Discord 使用者 id",
742
1068
  telegramUserPlaceholder: "你的 Telegram 使用者 id",
743
1069
  bindingApplyButton: "改綁",
744
- webEchoEnable: "開啟網頁轉發",
745
1070
  help1: "Agent:每個 agent 的設定、啟動/停止、暫停/喚醒,以及新增 agent。",
746
1071
  help2: "連線:誰可以使用各個 bot、它的綁定、狀態表情、新的 token;以及供應商 API key。",
747
1072
  help3: "ClassicBot:每個房間的 backend、model 與選項。",
@@ -0,0 +1,91 @@
1
+ // #1939 S2a: Settings → Web → Web authority — whether a signed-in admin's web messages carry their account's authority
2
+ // in delivery receipts (docs/design/1939-verified-web-sessions.md §0, §0.1, §3, §10): the server switch (on by default),
3
+ // "Only this computer can authorize", how long a session's authorization lasts, the sessions authorized now, and "Revoke
4
+ // web authority". Changes go through Review changes → Apply like every Settings edit, and apply at once (§0.1: none of
5
+ // them grants anything by itself — a session still needs its account's Confirm in Discord or Telegram).
6
+ import { html, useEffect, useState } from "/assets/app-html.js";
7
+ import { t } from "/assets/app-i18n.js";
8
+ import { toast } from "/assets/ui-toast.js";
9
+ import { confirmDialog } from "/assets/ui-confirm.js";
10
+ import { api } from "./settings-confirm.js";
11
+ import { Feedback } from "./settings-dialogs.js";
12
+ import { resetWebAuthorization } from "/assets/web-authorize.js";
13
+ import "./settings-strings.js";
14
+
15
+ const tn = (k, ...v) => t(`settings.${k}`, ...v);
16
+
17
+ /** What changed against what fleet.yaml says, as the PUT /api/settings/fleet/web body's `verified_authority` (null: nothing). */
18
+ export function verifiedAuthorityBody(original, f) {
19
+ const out = {};
20
+ if (f.enabled !== original.enabled) out.enabled = f.enabled ? null : false; // §0.1: on is the default
21
+ if (f.loopbackOnly !== original.loopbackOnly) out.loopback_only = f.loopbackOnly ? true : null;
22
+ if (f.hours !== original.hours) out.max_session_hours = f.hours === null ? null : f.hours;
23
+ return Object.keys(out).length ? out : null;
24
+ }
25
+
26
+ export function WebAuthorityCard({ ctx, staged, disabled = false }) {
27
+ const [overview, setOverview] = useState(null), [failed, setFailed] = useState(false);
28
+ const [original, setOriginal] = useState(null), [f, setF] = useState(null), [msg, setMsg] = useState(null);
29
+ const load = async () => {
30
+ // What changes here (a revoke, the switch) changes this browser's own line: the chat reads it again when it shows.
31
+ resetWebAuthorization();
32
+ let r = null;
33
+ try { r = await api("/api/settings/web-authority"); } catch { r = null; }
34
+ // Anything but the overview's shape (an older server, an error page) is "could not be loaded", never a crash.
35
+ const o = r && r.ok ? r.body : null;
36
+ if (!o || typeof o !== "object" || !o.state || !o.hours || !Array.isArray(o.lanHosts) || !Array.isArray(o.authorized)) { setFailed(true); return; }
37
+ const c = o.configured || {};
38
+ const orig = { enabled: c.enabled !== false, loopbackOnly: c.loopback_only === true, hours: typeof c.max_session_hours === "number" ? c.max_session_hours : null };
39
+ setOverview(o); setFailed(false);
40
+ setOriginal((prev) => prev || orig);
41
+ setF((prev) => prev || { ...orig });
42
+ };
43
+ useEffect(() => { load(); }, []);
44
+ const card = (body) => html`<section class="card s-web-authority"><h3>${tn("vaTitle")}</h3><p class="note">${tn("vaHint")}</p>${body}</section>`;
45
+ if (failed) return card(html`<p class="note" role="status">${tn("vaLoadFailed")} <button type="button" class="btn btn-sm" onClick=${load}>${t("app.retry")}</button></p>`);
46
+ if (!overview || !f) return card(html`<p class="note">${t("app.loading")}</p>`);
47
+
48
+ const set = (patch) => setF((x) => ({ ...x, ...patch }));
49
+ const hoursText = f.hours === null ? "" : String(f.hours);
50
+ const hoursError = f.hours !== null && (!Number.isFinite(f.hours) || f.hours < overview.hours.min || f.hours > overview.hours.max) ? "vaHoursRange" : "";
51
+ const stuckOff = f.enabled && original.enabled && !overview.state.enabled;
52
+ const warnHosts = !f.loopbackOnly && overview.lanHosts.length > 0;
53
+ const when = (ms) => new Date(ms).toLocaleString();
54
+
55
+ const review = () => {
56
+ if (hoursError) return;
57
+ const body = verifiedAuthorityBody(original, f);
58
+ if (body) ctx.stage("verified_authority", { label: tn("vaTitle"), impact: "now", request: { method: "PUT", url: "/api/settings/fleet/web", body: { verified_authority: body } } });
59
+ else if (staged.has("verified_authority")) ctx.unstage("verified_authority");
60
+ setMsg(tn("readyApply"));
61
+ };
62
+ const revoke = async () => {
63
+ const yes = await confirmDialog({ title: tn("vaRevokeTitle"), message: tn("vaRevokeConfirm"), confirmLabel: tn("vaRevoke"), danger: true });
64
+ if (!yes) return;
65
+ let r = null;
66
+ try { r = await api("/api/settings/web-authority/revoke", { method: "POST", body: "{}" }); } catch { r = null; }
67
+ if (r && r.ok) { toast(tn(r.body && r.body.durable === false ? "vaRevokedNotDurable" : "vaRevoked")); load(); }
68
+ else toast(tn("vaRevokeFailed"), false);
69
+ };
70
+
71
+ return card(html`<fieldset class="s-va-fields" disabled=${disabled}>
72
+ ${stuckOff ? html`<p class="note s-va-warn" role="status" id="vaStuckOff">${tn("vaStuckOff")}</p>` : null}
73
+ <label class="check"><input id="vaEnabled" type="checkbox" checked=${f.enabled} onChange=${(e) => set({ enabled: e.target.checked })} /><span>${tn("vaEnabled")}</span></label>
74
+ <p class="note">${tn("vaEnabledHint")}</p>
75
+ <label class="check"><input id="vaLoopbackOnly" type="checkbox" checked=${f.loopbackOnly} onChange=${(e) => set({ loopbackOnly: e.target.checked })} /><span>${tn("vaLoopbackOnly")}</span></label>
76
+ <p class="note">${tn("vaLoopbackOnlyHint")}</p>
77
+ ${warnHosts ? html`<p class="note s-va-warn" role="status" id="vaLanWarning">${tn("vaLanWarning", overview.lanHosts.join(", "))}</p>` : null}
78
+ <div class="field"><label for="vaHours">${tn("vaHours", overview.hours.min, overview.hours.max)}</label>
79
+ <input id="vaHours" type="number" min=${overview.hours.min} max=${overview.hours.max} step="any" placeholder=${tn("defaultHours", overview.hours.default)}
80
+ class=${hoursError ? "invalid" : ""} value=${hoursText} onInput=${(e) => set({ hours: e.target.value.trim() === "" ? null : Number(e.target.value) })} />
81
+ <${Feedback} error=${hoursError} /></div>
82
+ <h4>${tn("vaSessionsTitle")}</h4>
83
+ ${overview.authorized.length
84
+ ? html`<ul class="s-va-sessions" id="vaSessions">${overview.authorized.map((a) => html`<li key=${a.handle} data-handle=${a.handle}>
85
+ <strong>${a.label}</strong> <span class="note">${a.account}</span><br /><span class="note">${tn("vaSessionUntil", when(a.authorizedAt), when(a.until))}</span></li>`)}</ul>`
86
+ : html`<p class="note" id="vaSessionsNone">${tn("vaSessionsNone")}</p>`}
87
+ </fieldset>
88
+ <div class="save-row"><button type="button" class="btn btn-primary" id="vaReview" disabled=${disabled || !!hoursError} onClick=${review}>${tn("vaReview")}</button>
89
+ <button type="button" class="btn btn-danger" id="vaRevoke" disabled=${disabled} onClick=${revoke}>${tn("vaRevoke")}</button>
90
+ ${msg ? html`<span class="note" role="status">${msg}</span>` : null}</div>`);
91
+ }