botmux 3.16.0 → 3.17.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 (619) hide show
  1. package/dist/.runtime-build-id +1 -1
  2. package/dist/adapters/backend/riff-backend.d.ts +84 -1
  3. package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
  4. package/dist/adapters/backend/riff-backend.js +202 -19
  5. package/dist/adapters/backend/riff-backend.js.map +1 -1
  6. package/dist/adapters/backend/sandbox.d.ts +8 -0
  7. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  8. package/dist/adapters/backend/sandbox.js +15 -0
  9. package/dist/adapters/backend/sandbox.js.map +1 -1
  10. package/dist/adapters/backend/tmux-backend.d.ts +61 -7
  11. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  12. package/dist/adapters/backend/tmux-backend.js +80 -9
  13. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  14. package/dist/adapters/backend/tmux-pipe-backend.d.ts +62 -4
  15. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  16. package/dist/adapters/backend/tmux-pipe-backend.js +240 -27
  17. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  18. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  19. package/dist/adapters/cli/claude-code.js +4 -2
  20. package/dist/adapters/cli/claude-code.js.map +1 -1
  21. package/dist/adapters/cli/coco.d.ts.map +1 -1
  22. package/dist/adapters/cli/coco.js +27 -0
  23. package/dist/adapters/cli/coco.js.map +1 -1
  24. package/dist/adapters/cli/codex-app.d.ts.map +1 -1
  25. package/dist/adapters/cli/codex-app.js +28 -0
  26. package/dist/adapters/cli/codex-app.js.map +1 -1
  27. package/dist/adapters/cli/codex.d.ts.map +1 -1
  28. package/dist/adapters/cli/codex.js +51 -23
  29. package/dist/adapters/cli/codex.js.map +1 -1
  30. package/dist/adapters/cli/dsh-tui.d.ts +24 -0
  31. package/dist/adapters/cli/dsh-tui.d.ts.map +1 -0
  32. package/dist/adapters/cli/dsh-tui.js +99 -0
  33. package/dist/adapters/cli/dsh-tui.js.map +1 -0
  34. package/dist/adapters/cli/dsh.d.ts.map +1 -1
  35. package/dist/adapters/cli/dsh.js +15 -9
  36. package/dist/adapters/cli/dsh.js.map +1 -1
  37. package/dist/adapters/cli/fs-policy.d.ts +98 -1
  38. package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
  39. package/dist/adapters/cli/fs-policy.js +182 -7
  40. package/dist/adapters/cli/fs-policy.js.map +1 -1
  41. package/dist/adapters/cli/grok.js +16 -18
  42. package/dist/adapters/cli/grok.js.map +1 -1
  43. package/dist/adapters/cli/model-catalog-json.d.ts +17 -0
  44. package/dist/adapters/cli/model-catalog-json.d.ts.map +1 -0
  45. package/dist/adapters/cli/model-catalog-json.js +43 -0
  46. package/dist/adapters/cli/model-catalog-json.js.map +1 -0
  47. package/dist/adapters/cli/oh-my-pi.d.ts +2 -0
  48. package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
  49. package/dist/adapters/cli/oh-my-pi.js +45 -13
  50. package/dist/adapters/cli/oh-my-pi.js.map +1 -1
  51. package/dist/adapters/cli/opencode.js +1 -1
  52. package/dist/adapters/cli/opencode.js.map +1 -1
  53. package/dist/adapters/cli/registry.d.ts +2 -1
  54. package/dist/adapters/cli/registry.d.ts.map +1 -1
  55. package/dist/adapters/cli/registry.js +6 -1
  56. package/dist/adapters/cli/registry.js.map +1 -1
  57. package/dist/adapters/cli/relay.d.ts.map +1 -1
  58. package/dist/adapters/cli/relay.js +7 -0
  59. package/dist/adapters/cli/relay.js.map +1 -1
  60. package/dist/adapters/cli/seed.d.ts.map +1 -1
  61. package/dist/adapters/cli/seed.js +6 -0
  62. package/dist/adapters/cli/seed.js.map +1 -1
  63. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  64. package/dist/adapters/cli/shared-hints.js +20 -14
  65. package/dist/adapters/cli/shared-hints.js.map +1 -1
  66. package/dist/adapters/cli/traex.d.ts +4 -0
  67. package/dist/adapters/cli/traex.d.ts.map +1 -1
  68. package/dist/adapters/cli/traex.js +153 -0
  69. package/dist/adapters/cli/traex.js.map +1 -1
  70. package/dist/adapters/cli/types.d.ts +42 -1
  71. package/dist/adapters/cli/types.d.ts.map +1 -1
  72. package/dist/autostart.d.ts +6 -0
  73. package/dist/autostart.d.ts.map +1 -1
  74. package/dist/autostart.js +21 -1
  75. package/dist/autostart.js.map +1 -1
  76. package/dist/bot-registry.d.ts +27 -0
  77. package/dist/bot-registry.d.ts.map +1 -1
  78. package/dist/bot-registry.js +62 -2
  79. package/dist/bot-registry.js.map +1 -1
  80. package/dist/cli/vc-agent.d.ts.map +1 -1
  81. package/dist/cli/vc-agent.js +21 -3
  82. package/dist/cli/vc-agent.js.map +1 -1
  83. package/dist/cli.d.ts.map +1 -1
  84. package/dist/cli.js +92 -1
  85. package/dist/cli.js.map +1 -1
  86. package/dist/codex-app-runner.js +28 -0
  87. package/dist/codex-app-runner.js.map +1 -1
  88. package/dist/core/bot-steer-directive.d.ts +25 -0
  89. package/dist/core/bot-steer-directive.d.ts.map +1 -0
  90. package/dist/core/bot-steer-directive.js +47 -0
  91. package/dist/core/bot-steer-directive.js.map +1 -0
  92. package/dist/core/command-handler.d.ts.map +1 -1
  93. package/dist/core/command-handler.js +102 -18
  94. package/dist/core/command-handler.js.map +1 -1
  95. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  96. package/dist/core/dashboard-ipc-server.js +53 -13
  97. package/dist/core/dashboard-ipc-server.js.map +1 -1
  98. package/dist/core/dashboard-rows.d.ts +3 -0
  99. package/dist/core/dashboard-rows.d.ts.map +1 -1
  100. package/dist/core/dashboard-rows.js +26 -5
  101. package/dist/core/dashboard-rows.js.map +1 -1
  102. package/dist/core/dashboard-url.d.ts +10 -1
  103. package/dist/core/dashboard-url.d.ts.map +1 -1
  104. package/dist/core/dashboard-url.js +12 -2
  105. package/dist/core/dashboard-url.js.map +1 -1
  106. package/dist/core/dispatch.d.ts.map +1 -1
  107. package/dist/core/dispatch.js +5 -4
  108. package/dist/core/dispatch.js.map +1 -1
  109. package/dist/core/existing-app-server.d.ts +22 -0
  110. package/dist/core/existing-app-server.d.ts.map +1 -0
  111. package/dist/core/existing-app-server.js +85 -0
  112. package/dist/core/existing-app-server.js.map +1 -0
  113. package/dist/core/native-topic-id.d.ts +9 -0
  114. package/dist/core/native-topic-id.d.ts.map +1 -0
  115. package/dist/core/native-topic-id.js +14 -0
  116. package/dist/core/native-topic-id.js.map +1 -0
  117. package/dist/core/per-bot-env.d.ts.map +1 -1
  118. package/dist/core/per-bot-env.js +10 -0
  119. package/dist/core/per-bot-env.js.map +1 -1
  120. package/dist/core/plugins/mcp/gateway.d.ts +27 -3
  121. package/dist/core/plugins/mcp/gateway.d.ts.map +1 -1
  122. package/dist/core/plugins/mcp/gateway.js +272 -26
  123. package/dist/core/plugins/mcp/gateway.js.map +1 -1
  124. package/dist/core/plugins/mcp/host.d.ts +18 -0
  125. package/dist/core/plugins/mcp/host.d.ts.map +1 -1
  126. package/dist/core/plugins/mcp/host.js +80 -16
  127. package/dist/core/plugins/mcp/host.js.map +1 -1
  128. package/dist/core/plugins/mcp/launch-record.d.ts +14 -0
  129. package/dist/core/plugins/mcp/launch-record.d.ts.map +1 -0
  130. package/dist/core/plugins/mcp/launch-record.js +63 -0
  131. package/dist/core/plugins/mcp/launch-record.js.map +1 -0
  132. package/dist/core/session-activity.d.ts +11 -0
  133. package/dist/core/session-activity.d.ts.map +1 -1
  134. package/dist/core/session-activity.js +23 -0
  135. package/dist/core/session-activity.js.map +1 -1
  136. package/dist/core/session-group-birth.d.ts.map +1 -1
  137. package/dist/core/session-group-birth.js +23 -8
  138. package/dist/core/session-group-birth.js.map +1 -1
  139. package/dist/core/session-manager.d.ts +1 -4
  140. package/dist/core/session-manager.d.ts.map +1 -1
  141. package/dist/core/session-manager.js +16 -20
  142. package/dist/core/session-manager.js.map +1 -1
  143. package/dist/core/shared-adopt.d.ts +20 -0
  144. package/dist/core/shared-adopt.d.ts.map +1 -0
  145. package/dist/core/shared-adopt.js +26 -0
  146. package/dist/core/shared-adopt.js.map +1 -0
  147. package/dist/core/skills/customize-command.d.ts +7 -0
  148. package/dist/core/skills/customize-command.d.ts.map +1 -0
  149. package/dist/core/skills/customize-command.js +303 -0
  150. package/dist/core/skills/customize-command.js.map +1 -0
  151. package/dist/core/terminal-write-auth.d.ts +15 -0
  152. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  153. package/dist/core/terminal-write-auth.js +15 -0
  154. package/dist/core/terminal-write-auth.js.map +1 -1
  155. package/dist/core/terminal-write-frame.d.ts +30 -0
  156. package/dist/core/terminal-write-frame.d.ts.map +1 -0
  157. package/dist/core/terminal-write-frame.js +44 -0
  158. package/dist/core/terminal-write-frame.js.map +1 -0
  159. package/dist/core/types.d.ts +14 -4
  160. package/dist/core/types.d.ts.map +1 -1
  161. package/dist/core/types.js +6 -8
  162. package/dist/core/types.js.map +1 -1
  163. package/dist/core/worker-pool.d.ts +31 -6
  164. package/dist/core/worker-pool.d.ts.map +1 -1
  165. package/dist/core/worker-pool.js +444 -102
  166. package/dist/core/worker-pool.js.map +1 -1
  167. package/dist/core/worker-startup-retry.d.ts +52 -0
  168. package/dist/core/worker-startup-retry.d.ts.map +1 -0
  169. package/dist/core/worker-startup-retry.js +68 -0
  170. package/dist/core/worker-startup-retry.js.map +1 -0
  171. package/dist/daemon.d.ts +9 -8
  172. package/dist/daemon.d.ts.map +1 -1
  173. package/dist/daemon.js +467 -171
  174. package/dist/daemon.js.map +1 -1
  175. package/dist/dashboard/autostart-api.d.ts +26 -0
  176. package/dist/dashboard/autostart-api.d.ts.map +1 -0
  177. package/dist/dashboard/autostart-api.js +88 -0
  178. package/dist/dashboard/autostart-api.js.map +1 -0
  179. package/dist/dashboard/bot-payload.d.ts +5 -0
  180. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  181. package/dist/dashboard/bot-payload.js +2 -0
  182. package/dist/dashboard/bot-payload.js.map +1 -1
  183. package/dist/dashboard/control-csrf.d.ts +29 -1
  184. package/dist/dashboard/control-csrf.d.ts.map +1 -1
  185. package/dist/dashboard/control-csrf.js +49 -10
  186. package/dist/dashboard/control-csrf.js.map +1 -1
  187. package/dist/dashboard/customization-api.d.ts +23 -0
  188. package/dist/dashboard/customization-api.d.ts.map +1 -0
  189. package/dist/dashboard/customization-api.js +198 -0
  190. package/dist/dashboard/customization-api.js.map +1 -0
  191. package/dist/dashboard/debug-terminal.d.ts +13 -1
  192. package/dist/dashboard/debug-terminal.d.ts.map +1 -1
  193. package/dist/dashboard/debug-terminal.js +18 -4
  194. package/dist/dashboard/debug-terminal.js.map +1 -1
  195. package/dist/dashboard/settings-write-applier.d.ts +0 -23
  196. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  197. package/dist/dashboard/settings-write-applier.js +7 -28
  198. package/dist/dashboard/settings-write-applier.js.map +1 -1
  199. package/dist/dashboard/terminal-control-route.d.ts +32 -0
  200. package/dist/dashboard/terminal-control-route.d.ts.map +1 -0
  201. package/dist/dashboard/terminal-control-route.js +70 -0
  202. package/dist/dashboard/terminal-control-route.js.map +1 -0
  203. package/dist/dashboard/terminal-control.d.ts +64 -13
  204. package/dist/dashboard/terminal-control.d.ts.map +1 -1
  205. package/dist/dashboard/terminal-control.js +77 -14
  206. package/dist/dashboard/terminal-control.js.map +1 -1
  207. package/dist/dashboard/terminal-front-proxy.d.ts.map +1 -1
  208. package/dist/dashboard/terminal-front-proxy.js +41 -9
  209. package/dist/dashboard/terminal-front-proxy.js.map +1 -1
  210. package/dist/dashboard/vc-consumer-profiles-api.d.ts +69 -18
  211. package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
  212. package/dist/dashboard/vc-consumer-profiles-api.js +149 -29
  213. package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
  214. package/dist/dashboard/web/agent-workbench-api.d.ts +34 -2
  215. package/dist/dashboard/web/agent-workbench-api.d.ts.map +1 -1
  216. package/dist/dashboard/web/agent-workbench-api.js +39 -4
  217. package/dist/dashboard/web/agent-workbench-api.js.map +1 -1
  218. package/dist/dashboard/web/agent-workbench-appearance.d.ts +6 -3
  219. package/dist/dashboard/web/agent-workbench-appearance.d.ts.map +1 -1
  220. package/dist/dashboard/web/agent-workbench-appearance.js +7 -4
  221. package/dist/dashboard/web/agent-workbench-appearance.js.map +1 -1
  222. package/dist/dashboard/web/agent-workbench-model.d.ts +2 -0
  223. package/dist/dashboard/web/agent-workbench-model.d.ts.map +1 -1
  224. package/dist/dashboard/web/agent-workbench-model.js.map +1 -1
  225. package/dist/dashboard/web/agent-workbench-page.js +2 -2
  226. package/dist/dashboard/web/agent-workbench-page.js.map +1 -1
  227. package/dist/dashboard/web/agent-workbench-panes.d.ts +59 -4
  228. package/dist/dashboard/web/agent-workbench-panes.d.ts.map +1 -1
  229. package/dist/dashboard/web/agent-workbench-panes.js +493 -85
  230. package/dist/dashboard/web/agent-workbench-panes.js.map +1 -1
  231. package/dist/dashboard/web/agent-workbench-session-list.d.ts +11 -7
  232. package/dist/dashboard/web/agent-workbench-session-list.d.ts.map +1 -1
  233. package/dist/dashboard/web/agent-workbench-session-list.js +24 -31
  234. package/dist/dashboard/web/agent-workbench-session-list.js.map +1 -1
  235. package/dist/dashboard/web/agent-workbench-terminal-control.d.ts +198 -0
  236. package/dist/dashboard/web/agent-workbench-terminal-control.d.ts.map +1 -0
  237. package/dist/dashboard/web/agent-workbench-terminal-control.js +292 -0
  238. package/dist/dashboard/web/agent-workbench-terminal-control.js.map +1 -0
  239. package/dist/dashboard/web/agent-workbench-view.d.ts +3 -2
  240. package/dist/dashboard/web/agent-workbench-view.d.ts.map +1 -1
  241. package/dist/dashboard/web/agent-workbench-view.js +69 -50
  242. package/dist/dashboard/web/agent-workbench-view.js.map +1 -1
  243. package/dist/dashboard/web/app.d.ts.map +1 -1
  244. package/dist/dashboard/web/app.js +58 -7
  245. package/dist/dashboard/web/app.js.map +1 -1
  246. package/dist/dashboard/web/bot-defaults-page.d.ts +24 -0
  247. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  248. package/dist/dashboard/web/bot-defaults-page.js +191 -16
  249. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  250. package/dist/dashboard/web/bot-defaults.d.ts +17 -0
  251. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  252. package/dist/dashboard/web/bot-defaults.js +51 -2
  253. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  254. package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
  255. package/dist/dashboard/web/bot-onboarding.js +32 -8
  256. package/dist/dashboard/web/bot-onboarding.js.map +1 -1
  257. package/dist/dashboard/web/confirm-modal.d.ts +35 -0
  258. package/dist/dashboard/web/confirm-modal.d.ts.map +1 -0
  259. package/dist/dashboard/web/confirm-modal.js +111 -0
  260. package/dist/dashboard/web/confirm-modal.js.map +1 -0
  261. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  262. package/dist/dashboard/web/connectors-page.js +2 -1
  263. package/dist/dashboard/web/connectors-page.js.map +1 -1
  264. package/dist/dashboard/web/customization-page.d.ts +3 -0
  265. package/dist/dashboard/web/customization-page.d.ts.map +1 -0
  266. package/dist/dashboard/web/customization-page.js +315 -0
  267. package/dist/dashboard/web/customization-page.js.map +1 -0
  268. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  269. package/dist/dashboard/web/dashboard-routes.js +1 -0
  270. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  271. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  272. package/dist/dashboard/web/groups-page.js +11 -9
  273. package/dist/dashboard/web/groups-page.js.map +1 -1
  274. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  275. package/dist/dashboard/web/i18n.js +226 -42
  276. package/dist/dashboard/web/i18n.js.map +1 -1
  277. package/dist/dashboard/web/monitor-room.d.ts.map +1 -1
  278. package/dist/dashboard/web/monitor-room.js +3 -2
  279. package/dist/dashboard/web/monitor-room.js.map +1 -1
  280. package/dist/dashboard/web/overview-page.d.ts.map +1 -1
  281. package/dist/dashboard/web/overview-page.js +98 -63
  282. package/dist/dashboard/web/overview-page.js.map +1 -1
  283. package/dist/dashboard/web/roles-page.d.ts.map +1 -1
  284. package/dist/dashboard/web/roles-page.js +4 -3
  285. package/dist/dashboard/web/roles-page.js.map +1 -1
  286. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  287. package/dist/dashboard/web/schedules-page.js +165 -18
  288. package/dist/dashboard/web/schedules-page.js.map +1 -1
  289. package/dist/dashboard/web/sessions-kanban.d.ts +2 -0
  290. package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
  291. package/dist/dashboard/web/sessions-kanban.js +142 -24
  292. package/dist/dashboard/web/sessions-kanban.js.map +1 -1
  293. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  294. package/dist/dashboard/web/sessions-page.js +177 -94
  295. package/dist/dashboard/web/sessions-page.js.map +1 -1
  296. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  297. package/dist/dashboard/web/sessions.js +5 -4
  298. package/dist/dashboard/web/sessions.js.map +1 -1
  299. package/dist/dashboard/web/settings-page.d.ts +0 -8
  300. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  301. package/dist/dashboard/web/settings-page.js +185 -65
  302. package/dist/dashboard/web/settings-page.js.map +1 -1
  303. package/dist/dashboard/web/skills/skill-library-tab.d.ts +2 -0
  304. package/dist/dashboard/web/skills/skill-library-tab.d.ts.map +1 -1
  305. package/dist/dashboard/web/skills/skill-library-tab.js +15 -1
  306. package/dist/dashboard/web/skills/skill-library-tab.js.map +1 -1
  307. package/dist/dashboard/web/skills-page.d.ts.map +1 -1
  308. package/dist/dashboard/web/skills-page.js +5 -4
  309. package/dist/dashboard/web/skills-page.js.map +1 -1
  310. package/dist/dashboard/web/store.d.ts +5 -0
  311. package/dist/dashboard/web/store.d.ts.map +1 -1
  312. package/dist/dashboard/web/store.js +4 -0
  313. package/dist/dashboard/web/store.js.map +1 -1
  314. package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
  315. package/dist/dashboard/web/team-federation-page.js +3 -2
  316. package/dist/dashboard/web/team-federation-page.js.map +1 -1
  317. package/dist/dashboard/web/toast.d.ts +15 -0
  318. package/dist/dashboard/web/toast.d.ts.map +1 -0
  319. package/dist/dashboard/web/toast.js +70 -0
  320. package/dist/dashboard/web/toast.js.map +1 -0
  321. package/dist/dashboard/web/v3-components.d.ts.map +1 -1
  322. package/dist/dashboard/web/v3-components.js +2 -1
  323. package/dist/dashboard/web/v3-components.js.map +1 -1
  324. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts +10 -12
  325. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
  326. package/dist/dashboard/web/vc-consumer-profiles-section.js +219 -200
  327. package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
  328. package/dist/dashboard/web/whiteboards-page.d.ts.map +1 -1
  329. package/dist/dashboard/web/whiteboards-page.js +2 -1
  330. package/dist/dashboard/web/whiteboards-page.js.map +1 -1
  331. package/dist/dashboard-web/app.js +1 -1
  332. package/dist/dashboard-web/chunks/agent-workbench-dock-page-LZSUOCEQ.js +1 -0
  333. package/dist/dashboard-web/chunks/agent-workbench-page-YONDRJU7.js +1 -0
  334. package/dist/dashboard-web/chunks/bot-defaults-page-X7LV6373.js +1 -0
  335. package/dist/dashboard-web/chunks/chunk-2PVRDXEL.js +1 -0
  336. package/dist/dashboard-web/chunks/chunk-53JUKBU2.js +10 -0
  337. package/dist/dashboard-web/chunks/{chunk-5CJMHTT4.js → chunk-5QX4OYOR.js} +1 -1
  338. package/dist/dashboard-web/chunks/{chunk-NACP7BMR.js → chunk-5VRVJFQR.js} +1 -1
  339. package/dist/dashboard-web/chunks/{chunk-FDZ7WOBW.js → chunk-6ROOZWYV.js} +1 -1
  340. package/dist/dashboard-web/chunks/{chunk-F6KNPF4R.js → chunk-CK22743G.js} +15 -19
  341. package/dist/dashboard-web/chunks/chunk-CVNIMUPY.js +25 -0
  342. package/dist/dashboard-web/chunks/chunk-GJC2TMWS.js +2 -0
  343. package/dist/dashboard-web/chunks/chunk-OT6L6G7R.js +1 -0
  344. package/dist/dashboard-web/chunks/chunk-QITAMHW6.js +1 -0
  345. package/dist/dashboard-web/chunks/chunk-RHVFZC5Z.js +1 -0
  346. package/dist/dashboard-web/chunks/chunk-SOBMN2VY.js +1 -0
  347. package/dist/dashboard-web/chunks/chunk-SZOB6VK2.js +1 -0
  348. package/dist/dashboard-web/chunks/chunk-XVIXNQGC.js +44 -0
  349. package/dist/dashboard-web/chunks/chunk-YUJF34ME.js +1 -0
  350. package/dist/dashboard-web/chunks/connectors-page-LB2HEJ7F.js +1 -0
  351. package/dist/dashboard-web/chunks/customization-page-4GXBYLG6.js +105 -0
  352. package/dist/dashboard-web/chunks/feedback-page-IZQ7VLDG.js +1 -0
  353. package/dist/dashboard-web/chunks/groups-page-4WCP5OEV.js +8 -0
  354. package/dist/dashboard-web/chunks/{insights-page-HJFDYR5N.js → insights-page-TXQHIPQL.js} +1 -1
  355. package/dist/dashboard-web/chunks/{monitor-room-V7PCP47V.js → monitor-room-VBRVWXCM.js} +8 -8
  356. package/dist/dashboard-web/chunks/monitoring-page-QDDZWERE.js +2 -0
  357. package/dist/dashboard-web/chunks/office-page-PENFNYPG.js +1 -0
  358. package/dist/dashboard-web/chunks/overview-page-BZQDP6MP.js +1 -0
  359. package/dist/dashboard-web/chunks/plugin-page-JX4GSWZS.js +1 -0
  360. package/dist/dashboard-web/chunks/roles-page-VPNINZNK.js +1 -0
  361. package/dist/dashboard-web/chunks/schedules-page-BITO6HEA.js +1 -0
  362. package/dist/dashboard-web/chunks/sessions-page-ZKCOVTD2.js +8 -0
  363. package/dist/dashboard-web/chunks/settings-page-UT6JDTS6.js +2 -0
  364. package/dist/dashboard-web/chunks/skills-page-GULXVAJY.js +4 -0
  365. package/dist/dashboard-web/chunks/team-federation-page-CUUJWGEG.js +1 -0
  366. package/dist/dashboard-web/chunks/v3-page-5WVJ5AUR.js +94 -0
  367. package/dist/dashboard-web/chunks/whiteboards-page-FZ2CME4H.js +1 -0
  368. package/dist/dashboard-web/design-tokens.css +236 -0
  369. package/dist/dashboard-web/index.html +1 -0
  370. package/dist/dashboard-web/style.css +1930 -114
  371. package/dist/dashboard.js +360 -279
  372. package/dist/dashboard.js.map +1 -1
  373. package/dist/desktop/renderer/app.js +6 -0
  374. package/dist/desktop/renderer/app.js.map +1 -1
  375. package/dist/dsh-runner.js +139 -17
  376. package/dist/dsh-runner.js.map +1 -1
  377. package/dist/global-config.d.ts +33 -2
  378. package/dist/global-config.d.ts.map +1 -1
  379. package/dist/global-config.js +62 -0
  380. package/dist/global-config.js.map +1 -1
  381. package/dist/i18n/en.d.ts.map +1 -1
  382. package/dist/i18n/en.js +13 -4
  383. package/dist/i18n/en.js.map +1 -1
  384. package/dist/i18n/index.d.ts +27 -3
  385. package/dist/i18n/index.d.ts.map +1 -1
  386. package/dist/i18n/index.js +33 -4
  387. package/dist/i18n/index.js.map +1 -1
  388. package/dist/i18n/zh.d.ts.map +1 -1
  389. package/dist/i18n/zh.js +13 -4
  390. package/dist/i18n/zh.js.map +1 -1
  391. package/dist/im/lark/card-builder.d.ts +2 -0
  392. package/dist/im/lark/card-builder.d.ts.map +1 -1
  393. package/dist/im/lark/card-builder.js +7 -4
  394. package/dist/im/lark/card-builder.js.map +1 -1
  395. package/dist/im/lark/card-handler.d.ts.map +1 -1
  396. package/dist/im/lark/card-handler.js +135 -20
  397. package/dist/im/lark/card-handler.js.map +1 -1
  398. package/dist/im/lark/event-dispatcher.d.ts +38 -3
  399. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  400. package/dist/im/lark/event-dispatcher.js +163 -13
  401. package/dist/im/lark/event-dispatcher.js.map +1 -1
  402. package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -1
  403. package/dist/im/lark/v3-blocked-card-handler.js +2 -1
  404. package/dist/im/lark/v3-blocked-card-handler.js.map +1 -1
  405. package/dist/im/lark/v3-blocked-card.d.ts +1 -1
  406. package/dist/im/lark/v3-blocked-card.d.ts.map +1 -1
  407. package/dist/im/lark/v3-blocked-card.js +14 -0
  408. package/dist/im/lark/v3-blocked-card.js.map +1 -1
  409. package/dist/index-core-only.js +2 -0
  410. package/dist/index-core-only.js.map +1 -1
  411. package/dist/index-daemon.js +3 -0
  412. package/dist/index-daemon.js.map +1 -1
  413. package/dist/platform/binding.d.ts +37 -0
  414. package/dist/platform/binding.d.ts.map +1 -1
  415. package/dist/platform/binding.js +15 -0
  416. package/dist/platform/binding.js.map +1 -1
  417. package/dist/services/bridge-turn-journal.d.ts +63 -0
  418. package/dist/services/bridge-turn-journal.d.ts.map +1 -0
  419. package/dist/services/bridge-turn-journal.js +149 -0
  420. package/dist/services/bridge-turn-journal.js.map +1 -0
  421. package/dist/services/bridge-turn-queue.d.ts +8 -1
  422. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  423. package/dist/services/bridge-turn-queue.js +2 -1
  424. package/dist/services/bridge-turn-queue.js.map +1 -1
  425. package/dist/services/codex-app-runner-protocol.d.ts +5 -0
  426. package/dist/services/codex-app-runner-protocol.d.ts.map +1 -1
  427. package/dist/services/codex-app-runner-protocol.js +5 -0
  428. package/dist/services/codex-app-runner-protocol.js.map +1 -1
  429. package/dist/services/customization-store.d.ts +93 -0
  430. package/dist/services/customization-store.d.ts.map +1 -0
  431. package/dist/services/customization-store.js +542 -0
  432. package/dist/services/customization-store.js.map +1 -0
  433. package/dist/services/file-bridge-path.d.ts.map +1 -1
  434. package/dist/services/file-bridge-path.js +3 -0
  435. package/dist/services/file-bridge-path.js.map +1 -1
  436. package/dist/services/grok-transcript.d.ts.map +1 -1
  437. package/dist/services/grok-transcript.js +44 -9
  438. package/dist/services/grok-transcript.js.map +1 -1
  439. package/dist/services/local-cli-opener.d.ts.map +1 -1
  440. package/dist/services/local-cli-opener.js +12 -3
  441. package/dist/services/local-cli-opener.js.map +1 -1
  442. package/dist/services/model-catalog.d.ts +54 -0
  443. package/dist/services/model-catalog.d.ts.map +1 -0
  444. package/dist/services/model-catalog.js +147 -0
  445. package/dist/services/model-catalog.js.map +1 -0
  446. package/dist/services/omp-transcript.d.ts +27 -0
  447. package/dist/services/omp-transcript.d.ts.map +1 -0
  448. package/dist/services/omp-transcript.js +214 -0
  449. package/dist/services/omp-transcript.js.map +1 -0
  450. package/dist/services/platform-team-store.d.ts +16 -8
  451. package/dist/services/platform-team-store.d.ts.map +1 -1
  452. package/dist/services/platform-team-store.js +17 -10
  453. package/dist/services/platform-team-store.js.map +1 -1
  454. package/dist/services/project-scanner.d.ts.map +1 -1
  455. package/dist/services/project-scanner.js +13 -8
  456. package/dist/services/project-scanner.js.map +1 -1
  457. package/dist/services/resumable-session-discovery.d.ts.map +1 -1
  458. package/dist/services/resumable-session-discovery.js +117 -35
  459. package/dist/services/resumable-session-discovery.js.map +1 -1
  460. package/dist/services/structured-bridge-clis.d.ts +5 -3
  461. package/dist/services/structured-bridge-clis.d.ts.map +1 -1
  462. package/dist/services/structured-bridge-clis.js +5 -1
  463. package/dist/services/structured-bridge-clis.js.map +1 -1
  464. package/dist/services/vc-meeting-action-gate.d.ts.map +1 -1
  465. package/dist/services/vc-meeting-action-gate.js +15 -4
  466. package/dist/services/vc-meeting-action-gate.js.map +1 -1
  467. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +46 -66
  468. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -1
  469. package/dist/services/vc-meeting-consumer-profile-bootstrap.js +33 -292
  470. package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -1
  471. package/dist/services/vc-meeting-consumer-profile-templates.js +3 -3
  472. package/dist/services/vc-meeting-consumer-profile-templates.js.map +1 -1
  473. package/dist/services/vc-meeting-delivery-store.d.ts +18 -0
  474. package/dist/services/vc-meeting-delivery-store.d.ts.map +1 -1
  475. package/dist/services/vc-meeting-delivery-store.js +55 -0
  476. package/dist/services/vc-meeting-delivery-store.js.map +1 -1
  477. package/dist/services/vc-meeting-send-policy.d.ts +21 -1
  478. package/dist/services/vc-meeting-send-policy.d.ts.map +1 -1
  479. package/dist/services/vc-meeting-send-policy.js +30 -2
  480. package/dist/services/vc-meeting-send-policy.js.map +1 -1
  481. package/dist/services/vc-meeting-shared-consumer-catalog-store.d.ts +78 -0
  482. package/dist/services/vc-meeting-shared-consumer-catalog-store.d.ts.map +1 -0
  483. package/dist/services/vc-meeting-shared-consumer-catalog-store.js +227 -0
  484. package/dist/services/vc-meeting-shared-consumer-catalog-store.js.map +1 -0
  485. package/dist/services/vc-meeting-shared-consumer-catalog.d.ts +53 -0
  486. package/dist/services/vc-meeting-shared-consumer-catalog.d.ts.map +1 -0
  487. package/dist/services/vc-meeting-shared-consumer-catalog.js +161 -0
  488. package/dist/services/vc-meeting-shared-consumer-catalog.js.map +1 -0
  489. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  490. package/dist/setup/bot-config-editor.js +1 -0
  491. package/dist/setup/bot-config-editor.js.map +1 -1
  492. package/dist/setup/open-platform-automation.d.ts +20 -0
  493. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  494. package/dist/setup/open-platform-automation.js +27 -0
  495. package/dist/setup/open-platform-automation.js.map +1 -1
  496. package/dist/skills/customization-bundle.d.ts +83 -0
  497. package/dist/skills/customization-bundle.d.ts.map +1 -0
  498. package/dist/skills/customization-bundle.js +214 -0
  499. package/dist/skills/customization-bundle.js.map +1 -0
  500. package/dist/skills/definitions.d.ts.map +1 -1
  501. package/dist/skills/definitions.js +10 -3
  502. package/dist/skills/definitions.js.map +1 -1
  503. package/dist/skills/effective-builtins.d.ts +38 -0
  504. package/dist/skills/effective-builtins.d.ts.map +1 -0
  505. package/dist/skills/effective-builtins.js +96 -0
  506. package/dist/skills/effective-builtins.js.map +1 -0
  507. package/dist/skills/injection-mode.d.ts +4 -1
  508. package/dist/skills/injection-mode.d.ts.map +1 -1
  509. package/dist/skills/injection-mode.js +11 -3
  510. package/dist/skills/injection-mode.js.map +1 -1
  511. package/dist/skills/installer.d.ts.map +1 -1
  512. package/dist/skills/installer.js +24 -1
  513. package/dist/skills/installer.js.map +1 -1
  514. package/dist/skills/prompt-fragments.d.ts +58 -0
  515. package/dist/skills/prompt-fragments.d.ts.map +1 -0
  516. package/dist/skills/prompt-fragments.js +88 -0
  517. package/dist/skills/prompt-fragments.js.map +1 -0
  518. package/dist/types.d.ts +51 -0
  519. package/dist/types.d.ts.map +1 -1
  520. package/dist/utils/cli-usage-limit.d.ts +50 -0
  521. package/dist/utils/cli-usage-limit.d.ts.map +1 -1
  522. package/dist/utils/cli-usage-limit.js +43 -0
  523. package/dist/utils/cli-usage-limit.js.map +1 -1
  524. package/dist/utils/idle-detector.d.ts +12 -0
  525. package/dist/utils/idle-detector.d.ts.map +1 -1
  526. package/dist/utils/idle-detector.js +88 -2
  527. package/dist/utils/idle-detector.js.map +1 -1
  528. package/dist/utils/stuck-detector.d.ts +5 -0
  529. package/dist/utils/stuck-detector.d.ts.map +1 -1
  530. package/dist/utils/stuck-detector.js +41 -0
  531. package/dist/utils/stuck-detector.js.map +1 -1
  532. package/dist/utils/usage-limit-tracker.d.ts +46 -0
  533. package/dist/utils/usage-limit-tracker.d.ts.map +1 -0
  534. package/dist/utils/usage-limit-tracker.js +91 -0
  535. package/dist/utils/usage-limit-tracker.js.map +1 -0
  536. package/dist/utils/user-token.js +1 -1
  537. package/dist/utils/user-token.js.map +1 -1
  538. package/dist/worker.js +812 -125
  539. package/dist/worker.js.map +1 -1
  540. package/dist/workflows/definition.d.ts +14 -14
  541. package/dist/workflows/events/payloads.d.ts +12 -12
  542. package/dist/workflows/events/schema.d.ts +164 -164
  543. package/dist/workflows/migration/v2-to-v3.js +1 -1
  544. package/dist/workflows/migration/v2-to-v3.js.map +1 -1
  545. package/dist/workflows/v3/architect.d.ts.map +1 -1
  546. package/dist/workflows/v3/architect.js +11 -5
  547. package/dist/workflows/v3/architect.js.map +1 -1
  548. package/dist/workflows/v3/artifact-contract-declarations.d.ts +22 -0
  549. package/dist/workflows/v3/artifact-contract-declarations.d.ts.map +1 -0
  550. package/dist/workflows/v3/artifact-contract-declarations.js +95 -0
  551. package/dist/workflows/v3/artifact-contract-declarations.js.map +1 -0
  552. package/dist/workflows/v3/contract.d.ts +1 -0
  553. package/dist/workflows/v3/contract.d.ts.map +1 -1
  554. package/dist/workflows/v3/contract.js.map +1 -1
  555. package/dist/workflows/v3/daemon-run.d.ts +2 -2
  556. package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
  557. package/dist/workflows/v3/daemon-run.js +4 -0
  558. package/dist/workflows/v3/daemon-run.js.map +1 -1
  559. package/dist/workflows/v3/dag.d.ts +7 -0
  560. package/dist/workflows/v3/dag.d.ts.map +1 -1
  561. package/dist/workflows/v3/dag.js +69 -8
  562. package/dist/workflows/v3/dag.js.map +1 -1
  563. package/dist/workflows/v3/ephemeral-pool.js +1 -1
  564. package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
  565. package/dist/workflows/v3/event-contract.d.ts +3 -1
  566. package/dist/workflows/v3/event-contract.d.ts.map +1 -1
  567. package/dist/workflows/v3/host.d.ts.map +1 -1
  568. package/dist/workflows/v3/host.js +5 -1
  569. package/dist/workflows/v3/host.js.map +1 -1
  570. package/dist/workflows/v3/journal.d.ts +1 -1
  571. package/dist/workflows/v3/journal.d.ts.map +1 -1
  572. package/dist/workflows/v3/journal.js.map +1 -1
  573. package/dist/workflows/v3/library-materialize.d.ts.map +1 -1
  574. package/dist/workflows/v3/library-materialize.js +9 -1
  575. package/dist/workflows/v3/library-materialize.js.map +1 -1
  576. package/dist/workflows/v3/library-schema.d.ts +3 -1
  577. package/dist/workflows/v3/library-schema.d.ts.map +1 -1
  578. package/dist/workflows/v3/library-schema.js +20 -4
  579. package/dist/workflows/v3/library-schema.js.map +1 -1
  580. package/dist/workflows/v3/library-store.d.ts.map +1 -1
  581. package/dist/workflows/v3/library-store.js +15 -3
  582. package/dist/workflows/v3/library-store.js.map +1 -1
  583. package/dist/workflows/v3/run-envelope.d.ts +16 -16
  584. package/dist/workflows/v3/shared-node-runtime.d.ts +2 -1
  585. package/dist/workflows/v3/shared-node-runtime.d.ts.map +1 -1
  586. package/dist/workflows/v3/shared-node-runtime.js +48 -7
  587. package/dist/workflows/v3/shared-node-runtime.js.map +1 -1
  588. package/package.json +2 -1
  589. package/dist/dashboard-web/chunks/agent-workbench-dock-page-IKAC5CFL.js +0 -1
  590. package/dist/dashboard-web/chunks/agent-workbench-page-M53UN5EB.js +0 -1
  591. package/dist/dashboard-web/chunks/bot-defaults-page-YKE5SDZF.js +0 -10
  592. package/dist/dashboard-web/chunks/chunk-22WIADUT.js +0 -2
  593. package/dist/dashboard-web/chunks/chunk-24ONYQMR.js +0 -1
  594. package/dist/dashboard-web/chunks/chunk-2W6SCN3M.js +0 -1
  595. package/dist/dashboard-web/chunks/chunk-4XNJX6B3.js +0 -1
  596. package/dist/dashboard-web/chunks/chunk-5THX4DI2.js +0 -66
  597. package/dist/dashboard-web/chunks/chunk-7SZRL6FY.js +0 -1
  598. package/dist/dashboard-web/chunks/chunk-AGCPF6MT.js +0 -1
  599. package/dist/dashboard-web/chunks/chunk-FXW3V4JR.js +0 -1
  600. package/dist/dashboard-web/chunks/chunk-SYC6D5XU.js +0 -1
  601. package/dist/dashboard-web/chunks/connectors-page-VOISXXII.js +0 -1
  602. package/dist/dashboard-web/chunks/feedback-page-RN6HRZMS.js +0 -1
  603. package/dist/dashboard-web/chunks/groups-page-UQT6DCB7.js +0 -8
  604. package/dist/dashboard-web/chunks/monitoring-page-NKEKVQAP.js +0 -2
  605. package/dist/dashboard-web/chunks/office-page-GVJF73XW.js +0 -1
  606. package/dist/dashboard-web/chunks/overview-page-KHLV6VTI.js +0 -1
  607. package/dist/dashboard-web/chunks/plugin-page-J3OF5IY4.js +0 -1
  608. package/dist/dashboard-web/chunks/roles-page-WQIRSOLZ.js +0 -1
  609. package/dist/dashboard-web/chunks/schedules-page-J2DEY2X6.js +0 -1
  610. package/dist/dashboard-web/chunks/sessions-page-7BQFEA5P.js +0 -8
  611. package/dist/dashboard-web/chunks/settings-page-BJEIOFJH.js +0 -2
  612. package/dist/dashboard-web/chunks/skills-page-HGIFR3IU.js +0 -4
  613. package/dist/dashboard-web/chunks/team-federation-page-MR5ZPL4B.js +0 -1
  614. package/dist/dashboard-web/chunks/v3-page-GBR5JWPE.js +0 -94
  615. package/dist/dashboard-web/chunks/whiteboards-page-QAZM4BN3.js +0 -1
  616. package/dist/services/vc-meeting-consumer-profile-store.d.ts +0 -39
  617. package/dist/services/vc-meeting-consumer-profile-store.d.ts.map +0 -1
  618. package/dist/services/vc-meeting-consumer-profile-store.js +0 -191
  619. package/dist/services/vc-meeting-consumer-profile-store.js.map +0 -1
@@ -19,6 +19,8 @@ import { filterMentionBots, findMentionTrigger, insertBotMention, insertImageMar
19
19
  import { store } from './store.js';
20
20
  import { attentionWaitSince, botAvatarHtml, botDisplayName, chatAvatarHtml, chatDisplayTitle, loadNameMaps, relTime, stripMentionPrefix, t, ui, } from './ui.js';
21
21
  import { SessionsKanbanView, } from './sessions-kanban.js';
22
+ import { toast } from './toast.js';
23
+ import { confirm, promptText } from './confirm-modal.js';
22
24
  const CREATE_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
23
25
  const CREATE_IMAGE_MAX_COUNT = 8;
24
26
  const CREATE_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
@@ -343,7 +345,25 @@ export function CliFilterGroup(props) {
343
345
  if (props.selected.has(cli))
344
346
  props.onToggle(cli, false); }, children: t('sessions.cliClear') })] })] }), _jsx("div", { className: "filter-cli-options", children: visible.length === 0 ? (_jsx("span", { className: "filter-cli-empty", children: t('sessions.cliNoMatch') })) : visible.map(cli => (_jsxs("label", { className: "filter-check", children: [_jsx("input", { type: "checkbox", name: "cli", value: cli, checked: props.selected.has(cli), onChange: event => props.onToggle(cli, event.currentTarget.checked) }), _jsx("span", { children: cli })] }, cli))) })] })] }));
345
347
  }
346
- function SessionsFilters(props) {
348
+ /** 排序下拉:表格列排序之外的统一入口(看板/状态板/话题视图没有表头可点)。
349
+ * 只写既有 sortKey/sortDir,不引入新数据流。 */
350
+ function SortMenu(props) {
351
+ const options = [
352
+ { key: 'lastMessageAt', label: t('sessions.sort.lastMessageAt') },
353
+ { key: 'spawnedAt', label: t('sessions.sort.spawnedAt') },
354
+ { key: 'title', label: t('sessions.sort.title') },
355
+ { key: 'status', label: t('sessions.sort.status') },
356
+ ];
357
+ const current = options.find(option => option.key === props.sortKey) ?? options[0];
358
+ return (_jsxs("details", { className: "sessions-sort-menu sect-sort-menu", children: [_jsx("summary", { "aria-label": t('sessions.sort'), children: _jsxs("span", { className: "sect-sort-value", children: [t('sessions.sort'), ": ", current.label, " ", props.sortDir === 'asc' ? '↑' : '↓'] }) }), _jsx("div", { className: "sect-sort-pop", role: "menu", children: options.map(option => (_jsxs("button", { type: "button", role: "menuitem", "aria-current": option.key === props.sortKey ? 'true' : undefined, onClick: () => props.onSort(option.key), children: [option.label, option.key === props.sortKey ? (props.sortDir === 'asc' ? ' ↑' : ' ↓') : null] }, option.key))) })] }));
359
+ }
360
+ /** 高级筛选抽屉:来源 / CLI / 群 / 话题类型等低频筛选收进右侧抽屉,
361
+ * 筛选 state 仍是同一个 FiltersState,只是换了渲染位置。抽屉内一律用原生
362
+ * <select> + 内联复选列表(不用浮层),避免被抽屉滚动容器裁剪。 */
363
+ function SessionsFilterDrawer(props) {
364
+ const dialogRef = useRef(null);
365
+ useDialogVisibility(dialogRef, props.open);
366
+ const [cliQuery, setCliQuery] = useState('');
347
367
  const statusOptions = [
348
368
  { value: '', label: t('sessions.anyStatus') },
349
369
  ...SESSION_STATUS_OPTIONS.map(status => ({ value: status, label: sessionStatusText(status) })),
@@ -353,39 +373,77 @@ function SessionsFilters(props) {
353
373
  { value: 'yes', label: t('sessions.adoptYes') },
354
374
  { value: 'no', label: t('sessions.adoptNo') },
355
375
  ];
356
- const statusLabel = statusOptions.find(option => option.value === props.filters.status)?.label ?? t('sessions.anyStatus');
357
- const adoptLabel = adoptOptions.find(option => option.value === props.filters.adopt)?.label ?? t('sessions.adoptAny');
358
376
  const chatOptions = [
359
377
  { value: '', label: t('sessions.chatAny') },
360
378
  ...props.chatOptions,
361
379
  ];
362
- const chatLabel = chatOptions.find(option => option.value === props.filters.chat)?.label ?? t('sessions.chatAny');
363
- return (_jsxs("form", { id: "filters", className: "filters dashboard-toolbar sessions-filters", onSubmit: event => event.preventDefault(), children: [_jsx("input", { type: "search", name: "q", placeholder: t('sessions.search'), value: props.filters.q, onChange: event => {
380
+ const cliQueryNorm = cliQuery.trim().toLowerCase();
381
+ const visibleClis = cliQueryNorm
382
+ ? CLI_FILTER_OPTIONS.filter(cli => cli.toLowerCase().includes(cliQueryNorm))
383
+ : CLI_FILTER_OPTIONS;
384
+ const reset = () => {
385
+ writeStoredSessionsShowUnknownChats(windowStorage(), false);
386
+ props.setFilters(() => ({
387
+ q: props.filters.q,
388
+ status: '',
389
+ adopt: '',
390
+ chat: '',
391
+ multiBotTopics: false,
392
+ botTriggeredTopics: false,
393
+ showUnknownChats: false,
394
+ active: true,
395
+ cli: new Set(CLI_FILTER_OPTIONS),
396
+ }));
397
+ };
398
+ return (_jsxs("dialog", { ref: dialogRef, className: "sessions-filter-drawer", onClose: props.onClose, onClick: event => { if (event.target === event.currentTarget)
399
+ props.onClose(); }, children: [_jsxs("header", { children: [_jsx("h3", { children: t('sessions.filters.title') }), _jsx(IconActionButton, { className: "card-act drawer-close-btn", icon: ICON.close, label: t('sessions.dismiss'), onClick: props.onClose })] }), _jsxs("div", { className: "sessions-filter-drawer-body", children: [_jsxs("div", { className: "sessions-filter-field", children: [_jsx("span", { className: "sessions-filter-label", children: t('sessions.status') }), _jsx("select", { value: props.filters.status, onChange: event => props.setFilters(prev => ({ ...prev, status: event.currentTarget.value })), children: statusOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value || 'any')) })] }), _jsxs("div", { className: "sessions-filter-field", children: [_jsx("span", { className: "sessions-filter-label", children: t('sessions.adopt') }), _jsx("select", { value: props.filters.adopt, onChange: event => props.setFilters(prev => ({ ...prev, adopt: event.currentTarget.value })), children: adoptOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value || 'any')) })] }), _jsxs("div", { className: "sessions-filter-field", children: [_jsx("span", { className: "sessions-filter-label", children: t('sessions.location') }), _jsx("select", { value: props.filters.chat, onChange: event => props.setFilters(prev => ({ ...prev, chat: event.currentTarget.value })), children: chatOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value || 'any')) })] }), _jsxs("div", { className: "sessions-filter-field", children: [_jsx("span", { className: "sessions-filter-label", children: t('sessions.cli') }), _jsxs("div", { className: "sessions-filter-cli", children: [_jsx("input", { type: "search", className: "sessions-filter-cli-search", placeholder: t('sessions.cliSearch'), value: cliQuery, onChange: event => setCliQuery(event.currentTarget.value) }), _jsxs("div", { className: "sessions-filter-cli-bulk", children: [_jsx("button", { type: "button", onClick: () => props.setFilters(prev => ({ ...prev, cli: new Set(CLI_FILTER_OPTIONS) })), children: t('sessions.cliSelectAll') }), _jsx("button", { type: "button", onClick: () => props.setFilters(prev => ({ ...prev, cli: new Set() })), children: t('sessions.cliClear') })] }), _jsx("div", { className: "sessions-filter-cli-list", children: visibleClis.length === 0 ? (_jsx("span", { className: "filter-cli-empty", children: t('sessions.cliNoMatch') })) : visibleClis.map(cli => (_jsxs("label", { className: "filter-check", children: [_jsx("input", { type: "checkbox", name: "cli", value: cli, checked: props.filters.cli.has(cli), onChange: event => {
400
+ const checked = event.currentTarget.checked;
401
+ props.setFilters(prev => {
402
+ const next = new Set(prev.cli);
403
+ if (checked)
404
+ next.add(cli);
405
+ else
406
+ next.delete(cli);
407
+ return { ...prev, cli: next };
408
+ });
409
+ } }), _jsx("span", { children: cli })] }, cli))) })] })] }), _jsxs("div", { className: "sessions-filter-toggles", children: [_jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "multiBotTopics", checked: props.filters.multiBotTopics, onChange: event => {
410
+ const multiBotTopics = event.currentTarget.checked;
411
+ props.setFilters(prev => ({ ...prev, multiBotTopics }));
412
+ } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.multiBotTopics') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "botTriggeredTopics", checked: props.filters.botTriggeredTopics, onChange: event => {
413
+ const botTriggeredTopics = event.currentTarget.checked;
414
+ props.setFilters(prev => ({ ...prev, botTriggeredTopics }));
415
+ } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.botTriggeredTopics') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "showUnknownChats", checked: props.filters.showUnknownChats, onChange: event => {
416
+ const checked = event.currentTarget.checked;
417
+ writeStoredSessionsShowUnknownChats(windowStorage(), checked);
418
+ props.setFilters(prev => ({ ...prev, showUnknownChats: checked }));
419
+ } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.showUnknownChats') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "active", checked: props.filters.active, onChange: event => {
420
+ const active = event.currentTarget.checked;
421
+ props.setFilters(prev => ({ ...prev, active }));
422
+ } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.activeOnly') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] })] })] }), _jsxs("footer", { children: [_jsx("button", { type: "button", className: "sessions-filter-clear", onClick: reset, children: t('sessions.filters.clear') }), _jsx("button", { type: "button", className: "primary sessions-filter-done", onClick: props.onClose, children: t('sessions.filters.done') })] })] }));
423
+ }
424
+ function SessionsFilters(props) {
425
+ const [drawerOpen, setDrawerOpen] = useState(false);
426
+ // 快捷分段视图映射到既有 status 筛选:待处理=stalled(长时间无进展,最需要人看),
427
+ // 进行中=working,全部=任意。抽屉里的完整状态下拉可覆盖为其它状态,此时分段无激活项。
428
+ const quickViews = [
429
+ { value: 'stalled', label: t('sessions.view.need') },
430
+ { value: 'working', label: t('sessions.view.work') },
431
+ { value: '', label: t('sessions.view.all') },
432
+ ];
433
+ const activeFilterCount = [
434
+ props.filters.status !== '',
435
+ props.filters.adopt !== '',
436
+ props.filters.chat !== '',
437
+ props.filters.cli.size < CLI_FILTER_OPTIONS.length,
438
+ props.filters.multiBotTopics,
439
+ props.filters.botTriggeredTopics,
440
+ props.filters.showUnknownChats,
441
+ !props.filters.active,
442
+ ].filter(Boolean).length;
443
+ return (_jsxs("form", { id: "filters", className: "filters dashboard-toolbar sessions-filters sessions-toolbar", onSubmit: event => event.preventDefault(), children: [_jsx("input", { type: "search", name: "q", placeholder: t('sessions.search'), value: props.filters.q, onChange: event => {
364
444
  const q = event.currentTarget.value;
365
445
  props.setFilters(prev => ({ ...prev, q }));
366
- } }), _jsx(DropdownMenu, { label: statusLabel, value: props.filters.status, options: statusOptions, onChange: value => props.setFilters(prev => ({ ...prev, status: value })) }), _jsx(DropdownMenu, { label: adoptLabel, value: props.filters.adopt, options: adoptOptions, onChange: value => props.setFilters(prev => ({ ...prev, adopt: value })) }), _jsx(DropdownMenu, { ariaLabel: t('sessions.location'), className: "filter-chat-menu", label: chatLabel, value: props.filters.chat, options: chatOptions, searchable: true, searchPlaceholder: t('sessions.chatSearch'), searchEmptyLabel: t('sessions.chatNoMatch'), onChange: value => props.setFilters(prev => ({ ...prev, chat: value })) }), _jsx(CliFilterGroup, { selected: props.filters.cli, onToggle: (cli, checked) => {
367
- props.setFilters(prev => {
368
- const next = new Set(prev.cli);
369
- if (checked)
370
- next.add(cli);
371
- else
372
- next.delete(cli);
373
- return { ...prev, cli: next };
374
- });
375
- } }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "multiBotTopics", checked: props.filters.multiBotTopics, onChange: event => {
376
- const multiBotTopics = event.currentTarget.checked;
377
- props.setFilters(prev => ({ ...prev, multiBotTopics }));
378
- } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.multiBotTopics') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "botTriggeredTopics", checked: props.filters.botTriggeredTopics, onChange: event => {
379
- const botTriggeredTopics = event.currentTarget.checked;
380
- props.setFilters(prev => ({ ...prev, botTriggeredTopics }));
381
- } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.botTriggeredTopics') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "showUnknownChats", checked: props.filters.showUnknownChats, onChange: event => {
382
- const checked = event.currentTarget.checked;
383
- writeStoredSessionsShowUnknownChats(windowStorage(), checked);
384
- props.setFilters(prev => ({ ...prev, showUnknownChats: checked }));
385
- } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.showUnknownChats') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "active", checked: props.filters.active, onChange: event => {
386
- const active = event.currentTarget.checked;
387
- props.setFilters(prev => ({ ...prev, active }));
388
- } }), _jsx("span", { className: "filter-toggle-label", children: t('sessions.activeOnly') }), _jsx("span", { className: "filter-toggle-switch", "aria-hidden": "true" })] }), _jsx(IdleCleanupBar, { ...props.idleCleanup })] }));
446
+ } }), _jsx("div", { className: "segmented sessions-quick-view", role: "group", "aria-label": t('sessions.status'), children: quickViews.map(view => (_jsx("button", { type: "button", "data-quick": view.value, className: props.filters.status === view.value ? 'active' : undefined, "aria-pressed": props.filters.status === view.value, onClick: () => props.setFilters(prev => ({ ...prev, status: view.value })), children: view.label }, view.label))) }), _jsxs("button", { type: "button", className: `sessions-filter-btn${activeFilterCount > 0 ? ' has-active' : ''}`, "aria-haspopup": "dialog", "aria-expanded": drawerOpen, onClick: () => setDrawerOpen(true), children: [t('sessions.filters.title'), activeFilterCount > 0 ? _jsx("span", { className: "sessions-filter-count", children: activeFilterCount }) : null] }), _jsx(SortMenu, { sortKey: props.sortKey, sortDir: props.sortDir, onSort: props.onSort }), _jsx(IdleCleanupBar, { ...props.idleCleanup }), _jsx(SessionsFilterDrawer, { open: drawerOpen, chatOptions: props.chatOptions, filters: props.filters, setFilters: props.setFilters, onClose: () => setDrawerOpen(false) })] }));
389
447
  }
390
448
  function BulkBar(props) {
391
449
  const busy = !!props.closeProgress || !!props.lockProgress;
@@ -692,13 +750,15 @@ function BoardCard(props) {
692
750
  const signal = boardSignalLabel(row);
693
751
  const repo = repoBasename(row.workingDir);
694
752
  const exchange = sessionExchangePreview(row);
753
+ // 状态色条语义与看板卡片一致:需要你 / 进行中 / 待办 / 空闲;已关闭单独一色。
754
+ const signalKind = deriveSessionBoardColumn(row) ?? (row.status === 'closed' ? 'closed' : 'idle');
695
755
  const onCardClick = (event) => {
696
756
  const target = event.target;
697
757
  if (target.closest('a, button, input, label'))
698
758
  return;
699
759
  props.onToggleSelect(row);
700
760
  };
701
- return (_jsxs("article", { className: `session-card${props.selected ? ' selected' : ''}${row.locked ? ' locked' : ''}`, "data-id": row.sessionId, "aria-pressed": props.selected, onClick: onCardClick, children: [_jsxs("div", { className: "session-card-top", children: [_jsx("span", { dangerouslySetInnerHTML: rawHtml(botAvatarHtml({ name: botName, larkAppId: row.larkAppId, size: 'sm' })) }), _jsxs("div", { className: "session-card-title", children: [_jsx("strong", { title: String(row.title ?? title), children: String(title).slice(0, 72) }), _jsxs("span", { children: [botName, " \u00B7 ", chatTitle ?? sessionCliDisplayName(row)] })] }), _jsxs("span", { className: "session-card-status-group", children: [_jsx(StatusBadge, { status: row.status }), _jsx(TodoBadge, { row: row }), _jsx(LockChip, { row: row })] })] }), repo !== '-' || row.adopt || signal ? (_jsxs("div", { className: "session-card-meta", children: [repo !== '-' ? _jsx("span", { title: row.workingDir ?? '', children: repo }) : null, row.adopt ? _jsx("span", { className: "badge", children: "adopt" }) : null, signal ? _jsx("span", { className: "session-signal", title: signal, children: signal }) : null] })) : null, _jsx(SessionExchangePreview, { exchange: exchange }), _jsx("div", { className: "session-card-time", children: _jsx("span", { children: row.agentAttention?.at
761
+ return (_jsxs("article", { className: `session-card${props.selected ? ' selected' : ''}${row.locked ? ' locked' : ''}`, "data-id": row.sessionId, "data-signal": signalKind, "aria-pressed": props.selected, onClick: onCardClick, children: [_jsxs("div", { className: "session-card-top", children: [_jsx("span", { dangerouslySetInnerHTML: rawHtml(botAvatarHtml({ name: botName, larkAppId: row.larkAppId, size: 'sm' })) }), _jsxs("div", { className: "session-card-title", children: [_jsx("strong", { title: String(row.title ?? title), children: String(title).slice(0, 72) }), _jsxs("span", { children: [botName, " \u00B7 ", chatTitle ?? sessionCliDisplayName(row)] })] }), _jsxs("span", { className: "session-card-status-group", children: [_jsx(StatusBadge, { status: row.status }), _jsx(TodoBadge, { row: row }), _jsx(LockChip, { row: row })] })] }), repo !== '-' || row.adopt || signal ? (_jsxs("div", { className: "session-card-meta", children: [repo !== '-' ? _jsx("span", { title: row.workingDir ?? '', children: repo }) : null, row.adopt ? _jsx("span", { className: "badge", children: "adopt" }) : null, signal ? _jsx("span", { className: "session-signal", title: signal, children: signal }) : null] })) : null, _jsx(SessionExchangePreview, { exchange: exchange }), _jsx("div", { className: "session-card-time", children: _jsx("span", { children: row.agentAttention?.at
702
762
  ? `${t('sessions.board.waiting')} ${relTime(attentionWaitSince(row))}`
703
763
  : `${t('sessions.last')}: ${relTime(row.lastMessageAt)}` }) }), _jsxs("div", { className: "session-card-actions", children: [_jsx(ChatScopeLink, { row: row }), !row.feishuChatLink || row.scope !== 'chat' ? (_jsx(LocateIconButton, { row: row, onLocate: props.onLocate })) : null, _jsx(IconActionButton, { action: "details", icon: ICON.details, label: t('sessions.details'), onClick: () => props.onOpen(row) }), canRestartSession(row) ? (_jsx(IconActionButton, { action: "restart", icon: ICON.restart, label: t('sessions.restart'), onClick: button => props.onRestart(row, button) })) : null, _jsx(TerminalControls, { row: row, url: term }), row.status !== 'closed' ? (_jsxs(_Fragment, { children: [_jsx(IconActionButton, { action: "lock", icon: row.locked ? ICON.unlock : ICON.lock, label: lockActionLabel(row), kind: row.locked ? 'locked' : '', onClick: button => props.onLock(row, !row.locked, button) }), _jsx(IconActionButton, { action: "close", icon: ICON.close, label: t('sessions.close'), kind: "danger", onClick: button => props.onClose(row, button) })] })) : null] })] }));
704
764
  }
@@ -920,12 +980,14 @@ function Drawer(props) {
920
980
  useDialogVisibility(dialogRef, !!props.row);
921
981
  const row = props.row;
922
982
  const terminal = row ? terminalHref(row) : null;
983
+ const closed = !!row && row.status === 'closed';
984
+ const canTakeover = !!row && !closed && !!terminal;
923
985
  return (_jsx("dialog", { id: "drawer", ref: dialogRef, onClose: props.onClose, onClick: event => { if (event.target === event.currentTarget)
924
- props.onClose(); }, children: row ? (_jsxs("article", { children: [_jsxs("header", { children: [_jsxs("div", { className: "drawer-title-row", children: [_jsx("h3", { children: stripMentionPrefix(row.title) || row.sessionId }), _jsx(IconActionButton, { id: "drawer-close", className: "card-act drawer-close-btn", icon: ICON.close, label: t('sessions.dismiss'), onClick: props.onClose })] }), _jsxs("span", { className: "drawer-status-line", children: [_jsx(StatusBadge, { status: row.status }), _jsx(TodoBadge, { row: row }), _jsx(LockChip, { row: row })] }), _jsxs("p", { children: [_jsx("code", { children: row.sessionId }), " ", _jsx(CopyButton, { value: row.sessionId })] })] }), _jsxs("p", { children: [_jsxs("b", { children: [t('sessions.bot'), ":"] }), " ", botDisplayName(row), " \u00B7 ", _jsxs("b", { children: [t('sessions.cli'), ":"] }), " ", sessionCliDisplayName(row)] }), _jsxs("p", { children: [_jsxs("b", { children: [t('sessions.location'), ":"] }), " ", sessionLocationText(row)] }), _jsxs("p", { children: [_jsx("b", { children: "chatId:" }), " ", _jsx("code", { children: row.chatId ?? '' }), " ", _jsx(CopyButton, { value: row.chatId ?? '' })] }), _jsxs("p", { children: [_jsx("b", { children: "rootMessageId:" }), " ", _jsx("code", { children: row.rootMessageId ?? '' }), " ", _jsx(CopyButton, { value: row.rootMessageId ?? '' })] }), row.threadId ? _jsxs("p", { children: [_jsx("b", { children: "threadId:" }), " ", _jsx("code", { children: row.threadId })] }) : null, _jsxs("p", { children: [_jsxs("b", { children: [t('sessions.workingDir'), ":"] }), " ", row.workingDir ?? '-'] }), _jsxs("div", { className: "actions", children: [_jsx(ChatScopeLink, { row: row }), !row.feishuChatLink || row.scope !== 'chat' ? _jsx(LocateButton, { row: row, locateSession: props.locateSession }) : null, _jsx("button", { id: "history-drawer-btn", type: "button", onClick: () => props.openHistory(row), children: t('sessions.history.title') }), _jsx(TerminalControls, { row: row, url: terminal }), shouldOpenWritableTerminal() && row.status !== 'closed' ? (_jsx("button", { id: "copy-cmd-btn", type: "button", "data-tip": t('sessions.copyCommandHint'), onClick: event => void copySpawnCommand(row, event.currentTarget), children: t('sessions.copyCommand') })) : null, canRestartSession(row) ? (_jsx("button", { id: "restart-btn", type: "button", onClick: async (event) => { if (await props.restartSession(row, event.currentTarget))
925
- props.onClose(); }, children: t('sessions.restart') })) : null, _jsx("button", { id: "lock-btn", type: "button", onClick: event => void props.setSessionLocked(row, !row.locked, event.currentTarget), children: lockActionLabel(row) }), row.queued && row.status !== 'closed' ? (_jsx("button", { id: "start-btn", type: "button", className: "primary", onClick: async (event) => { if (await props.startSession(row, event.currentTarget))
926
- props.onClose(); }, children: t('sessions.create.start') })) : null, row.status === 'closed' ? (_jsx("button", { id: "resume-btn", type: "button", className: "primary", onClick: async (event) => { if (await props.resumeSession(row, event.currentTarget))
927
- props.onClose(); }, children: t('sessions.resume') })) : null, row.status !== 'closed' ? (_jsx("button", { id: "close-btn", type: "button", className: "contrast", onClick: async (event) => { if (await props.closeSession(row, event.currentTarget))
928
- props.onClose(); }, children: t('sessions.close') })) : null, _jsx(InsightPanel, { row: row })] })] })) : null }));
986
+ props.onClose(); }, children: row ? (_jsxs("article", { children: [_jsxs("header", { children: [_jsxs("div", { className: "drawer-title-row", children: [_jsx("h3", { children: stripMentionPrefix(row.title) || row.sessionId }), _jsx(IconActionButton, { id: "drawer-close", className: "card-act drawer-close-btn", icon: ICON.close, label: t('sessions.dismiss'), onClick: props.onClose })] }), _jsxs("span", { className: "drawer-status-line", children: [_jsx(StatusBadge, { status: row.status }), _jsx(TodoBadge, { row: row }), _jsx(LockChip, { row: row })] }), _jsxs("p", { children: [_jsx("code", { children: row.sessionId }), " ", _jsx(CopyButton, { value: row.sessionId })] })] }), _jsxs("div", { className: "drawer-body", children: [_jsxs("p", { children: [_jsxs("b", { children: [t('sessions.bot'), ":"] }), " ", botDisplayName(row), " \u00B7 ", _jsxs("b", { children: [t('sessions.cli'), ":"] }), " ", sessionCliDisplayName(row)] }), _jsxs("p", { children: [_jsxs("b", { children: [t('sessions.location'), ":"] }), " ", sessionLocationText(row)] }), _jsxs("p", { children: [_jsx("b", { children: "chatId:" }), " ", _jsx("code", { children: row.chatId ?? '' }), " ", _jsx(CopyButton, { value: row.chatId ?? '' })] }), _jsxs("p", { children: [_jsx("b", { children: "rootMessageId:" }), " ", _jsx("code", { children: row.rootMessageId ?? '' }), " ", _jsx(CopyButton, { value: row.rootMessageId ?? '' })] }), row.threadId ? _jsxs("p", { children: [_jsx("b", { children: "threadId:" }), " ", _jsx("code", { children: row.threadId })] }) : null, _jsxs("p", { children: [_jsxs("b", { children: [t('sessions.workingDir'), ":"] }), " ", row.workingDir ?? '-'] }), _jsx(InsightPanel, { row: row })] }), _jsxs("footer", { className: "drawer-foot", children: [_jsx("div", { className: "drawer-foot-actions", children: closed ? (_jsx("button", { id: "resume-btn", type: "button", className: "primary drawer-btn-primary", onClick: async (event) => { if (await props.resumeSession(row, event.currentTarget))
987
+ props.onClose(); }, children: t('sessions.resume') })) : (_jsxs(_Fragment, { children: [_jsx("button", { id: "takeover-btn", type: "button", className: "primary drawer-btn-primary", disabled: !canTakeover, title: canTakeover ? undefined : t('sessions.openReadonlyTerminal'), onClick: event => props.onTakeover(row, event.currentTarget), children: t('sessions.takeoverTerminal') }), canRestartSession(row) ? (_jsx("button", { id: "restart-btn", type: "button", className: "drawer-btn-secondary", onClick: async (event) => { if (await props.restartSession(row, event.currentTarget))
988
+ props.onClose(); }, children: t('sessions.restart') })) : null, _jsx("button", { id: "close-btn", type: "button", className: "drawer-btn-danger", onClick: async (event) => { if (await props.closeSession(row, event.currentTarget))
989
+ props.onClose(); }, children: t('sessions.close') })] })) }), _jsxs("details", { className: "drawer-more", children: [_jsx("summary", { "aria-label": t('sessions.more'), children: t('sessions.more') }), _jsxs("div", { className: "drawer-more-pop", role: "menu", children: [_jsx("button", { id: "history-drawer-btn", type: "button", role: "menuitem", onClick: () => props.openHistory(row), children: t('sessions.history.title') }), shouldOpenWritableTerminal() && !closed ? (_jsx("button", { id: "copy-cmd-btn", type: "button", role: "menuitem", "data-tip": t('sessions.copyCommandHint'), onClick: event => void copySpawnCommand(row, event.currentTarget), children: t('sessions.copyCommand') })) : null, _jsx("button", { id: "lock-btn", type: "button", role: "menuitem", onClick: event => void props.setSessionLocked(row, !row.locked, event.currentTarget), children: lockActionLabel(row) }), !row.feishuChatLink || row.scope !== 'chat' ? (_jsx("span", { className: "drawer-more-item", children: _jsx(LocateButton, { row: row, locateSession: props.locateSession }) })) : (_jsx("a", { className: "drawer-more-item drawer-more-link", href: row.feishuChatLink, target: "_blank", rel: "noopener", role: "menuitem", children: t('sessions.openChat') })), row.queued && !closed ? (_jsx("button", { id: "start-btn", type: "button", role: "menuitem", onClick: async (event) => { if (await props.startSession(row, event.currentTarget))
990
+ props.onClose(); }, children: t('sessions.create.start') })) : null] })] })] })] })) : null }));
929
991
  }
930
992
  function CreateSessionDialog(props) {
931
993
  const state = props.state;
@@ -1059,7 +1121,7 @@ function CreateSessionDialog(props) {
1059
1121
  const response = await fetch(`/api/feed-groups/auth-url${query}`);
1060
1122
  const body = await response.json().catch(() => ({}));
1061
1123
  if (!response.ok || !body.authUrl) {
1062
- alert(body.error ?? `HTTP ${response.status}`);
1124
+ toast(body.error ?? `HTTP ${response.status}`, { kind: 'error' });
1063
1125
  return;
1064
1126
  }
1065
1127
  setFeedGroupAuthUrl(String(body.authUrl));
@@ -1087,7 +1149,7 @@ function CreateSessionDialog(props) {
1087
1149
  setFeedGroupCallbackUrl('');
1088
1150
  }
1089
1151
  catch (error) {
1090
- alert(error instanceof Error ? error.message : String(error));
1152
+ toast(error instanceof Error ? error.message : String(error), { kind: 'error' });
1091
1153
  }
1092
1154
  finally {
1093
1155
  setFeedGroupAuthSubmitting(false);
@@ -1158,21 +1220,21 @@ function CreateSessionDialog(props) {
1158
1220
  const pasteEnd = event.currentTarget.selectionEnd ?? pasteStart;
1159
1221
  const supported = pasted.filter(file => CREATE_IMAGE_TYPES.has(file.type.toLowerCase()));
1160
1222
  if (supported.length !== pasted.length) {
1161
- alert(t('sessions.create.imageUnsupported'));
1223
+ toast(t('sessions.create.imageUnsupported'), { kind: 'warning' });
1162
1224
  return;
1163
1225
  }
1164
1226
  if (images.length + supported.length > CREATE_IMAGE_MAX_COUNT) {
1165
- alert(t('sessions.create.imageCountLimit', { n: String(CREATE_IMAGE_MAX_COUNT) }));
1227
+ toast(t('sessions.create.imageCountLimit', { n: String(CREATE_IMAGE_MAX_COUNT) }), { kind: 'warning' });
1166
1228
  return;
1167
1229
  }
1168
1230
  if (supported.some(file => file.size > CREATE_IMAGE_MAX_BYTES)) {
1169
- alert(t('sessions.create.imageSizeLimit'));
1231
+ toast(t('sessions.create.imageSizeLimit'), { kind: 'warning' });
1170
1232
  return;
1171
1233
  }
1172
1234
  const nextTotal = images.reduce((sum, image) => sum + image.size, 0)
1173
1235
  + supported.reduce((sum, file) => sum + file.size, 0);
1174
1236
  if (nextTotal > CREATE_IMAGE_MAX_TOTAL_BYTES) {
1175
- alert(t('sessions.create.imageTotalLimit'));
1237
+ toast(t('sessions.create.imageTotalLimit'), { kind: 'warning' });
1176
1238
  return;
1177
1239
  }
1178
1240
  try {
@@ -1208,23 +1270,23 @@ function CreateSessionDialog(props) {
1208
1270
  });
1209
1271
  }
1210
1272
  catch {
1211
- alert(t('sessions.create.imageReadFailed'));
1273
+ toast(t('sessions.create.imageReadFailed'), { kind: 'error' });
1212
1274
  }
1213
1275
  };
1214
1276
  const submit = async (event) => {
1215
1277
  event.preventDefault();
1216
1278
  const text = content.trim();
1217
1279
  if (!text) {
1218
- alert(t('sessions.create.errContent'));
1280
+ toast(t('sessions.create.errContent'), { kind: 'warning' });
1219
1281
  return;
1220
1282
  }
1221
1283
  if (checkedIds.length === 0) {
1222
- alert(t('sessions.create.errNoBot'));
1284
+ toast(t('sessions.create.errNoBot'), { kind: 'warning' });
1223
1285
  return;
1224
1286
  }
1225
1287
  const leadLarkAppId = lead || checkedIds[0] || '';
1226
1288
  if (mode === 'lead' && (!leadLarkAppId || !checkedIds.includes(leadLarkAppId))) {
1227
- alert(t('sessions.create.errLead'));
1289
+ toast(t('sessions.create.errLead'), { kind: 'warning' });
1228
1290
  return;
1229
1291
  }
1230
1292
  setSubmitting(true);
@@ -1266,10 +1328,10 @@ function CreateSessionDialog(props) {
1266
1328
  }
1267
1329
  }
1268
1330
  else if (r.status !== 401)
1269
- alert(`${t('sessions.create.failed')}: ${body?.error ?? r.status}`);
1331
+ toast(`${t('sessions.create.failed')}: ${body?.error ?? r.status}`, { kind: 'error' });
1270
1332
  }
1271
1333
  catch (e) {
1272
- alert(`${t('sessions.create.failed')}: ${e}`);
1334
+ toast(`${t('sessions.create.failed')}: ${e}`, { kind: 'error' });
1273
1335
  }
1274
1336
  finally {
1275
1337
  setSubmitting(false);
@@ -1312,9 +1374,15 @@ function CreateSessionDialog(props) {
1312
1374
  writeStoredCreateKeepOpen(windowStorage(), next);
1313
1375
  } }), _jsx("span", { children: t('sessions.create.keepOpen') })] }), _jsx("button", { type: "button", id: "cs-cancel", onClick: props.onClose, children: t('sessions.create.cancel') }), _jsx("button", { type: "submit", className: "cs-submit", disabled: submitting || bots.length === 0, children: submitting ? t('sessions.create.submitting') : t('sessions.create.submit') })] })] })] }));
1314
1376
  }
1377
+ /** 首屏骨架屏:首个 /api/sessions 快照到达前不闪「空」。布局模仿状态板四列,
1378
+ * 纯展示,无交互。 */
1379
+ function SessionsSkeleton() {
1380
+ return (_jsx("div", { className: "sessions-skeleton", "aria-busy": "true", "aria-label": t('sessions.loadingSessions'), children: [0, 1, 2, 3].map(column => (_jsxs("div", { className: "sessions-skeleton-col", children: [_jsx("div", { className: "skel skel-head" }), _jsx("div", { className: "skel skel-card" }), _jsx("div", { className: "skel skel-card skel-card-short" }), _jsx("div", { className: "skel skel-card" })] }, column))) }));
1381
+ }
1315
1382
  function SessionsPage() {
1316
1383
  useT();
1317
1384
  const storeRows = useStoreSelector(snapshot => [...snapshot.sessions.values()]);
1385
+ const bootstrapped = useStoreSelector(snapshot => snapshot.bootstrapped);
1318
1386
  const [revision, setRevision] = useState(0);
1319
1387
  const refresh = useCallback(() => setRevision(v => v + 1), []);
1320
1388
  const [filters, setFilters] = useState({
@@ -1573,7 +1641,7 @@ function SessionsPage() {
1573
1641
  return { ...prev, data: { ...prev.data, board } };
1574
1642
  });
1575
1643
  if (r.status !== 401)
1576
- alert(`${t('sessions.kanban.moveFail')}: ${body?.error ?? r.status}`);
1644
+ toast(`${t('sessions.kanban.moveFail')}: ${body?.error ?? r.status}`, { kind: 'error' });
1577
1645
  }
1578
1646
  }
1579
1647
  catch (e) {
@@ -1587,7 +1655,7 @@ function SessionsPage() {
1587
1655
  delete board[sessionId];
1588
1656
  return { ...prev, data: { ...prev.data, board } };
1589
1657
  });
1590
- alert(`${t('sessions.kanban.moveFail')}: ${e}`);
1658
+ toast(`${t('sessions.kanban.moveFail')}: ${e}`, { kind: 'error' });
1591
1659
  }
1592
1660
  }, []);
1593
1661
  const ensureTeamBoard = useCallback(async (team) => {
@@ -1652,14 +1720,14 @@ function SessionsPage() {
1652
1720
  row.kanbanPosition = prev.position;
1653
1721
  refresh();
1654
1722
  if (r.status !== 401)
1655
- alert(`${t('sessions.kanban.moveFail')}: ${body?.error ?? r.status}`);
1723
+ toast(`${t('sessions.kanban.moveFail')}: ${body?.error ?? r.status}`, { kind: 'error' });
1656
1724
  }
1657
1725
  }
1658
1726
  catch (e) {
1659
1727
  row.kanbanColumn = prev.column;
1660
1728
  row.kanbanPosition = prev.position;
1661
1729
  refresh();
1662
- alert(`${t('sessions.kanban.moveFail')}: ${e}`);
1730
+ toast(`${t('sessions.kanban.moveFail')}: ${e}`, { kind: 'error' });
1663
1731
  }
1664
1732
  }, [refresh]);
1665
1733
  const handleKanbanMoves = useCallback((moves) => {
@@ -1714,13 +1782,13 @@ function SessionsPage() {
1714
1782
  row.title = prevTitle;
1715
1783
  refresh();
1716
1784
  if (r.status !== 401)
1717
- alert(`${t('sessions.kanban.renameFail')}: ${body?.error ?? r.status}`);
1785
+ toast(`${t('sessions.kanban.renameFail')}: ${body?.error ?? r.status}`, { kind: 'error' });
1718
1786
  }
1719
1787
  }
1720
1788
  catch (e) {
1721
1789
  row.title = prevTitle;
1722
1790
  refresh();
1723
- alert(`${t('sessions.kanban.renameFail')}: ${e}`);
1791
+ toast(`${t('sessions.kanban.renameFail')}: ${e}`, { kind: 'error' });
1724
1792
  }
1725
1793
  }, [refresh]);
1726
1794
  const locateSession = useCallback(async (row) => {
@@ -1732,16 +1800,16 @@ function SessionsPage() {
1732
1800
  const body = await r.json();
1733
1801
  if (body.ok)
1734
1802
  return true;
1735
- alert(`Locate failed: ${body.error ?? r.status}`);
1803
+ toast(`Locate failed: ${body.error ?? r.status}`, { kind: 'error' });
1736
1804
  return false;
1737
1805
  }
1738
1806
  catch (e) {
1739
- alert(`Locate error: ${e}`);
1807
+ toast(`Locate error: ${e}`, { kind: 'error' });
1740
1808
  return false;
1741
1809
  }
1742
1810
  }, []);
1743
1811
  const closeSession = useCallback(async (row, closeBtn) => {
1744
- if (!confirm(t('sessions.closeConfirm')))
1812
+ if (!await confirm({ title: '关闭会话', message: t('sessions.closeConfirm'), danger: true }))
1745
1813
  return false;
1746
1814
  if (closeBtn)
1747
1815
  closeBtn.disabled = true;
@@ -1750,7 +1818,7 @@ function SessionsPage() {
1750
1818
  const body = await r.json().catch(() => ({}));
1751
1819
  if (!r.ok || body?.ok === false) {
1752
1820
  if (r.status !== 401)
1753
- alert(`Close failed: ${body?.error ?? r.status}`);
1821
+ toast(`Close failed: ${body?.error ?? r.status}`, { kind: 'error' });
1754
1822
  return false;
1755
1823
  }
1756
1824
  // Closed locally, but a remote session was left running (its control plane
@@ -1758,11 +1826,11 @@ function SessionsPage() {
1758
1826
  // moment the operator can be told.
1759
1827
  const residual = parseCloseResidual(body);
1760
1828
  if (residual) {
1761
- alert(closeResidualIsLocal(residual)
1829
+ toast(closeResidualIsLocal(residual)
1762
1830
  ? `⚠️ Closed locally, but a credentialed host subtree could NOT be proven terminated: `
1763
1831
  + `${describeCloseResidual(residual)}. The remote session WAS cancelled — inspect the local host process.`
1764
1832
  : `⚠️ Closed locally, but the remote session was NOT cancelled: `
1765
- + `${describeCloseResidual(residual)} — manual cleanup required.`);
1833
+ + `${describeCloseResidual(residual)} — manual cleanup required.`, { kind: 'warning' });
1766
1834
  }
1767
1835
  setSelected(prev => {
1768
1836
  const next = new Set(prev);
@@ -1773,7 +1841,7 @@ function SessionsPage() {
1773
1841
  return true;
1774
1842
  }
1775
1843
  catch (e) {
1776
- alert(`Close error: ${e}`);
1844
+ toast(`Close error: ${e}`, { kind: 'error' });
1777
1845
  return false;
1778
1846
  }
1779
1847
  finally {
@@ -1800,7 +1868,7 @@ function SessionsPage() {
1800
1868
  row.locked = prev;
1801
1869
  refresh();
1802
1870
  if (r.status !== 401)
1803
- alert(`${t('sessions.lockFailed')}: ${body?.error ?? r.status}`);
1871
+ toast(`${t('sessions.lockFailed')}: ${body?.error ?? r.status}`, { kind: 'error' });
1804
1872
  return false;
1805
1873
  }
1806
1874
  row.locked = !!body.locked;
@@ -1810,7 +1878,7 @@ function SessionsPage() {
1810
1878
  catch (e) {
1811
1879
  row.locked = prev;
1812
1880
  refresh();
1813
- alert(`${t('sessions.lockFailed')}: ${e}`);
1881
+ toast(`${t('sessions.lockFailed')}: ${e}`, { kind: 'error' });
1814
1882
  return false;
1815
1883
  }
1816
1884
  finally {
@@ -1821,7 +1889,7 @@ function SessionsPage() {
1821
1889
  const restartSession = useCallback(async (row, restartBtn) => {
1822
1890
  if (restartCooldownIds.current.has(row.sessionId))
1823
1891
  return false;
1824
- if (!confirm(restartConfirmMessage(row)))
1892
+ if (!await confirm({ title: '重启会话', message: restartConfirmMessage(row), danger: true }))
1825
1893
  return false;
1826
1894
  if (restartBtn)
1827
1895
  restartBtn.disabled = true;
@@ -1830,7 +1898,7 @@ function SessionsPage() {
1830
1898
  const body = await r.json().catch(() => ({}));
1831
1899
  if (!r.ok || body?.ok === false) {
1832
1900
  if (r.status !== 401)
1833
- alert(`${t('sessions.restartFailed')}: ${body?.message ?? body?.error ?? r.status}`);
1901
+ toast(`${t('sessions.restartFailed')}: ${body?.message ?? body?.error ?? r.status}`, { kind: 'error' });
1834
1902
  return false;
1835
1903
  }
1836
1904
  restartCooldownIds.current.add(row.sessionId);
@@ -1838,7 +1906,7 @@ function SessionsPage() {
1838
1906
  return true;
1839
1907
  }
1840
1908
  catch (e) {
1841
- alert(`${t('sessions.restartFailed')}: ${e}`);
1909
+ toast(`${t('sessions.restartFailed')}: ${e}`, { kind: 'error' });
1842
1910
  return false;
1843
1911
  }
1844
1912
  finally {
@@ -1853,13 +1921,13 @@ function SessionsPage() {
1853
1921
  const r = await fetch(`/api/sessions/${encodeURIComponent(row.sessionId)}/resume`, { method: 'POST' });
1854
1922
  const body = await r.json().catch(() => ({}));
1855
1923
  if (!r.ok || body.ok === false) {
1856
- alert(`${t('sessions.resumeFailed')}: ${body?.error ?? r.status}`);
1924
+ toast(`${t('sessions.resumeFailed')}: ${body?.error ?? r.status}`, { kind: 'error' });
1857
1925
  return false;
1858
1926
  }
1859
1927
  return true;
1860
1928
  }
1861
1929
  catch (e) {
1862
- alert(`${t('sessions.resumeFailed')}: ${e}`);
1930
+ toast(`${t('sessions.resumeFailed')}: ${e}`, { kind: 'error' });
1863
1931
  return false;
1864
1932
  }
1865
1933
  finally {
@@ -1875,13 +1943,13 @@ function SessionsPage() {
1875
1943
  const body = await r.json().catch(() => ({}));
1876
1944
  if (!r.ok || body.ok === false) {
1877
1945
  if (r.status !== 401)
1878
- alert(`${t('sessions.create.startFailed')}: ${body?.error ?? r.status}`);
1946
+ toast(`${t('sessions.create.startFailed')}: ${body?.error ?? r.status}`, { kind: 'error' });
1879
1947
  return false;
1880
1948
  }
1881
1949
  return true;
1882
1950
  }
1883
1951
  catch (e) {
1884
- alert(`${t('sessions.create.startFailed')}: ${e}`);
1952
+ toast(`${t('sessions.create.startFailed')}: ${e}`, { kind: 'error' });
1885
1953
  return false;
1886
1954
  }
1887
1955
  finally {
@@ -1922,11 +1990,19 @@ function SessionsPage() {
1922
1990
  const openWritableTerminal = useCallback((row, button) => {
1923
1991
  void openWriteLink(row, button);
1924
1992
  }, []);
1993
+ // 抽屉主操作「接管终端」:有权限直接开可写终端,否则退到只读终端弹窗。
1994
+ const takeoverSession = useCallback((row, button) => {
1995
+ if (shouldOpenWritableTerminal() && row.status !== 'closed') {
1996
+ void openWriteLink(row, button);
1997
+ return;
1998
+ }
1999
+ openTerminalModal(row);
2000
+ }, [openTerminalModal]);
1925
2001
  const runBulkClose = useCallback(async () => {
1926
2002
  const ids = [...selected];
1927
2003
  if (ids.length === 0)
1928
2004
  return;
1929
- if (!confirm(t('sessions.closeBulkConfirm', { count: ids.length })))
2005
+ if (!await confirm({ title: '关闭会话', message: t('sessions.closeBulkConfirm', { count: ids.length }), danger: true }))
1930
2006
  return;
1931
2007
  setBulkCloseProgress({ done: 0, total: ids.length });
1932
2008
  let done = 0;
@@ -1964,14 +2040,14 @@ function SessionsPage() {
1964
2040
  setSelected(new Set());
1965
2041
  refresh();
1966
2042
  if (failed > 0)
1967
- alert(`Failed: ${failed}/${ids.length}`);
2043
+ toast(`Failed: ${failed}/${ids.length}`, { kind: 'error' });
1968
2044
  if (residualIds.length > 0) {
1969
2045
  // Fires even when nothing failed — otherwise an all-residual batch is
1970
2046
  // entirely silent and the operator believes everything is gone. Kind-neutral
1971
2047
  // (a batch can mix a surviving remote session and a local host subtree); each
1972
2048
  // label already states which.
1973
- alert(`⚠️ ${residualIds.length}/${ids.length} closed locally but left a residual `
1974
- + `requiring manual cleanup: ${residualIds.join(', ')}`);
2049
+ toast(`⚠️ ${residualIds.length}/${ids.length} closed locally but left a residual `
2050
+ + `requiring manual cleanup: ${residualIds.join(', ')}`, { kind: 'warning' });
1975
2051
  }
1976
2052
  }, [refresh, selected]);
1977
2053
  const runBulkLock = useCallback(async (locked) => {
@@ -2017,7 +2093,7 @@ function SessionsPage() {
2017
2093
  setBulkLockProgress(null);
2018
2094
  refresh();
2019
2095
  if (failed > 0)
2020
- alert(`${t('sessions.lockFailed')}: ${failed}/${targetRows.length}`);
2096
+ toast(`${t('sessions.lockFailed')}: ${failed}/${targetRows.length}`, { kind: 'error' });
2021
2097
  }, [refresh, rowsById, selected]);
2022
2098
  const addSelectedToMonitorRoom = useCallback(() => {
2023
2099
  const ids = [...selected].filter(id => !!rowsById.get(id));
@@ -2046,7 +2122,7 @@ function SessionsPage() {
2046
2122
  const body = await r.json().catch(() => ({}));
2047
2123
  if (!r.ok) {
2048
2124
  if (r.status !== 401)
2049
- alert(`${t('sessions.idleCleanupFailed')}: ${body?.error ?? r.status}`);
2125
+ toast(`${t('sessions.idleCleanupFailed')}: ${body?.error ?? r.status}`, { kind: 'error' });
2050
2126
  setIdleCleanupStatus('');
2051
2127
  return;
2052
2128
  }
@@ -2070,13 +2146,13 @@ function SessionsPage() {
2070
2146
  // while some rows left a residual (a remote session still running, or a
2071
2147
  // local host subtree not proven terminated) needing manual cleanup.
2072
2148
  // Kind-neutral: a batch can mix both, and each label already says which.
2073
- alert(`⚠️ ${idleResiduals.length} session(s) closed locally but left a residual `
2074
- + `requiring manual cleanup: ${idleResiduals.join(', ')}`);
2149
+ toast(`⚠️ ${idleResiduals.length} session(s) closed locally but left a residual `
2150
+ + `requiring manual cleanup: ${idleResiduals.join(', ')}`, { kind: 'warning' });
2075
2151
  }
2076
2152
  refresh();
2077
2153
  }
2078
2154
  catch (e) {
2079
- alert(`${t('sessions.idleCleanupFailed')}: ${e}`);
2155
+ toast(`${t('sessions.idleCleanupFailed')}: ${e}`, { kind: 'error' });
2080
2156
  setIdleCleanupStatus('');
2081
2157
  }
2082
2158
  finally {
@@ -2090,6 +2166,15 @@ function SessionsPage() {
2090
2166
  setViewMode(next);
2091
2167
  writeStoredSessionsViewMode(windowStorage(), next);
2092
2168
  };
2169
+ // 表格表头排序与筛选条排序下拉共用同一套 state 切换逻辑。
2170
+ const handleSort = useCallback((key) => {
2171
+ if (sortKey === key)
2172
+ setSortDir(dir => (dir === 'asc' ? 'desc' : 'asc'));
2173
+ else {
2174
+ setSortKey(key);
2175
+ setSortDir(key === 'spawnedAt' || key === 'lastMessageAt' ? 'desc' : 'asc');
2176
+ }
2177
+ }, [sortKey]);
2093
2178
  const moveColumn = (id, delta) => {
2094
2179
  setBoardOrder(prev => {
2095
2180
  const from = prev.indexOf(id);
@@ -2165,7 +2250,7 @@ function SessionsPage() {
2165
2250
  // 调试终端:起一个 owner-only 裸 bash(不绑飞书话题),在新标签打开 xterm 页面。
2166
2251
  // 让用户把「复制复现命令」拿到的命令粘进去改参数复现问题,用完关闭即回收。
2167
2252
  const openDebugTerminal = useCallback(async () => {
2168
- const input = window.prompt(t('sessions.debugTerminalPrompt'), '');
2253
+ const input = await promptText({ title: t('sessions.debugTerminal'), message: t('sessions.debugTerminalPrompt') });
2169
2254
  if (input === null)
2170
2255
  return; // 用户取消
2171
2256
  const workingDir = input.trim();
@@ -2182,7 +2267,7 @@ function SessionsPage() {
2182
2267
  if (!r.ok || body?.ok === false || !body?.url) {
2183
2268
  tab?.close();
2184
2269
  if (r.status !== 401)
2185
- alert(`${t('sessions.debugTerminalFail')}: ${body?.error ?? r.status}`);
2270
+ toast(`${t('sessions.debugTerminalFail')}: ${body?.error ?? r.status}`, { kind: 'error' });
2186
2271
  return;
2187
2272
  }
2188
2273
  if (tab)
@@ -2192,7 +2277,7 @@ function SessionsPage() {
2192
2277
  }
2193
2278
  catch (e) {
2194
2279
  tab?.close();
2195
- alert(`${t('sessions.debugTerminalFail')}: ${e}`);
2280
+ toast(`${t('sessions.debugTerminalFail')}: ${e}`, { kind: 'error' });
2196
2281
  }
2197
2282
  }, []);
2198
2283
  useEffect(() => {
@@ -2226,13 +2311,13 @@ function SessionsPage() {
2226
2311
  window.localStorage.setItem(KANBAN_TEAM_STORAGE_KEY, next);
2227
2312
  }
2228
2313
  catch { /* current page only */ }
2229
- } })] })] }), _jsxs("div", { className: "page-heading-actions sessions-page-actions", children: [dashboardShellAllowsWebTerminal() ? (_jsx("button", { type: "button", id: "monitor-room-open", className: "monitor-room-open", onClick: () => { window.location.href = monitorRoomUrl(); }, children: t('sessions.monitorRoom') })) : null, ui.authed ? (_jsx("button", { type: "button", className: "debug-terminal-btn", title: t('sessions.debugTerminalHint'), onClick: () => void openDebugTerminal(), children: t('sessions.debugTerminal') })) : null, ui.authed ? (_jsx(CreateActionButton, { className: "page-primary-action create-session-btn", disabled: createLoading, onClick: () => void openCreateSession(), children: t('sessions.create.button') })) : null] })] }), _jsxs("div", { className: "session-runtime-stats", "aria-live": "polite", children: [_jsxs("span", { children: [_jsx("b", { children: runtimeCounts.logical }), t('sessions.runtime.logical')] }), _jsxs("span", { children: [_jsx("b", { children: runtimeCounts.resident }), t('sessions.runtime.resident')] }), _jsxs("span", { children: [_jsx("b", { children: runtimeCounts.dormant }), t('sessions.runtime.dormant')] })] }), _jsx(SessionsFilters, { chatOptions: chatOptions, filters: filters, setFilters: setFilters, idleCleanup: {
2314
+ } })] })] }), _jsxs("div", { className: "page-heading-actions sessions-page-actions", children: [dashboardShellAllowsWebTerminal() ? (_jsx("button", { type: "button", id: "monitor-room-open", className: "monitor-room-open", onClick: () => { window.location.href = monitorRoomUrl(); }, children: t('sessions.monitorRoom') })) : null, ui.authed ? (_jsx("button", { type: "button", className: "debug-terminal-btn", title: t('sessions.debugTerminalHint'), onClick: () => void openDebugTerminal(), children: t('sessions.debugTerminal') })) : null, ui.authed ? (_jsx(CreateActionButton, { className: "page-primary-action create-session-btn", disabled: createLoading, onClick: () => void openCreateSession(), children: t('sessions.create.button') })) : null] })] }), _jsxs("div", { className: "session-runtime-stats", "aria-live": "polite", children: [_jsxs("span", { children: [_jsx("b", { children: runtimeCounts.logical }), t('sessions.runtime.logical')] }), _jsxs("span", { children: [_jsx("b", { children: runtimeCounts.resident }), t('sessions.runtime.resident')] }), _jsxs("span", { children: [_jsx("b", { children: runtimeCounts.dormant }), t('sessions.runtime.dormant')] })] }), _jsx(SessionsFilters, { chatOptions: chatOptions, filters: filters, setFilters: setFilters, sortKey: sortKey, sortDir: sortDir, onSort: handleSort, idleCleanup: {
2230
2315
  busy: idleCleanupBusy,
2231
2316
  hours: idleCleanupHours,
2232
2317
  status: idleCleanupStatus,
2233
2318
  countForHours: hours => idleCleanupCandidatesFor(hours).length,
2234
2319
  onRun: runIdleCleanup,
2235
- } }), _jsx(BulkBar, { selectedCount: selected.size, lockDisabled: !selectedRows.some(row => !row.locked), unlockDisabled: !selectedRows.some(row => !!row.locked), closeProgress: bulkCloseProgress, lockProgress: bulkLockProgress, monitorRoomText: monitorRoomFeedback, onClear: () => setSelected(new Set()), onClose: () => void runBulkClose(), onAddToMonitorRoom: addSelectedToMonitorRoom, onLock: locked => void runBulkLock(locked) }), _jsxs("div", { className: `sessions-view-stage${viewStageAnimKey > 0 ? ' sessions-view-stage-enter' : ''}`, "data-view": viewMode, "data-kanban-group": kanbanGroupBy, children: [_jsx(SessionsTable, { rows: rows, selected: selected, hidden: viewMode !== 'table', sortKey: sortKey, sortDir: sortDir, selectAllChecked: selectAllChecked, selectAllIndeterminate: selectAllIndeterminate, selectAllDisabled: selectableRows.length === 0, hiddenColumns: hiddenColumns, onToggleColumn: (colId) => {
2320
+ } }), _jsx(BulkBar, { selectedCount: selected.size, lockDisabled: !selectedRows.some(row => !row.locked), unlockDisabled: !selectedRows.some(row => !!row.locked), closeProgress: bulkCloseProgress, lockProgress: bulkLockProgress, monitorRoomText: monitorRoomFeedback, onClear: () => setSelected(new Set()), onClose: () => void runBulkClose(), onAddToMonitorRoom: addSelectedToMonitorRoom, onLock: locked => void runBulkLock(locked) }), _jsxs("div", { className: `sessions-view-stage${viewStageAnimKey > 0 ? ' sessions-view-stage-enter' : ''}`, "data-view": viewMode, "data-kanban-group": kanbanGroupBy, children: [!bootstrapped ? _jsx(SessionsSkeleton, {}) : null, _jsx(SessionsTable, { rows: rows, selected: selected, hidden: viewMode !== 'table' || !bootstrapped, sortKey: sortKey, sortDir: sortDir, selectAllChecked: selectAllChecked, selectAllIndeterminate: selectAllIndeterminate, selectAllDisabled: selectableRows.length === 0, hiddenColumns: hiddenColumns, onToggleColumn: (colId) => {
2236
2321
  const willHide = !hiddenColumns.has(colId);
2237
2322
  const next = new Set(hiddenColumns);
2238
2323
  if (willHide)
@@ -2265,37 +2350,35 @@ function SessionsPage() {
2265
2350
  next.delete(row.sessionId);
2266
2351
  }
2267
2352
  return next;
2268
- }), onSort: (key) => {
2269
- if (sortKey === key)
2270
- setSortDir(sortDir === 'asc' ? 'desc' : 'asc');
2271
- else {
2272
- setSortKey(key);
2273
- setSortDir(key === 'spawnedAt' || key === 'lastMessageAt' ? 'desc' : 'asc');
2274
- }
2275
- } }), _jsx(BoardView, { rows: boardRows, selected: selected, hidden: viewMode !== 'board', order: boardOrder, animated: boardAnimated, dragColId: dragColId, dragOverCol: dragOverCol, onAnimated: () => setBoardAnimated(true), onMoveColumn: moveColumn, onMoveColumnTo: moveColumnTo, onDragCol: setDragColId, onDragOverCol: setDragOverCol, onToggleSelect: row => setSelected(prev => {
2353
+ }), onSort: handleSort }), _jsx(BoardView, { rows: boardRows, selected: selected, hidden: viewMode !== 'board' || !bootstrapped, order: boardOrder, animated: boardAnimated, dragColId: dragColId, dragOverCol: dragOverCol, onAnimated: () => setBoardAnimated(true), onMoveColumn: moveColumn, onMoveColumnTo: moveColumnTo, onDragCol: setDragColId, onDragOverCol: setDragOverCol, onToggleSelect: row => setSelected(prev => {
2276
2354
  const next = new Set(prev);
2277
2355
  if (next.has(row.sessionId))
2278
2356
  next.delete(row.sessionId);
2279
2357
  else
2280
2358
  next.add(row.sessionId);
2281
2359
  return next;
2282
- }), onOpen: row => setDrawerSessionId(row.sessionId), onHistory: openHistoryModal, onLocate: row => locateSession(row), onRestart: (row, button) => void restartSession(row, button), onLock: (row, locked, button) => void setSessionLocked(row, locked, button), onClose: (row, button) => void closeSession(row, button) }), _jsx(TopicGroupsView, { rows: rows, relationRows: storeRows, selected: selected, hidden: viewMode !== 'topics', onToggleSelect: row => setSelected(prev => {
2360
+ }), onOpen: row => setDrawerSessionId(row.sessionId), onHistory: openHistoryModal, onLocate: row => locateSession(row), onRestart: (row, button) => void restartSession(row, button), onLock: (row, locked, button) => void setSessionLocked(row, locked, button), onClose: (row, button) => void closeSession(row, button) }), _jsx(TopicGroupsView, { rows: rows, relationRows: storeRows, selected: selected, hidden: viewMode !== 'topics' || !bootstrapped, onToggleSelect: row => setSelected(prev => {
2283
2361
  const next = new Set(prev);
2284
2362
  if (next.has(row.sessionId))
2285
2363
  next.delete(row.sessionId);
2286
2364
  else
2287
2365
  next.add(row.sessionId);
2288
2366
  return next;
2289
- }), onOpen: row => setDrawerSessionId(row.sessionId), onHistory: openHistoryModal, onLocate: row => locateSession(row), onRestart: (row, button) => void restartSession(row, button), onLock: (row, locked, button) => void setSessionLocked(row, locked, button), onClose: (row, button) => void closeSession(row, button) }), _jsx("div", { id: "sessions-kanban", ref: setKanbanHost, className: `sessions-kanban${kanbanGroupBy === 'bot' ? ' kanban-mode-bot' : ''}`, hidden: viewMode !== 'kanban', children: viewMode === 'kanban' ? (_jsx(SessionsKanbanView, { host: kanbanHost, ...kanbanState, canRestartSession: canRestartSession, getTeamChatIds: teamChatIdsFor, icons: {
2367
+ }), onOpen: row => setDrawerSessionId(row.sessionId), onHistory: openHistoryModal, onLocate: row => locateSession(row), onRestart: (row, button) => void restartSession(row, button), onLock: (row, locked, button) => void setSessionLocked(row, locked, button), onClose: (row, button) => void closeSession(row, button) }), _jsx("div", { id: "sessions-kanban", ref: setKanbanHost, className: `sessions-kanban${kanbanGroupBy === 'bot' ? ' kanban-mode-bot' : ''}`, hidden: viewMode !== 'kanban' || !bootstrapped, children: viewMode === 'kanban' ? (_jsx(SessionsKanbanView, { host: kanbanHost, ...kanbanState, canRestartSession: canRestartSession, getTeamChatIds: teamChatIdsFor, icons: {
2290
2368
  details: ICON.details,
2291
2369
  feishu: ICON.feishu,
2292
2370
  history: ICON.history,
2293
2371
  key: ICON.key,
2294
2372
  lock: ICON.lock,
2295
2373
  restart: ICON.restart,
2374
+ close: ICON.close,
2296
2375
  terminal: ICON.terminal,
2297
2376
  unlock: ICON.unlock,
2298
- }, lockActionLabel: lockActionLabel, sessionStatusText: sessionStatusText, onDetails: row => setDrawerSessionId(String(row.sessionId)), onHistory: openHistoryModal, onMoveRows: handleKanbanMoves, onNeedTeamBoard: team => { void ensureTeamBoard(team); }, onNeedTeams: () => { void loadKanbanTeams(); }, onOpenTerminal: dashboardShellAllowsWebTerminal() ? openTerminalModal : undefined, onOpenWritableTerminal: dashboardShellAllowsWebTerminal() && shouldOpenWritableTerminal() ? openWritableTerminal : undefined, onRename: (row, title) => { const s = store.sessions.get(String(row.sessionId)); if (s)
2377
+ }, lockActionLabel: lockActionLabel, sessionStatusText: sessionStatusText, onClose: (row, button) => {
2378
+ const s = store.sessions.get(String(row.sessionId));
2379
+ if (s)
2380
+ void closeSession(s, button);
2381
+ }, onDetails: row => setDrawerSessionId(String(row.sessionId)), onHistory: openHistoryModal, onMoveRows: handleKanbanMoves, onNeedTeamBoard: team => { void ensureTeamBoard(team); }, onNeedTeams: () => { void loadKanbanTeams(); }, onOpenTerminal: dashboardShellAllowsWebTerminal() ? openTerminalModal : undefined, onOpenWritableTerminal: dashboardShellAllowsWebTerminal() && shouldOpenWritableTerminal() ? openWritableTerminal : undefined, onRename: (row, title) => { const s = store.sessions.get(String(row.sessionId)); if (s)
2299
2382
  void persistRename(s, title); }, onRestart: (row, button) => { const s = store.sessions.get(String(row.sessionId)); if (s)
2300
2383
  void restartSession(s, button); }, onTeamScope: scope => setTeamScopeText(scope ? t('sessions.kanban.teamScope', { chats: scope.chats, sessions: scope.sessions }) : ''), onToggleLock: (row, button) => { const s = store.sessions.get(String(row.sessionId)); if (s)
2301
2384
  void setSessionLocked(s, !s.locked, button); }, onToggleSelect: row => setSelected(prev => {
@@ -2306,7 +2389,7 @@ function SessionsPage() {
2306
2389
  else
2307
2390
  next.add(id);
2308
2391
  return next;
2309
- }), selectedSessionIds: selected })) : null })] }, viewStageAnimKey), _jsx(Drawer, { row: drawerRow, onClose: () => setDrawerSessionId(null), locateSession: locateSession, openHistory: openHistoryModal, resumeSession: resumeSession, restartSession: restartSession, closeSession: closeSession, setSessionLocked: setSessionLocked, startSession: startSession }), _jsx(TerminalModal, { state: termState, onClose: () => setTermState(null), onRename: persistRename }), _jsx(HistoryModal, { state: historyState, onClose: () => setHistoryState(null) }), createDialogEl ? createPortal(_jsx(CreateSessionDialog, { dialog: createDialogEl, state: createState, onClose: closeCreateSession, onSuccess: body => setCreateState(prev => prev ? { ...prev, success: body } : prev) }), createDialogEl) : null] }));
2392
+ }), selectedSessionIds: selected })) : null })] }, viewStageAnimKey), _jsx(Drawer, { row: drawerRow, onClose: () => setDrawerSessionId(null), locateSession: locateSession, openHistory: openHistoryModal, resumeSession: resumeSession, restartSession: restartSession, closeSession: closeSession, setSessionLocked: setSessionLocked, startSession: startSession, onTakeover: takeoverSession }), _jsx(TerminalModal, { state: termState, onClose: () => setTermState(null), onRename: persistRename }), _jsx(HistoryModal, { state: historyState, onClose: () => setHistoryState(null) }), createDialogEl ? createPortal(_jsx(CreateSessionDialog, { dialog: createDialogEl, state: createState, onClose: closeCreateSession, onSuccess: body => setCreateState(prev => prev ? { ...prev, success: body } : prev) }), createDialogEl) : null] }));
2310
2393
  }
2311
2394
  export function renderSessionsPage(root) {
2312
2395
  return mountReactPage(root, _jsx(SessionsPage, {}));