@songsid/agend 2.3.0-beta.9 → 2.3.0

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 (723) hide show
  1. package/README.md +16 -8
  2. package/README.zh-TW.md +16 -8
  3. package/dist/adapter-world.js.map +1 -1
  4. package/dist/agend-home.d.ts +5 -0
  5. package/dist/agend-home.js +7 -0
  6. package/dist/agend-home.js.map +1 -0
  7. package/dist/agent-cli-instructions.md +7 -1
  8. package/dist/agent-cli.js +41 -0
  9. package/dist/agent-cli.js.map +1 -1
  10. package/dist/agent-endpoint.d.ts +9 -0
  11. package/dist/agent-endpoint.js +23 -0
  12. package/dist/agent-endpoint.js.map +1 -1
  13. package/dist/agent-file-read.js +1 -1
  14. package/dist/agent-file-read.js.map +1 -1
  15. package/dist/agent-whats-new.d.ts +16 -0
  16. package/dist/agent-whats-new.js +53 -12
  17. package/dist/agent-whats-new.js.map +1 -1
  18. package/dist/apply-job.js.map +1 -1
  19. package/dist/atomic-write.js.map +1 -1
  20. package/dist/auth-api.d.ts +12 -0
  21. package/dist/auth-api.js +77 -22
  22. package/dist/auth-api.js.map +1 -1
  23. package/dist/authority/authority-state.d.ts +4 -0
  24. package/dist/authority/authority-state.js +17 -8
  25. package/dist/authority/authority-state.js.map +1 -1
  26. package/dist/authority/session-authorizations.js.map +1 -1
  27. package/dist/authority/web-authority.d.ts +16 -8
  28. package/dist/authority/web-authority.js +19 -5
  29. package/dist/authority/web-authority.js.map +1 -1
  30. package/dist/backend/antigravity.d.ts +2 -2
  31. package/dist/backend/antigravity.js +2 -1
  32. package/dist/backend/antigravity.js.map +1 -1
  33. package/dist/backend/claude-code.js +13 -4
  34. package/dist/backend/claude-code.js.map +1 -1
  35. package/dist/backend/codex-metadata.d.ts +8 -0
  36. package/dist/backend/codex-metadata.js +74 -17
  37. package/dist/backend/codex-metadata.js.map +1 -1
  38. package/dist/backend/codex-package.d.ts +30 -0
  39. package/dist/backend/codex-package.js +133 -0
  40. package/dist/backend/codex-package.js.map +1 -0
  41. package/dist/backend/codex-session-lookup.js.map +1 -1
  42. package/dist/backend/codex.d.ts +2 -0
  43. package/dist/backend/codex.js +25 -5
  44. package/dist/backend/codex.js.map +1 -1
  45. package/dist/backend/credential-profile.d.ts +2 -0
  46. package/dist/backend/credential-profile.js +2 -0
  47. package/dist/backend/credential-profile.js.map +1 -1
  48. package/dist/backend/effort-metadata.js.map +1 -1
  49. package/dist/backend/grok.js +58 -3
  50. package/dist/backend/grok.js.map +1 -1
  51. package/dist/backend/kiro-engine-ledger.js.map +1 -1
  52. package/dist/backend/kiro-kas-store.js.map +1 -1
  53. package/dist/backend/kiro-v2-store.js.map +1 -1
  54. package/dist/backend/kiro-v3-identity.js.map +1 -1
  55. package/dist/backend/kiro.d.ts +9 -1
  56. package/dist/backend/kiro.js +102 -1
  57. package/dist/backend/kiro.js.map +1 -1
  58. package/dist/backend/launch-effort.js.map +1 -1
  59. package/dist/backend/mock.js.map +1 -1
  60. package/dist/backend/muse.js.map +1 -1
  61. package/dist/backend/opencode-permission.js +1 -1
  62. package/dist/backend/opencode-permission.js.map +1 -1
  63. package/dist/backend/opencode.js +2 -1
  64. package/dist/backend/opencode.js.map +1 -1
  65. package/dist/backend/session-signals.js.map +1 -1
  66. package/dist/backend-availability.js.map +1 -1
  67. package/dist/backend-command.d.ts +2 -0
  68. package/dist/backend-command.js +3 -1
  69. package/dist/backend-command.js.map +1 -1
  70. package/dist/backend-outage.js.map +1 -1
  71. package/dist/binary-probe.js +1 -1
  72. package/dist/binary-probe.js.map +1 -1
  73. package/dist/bug-report-cli.d.ts +30 -0
  74. package/dist/bug-report-cli.js +139 -0
  75. package/dist/bug-report-cli.js.map +1 -0
  76. package/dist/bug-report.d.ts +47 -0
  77. package/dist/bug-report.js +137 -0
  78. package/dist/bug-report.js.map +1 -0
  79. package/dist/bundled-skills.d.ts +18 -0
  80. package/dist/bundled-skills.js +38 -0
  81. package/dist/bundled-skills.js.map +1 -0
  82. package/dist/cache-service.js +1 -1
  83. package/dist/cache-service.js.map +1 -1
  84. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  85. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  86. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  87. package/dist/channel/adapters/discord.d.ts +4 -0
  88. package/dist/channel/adapters/discord.js +57 -12
  89. package/dist/channel/adapters/discord.js.map +1 -1
  90. package/dist/channel/adapters/telegram.d.ts +6 -0
  91. package/dist/channel/adapters/telegram.js +54 -14
  92. package/dist/channel/adapters/telegram.js.map +1 -1
  93. package/dist/channel/mcp-server.js +21 -4
  94. package/dist/channel/mcp-server.js.map +1 -1
  95. package/dist/channel/mcp-tools.d.ts +3 -1
  96. package/dist/channel/mcp-tools.js +41 -4
  97. package/dist/channel/mcp-tools.js.map +1 -1
  98. package/dist/channel/message-queue.js.map +1 -1
  99. package/dist/channel/sticker-download.js.map +1 -1
  100. package/dist/channel/tool-router.js.map +1 -1
  101. package/dist/child-process.d.ts +21 -0
  102. package/dist/child-process.js +54 -0
  103. package/dist/child-process.js.map +1 -0
  104. package/dist/classic-channel-manager.js +3 -2
  105. package/dist/classic-channel-manager.js.map +1 -1
  106. package/dist/cli-entry.js.map +1 -1
  107. package/dist/cli-flags.js.map +1 -1
  108. package/dist/cli.d.ts +1 -0
  109. package/dist/cli.js +443 -311
  110. package/dist/cli.js.map +1 -1
  111. package/dist/command-table.d.ts +1 -1
  112. package/dist/command-table.js +1 -1
  113. package/dist/command-table.js.map +1 -1
  114. package/dist/compact-watch.js.map +1 -1
  115. package/dist/completion-install.js.map +1 -1
  116. package/dist/completion.js.map +1 -1
  117. package/dist/config-validator.d.ts +6 -0
  118. package/dist/config-validator.js +81 -8
  119. package/dist/config-validator.js.map +1 -1
  120. package/dist/config.d.ts +15 -3
  121. package/dist/config.js +41 -10
  122. package/dist/config.js.map +1 -1
  123. package/dist/connection-secrets.js.map +1 -1
  124. package/dist/context-guardian.js.map +1 -1
  125. package/dist/coredump-filter.js.map +1 -1
  126. package/dist/cpu-profile.js.map +1 -1
  127. package/dist/cross-instance-envelope.js.map +1 -1
  128. package/dist/cross-instance-notice.d.ts +7 -0
  129. package/dist/cross-instance-notice.js +10 -0
  130. package/dist/cross-instance-notice.js.map +1 -1
  131. package/dist/daemon.d.ts +39 -1
  132. package/dist/daemon.js +234 -15
  133. package/dist/daemon.js.map +1 -1
  134. package/dist/daily-summary.js.map +1 -1
  135. package/dist/darwin-memory.js +1 -1
  136. package/dist/darwin-memory.js.map +1 -1
  137. package/dist/dashboard-live.d.ts +8 -0
  138. package/dist/dashboard-live.js +35 -0
  139. package/dist/dashboard-live.js.map +1 -0
  140. package/dist/dashboard-permissions.d.ts +69 -0
  141. package/dist/dashboard-permissions.js +138 -0
  142. package/dist/dashboard-permissions.js.map +1 -0
  143. package/dist/decision-list.js.map +1 -1
  144. package/dist/delivery-consumed-watch.js.map +1 -1
  145. package/dist/delivery-outbox.js +5 -0
  146. package/dist/delivery-outbox.js.map +1 -1
  147. package/dist/delivery-outbox.test.js.map +1 -1
  148. package/dist/delivery-reconciliation.test.js.map +1 -1
  149. package/dist/diagnostic-redaction.d.ts +10 -0
  150. package/dist/diagnostic-redaction.js +167 -0
  151. package/dist/diagnostic-redaction.js.map +1 -0
  152. package/dist/doctor.d.ts +8 -0
  153. package/dist/doctor.js +52 -0
  154. package/dist/doctor.js.map +1 -1
  155. package/dist/e2e-isolation.js.map +1 -1
  156. package/dist/event-log.js.map +1 -1
  157. package/dist/export-import.js +7 -5
  158. package/dist/export-import.js.map +1 -1
  159. package/dist/fleet-control-audit.js.map +1 -1
  160. package/dist/fleet-label.js.map +1 -1
  161. package/dist/fleet-level-config.d.ts +1 -1
  162. package/dist/fleet-level-config.js +2 -0
  163. package/dist/fleet-level-config.js.map +1 -1
  164. package/dist/fleet-lock.js +3 -2
  165. package/dist/fleet-lock.js.map +1 -1
  166. package/dist/fleet-manager.d.ts +249 -13
  167. package/dist/fleet-manager.js +1561 -292
  168. package/dist/fleet-manager.js.map +1 -1
  169. package/dist/fleet-process-handlers.d.ts +18 -0
  170. package/dist/fleet-process-handlers.js +70 -0
  171. package/dist/fleet-process-handlers.js.map +1 -0
  172. package/dist/fleet-startup.d.ts +14 -0
  173. package/dist/fleet-startup.js +30 -0
  174. package/dist/fleet-startup.js.map +1 -0
  175. package/dist/fleet-traffic.js.map +1 -1
  176. package/dist/forged-envelope-scan.d.ts +0 -20
  177. package/dist/forged-envelope-scan.js +3 -2
  178. package/dist/forged-envelope-scan.js.map +1 -1
  179. package/dist/full-restart.d.ts +5 -5
  180. package/dist/full-restart.js +5 -5
  181. package/dist/full-restart.js.map +1 -1
  182. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  183. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  184. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  185. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  186. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  187. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  188. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  189. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  190. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  191. package/dist/general-knowledge/skills/web-appearance/SKILL.md +24 -4
  192. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  193. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +154 -31
  194. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  195. package/dist/general-knowledge/steering/core-rules.md +1 -1
  196. package/dist/host-memory.js.map +1 -1
  197. package/dist/idle-gate-log.d.ts +19 -0
  198. package/dist/idle-gate-log.js +15 -0
  199. package/dist/idle-gate-log.js.map +1 -0
  200. package/dist/instance-config-impact.js +25 -4
  201. package/dist/instance-config-impact.js.map +1 -1
  202. package/dist/instance-lifecycle.d.ts +10 -1
  203. package/dist/instance-lifecycle.js +86 -25
  204. package/dist/instance-lifecycle.js.map +1 -1
  205. package/dist/instructions.d.ts +12 -6
  206. package/dist/instructions.js +19 -10
  207. package/dist/instructions.js.map +1 -1
  208. package/dist/kiro-compact-pane.js.map +1 -1
  209. package/dist/kiro-db-reader.js.map +1 -1
  210. package/dist/kiro-engine-status.js.map +1 -1
  211. package/dist/kiro-log-gate.js.map +1 -1
  212. package/dist/kiro-transcript-lane.js.map +1 -1
  213. package/dist/locale.js +428 -20
  214. package/dist/locale.js.map +1 -1
  215. package/dist/log-service.js.map +1 -1
  216. package/dist/log-steps.d.ts +1 -0
  217. package/dist/log-steps.js +15 -0
  218. package/dist/log-steps.js.map +1 -1
  219. package/dist/logger.js +3 -2
  220. package/dist/logger.js.map +1 -1
  221. package/dist/login-controller.d.ts +45 -0
  222. package/dist/login-controller.js +101 -5
  223. package/dist/login-controller.js.map +1 -1
  224. package/dist/login-flows.js +1 -1
  225. package/dist/login-manager.js.map +1 -1
  226. package/dist/login-shell.js +3 -1
  227. package/dist/login-shell.js.map +1 -1
  228. package/dist/ls-attach-resolve.d.ts +96 -0
  229. package/dist/ls-attach-resolve.js +180 -0
  230. package/dist/ls-attach-resolve.js.map +1 -0
  231. package/dist/ls-rows.d.ts +12 -0
  232. package/dist/ls-rows.js +83 -4
  233. package/dist/ls-rows.js.map +1 -1
  234. package/dist/memory-pressure.js.map +1 -1
  235. package/dist/muse-usage-relay.js.map +1 -1
  236. package/dist/needs-you-hub.d.ts +98 -1
  237. package/dist/needs-you-hub.js +313 -44
  238. package/dist/needs-you-hub.js.map +1 -1
  239. package/dist/needs-you-live.d.ts +5 -2
  240. package/dist/needs-you-live.js +6 -3
  241. package/dist/needs-you-live.js.map +1 -1
  242. package/dist/needs-you.d.ts +68 -3
  243. package/dist/needs-you.js +38 -4
  244. package/dist/needs-you.js.map +1 -1
  245. package/dist/network-family.js.map +1 -1
  246. package/dist/operator-control-paths.js +3 -4
  247. package/dist/operator-control-paths.js.map +1 -1
  248. package/dist/outbound-handlers.d.ts +3 -0
  249. package/dist/outbound-handlers.js +76 -19
  250. package/dist/outbound-handlers.js.map +1 -1
  251. package/dist/outbound-schemas.d.ts +106 -60
  252. package/dist/outbound-schemas.js +33 -10
  253. package/dist/outbound-schemas.js.map +1 -1
  254. package/dist/outbox-open-error.js.map +1 -1
  255. package/dist/pane-context-cache.js.map +1 -1
  256. package/dist/paths.js.map +1 -1
  257. package/dist/private-dir.js.map +1 -1
  258. package/dist/probe-worker-pool.js.map +1 -1
  259. package/dist/profile-control.js.map +1 -1
  260. package/dist/prompt-file-ref.js.map +1 -1
  261. package/dist/provider-probe.js.map +1 -1
  262. package/dist/provider-secret-registry.d.ts +5 -3
  263. package/dist/provider-secret-registry.js +8 -2
  264. package/dist/provider-secret-registry.js.map +1 -1
  265. package/dist/public-link-auto-open.d.ts +32 -0
  266. package/dist/public-link-auto-open.js +86 -0
  267. package/dist/public-link-auto-open.js.map +1 -0
  268. package/dist/public-link-owner.d.ts +10 -0
  269. package/dist/public-link-owner.js +36 -0
  270. package/dist/public-link-owner.js.map +1 -0
  271. package/dist/public-link-progress.d.ts +12 -1
  272. package/dist/public-link-progress.js +5 -10
  273. package/dist/public-link-progress.js.map +1 -1
  274. package/dist/public-preview.js.map +1 -1
  275. package/dist/public-tunnel-config.d.ts +11 -0
  276. package/dist/public-tunnel-config.js +68 -0
  277. package/dist/public-tunnel-config.js.map +1 -0
  278. package/dist/public-web-gateway.d.ts +2 -0
  279. package/dist/public-web-gateway.js +19 -6
  280. package/dist/public-web-gateway.js.map +1 -1
  281. package/dist/public-web-link.d.ts +48 -3
  282. package/dist/public-web-link.js +177 -51
  283. package/dist/public-web-link.js.map +1 -1
  284. package/dist/quickstart-api.d.ts +9 -0
  285. package/dist/quickstart-api.js +82 -0
  286. package/dist/quickstart-api.js.map +1 -1
  287. package/dist/quickstart.d.ts +5 -0
  288. package/dist/quickstart.js +40 -25
  289. package/dist/quickstart.js.map +1 -1
  290. package/dist/reply-buttons-controller.js.map +1 -1
  291. package/dist/reply-dedup.js.map +1 -1
  292. package/dist/resource-report.js +1 -1
  293. package/dist/resource-report.js.map +1 -1
  294. package/dist/restart-guard.js.map +1 -1
  295. package/dist/restart-progress.d.ts +80 -1
  296. package/dist/restart-progress.js +306 -21
  297. package/dist/restart-progress.js.map +1 -1
  298. package/dist/rollout-index.js.map +1 -1
  299. package/dist/runtime-cpu-profile.js.map +1 -1
  300. package/dist/scheduler/db.d.ts +40 -13
  301. package/dist/scheduler/db.js +123 -89
  302. package/dist/scheduler/db.js.map +1 -1
  303. package/dist/scheduler/scheduler.js.map +1 -1
  304. package/dist/scheduler/task-board-text.d.ts +26 -0
  305. package/dist/scheduler/task-board-text.js +140 -0
  306. package/dist/scheduler/task-board-text.js.map +1 -0
  307. package/dist/scheduler/task-board.d.ts +730 -0
  308. package/dist/scheduler/task-board.js +2179 -0
  309. package/dist/scheduler/task-board.js.map +1 -0
  310. package/dist/scheduler/types.d.ts +6 -1
  311. package/dist/sd-notify.js +2 -1
  312. package/dist/sd-notify.js.map +1 -1
  313. package/dist/search/search-docs.d.ts +58 -0
  314. package/dist/search/search-docs.js +63 -0
  315. package/dist/search/search-docs.js.map +1 -0
  316. package/dist/search/search-index.d.ts +141 -0
  317. package/dist/search/search-index.js +440 -0
  318. package/dist/search/search-index.js.map +1 -0
  319. package/dist/search/search-store.d.ts +122 -0
  320. package/dist/search/search-store.js +236 -0
  321. package/dist/search/search-store.js.map +1 -0
  322. package/dist/search/search-worker.d.ts +1 -0
  323. package/dist/search/search-worker.js +163 -0
  324. package/dist/search/search-worker.js.map +1 -0
  325. package/dist/secret-file.js.map +1 -1
  326. package/dist/secret-store.d.ts +2 -0
  327. package/dist/secret-store.js +21 -0
  328. package/dist/secret-store.js.map +1 -1
  329. package/dist/service-installer.d.ts +75 -0
  330. package/dist/service-installer.js +206 -0
  331. package/dist/service-installer.js.map +1 -1
  332. package/dist/service-owner.d.ts +44 -0
  333. package/dist/service-owner.js +48 -0
  334. package/dist/service-owner.js.map +1 -0
  335. package/dist/service-plan.d.ts +39 -2
  336. package/dist/service-plan.js +188 -6
  337. package/dist/service-plan.js.map +1 -1
  338. package/dist/session-oom.d.ts +21 -0
  339. package/dist/session-oom.js +139 -0
  340. package/dist/session-oom.js.map +1 -0
  341. package/dist/settings-api.d.ts +13 -0
  342. package/dist/settings-api.js +73 -12
  343. package/dist/settings-api.js.map +1 -1
  344. package/dist/settings-baseline.js.map +1 -1
  345. package/dist/settings-change.d.ts +5 -0
  346. package/dist/settings-change.js +167 -6
  347. package/dist/settings-change.js.map +1 -1
  348. package/dist/settings-confirmation.d.ts +9 -1
  349. package/dist/settings-confirmation.js +18 -8
  350. package/dist/settings-confirmation.js.map +1 -1
  351. package/dist/settings-control.js +2 -1
  352. package/dist/settings-control.js.map +1 -1
  353. package/dist/settings-effect.js +29 -4
  354. package/dist/settings-effect.js.map +1 -1
  355. package/dist/settings-http-confirmation.d.ts +13 -0
  356. package/dist/settings-http-confirmation.js +15 -3
  357. package/dist/settings-http-confirmation.js.map +1 -1
  358. package/dist/settings-instance-patch.js +13 -1
  359. package/dist/settings-instance-patch.js.map +1 -1
  360. package/dist/settings-request-capability.d.ts +4 -1
  361. package/dist/settings-request-capability.js +11 -3
  362. package/dist/settings-request-capability.js.map +1 -1
  363. package/dist/settings-transaction.js.map +1 -1
  364. package/dist/setup-auth.d.ts +1 -0
  365. package/dist/setup-auth.js +2 -1
  366. package/dist/setup-auth.js.map +1 -1
  367. package/dist/setup-form.d.ts +1 -1
  368. package/dist/setup-form.js +23 -7
  369. package/dist/setup-form.js.map +1 -1
  370. package/dist/setup-host.d.ts +6 -1
  371. package/dist/setup-host.js +15 -4
  372. package/dist/setup-host.js.map +1 -1
  373. package/dist/setup-wizard.js +6 -3
  374. package/dist/setup-wizard.js.map +1 -1
  375. package/dist/spawn-gate.d.ts +5 -0
  376. package/dist/spawn-gate.js +28 -8
  377. package/dist/spawn-gate.js.map +1 -1
  378. package/dist/start-attempt.d.ts +1 -0
  379. package/dist/start-attempt.js +18 -0
  380. package/dist/start-attempt.js.map +1 -0
  381. package/dist/start-failure-notice.d.ts +4 -0
  382. package/dist/start-failure-notice.js +20 -0
  383. package/dist/start-failure-notice.js.map +1 -0
  384. package/dist/start-failure.d.ts +147 -0
  385. package/dist/start-failure.js +281 -0
  386. package/dist/start-failure.js.map +1 -0
  387. package/dist/startup-memory-deadline.d.ts +23 -0
  388. package/dist/startup-memory-deadline.js +55 -0
  389. package/dist/startup-memory-deadline.js.map +1 -0
  390. package/dist/statusline-watcher.js.map +1 -1
  391. package/dist/storm-window.js.map +1 -1
  392. package/dist/systemd-peer-bus.js.map +1 -1
  393. package/dist/target-queue-worker.js.map +1 -1
  394. package/dist/task-board-summary.d.ts +101 -0
  395. package/dist/task-board-summary.js +177 -0
  396. package/dist/task-board-summary.js.map +1 -0
  397. package/dist/task-board-tool.d.ts +25 -0
  398. package/dist/task-board-tool.js +155 -0
  399. package/dist/task-board-tool.js.map +1 -0
  400. package/dist/task-board-waker.d.ts +51 -0
  401. package/dist/task-board-waker.js +141 -0
  402. package/dist/task-board-waker.js.map +1 -0
  403. package/dist/tips.js.map +1 -1
  404. package/dist/tmux-control.js +1 -1
  405. package/dist/tmux-control.js.map +1 -1
  406. package/dist/tmux-exec-helper.d.ts +104 -0
  407. package/dist/tmux-exec-helper.js +412 -0
  408. package/dist/tmux-exec-helper.js.map +1 -0
  409. package/dist/tmux-manager.d.ts +1 -0
  410. package/dist/tmux-manager.js +29 -13
  411. package/dist/tmux-manager.js.map +1 -1
  412. package/dist/tmux-read.js +2 -2
  413. package/dist/tmux-read.js.map +1 -1
  414. package/dist/tool-permissions.js.map +1 -1
  415. package/dist/tool-progress.js.map +1 -1
  416. package/dist/topic-archiver.js.map +1 -1
  417. package/dist/topic-commands.d.ts +13 -0
  418. package/dist/topic-commands.js +56 -33
  419. package/dist/topic-commands.js.map +1 -1
  420. package/dist/topic-link.js.map +1 -1
  421. package/dist/transcript-delta-reader.js.map +1 -1
  422. package/dist/transcript-jsonl.js.map +1 -1
  423. package/dist/transcript-monitor.js +5 -0
  424. package/dist/transcript-monitor.js.map +1 -1
  425. package/dist/transcript-sources.d.ts +2 -0
  426. package/dist/transcript-sources.js +4 -0
  427. package/dist/transcript-sources.js.map +1 -1
  428. package/dist/tunnel/cloudflared-install.js +3 -1
  429. package/dist/tunnel/cloudflared-install.js.map +1 -1
  430. package/dist/tunnel/cloudflared.d.ts +7 -16
  431. package/dist/tunnel/cloudflared.js +100 -13
  432. package/dist/tunnel/cloudflared.js.map +1 -1
  433. package/dist/tunnel/lease.js +3 -2
  434. package/dist/tunnel/lease.js.map +1 -1
  435. package/dist/tunnel/manager.js.map +1 -1
  436. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  437. package/dist/tunnel/named-diagnostics.js +52 -0
  438. package/dist/tunnel/named-diagnostics.js.map +1 -0
  439. package/dist/tunnel/public-fetch.js.map +1 -1
  440. package/dist/tunnel/purpose-lane.js.map +1 -1
  441. package/dist/tunnel/types.d.ts +4 -1
  442. package/dist/tunnel/types.js.map +1 -1
  443. package/dist/types.d.ts +55 -2
  444. package/dist/ui/app-effects.js +23 -5
  445. package/dist/ui/app.html +2 -0
  446. package/dist/ui/backend-signin.js +297 -0
  447. package/dist/ui/chat-effects.js +10 -3
  448. package/dist/ui/chat-msg-actions.js +176 -0
  449. package/dist/ui/chat-render.js +62 -18
  450. package/dist/ui/chat-store.js +218 -48
  451. package/dist/ui/chat-strings.js +40 -8
  452. package/dist/ui/chat-thread.js +119 -10
  453. package/dist/ui/effect-trial-offer.js +2 -31
  454. package/dist/ui/effects-waker.js +2 -0
  455. package/dist/ui/fleet-canvas-layout.js +13 -4
  456. package/dist/ui/fleet-canvas.js +69 -28
  457. package/dist/ui/fleet-office-editor.js +149 -0
  458. package/dist/ui/fleet-office-model.js +358 -0
  459. package/dist/ui/fleet-office-pack.js +199 -0
  460. package/dist/ui/fleet-office-skin.js +474 -0
  461. package/dist/ui/fleet-office-store.js +49 -0
  462. package/dist/ui/fleet-office-zones.js +177 -0
  463. package/dist/ui/fleet-office.js +434 -0
  464. package/dist/ui/fleet-org.js +18 -5
  465. package/dist/ui/fleet-route-scene.js +272 -0
  466. package/dist/ui/fleet-route-worker.js +21 -0
  467. package/dist/ui/fleet-route.js +88 -0
  468. package/dist/ui/fleet-task-card.js +436 -0
  469. package/dist/ui/fleet-task-common.js +482 -0
  470. package/dist/ui/fleet-task-work.js +107 -0
  471. package/dist/ui/fleet-tasks.js +569 -0
  472. package/dist/ui/fleet-traffic.js +81 -18
  473. package/dist/ui/fleet-usage.js +36 -2
  474. package/dist/ui/guest-refused.html +41 -0
  475. package/dist/ui/icons/icon-192.png +0 -0
  476. package/dist/ui/icons/icon-512.png +0 -0
  477. package/dist/ui/image-lightbox.js +45 -1
  478. package/dist/ui/image-zoom.js +242 -0
  479. package/dist/ui/panel-chat.js +200 -56
  480. package/dist/ui/panel-details.js +2 -0
  481. package/dist/ui/panel-fleet.js +32 -71
  482. package/dist/ui/panel-needs.js +23 -6
  483. package/dist/ui/panel-settings.js +158 -32
  484. package/dist/ui/preview-panel.js +2 -1
  485. package/dist/ui/search-dialog.js +350 -0
  486. package/dist/ui/settings-appearance.js +170 -10
  487. package/dist/ui/settings-apply.js +3 -3
  488. package/dist/ui/settings-confirm.js +7 -2
  489. package/dist/ui/settings-dialogs.js +46 -21
  490. package/dist/ui/settings-discord.js +6 -2
  491. package/dist/ui/settings-guests.js +2 -1
  492. package/dist/ui/settings-learn.js +1 -0
  493. package/dist/ui/settings-model.js +51 -18
  494. package/dist/ui/settings-mods.js +8 -3
  495. package/dist/ui/settings-owner-effects.js +6 -4
  496. package/dist/ui/settings-strings.js +180 -6
  497. package/dist/ui/settings-token.js +3 -1
  498. package/dist/ui/settings-web-authority.js +13 -5
  499. package/dist/ui/settings-wizard.js +13 -7
  500. package/dist/ui/shared/agend-auth.js +2 -0
  501. package/dist/ui/shared/app-i18n.js +12 -5
  502. package/dist/ui/shared/app-needs.js +2 -2
  503. package/dist/ui/shared/app-prefs.js +15 -0
  504. package/dist/ui/shared/app-route.js +18 -0
  505. package/dist/ui/shared/app-shell.js +172 -28
  506. package/dist/ui/shared/app-store.js +3 -2
  507. package/dist/ui/shared/app-stream.js +5 -1
  508. package/dist/ui/shared/app-themes.js +116 -1
  509. package/dist/ui/shared/app.css +662 -48
  510. package/dist/ui/shared/app.js +9 -1
  511. package/dist/ui/shared/card-strings.js +4 -0
  512. package/dist/ui/shared/effect-app-runtime.js +7 -5
  513. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  514. package/dist/ui/shared/effect-cursor.js +3 -2
  515. package/dist/ui/shared/effect-display-metadata.js +39 -0
  516. package/dist/ui/shared/effect-owner-source.js +8 -1
  517. package/dist/ui/shared/effect-registry.js +14 -4
  518. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  519. package/dist/ui/shared/effect-stock-trust.js +5 -5
  520. package/dist/ui/shared/feature-flags.js +127 -0
  521. package/dist/ui/shared/guest-refused.js +35 -0
  522. package/dist/ui/shared/header-tools.js +2 -2
  523. package/dist/ui/shared/identity-card.js +26 -8
  524. package/dist/ui/shared/identity-color.js +17 -10
  525. package/dist/ui/shared/instance-nav.js +183 -28
  526. package/dist/ui/shared/owner-css.js +30 -1
  527. package/dist/ui/shared/panel-view.js +14 -29
  528. package/dist/ui/shared/text-undo.js +210 -0
  529. package/dist/ui/shared/tokens.css +4 -0
  530. package/dist/ui/shared/ui-dialog.js +5 -4
  531. package/dist/ui/shared/ui-icons.js +4 -0
  532. package/dist/ui/shared/ui-menu.js +20 -7
  533. package/dist/ui/shared/ui-toast.js +16 -3
  534. package/dist/ui/shared/usage-dialog.js +206 -16
  535. package/dist/ui/shared/view-strings.js +68 -4
  536. package/dist/ui/shared/web-authorize.js +50 -1
  537. package/dist/ui/signin.html +2 -0
  538. package/dist/ui/web-terminal/terminal.html +10 -10
  539. package/dist/ui/web-terminal/terminal.js +58 -12
  540. package/dist/update-check.js.map +1 -1
  541. package/dist/update-dispatch.js +1 -1
  542. package/dist/update-dispatch.js.map +1 -1
  543. package/dist/update-install.js.map +1 -1
  544. package/dist/update-launch.d.ts +10 -1
  545. package/dist/update-launch.js +39 -14
  546. package/dist/update-launch.js.map +1 -1
  547. package/dist/update-marker.js.map +1 -1
  548. package/dist/update-preflight.js +1 -1
  549. package/dist/update-preflight.js.map +1 -1
  550. package/dist/update-progress.d.ts +3 -1
  551. package/dist/update-progress.js +3 -1
  552. package/dist/update-progress.js.map +1 -1
  553. package/dist/usage/format-rich.js +6 -3
  554. package/dist/usage/format-rich.js.map +1 -1
  555. package/dist/usage/i18n-keys.d.ts +1 -1
  556. package/dist/usage/i18n-keys.js +2 -1
  557. package/dist/usage/i18n-keys.js.map +1 -1
  558. package/dist/usage/i18n.d.ts +13 -1
  559. package/dist/usage/i18n.js +29 -0
  560. package/dist/usage/i18n.js.map +1 -1
  561. package/dist/usage/providers.d.ts +89 -2
  562. package/dist/usage/providers.js +247 -41
  563. package/dist/usage/providers.js.map +1 -1
  564. package/dist/usage/statusline-usage.js.map +1 -1
  565. package/dist/usage/usage-api.d.ts +5 -1
  566. package/dist/usage/usage-api.js +185 -58
  567. package/dist/usage/usage-api.js.map +1 -1
  568. package/dist/usage-report.js.map +1 -1
  569. package/dist/usage-rollup.js +1 -1
  570. package/dist/usage-rollup.js.map +1 -1
  571. package/dist/user-systemd.d.ts +24 -0
  572. package/dist/user-systemd.js +75 -0
  573. package/dist/user-systemd.js.map +1 -0
  574. package/dist/view-api.d.ts +7 -0
  575. package/dist/view-api.js +16 -4
  576. package/dist/view-api.js.map +1 -1
  577. package/dist/wake-coordinator.js.map +1 -1
  578. package/dist/web-ambient.js.map +1 -1
  579. package/dist/web-api.d.ts +57 -10
  580. package/dist/web-api.js +1103 -70
  581. package/dist/web-api.js.map +1 -1
  582. package/dist/web-app-icon-worker.d.ts +1 -0
  583. package/dist/web-app-icon-worker.js +16 -0
  584. package/dist/web-app-icon-worker.js.map +1 -0
  585. package/dist/web-app-icon.d.ts +109 -0
  586. package/dist/web-app-icon.js +257 -0
  587. package/dist/web-app-icon.js.map +1 -0
  588. package/dist/web-appearance-policy.js.map +1 -1
  589. package/dist/web-appearance-tools.d.ts +1 -0
  590. package/dist/web-appearance-tools.js +7 -3
  591. package/dist/web-appearance-tools.js.map +1 -1
  592. package/dist/web-appearance-view.js.map +1 -1
  593. package/dist/web-appearance.d.ts +4 -10
  594. package/dist/web-appearance.js +7 -4
  595. package/dist/web-appearance.js.map +1 -1
  596. package/dist/web-auth.d.ts +8 -4
  597. package/dist/web-auth.js +33 -21
  598. package/dist/web-auth.js.map +1 -1
  599. package/dist/web-backend-login.d.ts +130 -0
  600. package/dist/web-backend-login.js +225 -0
  601. package/dist/web-backend-login.js.map +1 -0
  602. package/dist/web-card.js.map +1 -1
  603. package/dist/web-channel-echo.js.map +1 -1
  604. package/dist/web-chat-history.d.ts +118 -8
  605. package/dist/web-chat-history.js +220 -25
  606. package/dist/web-chat-history.js.map +1 -1
  607. package/dist/web-commands.d.ts +5 -1
  608. package/dist/web-commands.js +1 -1
  609. package/dist/web-commands.js.map +1 -1
  610. package/dist/web-cookie-names.d.ts +5 -0
  611. package/dist/web-cookie-names.js +12 -0
  612. package/dist/web-cookie-names.js.map +1 -0
  613. package/dist/web-effect-bundle.d.ts +2 -2
  614. package/dist/web-effect-library.js.map +1 -1
  615. package/dist/web-effect-playback.js.map +1 -1
  616. package/dist/web-effect-profiles.d.ts +16 -16
  617. package/dist/web-effect-profiles.js +3 -2
  618. package/dist/web-effect-profiles.js.map +1 -1
  619. package/dist/web-effect-service.js.map +1 -1
  620. package/dist/web-effect-tools.js.map +1 -1
  621. package/dist/web-effect-trials.js.map +1 -1
  622. package/dist/web-effect-upload.js.map +1 -1
  623. package/dist/web-effect.d.ts +6 -6
  624. package/dist/web-effect.js.map +1 -1
  625. package/dist/web-experimental-http.d.ts +2 -0
  626. package/dist/web-experimental-http.js +12 -0
  627. package/dist/web-experimental-http.js.map +1 -0
  628. package/dist/web-experimental.d.ts +11 -0
  629. package/dist/web-experimental.js +49 -0
  630. package/dist/web-experimental.js.map +1 -0
  631. package/dist/web-guest-access.d.ts +4 -2
  632. package/dist/web-guest-access.js +22 -10
  633. package/dist/web-guest-access.js.map +1 -1
  634. package/dist/web-guest-rooms.js.map +1 -1
  635. package/dist/web-host-guard.d.ts +11 -0
  636. package/dist/web-host-guard.js +11 -0
  637. package/dist/web-host-guard.js.map +1 -1
  638. package/dist/web-icons.d.ts +33 -1
  639. package/dist/web-icons.js +83 -11
  640. package/dist/web-icons.js.map +1 -1
  641. package/dist/web-identity-color.js.map +1 -1
  642. package/dist/web-image-meta.d.ts +13 -0
  643. package/dist/web-image-meta.js +62 -0
  644. package/dist/web-image-meta.js.map +1 -1
  645. package/dist/web-images.js.map +1 -1
  646. package/dist/web-libavoid.d.ts +14 -0
  647. package/dist/web-libavoid.js +46 -0
  648. package/dist/web-libavoid.js.map +1 -0
  649. package/dist/web-login.js.map +1 -1
  650. package/dist/web-mentions.js.map +1 -1
  651. package/dist/web-mod-agent.js.map +1 -1
  652. package/dist/web-mod-store.d.ts +2 -0
  653. package/dist/web-mod-store.js +10 -0
  654. package/dist/web-mod-store.js.map +1 -1
  655. package/dist/web-office-store.d.ts +104 -0
  656. package/dist/web-office-store.js +236 -0
  657. package/dist/web-office-store.js.map +1 -0
  658. package/dist/web-owner-css-store.d.ts +44 -1
  659. package/dist/web-owner-css-store.js +70 -9
  660. package/dist/web-owner-css-store.js.map +1 -1
  661. package/dist/web-owner-css.js.map +1 -1
  662. package/dist/web-png.d.ts +33 -0
  663. package/dist/web-png.js +329 -0
  664. package/dist/web-png.js.map +1 -0
  665. package/dist/web-prefs.d.ts +6 -0
  666. package/dist/web-prefs.js +29 -3
  667. package/dist/web-prefs.js.map +1 -1
  668. package/dist/web-preview.d.ts +2 -0
  669. package/dist/web-preview.js +2 -0
  670. package/dist/web-preview.js.map +1 -1
  671. package/dist/web-profile.js.map +1 -1
  672. package/dist/web-reactions.d.ts +35 -0
  673. package/dist/web-reactions.js +47 -0
  674. package/dist/web-reactions.js.map +1 -0
  675. package/dist/web-request-context.d.ts +5 -0
  676. package/dist/web-request-context.js.map +1 -1
  677. package/dist/web-returning-device.d.ts +4 -2
  678. package/dist/web-returning-device.js +13 -6
  679. package/dist/web-returning-device.js.map +1 -1
  680. package/dist/web-schedules.js.map +1 -1
  681. package/dist/web-send-dedupe.d.ts +36 -0
  682. package/dist/web-send-dedupe.js +69 -0
  683. package/dist/web-send-dedupe.js.map +1 -0
  684. package/dist/web-session-authorization.js.map +1 -1
  685. package/dist/web-session.js +1 -1
  686. package/dist/web-session.js.map +1 -1
  687. package/dist/web-settings-patch.d.ts +3 -1
  688. package/dist/web-settings-patch.js +11 -5
  689. package/dist/web-settings-patch.js.map +1 -1
  690. package/dist/web-settings-tools.d.ts +6 -0
  691. package/dist/web-settings-tools.js +52 -17
  692. package/dist/web-settings-tools.js.map +1 -1
  693. package/dist/web-terminal-http.js +15 -2
  694. package/dist/web-terminal-http.js.map +1 -1
  695. package/dist/web-terminal.js +1 -1
  696. package/dist/web-terminal.js.map +1 -1
  697. package/dist/web-theme-store.d.ts +2 -2
  698. package/dist/web-theme-store.js +6 -3
  699. package/dist/web-theme-store.js.map +1 -1
  700. package/dist/web-theme.d.ts +29 -0
  701. package/dist/web-theme.js +89 -1
  702. package/dist/web-theme.js.map +1 -1
  703. package/dist/web-upload.d.ts +18 -1
  704. package/dist/web-upload.js +45 -7
  705. package/dist/web-upload.js.map +1 -1
  706. package/dist/web-widget.js.map +1 -1
  707. package/dist/webhook-emitter.js.map +1 -1
  708. package/dist/windows-shortcuts.d.ts +78 -0
  709. package/dist/windows-shortcuts.js +203 -0
  710. package/dist/windows-shortcuts.js.map +1 -0
  711. package/dist/workflow-templates/default.md +3 -0
  712. package/dist/ws-server.js.map +1 -1
  713. package/dist/yaml-shared-nodes.d.ts +25 -0
  714. package/dist/yaml-shared-nodes.js +185 -0
  715. package/dist/yaml-shared-nodes.js.map +1 -0
  716. package/launcher/agend-install.cjs +828 -0
  717. package/launcher/install-admission.cjs +4 -39
  718. package/launcher/postinstall.cjs +14 -12
  719. package/launcher/private-home.cjs +43 -0
  720. package/package.json +16 -13
  721. package/scripts/preinstall-guard.cjs +2 -5
  722. package/templates/windows-shortcuts.ps1 +181 -0
  723. package/launcher/old-updater-note.cjs +0 -48
@@ -8,10 +8,10 @@
8
8
  // that apply to its state are offered (#1408 rough edges 4 and 7).
9
9
  import { html, useCallback, useEffect, useLayoutEffect, useRef, useState } from "/assets/app-html.js";
10
10
  import { lang, t } from "/assets/app-i18n.js";
11
- import { appStore, guestPage, useStore } from "/assets/app-store.js";
12
- import { AuthorizeChip } from "/assets/web-authorize.js";
11
+ import { appStore, createStore, guestPage, useStore } from "/assets/app-store.js";
12
+ import { ComposerAuth } from "/assets/web-authorize.js";
13
13
  import { useLease } from "/assets/app-ctx.js";
14
- import { modelText, namesOf, namesStore } from "/assets/instance-nav.js";
14
+ import { modelText, namesOf, namesStore, navStore as instanceNavStore } from "/assets/instance-nav.js";
15
15
  import { PanelHeader, onPanelKey, setTitle, statusClass, statusLabel, openDrawer, requestNewInstance } from "/assets/app-shell.js";
16
16
  import { detailsPath, textLinkSegments } from "/assets/app-route.js";
17
17
  import { InstanceSwitch } from "/assets/instance-switch.js";
@@ -21,33 +21,53 @@ import { Menu } from "/assets/ui-menu.js";
21
21
  import { Dialog } from "/assets/ui-dialog.js";
22
22
  import { Empty, Skeleton } from "/assets/ui-states.js";
23
23
  import { Icon } from "/assets/ui-icons.js";
24
+ import { recordEdit } from "/assets/text-undo.js";
24
25
  import { toast } from "/assets/ui-toast.js";
25
26
  import { confirmDialog } from "/assets/ui-confirm.js";
26
27
  import { savePref } from "/assets/app-prefs.js";
27
28
  import { applyTheme, clearAmbient, resolvedMode, themeFor, themeImageUrl, themeMenuItems, themesStore } from "/assets/app-themes.js";
28
29
  import { colorMenuItem } from "/assets/identity-color.js";
29
- import { IdentityCard, useCard } from "/assets/identity-card.js";
30
+ import { brokenPictures, cardFoldable, IdentityCard, useCard } from "/assets/identity-card.js";
30
31
  import { AgentWidget, instanceBinds, widgetFor } from "/assets/agent-widget.js";
31
32
 
32
- // #1629 r4 §1: the identity card folded into the chat's header — folded by default; open or not is this device's choice.
33
+ // #1629 r4 §1: the identity card under the chat's header — hidden by default; shown or not is this device's choice.
34
+ // #2217 (the user, 2026-10-19): no row of its own; its picture and bio can be folded away (the banner stays) — this
35
+ // device's choice too, kept the same way. The user (2026-10-20): no control on the card — one card button in the header
36
+ // (a guest's and the public link's header too: they have no ⋯ menu), pressed-looking while the card is shown, opens a
37
+ // small menu of two checkboxes: Show card, and Show picture and bio (disabled while the card is hidden, or when it cannot
38
+ // fold: no banner, or nothing on its row).
33
39
  const CHAT_CARD_KEY = "agend_chat_card";
34
- const chatCardOpen = () => { try { return localStorage.getItem(CHAT_CARD_KEY) === "open"; } catch { return false; } };
40
+ const CHAT_CARD_ROW_KEY = "agend_chat_card_row";
41
+ const readKey = (k, v) => { try { return localStorage.getItem(k) === v; } catch { return false; } };
42
+ const writeKey = (k, v) => { try { if (v) localStorage.setItem(k, v); else localStorage.removeItem(k); } catch { /* this page only */ } };
43
+ /** Shared by the header's Show card and the card itself, so the two never disagree. */
44
+ export const chatCardPrefs = createStore({ open: readKey(CHAT_CARD_KEY, "open"), rowHidden: readKey(CHAT_CARD_ROW_KEY, "hidden") });
45
+ export const setChatCardOpen = (open) => { writeKey(CHAT_CARD_KEY, open ? "open" : null); chatCardPrefs.set((s) => ({ ...s, open })); };
46
+ export const setChatCardRowHidden = (rowHidden) => { writeKey(CHAT_CARD_ROW_KEY, rowHidden ? "hidden" : null); chatCardPrefs.set((s) => ({ ...s, rowHidden })); };
35
47
  function ChatCard({ name, card }) {
36
- const [open, setOpen] = useState(chatCardOpen);
37
- if (!card) return null;
38
- const toggle = () => { const next = !open; setOpen(next); try { if (next) localStorage.setItem(CHAT_CARD_KEY, "open"); else localStorage.removeItem(CHAT_CARD_KEY); } catch { /* this page only */ } };
39
- return html`<div data-trust="card" class=${`chat-card${open ? " open" : ""}`}>
40
- <button type="button" class="chat-card-toggle" aria-expanded=${open ? "true" : "false"} onClick=${toggle}>
41
- <${Icon} name="chevron" size=${14} cls=${open ? "caret" : "caret flipped"} /><span>${t(open ? "card.hide" : "card.show")}</span>
42
- ${!open && card.tagline ? html`<span class="chat-card-peek">${card.tagline.text}</span>` : null}
43
- </button>
44
- ${open ? html`<${IdentityCard} name=${name} card=${card} compact=${true} />` : null}
48
+ const prefs = useStore(chatCardPrefs);
49
+ if (!card || !prefs.open) return null;
50
+ return html`<div data-trust="card" class="chat-card open">
51
+ <${IdentityCard} name=${name} card=${card} compact=${true} rowHidden=${prefs.rowHidden} />
45
52
  </div>`;
46
53
  }
54
+ /** The header's card menu: ☑ Show card, ☑ Show picture and bio. */
55
+ function CardMenu({ card }) {
56
+ const prefs = useStore(chatCardPrefs);
57
+ useStore(brokenPictures); // a banner that failed to load: the card cannot fold, the item greys out
58
+ if (!card) return null;
59
+ const items = [
60
+ { key: "card", checkbox: true, checked: prefs.open, label: t("card.show"), onSelect: () => setChatCardOpen(!prefs.open) },
61
+ { key: "row", checkbox: true, checked: !prefs.rowHidden && cardFoldable(card), disabled: !prefs.open || !cardFoldable(card), label: t("card.showRow"),
62
+ onSelect: () => setChatCardRowHidden(!prefs.rowHidden) },
63
+ ];
64
+ return html`<${Menu} items=${items} label=${t("card.menu")} icon="idcard" cls="chat-card-menu" active=${prefs.open} />`;
65
+ }
47
66
  import "./chat-strings.js";
48
- import { confirmedWrite } from "./settings-confirm.js";
67
+ import { confirmedWrite, selfConfirmed } from "./settings-confirm.js";
49
68
  import { createChatStore } from "./chat-store.js";
50
69
  import { createThread, msgKey } from "./chat-thread.js";
70
+ import { installMessageActions } from "./chat-msg-actions.js";
51
71
  import { createEmojiIndex } from "./chat-emojis.js";
52
72
  import { pollPublicPreview } from "./preview-status.js";
53
73
  import { createMentionIndex } from "./chat-mentions.js";
@@ -55,11 +75,14 @@ import { PreviewPanel, claimPanel, openPanel, panelClaims, panelStore, panelVers
55
75
  import { needsArgument, paletteFor, parseCommandLine } from "./chat-commands.js";
56
76
  import { installTour, refreshTourSpot } from "./chat-tour.js";
57
77
  import { LightboxHost, openLightbox } from "./image-lightbox.js";
58
- import { ChatEffectPosters } from "/ui/js/chat-effect-posters.js";
59
- import { ChatEffects, chatEffectsMenuAvailable } from "./chat-effects.js";
78
+ import { canvasWorkerMenuAvailable, experimentalComponent, useCanvasWorker } from "/assets/feature-flags.js";
79
+ const ChatEffectPosters = experimentalComponent(() => import("./chat-effect-posters.js"), m => m.ChatEffectPosters);
80
+ const ChatEffects = experimentalComponent(() => import("./chat-effects.js"), m => m.ChatEffects);
60
81
  import { setFollowsReducedMotion } from "/assets/fx-motion.js";
61
82
  import { AmbientMotionNote, ChatAmbient, ambientMenuItems } from "./chat-ambient.js";
62
- import { startAppEffects, getAppEffects } from "./app-effects.js";
83
+ import { startEffectsWaker, getAppEffects, wakeEffects, effectsLoaded, onEffectsAwake, chatHasEffects } from "/assets/feature-flags.js";
84
+ /** The composer's textarea (#2342: text put back into it is a step Ctrl+Z goes back from). */
85
+ const composerField = () => (typeof document !== "undefined" ? document.getElementById("msgIn") : null);
63
86
 
64
87
  const R = () => globalThis.AgendChatRender;
65
88
  const P = () => globalThis.AgendPreview;
@@ -99,7 +122,9 @@ export async function setPreviewOptIn(on, commit = (apply) => apply()) {
99
122
  export function boot({ stream, boot: bootData, deps = {} }) {
100
123
  if (store) return store;
101
124
  store = createChatStore({
102
- fetch: (...a) => fetch(...a), toast, announce, t, setTimeout: (fn, ms) => setTimeout(fn, ms), confirm: confirmDialog, ...deps,
125
+ fetch: (...a) => fetch(...a), toast, announce, t, setTimeout: (fn, ms) => setTimeout(fn, ms), confirm: confirmDialog,
126
+ XMLHttpRequest: typeof XMLHttpRequest === "function" ? XMLHttpRequest : undefined, // an upload's progress (chat-store.js)
127
+ ...deps,
103
128
  });
104
129
  emojiIndex = createEmojiIndex((url) => (deps.fetch || fetch)(url, { credentials: "same-origin" }));
105
130
  mentionIndex = createMentionIndex((url) => (deps.fetch || fetch)(url, { credentials: "same-origin" }));
@@ -119,8 +144,9 @@ export function boot({ stream, boot: bootData, deps = {} }) {
119
144
  }
120
145
  // #1604: the preview opt-in and Tour live in Settings → This device now (and on each preview card's menu).
121
146
  installTour();
122
- // #2118: viewing current in-scope Chat effects needs no management or personal-slot authority.
123
- startAppEffects({ store });
147
+ // #2118: viewing current in-scope Chat effects needs no management or personal-slot authority. #2193: the runtime
148
+ // itself loads only when there is something to play (effects-waker.js).
149
+ startEffectsWaker({ store });
124
150
  return store;
125
151
  }
126
152
 
@@ -163,6 +189,10 @@ function useChatTick(name, kinds) {
163
189
 
164
190
  /** #1722: the chat's title — the name that leads, the other on hover. */
165
191
  const headerName = ({ primary, secondary }) => (secondary ? html`<span title=${secondary}>${primary}</span>` : primary);
192
+ /** #2478: who the composer writes to — the display name, else the instance's name (a long id made the box two lines). */
193
+ const composerLabel = (inst, name) => (inst && typeof inst.display_name === "string" && inst.display_name.trim()) || name;
194
+ /** #2478: a touch screen (a coarse pointer) — Return is a new line there and only the Send button sends. Asked each time. */
195
+ const touchScreen = () => typeof matchMedia === "function" && matchMedia("(pointer: coarse)").matches;
166
196
 
167
197
  export function ChatPanel({ route, navKey }) {
168
198
  const lease = useLease(navKey);
@@ -238,7 +268,12 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
238
268
  }, [themeKey]);
239
269
  useEffect(() => { wrapListeners.add(setWrap); return () => wrapListeners.delete(setWrap); }, []);
240
270
  // First visit to this instance's chat on this page: its history (a navigation — it counts as use). Back again: nothing.
241
- useEffect(() => { store.openHistory(name, lease); }, [name]);
271
+ // #2188: left before it answered (passing through on the way to another chat) — the read is aborted.
272
+ useEffect(() => {
273
+ const ac = typeof AbortController === "function" ? new AbortController() : null;
274
+ store.openHistory(name, lease, ac?.signal);
275
+ return () => ac?.abort();
276
+ }, [name]);
242
277
  useEffect(() => { try { localStorage.setItem("agend_last_instance", name); } catch { /* none */ } }, [name]);
243
278
  // Files dragged over the chat show where they go; a drop attaches them (counted, so moving over messages does not flicker).
244
279
  useEffect(() => {
@@ -271,6 +306,9 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
271
306
  else if (r && r.held) toast(r.message);
272
307
  else toast(t(verb === "start" ? "chat.started" : verb === "stop" ? "chat.stoppedInst" : "chat.restarted", name));
273
308
  };
309
+ // #2193: this chat's Canvas Worker placements (its status row's effect_chat_v): none, no effects code runs for it.
310
+ const cwEnabled = useCanvasWorker();
311
+ const fxHere = cwEnabled && chatHasEffects(name);
274
312
  const items = [
275
313
  // #1523 N2: Details is a page now (the Fleet side of this instance), not a dialog.
276
314
  { key: "details", label: t("chat.details"), icon: "info", onSelect: () => navigate(detailsPath(name)) },
@@ -283,7 +321,7 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
283
321
  ...themeMenuItems(name),
284
322
  // #2117: its ambient — why it is not showing here (with the way to change that), and a person's Clear.
285
323
  ...ambientMenuItems(name, { publicLink: document.body.dataset.publicLink === "1", clear: clearAmbient }),
286
- chatEffectsMenuAvailable() ? { key: "effects", label: t("chatFx.title"), onSelect: () => setDialog("effects") } : null,
324
+ cwEnabled && canvasWorkerMenuAvailable(window) ? { key: "effects", label: t("cwControls.title"), onSelect: () => setDialog("effects") } : null,
287
325
  { key: "delete", label: t("chat.delete"), icon: "trash", danger: true, onSelect: () => setDialog("delete") },
288
326
  ];
289
327
  const cls = statusClass(inst, exec, awaiting);
@@ -296,7 +334,7 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
296
334
  ${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", modelText(inst))} aria-label=${t("chat.chipModel", modelText(inst))} onClick=${() => pick("model")}>${modelText(inst)}</button>` : null}
297
335
  ${inst.effort ? html`<button type="button" class="hd-chip" title=${t("chat.chipEffort", inst.effort)} aria-label=${t("chat.chipEffort", inst.effort)} onClick=${() => pick("effort")}>${inst.effort}</button>` : null}`;
298
336
  return html`<div class=${`panel p-chat${wrap ? " wrap-code" : ""}`} ref=${view}>
299
- <${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${guest ? null : html`<${InstanceSwitch} name=${name} current="chat" />`} notice=${html`<${ChatEffects} name=${name} lease=${lease} element=${effectSurface} store=${store} open=${dialog === "effects"} onPlayback=${publishCanvasPlayback} onClose=${() => setDialog(null)} />`}><${ChatEffectPosters} name=${name} lease=${lease} element=${effectSurface} /><${HeaderTools} navKey=${navKey} />${guest ? null : html`<${Menu} items=${items} label=${t("app.more")} />`}</${PanelHeader}>
337
+ <${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${guest ? null : html`<${InstanceSwitch} name=${name} current="chat" />`} notice=${html`<${ChatEffects} name=${name} lease=${lease} element=${effectSurface} store=${store} open=${dialog === "effects"} onPlayback=${publishCanvasPlayback} onClose=${() => setDialog(null)} active=${fxHere} />`}>${fxHere ? html`<${ChatEffectPosters} name=${name} lease=${lease} element=${effectSurface} />` : null}<${CardMenu} card=${card} /><${HeaderTools} navKey=${navKey} />${guest ? null : html`<${Menu} items=${items} label=${t("app.more")} />`}</${PanelHeader}>
300
338
  <${ChatCard} key=${name} name=${name} card=${card} />
301
339
  <${AgentWidget} slot="chat_header" widget=${widgetFor(name, "chat_header")} binds=${instanceBinds(inst, exec, awaiting)} />
302
340
  <div class="chat-split" ref=${split}>
@@ -322,9 +360,48 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
322
360
  * each switch built the thread again: a revisit was no faster than a first visit). A kept thread is its list element
323
361
  * and its renderer, and nothing more: it leaves as a chat always did (previews stop), with no subscription or timer
324
362
  * left; shown again, one render draws only what changed meanwhile, where the reader was. A new language, another
325
- * document, or more than THREAD_KEEP lets one go.
363
+ * document, or more than the budget lets one go.
364
+ *
365
+ * #2184: the budget (raised for people who switch among ~10 favourites): up to THREAD_KEEP threads on a wide screen and
366
+ * THREAD_KEEP_NARROW on a narrow one (a phone), and THREAD_KEEP_NODES drawn messages in all, so memory stays bounded
367
+ * however long the chats are. Over it, the least recently shown goes first — one that is not a favourite before a
368
+ * favourite; the chat on screen never goes.
369
+ */
370
+ export const THREAD_KEEP = 12;
371
+ export const THREAD_KEEP_NARROW = 6;
372
+ export const THREAD_KEEP_NODES = 2400;
373
+ /**
374
+ * #2188: a chat shown for less than this, on the way to another (clicking down the sidebar), is not kept: it is let go
375
+ * as it leaves, so passing through chats never evicts the ones in use. One that was already kept stays kept.
326
376
  */
327
- export const THREAD_KEEP = 4;
377
+ export const THREAD_PASS_MS = 1000;
378
+ const monotonic = () => (typeof performance === "object" && typeof performance.now === "function" ? performance.now() : Date.now());
379
+ let now = monotonic;
380
+ /** Tests only: the clock THREAD_PASS_MS is measured on (null: the page's monotonic clock). */
381
+ export function setThreadClock(fn) { now = typeof fn === "function" ? fn : monotonic; }
382
+ /**
383
+ * The kept threads to let go, in order. `kept`: [name, drawn messages], least recently shown first; `current`: the
384
+ * one on screen (never let go).
385
+ */
386
+ export function threadsToLetGo(kept, current, { keep, maxNodes, favorites }) {
387
+ let count = kept.length, nodes = kept.reduce((n, [, d]) => n + d, 0);
388
+ const out = [];
389
+ const order = [...kept.filter(([n]) => n !== current && !favorites.has(n)), ...kept.filter(([n]) => n !== current && favorites.has(n))];
390
+ for (const [n, d] of order) {
391
+ if (count <= keep && nodes <= maxNodes) break;
392
+ out.push(n); count--; nodes -= d;
393
+ }
394
+ return out;
395
+ }
396
+ const narrowScreen = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
397
+ /** Let go what the budget does not hold (after `current` was shown, or drew more). */
398
+ function trimKept(current) {
399
+ const kept = [...keptThreads].map(([n, e]) => [n, e.thread.nodes.size]);
400
+ const favorites = new Set(instanceNavStore.get().favorites);
401
+ for (const n of threadsToLetGo(kept, current, { keep: narrowScreen() ? THREAD_KEEP_NARROW : THREAD_KEEP, maxNodes: THREAD_KEEP_NODES, favorites })) {
402
+ letGo(keptThreads.get(n), true); keptThreads.delete(n);
403
+ }
404
+ }
328
405
  const keptThreads = new Map(); // name → { thread, list, sink, lang }
329
406
  /** Tests only: let every kept thread go. */
330
407
  export function forgetKeptThreads() { for (const e of keptThreads.values()) letGo(e, true); keptThreads.clear(); }
@@ -341,7 +418,8 @@ function threadEntry(name, doc) {
341
418
  const thread = createThread(list, doc.createElement("div"), {
342
419
  t, tf: t, isUser: (x) => store.isUser(x, name), onJump: (j) => e.sink?.setJump(j), onEmpty: (v) => e.sink?.setEmpty(v),
343
420
  setPreviewOptIn, copyText, download: downloadHtml, toggleWrap,
344
- effectTrialStatus: x => getAppEffects()?.trialStatus(x) ?? "localAdmin",
421
+ // #2193: an offer shown while the effects runtime sleeps wakes it; until it answers, the offer is being checked.
422
+ effectTrialStatus: x => { const fx = getAppEffects(); if (fx) return fx.trialStatus(x); if (!effectsLoaded()) { void wakeEffects(); return "checking"; } return "localAdmin"; },
345
423
  effectTrialFailure: x => getAppEffects()?.trialFailure(x),
346
424
  fixEffectTrial: (x, reason) => {
347
425
  if (reason === "reducedMotion") setFollowsReducedMotion(false);
@@ -353,6 +431,13 @@ function threadEntry(name, doc) {
353
431
  canTryEffect: x => getAppEffects()?.canTry(x) === true,
354
432
  startEffectTrial: x => { const seq = navStore.get().seq; void getAppEffects()?.startTrial(x).then(ok => { if (!ok && e.sink && navStore.get().seq === seq && document.hasFocus?.() === true && document.visibilityState === "visible") toast(t("chat.effectTrialUnavailable")); }); },
355
433
  clickReplyButton: (id, index) => store.clickReplyButton(name, id, index), // #1266
434
+ retryOutgoing: (clientId) => store.retryOutgoing(name, clientId), // a failed send's Retry and Delete
435
+ deleteOutgoing: (clientId) => store.deleteOutgoing(name, clientId),
436
+ putBackOutgoing: (clientId) => { recordEdit(composerField()); store.putBackOutgoing(name, clientId); }, // undoable, as typing
437
+ // #2272: reply to a message (the bar above the composer), and show the one a reply quotes.
438
+ startReply: (x) => { store.startReply(name, x); doc.getElementById("msgIn")?.focus(); },
439
+ findQuoted: (key) => store.findQuoted(name, key),
440
+ notice: (text) => toast(text, false),
356
441
  replyButtonBusy: (id) => store.state.rbBusy.has(id),
357
442
  pollMine: (id) => store.state.pollMine[id], // #1823: this device's own vote
358
443
  serverNow: () => Date.now() + store.state.clockSkew, // #1823: the deadline is the server's
@@ -370,16 +455,27 @@ function follow(name, thread) {
370
455
  // #1682: the same for mention names — asked for the ids the messages carry; when names arrive, drawn again.
371
456
  const wantEmojis = (msgs) => { if (emojiIndex && emojiIndex.wants(msgs)) emojiIndex.ensure(); if (mentionIndex) mentionIndex.ensure(msgs); };
372
457
  const offs = [];
373
- if (emojiIndex) offs.push(emojiIndex.subscribe(() => thread.render(store.state.msgs[name] || [])));
374
- if (mentionIndex) offs.push(mentionIndex.subscribe(() => thread.render(store.state.msgs[name] || [])));
458
+ if (emojiIndex) offs.push(emojiIndex.subscribe(() => thread.render(store.threadRows(name))));
459
+ if (mentionIndex) offs.push(mentionIndex.subscribe(() => thread.render(store.threadRows(name))));
375
460
  wantEmojis(store.state.msgs[name]);
376
461
  offs.push(store.subscribe((instance, kind) => {
377
462
  if (instance !== name) return;
378
- if (kind === "msgs") { thread.render(store.state.msgs[name] || []); wantEmojis(store.state.msgs[name]); }
463
+ if (kind === "msgs") { thread.render(store.threadRows(name)); wantEmojis(store.state.msgs[name]); }
464
+ else if (kind === "progress") thread.progress(); // an upload moved: its bar, in place
379
465
  else if (kind === "sent") thread.jumpLatest();
380
466
  }));
381
467
  offs.push(P() ? P().onChange(() => thread.refreshCards()) : () => {});
382
- offs.push(getAppEffects()?.subscribeTrial(() => thread.render(store.state.msgs[name] || [])) ?? (() => {}));
468
+ // #2193: the runtime may start later (an offer shown wakes it): its trial updates are followed from then.
469
+ let trialOff = null, trialOwner = null;
470
+ const watchTrial = () => {
471
+ const next = getAppEffects();
472
+ if (next === trialOwner) return;
473
+ trialOff?.(); trialOff = null; trialOwner = next;
474
+ trialOff = next?.subscribeTrial(() => thread.render(store.threadRows(name))) ?? null;
475
+ };
476
+ watchTrial();
477
+ offs.push(onEffectsAwake(() => { watchTrial(); thread.render(store.threadRows(name)); }));
478
+ offs.push(() => { trialOff?.(); trialOff = null; trialOwner = null; });
383
479
  offs.push(panelStore.subscribe(() => thread.refreshCards())); // a card shows whether the panel has its block
384
480
  return () => { for (const off of offs) off(); };
385
481
  }
@@ -398,29 +494,48 @@ function Thread({ name, th }) {
398
494
  if (e) keptThreads.delete(name);
399
495
  else e = threadEntry(name, doc);
400
496
  keptThreads.set(name, e); // the most recent last
401
- for (const [k, old] of keptThreads) {
402
- if (keptThreads.size <= THREAD_KEEP) break;
403
- if (k !== name) { letGo(old, true); keptThreads.delete(k); }
404
- }
497
+ // A thread already kept is trimmed against at once; a new one first has to stay (see THREAD_PASS_MS).
498
+ if (kept) trimKept(name);
499
+ const shownAt = now();
405
500
  const thread = e.thread, sc = scroller.current, ls = e.list;
406
501
  e.sink = { setJump, setEmpty };
407
502
  host.current.append(ls);
408
503
  thread.attach(sc);
409
504
  th.current = thread;
410
505
  // Up to date, at the reader's place (the bottom unless they had scrolled up); a kept one's cards say what they can do.
411
- thread.render(store.state.msgs[name] || [], { restore: store.state.scrollMemo[name] ?? null });
506
+ thread.render(store.threadRows(name), { restore: store.state.scrollMemo[name] ?? null });
412
507
  if (kept) thread.refreshCards();
413
508
  const unfollow = follow(name, thread);
414
509
  const onScroll = () => { store.state.scrollMemo[name] = thread.onScroll(); };
415
510
  sc.addEventListener("scroll", onScroll, { passive: true });
416
511
  ls.addEventListener("click", thread.onClick);
512
+ // #2272: the message menu, swipe left / long-press on a phone, R on a focused message.
513
+ const offActions = installMessageActions(ls, {
514
+ t, messageOf: thread.messageOf, rove: thread.rove, reply: (x) => { store.startReply(name, x); document.getElementById("msgIn")?.focus(); },
515
+ copyText, notice: (text, ok = true) => toast(text, ok),
516
+ linkOf: (x) => `${location.origin}/ui/chat/${encodeURIComponent(name)}#m=${msgKey(x)}`,
517
+ });
518
+ // A copied message link (#m=<boot>-<id>): show that message, flashed.
519
+ const linked = /^#m=([0-9a-f]{1,32}-\d{1,15})$/.exec(location.hash);
520
+ if (linked) void thread.jumpTo(linked[1]);
521
+ // #2293: search opening a message of this chat while it is shown — the address's #m= changes, the route does not.
522
+ // Only this chat's address: during a jump to another chat this one is still mounted for a moment.
523
+ const onHash = () => {
524
+ const m = /^#m=([0-9a-f]{1,32}-\d{1,15})$/.exec(location.hash);
525
+ if (m && location.pathname === `/ui/chat/${encodeURIComponent(name)}`) void thread.jumpTo(m[1]);
526
+ };
527
+ window.addEventListener("hashchange", onHash);
417
528
  return () => {
529
+ window.removeEventListener("hashchange", onHash);
418
530
  unfollow();
531
+ offActions();
419
532
  sc.removeEventListener("scroll", onScroll);
420
533
  ls.removeEventListener("click", thread.onClick);
421
534
  e.sink = null;
422
535
  th.current = null;
423
- if (keptThreads.get(name) === e) { thread.park(); ls.remove(); } // kept for a later visit: the chat left
536
+ // Passed through (new, and shown under THREAD_PASS_MS): let go. Otherwise kept for a later visit, within the budget.
537
+ if (keptThreads.get(name) === e && !kept && now() - shownAt < THREAD_PASS_MS) { keptThreads.delete(name); letGo(e, false); }
538
+ else if (keptThreads.get(name) === e) { thread.park(); ls.remove(); trimKept(null); } // kept for a later visit: the chat left
424
539
  else letGo(e, false); // let go meanwhile (a new language)
425
540
  };
426
541
  }, [name]);
@@ -441,15 +556,20 @@ function Dock({ name, inst, lease, exec, awaiting, workingLabel }) {
441
556
  <${WorkBar} name=${name} lease=${lease} exec=${exec} awaiting=${awaiting} workingLabel=${workingLabel} />
442
557
  <${CommandCard} name=${name} lease=${lease} />
443
558
  <${QuickActions} name=${name} inst=${inst} lease=${lease} />
444
- ${s.failedSends[name] ? html`<div class="failed-send" role="alert"><span>${t("chat.notSent")}</span><span class="txt">${s.failedSends[name]}</span>
445
- <button type="button" class="btn btn-primary btn-sm" onClick=${() => store.putBack(name)}>${t("chat.putBack")}</button>
446
- <button type="button" class="btn btn-sm" onClick=${() => store.discardFailed(name)}>${t("chat.discard")}</button></div>` : null}
447
- <${Composer} name=${name} lease=${lease} busy=${R().isBusy(exec)} />
448
- <p class="hint" title=${t(guestPage() ? "chat.guestMore" : "chat.composerMore")}>${t("chat.composerHint")}</p>
449
- ${guestPage() ? html`<p class="guest-note">${t("chat.guestNote")}</p>` : html`<${AuthorizeChip} />`}
559
+ ${s.waking[name] ? html`<p class="send-waking" role="status">${t("chat.waking", name)}</p>` : null}
560
+ <${Composer} name=${name} label=${composerLabel(inst, name)} lease=${lease} busy=${R().isBusy(exec)} />
561
+ <div class="composer-row">${guestPage() ? html`<span class="guest-note" title=${t("chat.guestNote")}>${t("chat.guestNote")}</span>` : html`<${ComposerAuth} />`}<span
562
+ class="hint" title=${t(guestPage() ? "chat.guestMore" : "chat.composerMore")}>${t(touchScreen() ? "chat.composerHintTouch" : "chat.composerHint")}</span></div>
450
563
  </div></div>`;
451
564
  }
452
565
 
566
+ /** #2233: the public link's page — the dashboard's Sign in is refused there, so it is never offered (#2262 review). */
567
+ const publicLinkPage = () => typeof document !== "undefined" && !!document.body && document.body.dataset.publicLink === "1";
568
+ /** #2233: a backend's "not signed in" choice offers Sign in (the module behind the session gate, loaded when asked). */
569
+ function openBackendSignIn(backend) {
570
+ import("./backend-signin.js").then((m) => m.openSignIn({ backend }), () => toast(t("app.loadFailed"), false));
571
+ }
572
+
453
573
  /** #1269: what the last chat command answered — its text, why it was refused, or a list to choose from. */
454
574
  function CommandCard({ name, lease }) {
455
575
  const c = store.state.commands[name];
@@ -468,6 +588,8 @@ function CommandCard({ name, lease }) {
468
588
  ${c.choices ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdChoose")}>${c.choices.options.map((o) => html`<button key=${o.id} type="button"
469
589
  class=${`btn btn-sm${o.id === c.choices.current ? " current" : ""}`} aria-current=${o.id === c.choices.current ? "true" : undefined}
470
590
  disabled=${!!o.disabled} title=${o.disabled || undefined} onClick=${() => { if (!o.disabled) run(o.id); }}>${o.label}</button>`)}</div>` : null}
591
+ ${c.choices && c.choices.options.some((o) => o.signIn) && !publicLinkPage() ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdSignIn")}>${c.choices.options.filter((o) => o.signIn).map((o) => html`<button
592
+ key=${`signin:${o.signIn}`} type="button" class="btn btn-sm btn-primary" onClick=${() => openBackendSignIn(o.signIn)}>${t("chat.cmdSignInTo", o.signIn)}</button>`)}</div>` : null}
471
593
  </div>`;
472
594
  }
473
595
 
@@ -514,7 +636,13 @@ function WorkBar({ name, lease, exec, awaiting, workingLabel }) {
514
636
  : html`<span class="elapsed" title=${t("chat.elapsedTitle")} aria-hidden="true">${since == null ? "" : R().formatElapsed(performance.now() - since)}</span>`}</div>`;
515
637
  }
516
638
 
517
- function Composer({ name, lease, busy }) {
639
+ /** #2272: the reply bar's quote — the first ~80 characters, or what it had instead of text. */
640
+ function replySnippet(r) {
641
+ const text = r.text ? (r.text.length > 80 ? `${r.text.slice(0, 79).trimEnd()}…` : r.text) : "";
642
+ return text || (r.media === "photo" ? t("chat.replyPhoto") : r.media === "document" ? t("chat.replyFile") : "");
643
+ }
644
+
645
+ function Composer({ name, label = name, lease, busy }) {
518
646
  const s = store.state;
519
647
  const input = useRef(null), fileIn = useRef(null);
520
648
  const [, tick] = useState(0);
@@ -522,14 +650,20 @@ function Composer({ name, lease, busy }) {
522
650
  const [closedFor, setClosedFor] = useState(null); // the draft the palette was closed on (Esc); it opens again on change
523
651
  const value = s.drafts[name] || "";
524
652
  const files = s.pendingFiles[name] || [];
653
+ const reply = s.replies[name]; // #2272: the message this one will reply to
525
654
  const content = !!value.trim() || files.length > 0;
526
655
  // A file waiting: what goes is a message with its file, never a command (no palette, no command line). A guest never
527
656
  // runs one (#1920: the server refuses its slash text), so it has no palette either.
528
657
  const guest = guestPage();
529
658
  const palette = guest || files.length || closedFor === value ? null : paletteFor(value);
530
659
  const pick = palette && palette.length ? palette[Math.min(sel, palette.length - 1)] : null;
531
- // Grow with the text, up to a limit: set through the CSSOM, never a style attribute (#1300).
532
- useLayoutEffect(() => { const el = input.current; if (!el) return; el.style.height = "auto"; el.style.height = `${Math.min(el.scrollHeight, 240)}px`; }, [value]);
660
+ // Grow with the text, up to a limit: set through the CSSOM, never a style attribute (#1300). Empty, it is one line
661
+ // (#2478 — a long name's placeholder made the box two lines tall).
662
+ useLayoutEffect(() => {
663
+ const el = input.current; if (!el) return;
664
+ el.style.height = "auto";
665
+ if (value) el.style.height = `${Math.min(el.scrollHeight, 240)}px`;
666
+ }, [value]);
533
667
  useEffect(() => { if (input.current) input.current.focus(); }, [name]);
534
668
  useEffect(() => { refreshTourSpot(); });
535
669
  const setValue = (v) => { store.setDraft(name, v); setSel(0); tick(n => n + 1); };
@@ -540,7 +674,8 @@ function Composer({ name, lease, busy }) {
540
674
  setValue("");
541
675
  store.runCommand(name, cmd.command, cmd.args, { alive: () => lease.current() });
542
676
  };
543
- const complete = (c) => setValue(`/${c.name}${c.arg ? " " : ""}`);
677
+ // #2342: a completion is a step Ctrl+Z goes back from (to what was typed); a command that runs consumes the line.
678
+ const complete = (c) => { recordEdit(input.current); setValue(`/${c.name}${c.arg ? " " : ""}`); };
544
679
  const submit = () => {
545
680
  if (pick) {
546
681
  if (value === `/${pick.name}` && !needsArgument(pick.name)) runLine({ command: pick.name, args: "" });
@@ -550,7 +685,7 @@ function Composer({ name, lease, busy }) {
550
685
  // #1920: a guest's "/…" would be refused as a command — said here, the draft kept to edit.
551
686
  if (guest && /^\s*\//.test(value)) { toast(t("chat.guestNoCommands"), false); return; }
552
687
  const cmd = files.length ? null : parseCommandLine(value);
553
- if (cmd && needsArgument(cmd.command) && !cmd.args) { setValue(`/${cmd.command} `); return; }
688
+ if (cmd && needsArgument(cmd.command) && !cmd.args) { recordEdit(input.current); setValue(`/${cmd.command} `); return; }
554
689
  if (cmd) { runLine(cmd); return; }
555
690
  store.send(name);
556
691
  };
@@ -562,7 +697,8 @@ function Composer({ name, lease, busy }) {
562
697
  }
563
698
  if (pick && e.key === "Tab" && !e.shiftKey) { e.preventDefault(); complete(pick); return; }
564
699
  if (palette && e.key === "Escape" && !e.isComposing) { e.preventDefault(); setClosedFor(value); return; }
565
- if (R().composerKey(e) === "send") { e.preventDefault(); submit(); }
700
+ if (reply && e.key === "Escape" && !e.isComposing) { e.preventDefault(); store.clearReply(name); return; } // #2272
701
+ if (R().composerKey(e, { touch: touchScreen() }) === "send") { e.preventDefault(); submit(); }
566
702
  };
567
703
  const onInput = (e) => { setValue(e.target.value); };
568
704
  // Files in a paste are attached; a very long text paste goes as a text file — only once it is really attached.
@@ -580,17 +716,25 @@ function Composer({ name, lease, busy }) {
580
716
  <span class="cmd-name mono">/${c.name}${c.arg ? html` <span class="cmd-arg">${c.arg}</span>` : null}</span><span class="cmd-desc">${t(`chat.cmd_${c.name}`)}</span></li>`)
581
717
  : html`<li class="cmd-none" role="option" aria-selected="false">${t("chat.cmdNotCommand")}</li>`}
582
718
  </ul>` : null}
719
+ ${reply ? html`<div class="reply-bar" data-trust="composer" role="status">
720
+ <span class="reply-mark" aria-hidden="true"><svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/></svg></span><span class="reply-label">${t("chat.replyingTo", reply.sender)}</span>
721
+ <span class="reply-text">${replySnippet(reply)}</span>
722
+ <button type="button" class="icon-btn reply-cancel" title=${t("chat.replyCancel")} aria-label=${t("chat.replyCancel")} onClick=${() => { store.clearReply(name); input.current?.focus(); }}><${Icon} name="close" size=${14} /></button>
723
+ </div>` : null}
583
724
  ${files.length ? html`<div class="pending-files">${files.map((f, i) => html`<${FileChip} key=${`${f.name}-${i}`} f=${f} i=${i} name=${name} />`)}</div>` : null}
584
725
  <div class="composer">
585
726
  <button id="attachBtn" type="button" class="icon-btn" title=${t("chat.attachTitle")} aria-label=${t("chat.attachTitle")} onClick=${() => fileIn.current && fileIn.current.click()}><${Icon} name="attach" /></button>
586
727
  <input ref=${fileIn} type="file" multiple hidden
587
728
  onChange=${(e) => { store.addFiles(name, e.target.files); e.target.value = ""; }} />
588
- <textarea id="msgIn" ref=${input} rows="1" value=${value} placeholder=${t("chat.composerPlaceholder", name)} aria-label=${t("chat.composerPlaceholder", name)}
589
- autocomplete="off" aria-controls=${palette ? "cmdPalette" : undefined} aria-expanded=${palette ? "true" : "false"}
590
- aria-activedescendant=${pick ? optId(pick) : undefined} onInput=${onInput} onKeyDown=${onKeyDown} onPaste=${onPaste}></textarea>
729
+ ${/* #2478: the placeholder is drawn beside the box, one line ending in "…" — a textarea's own placeholder is clipped,
730
+ never ellipsized, and a long name wrapped it to two lines. The box keeps the words as its accessible name. */ ""}
731
+ <span class="composer-field"><textarea id="msgIn" ref=${input} rows="1" value=${value} aria-label=${t("chat.composerPlaceholder", label)}
732
+ enterkeyhint=${touchScreen() ? "enter" : undefined} autocomplete="off" aria-controls=${palette ? "cmdPalette" : undefined} aria-expanded=${palette ? "true" : "false"}
733
+ aria-activedescendant=${pick ? optId(pick) : undefined} onInput=${onInput} onKeyDown=${onKeyDown} onPaste=${onPaste}></textarea>${value ? null
734
+ : html`<span class="composer-ph" aria-hidden="true">${t("chat.composerPlaceholder", label)}</span>`}</span>
591
735
  <button id="stopBtn" type="button" class="btn btn-stop" hidden=${!busy} title=${t("chat.stopReplyTitle")}
592
736
  disabled=${!!s.cancelling[name]} onClick=${() => store.cancelReply(name)}><${Icon} name="stop" size=${14} /><span class="stop-label">${t("chat.stopReply")}</span></button>
593
- <button id="sendBtn" type="button" class="btn btn-primary btn-send" hidden=${busy && !content} disabled=${!content || !!s.sending[name]}
737
+ <button id="sendBtn" type="button" class="btn btn-primary btn-send" hidden=${busy && !content} disabled=${!content}
594
738
  onMouseDown=${(e) => e.preventDefault()}
595
739
  aria-label=${t("chat.send")} title=${t("chat.send")} onClick=${submit}><${Icon} name="send" size=${16} /><span class="send-label">${t("chat.send")}</span></button>
596
740
  </div></div>`;
@@ -608,7 +752,7 @@ function FileChip({ f, i, name }) {
608
752
  return html`<span class="file-chip">
609
753
  ${isImage ? html`<img ref=${img} alt="" />` : html`<span class="ic"><${Icon} name="file" size=${16} /></span>`}
610
754
  <span class="nm">${f.name}</span><span class="sz">${R().formatSize(f.size)}</span>
611
- ${store.isPasted(f) ? html`<button type="button" class="as-text" onClick=${() => store.fileBackAsText(name, i)}>${t("chat.asText")}</button>` : null}
755
+ ${store.isPasted(f) ? html`<button type="button" class="as-text" onClick=${() => { recordEdit(composerField()); store.fileBackAsText(name, i); }}>${t("chat.asText")}</button>` : null}
612
756
  <button type="button" class="chip-x" title=${t("chat.removeFile")} aria-label=${`${t("chat.removeFile")} ${f.name}`} onClick=${() => store.removeFile(name, i)}><${Icon} name="close" size=${14} /></button></span>`;
613
757
  }
614
758
 
@@ -631,7 +775,7 @@ function DeleteDialog({ name, onClose }) {
631
775
  // navigates anything (the person may be anywhere by then).
632
776
  try {
633
777
  const res = await confirmedWrite(`/ui/instances/${encodeURIComponent(name)}/delete`, { method: "POST", body: { confirm: typed }, label: t("chat.deleteTitle", name),
634
- onPending: () => { handedOver = true; toast(t("app.pendingSent")); if (lease.current()) { setBusy(false); onClose(); } } });
778
+ onPending: (_id, view) => { handedOver = true; toast(t(selfConfirmed(view) ? "app.pendingSelfSent" : "app.pendingSent")); if (lease.current()) { setBusy(false); onClose(); } } });
635
779
  r = res.ok ? res.body || {} : { error: (res.body && res.body.error) || `HTTP ${res.status}` };
636
780
  } catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
637
781
  if (r && r.error) { toast(r.error, false); if (!handedOver && lease.current()) setBusy(false); return; }
@@ -25,6 +25,7 @@ import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
25
25
  import { toast } from "/assets/ui-toast.js";
26
26
  import "./chat-strings.js";
27
27
  import { api } from "./settings-confirm.js";
28
+ import { InstanceBoardWork } from "./fleet-task-work.js";
28
29
  import { requestAgentSettings } from "./settings-request.js";
29
30
 
30
31
  export function DetailsPanel({ route, navKey }) {
@@ -150,6 +151,7 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
150
151
  ${row(t("chat.dContext"), html`<span class="pct">${ctx != null ? `${Math.round(ctx)}%` : "--"}</span>${ctx != null ? bar(ctx, ctx > 80 ? "warn" : "") : null}`)}
151
152
  ${row(t("chat.dRate5"), html`<span class="pct">${Math.round(rl5)}%</span>${bar(rl5, rl5 > 90 ? "error" : rl5 > 70 ? "warn" : "")}`)}
152
153
  ${row(t("chat.dRate7"), html`<span class="pct">${Math.round(rl7)}%</span>${bar(rl7, rl7 > 90 ? "error" : rl7 > 70 ? "warn" : "")}`)}</section>
154
+ <${InstanceBoardWork} name=${name} onOpen=${(id) => navigate(`/ui/fleet?card=${encodeURIComponent(id)}`)} />
153
155
  <section class="card"><h3>${t("chat.dActivity")}</h3>${d.recent_activity?.length ? d.recent_activity.map((a, i) => html`<div key=${i} class="activity">
154
156
  <span class="mono muted">${a.timestamp ? new Date(`${a.timestamp.replace(" ", "T")}Z`).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}</span>
155
157
  <span class="ev">${a.event}</span> ${a.summary || ""}</div>`) : html`<p class="note">${t("chat.dNoActivity")}</p>`}</section>`;