@songsid/agend 2.3.2 → 2.3.3-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. package/dist/agent-cli-instructions.md +2 -2
  2. package/dist/agent-cli.js +13 -112
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.d.ts +0 -1
  5. package/dist/agent-endpoint.js +1 -9
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/agent-whats-new.d.ts +23 -5
  8. package/dist/agent-whats-new.js +58 -40
  9. package/dist/agent-whats-new.js.map +1 -1
  10. package/dist/auth-api.d.ts +0 -7
  11. package/dist/auth-api.js +1 -15
  12. package/dist/auth-api.js.map +1 -1
  13. package/dist/authority/authority-state.js +1 -1
  14. package/dist/authority/authority-state.js.map +1 -1
  15. package/dist/authority/web-authority.d.ts +9 -4
  16. package/dist/authority/web-authority.js +10 -5
  17. package/dist/authority/web-authority.js.map +1 -1
  18. package/dist/backend/antigravity.js +6 -1
  19. package/dist/backend/antigravity.js.map +1 -1
  20. package/dist/backend/claude-code.d.ts +20 -1
  21. package/dist/backend/claude-code.js +54 -29
  22. package/dist/backend/claude-code.js.map +1 -1
  23. package/dist/backend/claude-transcript-errors.d.ts +18 -0
  24. package/dist/backend/claude-transcript-errors.js +19 -0
  25. package/dist/backend/claude-transcript-errors.js.map +1 -0
  26. package/dist/backend/codex-session-lookup.d.ts +16 -3
  27. package/dist/backend/codex-session-lookup.js +45 -11
  28. package/dist/backend/codex-session-lookup.js.map +1 -1
  29. package/dist/backend/codex.d.ts +16 -0
  30. package/dist/backend/codex.js +184 -35
  31. package/dist/backend/codex.js.map +1 -1
  32. package/dist/backend/grok.js +58 -12
  33. package/dist/backend/grok.js.map +1 -1
  34. package/dist/backend/kiro-reconcile-store.js +8 -1
  35. package/dist/backend/kiro-reconcile-store.js.map +1 -1
  36. package/dist/backend/kiro.d.ts +0 -5
  37. package/dist/backend/kiro.js +2 -10
  38. package/dist/backend/kiro.js.map +1 -1
  39. package/dist/backend/muse.js +2 -1
  40. package/dist/backend/muse.js.map +1 -1
  41. package/dist/backend/types.d.ts +53 -4
  42. package/dist/backend/types.js.map +1 -1
  43. package/dist/bundled-skills.d.ts +4 -6
  44. package/dist/bundled-skills.js +10 -14
  45. package/dist/bundled-skills.js.map +1 -1
  46. package/dist/channel/adapters/discord.js +60 -17
  47. package/dist/channel/adapters/discord.js.map +1 -1
  48. package/dist/channel/mcp-server.js +5 -5
  49. package/dist/channel/mcp-server.js.map +1 -1
  50. package/dist/channel/mcp-tools.d.ts +1 -3
  51. package/dist/channel/mcp-tools.js +4 -58
  52. package/dist/channel/mcp-tools.js.map +1 -1
  53. package/dist/classic-channel-manager.d.ts +4 -1
  54. package/dist/classic-channel-manager.js +21 -7
  55. package/dist/classic-channel-manager.js.map +1 -1
  56. package/dist/cli.js +23 -6
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config-history.d.ts +50 -0
  59. package/dist/config-history.js +263 -0
  60. package/dist/config-history.js.map +1 -0
  61. package/dist/config-validator.js +10 -8
  62. package/dist/config-validator.js.map +1 -1
  63. package/dist/config.d.ts +3 -0
  64. package/dist/config.js +11 -4
  65. package/dist/config.js.map +1 -1
  66. package/dist/cross-instance-envelope.d.ts +10 -5
  67. package/dist/cross-instance-envelope.js +20 -17
  68. package/dist/cross-instance-envelope.js.map +1 -1
  69. package/dist/daemon.d.ts +130 -64
  70. package/dist/daemon.js +603 -428
  71. package/dist/daemon.js.map +1 -1
  72. package/dist/daily-summary.d.ts +8 -1
  73. package/dist/daily-summary.js +8 -5
  74. package/dist/daily-summary.js.map +1 -1
  75. package/dist/dashboard-live.d.ts +1 -1
  76. package/dist/dashboard-live.js +3 -3
  77. package/dist/dashboard-live.js.map +1 -1
  78. package/dist/dashboard-permissions.d.ts +1 -1
  79. package/dist/dashboard-permissions.js +1 -3
  80. package/dist/dashboard-permissions.js.map +1 -1
  81. package/dist/delivery-outbox.d.ts +31 -22
  82. package/dist/delivery-outbox.js +119 -161
  83. package/dist/delivery-outbox.js.map +1 -1
  84. package/dist/delivery-outbox.test.js +10 -25
  85. package/dist/delivery-outbox.test.js.map +1 -1
  86. package/dist/doctor.d.ts +4 -0
  87. package/dist/doctor.js +16 -1
  88. package/dist/doctor.js.map +1 -1
  89. package/dist/fleet-level-config.js +1 -1
  90. package/dist/fleet-level-config.js.map +1 -1
  91. package/dist/fleet-manager.d.ts +74 -66
  92. package/dist/fleet-manager.js +285 -414
  93. package/dist/fleet-manager.js.map +1 -1
  94. package/dist/fleet-process-handlers.d.ts +5 -0
  95. package/dist/fleet-process-handlers.js +21 -0
  96. package/dist/fleet-process-handlers.js.map +1 -1
  97. package/dist/fleet-service-owner.d.ts +11 -0
  98. package/dist/fleet-service-owner.js +3 -0
  99. package/dist/fleet-service-owner.js.map +1 -0
  100. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
  101. package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +1 -1
  102. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
  103. package/dist/general-knowledge/skills/session-management/SKILL.md +7 -1
  104. package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
  105. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +30 -68
  106. package/dist/instance-lifecycle.d.ts +19 -0
  107. package/dist/instance-lifecycle.js +73 -15
  108. package/dist/instance-lifecycle.js.map +1 -1
  109. package/dist/instructions.js +6 -7
  110. package/dist/instructions.js.map +1 -1
  111. package/dist/kiro-reconcile.js +3 -3
  112. package/dist/kiro-reconcile.js.map +1 -1
  113. package/dist/locale.js +96 -58
  114. package/dist/locale.js.map +1 -1
  115. package/dist/log-service.js +1 -1
  116. package/dist/log-service.js.map +1 -1
  117. package/dist/needs-you-hub.d.ts +1 -0
  118. package/dist/needs-you-hub.js +6 -3
  119. package/dist/needs-you-hub.js.map +1 -1
  120. package/dist/needs-you-live.d.ts +3 -1
  121. package/dist/needs-you-live.js +24 -2
  122. package/dist/needs-you-live.js.map +1 -1
  123. package/dist/needs-you.d.ts +13 -2
  124. package/dist/needs-you.js +11 -1
  125. package/dist/needs-you.js.map +1 -1
  126. package/dist/notify-socket.d.ts +10 -0
  127. package/dist/notify-socket.js +45 -0
  128. package/dist/notify-socket.js.map +1 -0
  129. package/dist/outbound-handlers.js +20 -8
  130. package/dist/outbound-handlers.js.map +1 -1
  131. package/dist/outbound-schemas.d.ts +0 -62
  132. package/dist/outbound-schemas.js +4 -43
  133. package/dist/outbound-schemas.js.map +1 -1
  134. package/dist/parked-notices.d.ts +87 -0
  135. package/dist/parked-notices.js +194 -0
  136. package/dist/parked-notices.js.map +1 -0
  137. package/dist/public-link-progress.d.ts +5 -2
  138. package/dist/public-link-progress.js +4 -3
  139. package/dist/public-link-progress.js.map +1 -1
  140. package/dist/public-web-gateway.js +0 -9
  141. package/dist/public-web-gateway.js.map +1 -1
  142. package/dist/public-web-link.d.ts +12 -0
  143. package/dist/public-web-link.js +29 -5
  144. package/dist/public-web-link.js.map +1 -1
  145. package/dist/quota-notice.d.ts +23 -0
  146. package/dist/quota-notice.js +22 -0
  147. package/dist/quota-notice.js.map +1 -0
  148. package/dist/scheduler/task-board.d.ts +17 -25
  149. package/dist/scheduler/task-board.js +29 -39
  150. package/dist/scheduler/task-board.js.map +1 -1
  151. package/dist/sd-notify.d.ts +23 -15
  152. package/dist/sd-notify.js +88 -29
  153. package/dist/sd-notify.js.map +1 -1
  154. package/dist/search/search-docs.d.ts +1 -1
  155. package/dist/search/search-docs.js +2 -2
  156. package/dist/search/search-docs.js.map +1 -1
  157. package/dist/settings-api.d.ts +16 -1
  158. package/dist/settings-api.js +56 -16
  159. package/dist/settings-api.js.map +1 -1
  160. package/dist/settings-change.js +3 -1
  161. package/dist/settings-change.js.map +1 -1
  162. package/dist/settings-confirmation.d.ts +17 -3
  163. package/dist/settings-confirmation.js +8 -5
  164. package/dist/settings-confirmation.js.map +1 -1
  165. package/dist/settings-effect.js +0 -2
  166. package/dist/settings-effect.js.map +1 -1
  167. package/dist/settings-http-confirmation.js +31 -1
  168. package/dist/settings-http-confirmation.js.map +1 -1
  169. package/dist/setup-wizard.d.ts +3 -0
  170. package/dist/setup-wizard.js +4 -2
  171. package/dist/setup-wizard.js.map +1 -1
  172. package/dist/task-board-waker.d.ts +43 -1
  173. package/dist/task-board-waker.js +121 -9
  174. package/dist/task-board-waker.js.map +1 -1
  175. package/dist/tmux-control.d.ts +1 -1
  176. package/dist/tmux-control.js +3 -2
  177. package/dist/tmux-control.js.map +1 -1
  178. package/dist/tmux-manager.js +18 -16
  179. package/dist/tmux-manager.js.map +1 -1
  180. package/dist/tmux-read.d.ts +2 -0
  181. package/dist/tmux-read.js +7 -1
  182. package/dist/tmux-read.js.map +1 -1
  183. package/dist/tool-permissions.js +3 -10
  184. package/dist/tool-permissions.js.map +1 -1
  185. package/dist/topic-commands.d.ts +29 -7
  186. package/dist/topic-commands.js +97 -37
  187. package/dist/topic-commands.js.map +1 -1
  188. package/dist/transcript-monitor.d.ts +7 -0
  189. package/dist/transcript-monitor.js +48 -3
  190. package/dist/transcript-monitor.js.map +1 -1
  191. package/dist/tunnel/cloudflared.d.ts +5 -0
  192. package/dist/tunnel/cloudflared.js +32 -1
  193. package/dist/tunnel/cloudflared.js.map +1 -1
  194. package/dist/tunnel/named-diagnostics.d.ts +2 -1
  195. package/dist/tunnel/named-diagnostics.js +4 -1
  196. package/dist/tunnel/named-diagnostics.js.map +1 -1
  197. package/dist/tunnel/named-link-test.d.ts +90 -0
  198. package/dist/tunnel/named-link-test.js +270 -0
  199. package/dist/tunnel/named-link-test.js.map +1 -0
  200. package/dist/tunnel/purpose-lane.d.ts +3 -1
  201. package/dist/tunnel/purpose-lane.js +2 -0
  202. package/dist/tunnel/purpose-lane.js.map +1 -1
  203. package/dist/types.d.ts +9 -11
  204. package/dist/ui/chat-ambient.js +4 -4
  205. package/dist/ui/chat-commands.js +3 -2
  206. package/dist/ui/chat-store.js +4 -1
  207. package/dist/ui/chat-strings.js +12 -46
  208. package/dist/ui/chat-thread.js +51 -59
  209. package/dist/ui/fleet-office-skin.js +37 -14
  210. package/dist/ui/fleet-office.js +31 -7
  211. package/dist/ui/html-attachment.js +22 -8
  212. package/dist/ui/panel-chat.js +21 -50
  213. package/dist/ui/panel-log.js +2 -2
  214. package/dist/ui/panel-needs.js +11 -9
  215. package/dist/ui/panel-settings.js +5 -3
  216. package/dist/ui/preview-panel.js +12 -21
  217. package/dist/ui/preview.js +10 -3
  218. package/dist/ui/search-dialog.js +30 -14
  219. package/dist/ui/settings-appearance.js +3 -37
  220. package/dist/ui/settings-confirm.js +18 -0
  221. package/dist/ui/settings-guests.js +13 -4
  222. package/dist/ui/settings-learn.js +1 -1
  223. package/dist/ui/settings-mods.js +5 -12
  224. package/dist/ui/settings-named-test.js +144 -0
  225. package/dist/ui/settings-registry.js +0 -2
  226. package/dist/ui/settings-strings.js +16 -16
  227. package/dist/ui/settings-web-authority.js +4 -3
  228. package/dist/ui/shared/app-i18n.js +15 -4
  229. package/dist/ui/shared/app-needs.js +5 -1
  230. package/dist/ui/shared/app-prefs.js +17 -17
  231. package/dist/ui/shared/app-shell.js +47 -9
  232. package/dist/ui/shared/app-store.js +6 -2
  233. package/dist/ui/shared/app.css +33 -39
  234. package/dist/ui/shared/app.js +5 -4
  235. package/dist/ui/shared/instance-nav.js +9 -9
  236. package/dist/ui/shared/instance-switch.js +8 -2
  237. package/dist/ui/shared/panel-view.js +22 -8
  238. package/dist/ui/shared/view-strings.js +6 -0
  239. package/dist/ui/shared/web-authorize.js +35 -13
  240. package/dist/update-check.d.ts +13 -4
  241. package/dist/update-check.js +17 -4
  242. package/dist/update-check.js.map +1 -1
  243. package/dist/usage/usage-api.d.ts +3 -0
  244. package/dist/usage/usage-api.js +5 -1
  245. package/dist/usage/usage-api.js.map +1 -1
  246. package/dist/view-api.d.ts +2 -0
  247. package/dist/view-api.js +64 -0
  248. package/dist/view-api.js.map +1 -1
  249. package/dist/web-api.d.ts +9 -17
  250. package/dist/web-api.js +257 -371
  251. package/dist/web-api.js.map +1 -1
  252. package/dist/web-appearance-tools.d.ts +0 -2
  253. package/dist/web-appearance-tools.js +2 -5
  254. package/dist/web-appearance-tools.js.map +1 -1
  255. package/dist/web-appearance-view.d.ts +0 -6
  256. package/dist/web-appearance-view.js +0 -1
  257. package/dist/web-appearance-view.js.map +1 -1
  258. package/dist/web-appearance.d.ts +14 -7
  259. package/dist/web-appearance.js +5 -6
  260. package/dist/web-appearance.js.map +1 -1
  261. package/dist/web-asset-parts.d.ts +1 -17
  262. package/dist/web-asset-parts.js +1 -15
  263. package/dist/web-asset-parts.js.map +1 -1
  264. package/dist/web-auth.js +1 -7
  265. package/dist/web-auth.js.map +1 -1
  266. package/dist/web-chat-history.d.ts +3 -7
  267. package/dist/web-chat-history.js +10 -17
  268. package/dist/web-chat-history.js.map +1 -1
  269. package/dist/web-commands.d.ts +9 -1
  270. package/dist/web-commands.js +13 -0
  271. package/dist/web-commands.js.map +1 -1
  272. package/dist/web-experimental.d.ts +3 -8
  273. package/dist/web-experimental.js +9 -33
  274. package/dist/web-experimental.js.map +1 -1
  275. package/dist/web-guest-access.d.ts +40 -2
  276. package/dist/web-guest-access.js +50 -14
  277. package/dist/web-guest-access.js.map +1 -1
  278. package/dist/web-mod-bundle.d.ts +2 -45
  279. package/dist/web-mod-bundle.js +15 -63
  280. package/dist/web-mod-bundle.js.map +1 -1
  281. package/dist/web-mod-store.d.ts +3 -48
  282. package/dist/web-mod-store.js +30 -97
  283. package/dist/web-mod-store.js.map +1 -1
  284. package/dist/web-prefs.d.ts +13 -0
  285. package/dist/web-prefs.js +38 -0
  286. package/dist/web-prefs.js.map +1 -1
  287. package/dist/web-preview.d.ts +6 -13
  288. package/dist/web-preview.js +12 -23
  289. package/dist/web-preview.js.map +1 -1
  290. package/dist/web-session.d.ts +11 -3
  291. package/dist/web-session.js +22 -11
  292. package/dist/web-session.js.map +1 -1
  293. package/dist/web-settings-patch.d.ts +1 -1
  294. package/dist/web-settings-patch.js +9 -7
  295. package/dist/web-settings-patch.js.map +1 -1
  296. package/dist/web-settings-tools.d.ts +0 -13
  297. package/dist/web-settings-tools.js +12 -84
  298. package/dist/web-settings-tools.js.map +1 -1
  299. package/dist/workflow-templates/default.md +2 -2
  300. package/dist/working-recovery.d.ts +0 -2
  301. package/dist/working-recovery.js +2 -23
  302. package/dist/working-recovery.js.map +1 -1
  303. package/launcher/agend-install.cjs +7 -1
  304. package/launcher/fleet-service-owner.cjs +150 -0
  305. package/package.json +1 -1
  306. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
  307. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -673
  308. package/dist/task-board-summary.d.ts +0 -101
  309. package/dist/task-board-summary.js +0 -177
  310. package/dist/task-board-summary.js.map +0 -1
  311. package/dist/ui/app-effects.js +0 -251
  312. package/dist/ui/chat-effect-posters.js +0 -42
  313. package/dist/ui/chat-effects.js +0 -167
  314. package/dist/ui/effect-trial-controller.js +0 -124
  315. package/dist/ui/effect-trial-offer.js +0 -2
  316. package/dist/ui/effect-trial-panel.js +0 -40
  317. package/dist/ui/effects-waker.js +0 -2
  318. package/dist/ui/settings-effects.js +0 -202
  319. package/dist/ui/settings-owner-effects.js +0 -82
  320. package/dist/ui/shared/effect-app-runtime.js +0 -299
  321. package/dist/ui/shared/effect-baseline.js +0 -64
  322. package/dist/ui/shared/effect-chat-runtime.js +0 -162
  323. package/dist/ui/shared/effect-cursor.js +0 -126
  324. package/dist/ui/shared/effect-display-metadata.js +0 -39
  325. package/dist/ui/shared/effect-frame.js +0 -146
  326. package/dist/ui/shared/effect-geometry.js +0 -137
  327. package/dist/ui/shared/effect-host-style.js +0 -10
  328. package/dist/ui/shared/effect-owner-regions.js +0 -74
  329. package/dist/ui/shared/effect-owner-source.js +0 -122
  330. package/dist/ui/shared/effect-policy.js +0 -151
  331. package/dist/ui/shared/effect-poster-reader.js +0 -98
  332. package/dist/ui/shared/effect-posters.js +0 -117
  333. package/dist/ui/shared/effect-profiler.js +0 -184
  334. package/dist/ui/shared/effect-profiles.js +0 -65
  335. package/dist/ui/shared/effect-registry.js +0 -545
  336. package/dist/ui/shared/effect-runtime-loader.js +0 -236
  337. package/dist/ui/shared/effect-safety.js +0 -153
  338. package/dist/ui/shared/effect-stock-snapshot.js +0 -43
  339. package/dist/ui/shared/effect-stock-trust.js +0 -217
  340. package/dist/ui/shared/effect-trial-shadow.js +0 -62
  341. package/dist/ui/shared/effect-trial-source.js +0 -103
  342. package/dist/ui/shared/effect-trial-stage.js +0 -170
  343. package/dist/ui/shared/effect-trial.css +0 -40
  344. package/dist/ui/shared/feature-flags.js +0 -127
  345. package/dist/ui/shared/owner-effect-prefs.js +0 -117
  346. package/dist/upgrade-notices.d.ts +0 -17
  347. package/dist/upgrade-notices.js +0 -93
  348. package/dist/upgrade-notices.js.map +0 -1
  349. package/dist/web-effect-bootstrap.d.ts +0 -12
  350. package/dist/web-effect-bootstrap.js +0 -49
  351. package/dist/web-effect-bootstrap.js.map +0 -1
  352. package/dist/web-effect-bundle.d.ts +0 -28
  353. package/dist/web-effect-bundle.js +0 -171
  354. package/dist/web-effect-bundle.js.map +0 -1
  355. package/dist/web-effect-canonical.d.ts +0 -8
  356. package/dist/web-effect-canonical.js +0 -27
  357. package/dist/web-effect-canonical.js.map +0 -1
  358. package/dist/web-effect-library.d.ts +0 -114
  359. package/dist/web-effect-library.js +0 -530
  360. package/dist/web-effect-library.js.map +0 -1
  361. package/dist/web-effect-playback.d.ts +0 -30
  362. package/dist/web-effect-playback.js +0 -71
  363. package/dist/web-effect-playback.js.map +0 -1
  364. package/dist/web-effect-poster.d.ts +0 -8
  365. package/dist/web-effect-poster.js +0 -52
  366. package/dist/web-effect-poster.js.map +0 -1
  367. package/dist/web-effect-profiles.d.ts +0 -118
  368. package/dist/web-effect-profiles.js +0 -181
  369. package/dist/web-effect-profiles.js.map +0 -1
  370. package/dist/web-effect-service.d.ts +0 -93
  371. package/dist/web-effect-service.js +0 -335
  372. package/dist/web-effect-service.js.map +0 -1
  373. package/dist/web-effect-tools.d.ts +0 -48
  374. package/dist/web-effect-tools.js +0 -129
  375. package/dist/web-effect-tools.js.map +0 -1
  376. package/dist/web-effect-trials.d.ts +0 -86
  377. package/dist/web-effect-trials.js +0 -204
  378. package/dist/web-effect-trials.js.map +0 -1
  379. package/dist/web-effect-upload.d.ts +0 -27
  380. package/dist/web-effect-upload.js +0 -185
  381. package/dist/web-effect-upload.js.map +0 -1
  382. package/dist/web-effect-worker.d.ts +0 -8
  383. package/dist/web-effect-worker.js +0 -170
  384. package/dist/web-effect-worker.js.map +0 -1
  385. package/dist/web-effect.d.ts +0 -103
  386. package/dist/web-effect.js +0 -153
  387. package/dist/web-effect.js.map +0 -1
  388. package/dist/web-experimental-http.d.ts +0 -2
  389. package/dist/web-experimental-http.js +0 -12
  390. package/dist/web-experimental-http.js.map +0 -1
  391. package/dist/web-mod-agent.d.ts +0 -50
  392. package/dist/web-mod-agent.js +0 -207
  393. package/dist/web-mod-agent.js.map +0 -1
@@ -393,16 +393,14 @@ register("settings", {
393
393
  modPartWidget_chat_header: "Chat header widget",
394
394
  modPartWidget_details: "Details page widget",
395
395
  modPartWidget_sidebar: "Your sidebar widget",
396
- modPartEffect: "Effect: {0}",
397
396
  modPartCss: "Custom CSS (on your screens only)",
398
397
  modCssWarn: "Custom CSS from this file — read it before turning it on.",
399
398
  modCssAssets: "{0} files for it ({1})",
400
399
  modAccent: "Accent", modFont: "Font", modPictures: "{0} pictures ({1})", modPlaces: "places {0} effects",
401
400
  modColorsLight: "Light colours", modColorsDark: "Dark colours", modBubble: "Bubbles", modWorkingLabel: "Working label",
402
401
  modBackground: "Background picture", modBackgroundFit: "Background fit and opacity", modAvatar: "Picture (face)",
403
- modPlacesEffect: "Places effect", modAllFields: "Every field, as it will be applied",
402
+ modAllFields: "Every field, as it will be applied",
404
403
  modStageGone: "That import was replaced or ran out of time. Showing what is staged now.",
405
- modRegions: "draws on: {0}", modWants: "hears: {0}",
406
404
  modTarget: "Apply to",
407
405
  modTargetPick: "Choose an agent…",
408
406
  modTargetNeeded: "Choose the agent this look goes to.",
@@ -412,7 +410,7 @@ register("settings", {
412
410
  modInstalled: "Installed {0}.",
413
411
  modFailed: "Not done: {0}",
414
412
  idLine: "ID: {0}",
415
- modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects, an experimental feature. Turn it on in Settings → Web dashboard first.",
413
+ modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects, which AgEnD no longer runs.",
416
414
  modDownload: "Download",
417
415
  modUninstall: "Uninstall",
418
416
  modUninstallConfirm: "Uninstall {0}? Its effects leave your library unless something still uses them. What it applied stays.",
@@ -472,7 +470,7 @@ register("settings", {
472
470
  cssTitle: "Custom CSS (yours only)",
473
471
  cssLead: "Applies to your screens only.",
474
472
  cssLoadFailed: "Couldn't load your custom CSS. Reload the page to try again.",
475
- cssPublicLink: "Custom CSS isn't available on a temporary public link.",
473
+ cssPublicLink: "Custom CSS isn't available over a public link.",
476
474
  cssInForce: "In force: {0}",
477
475
  cssOnTrial: "On trial: {0}. Choose Keep, or it reverts.",
478
476
  cssNone: "No custom CSS in force.",
@@ -509,9 +507,9 @@ register("settings", {
509
507
  cssError_owner_css_needs_a_signed_in_person: "Sign in in the browser to change custom CSS.",
510
508
  cssError_other: "Not saved ({0}).",
511
509
  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.",
512
- webPublicRefused: "Web settings can't be changed over a temporary public link. Open the dashboard at its own address to change them.",
510
+ webPublicRefused: "Web settings can't be changed over a public link. Open the dashboard at its own address to change them.",
513
511
  webSessionTitle: "Sign-in sessions",
514
- webSessionHint: "For sign-ins at the dashboard's own address (this computer, the LAN, a tailnet). A temporary public link always keeps 4 h / 30 min. Shortening ends the sessions it now outlives; lengthening applies to new sign-ins and to an existing one's idle time on its next use. Empty = the default.",
512
+ webSessionHint: "For sign-ins at the dashboard's own address (this computer, the LAN, a tailnet). Over a public link (a temporary one or your permanent link), a session lasts at most 8 h, ends after 30 min idle and never outlives the link; an admin's also never lasts longer than these settings (a guest's follows the guest settings). Shortening ends the sessions it now outlives; lengthening applies to new sign-ins and to an existing one's idle time on its next use. Empty = the default.",
515
513
  sessionAbsolute: "Session length, hours (1–720)",
516
514
  sessionIdle: "Sign out after unused for, hours (1–720)",
517
515
  sessionRange: "Must be a number of hours from 1 to 720",
@@ -541,6 +539,8 @@ register("settings", {
541
539
  grantsChoose: "Choose", grantsChosen: "Chosen", grantsMaySee: "{0} may see:", grantsClassicRooms: "ClassicBot rooms", grantsWroteHere: "wrote here", grantsWroteTo: "Wrote to: {0}",
542
540
  grantsLastSeen: "last seen {0}", grantsRecent: "Recent changes", grantsRecentNone: "No change to anyone's access yet.", grantsAuditDirect: "applied at once", grantsAuditConfirmed: "confirmed in General", grantsAuditEnded: "{0} session(s) ended", grantsAuditCodeSent: "sign-in code sent", grantsAuditCodeNot: "sign-in code not sent ({0})", grantsAuditDmFailed: "the DM did not go through", grantsAuditWait: "asked again within a minute", grantsAuditAdminLimit: "the admin's limit of codes was reached",
543
541
  grantsEditAgents: "Edit agents", grantsRemove: "Remove access", grantsUndoRemove: "Keep access",
542
+ grantsLevel: "What {0} may do", grantsLevelChat: "Chat", grantsLevelTrusted: "Trusted",
543
+ grantsLevelTrustedHint: "Trusted adds watching these agents' screens (read-only) and searching their chats. The screen shows everything the agent's terminal does: other people's messages to it, commands and their output, which can include secrets. Chat and search stay limited to what this person may see.", grantsAuditLevel: "→ {0}",
544
544
  grantsWillBeRemoved: "Access ends when you save.", grantsNew: "New — granted when you save", grantsNoAgents: "Tick at least one agent, or remove this person.",
545
545
  grantsSend: "Send sign-in code", grantsSendAgain: "Send again in {0}", grantsSendSaveFirst: "Save first: a code goes only to saved access.",
546
546
  grantsSent: "Code sent {0} · expires {1}", grantsSentPublic: "It works on the open public link too.", grantsSending: "Sending…",
@@ -561,7 +561,7 @@ register("settings", {
561
561
  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.",
562
562
  vaNamedLink: "Also over my named link ({0})", vaNamedLinkHint: "On: a browser signed in over your own named-tunnel hostname may be authorized too (the same Confirm in your DM). It is reached from the internet, and Cloudflare sees its traffic: turning this on is confirmed in a General or on this computer. Off applies at once, and every authorization given over it reads as none. The temporary public link has its own option below.",
563
563
  vaSessionNamed: "over your named link",
564
- vaQuickLink: "Also over the temporary public link", vaQuickLinkHint: "On: a browser signed in over the temporary public link that /web opens may be authorized too (the same Confirm in your DM). That link is an address on the internet, served by Cloudflare's quick-tunnel service, which sees its traffic. Turning this on is confirmed in a General or on this computer, and ends every authorization given so far (each browser confirms again). Turning it off applies at once. An authorized browser's authority ends with the link.",
564
+ vaQuickLink: "Also over the temporary public link", vaQuickLinkHint: "On by default: a browser signed in over the temporary public link that /web opens may be authorized too (the same Confirm in your DM). That link is an address on the internet, served by Cloudflare's quick-tunnel service, which sees its traffic. Turning it back on is confirmed in a General or on this computer, and ends every authorization given so far (each browser confirms again). Turning it off applies at once. An authorized browser's authority ends with the link.",
565
565
  vaSessionQuick: "over the temporary public link",
566
566
  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.",
567
567
  vaHours: "An authorization lasts (hours, {0}–{1})", vaHoursRange: "Must be a number from 1 to 48",
@@ -1047,16 +1047,14 @@ register("settings", {
1047
1047
  modPartWidget_chat_header: "聊天標頭小工具",
1048
1048
  modPartWidget_details: "詳細資料頁小工具",
1049
1049
  modPartWidget_sidebar: "你的側邊欄小工具",
1050
- modPartEffect: "效果:{0}",
1051
1050
  modPartCss: "自訂 CSS(只套用在你的畫面)",
1052
1051
  modCssWarn: "這是檔案裡的自訂 CSS——開啟前請先讀過。",
1053
1052
  modCssAssets: "附帶 {0} 個檔案({1})",
1054
1053
  modAccent: "強調色", modFont: "字型", modPictures: "{0} 張圖片({1})", modPlaces: "放置 {0} 個效果",
1055
1054
  modColorsLight: "淺色模式顏色", modColorsDark: "深色模式顏色", modBubble: "對話泡泡", modWorkingLabel: "工作中文字",
1056
1055
  modBackground: "背景圖片", modBackgroundFit: "背景填滿方式與不透明度", modAvatar: "圖片(頭像)",
1057
- modPlacesEffect: "放置效果", modAllFields: "所有欄位(套用時的樣子)",
1056
+ modAllFields: "所有欄位(套用時的樣子)",
1058
1057
  modStageGone: "那次匯入已被取代或已逾時。以下顯示目前暫存的內容。",
1059
- modRegions: "繪製於:{0}", modWants: "接收:{0}",
1060
1058
  modTarget: "套用到",
1061
1059
  modTargetPick: "選擇一個 agent…",
1062
1060
  modTargetNeeded: "請選擇這套外觀要套用到哪個 agent。",
@@ -1066,7 +1064,7 @@ register("settings", {
1066
1064
  modInstalled: "已安裝 {0}。",
1067
1065
  modFailed: "未完成:{0}",
1068
1066
  idLine: "ID:{0}",
1069
- modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker 效果,這是實驗性功能。請先到「設定 → 網頁儀表板」開啟。",
1067
+ modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker 效果,AgEnD 已不再執行這類效果。",
1070
1068
  modDownload: "下載",
1071
1069
  modUninstall: "解除安裝",
1072
1070
  modUninstallConfirm: "要解除安裝 {0} 嗎?它的效果會離開你的效果庫,除非還有東西在使用。它已套用的外觀會保留。",
@@ -1126,7 +1124,7 @@ register("settings", {
1126
1124
  cssTitle: "自訂 CSS(只套用在你自己)",
1127
1125
  cssLead: "只套用在你的畫面。",
1128
1126
  cssLoadFailed: "無法載入你的自訂 CSS。請重新整理頁面再試一次。",
1129
- cssPublicLink: "臨時公開連結無法使用自訂 CSS。",
1127
+ cssPublicLink: "透過公開連結無法使用自訂 CSS。",
1130
1128
  cssInForce: "使用中:{0}",
1131
1129
  cssOnTrial: "試用中:{0}。請按「保留」,否則會還原。",
1132
1130
  cssNone: "目前沒有使用自訂 CSS。",
@@ -1163,9 +1161,9 @@ register("settings", {
1163
1161
  cssError_owner_css_needs_a_signed_in_person: "請在瀏覽器登入後再變更自訂 CSS。",
1164
1162
  cssError_other: "未儲存({0})。",
1165
1163
  webLead: "網頁儀表板的行為。放寬存取的變更(延長 session、重新開啟或延長瀏覽器終端機、公開連結)需要 fleet admin 在聊天(General topic)或主機上確認;收緊的變更會立即套用。",
1166
- webPublicRefused: "無法透過臨時公開連結變更網頁設定。請從儀表板本身的網址開啟後再變更。",
1164
+ webPublicRefused: "無法透過公開連結變更網頁設定。請從儀表板本身的網址開啟後再變更。",
1167
1165
  webSessionTitle: "登入 session",
1168
- webSessionHint: "適用於從儀表板本身網址登入的 session(本機、區域網路、tailnet)。臨時公開連結固定為 4 小時 / 30 分鐘。縮短會讓已超過新限制的 session 結束;延長會套用到新的登入,以及既有 session 下次使用時的閒置時間。留空 = 預設值。",
1166
+ webSessionHint: "適用於從儀表板本身網址登入的 session(本機、區域網路、tailnet)。透過公開連結(臨時連結或你的固定網域)的 session 最長 8 小時、閒置 30 分鐘就結束,也不會超過連結本身;管理者的 session 也不會超過這裡的設定(訪客依訪客設定)。縮短會讓已超過新限制的 session 結束;延長會套用到新的登入,以及既有 session 下次使用時的閒置時間。留空 = 預設值。",
1169
1167
  sessionAbsolute: "Session 時長,小時(1–720)",
1170
1168
  sessionIdle: "閒置多久後登出,小時(1–720)",
1171
1169
  sessionRange: "必須是 1 到 720 之間的小時數",
@@ -1194,6 +1192,8 @@ register("settings", {
1194
1192
  grantsChoose: "選擇", grantsChosen: "已選擇", grantsMaySee: "{0} 可以看到:", grantsClassicRooms: "ClassicBot 聊天室", grantsWroteHere: "傳過訊息", grantsWroteTo: "傳過訊息給:{0}",
1195
1193
  grantsLastSeen: "最後出現 {0}", grantsRecent: "最近的變更", grantsRecentNone: "還沒有人的存取權變更過。", grantsAuditDirect: "立即生效", grantsAuditConfirmed: "在 General 確認後生效", grantsAuditEnded: "結束了 {0} 個登入", grantsAuditCodeSent: "已寄出登入碼", grantsAuditCodeNot: "登入碼未寄出({0})", grantsAuditDmFailed: "私訊沒有送達", grantsAuditWait: "一分鐘內重複要求", grantsAuditAdminLimit: "已達管理員的登入碼上限",
1196
1194
  grantsEditAgents: "編輯 agent", grantsRemove: "移除存取權", grantsUndoRemove: "保留存取權",
1195
+ grantsLevel: "{0} 可以做什麼", grantsLevelChat: "聊天", grantsLevelTrusted: "信任",
1196
+ grantsLevelTrustedHint: "信任多了:觀看這些 agent 的畫面(唯讀),以及搜尋它們的聊天。畫面會顯示 agent 終端上的一切:別人傳給它的訊息、指令和它們的輸出,其中可能有機密。聊天和搜尋仍只限這個人看得到的內容。", grantsAuditLevel: "→ {0}",
1197
1197
  grantsWillBeRemoved: "儲存後存取權就會結束。", grantsNew: "新增 —— 儲存後授權", grantsNoAgents: "至少勾選一個 agent,或移除這個人。",
1198
1198
  grantsSend: "傳送登入碼", grantsSendAgain: "{0} 後可再傳", grantsSendSaveFirst: "請先儲存:登入碼只會傳給已儲存的授權。",
1199
1199
  grantsSent: "{0} 已傳送 · {1} 到期", grantsSentPublic: "也可以用在目前開啟的公開連結上。", grantsSending: "傳送中…",
@@ -1214,7 +1214,7 @@ register("settings", {
1214
1214
  vaLoopbackOnly: "只有這台電腦可以授權", vaLoopbackOnlyHint: "開啟:只有這台電腦上的瀏覽器符合,網路或 tailnet 上的不算,之前從其他地方給出的授權視為無。再關掉也不會讓那些授權恢復。",
1215
1215
  vaNamedLink: "也允許透過我的固定網域({0})", vaNamedLinkHint: "開啟:透過你自己的 named tunnel 固定網域登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。它可從網際網路連到,Cloudflare 也看得到流量:開啟需在 General 或這台電腦上確認。關閉立即生效,透過它給出的授權都視為無。臨時公開連結另有下方的選項。",
1216
1216
  vaSessionNamed: "透過你的固定網域",
1217
- vaQuickLink: "也允許透過臨時公開連結", vaQuickLinkHint: "開啟:透過 /web 開出的臨時公開連結登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。這個連結是網際網路上的位址,由 Cloudflare 的 quick tunnel 服務轉送,Cloudflare 看得到流量。開啟需在 General 或這台電腦上確認,並會結束到目前為止給出的所有授權(每個瀏覽器都要重新確認);關閉立即生效。已授權的瀏覽器在連結結束時一併失去授權。",
1217
+ vaQuickLink: "也允許透過臨時公開連結", vaQuickLinkHint: "預設開啟:透過 /web 開出的臨時公開連結登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。這個連結是網際網路上的位址,由 Cloudflare 的 quick tunnel 服務轉送,Cloudflare 看得到流量。重新開啟需在 General 或這台電腦上確認,並會結束到目前為止給出的所有授權(每個瀏覽器都要重新確認);關閉立即生效。已授權的瀏覽器在連結結束時一併失去授權。",
1218
1218
  vaSessionQuick: "透過臨時公開連結",
1219
1219
  vaLanWarning: "dashboard 也接受 {0} 的連線(web.allowed_hosts)。任何人只要從那裡連上、又拿到被盜的登入,就能以你的名義給出授權。除非你信任所有能連到那裡的人,否則請開啟「只有這台電腦可以授權」。",
1220
1220
  vaHours: "一次授權的有效期(小時,{0}–{1})", vaHoursRange: "必須是 1 到 48 之間的數字",
@@ -25,8 +25,9 @@ export function verifiedAuthorityBody(original, f) {
25
25
  if (f.hours !== original.hours) out.max_session_hours = f.hours === null ? null : f.hours;
26
26
  // #2453 (§0.2): off by default; turning it on is confirmed in a General or on the host.
27
27
  if (f.namedLink !== original.namedLink) out.named_link = f.namedLink ? true : null;
28
- // §0.3: off by default (the user's decision); turning it on is confirmed in a General or on the host.
29
- if (f.quickLink !== original.quickLink) out.quick_link = f.quickLink ? true : null;
28
+ // §0.3: on by default (the user's decision, 2026-10-28), so off is written as false; turning it back on is confirmed in a
29
+ // General or on the host.
30
+ if (f.quickLink !== original.quickLink) out.quick_link = f.quickLink ? null : false;
30
31
  return Object.keys(out).length ? out : null;
31
32
  }
32
33
 
@@ -45,7 +46,7 @@ export function WebAuthorityCard({ ctx, staged, disabled = false }) {
45
46
  if (!o || typeof o !== "object" || !o.state || !o.hours || !Array.isArray(o.lanHosts) || !Array.isArray(o.authorized)) { setFailed(true); return; }
46
47
  const c = o.configured || {};
47
48
  const orig = { enabled: c.enabled !== false, loopbackOnly: c.loopback_only === true, hours: typeof c.max_session_hours === "number" ? c.max_session_hours : null,
48
- namedLink: c.named_link === true, quickLink: c.quick_link === true };
49
+ namedLink: c.named_link === true, quickLink: c.quick_link == null || c.quick_link === true }; // #2819: on unless set otherwise
49
50
  setOverview(o); setFailed(false);
50
51
  setOriginal((prev) => prev || orig);
51
52
  // #2347: a draft kept from before this card was last shown (still unsaved) comes back over what is saved now — only
@@ -89,7 +89,13 @@ register("app", {
89
89
  pendingWeb: "Confirmed by your account (this browser is web-verified). General is told.",
90
90
  pending_applied: "Confirmed and applied", pending_rejected: "Not applied", pending_expired: "Expired — nothing was changed",
91
91
  pending_stale: "Not applied — settings changed meanwhile", pending_failed: "Confirmed, but applying it failed",
92
- pendingChat: "A fleet admin confirms this in chat (General topic).", pendingHost: "Confirm it on the host: {0}", pendingLeft: "{0} left", withdraw: "Withdraw",
92
+ pendingLeft: "{0} left", withdraw: "Withdraw",
93
+ // #2868: where to confirm it, said plainly; the host's command folded away unless it is the only way.
94
+ pendingPosting: "Sending the confirm card to General…", pendingChatWhere: "To apply it, press Confirm on the card in General on {0}.",
95
+ pendingHostOnly: "No General can take the confirm card. Confirm it on the host: {0}", pendingAdvanced: "Advanced: confirm on the host",
96
+ pendingSelf: "This browser is verified, so you can also apply it here.", pendingApplyNow: "Apply now",
97
+ pendingApplyRefused: "This browser can't apply it here now — confirm it in General.",
98
+ pendingAuthorize: "Authorize this browser to apply changes like this here next time, without General.",
93
99
  opWriting: "Applying settings… {0}/{1}", opWaiting: "Settings: waiting for confirmation in chat", opApplying: "Applying settings…",
94
100
  opDone: "Settings applied", opRestart: "Settings saved — AgEnD needs a restart to use them", opPartial: "Some settings were not applied",
95
101
  opFailed: "Settings were not applied", openSettings: "Open Settings",
@@ -105,7 +111,7 @@ register("app", {
105
111
  confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
106
112
  sidePanelLeave: "Leave {0} without saving? Your changes there will be lost.", sidePanelDiscard: "Discard changes",
107
113
  // The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
108
- needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_question: "Asking you a question", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_backend_signin: "Backend sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
114
+ needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_question: "Asking you a question", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_backend_signin: "Backend sign-in needed", needs_reason_config_invalid: "Configuration file needs attention", needs_reason_config_fallback: "Running on stored configuration", config_history_edit: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. The next restart would use the stored valid copy from {4}. Correct the YAML error; the file has not been changed by AgEnD.", config_history_no_history: "{0}, line {1}, column {2}: {3}. AgEnD is still running on the previous settings. No stored valid copy is available, so the next restart cannot recover automatically. Correct the YAML error before restarting; the file has not been changed by AgEnD.", config_history_fallback: "{0}, line {1}, column {2}: {3}. AgEnD started using the stored valid copy from {4}. Correct the YAML error and reload the settings. The file on disk has not been changed by AgEnD.", needs_reason_crashed: "Crashed", needs_reason_usage_limit: "Usage limit reached · reset time unknown", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed", needs_reason_task_review: "Waiting for your confirmation", needs_reason_task_blocked: "Blocked: asks you",
109
115
  },
110
116
  "zh-TW": {
111
117
  brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
@@ -131,7 +137,12 @@ register("app", {
131
137
  pendingWeb: "由你的帳號確認(這個瀏覽器已通過網頁驗證),也會通知 General。",
132
138
  pending_applied: "已確認並套用", pending_rejected: "未套用", pending_expired: "已逾時——沒有任何變更",
133
139
  pending_stale: "未套用——設定在這期間已變動", pending_failed: "已確認,但套用失敗",
134
- pendingChat: "由 fleet 管理員在聊天(General topic)中確認。", pendingHost: "請在主機上確認:{0}", pendingLeft: "剩 {0}", withdraw: "撤回",
140
+ pendingLeft: "剩 {0}", withdraw: "撤回",
141
+ pendingPosting: "正在把確認卡送到 General…", pendingChatWhere: "要套用,請到 {0} 的 General,在確認卡上按「確認」。",
142
+ pendingHostOnly: "沒有可以接收確認卡的 General。請在主機上確認:{0}", pendingAdvanced: "進階:在主機上確認",
143
+ pendingSelf: "這個瀏覽器已通過驗證,也可以直接在這裡套用。", pendingApplyNow: "直接套用",
144
+ pendingApplyRefused: "這個瀏覽器現在無法直接套用,請到 General 確認。",
145
+ pendingAuthorize: "授權這個瀏覽器,之後這類變更可以直接套用,不必到 General。",
135
146
  opWriting: "正在套用設定… {0}/{1}", opWaiting: "設定:等待在聊天中確認", opApplying: "正在套用設定…",
136
147
  opDone: "設定已套用", opRestart: "設定已儲存——需要重新啟動 AgEnD 才會生效", opPartial: "部分設定沒有套用",
137
148
  opFailed: "設定沒有套用", openSettings: "開啟設定",
@@ -145,6 +156,6 @@ register("app", {
145
156
  search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
146
157
  confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
147
158
  sidePanelLeave: "不儲存就離開「{0}」?你在那裡的修改會遺失。", sidePanelDiscard: "捨棄修改",
148
- needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_question: "正在問你問題", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_backend_signin: "後端需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
159
+ needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_question: "正在問你問題", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_backend_signin: "後端需要登入", needs_reason_config_invalid: "設定檔需要處理", needs_reason_config_fallback: "正在使用儲存的設定副本", config_history_edit: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。下次重新啟動會改用 {4} 儲存的有效副本。請修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_no_history: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 仍使用先前的設定執行。沒有可用的有效副本,下次重新啟動將無法自動恢復。請在重新啟動前修正 YAML 錯誤;AgEnD 未更動此檔案。", config_history_fallback: "{0} 第 {1} 行、第 {2} 欄:{3}。AgEnD 已使用 {4} 儲存的有效副本啟動。請修正 YAML 錯誤並重新載入設定。AgEnD 未更動磁碟上的檔案。", needs_reason_crashed: "已崩潰", needs_reason_usage_limit: "用量已達上限 · 恢復時間未知", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗", needs_reason_task_review: "等你確認", needs_reason_task_blocked: "卡住,在問你",
149
160
  },
150
161
  });
@@ -59,6 +59,10 @@ export async function setNotify(on, env = globalThis) {
59
59
  return state;
60
60
  }
61
61
 
62
+ export const configDetail = (item) => {
63
+ const issue = item.configIssue;
64
+ return issue ? t(`app.config_history_${issue.mode === "fallback" ? "fallback" : issue.time ? "edit" : "no_history"}`, issue.file, issue.line, issue.column, issue.reason, issue.time || "") : item.detail;
65
+ };
62
66
  export const reasonText = (item) => t(`app.needs_reason_${item.reason}`);
63
67
 
64
68
  let stop = null;
@@ -77,7 +81,7 @@ export function startNeedsNotifier({ open, env = globalThis } = {}) {
77
81
  seen.add(item.id);
78
82
  if (!notifyOn(env)) return;
79
83
  try {
80
- const n = new env.Notification(item.instance || reasonText(item), { body: item.detail ? `${reasonText(item)}: ${item.detail}` : reasonText(item), tag: item.id });
84
+ const n = new env.Notification(item.instance || reasonText(item), { body: item.detail ? `${reasonText(item)}: ${configDetail(item)}` : reasonText(item), tag: item.id });
81
85
  n.onclick = () => { try { env.focus && env.focus(); } catch { /* ignore */ } if (open && item.instance) open(item.instance); n.close(); };
82
86
  } catch { /* a browser that refuses at the last moment: the list still shows it */ }
83
87
  };
@@ -91,15 +91,6 @@ let holding = 0;
91
91
  const held = new Map(); // key → value chosen in Settings, shown here, not saved yet
92
92
  const heldFrom = new Map(); // key → its cached form before it was held (a choice back to it is no change)
93
93
  const heldListeners = new Set();
94
- // #2193: whether the signed-in person has a personal effect slot chosen (their fx.* keys: in the page's data-prefs and
95
- // in every host read, never in this host cache). The effects runtime is loaded only when there is something to play.
96
- const ownerEffectsIn = (values) => !!values && OWNER_EFFECT_PREF_KEYS.some((k) => own(values, k) && values[k] != null && values[k] !== "");
97
- let ownerFx = initial ? ownerEffectsIn(initial.values) : false;
98
- const ownerFxListeners = new Set();
99
- /** Whether the person has any personal effect (fx.page/header/sidebar/box/cursor) chosen, as this page last read. */
100
- export function ownerEffectsChosen() { return ownerFx; }
101
- /** Called when that changes. Returns the unsubscribe. */
102
- export function onOwnerEffectsChanged(fn) { ownerFxListeners.add(fn); return () => ownerFxListeners.delete(fn); }
103
94
 
104
95
  // The host's values into the cache, now — before the sidebar, the tour or the first-run card read their keys. A key
105
96
  // the host does not have: the default, on a device in step with the host; this device's own (to upload) otherwise.
@@ -111,9 +102,20 @@ if (host) {
111
102
  }
112
103
  }
113
104
 
114
- /** This page may change the host's preferences: the signed-in app, not over the public link, not a guest's (#1920). */
115
- export function prefsWritable() {
116
- return !!initial && !guestPage() && !(typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1");
105
+ /**
106
+ * #2855: the preferences a guest keeps as its own, on the host under its account (the same list as web-prefs.ts
107
+ * GUEST_OWN_PREF_KEYS); the rest of a guest's page follows the host's look and stays on this browser.
108
+ */
109
+ export const GUEST_OWN_PREF_KEYS = Object.freeze(["theme", "lang", "nav.favorites", "nav.sort", "nav.filter"]);
110
+ const GUEST_OWN = new Set(GUEST_OWN_PREF_KEYS);
111
+ /**
112
+ * This page may change a preference on the host: the signed-in app, not over the public link (#1920). A guest's page
113
+ * (#2855): only its own keys — over the public link too, since only its own bucket is written; no key named: none.
114
+ */
115
+ export function prefsWritable(key) {
116
+ if (!initial) return false;
117
+ if (guestPage()) return key !== undefined && GUEST_OWN.has(key);
118
+ return !(typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1");
117
119
  }
118
120
  /**
119
121
  * The value in force for a key, in memory — never only in this browser's storage (a full storage must not bring back
@@ -140,8 +142,6 @@ function take(body) {
140
142
  if (!isView(body) || (rev !== null && body.rev < rev)) return false;
141
143
  rev = body.rev;
142
144
  host = hostValues(body.values);
143
- const fx = ownerEffectsIn(body.values);
144
- if (fx !== ownerFx) { ownerFx = fx; for (const fn of [...ownerFxListeners]) { try { fn(fx); } catch { /* the rest still hear */ } } }
145
145
  return true;
146
146
  }
147
147
 
@@ -153,7 +153,7 @@ export function savePref(key, value) {
153
153
  if (!hostKey(key)) return;
154
154
  if (holding && HELD_KEYS.has(key)) { hold(key, value); return; }
155
155
  cache(key, value);
156
- if (!prefsWritable()) return;
156
+ if (!prefsWritable(key)) return;
157
157
  pending.set(key, value);
158
158
  mine.set(key, value);
159
159
  clearTimeout(flushTimer);
@@ -328,9 +328,9 @@ function apply(changed) {
328
328
  * refused session or an unreadable store leaves the device unmarked, so the next load tries again.
329
329
  */
330
330
  export async function migratePrefs() {
331
- if (!prefsWritable() || inStep()) return false;
331
+ if (!initial || inStep() || !HOST_KEYS.some((key) => prefsWritable(key))) return false;
332
332
  for (const key of HOST_KEYS) {
333
- if (own(host, key)) continue;
333
+ if (own(host, key) || !prefsWritable(key)) continue;
334
334
  const local = SYNCED[key].fromLocal(readLocal(SYNCED[key].ls));
335
335
  if (local === undefined) continue;
336
336
  let r;
@@ -7,7 +7,7 @@ import { Toasts } from "./ui-toast.js";
7
7
  import { ConfirmHost, confirmDialog } from "./ui-confirm.js";
8
8
  import { ColorDialogHost } from "./identity-color.js";
9
9
  import { t, lang, setLang, onLang } from "./app-i18n.js";
10
- import { appStore, createStore, guestBadge, guestPage, useStore } from "./app-store.js";
10
+ import { appStore, createStore, guestBadge, guestPage, guestTrusted, useStore } from "./app-store.js";
11
11
  import { navStore } from "./app-nav.js";
12
12
  import { toast } from "./ui-toast.js";
13
13
  import { chatPath, viewPath, settingsPath, routeKey, NEEDS_PATH, fleetEntryPath } from "./app-route.js";
@@ -17,6 +17,7 @@ import { applyPageTheme, pageNow, resolvedMode, themesStore } from "./app-themes
17
17
  import { ErrorState, Skeleton } from "./ui-states.js";
18
18
  import { InstanceNav, RosterNav, namesStore, setNamesPrimary } from "./instance-nav.js";
19
19
  import { usageRailStore } from "./header-tools.js";
20
+ import { useWebAuthorization } from "./web-authorize.js";
20
21
  import { RightRail, sidePanelStore } from "./side-panel.js";
21
22
  import { OwnerCssKeepBar } from "./owner-css.js";
22
23
  import { AgentWidget, fleetBinds, sidebarWidget, sidebarWidgetStore } from "./agent-widget.js";
@@ -78,7 +79,8 @@ export const searchShortcut = () => (isMacLike() ? "⌘K" : "Ctrl K");
78
79
  export function searchOffered(admin) {
79
80
  const body = typeof document !== "undefined" ? document.body : null;
80
81
  const offLink = !!body && body.dataset.publicLink === "1" && body.dataset.searchLink === "0";
81
- return !!admin && !guestPage() && !offLink;
82
+ // #2855: a trusted guest searches too (only what it can see: the server's rule).
83
+ return (guestPage() ? guestTrusted() : !!admin) && !offLink;
82
84
  }
83
85
  let searchModule = null;
84
86
  /** Open search; `preset.instance`: narrowed to that agent (Ctrl+F in its chat). */
@@ -107,6 +109,10 @@ export function handleSearchKey(e) {
107
109
  openSearch(key === "f" ? { instance: route.instance } : {});
108
110
  }
109
111
 
112
+ /** The sidebar's Search row (Ctrl+K / ⌘K). */
113
+ const searchRow = () => html`<button type="button" class="side-row side-search" onClick=${() => openSearch()} title=${t("app.searchTitle", searchShortcut())}
114
+ aria-keyshortcuts=${isMacLike() ? "Meta+K" : "Control+K"}><${Icon} name="search" /><span class="grow">${t("app.search")}</span><kbd class="kbd-hint" aria-hidden="true">${searchShortcut()}</kbd></button>`;
115
+
110
116
  function readCollapsed() { try { return localStorage.getItem("agend_sidebar") === "hidden"; } catch { return false; } }
111
117
  const narrow = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
112
118
 
@@ -350,6 +356,7 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
350
356
  <a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
351
357
  <button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
352
358
  </div>
359
+ ${searchOffered(false) ? html`<nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>${searchRow()}</nav>` : null}
353
360
  <${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false} exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />
354
361
  <div class="side-foot" data-trust="navigation">
355
362
  <${GuestChip} />
@@ -372,8 +379,7 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
372
379
  <nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>
373
380
  ${overview}
374
381
  ${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
375
- ${searchOffered(canCreate) ? html`<button type="button" class="side-row side-search" onClick=${() => openSearch()} title=${t("app.searchTitle", searchShortcut())}
376
- aria-keyshortcuts=${isMacLike() ? "Meta+K" : "Control+K"}><${Icon} name="search" /><span class="grow">${t("app.search")}</span><kbd class="kbd-hint" aria-hidden="true">${searchShortcut()}</kbd></button>` : null}
382
+ ${searchOffered(canCreate) ? searchRow() : null}
377
383
  ${canCreate && onNewInstance ? html`<button type="button" class="side-row side-new" onClick=${onNewInstance}><${Icon} name="plus" /><span class="grow">${t("app.newAgent")}</span></button>` : null}
378
384
  </nav>
379
385
  ${shell.side ? html`<${shell.side.Component} />` : html`<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false}
@@ -393,8 +399,7 @@ function GuestChip() {
393
399
  const { name, platform } = guestBadge();
394
400
  const where = PLATFORM_NAMES[platform] || platform;
395
401
  const label = name ? (where ? t("app.guestAsOn", name, where) : t("app.guestAs", name)) : t("app.guestChip");
396
- // Inside .side-foot (a marked, stock-trusted element): no trust marker of its own — effect-stock-trust's closed inventory
397
- // refuses any element it does not know, which would hide a guest's static effect posters (#2101 review).
402
+ // Inside .side-foot (a marked element): no trust marker of its own (#2101 review).
398
403
  return html`<p class="guest-chip" title=${t("app.guestHint")}><${Icon} name="user" size=${14} /><span class="grow">${label}</span></p>`;
399
404
  }
400
405
 
@@ -571,13 +576,46 @@ export function PendingChanges({ inline = false } = {}) {
571
576
  ${p.dismiss ? html`<button type="button" class="icon-btn" aria-label=${t("app.close")} title=${t("app.close")} onClick=${p.dismiss}><${Icon} name="close" size=${14} /></button>` : null}</div>
572
577
  ${p.label ? html`<div class="pending-label">${p.label}</div>` : null}
573
578
  ${Array.isArray(p.summary) && p.summary.length ? html`<ul class="pending-summary">${p.summary.map((line, i) => html`<li key=${i}>${line}</li>`)}</ul>` : null}
574
- ${p.state === "pending" ? html`<p class="note">${p.confirmation && p.confirmation.kind === "host_cli" ? t("app.pendingHost", `agend settings confirm ${p.id}`) : t("app.pendingChat")}</p>` : null}
579
+ ${p.state === "pending" ? html`<${PendingHow} p=${p} />` : null}
575
580
  ${(p.state === "applying" || p.state === "applied") && p.confirmation && p.confirmation.kind === "web" ? html`<p class="note">${t("app.pendingWeb")}</p>` : null}
576
581
  ${p.state !== "pending" && p.state !== "applying" && p.state !== "applied" && p.outcome && p.outcome.message ? html`<p class="note">${p.outcome.message}</p>` : null}
577
582
  ${p.withdraw ? html`<div class="pending-actions"><button type="button" class="btn btn-sm" onClick=${p.withdraw}>${t("app.withdraw")}</button></div>` : null}
578
583
  </section>`)}</div>`;
579
584
  }
580
585
 
586
+ /** #2868: where the confirm card was posted: "Discord", or "Discord (team-b)" for a connection with an id of its own. */
587
+ function whereText(where) {
588
+ const names = (Array.isArray(where) ? where : []).map((w) => `${PLATFORM_NAMES[w.platform] || w.platform}${w.connection && w.connection !== w.platform ? ` (${w.connection})` : ""}`);
589
+ return names.length ? [...new Set(names)].join(" / ") : "Discord / Telegram";
590
+ }
591
+ /**
592
+ * #2868: how a pending change is confirmed, in the order a person can act on it. First where: the General card (naming
593
+ * the platform it was posted on), or the host's command when no General could take it. Then, when this browser could
594
+ * confirm it itself (the server's read says so: #2170's rule), "Apply now"; when it isn't verified but could be,
595
+ * "Authorize this browser" (the same DM card as the composer's). The host's command otherwise sits folded under
596
+ * "Advanced".
597
+ */
598
+ function PendingHow({ p }) {
599
+ const a = useWebAuthorization();
600
+ const [refused, setRefused] = useState(false);
601
+ const c = p.confirmation || {}, cmd = `agend settings confirm ${p.id}`;
602
+ const lead = c.kind === "posting" ? t("app.pendingPosting") : c.kind === "host_cli" ? t("app.pendingHostOnly", cmd) : t("app.pendingChatWhere", whereText(c.where));
603
+ // A browser that isn't verified but could be: authorizing it makes this one (and later ones) "Apply now".
604
+ const route = c.kind !== "host_cli" && !p.applyNow && a.st;
605
+ const canAsk = route && a.st.state === "none" && (a.st.reason === "not_authorized" || a.st.reason === "authorization_expired");
606
+ const asking = route && a.st.state === "pending";
607
+ const apply = async () => { setRefused(false); const r = await p.applyNow(); if (!r || !r.ok) setRefused(true); };
608
+ return html`<p class="note">${lead}</p>
609
+ ${p.applyNow ? html`<div class="pending-self"><span class="note">${t("app.pendingSelf")}</span>
610
+ <button type="button" class="btn btn-sm btn-primary" onClick=${apply}>${t("app.pendingApplyNow")}</button></div>` : null}
611
+ ${refused && !p.applyNow ? html`<p class="note" role="status">${t("app.pendingApplyRefused")}</p>` : null}
612
+ ${canAsk ? html`<div class="pending-self"><span class="note">${t("app.pendingAuthorize")}</span>
613
+ <button type="button" class="btn btn-sm" onClick=${a.ask}>${t("webauth.authorize")}</button></div>` : null}
614
+ ${asking ? html`<p class="note">${t("webauth.waiting", mmss(a.left))}</p>` : null}
615
+ ${a.notice && (canAsk || asking) ? html`<p class="note" role="status">${a.notice}</p>` : null}
616
+ ${c.kind !== "host_cli" ? html`<details class="pending-host"><summary>${t("app.pendingAdvanced")}</summary><code>${cmd}</code></details>` : null}`;
617
+ }
618
+
581
619
  /** Settings' Apply, followed from another panel: one line, and the way back to it (§5: progress shows in any panel). */
582
620
  function OperationLine({ route }) {
583
621
  const { settingsOp: op } = useStore(appStore);
@@ -781,7 +819,7 @@ export function Shell({ panels, onNewInstance, viewOnly = false }) {
781
819
  document.removeEventListener("compositionstart", start, true); document.removeEventListener("compositionend", end, true);
782
820
  };
783
821
  }, []);
784
- const guest = guestPage(); // #1920: a guest's page — no operations, usage, pending changes or owner CSS
822
+ const guest = guestPage(); // #1920: a guest's page — no operations, pending changes or owner CSS (#2855: usage, yes)
785
823
  const cls = ["shell", shell.collapsed ? "sb-collapsed" : "", shell.drawer ? "sb-open" : "", shell.keyboard ? "kb-open" : "", guest ? "guest" : ""].filter(Boolean).join(" ");
786
824
  return html`<div ref=${root} class=${cls}>
787
825
  <a data-trust="navigation" class="skip" href="#main">${t("app.skip")}</a>
@@ -795,7 +833,7 @@ export function Shell({ panels, onNewInstance, viewOnly = false }) {
795
833
  ${viewOnly || guest || !shell.banner ? null : html`<${shell.banner} />`}
796
834
  <${Outlet} route=${nav.route} seq=${nav.seq} panels=${panels} />
797
835
  </main>
798
- ${guest ? null : html`<${RightRail} route=${nav.route} />`}
836
+ <${RightRail} route=${nav.route} />
799
837
  <${BottomTabs} route=${nav.route} viewOnly=${viewOnly} />
800
838
  ${shell.dialog ? html`<${shell.dialog.Component} ...${shell.dialog.props} onClose=${closeDialog} />` : null}
801
839
  ${viewOnly || guest || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
@@ -24,7 +24,7 @@ export function createStore(initial) {
24
24
  * (app-stream.js catchUp) — "catching" / "retrying" / "failed" / "ok"; `retryHydration` asks for it again.
25
25
  * `connections`: how many chat connections the fleet has (#1519 P7: 0 is web-only — the first-run card); null until known. */
26
26
  export const appStore = createStore({ ready: false, instances: [], uptime: 0, exec: {}, awaiting: {}, connection: "connecting", needs: [], connections: null,
27
- hydration: "none", retryHydration: null, canvasWorker: typeof document !== "undefined" && document.body?.dataset.canvasWorker === "1" });
27
+ hydration: "none", retryHydration: null });
28
28
 
29
29
  /**
30
30
  * #1920 phase 3: this page is a guest's — the server says so on <body> (data-tier="guest"). A guest sees only its own
@@ -34,6 +34,10 @@ export const appStore = createStore({ ready: false, instances: [], uptime: 0, ex
34
34
  export function guestPage() {
35
35
  return typeof document !== "undefined" && !!document.body && document.body.dataset.tier === "guest";
36
36
  }
37
+ /** #2855: this guest's access is Trusted — its page offers View (read-only) and search (the server's, on <body>). */
38
+ export function guestTrusted() {
39
+ return guestPage() && document.body.dataset.guestLevel === "trusted";
40
+ }
37
41
  /** Who a guest's page is signed in as: its web name and its platform (the server's, on <body>). */
38
42
  export function guestBadge() {
39
43
  const d = typeof document !== "undefined" && document.body ? document.body.dataset : {};
@@ -49,7 +53,7 @@ export function applyStatus(d) {
49
53
  exec[i.name] = (i.execution_state !== undefined ? i.execution_state : i.state) ?? null;
50
54
  if (i.state === "awaiting_input") awaiting[i.name] = typeof i.interaction_summary === "string" ? i.interaction_summary : "";
51
55
  }
52
- appStore.set({ canvasWorker: d.canvas_worker === true, ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
56
+ appStore.set({ ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
53
57
  startup: d.startup?.phase === "starting" ? d.startup : null,
54
58
  connections: typeof d.connections === "number" ? d.connections : null,
55
59
  // #1665: the host preferences' revision (app-prefs.js re-reads them when it moves).