@songsid/agend 2.2.0-beta.1 → 2.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/README.md +1 -1
  2. package/README.zh-TW.md +1 -1
  3. package/dist/agent-cli-instructions.md +16 -9
  4. package/dist/agent-cli.js +15 -7
  5. package/dist/agent-cli.js.map +1 -1
  6. package/dist/agent-endpoint.js +21 -9
  7. package/dist/agent-endpoint.js.map +1 -1
  8. package/dist/agent-whats-new.d.ts +47 -0
  9. package/dist/agent-whats-new.js +147 -0
  10. package/dist/agent-whats-new.js.map +1 -0
  11. package/dist/auth-api.d.ts +2 -2
  12. package/dist/auth-api.js +4 -2
  13. package/dist/auth-api.js.map +1 -1
  14. package/dist/backend/antigravity.d.ts +3 -0
  15. package/dist/backend/antigravity.js +9 -0
  16. package/dist/backend/antigravity.js.map +1 -1
  17. package/dist/backend/claude-carry.d.ts +22 -0
  18. package/dist/backend/claude-carry.js +170 -0
  19. package/dist/backend/claude-carry.js.map +1 -0
  20. package/dist/backend/claude-code.d.ts +65 -2
  21. package/dist/backend/claude-code.js +226 -33
  22. package/dist/backend/claude-code.js.map +1 -1
  23. package/dist/backend/codex-metadata.d.ts +33 -0
  24. package/dist/backend/codex-metadata.js +122 -18
  25. package/dist/backend/codex-metadata.js.map +1 -1
  26. package/dist/backend/codex.d.ts +3 -0
  27. package/dist/backend/codex.js +17 -1
  28. package/dist/backend/codex.js.map +1 -1
  29. package/dist/backend/credential-profile.d.ts +40 -3
  30. package/dist/backend/credential-profile.js +113 -5
  31. package/dist/backend/credential-profile.js.map +1 -1
  32. package/dist/backend/effort-metadata.d.ts +1 -1
  33. package/dist/backend/effort-metadata.js +3 -2
  34. package/dist/backend/effort-metadata.js.map +1 -1
  35. package/dist/backend/grok.d.ts +4 -0
  36. package/dist/backend/grok.js +14 -0
  37. package/dist/backend/grok.js.map +1 -1
  38. package/dist/backend/kiro-engine-ledger.d.ts +5 -0
  39. package/dist/backend/kiro-engine-ledger.js +20 -0
  40. package/dist/backend/kiro-engine-ledger.js.map +1 -1
  41. package/dist/backend/kiro-identity.d.ts +6 -0
  42. package/dist/backend/kiro-identity.js +19 -5
  43. package/dist/backend/kiro-identity.js.map +1 -1
  44. package/dist/backend/kiro.d.ts +39 -3
  45. package/dist/backend/kiro.js +143 -19
  46. package/dist/backend/kiro.js.map +1 -1
  47. package/dist/backend/launch-effort.d.ts +33 -0
  48. package/dist/backend/launch-effort.js +123 -0
  49. package/dist/backend/launch-effort.js.map +1 -0
  50. package/dist/backend/muse.d.ts +84 -0
  51. package/dist/backend/muse.js +449 -53
  52. package/dist/backend/muse.js.map +1 -1
  53. package/dist/backend/types.d.ts +33 -4
  54. package/dist/backend/types.js +2 -1
  55. package/dist/backend/types.js.map +1 -1
  56. package/dist/backend-command.d.ts +91 -0
  57. package/dist/backend-command.js +122 -0
  58. package/dist/backend-command.js.map +1 -0
  59. package/dist/background-work-ended.d.ts +18 -0
  60. package/dist/background-work-ended.js +30 -0
  61. package/dist/background-work-ended.js.map +1 -0
  62. package/dist/cache-service.d.ts +2 -0
  63. package/dist/cache-service.js +2 -1
  64. package/dist/cache-service.js.map +1 -1
  65. package/dist/channel/adapters/discord.d.ts +24 -1
  66. package/dist/channel/adapters/discord.js +87 -2
  67. package/dist/channel/adapters/discord.js.map +1 -1
  68. package/dist/channel/adapters/telegram.d.ts +24 -2
  69. package/dist/channel/adapters/telegram.js +118 -20
  70. package/dist/channel/adapters/telegram.js.map +1 -1
  71. package/dist/channel/mcp-server.js +9 -1
  72. package/dist/channel/mcp-server.js.map +1 -1
  73. package/dist/channel/mcp-tools.d.ts +11 -0
  74. package/dist/channel/mcp-tools.js +24 -13
  75. package/dist/channel/mcp-tools.js.map +1 -1
  76. package/dist/channel/message-edit-errors.d.ts +5 -0
  77. package/dist/channel/message-edit-errors.js +24 -0
  78. package/dist/channel/message-edit-errors.js.map +1 -0
  79. package/dist/channel/telegram-markdown.d.ts +6 -0
  80. package/dist/channel/telegram-markdown.js +104 -0
  81. package/dist/channel/telegram-markdown.js.map +1 -0
  82. package/dist/channel/tool-router.js +9 -3
  83. package/dist/channel/tool-router.js.map +1 -1
  84. package/dist/channel/types.d.ts +39 -3
  85. package/dist/cli.js +133 -28
  86. package/dist/cli.js.map +1 -1
  87. package/dist/command-table.d.ts +2 -2
  88. package/dist/command-table.js +6 -3
  89. package/dist/command-table.js.map +1 -1
  90. package/dist/config-validator.js +59 -0
  91. package/dist/config-validator.js.map +1 -1
  92. package/dist/cross-instance-envelope.d.ts +15 -2
  93. package/dist/cross-instance-envelope.js +29 -5
  94. package/dist/cross-instance-envelope.js.map +1 -1
  95. package/dist/daemon.d.ts +156 -1
  96. package/dist/daemon.js +764 -89
  97. package/dist/daemon.js.map +1 -1
  98. package/dist/delivery-outbox.d.ts +62 -7
  99. package/dist/delivery-outbox.js +309 -22
  100. package/dist/delivery-outbox.js.map +1 -1
  101. package/dist/delivery-reconciliation.d.ts +18 -1
  102. package/dist/delivery-reconciliation.js +67 -2
  103. package/dist/delivery-reconciliation.js.map +1 -1
  104. package/dist/fleet-context.d.ts +10 -1
  105. package/dist/fleet-manager.d.ts +345 -10
  106. package/dist/fleet-manager.js +1868 -174
  107. package/dist/fleet-manager.js.map +1 -1
  108. package/dist/general-knowledge/skills/backend-providers/SKILL.md +1 -1
  109. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +92 -21
  110. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +27 -3
  111. package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +8 -8
  112. package/dist/general-knowledge/skills/fleet-config/SKILL.md +5 -5
  113. package/dist/general-knowledge/skills/fleet-health/SKILL.md +4 -4
  114. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +13 -13
  115. package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -2
  116. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +6 -0
  117. package/dist/general-knowledge/skills/model-discovery/SKILL.md +9 -9
  118. package/dist/general-knowledge/skills/multi-channel/SKILL.md +8 -2
  119. package/dist/general-knowledge/skills/scheduling/SKILL.md +5 -3
  120. package/dist/general-knowledge/skills/session-management/SKILL.md +6 -5
  121. package/dist/general-knowledge/skills/tui-effort/SKILL.md +2 -2
  122. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +8 -3
  123. package/dist/general-knowledge/steering/core-rules.md +8 -7
  124. package/dist/host-memory.d.ts +10 -0
  125. package/dist/host-memory.js +33 -1
  126. package/dist/host-memory.js.map +1 -1
  127. package/dist/human-delivery-receipts.d.ts +83 -0
  128. package/dist/human-delivery-receipts.js +194 -0
  129. package/dist/human-delivery-receipts.js.map +1 -0
  130. package/dist/instance-avatar.d.ts +36 -0
  131. package/dist/instance-avatar.js +57 -0
  132. package/dist/instance-avatar.js.map +1 -0
  133. package/dist/instance-config-impact.js +6 -0
  134. package/dist/instance-config-impact.js.map +1 -1
  135. package/dist/instance-lifecycle.d.ts +29 -6
  136. package/dist/instance-lifecycle.js +79 -28
  137. package/dist/instance-lifecycle.js.map +1 -1
  138. package/dist/instructions.d.ts +3 -1
  139. package/dist/instructions.js +11 -8
  140. package/dist/instructions.js.map +1 -1
  141. package/dist/kiro-log-gate.d.ts +42 -0
  142. package/dist/kiro-log-gate.js +39 -0
  143. package/dist/kiro-log-gate.js.map +1 -0
  144. package/dist/locale.js +200 -44
  145. package/dist/locale.js.map +1 -1
  146. package/dist/log-service.d.ts +99 -0
  147. package/dist/log-service.js +243 -0
  148. package/dist/log-service.js.map +1 -0
  149. package/dist/log-steps.d.ts +169 -0
  150. package/dist/log-steps.js +858 -0
  151. package/dist/log-steps.js.map +1 -0
  152. package/dist/login-controller.d.ts +20 -3
  153. package/dist/login-controller.js +71 -19
  154. package/dist/login-controller.js.map +1 -1
  155. package/dist/login-flows.d.ts +5 -2
  156. package/dist/login-flows.js +5 -4
  157. package/dist/login-flows.js.map +1 -1
  158. package/dist/memory-pressure.d.ts +13 -1
  159. package/dist/memory-pressure.js +50 -10
  160. package/dist/memory-pressure.js.map +1 -1
  161. package/dist/needs-you-hub.js +2 -0
  162. package/dist/needs-you-hub.js.map +1 -1
  163. package/dist/needs-you-live.d.ts +6 -0
  164. package/dist/needs-you-live.js +23 -3
  165. package/dist/needs-you-live.js.map +1 -1
  166. package/dist/next-steps.js +1 -1
  167. package/dist/next-steps.js.map +1 -1
  168. package/dist/outbound-handlers.d.ts +100 -0
  169. package/dist/outbound-handlers.js +263 -96
  170. package/dist/outbound-handlers.js.map +1 -1
  171. package/dist/outbound-schemas.d.ts +26 -15
  172. package/dist/outbound-schemas.js +24 -7
  173. package/dist/outbound-schemas.js.map +1 -1
  174. package/dist/public-link-progress.d.ts +1 -1
  175. package/dist/public-link-progress.js +8 -2
  176. package/dist/public-link-progress.js.map +1 -1
  177. package/dist/public-preview.d.ts +101 -0
  178. package/dist/public-preview.js +236 -0
  179. package/dist/public-preview.js.map +1 -0
  180. package/dist/public-web-gateway.js +11 -4
  181. package/dist/public-web-gateway.js.map +1 -1
  182. package/dist/public-web-link.d.ts +24 -1
  183. package/dist/public-web-link.js +63 -9
  184. package/dist/public-web-link.js.map +1 -1
  185. package/dist/reply-buttons-controller.d.ts +3 -0
  186. package/dist/reply-buttons-controller.js +3 -2
  187. package/dist/reply-buttons-controller.js.map +1 -1
  188. package/dist/restart-guard.d.ts +6 -3
  189. package/dist/restart-guard.js +6 -3
  190. package/dist/restart-guard.js.map +1 -1
  191. package/dist/restart-progress.d.ts +33 -0
  192. package/dist/restart-progress.js +30 -0
  193. package/dist/restart-progress.js.map +1 -1
  194. package/dist/service-activation.d.ts +15 -7
  195. package/dist/service-activation.js +46 -29
  196. package/dist/service-activation.js.map +1 -1
  197. package/dist/service-installer.d.ts +31 -0
  198. package/dist/service-installer.js +41 -2
  199. package/dist/service-installer.js.map +1 -1
  200. package/dist/settings-api.js +85 -25
  201. package/dist/settings-api.js.map +1 -1
  202. package/dist/settings-change.js +72 -1
  203. package/dist/settings-change.js.map +1 -1
  204. package/dist/settings-effect.js +28 -4
  205. package/dist/settings-effect.js.map +1 -1
  206. package/dist/settings-http-confirmation.js +7 -0
  207. package/dist/settings-http-confirmation.js.map +1 -1
  208. package/dist/setup-form.d.ts +1 -1
  209. package/dist/setup-form.js +1 -1
  210. package/dist/spawn-gate.js +5 -1
  211. package/dist/spawn-gate.js.map +1 -1
  212. package/dist/spawn-hold-reply.d.ts +12 -0
  213. package/dist/spawn-hold-reply.js +39 -0
  214. package/dist/spawn-hold-reply.js.map +1 -0
  215. package/dist/status-emojis.d.ts +10 -3
  216. package/dist/status-emojis.js +11 -2
  217. package/dist/status-emojis.js.map +1 -1
  218. package/dist/systemd-peer-bus.d.ts +95 -0
  219. package/dist/systemd-peer-bus.js +430 -0
  220. package/dist/systemd-peer-bus.js.map +1 -0
  221. package/dist/systemd-runtime.d.ts +27 -1
  222. package/dist/systemd-runtime.js +69 -7
  223. package/dist/systemd-runtime.js.map +1 -1
  224. package/dist/tips.js +4 -4
  225. package/dist/tips.js.map +1 -1
  226. package/dist/tool-progress.js +3 -2
  227. package/dist/tool-progress.js.map +1 -1
  228. package/dist/topic-commands.d.ts +42 -2
  229. package/dist/topic-commands.js +92 -7
  230. package/dist/topic-commands.js.map +1 -1
  231. package/dist/transcript-delta-reader.d.ts +3 -3
  232. package/dist/transcript-delta-reader.js +8 -8
  233. package/dist/transcript-delta-reader.js.map +1 -1
  234. package/dist/transcript-jsonl.d.ts +80 -3
  235. package/dist/transcript-jsonl.js +147 -10
  236. package/dist/transcript-jsonl.js.map +1 -1
  237. package/dist/transcript-monitor.d.ts +19 -0
  238. package/dist/transcript-monitor.js +87 -15
  239. package/dist/transcript-monitor.js.map +1 -1
  240. package/dist/transcript-sources.d.ts +78 -0
  241. package/dist/transcript-sources.js +375 -64
  242. package/dist/transcript-sources.js.map +1 -1
  243. package/dist/transcript-turns.d.ts +15 -2
  244. package/dist/transcript-turns.js +15 -2
  245. package/dist/transcript-turns.js.map +1 -1
  246. package/dist/tunnel/cloudflared.d.ts +7 -15
  247. package/dist/tunnel/cloudflared.js +36 -1
  248. package/dist/tunnel/cloudflared.js.map +1 -1
  249. package/dist/tunnel/purpose-lane.d.ts +5 -1
  250. package/dist/tunnel/purpose-lane.js +14 -7
  251. package/dist/tunnel/purpose-lane.js.map +1 -1
  252. package/dist/tunnel/types.d.ts +5 -1
  253. package/dist/tunnel/types.js.map +1 -1
  254. package/dist/turn-resume.d.ts +2 -0
  255. package/dist/turn-resume.js +1 -1
  256. package/dist/turn-resume.js.map +1 -1
  257. package/dist/types.d.ts +25 -0
  258. package/dist/ui/chat-commands.js +1 -0
  259. package/dist/ui/chat-emojis.js +33 -0
  260. package/dist/ui/chat-mentions.js +63 -0
  261. package/dist/ui/chat-render.js +42 -2
  262. package/dist/ui/chat-store.js +2 -2
  263. package/dist/ui/chat-strings.js +38 -20
  264. package/dist/ui/chat-thread.js +69 -12
  265. package/dist/ui/chat-time.js +80 -0
  266. package/dist/ui/panel-chat.js +39 -10
  267. package/dist/ui/panel-details.js +2 -0
  268. package/dist/ui/panel-fleet.js +199 -57
  269. package/dist/ui/panel-log.js +428 -0
  270. package/dist/ui/panel-needs.js +6 -2
  271. package/dist/ui/panel-settings.js +137 -32
  272. package/dist/ui/preview-panel.js +55 -15
  273. package/dist/ui/preview-status.js +28 -0
  274. package/dist/ui/preview.js +44 -3
  275. package/dist/ui/settings-dialogs.js +7 -2
  276. package/dist/ui/settings-model.js +2 -1
  277. package/dist/ui/settings-strings.js +46 -4
  278. package/dist/ui/settings-token.js +1 -1
  279. package/dist/ui/shared/app-i18n.js +43 -17
  280. package/dist/ui/shared/app-prefs.js +250 -0
  281. package/dist/ui/shared/app-route.js +7 -2
  282. package/dist/ui/shared/app-shell.js +165 -8
  283. package/dist/ui/shared/app-store.js +5 -1
  284. package/dist/ui/shared/app-stream.js +23 -5
  285. package/dist/ui/shared/app.css +155 -22
  286. package/dist/ui/shared/app.js +11 -1
  287. package/dist/ui/shared/fonts/README.md +1 -1
  288. package/dist/ui/shared/header-tools.js +55 -5
  289. package/dist/ui/shared/instance-nav.js +241 -45
  290. package/dist/ui/shared/instance-switch.js +4 -4
  291. package/dist/ui/shared/panel-view.js +6 -0
  292. package/dist/ui/shared/signin.js +7 -7
  293. package/dist/ui/shared/theme.js +39 -7
  294. package/dist/ui/shared/tokens.css +1 -1
  295. package/dist/ui/shared/ui-icons.js +1 -0
  296. package/dist/ui/shared/usage-dialog.js +23 -5
  297. package/dist/ui/shared/view-strings.js +32 -4
  298. package/dist/ui/signin.html +1 -1
  299. package/dist/unrecognised-prompt.d.ts +23 -0
  300. package/dist/unrecognised-prompt.js +74 -0
  301. package/dist/unrecognised-prompt.js.map +1 -0
  302. package/dist/update-install.d.ts +28 -2
  303. package/dist/update-install.js +22 -4
  304. package/dist/update-install.js.map +1 -1
  305. package/dist/update-marker.d.ts +51 -0
  306. package/dist/update-marker.js +61 -0
  307. package/dist/update-marker.js.map +1 -1
  308. package/dist/update-preflight.d.ts +100 -0
  309. package/dist/update-preflight.js +264 -0
  310. package/dist/update-preflight.js.map +1 -0
  311. package/dist/updater-caller.d.ts +31 -0
  312. package/dist/updater-caller.js +109 -0
  313. package/dist/updater-caller.js.map +1 -0
  314. package/dist/usage/i18n-keys.d.ts +1 -1
  315. package/dist/usage/i18n-keys.js +1 -1
  316. package/dist/usage/i18n-keys.js.map +1 -1
  317. package/dist/usage/providers.d.ts +34 -5
  318. package/dist/usage/providers.js +160 -27
  319. package/dist/usage/providers.js.map +1 -1
  320. package/dist/usage/statusline-usage.d.ts +6 -2
  321. package/dist/usage/statusline-usage.js +10 -4
  322. package/dist/usage/statusline-usage.js.map +1 -1
  323. package/dist/view-api.d.ts +1 -1
  324. package/dist/view-api.js +38 -8
  325. package/dist/view-api.js.map +1 -1
  326. package/dist/wake-coordinator.d.ts +11 -0
  327. package/dist/wake-coordinator.js +38 -4
  328. package/dist/wake-coordinator.js.map +1 -1
  329. package/dist/web-api.d.ts +49 -2
  330. package/dist/web-api.js +421 -31
  331. package/dist/web-api.js.map +1 -1
  332. package/dist/web-auth.d.ts +2 -2
  333. package/dist/web-auth.js +9 -4
  334. package/dist/web-auth.js.map +1 -1
  335. package/dist/web-commands.d.ts +27 -4
  336. package/dist/web-commands.js +19 -4
  337. package/dist/web-commands.js.map +1 -1
  338. package/dist/web-host-guard.d.ts +3 -11
  339. package/dist/web-host-guard.js +3 -12
  340. package/dist/web-host-guard.js.map +1 -1
  341. package/dist/web-images.d.ts +47 -0
  342. package/dist/web-images.js +169 -0
  343. package/dist/web-images.js.map +1 -0
  344. package/dist/web-mentions.d.ts +44 -0
  345. package/dist/web-mentions.js +75 -0
  346. package/dist/web-mentions.js.map +1 -0
  347. package/dist/web-prefs.d.ts +63 -0
  348. package/dist/web-prefs.js +265 -0
  349. package/dist/web-prefs.js.map +1 -0
  350. package/dist/web-preview.d.ts +14 -1
  351. package/dist/web-preview.js +35 -13
  352. package/dist/web-preview.js.map +1 -1
  353. package/dist/web-reply-files.d.ts +45 -0
  354. package/dist/web-reply-files.js +223 -0
  355. package/dist/web-reply-files.js.map +1 -0
  356. package/dist/web-schedules.d.ts +12 -0
  357. package/dist/web-schedules.js +34 -0
  358. package/dist/web-schedules.js.map +1 -0
  359. package/dist/web-server-drain.d.ts +10 -0
  360. package/dist/web-server-drain.js +50 -0
  361. package/dist/web-server-drain.js.map +1 -0
  362. package/dist/web-session.d.ts +36 -1
  363. package/dist/web-session.js +53 -6
  364. package/dist/web-session.js.map +1 -1
  365. package/dist/web-settings-patch.d.ts +23 -0
  366. package/dist/web-settings-patch.js +77 -0
  367. package/dist/web-settings-patch.js.map +1 -0
  368. package/dist/web-shell-routes.d.ts +5 -1
  369. package/dist/web-shell-routes.js +10 -1
  370. package/dist/web-shell-routes.js.map +1 -1
  371. package/dist/web-upload.d.ts +17 -4
  372. package/dist/web-upload.js +64 -13
  373. package/dist/web-upload.js.map +1 -1
  374. package/dist/workflow-templates/default.md +1 -1
  375. package/package.json +1 -1
  376. package/templates/launchd.plist.ejs +3 -1
  377. 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"];
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);
@@ -188,6 +190,18 @@ export function createStream(opts) {
188
190
  const es = sse = new env.EventSource("/ui/events");
189
191
  let spoke = false;
190
192
  silentTimer = env.setTimeout(startPolling, 15000); // the server sends a status frame the moment a stream opens
193
+ es.addEventListener("shutdown", (e) => {
194
+ if (es !== sse || closed || suspended || ended) return;
195
+ let data;
196
+ try { data = JSON.parse(e.data); } catch { return; }
197
+ if (data?.retry_ms !== RECONNECT.shutdownMs) return;
198
+ shutdownUntil = now() + RECONNECT.shutdownMs + Math.round(random() * 5000);
199
+ cancelWork(); closeStream(); stopPolling();
200
+ env.clearTimeout(reconnectTimer); reconnectTimer = null; waitingVisible = false;
201
+ attempts = Math.max(attempts, 4);
202
+ setConnection("reconnecting");
203
+ scheduleStep(shutdownUntil - now());
204
+ });
191
205
  for (const name of EVENTS) {
192
206
  es.addEventListener(name, (e) => {
193
207
  if (es !== sse) return; // a stream this page already let go of
@@ -216,15 +230,16 @@ export function createStream(opts) {
216
230
  else setConnection("reconnecting");
217
231
  scheduleStep();
218
232
  }
219
- function scheduleStep() {
233
+ function scheduleStep(delay) {
220
234
  if (reconnectTimer || closed || suspended || ended) return;
221
- const ms = reconnectDelay(attempts++, random);
235
+ const ms = Math.max(delay ?? reconnectDelay(attempts++, random), shutdownUntil - now());
222
236
  retryAt = now() + ms;
223
237
  emit("retry", { inMs: ms });
224
238
  reconnectTimer = env.setTimeout(() => { reconnectTimer = null; step(); }, ms);
225
239
  }
226
240
  function step() {
227
241
  if (closed || suspended || ended) return;
242
+ if (shutdownUntil > now()) { scheduleStep(shutdownUntil - now()); return; }
228
243
  if (hidden()) { waitingVisible = true; return; } // not while nobody looks: the next step waits to be shown
229
244
  if (opts.transport === "poll") { pollProbe(); return; }
230
245
  openStream(true);
@@ -255,7 +270,7 @@ export function createStream(opts) {
255
270
  * It opens no transport: still the one EventSource, and no polling loop.
256
271
  */
257
272
  function catchUp() {
258
- if (closed || ended) return Promise.resolve(false);
273
+ if (closed || ended || shutdownUntil > now()) return Promise.resolve(false);
259
274
  if (catching) return catching;
260
275
  env.clearTimeout(retryTimer); retryTimer = null;
261
276
  setHydration("catching");
@@ -327,6 +342,9 @@ export function createStream(opts) {
327
342
  if (closed || !suspended || ended) return;
328
343
  suspended = false;
329
344
  epoch++;
345
+ if (shutdownUntil > now()) {
346
+ setConnection("reconnecting"); scheduleStep(shutdownUntil - now()); return;
347
+ }
330
348
  attempts = 0;
331
349
  if (opts.transport === "poll") { startPolling(); return; }
332
350
  openStream(true);