botmux 3.11.0 → 3.12.1

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 (343) hide show
  1. package/dist/.runtime-build-id +1 -1
  2. package/dist/adapters/backend/riff-backend.d.ts +18 -0
  3. package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
  4. package/dist/adapters/backend/riff-backend.js +154 -2
  5. package/dist/adapters/backend/riff-backend.js.map +1 -1
  6. package/dist/adapters/cli/coco.js +3 -3
  7. package/dist/adapters/cli/coco.js.map +1 -1
  8. package/dist/adapters/cli/codex.js +2 -2
  9. package/dist/adapters/cli/codex.js.map +1 -1
  10. package/dist/adapters/cli/kimi.d.ts.map +1 -1
  11. package/dist/adapters/cli/kimi.js +22 -8
  12. package/dist/adapters/cli/kimi.js.map +1 -1
  13. package/dist/adapters/cli/pi.d.ts.map +1 -1
  14. package/dist/adapters/cli/pi.js +3 -1
  15. package/dist/adapters/cli/pi.js.map +1 -1
  16. package/dist/bot-registry.d.ts.map +1 -1
  17. package/dist/bot-registry.js +4 -1
  18. package/dist/bot-registry.js.map +1 -1
  19. package/dist/cli/dashboard-command.d.ts +23 -0
  20. package/dist/cli/dashboard-command.d.ts.map +1 -0
  21. package/dist/cli/dashboard-command.js +61 -0
  22. package/dist/cli/dashboard-command.js.map +1 -0
  23. package/dist/cli/dashboard-endpoint.d.ts +3 -3
  24. package/dist/cli/dashboard-endpoint.d.ts.map +1 -1
  25. package/dist/cli/dashboard-endpoint.js +1 -1
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +101 -49
  28. package/dist/cli.js.map +1 -1
  29. package/dist/codex-rpc-engine.d.ts +33 -3
  30. package/dist/codex-rpc-engine.d.ts.map +1 -1
  31. package/dist/codex-rpc-engine.js +182 -20
  32. package/dist/codex-rpc-engine.js.map +1 -1
  33. package/dist/codex-rpc-lifecycle.d.ts +42 -7
  34. package/dist/codex-rpc-lifecycle.d.ts.map +1 -1
  35. package/dist/codex-rpc-lifecycle.js +73 -7
  36. package/dist/codex-rpc-lifecycle.js.map +1 -1
  37. package/dist/config.d.ts +1 -1
  38. package/dist/config.js +1 -1
  39. package/dist/core/command-handler.d.ts +3 -2
  40. package/dist/core/command-handler.d.ts.map +1 -1
  41. package/dist/core/command-handler.js +19 -4
  42. package/dist/core/command-handler.js.map +1 -1
  43. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  44. package/dist/core/dashboard-ipc-server.js +16 -11
  45. package/dist/core/dashboard-ipc-server.js.map +1 -1
  46. package/dist/core/dashboard-rows.d.ts +17 -1
  47. package/dist/core/dashboard-rows.d.ts.map +1 -1
  48. package/dist/core/dashboard-rows.js +13 -1
  49. package/dist/core/dashboard-rows.js.map +1 -1
  50. package/dist/core/dispatch.d.ts +9 -10
  51. package/dist/core/dispatch.d.ts.map +1 -1
  52. package/dist/core/dispatch.js +17 -10
  53. package/dist/core/dispatch.js.map +1 -1
  54. package/dist/core/maintenance.d.ts.map +1 -1
  55. package/dist/core/maintenance.js +5 -0
  56. package/dist/core/maintenance.js.map +1 -1
  57. package/dist/core/role-resolver.d.ts +5 -2
  58. package/dist/core/role-resolver.d.ts.map +1 -1
  59. package/dist/core/role-resolver.js +55 -23
  60. package/dist/core/role-resolver.js.map +1 -1
  61. package/dist/core/session-manager.d.ts +2 -0
  62. package/dist/core/session-manager.d.ts.map +1 -1
  63. package/dist/core/session-manager.js +20 -18
  64. package/dist/core/session-manager.js.map +1 -1
  65. package/dist/core/skills/cli-admin-command.d.ts.map +1 -1
  66. package/dist/core/skills/cli-admin-command.js +142 -3
  67. package/dist/core/skills/cli-admin-command.js.map +1 -1
  68. package/dist/core/skills/frontmatter.d.ts.map +1 -1
  69. package/dist/core/skills/frontmatter.js +44 -7
  70. package/dist/core/skills/frontmatter.js.map +1 -1
  71. package/dist/core/skills/im-command.d.ts +6 -0
  72. package/dist/core/skills/im-command.d.ts.map +1 -1
  73. package/dist/core/skills/im-command.js +34 -7
  74. package/dist/core/skills/im-command.js.map +1 -1
  75. package/dist/core/skills/install-command.d.ts +4 -0
  76. package/dist/core/skills/install-command.d.ts.map +1 -0
  77. package/dist/core/skills/install-command.js +89 -0
  78. package/dist/core/skills/install-command.js.map +1 -0
  79. package/dist/core/skills/package.d.ts.map +1 -1
  80. package/dist/core/skills/package.js +10 -3
  81. package/dist/core/skills/package.js.map +1 -1
  82. package/dist/core/skills/policy.d.ts +5 -1
  83. package/dist/core/skills/policy.d.ts.map +1 -1
  84. package/dist/core/skills/policy.js +66 -3
  85. package/dist/core/skills/policy.js.map +1 -1
  86. package/dist/core/skills/references.d.ts +9 -1
  87. package/dist/core/skills/references.d.ts.map +1 -1
  88. package/dist/core/skills/references.js +35 -2
  89. package/dist/core/skills/references.js.map +1 -1
  90. package/dist/core/skills/registry-paths.d.ts +1 -0
  91. package/dist/core/skills/registry-paths.d.ts.map +1 -1
  92. package/dist/core/skills/registry-paths.js +3 -0
  93. package/dist/core/skills/registry-paths.js.map +1 -1
  94. package/dist/core/skills/session-resolver.d.ts +2 -1
  95. package/dist/core/skills/session-resolver.d.ts.map +1 -1
  96. package/dist/core/skills/session-resolver.js +1 -0
  97. package/dist/core/skills/session-resolver.js.map +1 -1
  98. package/dist/core/skills/session-runtime.d.ts.map +1 -1
  99. package/dist/core/skills/session-runtime.js +2 -0
  100. package/dist/core/skills/session-runtime.js.map +1 -1
  101. package/dist/core/skills/sources.d.ts +23 -0
  102. package/dist/core/skills/sources.d.ts.map +1 -1
  103. package/dist/core/skills/sources.js +128 -12
  104. package/dist/core/skills/sources.js.map +1 -1
  105. package/dist/core/skills/types.d.ts +22 -1
  106. package/dist/core/skills/types.d.ts.map +1 -1
  107. package/dist/core/terminal-write-auth.d.ts +4 -4
  108. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  109. package/dist/core/terminal-write-auth.js +18 -6
  110. package/dist/core/terminal-write-auth.js.map +1 -1
  111. package/dist/core/types.d.ts +2 -0
  112. package/dist/core/types.d.ts.map +1 -1
  113. package/dist/core/types.js.map +1 -1
  114. package/dist/core/worker-pool.d.ts.map +1 -1
  115. package/dist/core/worker-pool.js +52 -1
  116. package/dist/core/worker-pool.js.map +1 -1
  117. package/dist/daemon.d.ts +1 -0
  118. package/dist/daemon.d.ts.map +1 -1
  119. package/dist/daemon.js +101 -12
  120. package/dist/daemon.js.map +1 -1
  121. package/dist/dashboard/auth.d.ts +21 -11
  122. package/dist/dashboard/auth.d.ts.map +1 -1
  123. package/dist/dashboard/auth.js +39 -25
  124. package/dist/dashboard/auth.js.map +1 -1
  125. package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
  126. package/dist/dashboard/bot-onboarding.js +2 -114
  127. package/dist/dashboard/bot-onboarding.js.map +1 -1
  128. package/dist/dashboard/bot-payload.d.ts +0 -1
  129. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  130. package/dist/dashboard/bot-payload.js +0 -1
  131. package/dist/dashboard/bot-payload.js.map +1 -1
  132. package/dist/dashboard/connector-api.d.ts.map +1 -1
  133. package/dist/dashboard/connector-api.js +66 -6
  134. package/dist/dashboard/connector-api.js.map +1 -1
  135. package/dist/dashboard/dashboard-summary-endpoint.d.ts +39 -0
  136. package/dist/dashboard/dashboard-summary-endpoint.d.ts.map +1 -0
  137. package/dist/dashboard/dashboard-summary-endpoint.js +50 -0
  138. package/dist/dashboard/dashboard-summary-endpoint.js.map +1 -0
  139. package/dist/dashboard/dashboard-summary.d.ts +62 -0
  140. package/dist/dashboard/dashboard-summary.d.ts.map +1 -0
  141. package/dist/dashboard/dashboard-summary.js +106 -0
  142. package/dist/dashboard/dashboard-summary.js.map +1 -0
  143. package/dist/dashboard/public-redact.d.ts.map +1 -1
  144. package/dist/dashboard/public-redact.js +3 -0
  145. package/dist/dashboard/public-redact.js.map +1 -1
  146. package/dist/dashboard/skill-install-request.js +10 -11
  147. package/dist/dashboard/skill-install-request.js.map +1 -1
  148. package/dist/dashboard/skill-pack-response.d.ts +15 -0
  149. package/dist/dashboard/skill-pack-response.d.ts.map +1 -0
  150. package/dist/dashboard/skill-pack-response.js +32 -0
  151. package/dist/dashboard/skill-pack-response.js.map +1 -0
  152. package/dist/dashboard/web/connectors-page.d.ts +69 -0
  153. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  154. package/dist/dashboard/web/connectors-page.js +47 -7
  155. package/dist/dashboard/web/connectors-page.js.map +1 -1
  156. package/dist/dashboard/web/feed-group-picker.d.ts +13 -0
  157. package/dist/dashboard/web/feed-group-picker.d.ts.map +1 -0
  158. package/dist/dashboard/web/feed-group-picker.js +45 -0
  159. package/dist/dashboard/web/feed-group-picker.js.map +1 -0
  160. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  161. package/dist/dashboard/web/groups-page.js +2 -5
  162. package/dist/dashboard/web/groups-page.js.map +1 -1
  163. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  164. package/dist/dashboard/web/i18n.js +309 -40
  165. package/dist/dashboard/web/i18n.js.map +1 -1
  166. package/dist/dashboard/web/preferences.d.ts +4 -2
  167. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  168. package/dist/dashboard/web/preferences.js +14 -6
  169. package/dist/dashboard/web/preferences.js.map +1 -1
  170. package/dist/dashboard/web/roles-page.d.ts.map +1 -1
  171. package/dist/dashboard/web/roles-page.js +36 -4
  172. package/dist/dashboard/web/roles-page.js.map +1 -1
  173. package/dist/dashboard/web/roles.d.ts +3 -1
  174. package/dist/dashboard/web/roles.d.ts.map +1 -1
  175. package/dist/dashboard/web/roles.js +10 -2
  176. package/dist/dashboard/web/roles.js.map +1 -1
  177. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  178. package/dist/dashboard/web/schedules-page.js +8 -2
  179. package/dist/dashboard/web/schedules-page.js.map +1 -1
  180. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  181. package/dist/dashboard/web/sessions-page.js +101 -5
  182. package/dist/dashboard/web/sessions-page.js.map +1 -1
  183. package/dist/dashboard/web/sessions.d.ts +3 -1
  184. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  185. package/dist/dashboard/web/sessions.js +13 -6
  186. package/dist/dashboard/web/sessions.js.map +1 -1
  187. package/dist/dashboard/web/skills/bot-assignments-tab.d.ts +27 -0
  188. package/dist/dashboard/web/skills/bot-assignments-tab.d.ts.map +1 -0
  189. package/dist/dashboard/web/skills/bot-assignments-tab.js +257 -0
  190. package/dist/dashboard/web/skills/bot-assignments-tab.js.map +1 -0
  191. package/dist/dashboard/web/skills/delivery-settings-tab.d.ts +25 -0
  192. package/dist/dashboard/web/skills/delivery-settings-tab.d.ts.map +1 -0
  193. package/dist/dashboard/web/skills/delivery-settings-tab.js +20 -0
  194. package/dist/dashboard/web/skills/delivery-settings-tab.js.map +1 -0
  195. package/dist/dashboard/web/skills/shared.d.ts +86 -0
  196. package/dist/dashboard/web/skills/shared.d.ts.map +1 -0
  197. package/dist/dashboard/web/skills/shared.js +178 -0
  198. package/dist/dashboard/web/skills/shared.js.map +1 -0
  199. package/dist/dashboard/web/skills/skill-library-tab.d.ts +75 -0
  200. package/dist/dashboard/web/skills/skill-library-tab.d.ts.map +1 -0
  201. package/dist/dashboard/web/skills/skill-library-tab.js +108 -0
  202. package/dist/dashboard/web/skills/skill-library-tab.js.map +1 -0
  203. package/dist/dashboard/web/skills/skill-packs-tab.d.ts +21 -0
  204. package/dist/dashboard/web/skills/skill-packs-tab.d.ts.map +1 -0
  205. package/dist/dashboard/web/skills/skill-packs-tab.js +185 -0
  206. package/dist/dashboard/web/skills/skill-packs-tab.js.map +1 -0
  207. package/dist/dashboard/web/skills/types.d.ts +95 -0
  208. package/dist/dashboard/web/skills/types.d.ts.map +1 -0
  209. package/dist/dashboard/web/skills/types.js +2 -0
  210. package/dist/dashboard/web/skills/types.js.map +1 -0
  211. package/dist/dashboard/web/skills/use-skills-data.d.ts +31 -0
  212. package/dist/dashboard/web/skills/use-skills-data.d.ts.map +1 -0
  213. package/dist/dashboard/web/skills/use-skills-data.js +86 -0
  214. package/dist/dashboard/web/skills/use-skills-data.js.map +1 -0
  215. package/dist/dashboard/web/skills-page.d.ts +34 -31
  216. package/dist/dashboard/web/skills-page.d.ts.map +1 -1
  217. package/dist/dashboard/web/skills-page.js +321 -176
  218. package/dist/dashboard/web/skills-page.js.map +1 -1
  219. package/dist/dashboard/webhook-routes.d.ts +18 -0
  220. package/dist/dashboard/webhook-routes.d.ts.map +1 -1
  221. package/dist/dashboard/webhook-routes.js +35 -1
  222. package/dist/dashboard/webhook-routes.js.map +1 -1
  223. package/dist/dashboard-web/app.js +1 -1
  224. package/dist/dashboard-web/chunks/{bot-defaults-page-GED4FEMS.js → bot-defaults-page-HL655CNR.js} +1 -1
  225. package/dist/dashboard-web/chunks/{chunk-HK7NIBJG.js → chunk-5PAYQ3KT.js} +1 -1
  226. package/dist/dashboard-web/chunks/{chunk-KRHWZEXU.js → chunk-5ZL7NLR5.js} +1 -1
  227. package/dist/dashboard-web/chunks/chunk-6ALR252E.js +1 -0
  228. package/dist/dashboard-web/chunks/{chunk-VBXJOJFH.js → chunk-BFUTTYVK.js} +1 -1
  229. package/dist/dashboard-web/chunks/chunk-ELL53D62.js +55 -0
  230. package/dist/dashboard-web/chunks/connectors-page-3QQACF23.js +1 -0
  231. package/dist/dashboard-web/chunks/groups-page-SDZMJ7UV.js +8 -0
  232. package/dist/dashboard-web/chunks/{insights-page-54UBPPOC.js → insights-page-ZZ3JEJ6L.js} +1 -1
  233. package/dist/dashboard-web/chunks/{monitor-room-PORHVKRH.js → monitor-room-ROJ5GZ4N.js} +1 -1
  234. package/dist/dashboard-web/chunks/{monitoring-page-XGA7AXNL.js → monitoring-page-IATV7KJF.js} +1 -1
  235. package/dist/dashboard-web/chunks/{office-page-AO3AFG45.js → office-page-TYO5OIIT.js} +1 -1
  236. package/dist/dashboard-web/chunks/{overview-page-F5BUTYR6.js → overview-page-VJUULZF2.js} +1 -1
  237. package/dist/dashboard-web/chunks/roles-page-7RJJKZGK.js +1 -0
  238. package/dist/dashboard-web/chunks/schedules-page-JTEJ5IXW.js +1 -0
  239. package/dist/dashboard-web/chunks/sessions-page-KD7HDT3U.js +8 -0
  240. package/dist/dashboard-web/chunks/{settings-page-OJAZLZQT.js → settings-page-7CTTFBRS.js} +1 -1
  241. package/dist/dashboard-web/chunks/skills-page-57NZECJ3.js +4 -0
  242. package/dist/dashboard-web/chunks/{team-federation-page-ZJVAP7HW.js → team-federation-page-6YYIMJG3.js} +1 -1
  243. package/dist/dashboard-web/chunks/{v3-page-GYWTRGO2.js → v3-page-ZGKBSBK3.js} +1 -1
  244. package/dist/dashboard-web/chunks/{whiteboards-page-MSDAG6P7.js → whiteboards-page-AACJF6DB.js} +1 -1
  245. package/dist/dashboard-web/style.css +1952 -377
  246. package/dist/dashboard.js +316 -47
  247. package/dist/dashboard.js.map +1 -1
  248. package/dist/desktop/main/ipc.js +1 -1
  249. package/dist/desktop/main/runtime-service.js +2 -2
  250. package/dist/desktop/main/runtime-service.js.map +1 -1
  251. package/dist/desktop/shared/types.d.ts +1 -1
  252. package/dist/i18n/en.d.ts.map +1 -1
  253. package/dist/i18n/en.js +5 -1
  254. package/dist/i18n/en.js.map +1 -1
  255. package/dist/i18n/zh.d.ts.map +1 -1
  256. package/dist/i18n/zh.js +5 -1
  257. package/dist/i18n/zh.js.map +1 -1
  258. package/dist/index-daemon.js +6 -1
  259. package/dist/index-daemon.js.map +1 -1
  260. package/dist/services/adopt-input-sequence.d.ts +52 -0
  261. package/dist/services/adopt-input-sequence.d.ts.map +1 -0
  262. package/dist/services/adopt-input-sequence.js +50 -0
  263. package/dist/services/adopt-input-sequence.js.map +1 -0
  264. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  265. package/dist/services/bridge-fallback-gate.js +34 -11
  266. package/dist/services/bridge-fallback-gate.js.map +1 -1
  267. package/dist/services/codex-bridge-queue.d.ts +103 -7
  268. package/dist/services/codex-bridge-queue.d.ts.map +1 -1
  269. package/dist/services/codex-bridge-queue.js +291 -17
  270. package/dist/services/codex-bridge-queue.js.map +1 -1
  271. package/dist/services/codex-transcript.d.ts +4 -3
  272. package/dist/services/codex-transcript.d.ts.map +1 -1
  273. package/dist/services/codex-transcript.js.map +1 -1
  274. package/dist/services/connector-store.d.ts +14 -1
  275. package/dist/services/connector-store.d.ts.map +1 -1
  276. package/dist/services/connector-store.js.map +1 -1
  277. package/dist/services/connector-topic-template.d.ts +7 -0
  278. package/dist/services/connector-topic-template.d.ts.map +1 -0
  279. package/dist/services/connector-topic-template.js +210 -0
  280. package/dist/services/connector-topic-template.js.map +1 -0
  281. package/dist/services/project-scanner.d.ts +33 -0
  282. package/dist/services/project-scanner.d.ts.map +1 -1
  283. package/dist/services/project-scanner.js +40 -1
  284. package/dist/services/project-scanner.js.map +1 -1
  285. package/dist/services/skill-pack-store.d.ts +50 -0
  286. package/dist/services/skill-pack-store.d.ts.map +1 -0
  287. package/dist/services/skill-pack-store.js +270 -0
  288. package/dist/services/skill-pack-store.js.map +1 -0
  289. package/dist/services/skill-registry-store.d.ts +8 -0
  290. package/dist/services/skill-registry-store.d.ts.map +1 -1
  291. package/dist/services/skill-registry-store.js +100 -68
  292. package/dist/services/skill-registry-store.js.map +1 -1
  293. package/dist/services/structured-bridge-clis.d.ts +8 -1
  294. package/dist/services/structured-bridge-clis.d.ts.map +1 -1
  295. package/dist/services/structured-bridge-clis.js +13 -0
  296. package/dist/services/structured-bridge-clis.js.map +1 -1
  297. package/dist/services/submit-confirmation.d.ts +50 -0
  298. package/dist/services/submit-confirmation.d.ts.map +1 -1
  299. package/dist/services/submit-confirmation.js +82 -0
  300. package/dist/services/submit-confirmation.js.map +1 -1
  301. package/dist/services/todo-state.d.ts +74 -0
  302. package/dist/services/todo-state.d.ts.map +1 -0
  303. package/dist/services/todo-state.js +351 -0
  304. package/dist/services/todo-state.js.map +1 -0
  305. package/dist/setup/agent-preset.d.ts.map +1 -1
  306. package/dist/setup/agent-preset.js +2 -0
  307. package/dist/setup/agent-preset.js.map +1 -1
  308. package/dist/setup/owner-identity.d.ts +47 -0
  309. package/dist/setup/owner-identity.d.ts.map +1 -0
  310. package/dist/setup/owner-identity.js +196 -0
  311. package/dist/setup/owner-identity.js.map +1 -0
  312. package/dist/setup/register-app.d.ts +4 -3
  313. package/dist/setup/register-app.d.ts.map +1 -1
  314. package/dist/setup/register-app.js.map +1 -1
  315. package/dist/setup/setup-args.d.ts +1 -1
  316. package/dist/setup/setup-args.d.ts.map +1 -1
  317. package/dist/setup/setup-args.js +7 -3
  318. package/dist/setup/setup-args.js.map +1 -1
  319. package/dist/types.d.ts +11 -0
  320. package/dist/types.d.ts.map +1 -1
  321. package/dist/utils/async-serial-queue.d.ts +9 -0
  322. package/dist/utils/async-serial-queue.d.ts.map +1 -0
  323. package/dist/utils/async-serial-queue.js +13 -0
  324. package/dist/utils/async-serial-queue.js.map +1 -0
  325. package/dist/utils/child-env.d.ts +25 -0
  326. package/dist/utils/child-env.d.ts.map +1 -1
  327. package/dist/utils/child-env.js +47 -0
  328. package/dist/utils/child-env.js.map +1 -1
  329. package/dist/utils/runtime-screen-status.d.ts +52 -0
  330. package/dist/utils/runtime-screen-status.d.ts.map +1 -0
  331. package/dist/utils/runtime-screen-status.js +60 -0
  332. package/dist/utils/runtime-screen-status.js.map +1 -0
  333. package/dist/worker.js +1697 -468
  334. package/dist/worker.js.map +1 -1
  335. package/dist/workflows/definition.d.ts +44 -44
  336. package/package.json +1 -1
  337. package/dist/dashboard-web/chunks/chunk-6J5LS5AU.js +0 -51
  338. package/dist/dashboard-web/chunks/connectors-page-EELM66G3.js +0 -1
  339. package/dist/dashboard-web/chunks/groups-page-WKUV6E42.js +0 -8
  340. package/dist/dashboard-web/chunks/roles-page-M5GIASJU.js +0 -1
  341. package/dist/dashboard-web/chunks/schedules-page-O232WQRR.js +0 -1
  342. package/dist/dashboard-web/chunks/sessions-page-YFRPSTIL.js +0 -6
  343. package/dist/dashboard-web/chunks/skills-page-EFZQPWV4.js +0 -4
package/dist/dashboard.js CHANGED
@@ -11,7 +11,7 @@ import { logger } from './utils/logger.js';
11
11
  import { gracefulProcessExitCode } from './pm2-graceful-exit.js';
12
12
  import { config, isWildcardBindHost } from './config.js';
13
13
  import { listenWithProbe } from './utils/listen-with-probe.js';
14
- import { generateToken, parseCookie, buildSetCookie, verifyHmac, cliAuthBind, decideDashboardAuth, loadPersistedToken, loadOrCreatePersistedToken, persistToken, loadDashboardSecret, loadOrCreateDashboardSecret, } from './dashboard/auth.js';
14
+ import { parseCookie, buildSetCookie, verifyHmac, cliAuthBind, decideDashboardAuth, loadPersistedToken, loadOrCreatePersistedToken, rotatePersistedToken, loadDashboardSecret, loadOrCreateDashboardSecret, } from './dashboard/auth.js';
15
15
  import { DaemonRegistry, botsRosterSignature } from './dashboard/registry.js';
16
16
  import { Aggregator, subscribeDaemon } from './dashboard/aggregator.js';
17
17
  import { createSessionPresentationCoordinator } from './dashboard/session-presentation.js';
@@ -62,14 +62,17 @@ import { listTeamReports, readTeamBoard, setTeamBoardEntry } from './services/te
62
62
  import { createCliAdapterSync } from './adapters/cli/registry.js';
63
63
  import { hd2dAssetPath, hd2dStatus, startHd2dDownload } from './dashboard/hd2d-assets.js';
64
64
  import { buildSkillInstallAuditSummary, installLocalSkillLinks, readSkillRegistry, removeInstalledSkill, removeInstalledSkills, updateInstalledSkillAsync, } from './services/skill-registry-store.js';
65
+ import { readSkillPackRegistry } from './services/skill-pack-store.js';
66
+ import { cloneSkillPack, createSkillPack, deleteSkillPack, getSkillPack, listSkillPacks, updateSkillPack, SkillPackStoreError, } from './services/skill-pack-store.js';
65
67
  import { redactGitUrlCredentials } from './core/skills/sources.js';
68
+ import { enrichPackForDashboard, enrichPacksForDashboard, sanitizeSkillForDashboard, } from './dashboard/skill-pack-response.js';
66
69
  import { effectiveDefaultWorkingDir, getBot, loadBotConfigs, parseBotConfigsFromText } from './bot-registry.js';
67
70
  import { addChatToFeedGroup, createFeedGroup, FEED_GROUP_SCOPES, FeedGroupApiError, listFeedGroups } from './dashboard/feed-groups.js';
68
71
  import { generateAuthUrl, handleCallbackUrl, isCallbackUrl } from './utils/user-token.js';
69
72
  import { findEntryIndex, readRawConfig, requireConfigPath, writeRawConfigAtomic } from './services/config-store.js';
70
73
  import { emitCodexNotifierOutboxItem, installCodexNotifierHook, isCodexNotifierWorkerStateFresh, isCodexNotifierHookInstalled, listCodexNotifierOutbox, readCodexNotifierWorkerState, resolveCodexNotifierConfig, runCodexSideConversationMonitor, runCodexNotifierWorkerSupervisor, } from './features/codex-notifier/index.js';
71
74
  import { discoverNativeCliSkillGroups } from './core/skills/discovery.js';
72
- import { analyzeSkillReferences } from './core/skills/references.js';
75
+ import { analyzeSkillReferences, packsContainingSkill } from './core/skills/references.js';
73
76
  import { discoverDashboardSkills, installDashboardSkill, parseDashboardSkillInstallRequest, parseInstallLocalLinksSources, MAX_LOCAL_LINK_SOURCES } from './dashboard/skill-install-request.js';
74
77
  import { botDefaultsPayload, botSummaryPayload, brandMapByAppId } from './dashboard/bot-payload.js';
75
78
  import { handleVcMeetingConsumerProfilesGet, handleVcMeetingConsumerProfilesPut, } from './dashboard/vc-consumer-profiles-api.js';
@@ -104,6 +107,15 @@ import { resolveEffectivePluginIds, updateBotPluginOverride } from './core/plugi
104
107
  import { assertPluginBindingTransition, describePluginDependencyError } from './core/plugins/dependencies.js';
105
108
  import { inspectGatewayEntry } from './core/plugins/mcp/gateway-installer.js';
106
109
  import { fetchDaemonIpc } from './core/daemon-ipc-auth.js';
110
+ import { buildDashboardSummary, parseDashboardSummaryRows, } from './dashboard/dashboard-summary.js';
111
+ import { createDashboardSummaryEndpoint } from './dashboard/dashboard-summary-endpoint.js';
112
+ import { scrubWorkflowWorkerEnv } from './utils/child-env.js';
113
+ // The dashboard is an independent long-lived PM2 app and can be resurrected
114
+ // from a stale dump.pm2 without passing through cli.ts pm2Env(). Its start/stop
115
+ // and detached-restart children inherit process.env, so a leaked workflow
116
+ // marker would make those CLI commands fail at the workflow safety gate before
117
+ // they can reach their own cleanup boundary.
118
+ scrubWorkflowWorkerEnv(process.env);
107
119
  const SECRET_PATH = dashboardSecretPath();
108
120
  const TOKEN_PATH = join(homedir(), '.botmux', '.dashboard-token');
109
121
  /** Per-daemon budget for the cross-daemon insight overview fan-out — bounds
@@ -113,7 +125,8 @@ const BOTS_JSON_PATH = join(homedir(), '.botmux', 'bots.json');
113
125
  const REGISTRY_DIR = join(resolveBotmuxDataDir(), 'dashboard-daemons');
114
126
  // The dashboard probes upward if its configured port is busy (e.g. a second
115
127
  // botmux instance on this host). The actually-bound port is persisted here so
116
- // the `botmux dashboard` CLI can reach /__cli/rotate without guessing.
128
+ // the `botmux dashboard` CLI can reach /__cli/current, /__cli/ensure, and
129
+ // /__cli/rotate without guessing.
117
130
  const PORT_PATH = join(homedir(), '.botmux', '.dashboard-port');
118
131
  function loadOrCreateSecret() {
119
132
  let existing;
@@ -137,15 +150,21 @@ function loadOrCreateSecret() {
137
150
  process.exit(1);
138
151
  }
139
152
  }
140
- // The active dashboard token is persisted to disk so a previously-issued
141
- // dashboard URL survives `botmux restart`. A platform-bound dashboard creates
142
- // the first token on startup; only `botmux dashboard` (the /__cli/rotate
143
- // endpoint) replaces it and thereby invalidates the old link.
144
- // The start/restart hint reads it via the non-rotating /__cli/current endpoint
145
- // so it can show the live link without invalidating it.
146
- let activeToken = loadPersistedToken(TOKEN_PATH);
153
+ // The persisted file is the active-token authority. Reading it at each use
154
+ // keeps multiple dashboard processes coherent: first creation converges under
155
+ // a file lock, and an explicit rotation is observed by every process without a
156
+ // restart. `/__cli/current` remains a strictly read-only probe.
157
+ function currentDashboardToken() {
158
+ try {
159
+ return loadPersistedToken(TOKEN_PATH);
160
+ }
161
+ catch (error) {
162
+ logger.warn(`[dashboard] Failed to read token from ${TOKEN_PATH}: ${error.message}`);
163
+ return null;
164
+ }
165
+ }
147
166
  // The port we actually bound (may differ from config.dashboard.port after an
148
- // EADDRINUSE probe). Used for the rotation-URL and persisted for the CLI.
167
+ // EADDRINUSE probe). Used for token-bearing URLs and persisted for the CLI.
149
168
  let boundDashboardPort = config.dashboard.port;
150
169
  const SECRET = loadOrCreateSecret();
151
170
  function tcpPortAvailable(host, port) {
@@ -220,7 +239,7 @@ aggregator.on(sessionPresentation.onEvent);
220
239
  // 调试终端(owner-only 裸 bash)。默认工作目录取当前所有 session 的工作目录去重,
221
240
  // 让 owner 从熟悉的目录起终端复现问题;都没有时模块内退回 homedir。
222
241
  const debugTerminalManager = createDebugTerminalManager({
223
- getActiveToken: () => activeToken,
242
+ getActiveToken: currentDashboardToken,
224
243
  defaultWorkingDirs: () => {
225
244
  const dirs = new Set();
226
245
  for (const s of aggregator.getSessions()) {
@@ -1032,9 +1051,9 @@ const groupsActionDeps = {
1032
1051
  // ─── PR2 C8: Route B internal API (`/__daemon/*`) ───────────────────────────
1033
1052
  // HMAC + loopback + ts ±60s + nonce TTL, signed-request envelope = full
1034
1053
  // (ts, nonce, method, pathWithQuery, sha256(body)). Reuses `.dashboard-secret`
1035
- // for the HMAC key — the same secret `/__cli/rotate` already uses — but the
1036
- // signing material is wider so a `/__cli/rotate` signature cannot be replayed
1037
- // here and vice versa (different protocols, same secret, no cross-replay).
1054
+ // for the HMAC key — the same secret the `/__cli/*` protocol uses — but the
1055
+ // signing material is wider so a CLI signature cannot be replayed here and
1056
+ // vice versa (different protocols, same secret, no cross-replay).
1038
1057
  //
1039
1058
  // SECRET fail-closed: `loadOrCreateSecret()` returns a 32-byte base64url
1040
1059
  // string and never empty; we still guard below at server-startup time.
@@ -1751,7 +1770,7 @@ async function handlePluginManagementApi(req, res, url) {
1751
1770
  return false;
1752
1771
  }
1753
1772
  // ─── HTTP routing ────────────────────────────────────────────────────────────
1754
- function authedToken(req, url) {
1773
+ function authedToken(req, url, activeToken) {
1755
1774
  const q = url.searchParams.get('t');
1756
1775
  if (q && q === activeToken)
1757
1776
  return q;
@@ -2294,16 +2313,13 @@ function startSkillJob(type, run) {
2294
2313
  })());
2295
2314
  return job;
2296
2315
  }
2297
- function sanitizeSkillForDashboard(skill) {
2298
- if (skill.source.type !== 'git')
2299
- return skill;
2300
- return {
2301
- ...skill,
2302
- source: { ...skill.source, url: redactGitUrlCredentials(skill.source.url) },
2303
- };
2304
- }
2305
2316
  function dashboardSkillCliIds() {
2306
2317
  const ids = new Set();
2318
+ // Always scan all known CLI skill dirs, not just configured bots — users may
2319
+ // want to discover codex/trae/... skills even before creating a bot for them.
2320
+ const allCliIds = ['claude-code', 'seed', 'relay', 'aiden', 'coco', 'codex', 'codex-app', 'cursor', 'gemini', 'genius', 'opencode', 'antigravity', 'mtr', 'hermes', 'mira', 'mir', 'traex', 'pi', 'copilot', 'oh-my-pi', 'kimi', 'grok', 'kiro-cli', 'riff'];
2321
+ for (const cliId of allCliIds)
2322
+ ids.add(cliId);
2307
2323
  try {
2308
2324
  for (const cliId of configuredCliIds().values())
2309
2325
  ids.add(cliId);
@@ -2333,6 +2349,76 @@ function dashboardSkillsPayload() {
2333
2349
  delivery: globalSkills.delivery ?? 'auto',
2334
2350
  };
2335
2351
  }
2352
+ // --- Skill pack dashboard helpers ------------------------------------------
2353
+ function loadBotConfigsSafe() {
2354
+ try {
2355
+ return loadBotConfigs();
2356
+ }
2357
+ catch {
2358
+ return [];
2359
+ }
2360
+ }
2361
+ function botsReferencingPack(packId, bots) {
2362
+ const selector = `pack:${packId}`;
2363
+ return bots
2364
+ .filter((bot) => Array.isArray(bot.skills?.include) && bot.skills.include.includes(selector))
2365
+ .map((bot) => ({ larkAppId: bot.larkAppId, botName: bot.name ?? bot.larkAppId }))
2366
+ .sort((a, b) => a.botName.localeCompare(b.botName));
2367
+ }
2368
+ function parsePackInput(body) {
2369
+ if (!body || typeof body !== 'object' || Array.isArray(body))
2370
+ throw new SkillPackStoreError({ code: 'SKILL_PACK_INVALID', reason: 'body must be an object' });
2371
+ const b = body;
2372
+ return {
2373
+ id: typeof b.id === 'string' ? b.id : '',
2374
+ name: typeof b.name === 'string' ? b.name : '',
2375
+ description: typeof b.description === 'string' ? b.description : undefined,
2376
+ tags: Array.isArray(b.tags) ? b.tags : undefined,
2377
+ include: Array.isArray(b.include) ? b.include : [],
2378
+ };
2379
+ }
2380
+ function parsePackUpdate(body) {
2381
+ if (!body || typeof body !== 'object' || Array.isArray(body))
2382
+ throw new SkillPackStoreError({ code: 'SKILL_PACK_INVALID', reason: 'body must be an object' });
2383
+ const b = body;
2384
+ return {
2385
+ name: typeof b.name === 'string' ? b.name : undefined,
2386
+ description: b.description === null ? null : typeof b.description === 'string' ? b.description : undefined,
2387
+ tags: b.tags === null ? null : Array.isArray(b.tags) ? b.tags : undefined,
2388
+ include: Array.isArray(b.include) ? b.include : undefined,
2389
+ expectedRevision: typeof b.expectedRevision === 'number' ? b.expectedRevision : undefined,
2390
+ };
2391
+ }
2392
+ function packErrorStatus(err) {
2393
+ if (err instanceof SkillPackStoreError) {
2394
+ switch (err.detail.code) {
2395
+ case 'SKILL_PACK_NOT_FOUND': return 404;
2396
+ case 'SKILL_PACK_ID_CONFLICT': return 409;
2397
+ case 'SKILL_PACK_REVISION_CONFLICT': return 409;
2398
+ case 'SKILL_PACK_IN_USE': return 409;
2399
+ default: return 400;
2400
+ }
2401
+ }
2402
+ return 400;
2403
+ }
2404
+ function packErrorBody(err) {
2405
+ if (err instanceof SkillPackStoreError) {
2406
+ const d = err.detail;
2407
+ const body = { ok: false, error: d.code };
2408
+ if (d.code === 'SKILL_PACK_REVISION_CONFLICT')
2409
+ body.current = d.current;
2410
+ if (d.code === 'SKILL_PACK_INVALID')
2411
+ body.reason = d.reason;
2412
+ if (d.code === 'SKILL_PACK_INVALID_SELECTOR')
2413
+ body.selector = d.selector;
2414
+ return body;
2415
+ }
2416
+ return {
2417
+ ok: false,
2418
+ error: 'internal_error',
2419
+ detail: redactGitUrlCredentials(err instanceof Error ? err.message : String(err)),
2420
+ };
2421
+ }
2336
2422
  function mergeSkillReferenceBot(refs, ref) {
2337
2423
  const current = refs.get(ref.larkAppId);
2338
2424
  if (!current) {
@@ -2344,11 +2430,18 @@ function mergeSkillReferenceBot(refs, ref) {
2344
2430
  async function dashboardSkillReferencesMany(skillNames) {
2345
2431
  const uniqueNames = [...new Set(skillNames)];
2346
2432
  const refsBySkill = new Map(uniqueNames.map(name => [name, new Map()]));
2433
+ let packs;
2434
+ try {
2435
+ packs = readSkillPackRegistry().packs;
2436
+ }
2437
+ catch {
2438
+ // packs.json may be absent; fall back to direct-only analysis.
2439
+ }
2347
2440
  try {
2348
2441
  const configuredBots = loadBotConfigs();
2349
2442
  for (const name of uniqueNames) {
2350
2443
  const refs = refsBySkill.get(name);
2351
- for (const ref of analyzeSkillReferences(name, { bots: configuredBots }).bots)
2444
+ for (const ref of analyzeSkillReferences(name, { bots: configuredBots, packs }).bots)
2352
2445
  mergeSkillReferenceBot(refs, ref);
2353
2446
  }
2354
2447
  }
@@ -2374,15 +2467,16 @@ async function dashboardSkillReferencesMany(skillNames) {
2374
2467
  const availableOnlineConfigs = onlineConfigs.filter(config => config !== null);
2375
2468
  for (const name of uniqueNames) {
2376
2469
  const refs = refsBySkill.get(name);
2377
- for (const ref of analyzeSkillReferences(name, { bots: availableOnlineConfigs }).bots)
2470
+ for (const ref of analyzeSkillReferences(name, { bots: availableOnlineConfigs, packs }).bots)
2378
2471
  mergeSkillReferenceBot(refs, ref);
2379
2472
  }
2380
2473
  return new Map([...refsBySkill].map(([name, refs]) => [name, {
2381
2474
  bots: [...refs.values()].sort((a, b) => a.botName.localeCompare(b.botName)),
2475
+ packs: packsContainingSkill(name, packs),
2382
2476
  }]));
2383
2477
  }
2384
2478
  async function dashboardSkillReferences(skillName) {
2385
- return (await dashboardSkillReferencesMany([skillName])).get(skillName) ?? { bots: [] };
2479
+ return (await dashboardSkillReferencesMany([skillName])).get(skillName) ?? { bots: [], packs: [] };
2386
2480
  }
2387
2481
  /** Extract the sessionId from a terminal path `/s/<sessionId>[/...]`. Returns
2388
2482
  * the first path segment after `/s/` (stops at the next `/`; query/hash are
@@ -2393,6 +2487,52 @@ function parseTerminalSessionId(pathname) {
2393
2487
  const seg = pathname.slice(3).split('/')[0];
2394
2488
  return seg || undefined;
2395
2489
  }
2490
+ /**
2491
+ * Read every currently-online daemon directly for the public dashboard
2492
+ * summary. The regular aggregator intentionally retains offline
2493
+ * rows for operator history, so using it here would make an offline bot's old
2494
+ * sessions or schedules look live. A failed or malformed daemon snapshot
2495
+ * rejects the whole projection instead of silently turning missing data into
2496
+ * zeroes.
2497
+ */
2498
+ async function liveDashboardSummary() {
2499
+ const daemons = registry.list();
2500
+ const configuredBots = loadBotConfigs();
2501
+ const snapshots = await Promise.all(daemons.map(async (daemon) => {
2502
+ const [sessionsResponse, schedulesResponse] = await Promise.all([
2503
+ fetchDaemonIpc(daemon.ipcPort, '/api/sessions', {
2504
+ signal: AbortSignal.timeout(2_000),
2505
+ }),
2506
+ fetchDaemonIpc(daemon.ipcPort, '/api/schedules', {
2507
+ signal: AbortSignal.timeout(2_000),
2508
+ }),
2509
+ ]);
2510
+ if (!sessionsResponse.ok || !schedulesResponse.ok) {
2511
+ throw new Error('daemon_snapshot_http_error');
2512
+ }
2513
+ const [sessionsBody, schedulesBody] = await Promise.all([
2514
+ sessionsResponse.json(),
2515
+ schedulesResponse.json(),
2516
+ ]);
2517
+ return parseDashboardSummaryRows({
2518
+ sessions: sessionsBody.sessions,
2519
+ schedules: schedulesBody.schedules,
2520
+ });
2521
+ }));
2522
+ return buildDashboardSummary({
2523
+ generatedAt: new Date(),
2524
+ configuredBotAppIds: configuredBots.map(bot => bot.larkAppId),
2525
+ onlineBotAppIds: daemons.map(daemon => daemon.larkAppId),
2526
+ sessions: snapshots.flatMap(snapshot => snapshot.sessions),
2527
+ schedules: snapshots.flatMap(snapshot => snapshot.schedules),
2528
+ });
2529
+ }
2530
+ const dashboardSummaryEndpoint = createDashboardSummaryEndpoint({
2531
+ load: liveDashboardSummary,
2532
+ onError: error => {
2533
+ logger.warn(`[dashboard-summary] live snapshot unavailable: ${error instanceof Error ? error.message : String(error)}`);
2534
+ },
2535
+ });
2396
2536
  const server = createServer(async (req, res) => {
2397
2537
  try {
2398
2538
  const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
@@ -2411,7 +2551,8 @@ const server = createServer(async (req, res) => {
2411
2551
  // outside the browser auth gate so packaged desktop apps can decide whether
2412
2552
  // this runtime speaks their dashboard protocol before loading the SPA.
2413
2553
  if (req.method === 'GET' && url.pathname === '/__desktop/compat') {
2414
- const presentedToken = authedToken(req, url);
2554
+ const activeToken = currentDashboardToken();
2555
+ const presentedToken = authedToken(req, url, activeToken);
2415
2556
  const boundMachineId = activeToken && presentedToken === activeToken
2416
2557
  ? readPlatformBinding()?.machineId
2417
2558
  : null;
@@ -2473,32 +2614,53 @@ const server = createServer(async (req, res) => {
2473
2614
  if (await daemonInternalApi.handle(req, res, url)) {
2474
2615
  return;
2475
2616
  }
2476
- // CLI rotate (HMAC + loopback only) — for `botmux dashboard`. Mints a fresh
2477
- // token, invalidating any previously-issued link.
2617
+ // CLI rotate (HMAC + loopback only) — for `botmux dashboard rotate`.
2618
+ // Publish the new token only after a durable write succeeds.
2478
2619
  if (req.method === 'POST' && url.pathname === '/__cli/rotate') {
2479
2620
  const gate = verifyCliRequest(req, url.pathname);
2480
2621
  if (!gate.ok)
2481
2622
  return jsonRes(res, gate.status, gate.body);
2482
- activeToken = generateToken();
2483
2623
  try {
2484
- persistToken(TOKEN_PATH, activeToken);
2624
+ const token = rotatePersistedToken(TOKEN_PATH);
2625
+ return jsonRes(res, 200, dashboardUrlsFor(token));
2485
2626
  }
2486
2627
  catch (e) {
2487
2628
  logger.warn(`[dashboard] Failed to persist token to ${TOKEN_PATH}: ${e.message}`);
2629
+ return jsonRes(res, 500, { error: 'token_persist_failed' });
2488
2630
  }
2489
- return jsonRes(res, 200, dashboardUrlsFor(activeToken));
2490
2631
  }
2491
- // CLI read current URL (HMAC + loopback only) for the start/restart hint.
2492
- // Unlike /__cli/rotate this does NOT mint a token, so an already-issued
2493
- // dashboard link survives restart untouched. 404 no token has ever been
2494
- // minted (caller falls back to suggesting `botmux dashboard`).
2632
+ // CLI get-or-create URL (HMAC + loopback only). Existing links survive
2633
+ // untouched; the first caller atomically creates and persists a token.
2634
+ if (req.method === 'POST' && url.pathname === '/__cli/ensure') {
2635
+ const gate = verifyCliRequest(req, url.pathname);
2636
+ if (!gate.ok)
2637
+ return jsonRes(res, gate.status, gate.body);
2638
+ try {
2639
+ const token = loadOrCreatePersistedToken(TOKEN_PATH);
2640
+ return jsonRes(res, 200, dashboardUrlsFor(token));
2641
+ }
2642
+ catch (e) {
2643
+ logger.warn(`[dashboard] Failed to ensure token at ${TOKEN_PATH}: ${e.message}`);
2644
+ return jsonRes(res, 500, { error: 'token_persist_failed' });
2645
+ }
2646
+ }
2647
+ // CLI read current URL (HMAC + loopback only) — for start/restart hints and
2648
+ // safe port discovery. This never mints a token.
2495
2649
  if (req.method === 'POST' && url.pathname === '/__cli/current') {
2496
2650
  const gate = verifyCliRequest(req, url.pathname);
2497
2651
  if (!gate.ok)
2498
2652
  return jsonRes(res, gate.status, gate.body);
2499
- if (!activeToken)
2653
+ let token;
2654
+ try {
2655
+ token = loadPersistedToken(TOKEN_PATH);
2656
+ }
2657
+ catch (e) {
2658
+ logger.warn(`[dashboard] Failed to read token from ${TOKEN_PATH}: ${e.message}`);
2659
+ return jsonRes(res, 500, { error: 'token_unavailable' });
2660
+ }
2661
+ if (!token)
2500
2662
  return jsonRes(res, 404, { error: 'no_active_token' });
2501
- return jsonRes(res, 200, dashboardUrlsFor(activeToken));
2663
+ return jsonRes(res, 200, dashboardUrlsFor(token));
2502
2664
  }
2503
2665
  // CLI 通知绑定变化(HMAC + loopback)——`botmux bind` 写完绑定后捅一下,立即重连平台,
2504
2666
  // 无需重启 daemon,也不依赖 fs.watch。
@@ -2521,7 +2683,8 @@ const server = createServer(async (req, res) => {
2521
2683
  startPlatformTunnelIfBound();
2522
2684
  return jsonRes(res, 200, { ok: true });
2523
2685
  }
2524
- const presentedToken = authedToken(req, url);
2686
+ const activeToken = currentDashboardToken();
2687
+ const presentedToken = authedToken(req, url, activeToken);
2525
2688
  const globalDashboardConfig = readGlobalConfig().dashboard;
2526
2689
  const decision = decideDashboardAuth({
2527
2690
  method: req.method ?? 'GET',
@@ -2659,6 +2822,12 @@ const server = createServer(async (req, res) => {
2659
2822
  return jsonRes(res, 200, startHd2dDownload());
2660
2823
  }
2661
2824
  // ─── Public API (cookie/token already validated above) ──────────────────
2825
+ if (req.method === 'GET' && url.pathname === '/api/dashboard/v1/summary') {
2826
+ const result = await dashboardSummaryEndpoint.get({ authenticated: authed });
2827
+ for (const [name, value] of Object.entries(result.headers))
2828
+ res.setHeader(name, value);
2829
+ return jsonRes(res, result.status, result.body);
2830
+ }
2662
2831
  if (await handleResourceMonitorApi(req, res, url, resourceMonitor)) {
2663
2832
  return;
2664
2833
  }
@@ -3256,10 +3425,14 @@ const server = createServer(async (req, res) => {
3256
3425
  if (missing.length > 0)
3257
3426
  return jsonRes(res, 400, { ok: false, error: 'skill_not_installed', missing });
3258
3427
  const referencesBySkill = await dashboardSkillReferencesMany(names);
3259
- const references = names.map(name => ({ name, refs: referencesBySkill.get(name) ?? { bots: [] } }));
3428
+ const references = names.map(name => ({ name, refs: referencesBySkill.get(name) ?? { bots: [], packs: [] } }));
3260
3429
  const affectedSkills = references
3261
- .filter(item => item.refs.bots.length > 0)
3262
- .map(item => ({ name: item.name, affectedBots: item.refs.bots }));
3430
+ .filter(item => item.refs.bots.length > 0 || item.refs.packs.length > 0)
3431
+ .map(item => ({
3432
+ name: item.name,
3433
+ affectedBots: item.refs.bots,
3434
+ affectedPacks: item.refs.packs,
3435
+ }));
3263
3436
  if (body.force !== true && affectedSkills.length > 0) {
3264
3437
  return jsonRes(res, 409, {
3265
3438
  ok: false,
@@ -3390,11 +3563,12 @@ const server = createServer(async (req, res) => {
3390
3563
  if (!readSkillRegistry().skills[name])
3391
3564
  return jsonRes(res, 400, { ok: false, error: 'skill_not_installed' });
3392
3565
  const refs = await dashboardSkillReferences(name);
3393
- if (!force && refs.bots.length > 0) {
3566
+ if (!force && (refs.bots.length > 0 || refs.packs.length > 0)) {
3394
3567
  return jsonRes(res, 409, {
3395
3568
  ok: false,
3396
3569
  error: 'skill_in_use',
3397
3570
  affectedBots: refs.bots,
3571
+ affectedPacks: refs.packs,
3398
3572
  });
3399
3573
  }
3400
3574
  const r = removeInstalledSkill(name);
@@ -3403,9 +3577,103 @@ const server = createServer(async (req, res) => {
3403
3577
  return jsonRes(res, 200, {
3404
3578
  ok: true,
3405
3579
  affectedBots: refs.bots,
3580
+ affectedPacks: refs.packs,
3406
3581
  ...dashboardSkillsPayload(),
3407
3582
  });
3408
3583
  }
3584
+ // --- Skill pack CRUD ---------------------------------------------------
3585
+ if (req.method === 'GET' && url.pathname === '/api/skill-packs') {
3586
+ const registrySkills = readSkillRegistry().skills;
3587
+ const bots = loadBotConfigsSafe();
3588
+ const packs = enrichPacksForDashboard(listSkillPacks(), registrySkills, (packId) => botsReferencingPack(packId, bots));
3589
+ return jsonRes(res, 200, { ok: true, packs });
3590
+ }
3591
+ if (req.method === 'POST' && url.pathname === '/api/skill-packs') {
3592
+ let body;
3593
+ try {
3594
+ body = await readJsonBody(req);
3595
+ }
3596
+ catch {
3597
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3598
+ }
3599
+ try {
3600
+ const input = parsePackInput(body);
3601
+ const pack = createSkillPack(input);
3602
+ return jsonRes(res, 201, { ok: true, pack });
3603
+ }
3604
+ catch (err) {
3605
+ return jsonRes(res, packErrorStatus(err), packErrorBody(err));
3606
+ }
3607
+ }
3608
+ let mPack;
3609
+ if (req.method === 'GET' && (mPack = url.pathname.match(/^\/api\/skill-packs\/([^/]+)$/))) {
3610
+ const id = decodeURIComponent(mPack[1]);
3611
+ const pack = getSkillPack(id);
3612
+ if (!pack)
3613
+ return jsonRes(res, 404, { ok: false, error: 'SKILL_PACK_NOT_FOUND' });
3614
+ const registrySkills = readSkillRegistry().skills;
3615
+ const bots = loadBotConfigsSafe();
3616
+ return jsonRes(res, 200, {
3617
+ ok: true,
3618
+ pack: enrichPackForDashboard(pack, registrySkills, botsReferencingPack(pack.id, bots)),
3619
+ });
3620
+ }
3621
+ if (req.method === 'PUT' && (mPack = url.pathname.match(/^\/api\/skill-packs\/([^/]+)$/))) {
3622
+ const id = decodeURIComponent(mPack[1]);
3623
+ let body;
3624
+ try {
3625
+ body = await readJsonBody(req);
3626
+ }
3627
+ catch {
3628
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3629
+ }
3630
+ try {
3631
+ const input = parsePackUpdate(body);
3632
+ const pack = updateSkillPack(id, input);
3633
+ return jsonRes(res, 200, { ok: true, pack });
3634
+ }
3635
+ catch (err) {
3636
+ return jsonRes(res, packErrorStatus(err), packErrorBody(err));
3637
+ }
3638
+ }
3639
+ if (req.method === 'DELETE' && (mPack = url.pathname.match(/^\/api\/skill-packs\/([^/]+)$/))) {
3640
+ const id = decodeURIComponent(mPack[1]);
3641
+ const force = url.searchParams.get('force') === '1';
3642
+ const pack = getSkillPack(id);
3643
+ if (!pack)
3644
+ return jsonRes(res, 404, { ok: false, error: 'SKILL_PACK_NOT_FOUND' });
3645
+ const refs = botsReferencingPack(id, loadBotConfigsSafe());
3646
+ if (!force && refs.length > 0) {
3647
+ return jsonRes(res, 409, { ok: false, error: 'SKILL_PACK_IN_USE', references: refs });
3648
+ }
3649
+ try {
3650
+ deleteSkillPack(id);
3651
+ return jsonRes(res, 200, { ok: true, references: refs });
3652
+ }
3653
+ catch (err) {
3654
+ return jsonRes(res, packErrorStatus(err), packErrorBody(err));
3655
+ }
3656
+ }
3657
+ if (req.method === 'POST' && (mPack = url.pathname.match(/^\/api\/skill-packs\/([^/]+)\/clone$/))) {
3658
+ const id = decodeURIComponent(mPack[1]);
3659
+ let body;
3660
+ try {
3661
+ body = await readJsonBody(req);
3662
+ }
3663
+ catch {
3664
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3665
+ }
3666
+ const newId = typeof body?.id === 'string' ? body.id.trim() : '';
3667
+ if (!newId)
3668
+ return jsonRes(res, 400, { ok: false, error: 'id_required' });
3669
+ try {
3670
+ const pack = cloneSkillPack(id, newId);
3671
+ return jsonRes(res, 201, { ok: true, pack });
3672
+ }
3673
+ catch (err) {
3674
+ return jsonRes(res, packErrorStatus(err), packErrorBody(err));
3675
+ }
3676
+ }
3409
3677
  if (req.method === 'GET' && url.pathname === '/api/whiteboards') {
3410
3678
  return jsonRes(res, 200, { enabled: whiteboardEnabled(), whiteboards: listWhiteboards() });
3411
3679
  }
@@ -5482,15 +5750,16 @@ function startPlatformTunnelIfBound() {
5482
5750
  const binding = readPlatformBinding();
5483
5751
  if (!binding)
5484
5752
  return;
5485
- if (!activeToken) {
5486
- activeToken = loadOrCreatePersistedToken(TOKEN_PATH);
5753
+ const existingToken = currentDashboardToken();
5754
+ loadOrCreatePersistedToken(TOKEN_PATH);
5755
+ if (!existingToken) {
5487
5756
  logger.info('[platform-tunnel] 已初始化 dashboard token');
5488
5757
  }
5489
5758
  const version = readBotmuxVersion();
5490
5759
  platformTunnel = startPlatformTunnelClient({
5491
5760
  binding,
5492
5761
  getDashboardPort: () => boundDashboardPort,
5493
- getDashboardToken: () => activeToken,
5762
+ getDashboardToken: currentDashboardToken,
5494
5763
  getVersion: () => version,
5495
5764
  getBots: () => readPlatformBotsInfo(),
5496
5765
  getTeamSyncRev: () => getPlatformTeamSyncRev(config.session.dataDir),