@songsid/agend 2.3.0-beta.8 → 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 (736) 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 +9 -2
  8. package/dist/agent-cli.js +44 -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 +54 -11
  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 +43 -6
  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.d.ts +25 -0
  144. package/dist/decision-list.js +30 -0
  145. package/dist/decision-list.js.map +1 -0
  146. package/dist/delivery-consumed-watch.js.map +1 -1
  147. package/dist/delivery-outbox.js +5 -0
  148. package/dist/delivery-outbox.js.map +1 -1
  149. package/dist/delivery-outbox.test.js.map +1 -1
  150. package/dist/delivery-reconciliation.test.js.map +1 -1
  151. package/dist/diagnostic-redaction.d.ts +10 -0
  152. package/dist/diagnostic-redaction.js +167 -0
  153. package/dist/diagnostic-redaction.js.map +1 -0
  154. package/dist/doctor.d.ts +8 -0
  155. package/dist/doctor.js +52 -0
  156. package/dist/doctor.js.map +1 -1
  157. package/dist/e2e-isolation.js.map +1 -1
  158. package/dist/event-log.js.map +1 -1
  159. package/dist/export-import.js +7 -5
  160. package/dist/export-import.js.map +1 -1
  161. package/dist/fleet-control-audit.js.map +1 -1
  162. package/dist/fleet-label.js.map +1 -1
  163. package/dist/fleet-level-config.d.ts +1 -1
  164. package/dist/fleet-level-config.js +2 -0
  165. package/dist/fleet-level-config.js.map +1 -1
  166. package/dist/fleet-lock.js +3 -2
  167. package/dist/fleet-lock.js.map +1 -1
  168. package/dist/fleet-manager.d.ts +258 -15
  169. package/dist/fleet-manager.js +1605 -304
  170. package/dist/fleet-manager.js.map +1 -1
  171. package/dist/fleet-process-handlers.d.ts +18 -0
  172. package/dist/fleet-process-handlers.js +70 -0
  173. package/dist/fleet-process-handlers.js.map +1 -0
  174. package/dist/fleet-startup.d.ts +14 -0
  175. package/dist/fleet-startup.js +30 -0
  176. package/dist/fleet-startup.js.map +1 -0
  177. package/dist/fleet-traffic.d.ts +36 -0
  178. package/dist/fleet-traffic.js +100 -0
  179. package/dist/fleet-traffic.js.map +1 -1
  180. package/dist/forged-envelope-scan.d.ts +0 -20
  181. package/dist/forged-envelope-scan.js +3 -2
  182. package/dist/forged-envelope-scan.js.map +1 -1
  183. package/dist/full-restart.d.ts +5 -5
  184. package/dist/full-restart.js +5 -5
  185. package/dist/full-restart.js.map +1 -1
  186. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  187. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  188. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  189. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  190. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  191. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  192. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  193. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  194. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  195. package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
  196. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  197. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
  198. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  199. package/dist/general-knowledge/steering/core-rules.md +1 -1
  200. package/dist/host-memory.js.map +1 -1
  201. package/dist/idle-gate-log.d.ts +19 -0
  202. package/dist/idle-gate-log.js +15 -0
  203. package/dist/idle-gate-log.js.map +1 -0
  204. package/dist/instance-config-impact.js +25 -4
  205. package/dist/instance-config-impact.js.map +1 -1
  206. package/dist/instance-lifecycle.d.ts +10 -1
  207. package/dist/instance-lifecycle.js +86 -25
  208. package/dist/instance-lifecycle.js.map +1 -1
  209. package/dist/instructions.d.ts +12 -6
  210. package/dist/instructions.js +19 -10
  211. package/dist/instructions.js.map +1 -1
  212. package/dist/kiro-compact-pane.js.map +1 -1
  213. package/dist/kiro-db-reader.js.map +1 -1
  214. package/dist/kiro-engine-status.js.map +1 -1
  215. package/dist/kiro-log-gate.js.map +1 -1
  216. package/dist/kiro-transcript-lane.js.map +1 -1
  217. package/dist/locale.js +428 -20
  218. package/dist/locale.js.map +1 -1
  219. package/dist/log-service.js.map +1 -1
  220. package/dist/log-steps.d.ts +1 -0
  221. package/dist/log-steps.js +15 -0
  222. package/dist/log-steps.js.map +1 -1
  223. package/dist/logger.js +3 -2
  224. package/dist/logger.js.map +1 -1
  225. package/dist/login-controller.d.ts +45 -0
  226. package/dist/login-controller.js +101 -5
  227. package/dist/login-controller.js.map +1 -1
  228. package/dist/login-flows.js +1 -1
  229. package/dist/login-manager.js.map +1 -1
  230. package/dist/login-shell.js +3 -1
  231. package/dist/login-shell.js.map +1 -1
  232. package/dist/ls-attach-resolve.d.ts +96 -0
  233. package/dist/ls-attach-resolve.js +180 -0
  234. package/dist/ls-attach-resolve.js.map +1 -0
  235. package/dist/ls-rows.d.ts +12 -0
  236. package/dist/ls-rows.js +83 -4
  237. package/dist/ls-rows.js.map +1 -1
  238. package/dist/memory-pressure.js.map +1 -1
  239. package/dist/muse-usage-relay.js.map +1 -1
  240. package/dist/needs-you-hub.d.ts +98 -1
  241. package/dist/needs-you-hub.js +313 -44
  242. package/dist/needs-you-hub.js.map +1 -1
  243. package/dist/needs-you-live.d.ts +5 -2
  244. package/dist/needs-you-live.js +6 -3
  245. package/dist/needs-you-live.js.map +1 -1
  246. package/dist/needs-you.d.ts +68 -3
  247. package/dist/needs-you.js +38 -4
  248. package/dist/needs-you.js.map +1 -1
  249. package/dist/network-family.js.map +1 -1
  250. package/dist/operator-control-paths.js +3 -4
  251. package/dist/operator-control-paths.js.map +1 -1
  252. package/dist/outbound-handlers.d.ts +3 -0
  253. package/dist/outbound-handlers.js +76 -19
  254. package/dist/outbound-handlers.js.map +1 -1
  255. package/dist/outbound-schemas.d.ts +112 -64
  256. package/dist/outbound-schemas.js +39 -12
  257. package/dist/outbound-schemas.js.map +1 -1
  258. package/dist/outbox-open-error.js.map +1 -1
  259. package/dist/pane-context-cache.js.map +1 -1
  260. package/dist/paths.js.map +1 -1
  261. package/dist/private-dir.js.map +1 -1
  262. package/dist/probe-worker-pool.js.map +1 -1
  263. package/dist/profile-control.js.map +1 -1
  264. package/dist/prompt-file-ref.js.map +1 -1
  265. package/dist/provider-probe.js.map +1 -1
  266. package/dist/provider-secret-registry.d.ts +5 -3
  267. package/dist/provider-secret-registry.js +8 -2
  268. package/dist/provider-secret-registry.js.map +1 -1
  269. package/dist/public-link-auto-open.d.ts +32 -0
  270. package/dist/public-link-auto-open.js +86 -0
  271. package/dist/public-link-auto-open.js.map +1 -0
  272. package/dist/public-link-owner.d.ts +10 -0
  273. package/dist/public-link-owner.js +36 -0
  274. package/dist/public-link-owner.js.map +1 -0
  275. package/dist/public-link-progress.d.ts +12 -1
  276. package/dist/public-link-progress.js +5 -10
  277. package/dist/public-link-progress.js.map +1 -1
  278. package/dist/public-preview.js.map +1 -1
  279. package/dist/public-tunnel-config.d.ts +11 -0
  280. package/dist/public-tunnel-config.js +68 -0
  281. package/dist/public-tunnel-config.js.map +1 -0
  282. package/dist/public-web-gateway.d.ts +2 -0
  283. package/dist/public-web-gateway.js +19 -6
  284. package/dist/public-web-gateway.js.map +1 -1
  285. package/dist/public-web-link.d.ts +48 -3
  286. package/dist/public-web-link.js +177 -51
  287. package/dist/public-web-link.js.map +1 -1
  288. package/dist/quickstart-api.d.ts +9 -0
  289. package/dist/quickstart-api.js +82 -0
  290. package/dist/quickstart-api.js.map +1 -1
  291. package/dist/quickstart.d.ts +5 -0
  292. package/dist/quickstart.js +40 -25
  293. package/dist/quickstart.js.map +1 -1
  294. package/dist/reply-buttons-controller.js.map +1 -1
  295. package/dist/reply-dedup.js.map +1 -1
  296. package/dist/resource-report.js +1 -1
  297. package/dist/resource-report.js.map +1 -1
  298. package/dist/restart-guard.js.map +1 -1
  299. package/dist/restart-progress.d.ts +80 -1
  300. package/dist/restart-progress.js +306 -21
  301. package/dist/restart-progress.js.map +1 -1
  302. package/dist/rollout-index.js.map +1 -1
  303. package/dist/runtime-cpu-profile.js.map +1 -1
  304. package/dist/scheduler/db.d.ts +40 -13
  305. package/dist/scheduler/db.js +123 -89
  306. package/dist/scheduler/db.js.map +1 -1
  307. package/dist/scheduler/scheduler.js.map +1 -1
  308. package/dist/scheduler/task-board-text.d.ts +26 -0
  309. package/dist/scheduler/task-board-text.js +140 -0
  310. package/dist/scheduler/task-board-text.js.map +1 -0
  311. package/dist/scheduler/task-board.d.ts +730 -0
  312. package/dist/scheduler/task-board.js +2179 -0
  313. package/dist/scheduler/task-board.js.map +1 -0
  314. package/dist/scheduler/types.d.ts +6 -1
  315. package/dist/sd-notify.js +2 -1
  316. package/dist/sd-notify.js.map +1 -1
  317. package/dist/search/search-docs.d.ts +58 -0
  318. package/dist/search/search-docs.js +63 -0
  319. package/dist/search/search-docs.js.map +1 -0
  320. package/dist/search/search-index.d.ts +141 -0
  321. package/dist/search/search-index.js +440 -0
  322. package/dist/search/search-index.js.map +1 -0
  323. package/dist/search/search-store.d.ts +122 -0
  324. package/dist/search/search-store.js +236 -0
  325. package/dist/search/search-store.js.map +1 -0
  326. package/dist/search/search-worker.d.ts +1 -0
  327. package/dist/search/search-worker.js +163 -0
  328. package/dist/search/search-worker.js.map +1 -0
  329. package/dist/secret-file.js.map +1 -1
  330. package/dist/secret-store.d.ts +2 -0
  331. package/dist/secret-store.js +21 -0
  332. package/dist/secret-store.js.map +1 -1
  333. package/dist/service-installer.d.ts +75 -0
  334. package/dist/service-installer.js +206 -0
  335. package/dist/service-installer.js.map +1 -1
  336. package/dist/service-owner.d.ts +44 -0
  337. package/dist/service-owner.js +48 -0
  338. package/dist/service-owner.js.map +1 -0
  339. package/dist/service-plan.d.ts +39 -2
  340. package/dist/service-plan.js +188 -6
  341. package/dist/service-plan.js.map +1 -1
  342. package/dist/session-oom.d.ts +21 -0
  343. package/dist/session-oom.js +139 -0
  344. package/dist/session-oom.js.map +1 -0
  345. package/dist/settings-api.d.ts +13 -0
  346. package/dist/settings-api.js +73 -12
  347. package/dist/settings-api.js.map +1 -1
  348. package/dist/settings-baseline.js.map +1 -1
  349. package/dist/settings-change.d.ts +5 -0
  350. package/dist/settings-change.js +167 -6
  351. package/dist/settings-change.js.map +1 -1
  352. package/dist/settings-confirmation.d.ts +9 -1
  353. package/dist/settings-confirmation.js +18 -8
  354. package/dist/settings-confirmation.js.map +1 -1
  355. package/dist/settings-control.js +2 -1
  356. package/dist/settings-control.js.map +1 -1
  357. package/dist/settings-effect.js +29 -4
  358. package/dist/settings-effect.js.map +1 -1
  359. package/dist/settings-http-confirmation.d.ts +13 -0
  360. package/dist/settings-http-confirmation.js +15 -3
  361. package/dist/settings-http-confirmation.js.map +1 -1
  362. package/dist/settings-instance-patch.js +13 -1
  363. package/dist/settings-instance-patch.js.map +1 -1
  364. package/dist/settings-request-capability.d.ts +4 -1
  365. package/dist/settings-request-capability.js +11 -3
  366. package/dist/settings-request-capability.js.map +1 -1
  367. package/dist/settings-transaction.js.map +1 -1
  368. package/dist/setup-auth.d.ts +1 -0
  369. package/dist/setup-auth.js +2 -1
  370. package/dist/setup-auth.js.map +1 -1
  371. package/dist/setup-form.d.ts +1 -1
  372. package/dist/setup-form.js +23 -7
  373. package/dist/setup-form.js.map +1 -1
  374. package/dist/setup-host.d.ts +6 -1
  375. package/dist/setup-host.js +15 -4
  376. package/dist/setup-host.js.map +1 -1
  377. package/dist/setup-wizard.js +6 -3
  378. package/dist/setup-wizard.js.map +1 -1
  379. package/dist/spawn-gate.d.ts +5 -0
  380. package/dist/spawn-gate.js +28 -8
  381. package/dist/spawn-gate.js.map +1 -1
  382. package/dist/start-attempt.d.ts +1 -0
  383. package/dist/start-attempt.js +18 -0
  384. package/dist/start-attempt.js.map +1 -0
  385. package/dist/start-failure-notice.d.ts +4 -0
  386. package/dist/start-failure-notice.js +20 -0
  387. package/dist/start-failure-notice.js.map +1 -0
  388. package/dist/start-failure.d.ts +147 -0
  389. package/dist/start-failure.js +281 -0
  390. package/dist/start-failure.js.map +1 -0
  391. package/dist/startup-memory-deadline.d.ts +23 -0
  392. package/dist/startup-memory-deadline.js +55 -0
  393. package/dist/startup-memory-deadline.js.map +1 -0
  394. package/dist/statusline-watcher.js.map +1 -1
  395. package/dist/storm-window.js.map +1 -1
  396. package/dist/systemd-peer-bus.js.map +1 -1
  397. package/dist/target-queue-worker.js.map +1 -1
  398. package/dist/task-board-summary.d.ts +101 -0
  399. package/dist/task-board-summary.js +177 -0
  400. package/dist/task-board-summary.js.map +1 -0
  401. package/dist/task-board-tool.d.ts +25 -0
  402. package/dist/task-board-tool.js +155 -0
  403. package/dist/task-board-tool.js.map +1 -0
  404. package/dist/task-board-waker.d.ts +51 -0
  405. package/dist/task-board-waker.js +141 -0
  406. package/dist/task-board-waker.js.map +1 -0
  407. package/dist/tips.js.map +1 -1
  408. package/dist/tmux-control.js +1 -1
  409. package/dist/tmux-control.js.map +1 -1
  410. package/dist/tmux-exec-helper.d.ts +104 -0
  411. package/dist/tmux-exec-helper.js +412 -0
  412. package/dist/tmux-exec-helper.js.map +1 -0
  413. package/dist/tmux-manager.d.ts +1 -0
  414. package/dist/tmux-manager.js +29 -13
  415. package/dist/tmux-manager.js.map +1 -1
  416. package/dist/tmux-read.js +2 -2
  417. package/dist/tmux-read.js.map +1 -1
  418. package/dist/tool-permissions.js +9 -42
  419. package/dist/tool-permissions.js.map +1 -1
  420. package/dist/tool-progress.js.map +1 -1
  421. package/dist/topic-archiver.js.map +1 -1
  422. package/dist/topic-commands.d.ts +13 -0
  423. package/dist/topic-commands.js +56 -33
  424. package/dist/topic-commands.js.map +1 -1
  425. package/dist/topic-link.js.map +1 -1
  426. package/dist/transcript-delta-reader.js.map +1 -1
  427. package/dist/transcript-jsonl.js.map +1 -1
  428. package/dist/transcript-monitor.js +5 -0
  429. package/dist/transcript-monitor.js.map +1 -1
  430. package/dist/transcript-sources.d.ts +2 -0
  431. package/dist/transcript-sources.js +4 -0
  432. package/dist/transcript-sources.js.map +1 -1
  433. package/dist/tunnel/cloudflared-install.js +3 -1
  434. package/dist/tunnel/cloudflared-install.js.map +1 -1
  435. package/dist/tunnel/cloudflared.d.ts +7 -16
  436. package/dist/tunnel/cloudflared.js +100 -13
  437. package/dist/tunnel/cloudflared.js.map +1 -1
  438. package/dist/tunnel/lease.js +3 -2
  439. package/dist/tunnel/lease.js.map +1 -1
  440. package/dist/tunnel/manager.js.map +1 -1
  441. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  442. package/dist/tunnel/named-diagnostics.js +52 -0
  443. package/dist/tunnel/named-diagnostics.js.map +1 -0
  444. package/dist/tunnel/public-fetch.js.map +1 -1
  445. package/dist/tunnel/purpose-lane.js.map +1 -1
  446. package/dist/tunnel/types.d.ts +4 -1
  447. package/dist/tunnel/types.js.map +1 -1
  448. package/dist/types.d.ts +55 -2
  449. package/dist/ui/app-effects.js +27 -5
  450. package/dist/ui/app.html +2 -0
  451. package/dist/ui/backend-signin.js +297 -0
  452. package/dist/ui/chat-effects.js +15 -7
  453. package/dist/ui/chat-msg-actions.js +176 -0
  454. package/dist/ui/chat-render.js +67 -20
  455. package/dist/ui/chat-store.js +218 -48
  456. package/dist/ui/chat-strings.js +42 -10
  457. package/dist/ui/chat-thread.js +249 -23
  458. package/dist/ui/effect-trial-controller.js +13 -8
  459. package/dist/ui/effect-trial-offer.js +2 -31
  460. package/dist/ui/effects-waker.js +2 -0
  461. package/dist/ui/fleet-canvas-layout.js +13 -4
  462. package/dist/ui/fleet-canvas.js +120 -43
  463. package/dist/ui/fleet-office-editor.js +149 -0
  464. package/dist/ui/fleet-office-model.js +358 -0
  465. package/dist/ui/fleet-office-pack.js +199 -0
  466. package/dist/ui/fleet-office-skin.js +474 -0
  467. package/dist/ui/fleet-office-store.js +49 -0
  468. package/dist/ui/fleet-office-zones.js +177 -0
  469. package/dist/ui/fleet-office.js +434 -0
  470. package/dist/ui/fleet-org.js +21 -8
  471. package/dist/ui/fleet-route-scene.js +272 -0
  472. package/dist/ui/fleet-route-worker.js +21 -0
  473. package/dist/ui/fleet-route.js +88 -0
  474. package/dist/ui/fleet-task-card.js +436 -0
  475. package/dist/ui/fleet-task-common.js +482 -0
  476. package/dist/ui/fleet-task-work.js +107 -0
  477. package/dist/ui/fleet-tasks.js +569 -0
  478. package/dist/ui/fleet-traffic.js +227 -45
  479. package/dist/ui/fleet-usage.js +36 -2
  480. package/dist/ui/guest-refused.html +41 -0
  481. package/dist/ui/icons/icon-192.png +0 -0
  482. package/dist/ui/icons/icon-512.png +0 -0
  483. package/dist/ui/image-lightbox.js +45 -1
  484. package/dist/ui/image-zoom.js +242 -0
  485. package/dist/ui/panel-chat.js +282 -89
  486. package/dist/ui/panel-details.js +2 -0
  487. package/dist/ui/panel-fleet.js +32 -71
  488. package/dist/ui/panel-needs.js +23 -6
  489. package/dist/ui/panel-settings.js +158 -32
  490. package/dist/ui/preview-panel.js +2 -1
  491. package/dist/ui/search-dialog.js +350 -0
  492. package/dist/ui/settings-appearance.js +170 -10
  493. package/dist/ui/settings-apply.js +3 -3
  494. package/dist/ui/settings-confirm.js +7 -2
  495. package/dist/ui/settings-dialogs.js +46 -21
  496. package/dist/ui/settings-discord.js +6 -2
  497. package/dist/ui/settings-guests.js +2 -1
  498. package/dist/ui/settings-learn.js +1 -0
  499. package/dist/ui/settings-model.js +51 -18
  500. package/dist/ui/settings-mods.js +8 -3
  501. package/dist/ui/settings-owner-effects.js +6 -4
  502. package/dist/ui/settings-strings.js +180 -6
  503. package/dist/ui/settings-token.js +3 -1
  504. package/dist/ui/settings-web-authority.js +13 -5
  505. package/dist/ui/settings-wizard.js +13 -7
  506. package/dist/ui/shared/agend-auth.js +3 -1
  507. package/dist/ui/shared/app-i18n.js +12 -5
  508. package/dist/ui/shared/app-needs.js +2 -2
  509. package/dist/ui/shared/app-prefs.js +15 -0
  510. package/dist/ui/shared/app-route.js +18 -0
  511. package/dist/ui/shared/app-shell.js +172 -28
  512. package/dist/ui/shared/app-store.js +3 -2
  513. package/dist/ui/shared/app-stream.js +7 -2
  514. package/dist/ui/shared/app-themes.js +116 -1
  515. package/dist/ui/shared/app.css +681 -54
  516. package/dist/ui/shared/app.js +9 -1
  517. package/dist/ui/shared/card-strings.js +4 -0
  518. package/dist/ui/shared/effect-app-runtime.js +7 -5
  519. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  520. package/dist/ui/shared/effect-cursor.js +3 -2
  521. package/dist/ui/shared/effect-display-metadata.js +39 -0
  522. package/dist/ui/shared/effect-owner-source.js +8 -1
  523. package/dist/ui/shared/effect-policy.js +2 -2
  524. package/dist/ui/shared/effect-registry.js +30 -11
  525. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  526. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  527. package/dist/ui/shared/effect-stock-trust.js +40 -9
  528. package/dist/ui/shared/effect-trial-source.js +1 -1
  529. package/dist/ui/shared/effect-trial-stage.js +27 -21
  530. package/dist/ui/shared/effect-trial.css +1 -1
  531. package/dist/ui/shared/feature-flags.js +127 -0
  532. package/dist/ui/shared/guest-refused.js +35 -0
  533. package/dist/ui/shared/header-tools.js +2 -2
  534. package/dist/ui/shared/identity-card.js +26 -8
  535. package/dist/ui/shared/identity-color.js +17 -10
  536. package/dist/ui/shared/instance-nav.js +183 -28
  537. package/dist/ui/shared/owner-css.js +30 -1
  538. package/dist/ui/shared/panel-view.js +14 -29
  539. package/dist/ui/shared/text-undo.js +210 -0
  540. package/dist/ui/shared/tokens.css +13 -3
  541. package/dist/ui/shared/ui-dialog.js +5 -4
  542. package/dist/ui/shared/ui-icons.js +4 -0
  543. package/dist/ui/shared/ui-menu.js +20 -7
  544. package/dist/ui/shared/ui-toast.js +16 -3
  545. package/dist/ui/shared/usage-dialog.js +206 -16
  546. package/dist/ui/shared/view-strings.js +68 -4
  547. package/dist/ui/shared/web-authorize.js +50 -1
  548. package/dist/ui/signin.html +2 -0
  549. package/dist/ui/web-terminal/terminal.css +4 -4
  550. package/dist/ui/web-terminal/terminal.html +10 -10
  551. package/dist/ui/web-terminal/terminal.js +58 -12
  552. package/dist/update-check.js.map +1 -1
  553. package/dist/update-dispatch.js +1 -1
  554. package/dist/update-dispatch.js.map +1 -1
  555. package/dist/update-install.js.map +1 -1
  556. package/dist/update-launch.d.ts +10 -1
  557. package/dist/update-launch.js +39 -14
  558. package/dist/update-launch.js.map +1 -1
  559. package/dist/update-marker.js.map +1 -1
  560. package/dist/update-preflight.js +1 -1
  561. package/dist/update-preflight.js.map +1 -1
  562. package/dist/update-progress.d.ts +3 -1
  563. package/dist/update-progress.js +3 -1
  564. package/dist/update-progress.js.map +1 -1
  565. package/dist/usage/format-rich.js +6 -3
  566. package/dist/usage/format-rich.js.map +1 -1
  567. package/dist/usage/i18n-keys.d.ts +1 -1
  568. package/dist/usage/i18n-keys.js +2 -1
  569. package/dist/usage/i18n-keys.js.map +1 -1
  570. package/dist/usage/i18n.d.ts +13 -1
  571. package/dist/usage/i18n.js +29 -0
  572. package/dist/usage/i18n.js.map +1 -1
  573. package/dist/usage/providers.d.ts +89 -2
  574. package/dist/usage/providers.js +247 -41
  575. package/dist/usage/providers.js.map +1 -1
  576. package/dist/usage/statusline-usage.js.map +1 -1
  577. package/dist/usage/usage-api.d.ts +5 -1
  578. package/dist/usage/usage-api.js +185 -58
  579. package/dist/usage/usage-api.js.map +1 -1
  580. package/dist/usage-report.js.map +1 -1
  581. package/dist/usage-rollup.js +1 -1
  582. package/dist/usage-rollup.js.map +1 -1
  583. package/dist/user-systemd.d.ts +24 -0
  584. package/dist/user-systemd.js +75 -0
  585. package/dist/user-systemd.js.map +1 -0
  586. package/dist/view-api.d.ts +7 -0
  587. package/dist/view-api.js +16 -4
  588. package/dist/view-api.js.map +1 -1
  589. package/dist/wake-coordinator.js.map +1 -1
  590. package/dist/web-ambient.js +9 -2
  591. package/dist/web-ambient.js.map +1 -1
  592. package/dist/web-api.d.ts +58 -10
  593. package/dist/web-api.js +1104 -71
  594. package/dist/web-api.js.map +1 -1
  595. package/dist/web-app-icon-worker.d.ts +1 -0
  596. package/dist/web-app-icon-worker.js +16 -0
  597. package/dist/web-app-icon-worker.js.map +1 -0
  598. package/dist/web-app-icon.d.ts +109 -0
  599. package/dist/web-app-icon.js +257 -0
  600. package/dist/web-app-icon.js.map +1 -0
  601. package/dist/web-appearance-policy.js.map +1 -1
  602. package/dist/web-appearance-tools.d.ts +1 -0
  603. package/dist/web-appearance-tools.js +7 -3
  604. package/dist/web-appearance-tools.js.map +1 -1
  605. package/dist/web-appearance-view.js.map +1 -1
  606. package/dist/web-appearance.d.ts +4 -10
  607. package/dist/web-appearance.js +7 -4
  608. package/dist/web-appearance.js.map +1 -1
  609. package/dist/web-auth.d.ts +8 -4
  610. package/dist/web-auth.js +33 -21
  611. package/dist/web-auth.js.map +1 -1
  612. package/dist/web-backend-login.d.ts +130 -0
  613. package/dist/web-backend-login.js +225 -0
  614. package/dist/web-backend-login.js.map +1 -0
  615. package/dist/web-card.js.map +1 -1
  616. package/dist/web-channel-echo.js.map +1 -1
  617. package/dist/web-chat-history.d.ts +118 -8
  618. package/dist/web-chat-history.js +220 -25
  619. package/dist/web-chat-history.js.map +1 -1
  620. package/dist/web-commands.d.ts +5 -1
  621. package/dist/web-commands.js +1 -1
  622. package/dist/web-commands.js.map +1 -1
  623. package/dist/web-cookie-names.d.ts +5 -0
  624. package/dist/web-cookie-names.js +12 -0
  625. package/dist/web-cookie-names.js.map +1 -0
  626. package/dist/web-effect-bundle.d.ts +2 -2
  627. package/dist/web-effect-library.js.map +1 -1
  628. package/dist/web-effect-playback.js.map +1 -1
  629. package/dist/web-effect-profiles.d.ts +16 -16
  630. package/dist/web-effect-profiles.js +3 -2
  631. package/dist/web-effect-profiles.js.map +1 -1
  632. package/dist/web-effect-service.js.map +1 -1
  633. package/dist/web-effect-tools.js.map +1 -1
  634. package/dist/web-effect-trials.js.map +1 -1
  635. package/dist/web-effect-upload.js.map +1 -1
  636. package/dist/web-effect.d.ts +6 -6
  637. package/dist/web-effect.js.map +1 -1
  638. package/dist/web-experimental-http.d.ts +2 -0
  639. package/dist/web-experimental-http.js +12 -0
  640. package/dist/web-experimental-http.js.map +1 -0
  641. package/dist/web-experimental.d.ts +11 -0
  642. package/dist/web-experimental.js +49 -0
  643. package/dist/web-experimental.js.map +1 -0
  644. package/dist/web-guest-access.d.ts +4 -2
  645. package/dist/web-guest-access.js +22 -10
  646. package/dist/web-guest-access.js.map +1 -1
  647. package/dist/web-guest-rooms.js.map +1 -1
  648. package/dist/web-host-guard.d.ts +11 -0
  649. package/dist/web-host-guard.js +11 -0
  650. package/dist/web-host-guard.js.map +1 -1
  651. package/dist/web-icons.d.ts +33 -1
  652. package/dist/web-icons.js +83 -11
  653. package/dist/web-icons.js.map +1 -1
  654. package/dist/web-identity-color.js.map +1 -1
  655. package/dist/web-image-meta.d.ts +13 -0
  656. package/dist/web-image-meta.js +62 -0
  657. package/dist/web-image-meta.js.map +1 -1
  658. package/dist/web-images.js.map +1 -1
  659. package/dist/web-libavoid.d.ts +14 -0
  660. package/dist/web-libavoid.js +46 -0
  661. package/dist/web-libavoid.js.map +1 -0
  662. package/dist/web-login.js.map +1 -1
  663. package/dist/web-mentions.js.map +1 -1
  664. package/dist/web-mod-agent.js.map +1 -1
  665. package/dist/web-mod-store.d.ts +2 -0
  666. package/dist/web-mod-store.js +10 -0
  667. package/dist/web-mod-store.js.map +1 -1
  668. package/dist/web-office-store.d.ts +104 -0
  669. package/dist/web-office-store.js +236 -0
  670. package/dist/web-office-store.js.map +1 -0
  671. package/dist/web-owner-css-store.d.ts +44 -1
  672. package/dist/web-owner-css-store.js +70 -9
  673. package/dist/web-owner-css-store.js.map +1 -1
  674. package/dist/web-owner-css.js.map +1 -1
  675. package/dist/web-png.d.ts +33 -0
  676. package/dist/web-png.js +329 -0
  677. package/dist/web-png.js.map +1 -0
  678. package/dist/web-prefs.d.ts +6 -0
  679. package/dist/web-prefs.js +29 -3
  680. package/dist/web-prefs.js.map +1 -1
  681. package/dist/web-preview.d.ts +2 -0
  682. package/dist/web-preview.js +2 -0
  683. package/dist/web-preview.js.map +1 -1
  684. package/dist/web-profile.js.map +1 -1
  685. package/dist/web-reactions.d.ts +35 -0
  686. package/dist/web-reactions.js +47 -0
  687. package/dist/web-reactions.js.map +1 -0
  688. package/dist/web-request-context.d.ts +5 -0
  689. package/dist/web-request-context.js.map +1 -1
  690. package/dist/web-returning-device.d.ts +4 -2
  691. package/dist/web-returning-device.js +13 -6
  692. package/dist/web-returning-device.js.map +1 -1
  693. package/dist/web-schedules.js.map +1 -1
  694. package/dist/web-send-dedupe.d.ts +36 -0
  695. package/dist/web-send-dedupe.js +69 -0
  696. package/dist/web-send-dedupe.js.map +1 -0
  697. package/dist/web-session-authorization.js.map +1 -1
  698. package/dist/web-session.js +1 -1
  699. package/dist/web-session.js.map +1 -1
  700. package/dist/web-settings-patch.d.ts +3 -1
  701. package/dist/web-settings-patch.js +11 -5
  702. package/dist/web-settings-patch.js.map +1 -1
  703. package/dist/web-settings-tools.d.ts +6 -0
  704. package/dist/web-settings-tools.js +52 -17
  705. package/dist/web-settings-tools.js.map +1 -1
  706. package/dist/web-terminal-http.js +15 -2
  707. package/dist/web-terminal-http.js.map +1 -1
  708. package/dist/web-terminal.js +1 -1
  709. package/dist/web-terminal.js.map +1 -1
  710. package/dist/web-theme-store.d.ts +2 -2
  711. package/dist/web-theme-store.js +6 -3
  712. package/dist/web-theme-store.js.map +1 -1
  713. package/dist/web-theme.d.ts +29 -0
  714. package/dist/web-theme.js +89 -1
  715. package/dist/web-theme.js.map +1 -1
  716. package/dist/web-upload.d.ts +18 -1
  717. package/dist/web-upload.js +45 -7
  718. package/dist/web-upload.js.map +1 -1
  719. package/dist/web-widget.js.map +1 -1
  720. package/dist/webhook-emitter.js.map +1 -1
  721. package/dist/windows-shortcuts.d.ts +78 -0
  722. package/dist/windows-shortcuts.js +203 -0
  723. package/dist/windows-shortcuts.js.map +1 -0
  724. package/dist/workflow-templates/default.md +4 -1
  725. package/dist/ws-server.js.map +1 -1
  726. package/dist/yaml-shared-nodes.d.ts +25 -0
  727. package/dist/yaml-shared-nodes.js +185 -0
  728. package/dist/yaml-shared-nodes.js.map +1 -0
  729. package/launcher/agend-install.cjs +828 -0
  730. package/launcher/install-admission.cjs +4 -39
  731. package/launcher/postinstall.cjs +14 -12
  732. package/launcher/private-home.cjs +43 -0
  733. package/package.json +16 -13
  734. package/scripts/preinstall-guard.cjs +2 -5
  735. package/templates/windows-shortcuts.ps1 +181 -0
  736. package/launcher/old-updater-note.cjs +0 -48
@@ -5,7 +5,7 @@ import { chatEffectIdentity } from "/assets/effect-chat-runtime.js";
5
5
  const owners = new WeakSet(), safe = fn => { try { return fn(); } catch { return null; } };
6
6
  const LIMIT = 128 * 1024;
7
7
  export function createEffectTrialController({ window: host, current, allowed, onStart, onChange = () => {} }) {
8
- let dead = false, active = null, physical = null, previous = null, broken = false, clockBusy = false;
8
+ let dead = false, active = null, physical = null, previous = null, broken = false, clockBusy = false, endedReason = null, endedOffer = null;
9
9
  const cleanup = [], releases = [], identity = safe(() => chatEffectIdentity(host));
10
10
  const tell = () => { if (!dead) safe(onChange); };
11
11
  function clock() {
@@ -26,11 +26,16 @@ export function createEffectTrialController({ window: host, current, allowed, on
26
26
  }
27
27
  function end(op, reason = "stopped") {
28
28
  if (!op || op.dead) return false;
29
- op.dead = true; if (active === op) active = null; safe(() => op.resolve?.(false));
29
+ op.dead = true; if (active === op) active = null;
30
+ endedReason = typeof reason === "string" && /^[a-z][a-z0-9_]{0,79}$/.test(reason) ? reason : "trial_failed";
31
+ endedOffer = op.offer.offer;
32
+ safe(() => op.resolve?.(false));
30
33
  safe(() => host.clearTimeout(op.timer)); safe(() => op.controller.abort());
31
34
  if (op.reply && !op.stopQueued) { op.stopQueued = true; cleanup.push(op); }
32
35
  // Physical paint is removed before callbacks, cleanup I/O or another explicit click.
33
- safe(() => op.dispose?.()); op.dispose = null; tell(); drain(); return true;
36
+ safe(() => op.dispose?.()); op.dispose = null;
37
+ if (!["stopped", "replaced"].includes(endedReason)) safe(() => host.console?.warn("[AgEnD effects] Try stopped:", endedReason));
38
+ tell(); drain(); return true;
34
39
  }
35
40
  function arm(op) {
36
41
  safe(() => host.clearTimeout(op.timer));
@@ -67,7 +72,7 @@ export function createEffectTrialController({ window: host, current, allowed, on
67
72
  if (dead) return; dead = true; end(active); for (const off of releases.splice(0)) safe(off); tell();
68
73
  }
69
74
  const api = { ok: false, start: async () => false, stop: () => end(active), sync() { const op = active; if (op && !eligible(op)) end(op, "trial_ended"); },
70
- snapshot: () => Object.freeze({ busy: !!physical || cleanup.length > 0, phase: active ? active.reply ? "running" : "starting" : "idle" }), dispose };
75
+ snapshot: () => Object.freeze({ busy: !!physical || cleanup.length > 0, phase: active ? active.reply ? "running" : "starting" : "idle", reason: active ? null : endedReason, offer: active ? active.offer.offer : endedOffer }), dispose };
71
76
  if (!identity || owners.has(host) || typeof current !== "function" || typeof allowed !== "function" || typeof onStart !== "function"
72
77
  || typeof host.AgendAuth?.trialSession !== "function" || typeof host.AgendAuth?.onSessionEnd !== "function") return Object.freeze(api);
73
78
  owners.add(host);
@@ -75,7 +80,7 @@ export function createEffectTrialController({ window: host, current, allowed, on
75
80
  const off = host.AgendAuth.onSessionEnd(dispose);
76
81
  if (dead) { safe(off); return Object.freeze(api); }
77
82
  releases.push(off);
78
- for (const [target, type, fn] of [[host, "blur", () => end(active)], [host, "pagehide", dispose], [host.document, "visibilitychange", () => { if (host.document.visibilityState !== "visible") end(active); }]]) {
83
+ for (const [target, type, fn] of [[host, "blur", () => end(active, "trial_window_blur")], [host, "pagehide", dispose], [host.document, "visibilitychange", () => { if (host.document.visibilityState !== "visible") end(active, "hidden"); }]]) {
79
84
  target.addEventListener(type, fn); releases.push(() => target.removeEventListener(type, fn));
80
85
  }
81
86
  } catch { dispose(); return Object.freeze(api); }
@@ -86,7 +91,7 @@ export function createEffectTrialController({ window: host, current, allowed, on
86
91
  const offer = safe(() => effectTrialMessage(message)), instance = safe(() => message.instance), began = clock();
87
92
  if (!offer || began === null || began + 10000 > Number.MAX_SAFE_INTEGER || safe(() => host.Date.now() < offer.expiresAt) !== true) return false;
88
93
  const op = { instance, offer, began, until: began + 10000, controller: new host.AbortController(), timer: null, reply: null, dead: false, stopQueued: false, dispose: null };
89
- active = op; const token = {}; physical = token;
94
+ endedReason = null; endedOffer = null; active = op; const token = {}; physical = token;
90
95
  const cancelled = new Promise(resolve => { op.resolve = resolve; });
91
96
  const work = Promise.resolve().then(async () => {
92
97
  if (!eligible(op)) return false;
@@ -105,12 +110,12 @@ export function createEffectTrialController({ window: host, current, allowed, on
105
110
  op.until = began + reply.remainingMs;
106
111
  if (op.until > Number.MAX_SAFE_INTEGER || !eligible(op)) return false;
107
112
  arm(op);
108
- const handle = Object.freeze({ reply, startedAt: began, instance, current: () => eligible(op), stop: () => end(op), });
113
+ const handle = Object.freeze({ reply, startedAt: began, instance, current: () => eligible(op), stop: (reason = "stopped") => end(op, reason), });
109
114
  const disposer = onStart(handle);
110
115
  if (typeof disposer !== "function") return false;
111
116
  if (!eligible(op)) { safe(disposer); return false; }
112
117
  op.dispose = disposer; tell(); return eligible(op);
113
- }).catch(() => false).then(ok => { if (!ok) end(op); return ok; }).finally(() => { if (physical === token) physical = null; tell(); drain(); });
118
+ }).catch(() => false).then(ok => { if (!ok) end(op, "trial_start_failed"); return ok; }).finally(() => { if (physical === token) physical = null; tell(); drain(); });
114
119
  // The logical caller may stop immediately, while the physical request/cancel still owns the lane.
115
120
  tell();
116
121
  return Promise.race([work, cancelled]);
@@ -1,31 +1,2 @@
1
- /** #1629: closed host display metadata. Neither this object nor its token grants a trial read. */
2
- const KEYS = ["v", "offer", "id", "title", "expiresAt"], ID = /^[0-9a-f]{32}$/;
3
- const FORBIDDEN = /(?!\u200d)[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
4
- const VISIBLE = /[^\p{M}\p{C}\p{Z}\u115f\u1160\u3164\uffa0\u2800]/u;
5
- let graphemes = null;
6
- export function checkEffectTrialOffer(value) {
7
- try {
8
- if (!value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return null;
9
- const keys = Reflect.ownKeys(value);
10
- if (keys.length !== KEYS.length || keys.some(k => typeof k !== "string" || !KEYS.includes(k))) return null;
11
- const x = Object.create(null);
12
- for (const key of KEYS) {
13
- const d = Object.getOwnPropertyDescriptor(value, key);
14
- if (!d || !("value" in d) || !d.enumerable) return null;
15
- x[key] = d.value;
16
- }
17
- if (x.v !== 1 || typeof x.offer !== "string" || !ID.test(x.offer) || typeof x.id !== "string" || !ID.test(x.id)
18
- || typeof x.title !== "string" || x.title.length > 400 || x.title.normalize("NFC") !== x.title || x.title.trim() !== x.title
19
- || FORBIDDEN.test(x.title) || !VISIBLE.test(x.title) || !Number.isSafeInteger(x.expiresAt) || x.expiresAt < 0) return null;
20
- graphemes ??= new Intl.Segmenter(undefined, { granularity: "grapheme" });
21
- let count = 0; for (const _part of graphemes.segment(x.title)) if (++count > 40) return null;
22
- if (count < 1) return null;
23
- return Object.freeze({ v: 1, offer: x.offer, id: x.id, title: x.title, expiresAt: x.expiresAt });
24
- } catch { return null; }
25
- }
26
- /** Role and sender are host fields, never inferred from a message's text. Start must separately authorize. */
27
- export function effectTrialMessage(message) {
28
- if (!message || message.role !== "status" || message.sender !== "agend" || typeof message.instance !== "string"
29
- || message.instance.length < 1 || message.instance.length > 128) return null;
30
- return checkEffectTrialOffer(message.effectTrial);
31
- }
1
+ // On-only Canvas Worker display validation; ordinary chat boot imports no parser.
2
+ export { checkEffectTrialOffer, effectTrialMessage } from "/assets/effect-display-metadata.js";
@@ -0,0 +1,2 @@
1
+ // Compatibility entry for opted-in effect consumers. Product boot uses the neutral feature policy.
2
+ export { EMPTY_CHAT_EFFECTS, chatHasEffects, getAppEffects, effectsAwake, effectsLoaded, onEffectsAwake, wakeEffects, startEffectsWaker } from "/assets/feature-flags.js";
@@ -1,9 +1,18 @@
1
1
  // #1918: the org canvas's layout (fleet-canvas.js draws it; fleet-traffic.js routes lines through its empty lanes).
2
2
  // Fixed slots, no layout engine: the same structure always gives the same picture.
3
3
 
4
- /** Sizes in canvas units. NW×NH a member card, LW×LH a General card; FOLDED a folded (or empty) team's height. */
5
- export const OC = { NW: 184, NH: 56, GAP: 18, PAD: 24, HEAD: 34, TEAM_GAP: 56, ROW_GAP: 96, ROW_MAX: 1400, ROW_MAX_NARROW: 460, LW: 232, LH: 68, TOP_Y: 20, BUS: 44, FOLDED: 64, TRUNK: -30 };
4
+ /**
5
+ * Sizes in canvas units. NW×NH a member card, LW×LH a General card; FOLDED a folded (or empty) team's height. GAP and
6
+ * PAD (#2182): the gutters between cards and a box's padding are the traffic lines' channels inside a box — wide
7
+ * enough that the router (fleet-route-scene.js) keeps a few lines apart in each; a phone's narrow packing keeps the
8
+ * tighter GAP_NARROW and PAD_NARROW, so General and the first team still open at a readable size. A layout says which
9
+ * it used (L.gap, L.pad).
10
+ */
11
+ export const OC = { NW: 184, NH: 56, GAP: 28, PAD: 32, GAP_NARROW: 18, PAD_NARROW: 24, HEAD: 34, TEAM_GAP: 72, ROW_GAP: 96, ROW_MAX: 1400, ROW_MAX_NARROW: 460, LW: 232, LH: 68, TOP_Y: 20, BUS: 44, FOLDED: 64, TRUNK: -30 };
6
12
  const colsFor = (n, narrow) => (n <= 1 ? 1 : n <= 4 || narrow ? 2 : 3);
13
+ /** A search's needle, and whether a node matches it (its name or nickname): the canvas's Find, the Office view's too. */
14
+ export const needle = (q) => String(q || "").trim().toLowerCase();
15
+ export const hits = (node, q) => !!q && (node.name.toLowerCase().includes(q) || (!!node.i && typeof node.i.display_name === "string" && node.i.display_name.toLowerCase().includes(q)));
7
16
  /** The key a team folds by (per device): its name; the instances in no team have one of their own no team name can be. */
8
17
  export const REST_KEY = "\u0000rest";
9
18
 
@@ -13,7 +22,7 @@ export const REST_KEY = "\u0000rest";
13
22
  * size of the whole. `narrow`: a phone's packing.
14
23
  */
15
24
  export function canvasLayout(view, folded = new Set(), { narrow = false, label = (s, n) => `${n} ${s}` } = {}) {
16
- const { NW, NH, GAP, PAD, HEAD } = OC;
25
+ const { NW, NH, HEAD } = OC, GAP = narrow ? OC.GAP_NARROW : OC.GAP, PAD = narrow ? OC.PAD_NARROW : OC.PAD;
17
26
  const groups = [...view.teams.map((tm) => ({ key: tm.name, name: tm.name, loose: false, nodes: tm.nodes, counts: tm.counts })),
18
27
  ...(view.rest.nodes.length ? [{ key: REST_KEY, name: null, loose: true, nodes: view.rest.nodes, counts: view.rest.counts }] : [])];
19
28
  const rows = [];
@@ -49,7 +58,7 @@ export function canvasLayout(view, folded = new Set(), { narrow = false, label =
49
58
  const width = Math.max(rowsW, topW);
50
59
  const tops = view.top.map((node, i) => ({ node, key: `\u0000top/${node.name}`, x: width / 2 - topW / 2 + i * (OC.LW + GAP), y: OC.TOP_Y, w: OC.LW, h: OC.LH }));
51
60
  const height = boxes.length ? y - OC.ROW_GAP : tops.length ? OC.TOP_Y + OC.LH : 0;
52
- return { tops, boxes, width, height, tree: treeLines(tops, boxes) };
61
+ return { tops, boxes, width, height, tree: treeLines(tops, boxes), gap: GAP, pad: PAD };
53
62
  }
54
63
 
55
64
  /** A folded team's summary line height, and a label's width estimate (canvas units: wide for CJK, narrow otherwise). */
@@ -8,13 +8,16 @@
8
8
  // a team or searching never moves another one. Tree lines: a stem from General, a bus over each row, a trunk at the
9
9
  // left joining the rows, one drop per team — never a line per member (the box says who is in it). A phone packs
10
10
  // narrower (one team a row, at most two columns), so General and the first team open readable.
11
- // - Per device (localStorage; blocked storage: this page only): Canvas or List, and which teams are folded. The view
12
- // itself is not kept: it opens on General and the first row (#1918's user decision 2) — on a desktop as wide as the
13
- // panel allows (no larger than life), on a phone no smaller than readable. 0 / Fit shows the whole fleet.
11
+ // - Per device (localStorage; blocked storage: this page only): Canvas, List or Office (fleet-office.js: the same fleet
12
+ // as a pixel office), and which teams are folded. The view itself is not kept: it opens on General and the first row
13
+ // (#1918's user decision 2) — on a desktop as wide as the panel allows (no larger than life), on a phone no smaller
14
+ // than readable. 0 / Fit shows the whole fleet.
14
15
  // - Presentation only, like the list: a card opens that instance's chat; nothing is edited here (#1689 is how teams
15
16
  // change). The live state is the app store's (fleet-org.js buildOrgView), so the canvas moves with the stream.
16
17
  // - Live traffic (fleet-traffic.js): the messages between instances, drawn between the team boxes and the cards (never
17
18
  // hidden under a box, never across a name). Live on or off per device; the list says it in words ("Sending: …").
19
+ // #2182: routed around the cards and through the boxes' doors by libavoid in a worker (fleet-route-scene.js), each
20
+ // line from card to card; the lanes are the fallback.
18
21
  import { html, useEffect, useLayoutEffect, useMemo, useRef, useState } from "/assets/app-html.js";
19
22
  import { appStore } from "/assets/app-store.js";
20
23
  import { t, register } from "/assets/app-i18n.js";
@@ -22,30 +25,35 @@ import { chatPath } from "/assets/app-route.js";
22
25
  import { navigate } from "/assets/app-nav.js";
23
26
  import { Empty, Skeleton } from "/assets/ui-states.js";
24
27
  import { Icon } from "/assets/ui-icons.js";
25
- import { avatarOf, backendLabel, firstCharacter, namesOf } from "/assets/instance-nav.js";
28
+ import { avatarOf, firstCharacter, namesOf } from "/assets/instance-nav.js";
26
29
  import { identityClasses, identityOf, paintIdentity, useIdentityColors } from "/assets/identity-color.js";
27
- import { buildOrgView, OrgChart, OrgSummary } from "./fleet-org.js";
28
- import { OC, REST_KEY, SUM_LINE, canvasLayout, openingRegion, summaryRows } from "./fleet-canvas-layout.js";
29
- import { createTrafficStore, FAR_K, POLL_MS, sendingBy, trafficEdges } from "./fleet-traffic.js";
30
+ import { buildOrgView, nodeText, OrgChart, OrgSummary } from "./fleet-org.js";
31
+ import { Office } from "./fleet-office.js";
32
+ import { OC, REST_KEY, SUM_LINE, canvasLayout, hits, needle, openingRegion, summaryRows } from "./fleet-canvas-layout.js";
33
+ import { createTrafficStore, FAR_K, HEAD, POLL_MS, sendingBy, trafficEdges } from "./fleet-traffic.js";
34
+ import { routeScene } from "./fleet-route-scene.js";
35
+ import { createRouteClient } from "./fleet-route.js";
30
36
 
31
37
  register("orgc", {
32
38
  en: {
33
- view: "View", canvas: "Canvas", list: "List", find: "Find an instance", findShort: "Find", found: "{0} found", foundOne: "1 found", noMatch: "No match",
39
+ view: "View", canvas: "Canvas", list: "List", office: "Office", find: "Find an instance", findShort: "Find", found: "{0} found", foundOne: "1 found", noMatch: "No match",
34
40
  zoomIn: "Zoom in", zoomOut: "Zoom out", fit: "Fit to screen",
35
41
  label: "Org chart canvas. Tab or the arrow keys move between instances, Enter opens a chat, + and − zoom, 0 fits the fleet.",
36
42
  expand: "Expand", collapse: "Collapse", members: "{0} members", member: "1 member", inFolded: "{0} found · expand", noMembers: "No members",
37
43
  openChat: "Open chat", minimap: "Overview: click to move there",
38
44
  live: "Live", liveOn: "Hide live traffic", liveOff: "Show live traffic", lgTask: "delegate_task", lgSend: "send_to_instance",
39
45
  lgReport: "report_result", lgBroadcast: "broadcast", lgQueued: "queued", lgFading: "delivered", lgTeam: "between teams", legend: "Key",
46
+ lgWork: "in progress (until its report)", lgReturn: "done (report back)", lgStale: "no report yet",
40
47
  },
41
48
  "zh-TW": {
42
- view: "檢視", canvas: "畫布", list: "清單", find: "尋找 instance", findShort: "尋找", found: "找到 {0} 個", foundOne: "找到 1 個", noMatch: "沒有符合的",
49
+ view: "檢視", canvas: "畫布", list: "清單", office: "辦公室", find: "尋找 instance", findShort: "尋找", found: "找到 {0} 個", foundOne: "找到 1 個", noMatch: "沒有符合的",
43
50
  zoomIn: "放大", zoomOut: "縮小", fit: "符合畫面",
44
51
  label: "組織圖畫布。用 Tab 或方向鍵在 instance 之間移動,Enter 開啟聊天,+ 和 − 縮放,0 顯示整個 fleet。",
45
52
  expand: "展開", collapse: "收合", members: "{0} 名成員", member: "1 名成員", inFolded: "找到 {0} 個 · 展開", noMembers: "沒有成員",
46
53
  openChat: "開啟聊天", minimap: "總覽:點一下移到那裡",
47
54
  live: "即時", liveOn: "隱藏即時往來", liveOff: "顯示即時往來", lgTask: "delegate_task", lgSend: "send_to_instance",
48
55
  lgReport: "report_result", lgBroadcast: "broadcast", lgQueued: "排隊中", lgFading: "已送達", lgTeam: "team 之間", legend: "圖例",
56
+ lgWork: "進行中(直到回報)", lgReturn: "完成(回報送回)", lgStale: "尚未回報",
49
57
  },
50
58
  });
51
59
  const tc = (k, ...v) => t(`orgc.${k}`, ...v);
@@ -84,7 +92,8 @@ export function zoomAt(v, f, cx, cy) {
84
92
  // ── Per device ──
85
93
 
86
94
  const MODE_KEY = "agend_org_mode", FOLD_KEY = "agend_org_folded", LIVE_KEY = "agend_org_live", KEY_KEY = "agend_org_key";
87
- function readMode() { try { return localStorage.getItem(MODE_KEY) === "list" ? "list" : "canvas"; } catch { return "canvas"; } }
95
+ const MODES = ["canvas", "list", "office"];
96
+ function readMode() { try { const m = localStorage.getItem(MODE_KEY); return MODES.includes(m) ? m : "canvas"; } catch { return "canvas"; } }
88
97
  function readLive() { try { return localStorage.getItem(LIVE_KEY) !== "0"; } catch { return true; } }
89
98
  function readFolded() {
90
99
  try { const a = JSON.parse(localStorage.getItem(FOLD_KEY) || "[]"); return new Set(Array.isArray(a) ? a.filter((x) => typeof x === "string").slice(0, 500) : []); } catch { return new Set(); }
@@ -112,8 +121,6 @@ export function clipText(s, n) {
112
121
  return `${out}…`;
113
122
  }
114
123
  const clip = clipText;
115
- const needle = (q) => String(q || "").trim().toLowerCase();
116
- const hits = (node, q) => !!q && (node.name.toLowerCase().includes(q) || (!!node.i && typeof node.i.display_name === "string" && node.i.display_name.toLowerCase().includes(q)));
117
124
 
118
125
  function Face({ it, name, cx, cy, r }) {
119
126
  const a = it ? avatarOf(it) : { kind: "initial", text: firstCharacter(name) };
@@ -130,10 +137,8 @@ function Face({ it, name, cx, cy, r }) {
130
137
 
131
138
  function Card({ c, lead, cls, onOpen }) {
132
139
  const n = c.node, it = n.i;
133
- const names = it ? namesOf(it) : { primary: n.name, secondary: "" };
140
+ const { primary, sub, full } = nodeText(n);
134
141
  const id = it ? identityOf(it) : null;
135
- const sub = it ? `${STATE_LABEL(n.state)} · ${backendLabel(it.backend)}` : STATE_LABEL(n.state);
136
- const full = `${names.primary}${names.secondary ? ` (${names.secondary})` : ""} — ${sub}`;
137
142
  const cy = c.h / 2;
138
143
  return html`<g class=${`oc-node st-${n.state}${lead ? " lead" : ""}${cls ? ` ${cls}` : ""} ${identityClasses(id)}`} ref=${(el) => paintIdentity(el, id)}
139
144
  transform=${`translate(${c.x} ${c.y})`} data-name=${n.name} data-key=${c.key} tabindex="0" role=${it ? "link" : "img"}
@@ -143,19 +148,36 @@ function Card({ c, lead, cls, onOpen }) {
143
148
  <rect class="oc-idbar" x="0" y="8" width="4" height=${c.h - 16} rx="2" />
144
149
  <${Face} it=${it} name=${n.name} cx=${26} cy=${cy} r=${16} />
145
150
  <circle class=${`oc-dot st-${n.state}`} cx=${38} cy=${cy + 12} r=${5} />
146
- <text class="oc-name" x=${50} y=${cy - 4}>${clip(names.primary, lead ? 20 : 15)}</text>
151
+ <text class="oc-name" x=${50} y=${cy - 4}>${clip(primary, lead ? 20 : 15)}</text>
147
152
  <text class="oc-sub" x=${50} y=${cy + 13}><tspan class=${`oc-st st-${n.state}`}>${clip(sub, lead ? 27 : 20)}</tspan></text>
148
153
  </g>`;
149
154
  }
150
155
 
151
- function TeamBox({ b, q, onFold }) {
152
- const name = b.name === null ? t("org.unteamed") : b.name;
153
- const found = q ? b.nodes.filter((n) => hits(n, q)).length : 0;
154
- const count = b.nodes.length === 1 ? tc("member") : tc("members", b.nodes.length);
155
- const toggle = (e) => { if (e.type === "click" || e.key === "Enter" || e.key === " ") { e.preventDefault(); e.stopPropagation(); onFold(b.key); } };
156
+ function teamName(b) { return b.name === null ? t("org.unteamed") : b.name; }
157
+ const foundIn = (b, q) => (q ? b.nodes.filter((n) => hits(n, q)).length : 0);
158
+
159
+ /** A team's box: its frame, header band and (folded) summary — under the traffic lines. */
160
+ function TeamBox({ b, q }) {
161
+ const found = foundIn(b, q);
156
162
  return html`<g class=${`oc-team${b.loose ? " loose" : ""}${q && !found ? " dim" : ""}`} data-team=${b.key}>
157
163
  <rect class=${`oc-box${b.folded && found ? " match" : ""}`} x=${b.x} y=${b.y} width=${b.w} height=${b.h} rx="12" />
158
164
  <rect class="oc-head" x=${b.x + 1} y=${b.y + 1} width=${b.w - 2} height=${OC.HEAD - 2} rx="11" />
165
+ ${!b.nodes.length ? html`<text class="oc-team-sum" x=${b.x + 14} y=${b.y + OC.HEAD + 18}>${tc("noMembers")}</text>` : null}
166
+ ${b.folded ? b.summary.flatMap((row, i) => row.map((it) => html`<g key=${it.s}>
167
+ <circle class=${`oc-dot st-${it.s}`} cx=${b.x + it.dx + 5} cy=${b.y + OC.HEAD + 14 + i * SUM_LINE} r="5" />
168
+ <text class="oc-team-sum" x=${b.x + it.dx + 14} y=${b.y + OC.HEAD + 18 + i * SUM_LINE}>${it.label}</text></g>`)) : null}
169
+ </g>`;
170
+ }
171
+
172
+ /**
173
+ * A team's header: the fold control, its name and count — above the traffic lines (#1918 review: a line leaving the box
174
+ * through its header ran over the count), so it stays readable and clickable.
175
+ */
176
+ function TeamHead({ b, q, onFold }) {
177
+ const name = teamName(b), found = foundIn(b, q);
178
+ const count = b.nodes.length === 1 ? tc("member") : tc("members", b.nodes.length);
179
+ const toggle = (e) => { if (e.type === "click" || e.key === "Enter" || e.key === " ") { e.preventDefault(); e.stopPropagation(); onFold(b.key); } };
180
+ return html`<g class=${`oc-team-head${q && !found ? " dim" : ""}`} data-team=${b.key}>
159
181
  <g class=${`oc-toggle${b.nodes.length ? "" : " empty"}`} tabindex=${b.nodes.length ? "0" : undefined} role=${b.nodes.length ? "button" : undefined}
160
182
  aria-expanded=${b.nodes.length ? String(!b.folded) : undefined} aria-label=${`${name}, ${count}.${b.nodes.length ? ` ${b.folded ? tc("expand") : tc("collapse")}.` : ""}`}
161
183
  onClick=${b.nodes.length ? toggle : undefined} onKeyDown=${b.nodes.length ? toggle : undefined}>
@@ -164,40 +186,61 @@ function TeamBox({ b, q, onFold }) {
164
186
  <text class="oc-team-name" x=${b.x + (b.nodes.length ? 28 : 14)} y=${b.y + 22}>${clip(name, Math.max(8, Math.floor((b.w - 90) / 7.5)))}</text>
165
187
  <text class="oc-team-meta" x=${b.x + b.w - 12} y=${b.y + 22} text-anchor="end">${b.folded && found ? tc("inFolded", found) : String(b.nodes.length)}</text>
166
188
  </g>
167
- ${!b.nodes.length ? html`<text class="oc-team-sum" x=${b.x + 14} y=${b.y + OC.HEAD + 18}>${tc("noMembers")}</text>` : null}
168
- ${b.folded ? b.summary.flatMap((row, i) => row.map((it) => html`<g key=${it.s}>
169
- <circle class=${`oc-dot st-${it.s}`} cx=${b.x + it.dx + 5} cy=${b.y + OC.HEAD + 14 + i * SUM_LINE} r="5" />
170
- <text class="oc-team-sum" x=${b.x + it.dx + 14} y=${b.y + OC.HEAD + 18 + i * SUM_LINE}>${it.label}</text></g>`)) : null}
171
189
  </g>`;
172
190
  }
173
191
 
192
+ /** What a card (or an Office desk) opens: that instance's chat. */
193
+ const openChat = (name) => navigate(chatPath(name));
194
+
174
195
  /** Every card, in the order Tab walks them (General, then each team's members in reading order). */
175
196
  const cardsOf = (L) => [...L.tops, ...L.boxes.flatMap((b) => b.cells)];
176
197
 
177
198
  const reducedMotion = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
178
199
 
179
- /** The traffic lines: dotted while queued, a dash and a pulse while delivering, fading once delivered; ×N on shared lines. */
200
+ /**
201
+ * The traffic lines: dotted while queued, a dash and a pulse while delivering, fading once delivered; a delegation's
202
+ * slow moving dash while its work is in progress, one pulse back when its report comes, a faint dash when none came;
203
+ * ×N on shared lines.
204
+ */
205
+ const MARKER = (e) => (e.phase === "fading" || e.phase === "stale" ? "fading" : e.hue);
180
206
  function TrafficLayer({ edges, q }) {
181
207
  const still = reducedMotion();
182
208
  return html`<g class="oc-flows" aria-hidden="true">${edges.map((e) => {
183
209
  const dim = q && !e.names.some((n) => n.toLowerCase().includes(q));
184
- return html`<g key=${e.key} class=${`oc-fl${dim ? " dim" : ""}`}>
210
+ return html`<g key=${e.key} class=${`oc-fl${dim ? " dim" : ""}`} data-routed=${e.routed ? "1" : undefined}>
185
211
  <path class="oc-flow-halo" d=${e.d} />
186
- <path class=${`oc-flow h-${e.hue} ph-${e.phase}`} d=${e.d} marker-start=${`url(#oc-src-${e.phase === "fading" ? "fading" : e.hue})`} marker-end=${`url(#oc-ah-${e.phase === "fading" ? "fading" : e.hue})`} />
212
+ <path class=${`oc-flow h-${e.hue} ph-${e.phase}`} d=${e.d} stroke-width=${e.w} marker-start=${`url(#oc-src-${MARKER(e)})`}
213
+ marker-end=${e.head ? `url(#oc-ah-${MARKER(e)})` : undefined} />
187
214
  ${e.phase === "live" && !still ? html`<circle class=${`oc-pulse h-${e.hue}`} r="4"><animateMotion dur=${`${Math.max(1.6, e.pts.length * 0.3)}s`} repeatCount="indefinite" path=${e.d} /></circle>` : null}
215
+ ${e.phase === "return" && !still ? html`<circle class=${`oc-pulse h-${e.hue}`} r="5"><animateMotion dur="1.6s" repeatCount="1" fill="freeze" path=${e.d} /></circle>` : null}
188
216
  ${e.badge ? html`<g class="oc-badge" transform=${`translate(${e.badge.x - 14} ${e.badge.y - 10})`}><rect width="28" height="20" rx="10" /><text x="14" y="14" text-anchor="middle">${`×${e.n}`}</text></g>` : null}
189
217
  </g>`;
190
218
  })}</g>`;
191
219
  }
192
220
  const ARROWS = ["task", "send", "report", "broadcast", "team", "fading"];
221
+ /**
222
+ * The head (#2329), in a 10-unit box that is HEAD.LEN stroke widths each way: a slim swept triangle HEAD.WIDE across,
223
+ * its tip at x 10; the path ends HEAD.BACK stroke widths before the tip (refX), so the line's stroke ends inside it.
224
+ */
225
+ const HEAD_HALF = (5 * HEAD.WIDE) / HEAD.LEN;
226
+ const HEAD_D = `M0 ${5 - HEAD_HALF} L10 5 L0 ${5 + HEAD_HALF} L2.5 5 z`;
227
+ const HEAD_REF_X = 10 - (10 * HEAD.BACK) / HEAD.LEN;
193
228
 
194
- /** The key to the lines: folded until the person opens it (open, it covers a corner of the canvas); kept per device. */
229
+ /**
230
+ * The key to the lines (#2052): a **Key** toggle in the toolbar; open, its rows are a strip between the toolbar and the
231
+ * canvas — never over the canvas, so it covers no card (it used to sit in the canvas's bottom-left corner, over the
232
+ * team there at the opening view). Folded until the person opens it; kept per device.
233
+ */
234
+ function readKeyOpen() { try { return localStorage.getItem(KEY_KEY) === "1"; } catch { return false; } }
235
+ function KeyToggle({ open, onToggle }) {
236
+ return html`<button type="button" class=${`btn btn-sm oc-key${open ? " on" : ""}`} aria-expanded=${open ? "true" : "false"} aria-controls="oc-legend"
237
+ onClick=${onToggle}>${tc("legend")}</button>`;
238
+ }
195
239
  function Legend() {
196
- const [open] = useState(() => { try { return localStorage.getItem(KEY_KEY) === "1"; } catch { return false; } });
197
240
  const row = (cls, k) => html`<span class="oc-lg"><i class=${`oc-sw ${cls}`} aria-hidden="true"></i>${tc(k)}</span>`;
198
- return html`<details class="oc-legend" open=${open} onToggle=${(e) => save(KEY_KEY, e.currentTarget.open ? "1" : "0")}><summary>${tc("legend")}</summary>
241
+ return html`<div id="oc-legend" class="oc-legend" role="region" aria-label=${tc("legend")}>
199
242
  <div class="oc-lg-rows">${row("h-task", "lgTask")}${row("h-send", "lgSend")}${row("h-report", "lgReport")}${row("h-broadcast", "lgBroadcast")}
200
- ${row("ph-queued", "lgQueued")}${row("ph-fading", "lgFading")}</div></details>`;
243
+ ${row("ph-queued", "lgQueued")}${row("ph-fading", "lgFading")}${row("h-task ph-work", "lgWork")}${row("h-report ph-return", "lgReturn")}${row("ph-stale", "lgStale")}</div></div>`;
201
244
  }
202
245
 
203
246
  /**
@@ -212,11 +255,13 @@ function useTraffic(lease, on) {
212
255
  if (!on || !lease) return undefined;
213
256
  const bump = () => setRev((n) => n + 1);
214
257
  const read = async () => {
258
+ // What the stream had said when this was asked for: a stream event after it makes the answer possibly older.
259
+ const since = store.streamRev();
215
260
  try {
216
261
  const r = await lease.fetch("/ui/traffic", { method: "GET", headers: { "Content-Type": "application/json" } });
217
262
  if (!lease.current() || !r.ok) return;
218
263
  const d = await r.json();
219
- if (lease.current() && store.load(d)) bump();
264
+ if (lease.current() && store.load(d, undefined, since)) bump();
220
265
  } catch { /* the next poll, or the stream, brings it */ }
221
266
  };
222
267
  void read();
@@ -226,6 +271,7 @@ function useTraffic(lease, on) {
226
271
  const offs = [];
227
272
  if (sub) {
228
273
  offs.push(lease.hold(sub("traffic", (item) => { if (store.apply(item)) bump(); })));
274
+ offs.push(lease.hold(sub("delegation", (d) => { if (store.delegation(d)) bump(); })));
229
275
  offs.push(lease.hold(sub("connection", (c) => { if (c === "live") void read(); })));
230
276
  }
231
277
  const hs = [
@@ -237,6 +283,32 @@ function useTraffic(lease, on) {
237
283
  return useMemo(() => (on ? store.items() : []), [rev, on]);
238
284
  }
239
285
 
286
+ /**
287
+ * #2182: the traffic lines, routed around the canvas by libavoid in a worker (fleet-route.js) once it answers; until
288
+ * then, and zoomed out (one line per team pair), along the lanes (fleet-traffic.js route()). An answer is kept while the
289
+ * layout it was routed on is the one drawn: a line it has not seen yet takes its lane until the next answer.
290
+ */
291
+ let routeClient = null;
292
+ function useTrafficRoutes(traffic, L, far) {
293
+ const lanes = useMemo(() => (traffic ? trafficEdges(traffic, L, { far }) : []), [traffic, L, far]);
294
+ const scene = useMemo(() => (far || !lanes.length ? null : routeScene(L, lanes)), [lanes, L, far]);
295
+ const [answer, setAnswer] = useState(null); // { shapes, map }
296
+ // The layout as the router sees it: a status frame re-making the same layout keeps the answer (and asks nothing).
297
+ const shapes = scene ? JSON.stringify(scene.shapes) : null;
298
+ const ask = scene && scene.conns.length ? JSON.stringify(scene) : null;
299
+ useEffect(() => {
300
+ if (!ask) return undefined;
301
+ routeClient ??= createRouteClient();
302
+ if (!routeClient.available) return undefined;
303
+ let live = true;
304
+ routeClient.route(JSON.parse(ask)).then((map) => { if (live && map) setAnswer({ shapes, map }); });
305
+ return () => { live = false; };
306
+ }, [ask]);
307
+ useEffect(() => () => { routeClient?.close(); routeClient = null; }, []);
308
+ return useMemo(() => (answer && answer.shapes === shapes && traffic ? trafficEdges(traffic, L, { far, routed: answer.map }) : lanes),
309
+ [lanes, answer, shapes, L, far, traffic]);
310
+ }
311
+
240
312
  /** The canvas body: `view` buildOrgView's answer; `folded` the folded teams' keys; `q` the search needle; `traffic` the live items (null: Live is off). */
241
313
  function Canvas({ view, folded, onFold, q, jump, traffic }) {
242
314
  const [narrow] = useState(() => typeof matchMedia === "function" && matchMedia("(max-width: 640px)").matches);
@@ -276,7 +348,7 @@ function Canvas({ view, folded, onFold, q, jump, traffic }) {
276
348
  vp.current = narrow ? fitView(openingRegion(L), size(), { margin: 12, minK: 0.75 }) : fitView(whole(), size(), { widthOnly: true, maxK: 1, minK: 0.6 });
277
349
  setFar(vp.current.k < FAR_K);
278
350
  }, []);
279
- const edges = useMemo(() => (traffic ? trafficEdges(traffic, L, { far }) : []), [traffic, L, far]);
351
+ const edges = useTrafficRoutes(traffic, L, far);
280
352
  // Preact owns the markup, not the transform: put it back after every render.
281
353
  useLayoutEffect(apply);
282
354
  // A search's Enter: the first match, unfolded (by the panel) and then brought into view — once. It waits for the
@@ -291,7 +363,7 @@ function Canvas({ view, folded, onFold, q, jump, traffic }) {
291
363
  if (!L.boxes.some((b) => b.folded && b.nodes.some((n) => n.name === j.name))) pendingJump.current = null; // gone: nothing to wait for
292
364
  });
293
365
 
294
- const open = (name) => navigate(chatPath(name));
366
+ const open = openChat;
295
367
  // The click that ends a drag or a pinch opens nothing and folds nothing.
296
368
  const onClickCapture = (e) => { if (drag.current.swallow) { e.preventDefault(); e.stopPropagation(); } };
297
369
  const onWheel = (e) => {
@@ -377,21 +449,21 @@ function Canvas({ view, folded, onFold, q, jump, traffic }) {
377
449
  <svg ref=${svgRef} class="oc-svg" role="application" tabindex="0" aria-label=${tc("label")} onWheel=${onWheel} onPointerDown=${onPointerDown}
378
450
  onPointerMove=${onPointerMove} onPointerUp=${onPointerUp} onPointerCancel=${onPointerUp} onKeyDown=${onKeyDown} onFocusIn=${onFocusIn} onClickCapture=${onClickCapture}>
379
451
  <defs><clipPath id="oc-clip-av" clipPathUnits="objectBoundingBox"><circle cx="0.5" cy="0.5" r="0.5" /></clipPath>
380
- ${ARROWS.map((a) => html`<marker key=${a} id=${`oc-ah-${a}`} viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto">
381
- <path d="M0 0 L10 5 L0 10 z" class=${`oc-ah h-${a}`} /></marker>`)}
382
- ${ARROWS.map((a) => html`<marker key=${`s-${a}`} id=${`oc-src-${a}`} viewBox="0 0 10 10" refX="5" refY="5" markerWidth="5" markerHeight="5">
383
- <circle cx="5" cy="5" r="4" class=${`oc-ah h-${a}`} /></marker>`)}</defs>
452
+ ${ARROWS.map((a) => html`<marker key=${a} id=${`oc-ah-${a}`} viewBox="0 0 10 10" refX=${HEAD_REF_X} refY="5" markerWidth=${HEAD.LEN} markerHeight=${HEAD.LEN} orient="auto">
453
+ <path d=${HEAD_D} class=${`oc-ah h-${a}`} /></marker>`)}
454
+ ${ARROWS.map((a) => html`<marker key=${`s-${a}`} id=${`oc-src-${a}`} viewBox="0 0 10 10" refX="5" refY="5" markerWidth=${HEAD.DOT} markerHeight=${HEAD.DOT}>
455
+ <circle cx="5" cy="5" r="5" class=${`oc-ah h-${a}`} /></marker>`)}</defs>
384
456
  <g ref=${worldRef} class="oc-world">
385
457
  <g class="oc-tree">${L.tree.map((d, i) => html`<path key=${i} d=${d} />`)}</g>
386
- <g class="oc-teams">${L.boxes.map((b) => html`<${TeamBox} key=${b.key} b=${b} q=${q} onFold=${onFold} />`)}</g>
458
+ <g class="oc-teams">${L.boxes.map((b) => html`<${TeamBox} key=${b.key} b=${b} q=${q} />`)}</g>
387
459
  <${TrafficLayer} edges=${edges} q=${q} />
460
+ <g class="oc-heads">${L.boxes.map((b) => html`<${TeamHead} key=${b.key} b=${b} q=${q} onFold=${onFold} />`)}</g>
388
461
  <g class="oc-cards">
389
462
  ${L.tops.map((c) => html`<${Card} key=${c.key} c=${c} lead=${true} cls=${q ? (hits(c.node, q) ? "match" : "dim") : ""} onOpen=${open} />`)}
390
463
  ${L.boxes.flatMap((b) => b.cells.map((c) => html`<${Card} key=${c.key} c=${c} lead=${false} cls=${q ? (hits(c.node, q) ? "match" : "dim") : ""} onOpen=${open} />`))}
391
464
  </g>
392
465
  </g>
393
466
  </svg>
394
- ${traffic ? html`<${Legend} />` : null}
395
467
  <div class="oc-zoom" role="group" aria-label=${tc("view")}>
396
468
  <button type="button" class="icon-btn" aria-label=${tc("zoomIn")} title=${tc("zoomIn")} onClick=${() => zoomBy(1.25)}><${Icon} name="plus" size=${16} /></button>
397
469
  <button type="button" class="icon-btn" aria-label=${tc("zoomOut")} title=${tc("zoomOut")} onClick=${() => zoomBy(0.8)}><span aria-hidden="true">−</span></button>
@@ -469,21 +541,26 @@ export function OrgCanvas({ org, app, lease }) {
469
541
  if (holder && folded.has(holder[0])) onFold(holder[0]);
470
542
  setJump({ name: first.name, at: Date.now() });
471
543
  };
544
+ const [keyOpen, setKeyOpen] = useState(readKeyOpen);
545
+ const toggleKey = () => setKeyOpen((v) => { save(KEY_KEY, v ? "0" : "1"); return !v; });
472
546
  const modeBtn = (m) => html`<button type="button" class=${`btn btn-sm${mode === m ? " btn-primary" : ""}`} aria-pressed=${mode === m ? "true" : "false"}
473
547
  onClick=${() => setMode(m)}>${tc(m)}</button>`;
474
548
  return html`<div class=${`org oc oc-${mode}`}>
475
549
  <div class="list-head org-head oc-bar">
476
550
  <span>${view.total === 1 ? t("org.instance") : t("org.instances", view.total)}</span><${OrgSummary} counts=${view.counts} />
477
551
  <div class="oc-tools">
478
- ${mode === "canvas" ? html`<label class="s-search oc-find"><${Icon} name="search" size=${14} /><span class="sr-only">${tc("find")}</span>
552
+ ${mode !== "list" ? html`<label class="s-search oc-find"><${Icon} name="search" size=${14} /><span class="sr-only">${tc("find")}</span>
479
553
  <input type="search" value=${query} placeholder=${tc("findShort")} autocomplete="off" onInput=${(e) => setQuery(e.target.value)} onKeyDown=${onFind} />
480
554
  ${q ? html`<span class="oc-found" role="status">${found ? (found === 1 ? tc("foundOne") : tc("found", found)) : tc("noMatch")}</span>` : null}</label>` : null}
555
+ ${mode !== "list" && live ? html`<${KeyToggle} open=${keyOpen} onToggle=${toggleKey} />` : null}
481
556
  <button type="button" class=${`btn btn-sm oc-live${live ? " on" : ""}`} aria-pressed=${live ? "true" : "false"} title=${live ? tc("liveOn") : tc("liveOff")}
482
557
  onClick=${() => setLive((v) => !v)}><span class="oc-live-dot" aria-hidden="true"></span>${tc("live")}</button>
483
- <div class="seg-inline" role="group" aria-label=${tc("view")}>${modeBtn("canvas")}${modeBtn("list")}</div>
558
+ <div class="seg-inline" role="group" aria-label=${tc("view")}>${modeBtn("canvas")}${modeBtn("list")}${modeBtn("office")}</div>
484
559
  </div>
485
560
  </div>
561
+ ${mode !== "list" && live && keyOpen ? html`<${Legend} />` : null}
486
562
  ${mode === "list" ? html`<${OrgChart} org=${org} app=${app} bare=${true} sending=${sending} />`
563
+ : mode === "office" ? html`<${Office} view=${view} traffic=${live ? traffic : null} q=${q} lease=${lease} onOpen=${openChat} />`
487
564
  : html`<${Canvas} view=${view} folded=${folded} onFold=${onFold} q=${q} jump=${jump} traffic=${live ? traffic : null} />`}
488
565
  </div>`;
489
566
  }