@songsid/agend 2.2.0-beta.2 → 2.2.0-beta.20

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 (389) hide show
  1. package/README.md +40 -24
  2. package/README.zh-TW.md +40 -24
  3. package/dist/agent-cli-instructions.md +6 -2
  4. package/dist/agent-cli.js +15 -7
  5. package/dist/agent-cli.js.map +1 -1
  6. package/dist/agent-endpoint.js +3 -0
  7. package/dist/agent-endpoint.js.map +1 -1
  8. package/dist/agent-whats-new.js +16 -4
  9. package/dist/agent-whats-new.js.map +1 -1
  10. package/dist/auth-api.d.ts +3 -1
  11. package/dist/auth-api.js +17 -1
  12. package/dist/auth-api.js.map +1 -1
  13. package/dist/backend/antigravity.d.ts +33 -0
  14. package/dist/backend/antigravity.js +126 -18
  15. package/dist/backend/antigravity.js.map +1 -1
  16. package/dist/backend/claude-carry.d.ts +22 -0
  17. package/dist/backend/claude-carry.js +170 -0
  18. package/dist/backend/claude-carry.js.map +1 -0
  19. package/dist/backend/claude-code.d.ts +65 -2
  20. package/dist/backend/claude-code.js +226 -33
  21. package/dist/backend/claude-code.js.map +1 -1
  22. package/dist/backend/codex-metadata.d.ts +33 -0
  23. package/dist/backend/codex-metadata.js +122 -18
  24. package/dist/backend/codex-metadata.js.map +1 -1
  25. package/dist/backend/codex.d.ts +3 -0
  26. package/dist/backend/codex.js +17 -1
  27. package/dist/backend/codex.js.map +1 -1
  28. package/dist/backend/credential-profile.d.ts +40 -3
  29. package/dist/backend/credential-profile.js +113 -5
  30. package/dist/backend/credential-profile.js.map +1 -1
  31. package/dist/backend/effort-metadata.d.ts +37 -1
  32. package/dist/backend/effort-metadata.js +86 -15
  33. package/dist/backend/effort-metadata.js.map +1 -1
  34. package/dist/backend/grok.d.ts +4 -0
  35. package/dist/backend/grok.js +14 -0
  36. package/dist/backend/grok.js.map +1 -1
  37. package/dist/backend/kiro.d.ts +27 -1
  38. package/dist/backend/kiro.js +63 -10
  39. package/dist/backend/kiro.js.map +1 -1
  40. package/dist/backend/launch-effort.d.ts +61 -0
  41. package/dist/backend/launch-effort.js +170 -0
  42. package/dist/backend/launch-effort.js.map +1 -0
  43. package/dist/backend/muse.d.ts +84 -0
  44. package/dist/backend/muse.js +449 -53
  45. package/dist/backend/muse.js.map +1 -1
  46. package/dist/backend/types.d.ts +48 -2
  47. package/dist/backend/types.js +12 -1
  48. package/dist/backend/types.js.map +1 -1
  49. package/dist/backend-command.d.ts +91 -0
  50. package/dist/backend-command.js +122 -0
  51. package/dist/backend-command.js.map +1 -0
  52. package/dist/background-work-ended.d.ts +18 -0
  53. package/dist/background-work-ended.js +30 -0
  54. package/dist/background-work-ended.js.map +1 -0
  55. package/dist/cache-service.d.ts +2 -0
  56. package/dist/cache-service.js +2 -1
  57. package/dist/cache-service.js.map +1 -1
  58. package/dist/channel/adapters/discord.d.ts +26 -1
  59. package/dist/channel/adapters/discord.js +103 -3
  60. package/dist/channel/adapters/discord.js.map +1 -1
  61. package/dist/channel/adapters/telegram.d.ts +35 -3
  62. package/dist/channel/adapters/telegram.js +122 -23
  63. package/dist/channel/adapters/telegram.js.map +1 -1
  64. package/dist/channel/mcp-tools.js +5 -3
  65. package/dist/channel/mcp-tools.js.map +1 -1
  66. package/dist/channel/message-edit-errors.d.ts +5 -0
  67. package/dist/channel/message-edit-errors.js +24 -0
  68. package/dist/channel/message-edit-errors.js.map +1 -0
  69. package/dist/channel/telegram-markdown.d.ts +6 -0
  70. package/dist/channel/telegram-markdown.js +104 -0
  71. package/dist/channel/telegram-markdown.js.map +1 -0
  72. package/dist/channel/tool-router.d.ts +2 -0
  73. package/dist/channel/tool-router.js +6 -5
  74. package/dist/channel/tool-router.js.map +1 -1
  75. package/dist/channel/types.d.ts +46 -4
  76. package/dist/cli.js +184 -34
  77. package/dist/cli.js.map +1 -1
  78. package/dist/command-table.d.ts +2 -2
  79. package/dist/command-table.js +5 -2
  80. package/dist/command-table.js.map +1 -1
  81. package/dist/compact-watch.d.ts +86 -0
  82. package/dist/compact-watch.js +288 -0
  83. package/dist/compact-watch.js.map +1 -0
  84. package/dist/config-validator.js +55 -5
  85. package/dist/config-validator.js.map +1 -1
  86. package/dist/config.d.ts +1 -0
  87. package/dist/config.js +2 -1
  88. package/dist/config.js.map +1 -1
  89. package/dist/cross-instance-envelope.js +2 -0
  90. package/dist/cross-instance-envelope.js.map +1 -1
  91. package/dist/daemon.d.ts +129 -1
  92. package/dist/daemon.js +754 -94
  93. package/dist/daemon.js.map +1 -1
  94. package/dist/delivery-outbox.d.ts +64 -8
  95. package/dist/delivery-outbox.js +315 -24
  96. package/dist/delivery-outbox.js.map +1 -1
  97. package/dist/delivery-reconciliation.d.ts +18 -1
  98. package/dist/delivery-reconciliation.js +67 -2
  99. package/dist/delivery-reconciliation.js.map +1 -1
  100. package/dist/doctor.js +7 -0
  101. package/dist/doctor.js.map +1 -1
  102. package/dist/fleet-context.d.ts +12 -1
  103. package/dist/fleet-manager.d.ts +392 -19
  104. package/dist/fleet-manager.js +2030 -275
  105. package/dist/fleet-manager.js.map +1 -1
  106. package/dist/forged-envelope-scan.d.ts +4 -3
  107. package/dist/forged-envelope-scan.js +4 -3
  108. package/dist/forged-envelope-scan.js.map +1 -1
  109. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +84 -16
  110. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +16 -1
  111. package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
  112. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -0
  113. package/dist/host-memory.d.ts +10 -0
  114. package/dist/host-memory.js +33 -1
  115. package/dist/host-memory.js.map +1 -1
  116. package/dist/human-delivery-receipts.d.ts +83 -0
  117. package/dist/human-delivery-receipts.js +194 -0
  118. package/dist/human-delivery-receipts.js.map +1 -0
  119. package/dist/install-lock.d.ts +18 -1
  120. package/dist/install-lock.js +30 -3
  121. package/dist/install-lock.js.map +1 -1
  122. package/dist/instance-avatar.d.ts +5 -4
  123. package/dist/instance-avatar.js +12 -8
  124. package/dist/instance-avatar.js.map +1 -1
  125. package/dist/instance-config-impact.js +1 -0
  126. package/dist/instance-config-impact.js.map +1 -1
  127. package/dist/instance-lifecycle.d.ts +25 -6
  128. package/dist/instance-lifecycle.js +76 -27
  129. package/dist/instance-lifecycle.js.map +1 -1
  130. package/dist/instructions.d.ts +1 -1
  131. package/dist/instructions.js +3 -3
  132. package/dist/instructions.js.map +1 -1
  133. package/dist/kiro-compact-pane.d.ts +38 -0
  134. package/dist/kiro-compact-pane.js +57 -0
  135. package/dist/kiro-compact-pane.js.map +1 -0
  136. package/dist/kiro-log-gate.d.ts +42 -0
  137. package/dist/kiro-log-gate.js +39 -0
  138. package/dist/kiro-log-gate.js.map +1 -0
  139. package/dist/launchd-handoff.d.ts +43 -0
  140. package/dist/launchd-handoff.js +56 -0
  141. package/dist/launchd-handoff.js.map +1 -0
  142. package/dist/locale.js +268 -42
  143. package/dist/locale.js.map +1 -1
  144. package/dist/log-service.d.ts +99 -0
  145. package/dist/log-service.js +243 -0
  146. package/dist/log-service.js.map +1 -0
  147. package/dist/log-steps.d.ts +169 -0
  148. package/dist/log-steps.js +858 -0
  149. package/dist/log-steps.js.map +1 -0
  150. package/dist/login-controller.d.ts +20 -3
  151. package/dist/login-controller.js +71 -19
  152. package/dist/login-controller.js.map +1 -1
  153. package/dist/login-flows.d.ts +5 -2
  154. package/dist/login-flows.js +5 -4
  155. package/dist/login-flows.js.map +1 -1
  156. package/dist/login-shell.d.ts +21 -0
  157. package/dist/login-shell.js +98 -0
  158. package/dist/login-shell.js.map +1 -0
  159. package/dist/memory-pressure.d.ts +13 -1
  160. package/dist/memory-pressure.js +50 -10
  161. package/dist/memory-pressure.js.map +1 -1
  162. package/dist/needs-you-hub.js +2 -0
  163. package/dist/needs-you-hub.js.map +1 -1
  164. package/dist/needs-you-live.d.ts +6 -0
  165. package/dist/needs-you-live.js +23 -3
  166. package/dist/needs-you-live.js.map +1 -1
  167. package/dist/outbound-handlers.d.ts +100 -0
  168. package/dist/outbound-handlers.js +277 -93
  169. package/dist/outbound-handlers.js.map +1 -1
  170. package/dist/outbound-schemas.d.ts +30 -15
  171. package/dist/outbound-schemas.js +23 -5
  172. package/dist/outbound-schemas.js.map +1 -1
  173. package/dist/provider-probe.d.ts +29 -0
  174. package/dist/provider-probe.js +198 -2
  175. package/dist/provider-probe.js.map +1 -1
  176. package/dist/public-link-progress.d.ts +1 -1
  177. package/dist/public-link-progress.js +8 -2
  178. package/dist/public-link-progress.js.map +1 -1
  179. package/dist/public-preview.d.ts +101 -0
  180. package/dist/public-preview.js +236 -0
  181. package/dist/public-preview.js.map +1 -0
  182. package/dist/public-web-gateway.d.ts +2 -0
  183. package/dist/public-web-gateway.js +20 -6
  184. package/dist/public-web-gateway.js.map +1 -1
  185. package/dist/public-web-link.d.ts +24 -1
  186. package/dist/public-web-link.js +63 -9
  187. package/dist/public-web-link.js.map +1 -1
  188. package/dist/quickstart-api.d.ts +1 -1
  189. package/dist/quickstart-api.js +8 -6
  190. package/dist/quickstart-api.js.map +1 -1
  191. package/dist/quickstart.d.ts +12 -0
  192. package/dist/quickstart.js +36 -6
  193. package/dist/quickstart.js.map +1 -1
  194. package/dist/reply-buttons-controller.d.ts +89 -5
  195. package/dist/reply-buttons-controller.js +273 -8
  196. package/dist/reply-buttons-controller.js.map +1 -1
  197. package/dist/reply-buttons.d.ts +48 -3
  198. package/dist/reply-buttons.js +105 -10
  199. package/dist/reply-buttons.js.map +1 -1
  200. package/dist/reply-polls.d.ts +85 -0
  201. package/dist/reply-polls.js +154 -0
  202. package/dist/reply-polls.js.map +1 -0
  203. package/dist/restart-guard.d.ts +6 -3
  204. package/dist/restart-guard.js +6 -3
  205. package/dist/restart-guard.js.map +1 -1
  206. package/dist/restart-progress.d.ts +33 -2
  207. package/dist/restart-progress.js +30 -2
  208. package/dist/restart-progress.js.map +1 -1
  209. package/dist/sd-notify.d.ts +22 -1
  210. package/dist/sd-notify.js +63 -10
  211. package/dist/sd-notify.js.map +1 -1
  212. package/dist/service-activation.d.ts +15 -7
  213. package/dist/service-activation.js +42 -26
  214. package/dist/service-activation.js.map +1 -1
  215. package/dist/service-installer.d.ts +55 -0
  216. package/dist/service-installer.js +90 -3
  217. package/dist/service-installer.js.map +1 -1
  218. package/dist/service-plan.d.ts +11 -0
  219. package/dist/service-plan.js +23 -0
  220. package/dist/service-plan.js.map +1 -1
  221. package/dist/settings-api.js +14 -4
  222. package/dist/settings-api.js.map +1 -1
  223. package/dist/settings-change.js +4 -2
  224. package/dist/settings-change.js.map +1 -1
  225. package/dist/settings-effect.js +2 -0
  226. package/dist/settings-effect.js.map +1 -1
  227. package/dist/spawn-gate.js +5 -1
  228. package/dist/spawn-gate.js.map +1 -1
  229. package/dist/spawn-hold-reply.d.ts +12 -0
  230. package/dist/spawn-hold-reply.js +39 -0
  231. package/dist/spawn-hold-reply.js.map +1 -0
  232. package/dist/systemd-peer-bus.d.ts +95 -0
  233. package/dist/systemd-peer-bus.js +430 -0
  234. package/dist/systemd-peer-bus.js.map +1 -0
  235. package/dist/systemd-runtime.d.ts +27 -1
  236. package/dist/systemd-runtime.js +69 -7
  237. package/dist/systemd-runtime.js.map +1 -1
  238. package/dist/tips.js +1 -1
  239. package/dist/tips.js.map +1 -1
  240. package/dist/tool-permissions.js +3 -3
  241. package/dist/tool-permissions.js.map +1 -1
  242. package/dist/tool-progress.js +3 -2
  243. package/dist/tool-progress.js.map +1 -1
  244. package/dist/topic-commands.d.ts +71 -4
  245. package/dist/topic-commands.js +167 -34
  246. package/dist/topic-commands.js.map +1 -1
  247. package/dist/transcript-delta-reader.d.ts +3 -3
  248. package/dist/transcript-delta-reader.js +8 -8
  249. package/dist/transcript-delta-reader.js.map +1 -1
  250. package/dist/transcript-jsonl.d.ts +85 -3
  251. package/dist/transcript-jsonl.js +156 -13
  252. package/dist/transcript-jsonl.js.map +1 -1
  253. package/dist/transcript-monitor.d.ts +11 -0
  254. package/dist/transcript-monitor.js +61 -13
  255. package/dist/transcript-monitor.js.map +1 -1
  256. package/dist/transcript-sources.d.ts +24 -0
  257. package/dist/transcript-sources.js +211 -56
  258. package/dist/transcript-sources.js.map +1 -1
  259. package/dist/tunnel/cloudflared.d.ts +7 -15
  260. package/dist/tunnel/cloudflared.js +36 -1
  261. package/dist/tunnel/cloudflared.js.map +1 -1
  262. package/dist/tunnel/purpose-lane.d.ts +5 -1
  263. package/dist/tunnel/purpose-lane.js +14 -7
  264. package/dist/tunnel/purpose-lane.js.map +1 -1
  265. package/dist/tunnel/types.d.ts +5 -1
  266. package/dist/tunnel/types.js.map +1 -1
  267. package/dist/turn-resume.d.ts +2 -0
  268. package/dist/turn-resume.js +1 -1
  269. package/dist/turn-resume.js.map +1 -1
  270. package/dist/types.d.ts +22 -0
  271. package/dist/ui/chat-commands.js +1 -0
  272. package/dist/ui/chat-mentions.js +63 -0
  273. package/dist/ui/chat-render.js +80 -10
  274. package/dist/ui/chat-store.js +70 -6
  275. package/dist/ui/chat-strings.js +62 -32
  276. package/dist/ui/chat-thread.js +199 -24
  277. package/dist/ui/chat-time.js +80 -0
  278. package/dist/ui/chat-tour.js +17 -14
  279. package/dist/ui/panel-chat.js +45 -21
  280. package/dist/ui/panel-details.js +2 -0
  281. package/dist/ui/panel-fleet.js +213 -58
  282. package/dist/ui/panel-log.js +428 -0
  283. package/dist/ui/panel-needs.js +14 -10
  284. package/dist/ui/panel-settings.js +82 -17
  285. package/dist/ui/preview-panel.js +55 -15
  286. package/dist/ui/preview-status.js +28 -0
  287. package/dist/ui/preview.js +44 -3
  288. package/dist/ui/settings-dialogs.js +11 -6
  289. package/dist/ui/settings-model.js +3 -1
  290. package/dist/ui/settings-strings.js +32 -12
  291. package/dist/ui/settings-token.js +8 -1
  292. package/dist/ui/settings-wizard.js +5 -3
  293. package/dist/ui/shared/app-i18n.js +41 -15
  294. package/dist/ui/shared/app-prefs.js +250 -0
  295. package/dist/ui/shared/app-route.js +6 -1
  296. package/dist/ui/shared/app-shell.js +165 -8
  297. package/dist/ui/shared/app-store.js +5 -1
  298. package/dist/ui/shared/app-stream.js +26 -5
  299. package/dist/ui/shared/app.css +170 -30
  300. package/dist/ui/shared/app.js +11 -1
  301. package/dist/ui/shared/fonts/README.md +1 -1
  302. package/dist/ui/shared/header-tools.js +83 -13
  303. package/dist/ui/shared/instance-nav.js +178 -51
  304. package/dist/ui/shared/instance-switch.js +8 -5
  305. package/dist/ui/shared/panel-view.js +21 -4
  306. package/dist/ui/shared/signin.js +15 -9
  307. package/dist/ui/shared/theme.js +39 -7
  308. package/dist/ui/shared/tokens.css +1 -1
  309. package/dist/ui/shared/ui-icons.js +2 -0
  310. package/dist/ui/shared/usage-dialog.js +23 -5
  311. package/dist/ui/shared/view-strings.js +40 -4
  312. package/dist/ui/signin.html +8 -3
  313. package/dist/unrecognised-prompt.d.ts +23 -0
  314. package/dist/unrecognised-prompt.js +74 -0
  315. package/dist/unrecognised-prompt.js.map +1 -0
  316. package/dist/update-check.d.ts +31 -0
  317. package/dist/update-check.js +47 -0
  318. package/dist/update-check.js.map +1 -1
  319. package/dist/update-install.d.ts +13 -1
  320. package/dist/update-install.js +16 -4
  321. package/dist/update-install.js.map +1 -1
  322. package/dist/update-launch.d.ts +48 -1
  323. package/dist/update-launch.js +159 -5
  324. package/dist/update-launch.js.map +1 -1
  325. package/dist/update-marker.d.ts +51 -0
  326. package/dist/update-marker.js +61 -0
  327. package/dist/update-marker.js.map +1 -1
  328. package/dist/usage/i18n-keys.d.ts +1 -1
  329. package/dist/usage/i18n-keys.js +1 -1
  330. package/dist/usage/i18n-keys.js.map +1 -1
  331. package/dist/usage/providers.d.ts +62 -13
  332. package/dist/usage/providers.js +256 -68
  333. package/dist/usage/providers.js.map +1 -1
  334. package/dist/usage/statusline-usage.d.ts +6 -2
  335. package/dist/usage/statusline-usage.js +10 -4
  336. package/dist/usage/statusline-usage.js.map +1 -1
  337. package/dist/view-api.js +31 -9
  338. package/dist/view-api.js.map +1 -1
  339. package/dist/web-api.d.ts +82 -4
  340. package/dist/web-api.js +632 -88
  341. package/dist/web-api.js.map +1 -1
  342. package/dist/web-auth.js +5 -2
  343. package/dist/web-auth.js.map +1 -1
  344. package/dist/web-chat-history.d.ts +26 -1
  345. package/dist/web-chat-history.js +47 -8
  346. package/dist/web-chat-history.js.map +1 -1
  347. package/dist/web-commands.d.ts +41 -5
  348. package/dist/web-commands.js +25 -7
  349. package/dist/web-commands.js.map +1 -1
  350. package/dist/web-login.d.ts +14 -0
  351. package/dist/web-login.js +4 -2
  352. package/dist/web-login.js.map +1 -1
  353. package/dist/web-mentions.d.ts +44 -0
  354. package/dist/web-mentions.js +75 -0
  355. package/dist/web-mentions.js.map +1 -0
  356. package/dist/web-prefs.d.ts +81 -0
  357. package/dist/web-prefs.js +297 -0
  358. package/dist/web-prefs.js.map +1 -0
  359. package/dist/web-preview.d.ts +14 -1
  360. package/dist/web-preview.js +35 -13
  361. package/dist/web-preview.js.map +1 -1
  362. package/dist/web-profile.d.ts +32 -0
  363. package/dist/web-profile.js +132 -0
  364. package/dist/web-profile.js.map +1 -0
  365. package/dist/web-reply-files.d.ts +45 -0
  366. package/dist/web-reply-files.js +223 -0
  367. package/dist/web-reply-files.js.map +1 -0
  368. package/dist/web-schedules.d.ts +12 -0
  369. package/dist/web-schedules.js +34 -0
  370. package/dist/web-schedules.js.map +1 -0
  371. package/dist/web-server-drain.d.ts +10 -0
  372. package/dist/web-server-drain.js +50 -0
  373. package/dist/web-server-drain.js.map +1 -0
  374. package/dist/web-session.d.ts +14 -0
  375. package/dist/web-session.js +11 -1
  376. package/dist/web-session.js.map +1 -1
  377. package/dist/web-settings-patch.d.ts +3 -1
  378. package/dist/web-settings-patch.js +4 -1
  379. package/dist/web-settings-patch.js.map +1 -1
  380. package/dist/web-shell-routes.d.ts +4 -0
  381. package/dist/web-shell-routes.js +9 -0
  382. package/dist/web-shell-routes.js.map +1 -1
  383. package/dist/web-upload.d.ts +135 -7
  384. package/dist/web-upload.js +315 -51
  385. package/dist/web-upload.js.map +1 -1
  386. package/launcher/install-admission.cjs +61 -6
  387. package/package.json +3 -3
  388. package/templates/launchd.plist.ejs +3 -1
  389. package/templates/systemd.service.ejs +2 -1
@@ -8,10 +8,12 @@ import { ConfirmHost } from "./ui-confirm.js";
8
8
  import { t, lang, setLang, onLang } from "./app-i18n.js";
9
9
  import { appStore, createStore, useStore } from "./app-store.js";
10
10
  import { navStore } from "./app-nav.js";
11
- import { chatPath, viewPath, settingsPath, routeKey, NEEDS_PATH, detailsPath } from "./app-route.js";
11
+ import { chatPath, viewPath, settingsPath, routeKey, NEEDS_PATH, detailsPath, fleetPath } from "./app-route.js";
12
12
  import { SessionMenu } from "./app-session.js";
13
+ import { savePref } from "./app-prefs.js";
13
14
  import { ErrorState, Skeleton } from "./ui-states.js";
14
- import { InstanceNav, RosterNav } from "./instance-nav.js";
15
+ import { InstanceNav, RosterNav, namesStore, setNamesPrimary } from "./instance-nav.js";
16
+ import { UsageRail, usageRailStore } from "./header-tools.js";
15
17
 
16
18
  /** Shell state shared with panels: the phone drawer, the collapsed sidebar, extensions a panel module adds. */
17
19
  export const shellStore = createStore({ drawer: false, collapsed: readCollapsed(), keyboard: false, dialog: null, side: null });
@@ -41,6 +43,144 @@ export function closeDialog() { shellStore.set({ dialog: null }); }
41
43
  function readCollapsed() { try { return localStorage.getItem("agend_sidebar") === "hidden"; } catch { return false; } }
42
44
  const narrow = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
43
45
 
46
+ // ── #1722: the sidebar's width — this device's (the #1665 split: a width depends on the screen), through the CSSOM ──
47
+ export const SIDEBAR_W = { min: 200, max: 480, def: 260, step: 16, mainMin: 480 };
48
+ const SIDEBAR_W_KEY = "agend_sidebar_w";
49
+ const win = () => (typeof window !== "undefined" ? window : null);
50
+ const viewportWidth = () => { const w = win(); return w && typeof w.innerWidth === "number" && w.innerWidth > 0 ? w.innerWidth : 1366; };
51
+ /** The width the sidebar may have on a viewport `vw` px wide: within [min, max], and leaving the main pane mainMin. */
52
+ export function clampSidebarWidth(w, vw) {
53
+ const max = Math.max(SIDEBAR_W.min, Math.min(SIDEBAR_W.max, vw - SIDEBAR_W.mainMin));
54
+ return Math.round(Math.min(max, Math.max(SIDEBAR_W.min, w)));
55
+ }
56
+ function storedSidebarWidth() { try { const v = Number(localStorage.getItem(SIDEBAR_W_KEY)); return Number.isFinite(v) && v > 0 ? v : null; } catch { return null; } }
57
+ /** { width: px | null } — null: the default width (tokens.css). */
58
+ export const sidebarWidthStore = createStore({ width: null });
59
+ /** Set the width (clamped to this viewport); `save`: this device keeps it. null: back to the default, nothing kept. */
60
+ /**
61
+ * The room the main pane has beside the sidebar: the window, less the usage rail when it is on screen (#1673 — shown
62
+ * open, ≥ 1200 px; its CSS width when the layout gives none). #1722 review: the sidebar never leaves main under 480.
63
+ */
64
+ function mainBudget() {
65
+ const vw = viewportWidth();
66
+ if (vw < 1200 || typeof document === "undefined") return vw;
67
+ const rail = document.querySelector(".u-rail");
68
+ if (!rail) return vw;
69
+ const w = Math.round(rail.getBoundingClientRect ? rail.getBoundingClientRect().width : 0) || RAIL_W;
70
+ return vw - w;
71
+ }
72
+ const RAIL_W = 320;
73
+ /** Show a width (clamped to the room there is now) — this page only; null: the default width. Nothing is kept. */
74
+ function showSidebarWidth(w) {
75
+ const root = document.documentElement;
76
+ if (w == null) { root.style.removeProperty("--sidebar-w"); sidebarWidthStore.set({ width: null }); return null; }
77
+ const v = clampSidebarWidth(w, mainBudget());
78
+ root.style.setProperty("--sidebar-w", `${v}px`); // CSSOM: the page's CSP allows no style attribute
79
+ sidebarWidthStore.set({ width: v });
80
+ return v;
81
+ }
82
+ /** Set the width (clamped to the room there is now); `save`: this device keeps it. null: back to the default, nothing kept. */
83
+ export function setSidebarWidth(w, save = false) {
84
+ if (w == null) {
85
+ try { localStorage.removeItem(SIDEBAR_W_KEY); } catch { /* this page only */ }
86
+ return showSidebarWidth(null);
87
+ }
88
+ const v = showSidebarWidth(w);
89
+ // Kept: the choice within the window, not the squeeze beside the rail — it comes back when the rail goes.
90
+ if (save) { try { localStorage.setItem(SIDEBAR_W_KEY, String(clampSidebarWidth(w, viewportWidth()))); } catch { /* this page only */ } }
91
+ return v;
92
+ }
93
+ /** A drag in progress (one at a time): its end(commit). Only it may set the width until it ends. */
94
+ let activeDrag = null;
95
+ /**
96
+ * This device's kept width, shown within the room there is now — again whenever that changes (the window, the usage
97
+ * rail, the page). A squeeze is shown, never kept: the device's choice comes back when there is room. On a phone (the
98
+ * drawer) none applies, and a drag in progress is cancelled.
99
+ */
100
+ function applyKeptSidebarWidth() {
101
+ if (narrow()) {
102
+ if (activeDrag) activeDrag.end(false);
103
+ showSidebarWidth(null);
104
+ return;
105
+ }
106
+ if (activeDrag) return;
107
+ const w = storedSidebarWidth();
108
+ if (w != null) showSidebarWidth(w);
109
+ }
110
+ const afterPaint = (fn) => (typeof requestAnimationFrame === "function" ? requestAnimationFrame(() => fn()) : setTimeout(fn, 0));
111
+ /** The separator on the sidebar's right edge: drag, ← → (16 px), Home / End, Enter or a double-click resets. */
112
+ function SidebarResize() {
113
+ const { width } = useStore(sidebarWidthStore);
114
+ useStore(usageRailStore); // the rail's room is the separator's limit too
115
+ useLayoutEffect(() => {
116
+ applyKeptSidebarWidth();
117
+ // The room changes with the window, the rail (opened, closed) and the page (a page with no rail): shown again,
118
+ // once the page has drawn its change.
119
+ const again = () => afterPaint(applyKeptSidebarWidth);
120
+ const offRail = usageRailStore.subscribe(again);
121
+ const offNav = navStore.subscribe(again);
122
+ const w = win();
123
+ if (w && typeof w.addEventListener === "function") w.addEventListener("resize", applyKeptSidebarWidth);
124
+ return () => {
125
+ offRail(); offNav();
126
+ if (w && typeof w.removeEventListener === "function") w.removeEventListener("resize", applyKeptSidebarWidth);
127
+ if (activeDrag) activeDrag.end(false); // unmounted mid-drag: nothing kept, nothing left behind
128
+ };
129
+ }, []);
130
+ const now = width ?? SIDEBAR_W.def;
131
+ const onKey = (e) => {
132
+ const cur = sidebarWidthStore.get().width ?? SIDEBAR_W.def;
133
+ if (e.key === "ArrowRight") setSidebarWidth(cur + SIDEBAR_W.step, true);
134
+ else if (e.key === "ArrowLeft") setSidebarWidth(cur - SIDEBAR_W.step, true);
135
+ else if (e.key === "Home") setSidebarWidth(SIDEBAR_W.min, true);
136
+ else if (e.key === "End") setSidebarWidth(SIDEBAR_W.max, true);
137
+ else if (e.key === "Enter") setSidebarWidth(null);
138
+ else return;
139
+ e.preventDefault();
140
+ };
141
+ // One pointer owns a drag. Only its release keeps the width; a cancel, a lost capture, the drawer or an unmount
142
+ // puts back the width shown before it and keeps nothing — and no event of it can write after it ended. What is kept
143
+ // is where the pointer went (within the window), not what the room beside the rail let it show.
144
+ const onDown = (e) => {
145
+ if (e.button !== 0 || activeDrag || narrow()) return;
146
+ e.preventDefault();
147
+ const handle = e.currentTarget, pointerId = e.pointerId;
148
+ const before = sidebarWidthStore.get().width;
149
+ let chosen = null; // the pointer's own width this drag; null: it never moved
150
+ const left = handle.parentElement ? handle.parentElement.getBoundingClientRect().left : 0;
151
+ const mine = {};
152
+ const own = (ev) => activeDrag === mine && (ev.pointerId === undefined || ev.pointerId === pointerId);
153
+ const move = (ev) => { if (own(ev)) { chosen = ev.clientX - left; showSidebarWidth(chosen); } };
154
+ const up = (ev) => { if (own(ev)) mine.end(true); };
155
+ const cancel = (ev) => { if (own(ev)) mine.end(false); };
156
+ mine.end = (commit) => {
157
+ if (activeDrag !== mine) return;
158
+ activeDrag = null;
159
+ handle.removeEventListener("pointermove", move);
160
+ handle.removeEventListener("pointerup", up);
161
+ handle.removeEventListener("pointercancel", cancel);
162
+ handle.removeEventListener("lostpointercapture", cancel);
163
+ handle.classList.remove("dragging");
164
+ document.body.classList.remove("side-resizing");
165
+ try { handle.releasePointerCapture(pointerId); } catch { /* not held */ }
166
+ if (commit && chosen != null) setSidebarWidth(chosen, true);
167
+ else showSidebarWidth(before);
168
+ };
169
+ activeDrag = mine;
170
+ try { handle.setPointerCapture(pointerId); } catch { /* the move still works while over the handle */ }
171
+ handle.classList.add("dragging");
172
+ document.body.classList.add("side-resizing");
173
+ handle.addEventListener("pointermove", move);
174
+ handle.addEventListener("pointerup", up);
175
+ handle.addEventListener("pointercancel", cancel);
176
+ handle.addEventListener("lostpointercapture", cancel);
177
+ };
178
+ return html`<div class="side-resize" role="separator" aria-orientation="vertical" tabindex="0" aria-controls="sidebar"
179
+ aria-label=${t("app.resizeSidebar")} title=${t("app.resizeSidebarHint")} aria-valuemin=${String(SIDEBAR_W.min)}
180
+ aria-valuemax=${String(clampSidebarWidth(Infinity, mainBudget()))} aria-valuenow=${String(now)}
181
+ onKeyDown=${onKey} onPointerDown=${onDown} ondblclick=${() => setSidebarWidth(null)}></div>`;
182
+ }
183
+
44
184
  export function openDrawer() { shellStore.set({ drawer: true }); }
45
185
  export function closeDrawer() { if (shellStore.get().drawer) shellStore.set({ drawer: false }); }
46
186
  export function toggleSidebar() {
@@ -104,7 +244,8 @@ export function signInHref() {
104
244
  function Sidebar({ route, onNewInstance, viewOnly }) {
105
245
  const app = useStore(appStore);
106
246
  const shell = useStore(shellStore);
107
- const on = (panel) => !!route && (route.panel === panel || (panel === "fleet" && route.panel === "details"));
247
+ // #1675: the Fleet panel is "Fleet overview"'s (one current row); the "Fleet" row is current on an instance's Details.
248
+ const on = (panel) => !!route && (panel === "fleet" ? route.panel === "details" : route.panel === panel);
108
249
  const openInstance = openInstanceOf(route);
109
250
  // A count badge is hidden at 0; its number is also in the link's accessible name.
110
251
  const navLink = (panel, href, icon, label, count = 0) => html`<a class=${`side-row${on(panel) ? " active" : ""}`} href=${href}
@@ -124,8 +265,14 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
124
265
  <a class="side-row" href=${signInHref()}><${Icon} name="user" /><span>${t("app.signIn")}</span></a>
125
266
  <${PrefsPopover} />
126
267
  </div>
268
+ <${SidebarResize} />
127
269
  </aside>`;
128
270
  }
271
+ // #1675: the whole fleet, on its Org chart (#1389), from anywhere — top left, so at the top of a phone's drawer too. The
272
+ // "Fleet" row under it goes to the open instance's Details (#1523 N2); this one is the Fleet panel, any of its tabs.
273
+ const onFleet = !!route && route.panel === "fleet";
274
+ const overview = html`<a class=${`side-row side-overview${onFleet ? " active" : ""}`} href=${fleetPath("org")}
275
+ aria-current=${onFleet ? "page" : undefined} onClick=${closeDrawer}><${Icon} name="org" /><span class="grow">${t("app.fleetOverview")}</span></a>`;
129
276
  return html`<aside id="sidebar" class="sidebar" aria-label=${t("app.menu")}>
130
277
  <div class="side-head">
131
278
  <a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
@@ -133,6 +280,7 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
133
280
  <button type="button" class="icon-btn" onClick=${onNewInstance} aria-label=${t("app.newInstance")} title=${t("app.newInstance")}><${Icon} name="plus" /></button>
134
281
  </div>
135
282
  <nav class="side-nav" aria-label=${t("app.menu")}>
283
+ ${overview}
136
284
  ${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
137
285
  ${navLink("fleet", openInstance ? detailsPath(openInstance) : "/ui/fleet", "fleet", t("app.fleet"))}
138
286
  ${navLink("view", "/view", "view", t("app.view"))}
@@ -143,6 +291,7 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
143
291
  ${navLink("settings", settingsPath(), "settings", t("app.settings"))}
144
292
  <${SessionMenu} />
145
293
  </div>
294
+ <${SidebarResize} />
146
295
  </aside>`;
147
296
  }
148
297
 
@@ -158,13 +307,20 @@ function ViewOnlyNav({ route }) {
158
307
  export function DevicePrefs({ labels = false } = {}) {
159
308
  const [theme, setTheme] = useState(typeof AgendTheme !== "undefined" ? AgendTheme.get() : "system");
160
309
  const [l, setL] = useState(lang());
310
+ const names = useStore(namesStore); // #1722
311
+ // #1665: what is in force, as it changes — another device's choice arriving while this is open is shown at once.
312
+ useEffect(() => (typeof AgendTheme !== "undefined" && typeof AgendTheme.onChange === "function" ? AgendTheme.onChange(setTheme) : undefined), []);
313
+ useEffect(() => onLang(setL), []);
161
314
  return html`<div class=${`prefs${labels ? " labelled" : ""}`}>
162
315
  <label class="pref"><${Icon} name="sun" size=${16} /><span class=${labels ? "pref-label" : "sr-only"}>${t("app.theme")}</span>
163
- <select value=${theme} aria-label=${t("app.theme")} onChange=${(e) => { setTheme(e.target.value); if (typeof AgendTheme !== "undefined") AgendTheme.set(e.target.value); }}>
316
+ <select value=${theme} aria-label=${t("app.theme")} onChange=${(e) => { setTheme(e.target.value); if (typeof AgendTheme !== "undefined") AgendTheme.set(e.target.value); savePref("theme", e.target.value); }}>
164
317
  <option value="system">${t("app.themeSystem")}</option><option value="light">${t("app.themeLight")}</option><option value="dark">${t("app.themeDark")}</option></select></label>
165
318
  <label class="pref"><${Icon} name="globe" size=${16} /><span class=${labels ? "pref-label" : "sr-only"}>${t("app.language")}</span>
166
- <select value=${l} aria-label=${t("app.language")} onChange=${(e) => { setL(e.target.value); setLang(e.target.value); }}>
319
+ <select value=${l} aria-label=${t("app.language")} onChange=${(e) => { setL(e.target.value); setLang(e.target.value); savePref("lang", e.target.value); }}>
167
320
  <option value="en">English</option><option value="zh-TW">中文</option></select></label>
321
+ <label class="pref"><${Icon} name="user" size=${16} /><span class=${labels ? "pref-label" : "sr-only"}>${t("app.names")}</span>
322
+ <select value=${names.primary} aria-label=${t("app.names")} onChange=${(e) => setNamesPrimary(e.target.value)}>
323
+ <option value="nickname">${t("app.namesNickname")}</option><option value="instance">${t("app.namesInstance")}</option></select></label>
168
324
  </div>`;
169
325
  }
170
326
 
@@ -192,11 +348,11 @@ export function PanelHeader({ title, sub, children, headingRef, nav }) {
192
348
  }
193
349
 
194
350
  /**
195
- * #1523 N2: the instance a page is about — Chat, View or Details of it — or null. With one open, Fleet goes to its
351
+ * #1523 N2: the instance a page is about — Chat, View, Log (#1218) or Details of it — or null. With one open, Fleet goes to its
196
352
  * Details (the user's complaint: Fleet always landed on Tasks), and Chat and View keep it; with none, as before.
197
353
  */
198
354
  export function openInstanceOf(route) {
199
- return route && (route.panel === "chat" || route.panel === "view" || route.panel === "details") && route.instance ? route.instance : null;
355
+ return route && (route.panel === "chat" || route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? route.instance : null;
200
356
  }
201
357
 
202
358
  function BottomTabs({ route, viewOnly }) {
@@ -210,7 +366,7 @@ function BottomTabs({ route, viewOnly }) {
210
366
  <${Icon} name=${icon} size=${20} /><span>${label}</span>${badge ? html`<span class="tab-badge" aria-label=${badgeLabel || t("app.needsYou")}>${badge}</span>` : null}</a>`;
211
367
  let lastView = null;
212
368
  try { lastView = localStorage.getItem("agend_last_view"); } catch { /* none */ }
213
- const viewHref = route && (route.panel === "view" || route.panel === "details") && route.instance ? viewPath(route.instance) : viewPath(lastView);
369
+ const viewHref = route && (route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? viewPath(route.instance) : viewPath(lastView);
214
370
  if (viewOnly) {
215
371
  return html`<nav class="tabs" aria-label=${t("app.menu")}>
216
372
  ${tab(viewHref, "view", t("app.view"), route && route.panel === "view")}
@@ -351,6 +507,7 @@ export function Shell({ panels, onNewInstance, viewOnly = false }) {
351
507
  ${viewOnly ? null : html`<${OperationLine} route=${nav.route} />`}
352
508
  <${Outlet} route=${nav.route} seq=${nav.seq} panels=${panels} />
353
509
  </main>
510
+ <${UsageRail} route=${nav.route} />
354
511
  <${BottomTabs} route=${nav.route} viewOnly=${viewOnly} />
355
512
  ${shell.dialog ? html`<${shell.dialog.Component} ...${shell.dialog.props} onClose=${closeDialog} />` : null}
356
513
  ${viewOnly || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
@@ -36,7 +36,11 @@ export function applyStatus(d) {
36
36
  if (i.state === "awaiting_input") awaiting[i.name] = typeof i.interaction_summary === "string" ? i.interaction_summary : "";
37
37
  }
38
38
  appStore.set({ ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
39
- connections: typeof d.connections === "number" ? d.connections : null });
39
+ connections: typeof d.connections === "number" ? d.connections : null,
40
+ // #1665: the host preferences' revision (app-prefs.js re-reads them when it moves).
41
+ prefsRev: typeof d.prefs_rev === "number" ? d.prefs_rev : null,
42
+ // #1685: host memory pressure slowing or holding new agents ("elevated" | "critical"), else null.
43
+ hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null });
40
44
  }
41
45
 
42
46
  /** One "activity" event: an instance started or stopped working. */
@@ -29,14 +29,15 @@
29
29
  // - a 401 is the session ending: nothing is retried (agend-auth.js says so).
30
30
  // - suspend()/resume(): the page is leaving (pagehide) / came back from the back-forward cache.
31
31
 
32
- const EVENTS = ["status", "message", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons"];
32
+ // #1218: steps_tick — an instance's transcript moved while a Log watches it (SSE only: a poll page asks the Log itself).
33
+ const EVENTS = ["status", "message", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock"];
33
34
  const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
34
35
  const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
35
36
  const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
36
37
  const MAX_OVERFLOW_READS = 3; // reads again after dropped live events, within one catch-up
37
38
  // #1580: the reconnect backoff — step n waits min(cap, base·2ⁿ), drawn from 50–100 % of that (jitter: tabs that lost
38
39
  // the fleet together do not come back together).
39
- export const RECONNECT = { baseMs: 1000, capMs: 30000 };
40
+ export const RECONNECT = { baseMs: 1000, capMs: 30000, shutdownMs: 10000 };
40
41
  export function reconnectDelay(step, random = Math.random) {
41
42
  const full = Math.min(RECONNECT.capMs, RECONNECT.baseMs * 2 ** Math.min(step, 20));
42
43
  return Math.round(full * (0.5 + random() * 0.5));
@@ -49,6 +50,7 @@ export function createStream(opts) {
49
50
  let sse = null, pollTimer = null, silentTimer = null, closed = false, started = false;
50
51
  // #1580: the reconnect step waiting, how many failed in a row, a step waiting for the tab to be shown, a page that left.
51
52
  let reconnectTimer = null, attempts = 0, waitingVisible = false, suspended = false, ended = false, retryAt = 0;
53
+ let shutdownUntil = 0; // monotonic; retained through pagehide/pageshow
52
54
  const random = typeof env.random === "function" ? env.random : Math.random;
53
55
  const doc = env.document || null;
54
56
  const hidden = () => !!(doc && doc.hidden);
@@ -112,6 +114,7 @@ export function createStream(opts) {
112
114
  if (closed || mine !== pollSeq || !r.ok) return false;
113
115
  const d = await r.json();
114
116
  if (closed || mine !== pollSeq) return false;
117
+ if (typeof d.now === "number") emit("clock", { now: d.now }); // #1823: read just now, handed over at once
115
118
  if (d.status) emit("status", d.status);
116
119
  for (const m of d.messages || []) emit("message", m);
117
120
  if (typeof d.cursor === "string") state.cursor = d.cursor;
@@ -188,6 +191,18 @@ export function createStream(opts) {
188
191
  const es = sse = new env.EventSource("/ui/events");
189
192
  let spoke = false;
190
193
  silentTimer = env.setTimeout(startPolling, 15000); // the server sends a status frame the moment a stream opens
194
+ es.addEventListener("shutdown", (e) => {
195
+ if (es !== sse || closed || suspended || ended) return;
196
+ let data;
197
+ try { data = JSON.parse(e.data); } catch { return; }
198
+ if (data?.retry_ms !== RECONNECT.shutdownMs) return;
199
+ shutdownUntil = now() + RECONNECT.shutdownMs + Math.round(random() * 5000);
200
+ cancelWork(); closeStream(); stopPolling();
201
+ env.clearTimeout(reconnectTimer); reconnectTimer = null; waitingVisible = false;
202
+ attempts = Math.max(attempts, 4);
203
+ setConnection("reconnecting");
204
+ scheduleStep(shutdownUntil - now());
205
+ });
191
206
  for (const name of EVENTS) {
192
207
  es.addEventListener(name, (e) => {
193
208
  if (es !== sse) return; // a stream this page already let go of
@@ -195,6 +210,8 @@ export function createStream(opts) {
195
210
  try { data = JSON.parse(e.data); } catch { return; }
196
211
  if (!spoke) { spoke = true; alive(); if (again) catchUp(); }
197
212
  else alive();
213
+ // #1823: a clock reading is about now, not about order: it is never held behind a catch-up (it would be stale).
214
+ if (name === "clock") { emit(name, data); return; }
198
215
  live(name, data, name === "message" ? e.lastEventId : null);
199
216
  });
200
217
  }
@@ -216,15 +233,16 @@ export function createStream(opts) {
216
233
  else setConnection("reconnecting");
217
234
  scheduleStep();
218
235
  }
219
- function scheduleStep() {
236
+ function scheduleStep(delay) {
220
237
  if (reconnectTimer || closed || suspended || ended) return;
221
- const ms = reconnectDelay(attempts++, random);
238
+ const ms = Math.max(delay ?? reconnectDelay(attempts++, random), shutdownUntil - now());
222
239
  retryAt = now() + ms;
223
240
  emit("retry", { inMs: ms });
224
241
  reconnectTimer = env.setTimeout(() => { reconnectTimer = null; step(); }, ms);
225
242
  }
226
243
  function step() {
227
244
  if (closed || suspended || ended) return;
245
+ if (shutdownUntil > now()) { scheduleStep(shutdownUntil - now()); return; }
228
246
  if (hidden()) { waitingVisible = true; return; } // not while nobody looks: the next step waits to be shown
229
247
  if (opts.transport === "poll") { pollProbe(); return; }
230
248
  openStream(true);
@@ -255,7 +273,7 @@ export function createStream(opts) {
255
273
  * It opens no transport: still the one EventSource, and no polling loop.
256
274
  */
257
275
  function catchUp() {
258
- if (closed || ended) return Promise.resolve(false);
276
+ if (closed || ended || shutdownUntil > now()) return Promise.resolve(false);
259
277
  if (catching) return catching;
260
278
  env.clearTimeout(retryTimer); retryTimer = null;
261
279
  setHydration("catching");
@@ -327,6 +345,9 @@ export function createStream(opts) {
327
345
  if (closed || !suspended || ended) return;
328
346
  suspended = false;
329
347
  epoch++;
348
+ if (shutdownUntil > now()) {
349
+ setConnection("reconnecting"); scheduleStep(shutdownUntil - now()); return;
350
+ }
330
351
  attempts = 0;
331
352
  if (opts.transport === "poll") { startPolling(); return; }
332
353
  openStream(true);