botmux 2.107.0 → 2.108.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 (515) hide show
  1. package/README.en.md +17 -14
  2. package/README.md +19 -14
  3. package/dist/adapters/backend/sandbox.d.ts +3 -1
  4. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  5. package/dist/adapters/backend/sandbox.js +19 -3
  6. package/dist/adapters/backend/sandbox.js.map +1 -1
  7. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  8. package/dist/adapters/backend/tmux-backend.js +16 -1
  9. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  10. package/dist/adapters/backend/tmux-pipe-backend.d.ts +24 -15
  11. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  12. package/dist/adapters/backend/tmux-pipe-backend.js +75 -43
  13. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  14. package/dist/adapters/cli/genius.d.ts.map +1 -1
  15. package/dist/adapters/cli/genius.js +9 -15
  16. package/dist/adapters/cli/genius.js.map +1 -1
  17. package/dist/adapters/cli/grok.d.ts +73 -0
  18. package/dist/adapters/cli/grok.d.ts.map +1 -0
  19. package/dist/adapters/cli/grok.js +298 -0
  20. package/dist/adapters/cli/grok.js.map +1 -0
  21. package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
  22. package/dist/adapters/cli/oh-my-pi.js +133 -12
  23. package/dist/adapters/cli/oh-my-pi.js.map +1 -1
  24. package/dist/adapters/cli/registry.d.ts +2 -1
  25. package/dist/adapters/cli/registry.d.ts.map +1 -1
  26. package/dist/adapters/cli/registry.js +3 -1
  27. package/dist/adapters/cli/registry.js.map +1 -1
  28. package/dist/adapters/cli/shared-hints.d.ts +8 -4
  29. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  30. package/dist/adapters/cli/shared-hints.js +8 -4
  31. package/dist/adapters/cli/shared-hints.js.map +1 -1
  32. package/dist/adapters/cli/types.d.ts +18 -16
  33. package/dist/adapters/cli/types.d.ts.map +1 -1
  34. package/dist/adapters/hook-installer.d.ts +5 -4
  35. package/dist/adapters/hook-installer.d.ts.map +1 -1
  36. package/dist/adapters/hook-installer.js +42 -0
  37. package/dist/adapters/hook-installer.js.map +1 -1
  38. package/dist/cli/send-dispatch.d.ts +21 -0
  39. package/dist/cli/send-dispatch.d.ts.map +1 -1
  40. package/dist/cli/send-dispatch.js +159 -0
  41. package/dist/cli/send-dispatch.js.map +1 -1
  42. package/dist/cli/session-list-liveness.d.ts +22 -0
  43. package/dist/cli/session-list-liveness.d.ts.map +1 -0
  44. package/dist/cli/session-list-liveness.js +22 -0
  45. package/dist/cli/session-list-liveness.js.map +1 -0
  46. package/dist/cli.d.ts.map +1 -1
  47. package/dist/cli.js +182 -33
  48. package/dist/cli.js.map +1 -1
  49. package/dist/core/ask-types.d.ts +4 -0
  50. package/dist/core/ask-types.d.ts.map +1 -1
  51. package/dist/core/ask-types.js +10 -0
  52. package/dist/core/ask-types.js.map +1 -1
  53. package/dist/core/cost-calculator.d.ts.map +1 -1
  54. package/dist/core/cost-calculator.js +35 -13
  55. package/dist/core/cost-calculator.js.map +1 -1
  56. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  57. package/dist/core/dashboard-ipc-server.js +89 -16
  58. package/dist/core/dashboard-ipc-server.js.map +1 -1
  59. package/dist/core/dashboard-rows.d.ts.map +1 -1
  60. package/dist/core/dashboard-rows.js +6 -2
  61. package/dist/core/dashboard-rows.js.map +1 -1
  62. package/dist/core/dashboard-url.d.ts +6 -5
  63. package/dist/core/dashboard-url.d.ts.map +1 -1
  64. package/dist/core/dashboard-url.js +11 -8
  65. package/dist/core/dashboard-url.js.map +1 -1
  66. package/dist/core/maintenance.d.ts +11 -8
  67. package/dist/core/maintenance.d.ts.map +1 -1
  68. package/dist/core/maintenance.js +45 -20
  69. package/dist/core/maintenance.js.map +1 -1
  70. package/dist/core/per-bot-env.d.ts.map +1 -1
  71. package/dist/core/per-bot-env.js +4 -0
  72. package/dist/core/per-bot-env.js.map +1 -1
  73. package/dist/core/session-discovery.d.ts.map +1 -1
  74. package/dist/core/session-discovery.js +4 -0
  75. package/dist/core/session-discovery.js.map +1 -1
  76. package/dist/core/skills/cli-admin-command.d.ts.map +1 -1
  77. package/dist/core/skills/cli-admin-command.js +8 -2
  78. package/dist/core/skills/cli-admin-command.js.map +1 -1
  79. package/dist/core/skills/im-command.d.ts.map +1 -1
  80. package/dist/core/skills/im-command.js +3 -1
  81. package/dist/core/skills/im-command.js.map +1 -1
  82. package/dist/core/skills/sources.d.ts +33 -1
  83. package/dist/core/skills/sources.d.ts.map +1 -1
  84. package/dist/core/skills/sources.js +97 -0
  85. package/dist/core/skills/sources.js.map +1 -1
  86. package/dist/core/skills/types.d.ts +8 -0
  87. package/dist/core/skills/types.d.ts.map +1 -1
  88. package/dist/core/terminal-url.d.ts.map +1 -1
  89. package/dist/core/terminal-url.js +12 -2
  90. package/dist/core/terminal-url.js.map +1 -1
  91. package/dist/core/terminal-write-auth.d.ts +34 -0
  92. package/dist/core/terminal-write-auth.d.ts.map +1 -0
  93. package/dist/core/terminal-write-auth.js +76 -0
  94. package/dist/core/terminal-write-auth.js.map +1 -0
  95. package/dist/core/tmux-recovery.d.ts +11 -0
  96. package/dist/core/tmux-recovery.d.ts.map +1 -0
  97. package/dist/core/tmux-recovery.js +19 -0
  98. package/dist/core/tmux-recovery.js.map +1 -0
  99. package/dist/core/types.d.ts +10 -4
  100. package/dist/core/types.d.ts.map +1 -1
  101. package/dist/core/types.js.map +1 -1
  102. package/dist/core/update-check.d.ts +2 -2
  103. package/dist/core/update-check.js +2 -2
  104. package/dist/core/worker-pool.d.ts +3 -0
  105. package/dist/core/worker-pool.d.ts.map +1 -1
  106. package/dist/core/worker-pool.js +70 -3
  107. package/dist/core/worker-pool.js.map +1 -1
  108. package/dist/daemon.d.ts.map +1 -1
  109. package/dist/daemon.js +15 -8
  110. package/dist/daemon.js.map +1 -1
  111. package/dist/dashboard/auth.d.ts +1 -1
  112. package/dist/dashboard/auth.d.ts.map +1 -1
  113. package/dist/dashboard/auth.js +7 -2
  114. package/dist/dashboard/auth.js.map +1 -1
  115. package/dist/dashboard/bot-payload.d.ts +3 -0
  116. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  117. package/dist/dashboard/bot-payload.js +3 -0
  118. package/dist/dashboard/bot-payload.js.map +1 -1
  119. package/dist/dashboard/connector-api.d.ts.map +1 -1
  120. package/dist/dashboard/connector-api.js +39 -13
  121. package/dist/dashboard/connector-api.js.map +1 -1
  122. package/dist/dashboard/history-senders.d.ts +37 -0
  123. package/dist/dashboard/history-senders.d.ts.map +1 -0
  124. package/dist/dashboard/history-senders.js +60 -0
  125. package/dist/dashboard/history-senders.js.map +1 -0
  126. package/dist/dashboard/roles-batch.d.ts +31 -0
  127. package/dist/dashboard/roles-batch.d.ts.map +1 -0
  128. package/dist/dashboard/roles-batch.js +87 -0
  129. package/dist/dashboard/roles-batch.js.map +1 -0
  130. package/dist/dashboard/settings-card-model.d.ts +4 -2
  131. package/dist/dashboard/settings-card-model.d.ts.map +1 -1
  132. package/dist/dashboard/settings-card-model.js +13 -5
  133. package/dist/dashboard/settings-card-model.js.map +1 -1
  134. package/dist/dashboard/settings-write-applier.d.ts +4 -1
  135. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  136. package/dist/dashboard/settings-write-applier.js +6 -1
  137. package/dist/dashboard/settings-write-applier.js.map +1 -1
  138. package/dist/dashboard/skill-install-request.d.ts +4 -0
  139. package/dist/dashboard/skill-install-request.d.ts.map +1 -1
  140. package/dist/dashboard/skill-install-request.js +11 -1
  141. package/dist/dashboard/skill-install-request.js.map +1 -1
  142. package/dist/dashboard/trigger-api.d.ts +9 -1
  143. package/dist/dashboard/trigger-api.d.ts.map +1 -1
  144. package/dist/dashboard/trigger-api.js +48 -10
  145. package/dist/dashboard/trigger-api.js.map +1 -1
  146. package/dist/dashboard/web/app.d.ts.map +1 -1
  147. package/dist/dashboard/web/app.js +286 -271
  148. package/dist/dashboard/web/app.js.map +1 -1
  149. package/dist/dashboard/web/bot-defaults-page.d.ts +26 -0
  150. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  151. package/dist/dashboard/web/bot-defaults-page.js +1408 -12
  152. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  153. package/dist/dashboard/web/bot-defaults.d.ts +91 -4
  154. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  155. package/dist/dashboard/web/bot-defaults.js +43 -2141
  156. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  157. package/dist/dashboard/web/bot-onboarding.d.ts +6 -1
  158. package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
  159. package/dist/dashboard/web/bot-onboarding.js +261 -306
  160. package/dist/dashboard/web/bot-onboarding.js.map +1 -1
  161. package/dist/dashboard/web/connectors-page.d.ts +4 -0
  162. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  163. package/dist/dashboard/web/connectors-page.js +228 -48
  164. package/dist/dashboard/web/connectors-page.js.map +1 -1
  165. package/dist/dashboard/web/dashboard-api.d.ts +9 -0
  166. package/dist/dashboard/web/dashboard-api.d.ts.map +1 -0
  167. package/dist/dashboard/web/dashboard-api.js +18 -0
  168. package/dist/dashboard/web/dashboard-api.js.map +1 -0
  169. package/dist/dashboard/web/dashboard-components.d.ts +92 -0
  170. package/dist/dashboard/web/dashboard-components.d.ts.map +1 -0
  171. package/dist/dashboard/web/dashboard-components.js +250 -0
  172. package/dist/dashboard/web/dashboard-components.js.map +1 -0
  173. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  174. package/dist/dashboard/web/dashboard-routes.js +30 -183
  175. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  176. package/dist/dashboard/web/floating-scrollbars.d.ts +2 -0
  177. package/dist/dashboard/web/floating-scrollbars.d.ts.map +1 -0
  178. package/dist/dashboard/web/floating-scrollbars.js +264 -0
  179. package/dist/dashboard/web/floating-scrollbars.js.map +1 -0
  180. package/dist/dashboard/web/groups-api.d.ts +36 -0
  181. package/dist/dashboard/web/groups-api.d.ts.map +1 -0
  182. package/dist/dashboard/web/groups-api.js +44 -0
  183. package/dist/dashboard/web/groups-api.js.map +1 -0
  184. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  185. package/dist/dashboard/web/groups-page.js +746 -15
  186. package/dist/dashboard/web/groups-page.js.map +1 -1
  187. package/dist/dashboard/web/groups.d.ts +51 -18
  188. package/dist/dashboard/web/groups.d.ts.map +1 -1
  189. package/dist/dashboard/web/groups.js +145 -1096
  190. package/dist/dashboard/web/groups.js.map +1 -1
  191. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  192. package/dist/dashboard/web/i18n.js +545 -255
  193. package/dist/dashboard/web/i18n.js.map +1 -1
  194. package/dist/dashboard/web/insights-page.d.ts.map +1 -1
  195. package/dist/dashboard/web/insights-page.js +1047 -14
  196. package/dist/dashboard/web/insights-page.js.map +1 -1
  197. package/dist/dashboard/web/insights.d.ts +177 -7
  198. package/dist/dashboard/web/insights.d.ts.map +1 -1
  199. package/dist/dashboard/web/insights.js +187 -1926
  200. package/dist/dashboard/web/insights.js.map +1 -1
  201. package/dist/dashboard/web/legacy-workflow-page.d.ts +3 -0
  202. package/dist/dashboard/web/legacy-workflow-page.d.ts.map +1 -0
  203. package/dist/dashboard/web/legacy-workflow-page.js +717 -0
  204. package/dist/dashboard/web/legacy-workflow-page.js.map +1 -0
  205. package/dist/dashboard/web/monitor-room.d.ts.map +1 -1
  206. package/dist/dashboard/web/monitor-room.js +10 -8
  207. package/dist/dashboard/web/monitor-room.js.map +1 -1
  208. package/dist/dashboard/web/monitoring-page.d.ts.map +1 -1
  209. package/dist/dashboard/web/monitoring-page.js +188 -14
  210. package/dist/dashboard/web/monitoring-page.js.map +1 -1
  211. package/dist/dashboard/web/office-page.d.ts.map +1 -1
  212. package/dist/dashboard/web/office-page.js +11 -23
  213. package/dist/dashboard/web/office-page.js.map +1 -1
  214. package/dist/dashboard/web/overview-page.d.ts.map +1 -1
  215. package/dist/dashboard/web/overview-page.js +141 -147
  216. package/dist/dashboard/web/overview-page.js.map +1 -1
  217. package/dist/dashboard/web/overview.d.ts +0 -1
  218. package/dist/dashboard/web/overview.d.ts.map +1 -1
  219. package/dist/dashboard/web/overview.js +3 -275
  220. package/dist/dashboard/web/overview.js.map +1 -1
  221. package/dist/dashboard/web/preferences.d.ts +1 -6
  222. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  223. package/dist/dashboard/web/preferences.js +0 -21
  224. package/dist/dashboard/web/preferences.js.map +1 -1
  225. package/dist/dashboard/web/role-batch.d.ts +9 -0
  226. package/dist/dashboard/web/role-batch.d.ts.map +1 -0
  227. package/dist/dashboard/web/role-batch.js +42 -0
  228. package/dist/dashboard/web/role-batch.js.map +1 -0
  229. package/dist/dashboard/web/roles-page.d.ts.map +1 -1
  230. package/dist/dashboard/web/roles-page.js +538 -13
  231. package/dist/dashboard/web/roles-page.js.map +1 -1
  232. package/dist/dashboard/web/roles.d.ts +98 -1
  233. package/dist/dashboard/web/roles.d.ts.map +1 -1
  234. package/dist/dashboard/web/roles.js +117 -903
  235. package/dist/dashboard/web/roles.js.map +1 -1
  236. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  237. package/dist/dashboard/web/schedules-page.js +82 -24
  238. package/dist/dashboard/web/schedules-page.js.map +1 -1
  239. package/dist/dashboard/web/sessions-kanban.d.ts +67 -0
  240. package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -0
  241. package/dist/dashboard/web/sessions-kanban.js +481 -0
  242. package/dist/dashboard/web/sessions-kanban.js.map +1 -0
  243. package/dist/dashboard/web/sessions-page.d.ts +4 -0
  244. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  245. package/dist/dashboard/web/sessions-page.js +1633 -18
  246. package/dist/dashboard/web/sessions-page.js.map +1 -1
  247. package/dist/dashboard/web/sessions.d.ts +45 -4
  248. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  249. package/dist/dashboard/web/sessions.js +53 -2535
  250. package/dist/dashboard/web/sessions.js.map +1 -1
  251. package/dist/dashboard/web/settings-page.d.ts +0 -2
  252. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  253. package/dist/dashboard/web/settings-page.js +127 -117
  254. package/dist/dashboard/web/settings-page.js.map +1 -1
  255. package/dist/dashboard/web/skills-page.d.ts +10 -1
  256. package/dist/dashboard/web/skills-page.d.ts.map +1 -1
  257. package/dist/dashboard/web/skills-page.js +235 -93
  258. package/dist/dashboard/web/skills-page.js.map +1 -1
  259. package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
  260. package/dist/dashboard/web/team-federation-page.js +446 -28
  261. package/dist/dashboard/web/team-federation-page.js.map +1 -1
  262. package/dist/dashboard/web/team-federation.d.ts +91 -2
  263. package/dist/dashboard/web/team-federation.d.ts.map +1 -1
  264. package/dist/dashboard/web/team-federation.js +87 -474
  265. package/dist/dashboard/web/team-federation.js.map +1 -1
  266. package/dist/dashboard/web/theme-menu.d.ts +1 -0
  267. package/dist/dashboard/web/theme-menu.d.ts.map +1 -1
  268. package/dist/dashboard/web/theme-menu.js +79 -20
  269. package/dist/dashboard/web/theme-menu.js.map +1 -1
  270. package/dist/dashboard/web/ui.d.ts +1 -2
  271. package/dist/dashboard/web/ui.d.ts.map +1 -1
  272. package/dist/dashboard/web/ui.js +8 -20
  273. package/dist/dashboard/web/ui.js.map +1 -1
  274. package/dist/dashboard/web/v3-api.d.ts +16 -0
  275. package/dist/dashboard/web/v3-api.d.ts.map +1 -0
  276. package/dist/dashboard/web/v3-api.js +21 -0
  277. package/dist/dashboard/web/v3-api.js.map +1 -0
  278. package/dist/dashboard/web/v3-components.d.ts +2 -0
  279. package/dist/dashboard/web/v3-components.d.ts.map +1 -0
  280. package/dist/dashboard/web/v3-components.js +290 -0
  281. package/dist/dashboard/web/v3-components.js.map +1 -0
  282. package/dist/dashboard/web/v3-model.d.ts +80 -0
  283. package/dist/dashboard/web/v3-model.d.ts.map +1 -0
  284. package/dist/dashboard/web/v3-model.js +240 -0
  285. package/dist/dashboard/web/v3-model.js.map +1 -0
  286. package/dist/dashboard/web/v3-page.d.ts.map +1 -1
  287. package/dist/dashboard/web/v3-page.js +2 -22
  288. package/dist/dashboard/web/v3-page.js.map +1 -1
  289. package/dist/dashboard/web/v3-terminal.d.ts +14 -0
  290. package/dist/dashboard/web/v3-terminal.d.ts.map +1 -1
  291. package/dist/dashboard/web/v3-terminal.js +31 -19
  292. package/dist/dashboard/web/v3-terminal.js.map +1 -1
  293. package/dist/dashboard/web/webhook-logs-page.d.ts +16 -0
  294. package/dist/dashboard/web/webhook-logs-page.d.ts.map +1 -0
  295. package/dist/dashboard/web/webhook-logs-page.js +195 -0
  296. package/dist/dashboard/web/webhook-logs-page.js.map +1 -0
  297. package/dist/dashboard/web/whiteboards-page.d.ts.map +1 -1
  298. package/dist/dashboard/web/whiteboards-page.js +18 -23
  299. package/dist/dashboard/web/whiteboards-page.js.map +1 -1
  300. package/dist/dashboard/web/workflow-version-switch.d.ts +8 -0
  301. package/dist/dashboard/web/workflow-version-switch.d.ts.map +1 -0
  302. package/dist/dashboard/web/workflow-version-switch.js +9 -0
  303. package/dist/dashboard/web/workflow-version-switch.js.map +1 -0
  304. package/dist/dashboard/web/workflows.d.ts +272 -1
  305. package/dist/dashboard/web/workflows.d.ts.map +1 -1
  306. package/dist/dashboard/web/workflows.js +211 -1397
  307. package/dist/dashboard/web/workflows.js.map +1 -1
  308. package/dist/dashboard/webhook-routes.d.ts.map +1 -1
  309. package/dist/dashboard/webhook-routes.js +92 -39
  310. package/dist/dashboard/webhook-routes.js.map +1 -1
  311. package/dist/dashboard-web/app.js +1 -65
  312. package/dist/dashboard-web/brand-logo.png +0 -0
  313. package/dist/dashboard-web/chunks/bot-defaults-page-HSQ6HR3R.js +1 -0
  314. package/dist/dashboard-web/chunks/chunk-6TPODDDC.js +1 -0
  315. package/dist/dashboard-web/chunks/chunk-73EJP2MO.js +1 -0
  316. package/dist/dashboard-web/chunks/chunk-BRTZFELS.js +1 -0
  317. package/dist/dashboard-web/chunks/chunk-EVK77ASG.js +1 -0
  318. package/dist/dashboard-web/chunks/chunk-R3FXBFQH.js +1 -0
  319. package/dist/dashboard-web/chunks/chunk-VRLL7SNU.js +1 -0
  320. package/dist/dashboard-web/chunks/chunk-XCPSHD3G.js +37 -0
  321. package/dist/dashboard-web/chunks/chunk-XJ7BGPJH.js +1 -0
  322. package/dist/dashboard-web/chunks/chunk-YVRWYGXR.js +1 -0
  323. package/dist/dashboard-web/chunks/chunk-ZJING6FY.js +66 -0
  324. package/dist/dashboard-web/chunks/connectors-page-ODUA5UCW.js +1 -0
  325. package/dist/dashboard-web/chunks/groups-page-OYX5M6NK.js +8 -0
  326. package/dist/dashboard-web/chunks/insights-page-YCQO6OCR.js +22 -0
  327. package/dist/dashboard-web/chunks/legacy-workflow-page-XJAUNONP.js +2 -0
  328. package/dist/dashboard-web/chunks/{monitor-room-RFX4HPS5.js → monitor-room-WTZNYAFV.js} +17 -15
  329. package/dist/dashboard-web/chunks/monitoring-page-R6LJUK7G.js +2 -0
  330. package/dist/dashboard-web/chunks/office-page-4OXK3GNR.js +1 -0
  331. package/dist/dashboard-web/chunks/overview-page-4MVEJY6U.js +1 -0
  332. package/dist/dashboard-web/chunks/roles-page-NQDW27VV.js +1 -0
  333. package/dist/dashboard-web/chunks/schedules-page-JRNKYHOX.js +1 -0
  334. package/dist/dashboard-web/chunks/sessions-page-LF7UVI7B.js +3 -0
  335. package/dist/dashboard-web/chunks/settings-page-WGW7KQQS.js +2 -0
  336. package/dist/dashboard-web/chunks/skills-page-AMD4XP3T.js +3 -0
  337. package/dist/dashboard-web/chunks/team-federation-page-SYG3K4GG.js +1 -0
  338. package/dist/dashboard-web/chunks/v3-page-6NFFWNUK.js +94 -0
  339. package/dist/dashboard-web/chunks/whiteboards-page-FBRUK2AS.js +1 -0
  340. package/dist/dashboard-web/favicon.png +0 -0
  341. package/dist/dashboard-web/index.html +5 -69
  342. package/dist/dashboard-web/style.css +18835 -7211
  343. package/dist/dashboard.js +150 -32
  344. package/dist/dashboard.js.map +1 -1
  345. package/dist/global-config.d.ts +2 -2
  346. package/dist/global-config.d.ts.map +1 -1
  347. package/dist/i18n/en.d.ts.map +1 -1
  348. package/dist/i18n/en.js +3 -0
  349. package/dist/i18n/en.js.map +1 -1
  350. package/dist/i18n/zh.d.ts.map +1 -1
  351. package/dist/i18n/zh.js +3 -0
  352. package/dist/i18n/zh.js.map +1 -1
  353. package/dist/im/lark/card-builder.d.ts +7 -5
  354. package/dist/im/lark/card-builder.d.ts.map +1 -1
  355. package/dist/im/lark/card-builder.js +10 -7
  356. package/dist/im/lark/card-builder.js.map +1 -1
  357. package/dist/im/lark/card-handler.d.ts.map +1 -1
  358. package/dist/im/lark/card-handler.js +25 -1
  359. package/dist/im/lark/card-handler.js.map +1 -1
  360. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  361. package/dist/im/lark/event-dispatcher.js +84 -0
  362. package/dist/im/lark/event-dispatcher.js.map +1 -1
  363. package/dist/platform/binding.d.ts +9 -0
  364. package/dist/platform/binding.d.ts.map +1 -1
  365. package/dist/platform/binding.js +14 -0
  366. package/dist/platform/binding.js.map +1 -1
  367. package/dist/platform/tunnel-client.d.ts.map +1 -1
  368. package/dist/platform/tunnel-client.js +9 -0
  369. package/dist/platform/tunnel-client.js.map +1 -1
  370. package/dist/services/bot-config-store.d.ts +1 -1
  371. package/dist/services/bot-config-store.d.ts.map +1 -1
  372. package/dist/services/bot-config-store.js +11 -5
  373. package/dist/services/bot-config-store.js.map +1 -1
  374. package/dist/services/file-bridge-path.d.ts +8 -0
  375. package/dist/services/file-bridge-path.d.ts.map +1 -0
  376. package/dist/services/file-bridge-path.js +75 -0
  377. package/dist/services/file-bridge-path.js.map +1 -0
  378. package/dist/services/grok-paths.d.ts +27 -0
  379. package/dist/services/grok-paths.d.ts.map +1 -0
  380. package/dist/services/grok-paths.js +106 -0
  381. package/dist/services/grok-paths.js.map +1 -0
  382. package/dist/services/grok-transcript.d.ts +67 -0
  383. package/dist/services/grok-transcript.d.ts.map +1 -0
  384. package/dist/services/grok-transcript.js +630 -0
  385. package/dist/services/grok-transcript.js.map +1 -0
  386. package/dist/services/hermes-session-filter.d.ts +28 -0
  387. package/dist/services/hermes-session-filter.d.ts.map +1 -0
  388. package/dist/services/hermes-session-filter.js +53 -0
  389. package/dist/services/hermes-session-filter.js.map +1 -0
  390. package/dist/services/hermes-transcript.d.ts +3 -0
  391. package/dist/services/hermes-transcript.d.ts.map +1 -1
  392. package/dist/services/hermes-transcript.js +20 -2
  393. package/dist/services/hermes-transcript.js.map +1 -1
  394. package/dist/services/resumable-session-discovery.d.ts +3 -0
  395. package/dist/services/resumable-session-discovery.d.ts.map +1 -1
  396. package/dist/services/resumable-session-discovery.js +6 -1
  397. package/dist/services/resumable-session-discovery.js.map +1 -1
  398. package/dist/services/skill-registry-store.d.ts +9 -0
  399. package/dist/services/skill-registry-store.d.ts.map +1 -1
  400. package/dist/services/skill-registry-store.js +304 -1
  401. package/dist/services/skill-registry-store.js.map +1 -1
  402. package/dist/services/structured-bridge-clis.d.ts +29 -0
  403. package/dist/services/structured-bridge-clis.d.ts.map +1 -0
  404. package/dist/services/structured-bridge-clis.js +76 -0
  405. package/dist/services/structured-bridge-clis.js.map +1 -0
  406. package/dist/services/trigger-log-store.d.ts +59 -0
  407. package/dist/services/trigger-log-store.d.ts.map +1 -1
  408. package/dist/services/trigger-log-store.js +81 -10
  409. package/dist/services/trigger-log-store.js.map +1 -1
  410. package/dist/services/usage-ledger.d.ts +4 -1
  411. package/dist/services/usage-ledger.d.ts.map +1 -1
  412. package/dist/services/usage-ledger.js +48 -10
  413. package/dist/services/usage-ledger.js.map +1 -1
  414. package/dist/services/webhook-audit.d.ts +10 -0
  415. package/dist/services/webhook-audit.d.ts.map +1 -0
  416. package/dist/services/webhook-audit.js +116 -0
  417. package/dist/services/webhook-audit.js.map +1 -0
  418. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  419. package/dist/setup/bot-config-editor.js +2 -0
  420. package/dist/setup/bot-config-editor.js.map +1 -1
  421. package/dist/setup/ensure-tmux.d.ts +26 -12
  422. package/dist/setup/ensure-tmux.d.ts.map +1 -1
  423. package/dist/setup/ensure-tmux.js +85 -18
  424. package/dist/setup/ensure-tmux.js.map +1 -1
  425. package/dist/skills/definitions.d.ts.map +1 -1
  426. package/dist/skills/definitions.js +14 -1
  427. package/dist/skills/definitions.js.map +1 -1
  428. package/dist/skills/injection-mode.d.ts +16 -0
  429. package/dist/skills/injection-mode.d.ts.map +1 -1
  430. package/dist/skills/injection-mode.js +25 -0
  431. package/dist/skills/injection-mode.js.map +1 -1
  432. package/dist/types.d.ts +9 -0
  433. package/dist/types.d.ts.map +1 -1
  434. package/dist/utils/global-install.d.ts +22 -0
  435. package/dist/utils/global-install.d.ts.map +1 -0
  436. package/dist/utils/global-install.js +106 -0
  437. package/dist/utils/global-install.js.map +1 -0
  438. package/dist/utils/install-diagnostics.d.ts +1 -1
  439. package/dist/utils/install-diagnostics.d.ts.map +1 -1
  440. package/dist/utils/install-diagnostics.js +6 -4
  441. package/dist/utils/install-diagnostics.js.map +1 -1
  442. package/dist/utils/install-info.d.ts +2 -0
  443. package/dist/utils/install-info.d.ts.map +1 -1
  444. package/dist/utils/install-info.js +10 -4
  445. package/dist/utils/install-info.js.map +1 -1
  446. package/dist/worker.js +293 -172
  447. package/dist/worker.js.map +1 -1
  448. package/dist/workflows/events/payloads.d.ts +10 -10
  449. package/dist/workflows/events/schema.d.ts +28 -28
  450. package/package.json +8 -7
  451. package/dist/dashboard/web/connectors.d.ts +0 -2
  452. package/dist/dashboard/web/connectors.d.ts.map +0 -1
  453. package/dist/dashboard/web/connectors.js +0 -2
  454. package/dist/dashboard/web/connectors.js.map +0 -1
  455. package/dist/dashboard/web/office.d.ts +0 -2
  456. package/dist/dashboard/web/office.d.ts.map +0 -1
  457. package/dist/dashboard/web/office.js +0 -2
  458. package/dist/dashboard/web/office.js.map +0 -1
  459. package/dist/dashboard/web/schedules.d.ts +0 -2
  460. package/dist/dashboard/web/schedules.d.ts.map +0 -1
  461. package/dist/dashboard/web/schedules.js +0 -2
  462. package/dist/dashboard/web/schedules.js.map +0 -1
  463. package/dist/dashboard/web/settings.d.ts +0 -2
  464. package/dist/dashboard/web/settings.d.ts.map +0 -1
  465. package/dist/dashboard/web/settings.js +0 -2
  466. package/dist/dashboard/web/settings.js.map +0 -1
  467. package/dist/dashboard/web/skills.d.ts +0 -2
  468. package/dist/dashboard/web/skills.d.ts.map +0 -1
  469. package/dist/dashboard/web/skills.js +0 -2
  470. package/dist/dashboard/web/skills.js.map +0 -1
  471. package/dist/dashboard/web/skin-intro.d.ts +0 -4
  472. package/dist/dashboard/web/skin-intro.d.ts.map +0 -1
  473. package/dist/dashboard/web/skin-intro.js +0 -49
  474. package/dist/dashboard/web/skin-intro.js.map +0 -1
  475. package/dist/dashboard/web/v3.d.ts +0 -3
  476. package/dist/dashboard/web/v3.d.ts.map +0 -1
  477. package/dist/dashboard/web/v3.js +0 -539
  478. package/dist/dashboard/web/v3.js.map +0 -1
  479. package/dist/dashboard/web/whiteboards.d.ts +0 -2
  480. package/dist/dashboard/web/whiteboards.d.ts.map +0 -1
  481. package/dist/dashboard/web/whiteboards.js +0 -2
  482. package/dist/dashboard/web/whiteboards.js.map +0 -1
  483. package/dist/dashboard-web/chunks/bot-defaults-page-OCIHPGEU.js +0 -438
  484. package/dist/dashboard-web/chunks/chunk-3N2PPQVD.js +0 -1
  485. package/dist/dashboard-web/chunks/chunk-3UJYRR2Q.js +0 -37
  486. package/dist/dashboard-web/chunks/chunk-5E3MJJL4.js +0 -1
  487. package/dist/dashboard-web/chunks/chunk-7SZRL6FY.js +0 -1
  488. package/dist/dashboard-web/chunks/chunk-JTSE5VP6.js +0 -54
  489. package/dist/dashboard-web/chunks/chunk-LXIK7OUJ.js +0 -1
  490. package/dist/dashboard-web/chunks/chunk-PE6W3C2C.js +0 -1
  491. package/dist/dashboard-web/chunks/chunk-QW54DWU3.js +0 -325
  492. package/dist/dashboard-web/chunks/connectors-IGETYWCP.js +0 -1
  493. package/dist/dashboard-web/chunks/groups-page-MYBS4ZYJ.js +0 -207
  494. package/dist/dashboard-web/chunks/insights-page-UPA32V2S.js +0 -309
  495. package/dist/dashboard-web/chunks/monitoring-page-7T3BESZ2.js +0 -1
  496. package/dist/dashboard-web/chunks/office-page-6DXYOG55.js +0 -1
  497. package/dist/dashboard-web/chunks/overview-page-LJSBCQW4.js +0 -1
  498. package/dist/dashboard-web/chunks/roles-page-ESURTVQH.js +0 -98
  499. package/dist/dashboard-web/chunks/schedules-LML2ISOT.js +0 -1
  500. package/dist/dashboard-web/chunks/sessions-YB73XOTU.js +0 -1
  501. package/dist/dashboard-web/chunks/sessions-page-MCO5QR7Z.js +0 -1
  502. package/dist/dashboard-web/chunks/settings-page-OSDKNVS3.js +0 -2
  503. package/dist/dashboard-web/chunks/skills-page-PXBZJ6P6.js +0 -2
  504. package/dist/dashboard-web/chunks/team-federation-page-TTPVHFPX.js +0 -10
  505. package/dist/dashboard-web/chunks/v3-page-FVPUL665.js +0 -149
  506. package/dist/dashboard-web/chunks/whiteboards-page-HLCTYSSV.js +0 -1
  507. package/dist/dashboard-web/chunks/workflows-FCPM4S4D.js +0 -184
  508. package/dist/dashboard-web/skins/bluearchive-hero.webp +0 -0
  509. package/dist/dashboard-web/skins/dragonball-goku.webp +0 -0
  510. package/dist/dashboard-web/skins/dragonball-wukong.webp +0 -0
  511. package/dist/dashboard-web/skins/genshin-breeze.webp +0 -0
  512. package/dist/dashboard-web/skins/ikun-hero.webp +0 -0
  513. package/dist/dashboard-web/skins/prts-priestess.webp +0 -0
  514. package/dist/dashboard-web/skins/zzz-hero.webp +0 -0
  515. package/dist/dashboard-web/skins/zzz-pattern.svg +0 -25
@@ -1,64 +1,252 @@
1
- // Dashboard SPA entry: hash router + bootstrap + online indicator.
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Dashboard SPA entry: React chrome + lazy route host + SSE bootstrap.
3
+ import { createRoot } from 'react-dom/client';
4
+ import { useEffect, useRef, useState } from 'react';
2
5
  import { bootstrap, store } from './store.js';
3
- import { wireBotOnboardingButton } from './bot-onboarding.js';
4
- import { attentionReason, attentionWaitSince, botDisplayName, escapeHtml, loadNameMaps, relTime, t, ui } from './ui.js';
5
- import { initThemeMenu, paintThemeMenu } from './theme-menu.js';
6
+ import { attentionReason, attentionWaitSince, botDisplayName, escapeHtml, loadNameMaps, relTime, t, ui, } from './ui.js';
7
+ import { CLOSE_THEME_MENU_EVENT, initThemeMenu, paintThemeMenu } from './theme-menu.js';
6
8
  import { normalizeDashboardLocale } from './i18n.js';
7
- import { readStoredSidebarMode, writeStoredSidebarMode } from './preferences.js';
8
9
  import { findDashboardRoute, loadOverviewPage } from './dashboard-routes.js';
9
10
  import { beginDashboardRoute, createDashboardRouteState, loadAndRenderDashboardRoute, } from './route-lifecycle.js';
10
- const root = document.getElementById('root');
11
- // Resolved once at bootstrap from GET /api/settings:
12
- // - `isAuthed` → gates the management nav + route guards
13
- // - `publicReadOnly` → decides whether a read 401 is a hard lockout (token
14
- // rotated blocking overlay) or just a read-only
15
- // visitor touching a token-gated page (soft toast).
16
- // Defaults keep the authed / legacy UX if the probe fails.
11
+ import { buildBotCards, loadGroupsSnapshot } from './overview.js';
12
+ import { BotOnboardingDialog, OPEN_BOT_ONBOARDING_EVENT } from './bot-onboarding.js';
13
+ import { InfoTip } from './dashboard-components.js';
14
+ import { initFloatingScrollbars } from './floating-scrollbars.js';
15
+ const MANAGE_ROUTES = [
16
+ 'roles',
17
+ 'role-profiles',
18
+ 'bot-defaults',
19
+ 'skills',
20
+ 'team',
21
+ 'connectors',
22
+ 'insights',
23
+ 'whiteboards',
24
+ ];
25
+ const NAV_ITEMS = [
26
+ {
27
+ id: 'overview',
28
+ href: '#/',
29
+ labelKey: 'nav.overview',
30
+ icon: (_jsxs(_Fragment, { children: [_jsx("rect", { x: "1.5", y: "1.5", width: "5.4", height: "5.4", rx: "1.5" }), _jsx("rect", { x: "9.1", y: "1.5", width: "5.4", height: "5.4", rx: "1.5" }), _jsx("rect", { x: "1.5", y: "9.1", width: "5.4", height: "5.4", rx: "1.5" }), _jsx("rect", { x: "9.1", y: "9.1", width: "5.4", height: "5.4", rx: "1.5" })] })),
31
+ },
32
+ { id: 'sessions', href: '#/sessions', labelKey: 'nav.sessions', icon: _jsx("path", { d: "M2 3.5h12v7H6l-3 3v-3H2z" }) },
33
+ {
34
+ id: 'groups',
35
+ href: '#/groups',
36
+ labelKey: 'nav.groups',
37
+ icon: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: "5.6", cy: "5.8", r: "2.4" }), _jsx("circle", { cx: "11", cy: "6.8", r: "1.9" }), _jsx("path", { d: "M1.8 13.2c.5-2.4 2-3.6 3.8-3.6s3.3 1.2 3.8 3.6M9.8 12.6c.4-1.7 1.5-2.6 2.8-2.6 1 0 1.9.5 2.4 1.6" })] })),
38
+ },
39
+ { id: 'roles', href: '#/roles', labelKey: 'nav.roles', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("path", { d: "M8 1.8l5.2 2v3.4c0 3.4-2.2 5.9-5.2 7-3-1.1-5.2-3.6-5.2-7V3.8z" }), _jsx("path", { d: "M5.8 8l1.6 1.6 2.8-3" })] }) },
40
+ {
41
+ id: 'monitoring',
42
+ href: '#/monitoring',
43
+ labelKey: 'nav.monitoring',
44
+ icon: (_jsxs(_Fragment, { children: [_jsx("path", { d: "M2 9.2h2.3l1.3-4.8 2.5 8.4 1.8-5.1h4.1" }), _jsx("path", { d: "M2 2.5h12v11H2z" })] })),
45
+ },
46
+ { id: 'insights', href: '#/insights', labelKey: 'nav.insights', manage: true, icon: _jsx(_Fragment, { children: _jsx("path", { d: "M2 2v12h12M5 11V7M8.5 11V4.5M12 11V8.5" }) }) },
47
+ {
48
+ id: 'workflows',
49
+ href: '#/workflows',
50
+ labelKey: 'nav.workflows',
51
+ icon: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: "3.4", cy: "3.6", r: "1.9" }), _jsx("circle", { cx: "3.4", cy: "12.4", r: "1.9" }), _jsx("circle", { cx: "12.6", cy: "8", r: "1.9" }), _jsx("path", { d: "M5.2 4.4l5.6 2.8M5.2 11.6l5.6-2.8" })] })),
52
+ },
53
+ { id: 'schedules', href: '#/schedules', labelKey: 'nav.schedules', icon: _jsxs(_Fragment, { children: [_jsx("circle", { cx: "8", cy: "8", r: "6.2" }), _jsx("path", { d: "M8 4.5V8l2.4 1.6" })] }) },
54
+ { id: 'whiteboards', href: '#/whiteboards', labelKey: 'nav.whiteboards', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("rect", { x: "2.2", y: "2.2", width: "11.6", height: "11.6", rx: "2" }), _jsx("path", { d: "M4.8 5.2h6.4M4.8 8h6.4M4.8 10.8h4" })] }) },
55
+ { id: 'office', href: '#/office', labelKey: 'nav.office', icon: _jsxs(_Fragment, { children: [_jsx("rect", { x: "3", y: "4", width: "10", height: "7", rx: "2" }), _jsx("circle", { cx: "6", cy: "7.5", r: "1" }), _jsx("circle", { cx: "10", cy: "7.5", r: "1" }), _jsx("path", { d: "M8 4V2M4.5 11v2M11.5 11v2" })] }) },
56
+ { id: 'bot-defaults', href: '#/bot-defaults', labelKey: 'nav.botDefaults', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("rect", { x: "2.5", y: "5", width: "11", height: "8", rx: "2" }), _jsx("circle", { cx: "5.8", cy: "9", r: "1" }), _jsx("circle", { cx: "10.2", cy: "9", r: "1" }), _jsx("path", { d: "M8 5V2.5M5.5 13v1.2M10.5 13v1.2" })] }) },
57
+ { id: 'skills', href: '#/skills', labelKey: 'nav.skills', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("path", { d: "M3 2.5h10v3H3zM3 7h10v6.5H3z" }), _jsx("path", { d: "M5.4 9.2h5.2M5.4 11.2h3.8" })] }) },
58
+ { id: 'team', href: '#/team', labelKey: 'nav.team', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("circle", { cx: "8", cy: "8", r: "6.2" }), _jsx("path", { d: "M1.8 8h12.4M8 1.8c-2 1.8-2 10.6 0 12.4 2-1.8 2-10.6 0-12.4z" })] }) },
59
+ { id: 'connectors', href: '#/connectors', labelKey: 'nav.connectors', manage: true, icon: _jsxs(_Fragment, { children: [_jsx("path", { d: "M5.5 6.5v-3a2.5 2.5 0 0 1 5 0v3" }), _jsx("rect", { x: "3.5", y: "6.5", width: "9", height: "7", rx: "2" })] }) },
60
+ { id: 'settings', href: '#/settings', labelKey: 'nav.settings', icon: _jsxs(_Fragment, { children: [_jsx("path", { d: "M8 1.75 9.35 2.05 10 3.28l1.38.3 1.04-.96.96.96-.96 1.04.3 1.38 1.23.65L14.25 8l-.3 1.35-1.23.65-.3 1.38.96 1.04-.96.96-1.04-.96-1.38.3-.65 1.23L8 14.25l-1.35-.3L6 12.72l-1.38-.3-1.04.96-.96-.96.96-1.04-.3-1.38-1.23-.65L1.75 8l.3-1.35 1.23-.65.3-1.38-.96-1.04.96-.96 1.04.96 1.38-.3.65-1.23z" }), _jsx("circle", { cx: "8", cy: "8", r: "2" })] }) },
61
+ ];
17
62
  let isAuthed = true;
18
63
  let publicReadOnly = false;
19
- // Management pages are token-gated end-to-end (no public GET) — a read-only
20
- // visitor must not reach them. `data-route` values from index.html's nav.
21
- const MANAGE_ROUTES = ['roles', 'role-profiles', 'bot-defaults', 'skills', 'team', 'connectors', 'insights', 'whiteboards'];
64
+ let activeHash = location.hash || '#/';
65
+ let ownerAvatar = null;
66
+ let updateBehind = false;
67
+ let latestVersion = null;
68
+ let routeRoot = null;
69
+ let appRoot = null;
70
+ const routeState = createDashboardRouteState();
71
+ const OWNER_AVATAR_KEY = 'botmux.ownerAvatar.v1';
72
+ const BUSY_STATUSES = new Set(['working', 'analyzing', 'active', 'starting']);
73
+ const AUTH_EXPIRED_EVENT = 'botmux:auth-expired';
74
+ function icon(children) {
75
+ return _jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", children: children });
76
+ }
77
+ function labelOf(item) {
78
+ return item.labelKey ? t(item.labelKey) : (item.label ?? '');
79
+ }
80
+ function isActiveNav(item, hash) {
81
+ const current = hash || '#/';
82
+ if (item.id === 'workflows' &&
83
+ (current === '#/legacy-workflow' || current.startsWith('#/legacy-workflow?') || current.startsWith('#/legacy-workflow/'))) {
84
+ return true;
85
+ }
86
+ if (item.id === 'sessions' &&
87
+ (current === '#/monitor-room' || current.startsWith('#/monitor-room?') || current.startsWith('#/monitor-room/'))) {
88
+ return true;
89
+ }
90
+ if (item.id === 'connectors' && (current === '#/webhook-logs' || current.startsWith('#/webhook-logs?') || current.startsWith('#/webhook-logs/'))) {
91
+ return true;
92
+ }
93
+ return item.href === current || (item.href !== '#/' && (current.startsWith(`${item.href}?`) || current.startsWith(`${item.href}/`)));
94
+ }
95
+ function navClassName(item) {
96
+ const classes = [];
97
+ if (isActiveNav(item, activeHash))
98
+ classes.push('active');
99
+ if (item.id === 'settings' && updateBehind)
100
+ classes.push('nav-has-update');
101
+ return classes.length ? classes.join(' ') : undefined;
102
+ }
103
+ function setRouteRoot(node) {
104
+ routeRoot = node;
105
+ }
106
+ function getRouteRoot() {
107
+ if (routeRoot)
108
+ return routeRoot;
109
+ const el = document.getElementById('root');
110
+ if (!el)
111
+ throw new Error('dashboard root is not mounted');
112
+ routeRoot = el;
113
+ return el;
114
+ }
115
+ function ThemeMenuSlot() {
116
+ useEffect(() => {
117
+ initThemeMenu();
118
+ }, []);
119
+ useEffect(() => {
120
+ paintThemeMenu();
121
+ });
122
+ return (_jsxs("div", { className: "theme-menu", id: "theme-menu", children: [_jsx("button", { type: "button", className: "theme-menu-btn", id: "theme-menu-btn", "aria-haspopup": "listbox", "aria-expanded": "false", "aria-label": "Theme", children: _jsx("span", { className: "tm-ic", children: _jsxs("svg", { className: "tm-svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }), _jsx("circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }), _jsx("circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }), _jsx("circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }), _jsx("path", { d: "M12 2a10 10 0 0 0 0 20h1.7a2.3 2.3 0 0 0 1.6-4c-.5-.5-.2-1.3.5-1.3H17a5 5 0 0 0 5-5 9.7 9.7 0 0 0-10-9.7z" })] }) }) }), _jsx("div", { className: "theme-menu-pop", id: "theme-menu-pop", role: "listbox", hidden: true })] }));
123
+ }
124
+ function dashboardStatusSummary() {
125
+ const sessions = [...store.sessions.values()];
126
+ const active = sessions.filter(s => s.status !== 'closed');
127
+ const attention = active
128
+ .map(s => ({ s, reason: attentionReason(s) }))
129
+ .filter((x) => !!x.reason)
130
+ .sort((a, b) => attentionWaitSince(a.s) - attentionWaitSince(b.s));
131
+ const attentionIds = new Set(attention.map(item => String(item.s.sessionId ?? '')));
132
+ const working = active.filter(s => BUSY_STATUSES.has(String(s.status)) && !attentionIds.has(String(s.sessionId ?? ''))).length;
133
+ const longest = attention[0] ?? null;
134
+ const onlineBots = buildBotCards(sessions).filter(c => c.online || c.active.length > 0).length;
135
+ const idle = Math.max(0, active.length - attention.length - working);
136
+ return {
137
+ working,
138
+ attention: attention.length,
139
+ idle,
140
+ onlineBots,
141
+ attentionNotice: longest ? {
142
+ count: attention.length,
143
+ time: relTime(attentionWaitSince(longest.s)),
144
+ bot: botDisplayName(longest.s),
145
+ reason: longest.reason,
146
+ } : null,
147
+ };
148
+ }
149
+ function TopbarStatusRow(props) {
150
+ return (_jsxs("div", { className: `topbar-status-row${props.hot ? ' topbar-status-row-hot' : ''}`, children: [_jsx("span", { children: props.label }), _jsx("b", { className: props.value > 0 ? 'status-count-on' : undefined, children: props.value })] }));
151
+ }
152
+ function TopbarStatusDonut(props) {
153
+ const { attention, idle, working } = props.summary;
154
+ const total = working + attention + idle;
155
+ const background = total === 0
156
+ ? 'conic-gradient(var(--border) 0 360deg)'
157
+ : (() => {
158
+ const workingDeg = (working / total) * 360;
159
+ const attentionDeg = workingDeg + (attention / total) * 360;
160
+ return `conic-gradient(var(--accent) 0 ${workingDeg}deg, var(--warning) ${workingDeg}deg ${attentionDeg}deg, var(--success) ${attentionDeg}deg 360deg)`;
161
+ })();
162
+ return (_jsxs("div", { className: "topbar-status-donut-wrap", "aria-hidden": "true", children: [_jsx("div", { className: "topbar-status-donut", style: { background } }), _jsxs("div", { className: "topbar-status-donut-center", children: [_jsx("b", { children: total }), _jsx("span", { children: t('overview.openSessions') })] })] }));
163
+ }
164
+ function closeThemeMenuFromStatus() {
165
+ window.dispatchEvent(new Event(CLOSE_THEME_MENU_EVENT));
166
+ }
167
+ function TopbarStatusMenu(props) {
168
+ const { autoOpen = false, summary } = props;
169
+ return (_jsxs("div", { className: `topbar-status-menu${autoOpen ? ' topbar-status-auto-open' : ''}`, onPointerEnter: closeThemeMenuFromStatus, onFocusCapture: closeThemeMenuFromStatus, children: [_jsx("span", { id: "status", className: "connection-status", "aria-haspopup": "true", "aria-expanded": autoOpen, children: t('overview.sessionOverview') }), _jsxs("div", { className: "topbar-status-pop", children: [summary.attentionNotice ? (_jsxs("a", { className: "topbar-attention-notice", href: "#/sessions", children: [_jsx("span", { className: "topbar-attention-dot", "aria-hidden": "true" }), _jsxs("span", { className: "topbar-attention-copy", children: [_jsx("b", { children: t('strip.pending', { count: summary.attentionNotice.count }) }), _jsx("small", { children: t('strip.longestCompact', {
170
+ time: summary.attentionNotice.time,
171
+ bot: summary.attentionNotice.bot,
172
+ reason: summary.attentionNotice.reason,
173
+ }) })] }), _jsx("span", { className: "topbar-attention-action", children: t('strip.handle') })] })) : null, _jsxs("div", { className: "topbar-status-list", children: [_jsx(TopbarStatusRow, { label: t('overview.workingSessions'), value: summary.working }), _jsx(TopbarStatusRow, { label: t('overview.idleSessions'), value: summary.idle }), _jsx(TopbarStatusRow, { label: t('overview.attention'), value: summary.attention, hot: summary.attention > 0 }), _jsx(TopbarStatusRow, { label: t('overview.onlineBots'), value: summary.onlineBots })] }), _jsx(TopbarStatusDonut, { summary: summary })] })] }));
174
+ }
175
+ function AuthExpiredOverlay(props) {
176
+ if (!props.open)
177
+ return null;
178
+ return (_jsx("div", { id: "auth-expired-overlay", className: "auth-expired-overlay", role: "presentation", onClick: event => { if (event.target === event.currentTarget)
179
+ props.onClose(); }, children: _jsxs("div", { className: "auth-expired-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "auth-expired-title", children: [_jsx("h2", { id: "auth-expired-title", children: "\u8BBF\u95EE\u94FE\u63A5\u5DF2\u5931\u6548" }), _jsx("p", { children: "\u5F53\u524D\u94FE\u63A5/\u8BBF\u95EE\u5DF2\u5931\u6548\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u6388\u6743\u94FE\u63A5\u91CD\u65B0\u8FDB\u5165\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09\u3002" }), _jsx("button", { id: "auth-expired-dismiss", type: "button", className: "primary", onClick: props.onClose, children: "\u77E5\u9053\u4E86" })] }) }));
180
+ }
181
+ function DashboardShell() {
182
+ const statusSummary = dashboardStatusSummary();
183
+ const [botOnboardingOpen, setBotOnboardingOpen] = useState(false);
184
+ const [authExpiredOpen, setAuthExpiredOpen] = useState(false);
185
+ const [statusAutoOpen, setStatusAutoOpen] = useState(false);
186
+ const previousAttentionRef = useRef(statusSummary.attention);
187
+ const statusAutoOpenTimerRef = useRef(null);
188
+ const clearStatusAutoOpenTimer = () => {
189
+ if (statusAutoOpenTimerRef.current === null)
190
+ return;
191
+ window.clearTimeout(statusAutoOpenTimerRef.current);
192
+ statusAutoOpenTimerRef.current = null;
193
+ };
194
+ useEffect(() => {
195
+ const open = () => setBotOnboardingOpen(true);
196
+ window.addEventListener(OPEN_BOT_ONBOARDING_EVENT, open);
197
+ return () => window.removeEventListener(OPEN_BOT_ONBOARDING_EVENT, open);
198
+ }, []);
199
+ useEffect(() => {
200
+ const open = () => setAuthExpiredOpen(true);
201
+ window.addEventListener(AUTH_EXPIRED_EVENT, open);
202
+ // Catch a 401 that latched expiredShown before this listener mounted (else the overlay
203
+ // would be permanently suppressed by the module-level guard).
204
+ if (expiredShown)
205
+ setAuthExpiredOpen(true);
206
+ return () => window.removeEventListener(AUTH_EXPIRED_EVENT, open);
207
+ }, []);
208
+ useEffect(() => {
209
+ return () => clearStatusAutoOpenTimer();
210
+ }, []);
211
+ useEffect(() => {
212
+ const previousAttention = previousAttentionRef.current;
213
+ previousAttentionRef.current = statusSummary.attention;
214
+ if (statusSummary.attention === 0) {
215
+ clearStatusAutoOpenTimer();
216
+ setStatusAutoOpen(false);
217
+ return;
218
+ }
219
+ if (previousAttention !== 0 || document.body.classList.contains('theme-menu-open'))
220
+ return;
221
+ setStatusAutoOpen(true);
222
+ clearStatusAutoOpenTimer();
223
+ statusAutoOpenTimerRef.current = window.setTimeout(() => {
224
+ statusAutoOpenTimerRef.current = null;
225
+ setStatusAutoOpen(false);
226
+ }, 4000);
227
+ }, [statusSummary.attention]);
228
+ const closeAuthExpired = () => {
229
+ expiredShown = false;
230
+ setAuthExpiredOpen(false);
231
+ };
232
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "aurora", "aria-hidden": "true", children: [_jsx("i", { className: "a1" }), _jsx("i", { className: "a2" }), _jsx("i", { className: "a3" })] }), _jsxs("div", { className: "app-shell", children: [_jsxs("header", { className: "topbar", children: [_jsx("div", { className: "topbar-left", children: _jsxs("a", { className: "brand", href: "#/", children: [_jsx("span", { className: "brand-mark", "aria-hidden": "true", children: _jsx("img", { className: "brand-logo-img", src: "/assets/brand-logo.png", alt: "", decoding: "sync", loading: "eager", fetchPriority: "high" }) }), _jsx("strong", { className: "brand-wordmark", children: "Botmux" }), _jsx("span", { className: "brand-product", children: "Dashboard" })] }) }), _jsxs("div", { className: "topbar-actions", children: [_jsx(TopbarStatusMenu, { summary: statusSummary, autoOpen: statusAutoOpen }), _jsxs("div", { className: "topbar-tool-group", children: [_jsx("button", { type: "button", className: "topbar-locale-toggle", "aria-label": ui.locale === 'zh' ? 'Switch to English' : '切换到中文', title: ui.locale === 'zh' ? 'Switch to English' : '切换到中文', onClick: () => setLocale(ui.locale === 'zh' ? 'en' : 'zh'), children: ui.locale === 'zh' ? 'CN' : 'EN' }), _jsx(ThemeMenuSlot, {}), _jsxs("a", { className: "topbar-docs-link", href: "https://bytedance.aiforce.cloud/app/app_4k9smq6rdxher/", target: "_blank", rel: "noopener noreferrer", title: t('nav.docs'), "aria-label": t('nav.docs'), children: [icon(_jsxs(_Fragment, { children: [_jsx("rect", { x: "2.2", y: "2.2", width: "11.6", height: "11.6", rx: "2" }), _jsx("path", { d: "M4.8 5.2h6.4M4.8 8h6.4M4.8 10.8h4" })] })), _jsx("span", { children: t('nav.docs') })] })] }), _jsxs("span", { className: "topbar-owner", title: ownerAvatar?.name, "aria-label": ownerAvatar?.name ?? 'Owner', children: [_jsx("span", { className: "topbar-owner-placeholder", "aria-hidden": "true", children: icon(_jsxs(_Fragment, { children: [_jsx("circle", { cx: "8", cy: "6", r: "2.4" }), _jsx("path", { d: "M3.7 13c.7-2.5 2.2-3.7 4.3-3.7s3.6 1.2 4.3 3.7" })] })) }), ownerAvatar?.avatarUrl ? (_jsx("img", { className: "topbar-owner-img", src: ownerAvatar.avatarUrl, alt: "", decoding: "async", referrerPolicy: "no-referrer", onError: (e) => { e.currentTarget.remove(); } })) : null] })] })] }), _jsxs("div", { className: "chrome-body", children: [_jsx("aside", { className: "sidebar", children: _jsx("nav", { className: "sidebar-nav", "aria-label": "Dashboard", children: NAV_ITEMS.filter(item => isAuthed || !item.manage).map(item => (_jsxs("a", { href: item.href, "data-route": item.id, className: navClassName(item), children: [icon(item.icon), _jsx("span", { className: "sidebar-nav-label", children: labelOf(item) }), item.id === 'settings' && updateBehind ? (_jsx(InfoTip, { className: "nav-update-tip", label: t('update.navBadgeTitle', { version: latestVersion ? `v${latestVersion}` : '' }), trigger: _jsx("span", { className: "nav-update-dot", "aria-hidden": "true" }), preventClick: false, focusable: false, children: t('update.navBadgeTitle', { version: latestVersion ? `v${latestVersion}` : '' }) })) : null] }, item.id))) }) }), _jsxs("div", { className: "workspace", children: [_jsx("dialog", { id: "create-session-modal", className: "create-session-modal" }), _jsx(BotOnboardingDialog, { open: botOnboardingOpen, onClose: () => setBotOnboardingOpen(false) }), _jsx("main", { id: "root", ref: setRouteRoot })] })] })] }), _jsx(AuthExpiredOverlay, { open: authExpiredOpen, onClose: closeAuthExpired })] }));
233
+ }
234
+ function renderShell() {
235
+ appRoot?.render(_jsx(DashboardShell, {}));
236
+ }
237
+ function setLocale(locale) {
238
+ ui.setLocale(locale);
239
+ void persistLocale(locale);
240
+ }
22
241
  // ── Auth-expiry overlay ──────────────────────────────────────────────────────
23
- // Shown only when the dashboard token was rotated WHILE public read-only is off
24
- // (a real hard lockout). Under public read-only a 401 is a soft toast instead
25
- // (see patchedFetch) — so this no longer fires for read-only visitors.
26
- let _expiredShown = false;
242
+ let expiredShown = false;
27
243
  export function showAuthExpiredOverlay() {
28
- if (_expiredShown)
244
+ if (expiredShown)
29
245
  return;
30
- _expiredShown = true;
31
- const el = document.createElement('div');
32
- el.id = 'auth-expired-overlay';
33
- el.style.cssText =
34
- 'position:fixed;inset:0;background:rgba(0,0,0,.65);display:flex;' +
35
- 'align-items:center;justify-content:center;z-index:9999';
36
- el.innerHTML =
37
- '<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:12px;' +
38
- 'padding:36px 40px;max-width:460px;width:90vw;text-align:center;' +
39
- 'box-shadow:0 12px 40px rgba(0,0,0,.35)">' +
40
- '<h2 style="margin:0 0 14px;font-size:19px;color:var(--fg)">访问链接已失效</h2>' +
41
- '<p style="margin:0 0 24px;line-height:1.7;color:var(--muted,#8f959e);font-size:14px">' +
42
- '当前链接/访问已失效,请使用最新授权链接重新进入(运行 botmux dashboard 获取)。</p>' +
43
- '<button id="auth-expired-dismiss" type="button" ' +
44
- 'style="padding:8px 22px;background:var(--accent);color:var(--on-accent);border:none;' +
45
- 'border-radius:8px;cursor:pointer;font-size:14px">知道了</button>' +
46
- '</div>';
47
- document.body.appendChild(el);
48
- // `window.close()` can't close a tab the user opened, so the old inline
49
- // onclick was a dead button (overlay got stuck). Dismiss the overlay instead,
50
- // and let it reappear on the next genuine 401.
51
- const dismiss = () => { el.remove(); _expiredShown = false; };
52
- el.querySelector('#auth-expired-dismiss')?.addEventListener('click', dismiss);
53
- el.addEventListener('click', (e) => { if (e.target === el)
54
- dismiss(); });
246
+ expiredShown = true;
247
+ window.dispatchEvent(new Event(AUTH_EXPIRED_EVENT));
55
248
  }
56
- // ── Read-only toast (write attempt without a valid token) ───────────────────
57
- // In public read-only mode browsing GETs never 401, but a write action
58
- // (close session, cancel run, …) without the active token does. That's not
59
- // "your link died" — it's "you're a read-only visitor", so show a transient
60
- // toast instead of the blocking overlay.
61
- let _roToastTimer;
249
+ let roToastTimer;
62
250
  export function showReadOnlyToast() {
63
251
  let el = document.getElementById('readonly-toast');
64
252
  if (!el) {
@@ -67,29 +255,21 @@ export function showReadOnlyToast() {
67
255
  el.style.cssText =
68
256
  'position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:9999;' +
69
257
  'background:var(--fg,#1f2329);color:var(--bg,#fff);padding:10px 18px;' +
70
- 'border-radius:8px;font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.25)';
258
+ 'border-radius:var(--radius-lg);font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.25)';
71
259
  document.body.appendChild(el);
72
260
  }
73
261
  el.textContent = '当前是只读访问,此操作需要授权链接(运行 botmux dashboard 获取)';
74
262
  el.style.display = 'block';
75
- if (_roToastTimer)
76
- window.clearTimeout(_roToastTimer);
77
- _roToastTimer = window.setTimeout(() => { el.style.display = 'none'; }, 4000);
263
+ if (roToastTimer)
264
+ window.clearTimeout(roToastTimer);
265
+ roToastTimer = window.setTimeout(() => { el.style.display = 'none'; }, 4000);
78
266
  }
79
- // Patch the global fetch to route 401s: a read (GET/HEAD) 401 means the token
80
- // was rotated while this tab was open (only possible when public read-only
81
- // mode is off) → blocking overlay; a write 401 means "read-only visitor" →
82
- // transient toast.
83
- const _origFetch = window.fetch.bind(window);
267
+ const origFetch = window.fetch.bind(window);
84
268
  window.fetch = async function patchedFetch(...args) {
85
- const res = await _origFetch(...args);
269
+ const res = await origFetch(...args);
86
270
  if (res.status === 401) {
87
271
  const method = (args[1]?.method ?? 'GET').toUpperCase();
88
272
  const isRead = method === 'GET' || method === 'HEAD';
89
- // A read 401 is a hard lockout (token rotated → blocking overlay) ONLY when
90
- // public read-only is off. Under public read-only a read 401 just means a
91
- // tokenless visitor touched a token-gated page → soft toast, never the
92
- // stuck overlay. Writes are always a soft "needs the active token".
93
273
  if (isRead && !publicReadOnly)
94
274
  showAuthExpiredOverlay();
95
275
  else
@@ -97,61 +277,15 @@ window.fetch = async function patchedFetch(...args) {
97
277
  }
98
278
  return res;
99
279
  };
100
- // ── 全局 attention strip ─────────────────────────────────────────────────────
101
- // 「需要你」是全局最高优先级:不管在哪个页面,待处理数和最久等待项都常驻
102
- // 顶部一条琥珀色 strip,点「立即处理」跳到会话页(needs-you 列置顶)。
103
- let lastStripHtml = '';
104
- function paintAttentionStrip() {
105
- const el = document.getElementById('attention-strip');
106
- if (!el)
107
- return;
108
- const pending = [...store.sessions.values()]
109
- .map(s => ({ s, reason: attentionReason(s) }))
110
- .filter((x) => !!x.reason)
111
- .sort((a, b) => attentionWaitSince(a.s) - attentionWaitSince(b.s));
112
- if (pending.length === 0) {
113
- el.hidden = true;
114
- el.innerHTML = '';
115
- lastStripHtml = '';
116
- return;
117
- }
118
- const longest = pending[0];
119
- const html = `
120
- <span class="attention-strip-ic" aria-hidden="true">!</span>
121
- <b>${escapeHtml(t('strip.pending', { count: pending.length }))}</b>
122
- <span class="attention-strip-longest">${escapeHtml(t('strip.longest', {
123
- time: relTime(attentionWaitSince(longest.s)),
124
- bot: botDisplayName(longest.s),
125
- reason: longest.reason,
126
- }))}</span>
127
- <a class="attention-strip-go" href="#/sessions">${escapeHtml(t('strip.handle'))}</a>`;
128
- el.hidden = false;
129
- // 内容没变就不重写 — innerHTML 重建会把 strip-pulse 动画打回起点(视觉跳变)
130
- if (html === lastStripHtml)
131
- return;
132
- lastStripHtml = html;
133
- el.innerHTML = html;
134
- }
135
- store.on(paintAttentionStrip);
136
- // bot 友好名异步解析回来后刷一次 strip(页面级重绘由各 mount 自己处理)
137
- void loadNameMaps().then(paintAttentionStrip);
138
- // Resolve the read-only/authed state from /api/settings (authed reflects the
139
- // cookie; publicReadOnly is the global toggle). Errors keep the authed default
140
- // so a transient probe failure never hides nav from a real token holder.
141
280
  async function loadAuthState() {
142
281
  try {
143
282
  const r = await fetch('/api/settings');
144
283
  if (r.ok) {
145
284
  const j = await r.json();
146
285
  isAuthed = !!j.authed;
147
- // Share the cookie-auth verdict with per-row renderers (the sessions
148
- // board's writable-terminal segment reads ui.authed at render time).
149
286
  ui.authed = isAuthed;
150
287
  publicReadOnly = !!(j.settings && j.settings.publicReadOnly);
151
- // The global UI locale (`botmux lang`) is the single source of truth: when
152
- // set, it wins over the browser-detected / locally-stored locale so the
153
- // dashboard always reflects the same language as the Feishu cards. When
154
- // unset (null), keep the browser/local default ui.init() already picked.
288
+ ui.publicReadOnly = publicReadOnly;
155
289
  const serverLocale = normalizeDashboardLocale(j.lang);
156
290
  if (serverLocale)
157
291
  ui.setLocale(serverLocale);
@@ -159,10 +293,6 @@ async function loadAuthState() {
159
293
  }
160
294
  catch { /* keep defaults */ }
161
295
  }
162
- // Persist a language choice back to the global config so it drives `botmux lang`
163
- // and the Feishu cards too (the server fans the change out to every daemon
164
- // live). Authed-only — read-only visitors just change their local view, which
165
- // the server-authoritative locale overrides on their next load.
166
296
  async function persistLocale(locale) {
167
297
  if (!isAuthed)
168
298
  return;
@@ -175,26 +305,6 @@ async function persistLocale(locale) {
175
305
  }
176
306
  catch { /* best-effort; UI already switched locally */ }
177
307
  }
178
- // Read-only visitors can't use the management pages (all token-gated), so hide
179
- // their nav entries + the add-bot action instead of luring them into a 401.
180
- function applyAuthVisibility() {
181
- for (const r of MANAGE_ROUTES) {
182
- const a = document.querySelector(`.sidebar-nav a[data-route="${r}"]`);
183
- if (a)
184
- a.style.display = isAuthed ? '' : 'none';
185
- }
186
- const addBot = document.getElementById('add-bot-btn');
187
- if (addBot)
188
- addBot.style.display = isAuthed ? '' : 'none';
189
- // 创建会话同为管理动作(/api/sessions/create token-gated),只读访客隐藏。
190
- const createSession = document.getElementById('create-session-btn');
191
- if (createSession)
192
- createSession.style.display = isAuthed ? '' : 'none';
193
- }
194
- // Show a small dot on the Settings nav when a newer botmux version is published,
195
- // so an available update is visible without opening the page. Authed-only (the
196
- // status endpoint is token-gated; the result is server-cached so this is cheap).
197
- // Best-effort and silent on failure.
198
308
  async function checkUpdateBadge() {
199
309
  if (!isAuthed)
200
310
  return;
@@ -203,68 +313,40 @@ async function checkUpdateBadge() {
203
313
  if (!r.ok)
204
314
  return;
205
315
  const j = await r.json();
206
- const a = document.querySelector('.sidebar-nav a[data-route="settings"]');
207
- if (!a)
208
- return;
209
- const behind = j.behind === true;
210
- a.classList.toggle('nav-has-update', behind);
211
- if (behind)
212
- a.title = t('update.navBadgeTitle', { version: `v${j.latest}` });
213
- else
214
- a.removeAttribute('title');
316
+ updateBehind = j.behind === true;
317
+ latestVersion = updateBehind && j.latest ? String(j.latest) : null;
318
+ renderShell();
215
319
  }
216
320
  catch { /* best-effort */ }
217
321
  }
218
322
  function renderAuthRequiredPage(host) {
219
323
  host.innerHTML =
220
324
  '<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;' +
221
- 'background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;' +
325
+ 'background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:var(--radius-lg);' +
222
326
  'padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)">' +
223
327
  '<h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">此页需要授权链接</h2>' +
224
328
  '<p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">' +
225
329
  '你当前是只读访问,管理页(群角色 / Profiles / Bot 配置 / 团队 / Webhook)需要授权链接。' +
226
330
  '运行 <code>botmux dashboard</code> 获取最新链接后即可管理。</p>' +
227
331
  '<a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);' +
228
- 'color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">返回总览</a>' +
332
+ 'color:var(--on-accent);border-radius:var(--radius-lg);text-decoration:none;font-size:14px">返回总览</a>' +
229
333
  '</section>';
230
334
  }
231
- // Pages that own a polling loop / cleanup return a disposer; we run it
232
- // on the next route switch so timers don't leak across navigations.
233
- const routeState = createDashboardRouteState();
234
- function highlightNav(hash) {
235
- for (const a of document.querySelectorAll('.sidebar-nav a')) {
236
- const href = a.getAttribute('href') ?? '#/';
237
- const current = hash || '#/';
238
- const isActive = href === current || (href !== '#/' && (current.startsWith(`${href}?`) || current.startsWith(`${href}/`)));
239
- a.classList.toggle('active', isActive);
240
- }
241
- }
242
335
  async function route() {
243
336
  const seq = beginDashboardRoute(routeState);
244
337
  const hash = location.hash || '#/';
245
- // Read-only hard-guard: a tokenless visitor hitting a management route gets a
246
- // friendly notice instead of a page that fires a 401 (which used to pop a
247
- // stuck "link expired" overlay).
338
+ activeHash = hash;
339
+ renderShell();
248
340
  if (!isAuthed && MANAGE_ROUTES.some(r => hash.startsWith('#/' + r))) {
249
- renderAuthRequiredPage(root);
341
+ renderAuthRequiredPage(getRouteRoot());
250
342
  routeState.rerenderOnUiChange = true;
251
- highlightNav(hash);
252
343
  return;
253
344
  }
254
- // The "工作流" nav now points at the v3 runs page (#/workflows). The v2 (v0.2)
255
- // engine is kept (backend + Feishu cards), so its run-detail page survives at
256
- // the dedicated #/legacy-workflow route (where v2 cards now link). Legacy URL
257
- // upkeep so old bookmarks/pasted links don't 404:
258
- // - `#/v3[/<id>]` → `#/workflows[/<id>]` (v3 promoted)
259
- // - `#/workflows/catalog`, `#/workflows-catalog` → `#/workflows` (v2 catalog gone)
260
345
  if (hash.startsWith('#/v3')) {
261
346
  window.location.replace(`#/workflows${hash.slice('#/v3'.length)}`);
262
347
  return;
263
348
  }
264
349
  else if (/^#\/workflows(?:\/|-)catalog(?:[/?].*)?$/.test(hash)) {
265
- // Bounded match (NOT startsWith): a v3 runId can begin with "catalog"
266
- // (goal slug → `catalog-all-open-prs-…`), and `#/workflows/catalog-…`
267
- // must open that run's detail, not bounce to the list.
268
350
  window.location.replace('#/workflows');
269
351
  return;
270
352
  }
@@ -274,133 +356,64 @@ async function route() {
274
356
  }
275
357
  try {
276
358
  const matched = findDashboardRoute(hash);
277
- await loadAndRenderDashboardRoute(routeState, seq, root, matched ? matched.load : loadOverviewPage, { rerenderOnUiChange: matched ? matched.rerenderOnUiChange : false });
359
+ await loadAndRenderDashboardRoute(routeState, seq, getRouteRoot(), matched ? matched.load : loadOverviewPage, { rerenderOnUiChange: matched ? matched.rerenderOnUiChange : false });
278
360
  }
279
361
  catch (err) {
280
362
  if (seq !== routeState.seq)
281
363
  return;
282
- root.innerHTML = `<section class="page"><div class="empty">Dashboard route failed: ${escapeHtml(String(err))}</div></section>`;
364
+ getRouteRoot().innerHTML = `<section class="page"><div class="empty">Dashboard route failed: ${escapeHtml(String(err))}</div></section>`;
283
365
  routeState.pageDispose = null;
284
366
  routeState.rerenderOnUiChange = true;
285
367
  }
286
- finally {
287
- if (seq === routeState.seq)
288
- highlightNav(hash);
289
- }
290
- }
291
- const statusEl = document.getElementById('status');
292
- function paintStatus() {
293
- if (!statusEl)
294
- return;
295
- statusEl.textContent = store.online ? t('status.live') : t('status.disconnected');
296
- statusEl.className = 'connection-status ' + (store.online ? 'online' : 'offline');
297
- }
298
- store.on(paintStatus);
299
- function paintChrome() {
300
- document.querySelectorAll('[data-i18n]').forEach(el => {
301
- el.textContent = t(el.dataset.i18n ?? '');
302
- });
303
- document.querySelectorAll('[data-locale]').forEach(btn => {
304
- btn.classList.toggle('active', btn.dataset.locale === ui.locale);
305
- });
306
- paintThemeMenu();
307
- paintStatus();
308
- }
309
- function wireChromeControls() {
310
- document.querySelectorAll('[data-locale]').forEach(btn => {
311
- btn.onclick = () => {
312
- const locale = btn.dataset.locale;
313
- ui.setLocale(locale);
314
- void persistLocale(locale);
315
- };
316
- });
317
- initThemeMenu();
318
- wireSidebarToggle();
319
368
  }
320
- // 左上角 brand 显示部署 owner(「我」)的飞书头像:localStorage 缓存先出图
321
- // 防闪烁,再后台刷新;拿不到(未绑定 owner / 只读访客 401)保持渐变球。
322
- const OWNER_AVATAR_KEY = 'botmux.ownerAvatar.v1';
323
- function paintOwnerAvatar(avatarUrl, name) {
324
- const mark = document.querySelector('.brand-mark');
325
- if (!mark || !avatarUrl)
326
- return;
327
- mark.innerHTML = `<img class="brand-owner-img" src="${escapeHtml(avatarUrl)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`;
328
- if (name)
329
- mark.title = name;
330
- }
331
- function initOwnerAvatar() {
369
+ function readCachedOwnerAvatar() {
332
370
  try {
333
371
  const cached = JSON.parse(window.localStorage.getItem(OWNER_AVATAR_KEY) ?? 'null');
334
- if (cached?.avatarUrl)
335
- paintOwnerAvatar(String(cached.avatarUrl), cached.name ? String(cached.name) : undefined);
372
+ if (cached?.avatarUrl) {
373
+ return {
374
+ avatarUrl: String(cached.avatarUrl),
375
+ name: cached.name ? String(cached.name) : undefined,
376
+ };
377
+ }
336
378
  }
337
- catch { /* 缓存损坏忽略 */ }
379
+ catch { /* ignore corrupt cache */ }
380
+ return null;
381
+ }
382
+ function initOwnerAvatar() {
383
+ ownerAvatar = readCachedOwnerAvatar();
384
+ renderShell();
338
385
  void fetch('/api/owner-profile')
339
386
  .then(r => (r.ok ? r.json() : null))
340
387
  .then(body => {
341
388
  if (!body?.ok || !body.avatarUrl)
342
389
  return;
343
- paintOwnerAvatar(String(body.avatarUrl), body.name ? String(body.name) : undefined);
390
+ ownerAvatar = { avatarUrl: String(body.avatarUrl), name: body.name ? String(body.name) : undefined };
344
391
  try {
345
392
  window.localStorage.setItem(OWNER_AVATAR_KEY, JSON.stringify({ avatarUrl: body.avatarUrl, name: body.name ?? '' }));
346
393
  }
347
- catch { /* 忽略 */ }
394
+ catch { /* ignore */ }
395
+ renderShell();
348
396
  })
349
397
  .catch(() => { });
350
398
  }
351
- // 左侧菜单栏收起/展开:状态挂在 <html data-sidebar>,CSS 收窄成图标栏;
352
- // 偏好进 localStorage,刷新/换页保持。
353
- function wireSidebarToggle() {
354
- const btn = document.getElementById('sidebar-toggle');
355
- if (!btn)
356
- return;
357
- let mode = readStoredSidebarMode(window.localStorage);
358
- const apply = () => {
359
- document.documentElement.dataset.sidebar = mode;
360
- btn.title = t(mode === 'collapsed' ? 'nav.sidebarExpand' : 'nav.sidebarCollapse');
361
- };
362
- apply();
363
- btn.addEventListener('click', () => {
364
- mode = mode === 'collapsed' ? 'expanded' : 'collapsed';
365
- writeStoredSidebarMode(window.localStorage, mode);
366
- apply();
367
- });
368
- }
369
- // 全局顶栏「创建会话」按钮:点击时按需动态 import 较重的 sessions 模块并拉起弹窗,
370
- // 让创建逻辑留在懒加载 chunk 里、不撑大主包(对应 wireBotOnboardingButton,但走懒加载)。
371
- function wireCreateSessionButton() {
372
- const btn = document.getElementById('create-session-btn');
373
- if (!btn)
374
- return;
375
- btn.onclick = async () => {
376
- btn.disabled = true;
377
- try {
378
- const mod = await import('./sessions.js');
379
- await mod.openCreateSessionModal();
380
- }
381
- finally {
382
- btn.disabled = false;
383
- }
384
- };
385
- }
386
- // Keep bootstrap sequencing explicit even though the dashboard bundle is ESM.
387
399
  void (async () => {
388
400
  ui.init();
389
- wireChromeControls();
390
- wireBotOnboardingButton();
391
- wireCreateSessionButton();
401
+ const host = document.getElementById('app-root');
402
+ if (!host)
403
+ throw new Error('missing dashboard app root');
404
+ initFloatingScrollbars(host);
405
+ appRoot = createRoot(host);
406
+ renderShell();
392
407
  ui.on(() => {
393
- paintChrome();
394
- paintAttentionStrip();
408
+ renderShell();
395
409
  if (routeState.rerenderOnUiChange)
396
410
  void route();
397
411
  });
398
- paintChrome();
399
- paintAttentionStrip();
400
- // Resolve authed/publicReadOnly BEFORE first render so the management nav is
401
- // hidden and route guards are active for read-only visitors from frame one.
412
+ store.on(() => {
413
+ renderShell();
414
+ });
402
415
  await loadAuthState();
403
- applyAuthVisibility();
416
+ renderShell();
404
417
  void checkUpdateBadge();
405
418
  initOwnerAvatar();
406
419
  try {
@@ -410,7 +423,9 @@ void (async () => {
410
423
  console.error('botmux dashboard bootstrap failed', err);
411
424
  store.setOnline(false);
412
425
  }
413
- window.addEventListener('hashchange', () => void route());
426
+ void loadNameMaps().then(renderShell);
427
+ void loadGroupsSnapshot().then(renderShell);
428
+ window.addEventListener('hashchange', () => { void route(); });
414
429
  void route();
415
430
  })();
416
431
  //# sourceMappingURL=app.js.map