botmux 3.14.0 → 3.16.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 (812) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/.runtime-build-id +1 -1
  4. package/dist/adapters/backend/destroy-result.d.ts +159 -0
  5. package/dist/adapters/backend/destroy-result.d.ts.map +1 -0
  6. package/dist/adapters/backend/destroy-result.js +223 -0
  7. package/dist/adapters/backend/destroy-result.js.map +1 -0
  8. package/dist/adapters/backend/herdr-backend.d.ts +4 -0
  9. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  10. package/dist/adapters/backend/herdr-backend.js +23 -1
  11. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  12. package/dist/adapters/backend/mojo-backend.d.ts +577 -0
  13. package/dist/adapters/backend/mojo-backend.d.ts.map +1 -0
  14. package/dist/adapters/backend/mojo-backend.js +2471 -0
  15. package/dist/adapters/backend/mojo-backend.js.map +1 -0
  16. package/dist/adapters/backend/mojo-budgets.d.ts +21 -0
  17. package/dist/adapters/backend/mojo-budgets.d.ts.map +1 -0
  18. package/dist/adapters/backend/mojo-budgets.js +22 -0
  19. package/dist/adapters/backend/mojo-budgets.js.map +1 -0
  20. package/dist/adapters/backend/mojo-isolated-workspace.d.ts +69 -0
  21. package/dist/adapters/backend/mojo-isolated-workspace.d.ts.map +1 -0
  22. package/dist/adapters/backend/mojo-isolated-workspace.js +213 -0
  23. package/dist/adapters/backend/mojo-isolated-workspace.js.map +1 -0
  24. package/dist/adapters/backend/mojo-process-tree.d.ts +292 -0
  25. package/dist/adapters/backend/mojo-process-tree.d.ts.map +1 -0
  26. package/dist/adapters/backend/mojo-process-tree.js +486 -0
  27. package/dist/adapters/backend/mojo-process-tree.js.map +1 -0
  28. package/dist/adapters/backend/mojo-types.d.ts +542 -0
  29. package/dist/adapters/backend/mojo-types.d.ts.map +1 -0
  30. package/dist/adapters/backend/mojo-types.js +682 -0
  31. package/dist/adapters/backend/mojo-types.js.map +1 -0
  32. package/dist/adapters/backend/reproduce-command.js +3 -3
  33. package/dist/adapters/backend/reproduce-command.js.map +1 -1
  34. package/dist/adapters/backend/riff-backend.js +1 -1
  35. package/dist/adapters/backend/riff-backend.js.map +1 -1
  36. package/dist/adapters/backend/sandbox.d.ts +44 -7
  37. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  38. package/dist/adapters/backend/sandbox.js +30 -7
  39. package/dist/adapters/backend/sandbox.js.map +1 -1
  40. package/dist/adapters/backend/session-backend-selector.d.ts +14 -1
  41. package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -1
  42. package/dist/adapters/backend/session-backend-selector.js +82 -10
  43. package/dist/adapters/backend/session-backend-selector.js.map +1 -1
  44. package/dist/adapters/backend/tmux-pipe-backend.d.ts +30 -0
  45. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  46. package/dist/adapters/backend/tmux-pipe-backend.js +60 -0
  47. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  48. package/dist/adapters/backend/types.d.ts +108 -6
  49. package/dist/adapters/backend/types.d.ts.map +1 -1
  50. package/dist/adapters/backend/types.js.map +1 -1
  51. package/dist/adapters/backend/zmx-backend.d.ts +11 -0
  52. package/dist/adapters/backend/zmx-backend.d.ts.map +1 -1
  53. package/dist/adapters/backend/zmx-backend.js +16 -1
  54. package/dist/adapters/backend/zmx-backend.js.map +1 -1
  55. package/dist/adapters/cli/codex-app.d.ts.map +1 -1
  56. package/dist/adapters/cli/codex-app.js +2 -2
  57. package/dist/adapters/cli/codex-app.js.map +1 -1
  58. package/dist/adapters/cli/codex.d.ts.map +1 -1
  59. package/dist/adapters/cli/codex.js +7 -0
  60. package/dist/adapters/cli/codex.js.map +1 -1
  61. package/dist/adapters/cli/copilot.d.ts +3 -1
  62. package/dist/adapters/cli/copilot.d.ts.map +1 -1
  63. package/dist/adapters/cli/copilot.js +23 -5
  64. package/dist/adapters/cli/copilot.js.map +1 -1
  65. package/dist/adapters/cli/cursor.d.ts.map +1 -1
  66. package/dist/adapters/cli/cursor.js +26 -4
  67. package/dist/adapters/cli/cursor.js.map +1 -1
  68. package/dist/adapters/cli/dsh.d.ts.map +1 -1
  69. package/dist/adapters/cli/dsh.js +5 -1
  70. package/dist/adapters/cli/dsh.js.map +1 -1
  71. package/dist/adapters/cli/grok.d.ts.map +1 -1
  72. package/dist/adapters/cli/grok.js +24 -5
  73. package/dist/adapters/cli/grok.js.map +1 -1
  74. package/dist/adapters/cli/kimi.d.ts.map +1 -1
  75. package/dist/adapters/cli/kimi.js +19 -1
  76. package/dist/adapters/cli/kimi.js.map +1 -1
  77. package/dist/adapters/cli/mojo.d.ts +28 -0
  78. package/dist/adapters/cli/mojo.d.ts.map +1 -0
  79. package/dist/adapters/cli/mojo.js +58 -0
  80. package/dist/adapters/cli/mojo.js.map +1 -0
  81. package/dist/adapters/cli/pi.d.ts +20 -5
  82. package/dist/adapters/cli/pi.d.ts.map +1 -1
  83. package/dist/adapters/cli/pi.js +27 -5
  84. package/dist/adapters/cli/pi.js.map +1 -1
  85. package/dist/adapters/cli/read-isolation.d.ts +251 -1
  86. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  87. package/dist/adapters/cli/read-isolation.js +254 -1
  88. package/dist/adapters/cli/read-isolation.js.map +1 -1
  89. package/dist/adapters/cli/registry.d.ts +13 -1
  90. package/dist/adapters/cli/registry.d.ts.map +1 -1
  91. package/dist/adapters/cli/registry.js +19 -1
  92. package/dist/adapters/cli/registry.js.map +1 -1
  93. package/dist/adapters/cli/runner-input.d.ts +3 -3
  94. package/dist/adapters/cli/runner-input.d.ts.map +1 -1
  95. package/dist/adapters/cli/runner-input.js +4 -3
  96. package/dist/adapters/cli/runner-input.js.map +1 -1
  97. package/dist/adapters/cli/shared-hints.d.ts +3 -1
  98. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  99. package/dist/adapters/cli/shared-hints.js +51 -30
  100. package/dist/adapters/cli/shared-hints.js.map +1 -1
  101. package/dist/adapters/cli/types.d.ts +33 -4
  102. package/dist/adapters/cli/types.d.ts.map +1 -1
  103. package/dist/bot-registry.d.ts +42 -0
  104. package/dist/bot-registry.d.ts.map +1 -1
  105. package/dist/bot-registry.js +54 -4
  106. package/dist/bot-registry.js.map +1 -1
  107. package/dist/cli/arg-utils.d.ts +5 -0
  108. package/dist/cli/arg-utils.d.ts.map +1 -1
  109. package/dist/cli/arg-utils.js +7 -0
  110. package/dist/cli/arg-utils.js.map +1 -1
  111. package/dist/cli/bots-list-output.d.ts +130 -2
  112. package/dist/cli/bots-list-output.d.ts.map +1 -1
  113. package/dist/cli/bots-list-output.js +173 -27
  114. package/dist/cli/bots-list-output.js.map +1 -1
  115. package/dist/cli/daemon-lifecycle-env.d.ts +10 -3
  116. package/dist/cli/daemon-lifecycle-env.d.ts.map +1 -1
  117. package/dist/cli/daemon-lifecycle-env.js +38 -11
  118. package/dist/cli/daemon-lifecycle-env.js.map +1 -1
  119. package/dist/cli/dashboard-command.d.ts +15 -0
  120. package/dist/cli/dashboard-command.d.ts.map +1 -1
  121. package/dist/cli/dashboard-command.js +22 -0
  122. package/dist/cli/dashboard-command.js.map +1 -1
  123. package/dist/cli/log-tail.d.ts +54 -0
  124. package/dist/cli/log-tail.d.ts.map +1 -0
  125. package/dist/cli/log-tail.js +167 -0
  126. package/dist/cli/log-tail.js.map +1 -0
  127. package/dist/cli/pm2-env.d.ts +16 -0
  128. package/dist/cli/pm2-env.d.ts.map +1 -0
  129. package/dist/cli/pm2-env.js +63 -0
  130. package/dist/cli/pm2-env.js.map +1 -0
  131. package/dist/cli/pm2-fleet-lock.d.ts +26 -0
  132. package/dist/cli/pm2-fleet-lock.d.ts.map +1 -0
  133. package/dist/cli/pm2-fleet-lock.js +50 -0
  134. package/dist/cli/pm2-fleet-lock.js.map +1 -0
  135. package/dist/cli/pm2-god-retirement.d.ts +59 -0
  136. package/dist/cli/pm2-god-retirement.d.ts.map +1 -0
  137. package/dist/cli/pm2-god-retirement.js +95 -0
  138. package/dist/cli/pm2-god-retirement.js.map +1 -0
  139. package/dist/cli/session-list-wake.d.ts +41 -0
  140. package/dist/cli/session-list-wake.d.ts.map +1 -0
  141. package/dist/cli/session-list-wake.js +102 -0
  142. package/dist/cli/session-list-wake.js.map +1 -0
  143. package/dist/cli/workflow.d.ts.map +1 -1
  144. package/dist/cli/workflow.js +26 -0
  145. package/dist/cli/workflow.js.map +1 -1
  146. package/dist/cli.d.ts.map +1 -1
  147. package/dist/cli.js +941 -118
  148. package/dist/cli.js.map +1 -1
  149. package/dist/codex-app-runner.js +261 -49
  150. package/dist/codex-app-runner.js.map +1 -1
  151. package/dist/core/cli-runtime-update.d.ts +8 -0
  152. package/dist/core/cli-runtime-update.d.ts.map +1 -1
  153. package/dist/core/cli-runtime-update.js +127 -8
  154. package/dist/core/cli-runtime-update.js.map +1 -1
  155. package/dist/core/close-residual.d.ts +64 -0
  156. package/dist/core/close-residual.d.ts.map +1 -0
  157. package/dist/core/close-residual.js +93 -0
  158. package/dist/core/close-residual.js.map +1 -0
  159. package/dist/core/closed-session-card.d.ts.map +1 -1
  160. package/dist/core/closed-session-card.js +11 -3
  161. package/dist/core/closed-session-card.js.map +1 -1
  162. package/dist/core/command-discovery.d.ts.map +1 -1
  163. package/dist/core/command-discovery.js +4 -1
  164. package/dist/core/command-discovery.js.map +1 -1
  165. package/dist/core/command-handler.d.ts.map +1 -1
  166. package/dist/core/command-handler.js +129 -27
  167. package/dist/core/command-handler.js.map +1 -1
  168. package/dist/core/cost-calculator.d.ts +3 -1
  169. package/dist/core/cost-calculator.d.ts.map +1 -1
  170. package/dist/core/cost-calculator.js +230 -1
  171. package/dist/core/cost-calculator.js.map +1 -1
  172. package/dist/core/daemon-background-close.d.ts +19 -0
  173. package/dist/core/daemon-background-close.d.ts.map +1 -0
  174. package/dist/core/daemon-background-close.js +39 -0
  175. package/dist/core/daemon-background-close.js.map +1 -0
  176. package/dist/core/dashboard-command/overview.d.ts +4 -0
  177. package/dist/core/dashboard-command/overview.d.ts.map +1 -1
  178. package/dist/core/dashboard-command/overview.js +8 -1
  179. package/dist/core/dashboard-command/overview.js.map +1 -1
  180. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  181. package/dist/core/dashboard-ipc-server.js +415 -42
  182. package/dist/core/dashboard-ipc-server.js.map +1 -1
  183. package/dist/core/dashboard-rows.d.ts +4 -0
  184. package/dist/core/dashboard-rows.d.ts.map +1 -1
  185. package/dist/core/dashboard-rows.js +3 -0
  186. package/dist/core/dashboard-rows.js.map +1 -1
  187. package/dist/core/dashboard-url.d.ts +37 -0
  188. package/dist/core/dashboard-url.d.ts.map +1 -1
  189. package/dist/core/dashboard-url.js +71 -0
  190. package/dist/core/dashboard-url.js.map +1 -1
  191. package/dist/core/deferred-schedule-settlement.d.ts +15 -1
  192. package/dist/core/deferred-schedule-settlement.d.ts.map +1 -1
  193. package/dist/core/deferred-schedule-settlement.js +4 -1
  194. package/dist/core/deferred-schedule-settlement.js.map +1 -1
  195. package/dist/core/device-isolation-daemon.d.ts +91 -1
  196. package/dist/core/device-isolation-daemon.d.ts.map +1 -1
  197. package/dist/core/device-isolation-daemon.js +346 -2
  198. package/dist/core/device-isolation-daemon.js.map +1 -1
  199. package/dist/core/local-terminal-opener.d.ts.map +1 -1
  200. package/dist/core/local-terminal-opener.js +5 -1
  201. package/dist/core/local-terminal-opener.js.map +1 -1
  202. package/dist/core/loopback-target.d.ts +14 -0
  203. package/dist/core/loopback-target.d.ts.map +1 -0
  204. package/dist/core/loopback-target.js +20 -0
  205. package/dist/core/loopback-target.js.map +1 -0
  206. package/dist/core/maintenance.d.ts.map +1 -1
  207. package/dist/core/maintenance.js +16 -2
  208. package/dist/core/maintenance.js.map +1 -1
  209. package/dist/core/mojo-containment-command.d.ts +20 -0
  210. package/dist/core/mojo-containment-command.d.ts.map +1 -0
  211. package/dist/core/mojo-containment-command.js +266 -0
  212. package/dist/core/mojo-containment-command.js.map +1 -0
  213. package/dist/core/mojo-containment.d.ts +575 -0
  214. package/dist/core/mojo-containment.d.ts.map +1 -0
  215. package/dist/core/mojo-containment.js +1158 -0
  216. package/dist/core/mojo-containment.js.map +1 -0
  217. package/dist/core/mojo-launcher-env-quarantine.d.ts +30 -0
  218. package/dist/core/mojo-launcher-env-quarantine.d.ts.map +1 -0
  219. package/dist/core/mojo-launcher-env-quarantine.js +175 -0
  220. package/dist/core/mojo-launcher-env-quarantine.js.map +1 -0
  221. package/dist/core/mojo-session-identity.d.ts +3 -0
  222. package/dist/core/mojo-session-identity.d.ts.map +1 -0
  223. package/dist/core/mojo-session-identity.js +126 -0
  224. package/dist/core/mojo-session-identity.js.map +1 -0
  225. package/dist/core/persistent-backend.d.ts +32 -8
  226. package/dist/core/persistent-backend.d.ts.map +1 -1
  227. package/dist/core/persistent-backend.js +55 -17
  228. package/dist/core/persistent-backend.js.map +1 -1
  229. package/dist/core/plugins/mcp/gateway.d.ts +14 -1
  230. package/dist/core/plugins/mcp/gateway.d.ts.map +1 -1
  231. package/dist/core/plugins/mcp/gateway.js +70 -3
  232. package/dist/core/plugins/mcp/gateway.js.map +1 -1
  233. package/dist/core/plugins/mcp/host.d.ts +2 -0
  234. package/dist/core/plugins/mcp/host.d.ts.map +1 -1
  235. package/dist/core/plugins/mcp/host.js +2 -0
  236. package/dist/core/plugins/mcp/host.js.map +1 -1
  237. package/dist/core/plugins/pm2.d.ts.map +1 -1
  238. package/dist/core/plugins/pm2.js +16 -3
  239. package/dist/core/plugins/pm2.js.map +1 -1
  240. package/dist/core/plugins/service-manager.d.ts +9 -0
  241. package/dist/core/plugins/service-manager.d.ts.map +1 -1
  242. package/dist/core/plugins/service-manager.js +33 -16
  243. package/dist/core/plugins/service-manager.js.map +1 -1
  244. package/dist/core/preview-port-owner.d.ts +109 -0
  245. package/dist/core/preview-port-owner.d.ts.map +1 -0
  246. package/dist/core/preview-port-owner.js +320 -0
  247. package/dist/core/preview-port-owner.js.map +1 -0
  248. package/dist/core/remote-cli-ids.d.ts +5 -0
  249. package/dist/core/remote-cli-ids.d.ts.map +1 -0
  250. package/dist/core/remote-cli-ids.js +24 -0
  251. package/dist/core/remote-cli-ids.js.map +1 -0
  252. package/dist/core/{riff-shutdown-detach.d.ts → remote-shutdown-detach.d.ts} +40 -39
  253. package/dist/core/remote-shutdown-detach.d.ts.map +1 -0
  254. package/dist/core/{riff-shutdown-detach.js → remote-shutdown-detach.js} +85 -83
  255. package/dist/core/remote-shutdown-detach.js.map +1 -0
  256. package/dist/core/{riff-worker-shutdown-readiness.d.ts → remote-worker-shutdown-readiness.d.ts} +5 -4
  257. package/dist/core/remote-worker-shutdown-readiness.d.ts.map +1 -0
  258. package/dist/core/{riff-worker-shutdown-readiness.js → remote-worker-shutdown-readiness.js} +4 -3
  259. package/dist/core/remote-worker-shutdown-readiness.js.map +1 -0
  260. package/dist/core/reply-target.d.ts +16 -1
  261. package/dist/core/reply-target.d.ts.map +1 -1
  262. package/dist/core/reply-target.js +61 -0
  263. package/dist/core/reply-target.js.map +1 -1
  264. package/dist/core/session-group-birth.d.ts +26 -0
  265. package/dist/core/session-group-birth.d.ts.map +1 -1
  266. package/dist/core/session-group-birth.js +81 -4
  267. package/dist/core/session-group-birth.js.map +1 -1
  268. package/dist/core/session-manager.d.ts +15 -2
  269. package/dist/core/session-manager.d.ts.map +1 -1
  270. package/dist/core/session-manager.js +259 -5
  271. package/dist/core/session-manager.js.map +1 -1
  272. package/dist/core/session-model.d.ts +46 -0
  273. package/dist/core/session-model.d.ts.map +1 -0
  274. package/dist/core/session-model.js +42 -0
  275. package/dist/core/session-model.js.map +1 -0
  276. package/dist/core/session-owner-reminder.d.ts +63 -0
  277. package/dist/core/session-owner-reminder.d.ts.map +1 -0
  278. package/dist/core/session-owner-reminder.js +196 -0
  279. package/dist/core/session-owner-reminder.js.map +1 -0
  280. package/dist/core/session-preview-registry.d.ts +53 -0
  281. package/dist/core/session-preview-registry.d.ts.map +1 -0
  282. package/dist/core/session-preview-registry.js +82 -0
  283. package/dist/core/session-preview-registry.js.map +1 -0
  284. package/dist/core/session-preview.d.ts +114 -0
  285. package/dist/core/session-preview.d.ts.map +1 -0
  286. package/dist/core/session-preview.js +184 -0
  287. package/dist/core/session-preview.js.map +1 -0
  288. package/dist/core/session-rename.d.ts.map +1 -1
  289. package/dist/core/session-rename.js +5 -3
  290. package/dist/core/session-rename.js.map +1 -1
  291. package/dist/core/session-wake-deadline.d.ts +5 -0
  292. package/dist/core/session-wake-deadline.d.ts.map +1 -0
  293. package/dist/core/session-wake-deadline.js +13 -0
  294. package/dist/core/session-wake-deadline.js.map +1 -0
  295. package/dist/core/shutdown-budgets.d.ts +7 -6
  296. package/dist/core/shutdown-budgets.d.ts.map +1 -1
  297. package/dist/core/shutdown-budgets.js +11 -10
  298. package/dist/core/shutdown-budgets.js.map +1 -1
  299. package/dist/core/skills/frontmatter.d.ts.map +1 -1
  300. package/dist/core/skills/frontmatter.js +6 -1
  301. package/dist/core/skills/frontmatter.js.map +1 -1
  302. package/dist/core/terminal-control-grant.d.ts +74 -0
  303. package/dist/core/terminal-control-grant.d.ts.map +1 -0
  304. package/dist/core/terminal-control-grant.js +183 -0
  305. package/dist/core/terminal-control-grant.js.map +1 -0
  306. package/dist/core/terminal-proxy.d.ts.map +1 -1
  307. package/dist/core/terminal-proxy.js +4 -5
  308. package/dist/core/terminal-proxy.js.map +1 -1
  309. package/dist/core/terminal-write-auth.d.ts +4 -11
  310. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  311. package/dist/core/terminal-write-auth.js +19 -16
  312. package/dist/core/terminal-write-auth.js.map +1 -1
  313. package/dist/core/trigger-session.d.ts.map +1 -1
  314. package/dist/core/trigger-session.js +36 -29
  315. package/dist/core/trigger-session.js.map +1 -1
  316. package/dist/core/types.d.ts +88 -10
  317. package/dist/core/types.d.ts.map +1 -1
  318. package/dist/core/types.js +9 -7
  319. package/dist/core/types.js.map +1 -1
  320. package/dist/core/workbench-link.d.ts +81 -0
  321. package/dist/core/workbench-link.d.ts.map +1 -0
  322. package/dist/core/workbench-link.js +109 -0
  323. package/dist/core/workbench-link.js.map +1 -0
  324. package/dist/core/worker-pool.d.ts +312 -11
  325. package/dist/core/worker-pool.d.ts.map +1 -1
  326. package/dist/core/worker-pool.js +2515 -217
  327. package/dist/core/worker-pool.js.map +1 -1
  328. package/dist/daemon.d.ts +6 -0
  329. package/dist/daemon.d.ts.map +1 -1
  330. package/dist/daemon.js +447 -116
  331. package/dist/daemon.js.map +1 -1
  332. package/dist/dashboard/aggregator.d.ts +33 -3
  333. package/dist/dashboard/aggregator.d.ts.map +1 -1
  334. package/dist/dashboard/aggregator.js +93 -17
  335. package/dist/dashboard/aggregator.js.map +1 -1
  336. package/dist/dashboard/auth-session-connections.d.ts +59 -0
  337. package/dist/dashboard/auth-session-connections.d.ts.map +1 -0
  338. package/dist/dashboard/auth-session-connections.js +109 -0
  339. package/dist/dashboard/auth-session-connections.js.map +1 -0
  340. package/dist/dashboard/auth.d.ts +99 -1
  341. package/dist/dashboard/auth.d.ts.map +1 -1
  342. package/dist/dashboard/auth.js +176 -64
  343. package/dist/dashboard/auth.js.map +1 -1
  344. package/dist/dashboard/bot-payload.d.ts +5 -0
  345. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  346. package/dist/dashboard/bot-payload.js +4 -0
  347. package/dist/dashboard/bot-payload.js.map +1 -1
  348. package/dist/dashboard/control-audit.d.ts +112 -0
  349. package/dist/dashboard/control-audit.d.ts.map +1 -0
  350. package/dist/dashboard/control-audit.js +195 -0
  351. package/dist/dashboard/control-audit.js.map +1 -0
  352. package/dist/dashboard/control-csrf.d.ts +123 -0
  353. package/dist/dashboard/control-csrf.d.ts.map +1 -0
  354. package/dist/dashboard/control-csrf.js +392 -0
  355. package/dist/dashboard/control-csrf.js.map +1 -0
  356. package/dist/dashboard/daemon-reconcile.d.ts +26 -0
  357. package/dist/dashboard/daemon-reconcile.d.ts.map +1 -0
  358. package/dist/dashboard/daemon-reconcile.js +46 -0
  359. package/dist/dashboard/daemon-reconcile.js.map +1 -0
  360. package/dist/dashboard/debug-terminal.d.ts.map +1 -1
  361. package/dist/dashboard/debug-terminal.js +18 -4
  362. package/dist/dashboard/debug-terminal.js.map +1 -1
  363. package/dist/dashboard/events-sse.d.ts +60 -0
  364. package/dist/dashboard/events-sse.d.ts.map +1 -0
  365. package/dist/dashboard/events-sse.js +63 -0
  366. package/dist/dashboard/events-sse.js.map +1 -0
  367. package/dist/dashboard/h5-auth.d.ts +256 -0
  368. package/dist/dashboard/h5-auth.d.ts.map +1 -0
  369. package/dist/dashboard/h5-auth.js +825 -0
  370. package/dist/dashboard/h5-auth.js.map +1 -0
  371. package/dist/dashboard/managed-spawn.d.ts +36 -0
  372. package/dist/dashboard/managed-spawn.d.ts.map +1 -0
  373. package/dist/dashboard/managed-spawn.js +169 -0
  374. package/dist/dashboard/managed-spawn.js.map +1 -0
  375. package/dist/dashboard/preview-content-capability.d.ts +41 -0
  376. package/dist/dashboard/preview-content-capability.d.ts.map +1 -0
  377. package/dist/dashboard/preview-content-capability.js +127 -0
  378. package/dist/dashboard/preview-content-capability.js.map +1 -0
  379. package/dist/dashboard/preview-contract.d.ts +85 -0
  380. package/dist/dashboard/preview-contract.d.ts.map +1 -0
  381. package/dist/dashboard/preview-contract.js +198 -0
  382. package/dist/dashboard/preview-contract.js.map +1 -0
  383. package/dist/dashboard/preview-guard-page.d.ts +52 -0
  384. package/dist/dashboard/preview-guard-page.d.ts.map +1 -0
  385. package/dist/dashboard/preview-guard-page.js +162 -0
  386. package/dist/dashboard/preview-guard-page.js.map +1 -0
  387. package/dist/dashboard/preview-interaction.d.ts +57 -0
  388. package/dist/dashboard/preview-interaction.d.ts.map +1 -0
  389. package/dist/dashboard/preview-interaction.js +198 -0
  390. package/dist/dashboard/preview-interaction.js.map +1 -0
  391. package/dist/dashboard/preview-proxy.d.ts +113 -0
  392. package/dist/dashboard/preview-proxy.d.ts.map +1 -0
  393. package/dist/dashboard/preview-proxy.js +543 -0
  394. package/dist/dashboard/preview-proxy.js.map +1 -0
  395. package/dist/dashboard/public-redact.d.ts +23 -0
  396. package/dist/dashboard/public-redact.d.ts.map +1 -1
  397. package/dist/dashboard/public-redact.js +90 -21
  398. package/dist/dashboard/public-redact.js.map +1 -1
  399. package/dist/dashboard/request-identity.d.ts +77 -0
  400. package/dist/dashboard/request-identity.d.ts.map +1 -0
  401. package/dist/dashboard/request-identity.js +72 -0
  402. package/dist/dashboard/request-identity.js.map +1 -0
  403. package/dist/dashboard/session-cleanup.d.ts +5 -0
  404. package/dist/dashboard/session-cleanup.d.ts.map +1 -1
  405. package/dist/dashboard/session-cleanup.js +4 -0
  406. package/dist/dashboard/session-cleanup.js.map +1 -1
  407. package/dist/dashboard/settings-write-applier.d.ts +5 -1
  408. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  409. package/dist/dashboard/settings-write-applier.js +14 -0
  410. package/dist/dashboard/settings-write-applier.js.map +1 -1
  411. package/dist/dashboard/standing-link.d.ts +76 -0
  412. package/dist/dashboard/standing-link.d.ts.map +1 -0
  413. package/dist/dashboard/standing-link.js +111 -0
  414. package/dist/dashboard/standing-link.js.map +1 -0
  415. package/dist/dashboard/terminal-control.d.ts +105 -0
  416. package/dist/dashboard/terminal-control.d.ts.map +1 -0
  417. package/dist/dashboard/terminal-control.js +296 -0
  418. package/dist/dashboard/terminal-control.js.map +1 -0
  419. package/dist/dashboard/terminal-front-proxy.d.ts +55 -0
  420. package/dist/dashboard/terminal-front-proxy.d.ts.map +1 -0
  421. package/dist/dashboard/terminal-front-proxy.js +397 -0
  422. package/dist/dashboard/terminal-front-proxy.js.map +1 -0
  423. package/dist/dashboard/terminal-view-capability.d.ts +97 -0
  424. package/dist/dashboard/terminal-view-capability.d.ts.map +1 -0
  425. package/dist/dashboard/terminal-view-capability.js +145 -0
  426. package/dist/dashboard/terminal-view-capability.js.map +1 -0
  427. package/dist/dashboard/web/agent-workbench-api.d.ts +59 -0
  428. package/dist/dashboard/web/agent-workbench-api.d.ts.map +1 -0
  429. package/dist/dashboard/web/agent-workbench-api.js +227 -0
  430. package/dist/dashboard/web/agent-workbench-api.js.map +1 -0
  431. package/dist/dashboard/web/agent-workbench-appearance-menu.d.ts +59 -0
  432. package/dist/dashboard/web/agent-workbench-appearance-menu.d.ts.map +1 -0
  433. package/dist/dashboard/web/agent-workbench-appearance-menu.js +195 -0
  434. package/dist/dashboard/web/agent-workbench-appearance-menu.js.map +1 -0
  435. package/dist/dashboard/web/agent-workbench-appearance.d.ts +222 -0
  436. package/dist/dashboard/web/agent-workbench-appearance.d.ts.map +1 -0
  437. package/dist/dashboard/web/agent-workbench-appearance.js +499 -0
  438. package/dist/dashboard/web/agent-workbench-appearance.js.map +1 -0
  439. package/dist/dashboard/web/agent-workbench-capabilities.d.ts +13 -0
  440. package/dist/dashboard/web/agent-workbench-capabilities.d.ts.map +1 -0
  441. package/dist/dashboard/web/agent-workbench-capabilities.js +24 -0
  442. package/dist/dashboard/web/agent-workbench-capabilities.js.map +1 -0
  443. package/dist/dashboard/web/agent-workbench-chat.d.ts +90 -0
  444. package/dist/dashboard/web/agent-workbench-chat.d.ts.map +1 -0
  445. package/dist/dashboard/web/agent-workbench-chat.js +168 -0
  446. package/dist/dashboard/web/agent-workbench-chat.js.map +1 -0
  447. package/dist/dashboard/web/agent-workbench-dock-page.d.ts +3 -0
  448. package/dist/dashboard/web/agent-workbench-dock-page.d.ts.map +1 -0
  449. package/dist/dashboard/web/agent-workbench-dock-page.js +23 -0
  450. package/dist/dashboard/web/agent-workbench-dock-page.js.map +1 -0
  451. package/dist/dashboard/web/agent-workbench-dock-view.d.ts +22 -0
  452. package/dist/dashboard/web/agent-workbench-dock-view.d.ts.map +1 -0
  453. package/dist/dashboard/web/agent-workbench-dock-view.js +76 -0
  454. package/dist/dashboard/web/agent-workbench-dock-view.js.map +1 -0
  455. package/dist/dashboard/web/agent-workbench-model.d.ts +196 -0
  456. package/dist/dashboard/web/agent-workbench-model.d.ts.map +1 -0
  457. package/dist/dashboard/web/agent-workbench-model.js +529 -0
  458. package/dist/dashboard/web/agent-workbench-model.js.map +1 -0
  459. package/dist/dashboard/web/agent-workbench-page.d.ts +3 -0
  460. package/dist/dashboard/web/agent-workbench-page.d.ts.map +1 -0
  461. package/dist/dashboard/web/agent-workbench-page.js +27 -0
  462. package/dist/dashboard/web/agent-workbench-page.js.map +1 -0
  463. package/dist/dashboard/web/agent-workbench-panes.d.ts +49 -0
  464. package/dist/dashboard/web/agent-workbench-panes.d.ts.map +1 -0
  465. package/dist/dashboard/web/agent-workbench-panes.js +468 -0
  466. package/dist/dashboard/web/agent-workbench-panes.js.map +1 -0
  467. package/dist/dashboard/web/agent-workbench-session-list.d.ts +42 -0
  468. package/dist/dashboard/web/agent-workbench-session-list.d.ts.map +1 -0
  469. package/dist/dashboard/web/agent-workbench-session-list.js +353 -0
  470. package/dist/dashboard/web/agent-workbench-session-list.js.map +1 -0
  471. package/dist/dashboard/web/agent-workbench-storage.d.ts +49 -0
  472. package/dist/dashboard/web/agent-workbench-storage.d.ts.map +1 -0
  473. package/dist/dashboard/web/agent-workbench-storage.js +197 -0
  474. package/dist/dashboard/web/agent-workbench-storage.js.map +1 -0
  475. package/dist/dashboard/web/agent-workbench-touch.d.ts +46 -0
  476. package/dist/dashboard/web/agent-workbench-touch.d.ts.map +1 -0
  477. package/dist/dashboard/web/agent-workbench-touch.js +96 -0
  478. package/dist/dashboard/web/agent-workbench-touch.js.map +1 -0
  479. package/dist/dashboard/web/agent-workbench-view.d.ts +34 -0
  480. package/dist/dashboard/web/agent-workbench-view.d.ts.map +1 -0
  481. package/dist/dashboard/web/agent-workbench-view.js +439 -0
  482. package/dist/dashboard/web/agent-workbench-view.js.map +1 -0
  483. package/dist/dashboard/web/app.d.ts.map +1 -1
  484. package/dist/dashboard/web/app.js +63 -2
  485. package/dist/dashboard/web/app.js.map +1 -1
  486. package/dist/dashboard/web/bot-defaults-page.d.ts +18 -0
  487. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  488. package/dist/dashboard/web/bot-defaults-page.js +362 -36
  489. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  490. package/dist/dashboard/web/bot-defaults.d.ts +8 -0
  491. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  492. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  493. package/dist/dashboard/web/control-csrf.d.ts +4 -0
  494. package/dist/dashboard/web/control-csrf.d.ts.map +1 -0
  495. package/dist/dashboard/web/control-csrf.js +26 -0
  496. package/dist/dashboard/web/control-csrf.js.map +1 -0
  497. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  498. package/dist/dashboard/web/dashboard-routes.js +2 -0
  499. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  500. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  501. package/dist/dashboard/web/groups-page.js +11 -2
  502. package/dist/dashboard/web/groups-page.js.map +1 -1
  503. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  504. package/dist/dashboard/web/i18n.js +140 -6
  505. package/dist/dashboard/web/i18n.js.map +1 -1
  506. package/dist/dashboard/web/overview-page.d.ts.map +1 -1
  507. package/dist/dashboard/web/overview-page.js +3 -2
  508. package/dist/dashboard/web/overview-page.js.map +1 -1
  509. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  510. package/dist/dashboard/web/sessions-page.js +41 -1
  511. package/dist/dashboard/web/sessions-page.js.map +1 -1
  512. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  513. package/dist/dashboard/web/sessions.js +5 -1
  514. package/dist/dashboard/web/sessions.js.map +1 -1
  515. package/dist/dashboard/web/settings-page.d.ts +3 -0
  516. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  517. package/dist/dashboard/web/settings-page.js +56 -10
  518. package/dist/dashboard/web/settings-page.js.map +1 -1
  519. package/dist/dashboard/web/skills-page.d.ts.map +1 -1
  520. package/dist/dashboard/web/skills-page.js +4 -2
  521. package/dist/dashboard/web/skills-page.js.map +1 -1
  522. package/dist/dashboard/web/store.d.ts +27 -2
  523. package/dist/dashboard/web/store.d.ts.map +1 -1
  524. package/dist/dashboard/web/store.js +43 -4
  525. package/dist/dashboard/web/store.js.map +1 -1
  526. package/dist/dashboard/web/ui.d.ts +3 -0
  527. package/dist/dashboard/web/ui.d.ts.map +1 -1
  528. package/dist/dashboard/web/ui.js +11 -0
  529. package/dist/dashboard/web/ui.js.map +1 -1
  530. package/dist/dashboard/web/update-action.d.ts +12 -0
  531. package/dist/dashboard/web/update-action.d.ts.map +1 -1
  532. package/dist/dashboard/web/update-action.js +11 -0
  533. package/dist/dashboard/web/update-action.js.map +1 -1
  534. package/dist/dashboard/workbench-doctor.d.ts +114 -0
  535. package/dist/dashboard/workbench-doctor.d.ts.map +1 -0
  536. package/dist/dashboard/workbench-doctor.js +620 -0
  537. package/dist/dashboard/workbench-doctor.js.map +1 -0
  538. package/dist/dashboard/workbench-ticket.d.ts +165 -0
  539. package/dist/dashboard/workbench-ticket.d.ts.map +1 -0
  540. package/dist/dashboard/workbench-ticket.js +495 -0
  541. package/dist/dashboard/workbench-ticket.js.map +1 -0
  542. package/dist/dashboard-web/app.js +1 -1
  543. package/dist/dashboard-web/chunks/agent-workbench-dock-page-IKAC5CFL.js +1 -0
  544. package/dist/dashboard-web/chunks/agent-workbench-page-M53UN5EB.js +1 -0
  545. package/dist/dashboard-web/chunks/bot-defaults-page-YKE5SDZF.js +10 -0
  546. package/dist/dashboard-web/chunks/chunk-22WIADUT.js +2 -0
  547. package/dist/dashboard-web/chunks/chunk-24ONYQMR.js +1 -0
  548. package/dist/dashboard-web/chunks/{chunk-6O7KXFD2.js → chunk-2W6SCN3M.js} +1 -1
  549. package/dist/dashboard-web/chunks/chunk-4XNJX6B3.js +1 -0
  550. package/dist/dashboard-web/chunks/{chunk-Q2MT4VWH.js → chunk-F6KNPF4R.js} +11 -9
  551. package/dist/dashboard-web/chunks/chunk-FXW3V4JR.js +1 -0
  552. package/dist/dashboard-web/chunks/chunk-G5ZS2YUS.js +1 -0
  553. package/dist/dashboard-web/chunks/chunk-KTQ7B6ZR.js +1 -0
  554. package/dist/dashboard-web/chunks/{chunk-U3ZFSO7E.js → chunk-NACP7BMR.js} +1 -1
  555. package/dist/dashboard-web/chunks/{connectors-page-2KZO5KSJ.js → connectors-page-VOISXXII.js} +1 -1
  556. package/dist/dashboard-web/chunks/{feedback-page-CLVTOLLO.js → feedback-page-RN6HRZMS.js} +1 -1
  557. package/dist/dashboard-web/chunks/groups-page-UQT6DCB7.js +8 -0
  558. package/dist/dashboard-web/chunks/{insights-page-4RPU2CRU.js → insights-page-HJFDYR5N.js} +3 -3
  559. package/dist/dashboard-web/chunks/{monitor-room-OTKQ2CXK.js → monitor-room-V7PCP47V.js} +1 -1
  560. package/dist/dashboard-web/chunks/{monitoring-page-IJPUB6JT.js → monitoring-page-NKEKVQAP.js} +1 -1
  561. package/dist/dashboard-web/chunks/{office-page-QSR3J44Y.js → office-page-GVJF73XW.js} +1 -1
  562. package/dist/dashboard-web/chunks/overview-page-KHLV6VTI.js +1 -0
  563. package/dist/dashboard-web/chunks/{plugin-page-VEGTCEAS.js → plugin-page-J3OF5IY4.js} +1 -1
  564. package/dist/dashboard-web/chunks/{roles-page-6NWJMOB5.js → roles-page-WQIRSOLZ.js} +1 -1
  565. package/dist/dashboard-web/chunks/{schedules-page-6I3LNXD4.js → schedules-page-J2DEY2X6.js} +1 -1
  566. package/dist/dashboard-web/chunks/sessions-page-7BQFEA5P.js +8 -0
  567. package/dist/dashboard-web/chunks/settings-page-BJEIOFJH.js +2 -0
  568. package/dist/dashboard-web/chunks/{skills-page-M2Q6L5CB.js → skills-page-HGIFR3IU.js} +2 -2
  569. package/dist/dashboard-web/chunks/{team-federation-page-7I7FDE3B.js → team-federation-page-MR5ZPL4B.js} +1 -1
  570. package/dist/dashboard-web/chunks/{v3-page-HQXRL65L.js → v3-page-GBR5JWPE.js} +2 -2
  571. package/dist/dashboard-web/chunks/{whiteboards-page-LQKC4TAZ.js → whiteboards-page-QAZM4BN3.js} +1 -1
  572. package/dist/dashboard-web/index.html +8 -1
  573. package/dist/dashboard-web/style.css +2006 -10
  574. package/dist/dashboard.js +1017 -264
  575. package/dist/dashboard.js.map +1 -1
  576. package/dist/dsh-runner.js +8 -1
  577. package/dist/dsh-runner.js.map +1 -1
  578. package/dist/global-config.d.ts +30 -0
  579. package/dist/global-config.d.ts.map +1 -1
  580. package/dist/global-config.js +33 -0
  581. package/dist/global-config.js.map +1 -1
  582. package/dist/i18n/en.d.ts.map +1 -1
  583. package/dist/i18n/en.js +46 -27
  584. package/dist/i18n/en.js.map +1 -1
  585. package/dist/i18n/zh.d.ts.map +1 -1
  586. package/dist/i18n/zh.js +43 -27
  587. package/dist/i18n/zh.js.map +1 -1
  588. package/dist/im/lark/card-builder.d.ts +1 -1
  589. package/dist/im/lark/card-builder.d.ts.map +1 -1
  590. package/dist/im/lark/card-builder.js +22 -6
  591. package/dist/im/lark/card-builder.js.map +1 -1
  592. package/dist/im/lark/card-handler.d.ts.map +1 -1
  593. package/dist/im/lark/card-handler.js +118 -24
  594. package/dist/im/lark/card-handler.js.map +1 -1
  595. package/dist/im/lark/client.d.ts +15 -0
  596. package/dist/im/lark/client.d.ts.map +1 -1
  597. package/dist/im/lark/client.js +30 -0
  598. package/dist/im/lark/client.js.map +1 -1
  599. package/dist/im/lark/event-dispatcher.d.ts +48 -0
  600. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  601. package/dist/im/lark/event-dispatcher.js +138 -41
  602. package/dist/im/lark/event-dispatcher.js.map +1 -1
  603. package/dist/im/lark/identity-cache.d.ts +14 -6
  604. package/dist/im/lark/identity-cache.d.ts.map +1 -1
  605. package/dist/im/lark/identity-cache.js +69 -26
  606. package/dist/im/lark/identity-cache.js.map +1 -1
  607. package/dist/im/lark/lark-hosts.d.ts +13 -0
  608. package/dist/im/lark/lark-hosts.d.ts.map +1 -1
  609. package/dist/im/lark/lark-hosts.js +16 -0
  610. package/dist/im/lark/lark-hosts.js.map +1 -1
  611. package/dist/im/lark/overview-card.d.ts +22 -0
  612. package/dist/im/lark/overview-card.d.ts.map +1 -1
  613. package/dist/im/lark/overview-card.js +53 -3
  614. package/dist/im/lark/overview-card.js.map +1 -1
  615. package/dist/im/lark/sessions-card.d.ts.map +1 -1
  616. package/dist/im/lark/sessions-card.js +26 -3
  617. package/dist/im/lark/sessions-card.js.map +1 -1
  618. package/dist/im/lark/workflow-slash-command.d.ts +6 -0
  619. package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
  620. package/dist/im/lark/workflow-slash-command.js +7 -0
  621. package/dist/im/lark/workflow-slash-command.js.map +1 -1
  622. package/dist/index-daemon.js +27 -4
  623. package/dist/index-daemon.js.map +1 -1
  624. package/dist/index-dashboard.d.ts +3 -0
  625. package/dist/index-dashboard.d.ts.map +1 -0
  626. package/dist/index-dashboard.js +94 -0
  627. package/dist/index-dashboard.js.map +1 -0
  628. package/dist/platform/team-agents-client.d.ts +199 -0
  629. package/dist/platform/team-agents-client.d.ts.map +1 -0
  630. package/dist/platform/team-agents-client.js +263 -0
  631. package/dist/platform/team-agents-client.js.map +1 -0
  632. package/dist/platform/tunnel-client.d.ts +6 -0
  633. package/dist/platform/tunnel-client.d.ts.map +1 -1
  634. package/dist/platform/tunnel-client.js.map +1 -1
  635. package/dist/services/async-trigger-state.d.ts +7 -3
  636. package/dist/services/async-trigger-state.d.ts.map +1 -1
  637. package/dist/services/async-trigger-state.js +28 -0
  638. package/dist/services/async-trigger-state.js.map +1 -1
  639. package/dist/services/async-trigger-store.d.ts +13 -4
  640. package/dist/services/async-trigger-store.d.ts.map +1 -1
  641. package/dist/services/async-trigger-store.js +55 -8
  642. package/dist/services/async-trigger-store.js.map +1 -1
  643. package/dist/services/bot-config-store.d.ts +1 -11
  644. package/dist/services/bot-config-store.d.ts.map +1 -1
  645. package/dist/services/bot-config-store.js +27 -3
  646. package/dist/services/bot-config-store.js.map +1 -1
  647. package/dist/services/bot-profile-store.d.ts +17 -2
  648. package/dist/services/bot-profile-store.d.ts.map +1 -1
  649. package/dist/services/bot-profile-store.js +93 -12
  650. package/dist/services/bot-profile-store.js.map +1 -1
  651. package/dist/services/bridge-fallback-gate.d.ts +15 -7
  652. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  653. package/dist/services/bridge-fallback-gate.js +43 -16
  654. package/dist/services/bridge-fallback-gate.js.map +1 -1
  655. package/dist/services/bridge-turn-queue.d.ts +10 -1
  656. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  657. package/dist/services/bridge-turn-queue.js +29 -9
  658. package/dist/services/bridge-turn-queue.js.map +1 -1
  659. package/dist/services/claude-transcript.d.ts +19 -0
  660. package/dist/services/claude-transcript.d.ts.map +1 -1
  661. package/dist/services/claude-transcript.js +57 -5
  662. package/dist/services/claude-transcript.js.map +1 -1
  663. package/dist/services/codex-app-threads.d.ts +2 -0
  664. package/dist/services/codex-app-threads.d.ts.map +1 -1
  665. package/dist/services/codex-app-threads.js +1 -1
  666. package/dist/services/codex-app-threads.js.map +1 -1
  667. package/dist/services/codex-reasoning-effort.d.ts +8 -0
  668. package/dist/services/codex-reasoning-effort.d.ts.map +1 -1
  669. package/dist/services/codex-reasoning-effort.js +24 -0
  670. package/dist/services/codex-reasoning-effort.js.map +1 -1
  671. package/dist/services/cursor-resume-policy.d.ts.map +1 -1
  672. package/dist/services/cursor-resume-policy.js +15 -3
  673. package/dist/services/cursor-resume-policy.js.map +1 -1
  674. package/dist/services/open-platform-rename.d.ts.map +1 -1
  675. package/dist/services/open-platform-rename.js +3 -2
  676. package/dist/services/open-platform-rename.js.map +1 -1
  677. package/dist/services/ordinary-turn-recovery.d.ts +76 -0
  678. package/dist/services/ordinary-turn-recovery.d.ts.map +1 -0
  679. package/dist/services/ordinary-turn-recovery.js +349 -0
  680. package/dist/services/ordinary-turn-recovery.js.map +1 -0
  681. package/dist/services/peer-cross-ref-store.d.ts +8 -0
  682. package/dist/services/peer-cross-ref-store.d.ts.map +1 -0
  683. package/dist/services/peer-cross-ref-store.js +95 -0
  684. package/dist/services/peer-cross-ref-store.js.map +1 -0
  685. package/dist/services/pi-transcript.d.ts.map +1 -1
  686. package/dist/services/pi-transcript.js +10 -6
  687. package/dist/services/pi-transcript.js.map +1 -1
  688. package/dist/services/resume-fresh-policy.d.ts +17 -0
  689. package/dist/services/resume-fresh-policy.d.ts.map +1 -0
  690. package/dist/services/resume-fresh-policy.js +24 -0
  691. package/dist/services/resume-fresh-policy.js.map +1 -0
  692. package/dist/services/session-group-title.d.ts +1 -0
  693. package/dist/services/session-group-title.d.ts.map +1 -1
  694. package/dist/services/session-group-title.js +16 -1
  695. package/dist/services/session-group-title.js.map +1 -1
  696. package/dist/services/session-groups-store.d.ts +30 -0
  697. package/dist/services/session-groups-store.d.ts.map +1 -1
  698. package/dist/services/session-groups-store.js +26 -4
  699. package/dist/services/session-groups-store.js.map +1 -1
  700. package/dist/services/session-owner-notification.d.ts +9 -0
  701. package/dist/services/session-owner-notification.d.ts.map +1 -0
  702. package/dist/services/session-owner-notification.js +10 -0
  703. package/dist/services/session-owner-notification.js.map +1 -0
  704. package/dist/services/session-owner-reminder-config-store.d.ts +9 -0
  705. package/dist/services/session-owner-reminder-config-store.d.ts.map +1 -0
  706. package/dist/services/session-owner-reminder-config-store.js +24 -0
  707. package/dist/services/session-owner-reminder-config-store.js.map +1 -0
  708. package/dist/services/session-owner-reminder-store.d.ts +5 -0
  709. package/dist/services/session-owner-reminder-store.d.ts.map +1 -0
  710. package/dist/services/session-owner-reminder-store.js +54 -0
  711. package/dist/services/session-owner-reminder-store.js.map +1 -0
  712. package/dist/services/session-store.d.ts +98 -21
  713. package/dist/services/session-store.d.ts.map +1 -1
  714. package/dist/services/session-store.js +406 -48
  715. package/dist/services/session-store.js.map +1 -1
  716. package/dist/services/structured-bridge-clis.d.ts +15 -2
  717. package/dist/services/structured-bridge-clis.d.ts.map +1 -1
  718. package/dist/services/structured-bridge-clis.js +16 -1
  719. package/dist/services/structured-bridge-clis.js.map +1 -1
  720. package/dist/services/transcript-resolver.d.ts +1 -1
  721. package/dist/services/transcript-resolver.d.ts.map +1 -1
  722. package/dist/services/transcript-resolver.js +6 -1
  723. package/dist/services/transcript-resolver.js.map +1 -1
  724. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  725. package/dist/setup/bot-config-editor.js +7 -2
  726. package/dist/setup/bot-config-editor.js.map +1 -1
  727. package/dist/setup/ensure-herdr-integrations.d.ts +13 -0
  728. package/dist/setup/ensure-herdr-integrations.d.ts.map +1 -1
  729. package/dist/setup/ensure-herdr-integrations.js +21 -3
  730. package/dist/setup/ensure-herdr-integrations.js.map +1 -1
  731. package/dist/setup/open-platform-automation.d.ts +1 -0
  732. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  733. package/dist/setup/open-platform-automation.js +107 -7
  734. package/dist/setup/open-platform-automation.js.map +1 -1
  735. package/dist/skills/definitions.d.ts +17 -0
  736. package/dist/skills/definitions.d.ts.map +1 -1
  737. package/dist/skills/definitions.js +78 -8
  738. package/dist/skills/definitions.js.map +1 -1
  739. package/dist/skills/injection-mode.d.ts +24 -3
  740. package/dist/skills/injection-mode.d.ts.map +1 -1
  741. package/dist/skills/injection-mode.js +64 -15
  742. package/dist/skills/injection-mode.js.map +1 -1
  743. package/dist/skills/installer.d.ts +18 -0
  744. package/dist/skills/installer.d.ts.map +1 -1
  745. package/dist/skills/installer.js +45 -1
  746. package/dist/skills/installer.js.map +1 -1
  747. package/dist/types.d.ts +222 -10
  748. package/dist/types.d.ts.map +1 -1
  749. package/dist/utils/bot-routing.d.ts +1 -1
  750. package/dist/utils/bot-routing.d.ts.map +1 -1
  751. package/dist/utils/bot-routing.js.map +1 -1
  752. package/dist/utils/child-env.d.ts +92 -2
  753. package/dist/utils/child-env.d.ts.map +1 -1
  754. package/dist/utils/child-env.js +195 -1
  755. package/dist/utils/child-env.js.map +1 -1
  756. package/dist/utils/cli-usage-limit.d.ts +25 -14
  757. package/dist/utils/cli-usage-limit.d.ts.map +1 -1
  758. package/dist/utils/cli-usage-limit.js +25 -15
  759. package/dist/utils/cli-usage-limit.js.map +1 -1
  760. package/dist/utils/daemon-rejection-guard.d.ts +35 -0
  761. package/dist/utils/daemon-rejection-guard.d.ts.map +1 -0
  762. package/dist/utils/daemon-rejection-guard.js +101 -0
  763. package/dist/utils/daemon-rejection-guard.js.map +1 -0
  764. package/dist/utils/dashboard-env.d.ts +53 -0
  765. package/dist/utils/dashboard-env.d.ts.map +1 -0
  766. package/dist/utils/dashboard-env.js +116 -0
  767. package/dist/utils/dashboard-env.js.map +1 -0
  768. package/dist/utils/global-install.d.ts.map +1 -1
  769. package/dist/utils/global-install.js +61 -5
  770. package/dist/utils/global-install.js.map +1 -1
  771. package/dist/utils/install-diagnostics.d.ts +14 -7
  772. package/dist/utils/install-diagnostics.d.ts.map +1 -1
  773. package/dist/utils/install-diagnostics.js +20 -11
  774. package/dist/utils/install-diagnostics.js.map +1 -1
  775. package/dist/utils/local-dev-update.d.ts +132 -0
  776. package/dist/utils/local-dev-update.d.ts.map +1 -0
  777. package/dist/utils/local-dev-update.js +176 -0
  778. package/dist/utils/local-dev-update.js.map +1 -0
  779. package/dist/utils/pending-input-queue.d.ts +12 -1
  780. package/dist/utils/pending-input-queue.d.ts.map +1 -1
  781. package/dist/utils/pending-input-queue.js.map +1 -1
  782. package/dist/worker.js +1517 -236
  783. package/dist/worker.js.map +1 -1
  784. package/dist/workflows/definition.d.ts +68 -68
  785. package/dist/workflows/events/payloads.d.ts +14 -14
  786. package/dist/workflows/events/schema.d.ts +312 -312
  787. package/dist/workflows/migration/v2-run-archive-schema.d.ts +40 -40
  788. package/dist/workflows/v3/cli-run.d.ts.map +1 -1
  789. package/dist/workflows/v3/cli-run.js +7 -0
  790. package/dist/workflows/v3/cli-run.js.map +1 -1
  791. package/dist/workflows/v3/goal-cli.d.ts +3 -0
  792. package/dist/workflows/v3/goal-cli.d.ts.map +1 -1
  793. package/dist/workflows/v3/goal-cli.js +11 -0
  794. package/dist/workflows/v3/goal-cli.js.map +1 -1
  795. package/dist/workflows/v3/run-envelope.d.ts +144 -144
  796. package/package.json +7 -2
  797. package/dist/cli/pm2-god-admission.d.ts +0 -8
  798. package/dist/cli/pm2-god-admission.d.ts.map +0 -1
  799. package/dist/cli/pm2-god-admission.js +0 -25
  800. package/dist/cli/pm2-god-admission.js.map +0 -1
  801. package/dist/core/riff-shutdown-detach.d.ts.map +0 -1
  802. package/dist/core/riff-shutdown-detach.js.map +0 -1
  803. package/dist/core/riff-worker-shutdown-readiness.d.ts.map +0 -1
  804. package/dist/core/riff-worker-shutdown-readiness.js.map +0 -1
  805. package/dist/dashboard-web/chunks/bot-defaults-page-4RENHE7J.js +0 -10
  806. package/dist/dashboard-web/chunks/chunk-2WQDS65D.js +0 -1
  807. package/dist/dashboard-web/chunks/chunk-G5XGBCM6.js +0 -1
  808. package/dist/dashboard-web/chunks/chunk-WLIVBPJC.js +0 -1
  809. package/dist/dashboard-web/chunks/groups-page-HLASRTSY.js +0 -8
  810. package/dist/dashboard-web/chunks/overview-page-6OK63V4V.js +0 -1
  811. package/dist/dashboard-web/chunks/sessions-page-B2TXGJDO.js +0 -8
  812. package/dist/dashboard-web/chunks/settings-page-6KJADSC6.js +0 -2
@@ -0,0 +1,165 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ /**
3
+ * 工作台入口短时票据(P2-1)。
4
+ *
5
+ * 背景:`/dashboard` 飞书卡片的「打开工作台」按钮曾直接把长期 Dashboard 管理
6
+ * token 拼进 URL 写入持久化卡片——管理员门禁只保护首次投递,覆盖不了卡片历史、
7
+ * 转发和截图,等于把常驻凭证抄送给未来所有能看到这张卡的人。改为:卡片构建时
8
+ * 现 mint 一张 **30 分钟 TTL 的不可预测票据**,按钮链接只携带票据;访客打开
9
+ * `GET /workbench-ticket/<ticket>` 时由 dashboard 验票,通过则按既有 `?t=` 流程
10
+ * 同款种 legacy cookie 再 302 进工作台。到期后卡片历史/转发/截图里的链接一律
11
+ * 作废,只回一个无凭据的提示页。
12
+ *
13
+ * 设计要点:
14
+ * - **非一次性**:同一张卡片会被同一个管理员在 PC / 手机多端点开,票据在 TTL
15
+ * 内可重复兑换,到期即死。不做兑换计数,避免飞书链接预抓取把票据「烧」掉。
16
+ * - **绑定 token generation(P1-6)**:见下方「票据 ↔ token generation」小节。
17
+ * - **跨进程**:mint 发生在 daemon 进程(构建卡片处),验票发生在 dashboard
18
+ * 进程,两边靠 `~/.botmux/.workbench-tickets.json` 交接;进程内 Map 只是
19
+ * 本进程的快路径缓存。落盘复用 secure-host-file 的 0600 + 目录 0700 + 泄漏
20
+ * 检查惯例(与 `.dashboard-token` 同一套),读-并-写走跨进程文件锁,杜绝并发
21
+ * mint / prune 互相丢条目。
22
+ * - **文件里绝不存明文**:只存 `sha256(ticket)` 的 base64url + 过期时间 +
23
+ * generation 标签。拿到文件读权限的人无法还原票据;但能**写**这个文件就等于
24
+ * 能自铸门票,所以文件的安全形状(属主 / 0600 / 拒符号链接)由 secure-host-file
25
+ * 强制,不满足即 fail closed。
26
+ * - **重启不废票**:dashboard 重启后 Map 为空,验票落到文件比对 hash,刚发出
27
+ * 的卡片链接照常可用。
28
+ *
29
+ * ─── 票据 ↔ token generation(P1-6)────────────────────────────────────────
30
+ * 票据兑换出来的是「**当前**活跃 token」的 cookie。只按 TTL 判活时,rotate 之前
31
+ * 泄漏出去的票据能在 rotate 之后继续兑换——而且兑出来的是**新**管理 cookie。若
32
+ * rotate 的原因正是「链接/卡片泄漏了」,rotation 就此失去全部安全语义:管理员轮
33
+ * 换了凭证,攻击者拿旧票据无缝续上新凭证。
34
+ *
35
+ * 所以每张票在 mint 时钉住当时 token 的 generation 标签(`sha256("…" + token)`),
36
+ * 兑换时要求这个标签仍等于**此刻即将下发的那份 token** 的标签。rotate 换掉 token
37
+ * ⇒ 标签变 ⇒ 旧 generation 的票据一律 410。这条判定是构造性的:不依赖 rotate
38
+ * 路径记得去清理存量票据,清理({@link revokeWorkbenchTicketsOutsideGeneration})
39
+ * 只是把死条目从文件里扫掉的保洁。
40
+ *
41
+ * 同一 generation 内仍然**不是**一次性票:多端重复兑换的语义(P2-1)原样保留。
42
+ *
43
+ * ─── 公开兑换端点的 DoS 面(P1-10)────────────────────────────────────────
44
+ * 兑换端点在 auth gate 之前放行(票据自身就是凭证),任何人都能打。旧实现里每个
45
+ * 「形状合法但未知」的票据都会同步 realpath/stat/open/read/fstat 一遍凭证文件再
46
+ * 全表扫描——HOME 挂在 NFS 上时,几百个伪造票据就能把 event loop 焊死。现在三层
47
+ * 一起收口,且都保持 fail closed 与 timingSafeEqual 语义:
48
+ * 1. **限流**:每 IP + 全局滑动窗口(复用 H5 兑换口那套 gate 与可信代理取 IP
49
+ * 口径),拒绝在读任何盘之前发生;
50
+ * 2. **快照**:落盘内容在进程内缓存 {@link STORE_SNAPSHOT_TTL_MS},打盘次数只跟
51
+ * 时间走、不跟请求量走——请求量翻一万倍,打盘次数不变;
52
+ * 3. **负缓存**:验失败的 (票据 hash, generation) 短期记住,重复打同一张票连
53
+ * 全表扫描都省掉。负缓存条目钉住快照版本号,快照内容一变即失效,所以「刚
54
+ * mint 出来的新票被前一次探测顺手拉黑」最多只存在一个快照周期。
55
+ */
56
+ /** 票据有效期:30 分钟。够管理员从卡片点进去(含转发到手机再点),又短到卡片
57
+ * 历史里的旧链接很快失效。 */
58
+ export declare const WORKBENCH_TICKET_TTL_MS: number;
59
+ /** 兑换端点路径:`GET /workbench-ticket/<ticket>`。auth.ts 的公共面豁免与这里
60
+ * 必须保持同一个 pattern(那边按 `/^\/workbench-ticket\/[^/]+$/` 放行)。 */
61
+ export declare const WORKBENCH_TICKET_ROUTE_RE: RegExp;
62
+ /** 兑换端点限流:滑动窗口长度。 */
63
+ export declare const WORKBENCH_TICKET_RATE_WINDOW_MS = 60000;
64
+ /** 单 IP 每窗口兑换次数上限。管理员多端打开 + 客户端链接预抓取远在这之下。 */
65
+ export declare const WORKBENCH_TICKET_MAX_PER_IP_PER_WINDOW = 20;
66
+ /** 端点级每窗口上限:换一堆源地址也绕不开这个天花板。 */
67
+ export declare const WORKBENCH_TICKET_MAX_GLOBAL_PER_WINDOW = 120;
68
+ /** sha256 → base64url。导出仅为测试断言「文件里只有 hash 没有明文」。 */
69
+ export declare function hashWorkbenchTicket(ticket: string): string;
70
+ /** 尚无活跃 token 时的 generation 标签。此时 mint 出的票据也只能在「仍然没有
71
+ * token」的状态下兑换(兑不出 cookie,等于把用户送到登录墙),一旦 dashboard
72
+ * 发出了第一份 token,这些票即刻作废——fail closed 方向。 */
73
+ export declare const WORKBENCH_TICKET_NO_TOKEN_GENERATION = "none";
74
+ /**
75
+ * token 的 generation 标签:`sha256("workbench-ticket-generation:" + token)`。
76
+ *
77
+ * 只用于相等比较,不是凭证:它不可逆推 token(token 本身是高熵随机串),而且和
78
+ * 票据 hash 一起躺在同一个 0600 凭证文件里,不扩大任何暴露面。用 hash 而不是
79
+ * 计数器,是为了让 daemon(mint 侧)与 dashboard(验票侧)无需共享任何额外状态
80
+ * ——两边各自从同一份 token 现算即可,天然跨进程、跨重启一致。
81
+ */
82
+ export declare function workbenchTicketGeneration(token: string | null | undefined): string;
83
+ /**
84
+ * 从 `~/.botmux/.dashboard-token` 现算当前 generation。返回 `null` 表示**读不出
85
+ * 来**(目录/文件形状不安全等)——调用方一律 fail closed:mint 抛出(卡片退化成
86
+ * 无凭证登录链接),验票返回 false。「文件不存在」不算读不出来,它是合法的
87
+ * 「还没有 token」状态,归一到 {@link WORKBENCH_TICKET_NO_TOKEN_GENERATION}。
88
+ */
89
+ export declare function currentWorkbenchTokenGeneration(): string | null;
90
+ /**
91
+ * Mint 一张新票据并落盘,返回**明文票据**(只出现在返回值和最终 URL 里,不进
92
+ * 日志不进文件)。落盘失败直接抛出——文件是 daemon(mint) 与 dashboard(验票)
93
+ * 之间唯一的交接面,写不进去的票据必然兑换失败,调用方(workbench-link)捕获
94
+ * 后退化为不带票据的登录墙链接,而不是发出一个注定 404 的死链。
95
+ *
96
+ * 读不出当前 token 的 generation 时同样抛出:宁可发无凭证链接,也不发一张绑不上
97
+ * generation、语义不明的票。
98
+ */
99
+ export declare function mintWorkbenchTicket(nowMs?: number): string;
100
+ /**
101
+ * 验票:格式门 → generation 门 → 进程内缓存 → 快照(跨进程 / 重启恢复路径)。
102
+ * 任何读盘异常(目录形状不安全、文件损坏)一律 fail closed 返回 false,绝不因为
103
+ * 存储出问题就放行。hash 比对用 timingSafeEqual 且**不提前退出**,不给远端留计时
104
+ * 侧信道。
105
+ *
106
+ * `generation` 默认从磁盘现算;兑换端点会显式传入「即将下发的那份 token」的
107
+ * generation,把票据直接绑到真正要交出去的凭证上。传入 `null`(读不出来)即
108
+ * fail closed。
109
+ */
110
+ export declare function verifyWorkbenchTicket(ticket: string, nowMs?: number, generation?: string | null): boolean;
111
+ /**
112
+ * 定期清理:进程内 Map 直接清;落盘文件只在真有过期条目时才持锁重写(避免每个
113
+ * 节拍都空转写盘)。文件不存在 / 目录形状不安全时静默跳过——prune 是保洁工作,
114
+ * 不能因为存储异常把进程打崩。
115
+ */
116
+ export declare function pruneExpiredWorkbenchTickets(nowMs?: number): void;
117
+ /**
118
+ * 作废「不属于 `generation` 这一代」的全部票据(P1-6)。`botmux dashboard rotate`
119
+ * 落盘成功后调用,传入**新** token 的 generation。
120
+ *
121
+ * 这是保洁,不是防线:真正的防线是验票时的 generation 相等判定,即使这里一次都
122
+ * 没跑过(进程崩了、文件临时不可写),旧票也一样兑不出新 cookie。所以整段吞异常
123
+ * ——rotate 绝不能因为清理失败而失败。
124
+ */
125
+ export declare function revokeWorkbenchTicketsOutsideGeneration(generation: string, nowMs?: number): void;
126
+ /** 测试专用:清空进程内缓存、限流闸与定时器,模拟进程重启(文件保留)。 */
127
+ export declare function resetWorkbenchTicketStoreForTests(): void;
128
+ /** 测试专用诊断:真正打盘次数与负缓存命中次数。`diskReads` 必须随请求量保持
129
+ * 平坦,否则说明请求路径又退回到「每次同步读凭证文件」。 */
130
+ export declare function workbenchTicketStoreStatsForTests(): {
131
+ diskReads: number;
132
+ negativeHits: number;
133
+ negativeEntries: number;
134
+ };
135
+ /** 过期 / 无效票据的提示页正文(测试断言用同一常量)。零凭据、零回显:不含
136
+ * token、不含来访票据本身,只告诉用户下一步怎么拿新入口。 */
137
+ export declare const WORKBENCH_TICKET_EXPIRED_MESSAGE = "\u94FE\u63A5\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5728\u4F1A\u8BDD\u91CC\u91CD\u65B0\u53D1\u9001 /dashboard \u83B7\u53D6\u65B0\u5165\u53E3";
138
+ /** 触发限流时的提示页正文。同样零凭据、零回显,且不透露票据是否存在。 */
139
+ export declare const WORKBENCH_TICKET_RATE_LIMITED_MESSAGE = "\u5151\u6362\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
140
+ export interface WorkbenchTicketRedemptionDeps {
141
+ /** 当前活跃的 legacy 管理 token(`null` = dashboard 还没发过号)。 */
142
+ activeToken: () => string | null;
143
+ /** 反代跳数,语义同 {@link dashboardH5ClientIp}:0(默认)= 只认 socket 对端,
144
+ * 完全不看客户端可伪造的 `x-forwarded-for`。 */
145
+ trustedProxyHops?: number;
146
+ }
147
+ /**
148
+ * `GET /workbench-ticket/<ticket>` 兑换处理器。命中路径返回 true(响应已写完),
149
+ * 未命中返回 false 交还路由。语义对齐既有 `?t=` 流程(auth.ts 的
150
+ * `allow+set-cookie` 分支):验票通过 → 种同一个 legacy cookie → 302 进工作台。
151
+ *
152
+ * - 触发限流:429 + Retry-After + 无凭据提示页(在读任何盘之前就返回,见文件
153
+ * 顶部 P1-10)。名额按尝试消耗,与 LocateRateLimiter 一致。
154
+ * - 票据有效(含 generation 命中)且有活跃 token:
155
+ * `Set-Cookie: botmux_dashboard_token=<active>` + 302 `/#/agent-workbench`。
156
+ * - 票据有效但当前没有活跃 token(dashboard 从未发号):302 进工作台但不种
157
+ * cookie,用户面对正常登录墙。这是旧「读不到 token 就发裸链接」行为的对位,
158
+ * 绝不在匿名请求侧顺手铸造新 token。
159
+ * - 票据无效 / 过期 / 属于 rotate 之前那一代:410 + 无凭据中文提示页。
160
+ *
161
+ * 所有响应一律 no-store:兑换 URL 本身携带凭据性质的票据,任何中间缓存都不该
162
+ * 存它的响应。
163
+ */
164
+ export declare function handleWorkbenchTicketRedemption(req: IncomingMessage, res: ServerResponse, url: URL, deps: WorkbenchTicketRedemptionDeps): boolean;
165
+ //# sourceMappingURL=workbench-ticket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workbench-ticket.d.ts","sourceRoot":"","sources":["../../src/dashboard/workbench-ticket.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAYjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH;mBACmB;AACnB,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAanD;+DAC+D;AAC/D,eAAO,MAAM,yBAAyB,QAAkC,CAAC;AAazE,qBAAqB;AACrB,eAAO,MAAM,+BAA+B,QAAS,CAAC;AACtD,8CAA8C;AAC9C,eAAO,MAAM,sCAAsC,KAAK,CAAC;AACzD,gCAAgC;AAChC,eAAO,MAAM,sCAAsC,MAAM,CAAC;AA2D1D,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;4CAE4C;AAC5C,eAAO,MAAM,oCAAoC,SAAS,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKlF;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAS/D;AAwFD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAa,GAAG,MAAM,CA2B9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,SAAa,EAClB,UAAU,GAAE,MAAM,GAAG,IAAwC,GAC5D,OAAO,CAyCT;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,SAAa,GAAG,IAAI,CAgBrE;AAED;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,CACrD,UAAU,EAAE,MAAM,EAClB,KAAK,SAAa,GACjB,IAAI,CAiBN;AAED,yCAAyC;AACzC,wBAAgB,iCAAiC,IAAI,IAAI,CAaxD;AAED;kCACkC;AAClC,wBAAgB,iCAAiC,IAAI;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CAEA;AAID;qCACqC;AACrC,eAAO,MAAM,gCAAgC,yIACT,CAAC;AAErC,wCAAwC;AACxC,eAAO,MAAM,qCAAqC,yFAChC,CAAC;AAWnB,MAAM,WAAW,6BAA6B;IAC5C,uDAAuD;IACvD,WAAW,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACjC;yCACqC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,6BAA6B,GAClC,OAAO,CAmCT"}
@@ -0,0 +1,495 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { readSecureHostFileSync, withSecureHostParentSync, } from '../platform/secure-host-file.js';
5
+ import { buildSetCookie } from './auth.js';
6
+ import { DashboardH5ExchangeGate, dashboardH5ClientIp } from './h5-auth.js';
7
+ /**
8
+ * 工作台入口短时票据(P2-1)。
9
+ *
10
+ * 背景:`/dashboard` 飞书卡片的「打开工作台」按钮曾直接把长期 Dashboard 管理
11
+ * token 拼进 URL 写入持久化卡片——管理员门禁只保护首次投递,覆盖不了卡片历史、
12
+ * 转发和截图,等于把常驻凭证抄送给未来所有能看到这张卡的人。改为:卡片构建时
13
+ * 现 mint 一张 **30 分钟 TTL 的不可预测票据**,按钮链接只携带票据;访客打开
14
+ * `GET /workbench-ticket/<ticket>` 时由 dashboard 验票,通过则按既有 `?t=` 流程
15
+ * 同款种 legacy cookie 再 302 进工作台。到期后卡片历史/转发/截图里的链接一律
16
+ * 作废,只回一个无凭据的提示页。
17
+ *
18
+ * 设计要点:
19
+ * - **非一次性**:同一张卡片会被同一个管理员在 PC / 手机多端点开,票据在 TTL
20
+ * 内可重复兑换,到期即死。不做兑换计数,避免飞书链接预抓取把票据「烧」掉。
21
+ * - **绑定 token generation(P1-6)**:见下方「票据 ↔ token generation」小节。
22
+ * - **跨进程**:mint 发生在 daemon 进程(构建卡片处),验票发生在 dashboard
23
+ * 进程,两边靠 `~/.botmux/.workbench-tickets.json` 交接;进程内 Map 只是
24
+ * 本进程的快路径缓存。落盘复用 secure-host-file 的 0600 + 目录 0700 + 泄漏
25
+ * 检查惯例(与 `.dashboard-token` 同一套),读-并-写走跨进程文件锁,杜绝并发
26
+ * mint / prune 互相丢条目。
27
+ * - **文件里绝不存明文**:只存 `sha256(ticket)` 的 base64url + 过期时间 +
28
+ * generation 标签。拿到文件读权限的人无法还原票据;但能**写**这个文件就等于
29
+ * 能自铸门票,所以文件的安全形状(属主 / 0600 / 拒符号链接)由 secure-host-file
30
+ * 强制,不满足即 fail closed。
31
+ * - **重启不废票**:dashboard 重启后 Map 为空,验票落到文件比对 hash,刚发出
32
+ * 的卡片链接照常可用。
33
+ *
34
+ * ─── 票据 ↔ token generation(P1-6)────────────────────────────────────────
35
+ * 票据兑换出来的是「**当前**活跃 token」的 cookie。只按 TTL 判活时,rotate 之前
36
+ * 泄漏出去的票据能在 rotate 之后继续兑换——而且兑出来的是**新**管理 cookie。若
37
+ * rotate 的原因正是「链接/卡片泄漏了」,rotation 就此失去全部安全语义:管理员轮
38
+ * 换了凭证,攻击者拿旧票据无缝续上新凭证。
39
+ *
40
+ * 所以每张票在 mint 时钉住当时 token 的 generation 标签(`sha256("…" + token)`),
41
+ * 兑换时要求这个标签仍等于**此刻即将下发的那份 token** 的标签。rotate 换掉 token
42
+ * ⇒ 标签变 ⇒ 旧 generation 的票据一律 410。这条判定是构造性的:不依赖 rotate
43
+ * 路径记得去清理存量票据,清理({@link revokeWorkbenchTicketsOutsideGeneration})
44
+ * 只是把死条目从文件里扫掉的保洁。
45
+ *
46
+ * 同一 generation 内仍然**不是**一次性票:多端重复兑换的语义(P2-1)原样保留。
47
+ *
48
+ * ─── 公开兑换端点的 DoS 面(P1-10)────────────────────────────────────────
49
+ * 兑换端点在 auth gate 之前放行(票据自身就是凭证),任何人都能打。旧实现里每个
50
+ * 「形状合法但未知」的票据都会同步 realpath/stat/open/read/fstat 一遍凭证文件再
51
+ * 全表扫描——HOME 挂在 NFS 上时,几百个伪造票据就能把 event loop 焊死。现在三层
52
+ * 一起收口,且都保持 fail closed 与 timingSafeEqual 语义:
53
+ * 1. **限流**:每 IP + 全局滑动窗口(复用 H5 兑换口那套 gate 与可信代理取 IP
54
+ * 口径),拒绝在读任何盘之前发生;
55
+ * 2. **快照**:落盘内容在进程内缓存 {@link STORE_SNAPSHOT_TTL_MS},打盘次数只跟
56
+ * 时间走、不跟请求量走——请求量翻一万倍,打盘次数不变;
57
+ * 3. **负缓存**:验失败的 (票据 hash, generation) 短期记住,重复打同一张票连
58
+ * 全表扫描都省掉。负缓存条目钉住快照版本号,快照内容一变即失效,所以「刚
59
+ * mint 出来的新票被前一次探测顺手拉黑」最多只存在一个快照周期。
60
+ */
61
+ /** 票据有效期:30 分钟。够管理员从卡片点进去(含转发到手机再点),又短到卡片
62
+ * 历史里的旧链接很快失效。 */
63
+ export const WORKBENCH_TICKET_TTL_MS = 30 * 60_000;
64
+ /** 定期清理间隔。mint / 验票时也会顺手清,这只是兜底节拍。 */
65
+ const PRUNE_INTERVAL_MS = 5 * 60_000;
66
+ /** 落盘条目上限(按过期时间保最新)。正常量级是每次 /dashboard 卡片 mint 一张、
67
+ * 30 分钟自然过期,这里只防异常调用方把文件刷爆。 */
68
+ const MAX_PERSISTED_TICKETS = 256;
69
+ /** mint 出的票据形状:24 字节随机数的 base64url(32 字符)。验票先过这个格式
70
+ * 门,明显不是我们发的串直接拒绝,不进 hash 比对。 */
71
+ const TICKET_SHAPE = /^[A-Za-z0-9_-]{32,128}$/;
72
+ /** 兑换端点路径:`GET /workbench-ticket/<ticket>`。auth.ts 的公共面豁免与这里
73
+ * 必须保持同一个 pattern(那边按 `/^\/workbench-ticket\/[^/]+$/` 放行)。 */
74
+ export const WORKBENCH_TICKET_ROUTE_RE = /^\/workbench-ticket\/([^/]+)$/;
75
+ /** 落盘内容在进程内的最长复用时长。取 250ms:人从卡片点到兑换至少是几百毫秒到
76
+ * 几十秒级,跨进程「刚 mint 的票立刻可兑」的体感不受影响;而洪水攻击下打盘次数
77
+ * 被钉死在 4 次/秒,与请求速率彻底解耦。 */
78
+ const STORE_SNAPSHOT_TTL_MS = 250;
79
+ /** 验失败的 (hash, generation) 记住多久。上限之内重复打同一张废票不再全表扫。 */
80
+ const NEGATIVE_CACHE_TTL_MS = 60_000;
81
+ /** 负缓存条目上限(LRU)。攻击者用无穷多张废票也只能占住这么多条。 */
82
+ const MAX_NEGATIVE_CACHE_ENTRIES = 4_096;
83
+ /** 兑换端点限流:滑动窗口长度。 */
84
+ export const WORKBENCH_TICKET_RATE_WINDOW_MS = 60_000;
85
+ /** 单 IP 每窗口兑换次数上限。管理员多端打开 + 客户端链接预抓取远在这之下。 */
86
+ export const WORKBENCH_TICKET_MAX_PER_IP_PER_WINDOW = 20;
87
+ /** 端点级每窗口上限:换一堆源地址也绕不开这个天花板。 */
88
+ export const WORKBENCH_TICKET_MAX_GLOBAL_PER_WINDOW = 120;
89
+ /** 限流表跟踪的 IP 上限(超过按 LRU 淘汰,不做全表扫)。 */
90
+ const RATE_MAX_TRACKED_IPS = 4_096;
91
+ /** 进程内快路径缓存:hash → 过期时间 + generation。真相在文件里,这里只加速同
92
+ * 进程验票。 */
93
+ const liveTickets = new Map();
94
+ /** 负缓存:`hash|generation` → 失效时间 + 记录时的快照版本号。 */
95
+ const negativeCache = new Map();
96
+ /** 落盘内容的进程内快照。`null` 表示需要重新读盘。 */
97
+ let storeSnapshot = null;
98
+ /** 上次读到的原始文件内容,用来判断内容是否真的变了(变了才推进版本号)。 */
99
+ let storeRaw = null;
100
+ /** 快照版本号:内容每变一次 +1,负缓存据此整体失效。 */
101
+ let storeVersion = 0;
102
+ let pruneTimer = null;
103
+ /** 诊断计数:**任何**凭证文件的同步读次数 / 负缓存命中次数。前者必须随请求量
104
+ * 保持平坦——票据文件和 token 文件都算,免得「快照挡住了票据文件、却每个请求
105
+ * 还去读一次 token 文件」这种半吊子实现看起来是绿的。 */
106
+ let diskReads = 0;
107
+ let negativeHits = 0;
108
+ /**
109
+ * 兑换端点的进程内限流闸。复用 H5 兑换口那只 gate 的 `admit`(每 IP 滑动窗口 +
110
+ * 全局滑动窗口 + LRU 有界跟踪表),这里只是换一套额度:两个端点都是「auth gate
111
+ * 之前放行的公开面」,限流语义完全一样,没有理由再写一份。
112
+ */
113
+ function createRedemptionGate() {
114
+ return new DashboardH5ExchangeGate({
115
+ windowMs: WORKBENCH_TICKET_RATE_WINDOW_MS,
116
+ maxPerIpPerWindow: WORKBENCH_TICKET_MAX_PER_IP_PER_WINDOW,
117
+ maxGlobalPerWindow: WORKBENCH_TICKET_MAX_GLOBAL_PER_WINDOW,
118
+ maxTrackedIps: RATE_MAX_TRACKED_IPS,
119
+ });
120
+ }
121
+ let redemptionGate = createRedemptionGate();
122
+ function ticketsFilePath() {
123
+ return join(homedir(), '.botmux', '.workbench-tickets.json');
124
+ }
125
+ function dashboardTokenFilePath() {
126
+ return join(homedir(), '.botmux', '.dashboard-token');
127
+ }
128
+ /** sha256 → base64url。导出仅为测试断言「文件里只有 hash 没有明文」。 */
129
+ export function hashWorkbenchTicket(ticket) {
130
+ return createHash('sha256').update(ticket, 'utf8').digest('base64url');
131
+ }
132
+ /** 尚无活跃 token 时的 generation 标签。此时 mint 出的票据也只能在「仍然没有
133
+ * token」的状态下兑换(兑不出 cookie,等于把用户送到登录墙),一旦 dashboard
134
+ * 发出了第一份 token,这些票即刻作废——fail closed 方向。 */
135
+ export const WORKBENCH_TICKET_NO_TOKEN_GENERATION = 'none';
136
+ /**
137
+ * token 的 generation 标签:`sha256("workbench-ticket-generation:" + token)`。
138
+ *
139
+ * 只用于相等比较,不是凭证:它不可逆推 token(token 本身是高熵随机串),而且和
140
+ * 票据 hash 一起躺在同一个 0600 凭证文件里,不扩大任何暴露面。用 hash 而不是
141
+ * 计数器,是为了让 daemon(mint 侧)与 dashboard(验票侧)无需共享任何额外状态
142
+ * ——两边各自从同一份 token 现算即可,天然跨进程、跨重启一致。
143
+ */
144
+ export function workbenchTicketGeneration(token) {
145
+ if (!token)
146
+ return WORKBENCH_TICKET_NO_TOKEN_GENERATION;
147
+ return createHash('sha256')
148
+ .update(`workbench-ticket-generation:${token}`, 'utf8')
149
+ .digest('base64url');
150
+ }
151
+ /**
152
+ * 从 `~/.botmux/.dashboard-token` 现算当前 generation。返回 `null` 表示**读不出
153
+ * 来**(目录/文件形状不安全等)——调用方一律 fail closed:mint 抛出(卡片退化成
154
+ * 无凭证登录链接),验票返回 false。「文件不存在」不算读不出来,它是合法的
155
+ * 「还没有 token」状态,归一到 {@link WORKBENCH_TICKET_NO_TOKEN_GENERATION}。
156
+ */
157
+ export function currentWorkbenchTokenGeneration() {
158
+ try {
159
+ diskReads += 1;
160
+ return workbenchTicketGeneration(readSecureHostFileSync(dashboardTokenFilePath(), 256)?.trim() || null);
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ function parsePersisted(raw) {
167
+ if (!raw)
168
+ return [];
169
+ let parsed;
170
+ try {
171
+ parsed = JSON.parse(raw);
172
+ }
173
+ catch {
174
+ return [];
175
+ }
176
+ if (!Array.isArray(parsed))
177
+ return [];
178
+ const out = [];
179
+ for (const entry of parsed) {
180
+ if (!entry || typeof entry !== 'object')
181
+ continue;
182
+ const h = entry.h;
183
+ const exp = entry.exp;
184
+ const g = entry.g;
185
+ // 没有 generation 的条目(旧版本残留 / 手工伪造)一律丢弃:绑定关系缺失就
186
+ // 等于不可验证,fail closed。票据 TTL 只有 30 分钟,升级期间最多让一张卡
187
+ // 片链接提前失效。
188
+ if (typeof h === 'string' && h.length > 0
189
+ && typeof exp === 'number' && Number.isFinite(exp)
190
+ && typeof g === 'string' && g.length > 0) {
191
+ out.push({ h, exp, g });
192
+ }
193
+ }
194
+ return out;
195
+ }
196
+ function ensurePruneTimer() {
197
+ if (pruneTimer)
198
+ return;
199
+ // unref:清理节拍不该拖住进程退出。回调吞错——prune 是保洁,不是正确性关键路径
200
+ // (验票自身按 exp 判断过期,从不依赖 prune 已经跑过)。
201
+ pruneTimer = setInterval(() => {
202
+ try {
203
+ pruneExpiredWorkbenchTickets();
204
+ }
205
+ catch { /* best effort */ }
206
+ }, PRUNE_INTERVAL_MS);
207
+ pruneTimer.unref();
208
+ }
209
+ function pruneLiveMap(nowMs) {
210
+ for (const [h, entry] of liveTickets) {
211
+ if (entry.exp <= nowMs)
212
+ liveTickets.delete(h);
213
+ }
214
+ }
215
+ /** 本进程刚写过盘:快照作废并推进版本号(连带让负缓存整体失效)。 */
216
+ function invalidateStoreSnapshot() {
217
+ storeSnapshot = null;
218
+ storeRaw = null;
219
+ storeVersion += 1;
220
+ }
221
+ /**
222
+ * 取落盘内容的快照:{@link STORE_SNAPSHOT_TTL_MS} 之内直接复用上一次的解析结果,
223
+ * 过期才真正打一次盘。返回 `null` 表示这次读盘失败(形状不安全等)——调用方
224
+ * fail closed,且**不得**据此写负缓存(存储抖动不该把好票拉黑)。
225
+ *
226
+ * 时钟是注入的(验票传入 `nowMs`),所以「快照年龄为负」意味着调用方在用一个更
227
+ * 早的时间点,此时一律重读,避免测试/回拨时钟拿到错误的缓存。
228
+ */
229
+ function loadStoreSnapshot(nowMs) {
230
+ if (storeSnapshot) {
231
+ const age = nowMs - storeSnapshot.loadedAt;
232
+ if (age >= 0 && age < STORE_SNAPSHOT_TTL_MS)
233
+ return storeSnapshot;
234
+ }
235
+ let raw;
236
+ try {
237
+ diskReads += 1;
238
+ raw = readSecureHostFileSync(ticketsFilePath());
239
+ }
240
+ catch {
241
+ invalidateStoreSnapshot();
242
+ return null;
243
+ }
244
+ if (raw !== storeRaw) {
245
+ storeRaw = raw;
246
+ storeVersion += 1;
247
+ }
248
+ storeSnapshot = { entries: parsePersisted(raw), loadedAt: nowMs };
249
+ return storeSnapshot;
250
+ }
251
+ function rememberNegative(key, nowMs) {
252
+ // delete + set = LRU 重排;表满时淘汰最久未用的一条,恒定时间,永不全表扫。
253
+ if (!negativeCache.delete(key) && negativeCache.size >= MAX_NEGATIVE_CACHE_ENTRIES) {
254
+ const oldest = negativeCache.keys().next();
255
+ if (!oldest.done)
256
+ negativeCache.delete(oldest.value);
257
+ }
258
+ negativeCache.set(key, { until: nowMs + NEGATIVE_CACHE_TTL_MS, version: storeVersion });
259
+ }
260
+ /**
261
+ * Mint 一张新票据并落盘,返回**明文票据**(只出现在返回值和最终 URL 里,不进
262
+ * 日志不进文件)。落盘失败直接抛出——文件是 daemon(mint) 与 dashboard(验票)
263
+ * 之间唯一的交接面,写不进去的票据必然兑换失败,调用方(workbench-link)捕获
264
+ * 后退化为不带票据的登录墙链接,而不是发出一个注定 404 的死链。
265
+ *
266
+ * 读不出当前 token 的 generation 时同样抛出:宁可发无凭证链接,也不发一张绑不上
267
+ * generation、语义不明的票。
268
+ */
269
+ export function mintWorkbenchTicket(nowMs = Date.now()) {
270
+ const generation = currentWorkbenchTokenGeneration();
271
+ if (generation === null) {
272
+ throw new Error('workbench ticket mint aborted: dashboard token generation unreadable');
273
+ }
274
+ const ticket = randomBytes(24).toString('base64url');
275
+ const hash = hashWorkbenchTicket(ticket);
276
+ const exp = nowMs + WORKBENCH_TICKET_TTL_MS;
277
+ // 读-并-写整段持跨进程文件锁:并发的另一处 mint / 定期 prune 不会把这条刚写的
278
+ // 票据覆盖掉(与 loadOrCreatePersistedToken 的 get-or-create 同一套串行化)。
279
+ withSecureHostParentSync(ticketsFilePath(), (parent) => parent.withLeafLock(() => {
280
+ // 顺手扔掉过期条目**和**上一代 token 的条目:后者已经不可能验过,留着只是
281
+ // 占位。这也让 rotate 后的文件在下一次 mint 时自愈,不依赖 revoke 跑过。
282
+ const entries = parsePersisted(parent.readLeaf())
283
+ .filter((e) => e.exp > nowMs && e.g === generation);
284
+ entries.push({ h: hash, exp, g: generation });
285
+ entries.sort((a, b) => b.exp - a.exp);
286
+ parent.writeLeaf(JSON.stringify(entries.slice(0, MAX_PERSISTED_TICKETS)));
287
+ }));
288
+ // 文件写成功才进缓存:Map 里绝不出现 dashboard 进程看不见的「幽灵票」。
289
+ invalidateStoreSnapshot();
290
+ pruneLiveMap(nowMs);
291
+ liveTickets.set(hash, { exp, g: generation });
292
+ ensurePruneTimer();
293
+ return ticket;
294
+ }
295
+ /**
296
+ * 验票:格式门 → generation 门 → 进程内缓存 → 快照(跨进程 / 重启恢复路径)。
297
+ * 任何读盘异常(目录形状不安全、文件损坏)一律 fail closed 返回 false,绝不因为
298
+ * 存储出问题就放行。hash 比对用 timingSafeEqual 且**不提前退出**,不给远端留计时
299
+ * 侧信道。
300
+ *
301
+ * `generation` 默认从磁盘现算;兑换端点会显式传入「即将下发的那份 token」的
302
+ * generation,把票据直接绑到真正要交出去的凭证上。传入 `null`(读不出来)即
303
+ * fail closed。
304
+ */
305
+ export function verifyWorkbenchTicket(ticket, nowMs = Date.now(), generation = currentWorkbenchTokenGeneration()) {
306
+ if (typeof ticket !== 'string' || !TICKET_SHAPE.test(ticket))
307
+ return false;
308
+ if (generation === null)
309
+ return false;
310
+ const hash = hashWorkbenchTicket(ticket);
311
+ pruneLiveMap(nowMs);
312
+ const cached = liveTickets.get(hash);
313
+ if (cached !== undefined && cached.exp > nowMs && cached.g === generation) {
314
+ ensurePruneTimer();
315
+ return true;
316
+ }
317
+ // 先(按时间闸)刷新快照再查负缓存:否则负缓存会把自己钉死在一个旧版本号上,
318
+ // 新 mint 的票据永远等不到重新判定。
319
+ const snapshot = loadStoreSnapshot(nowMs);
320
+ if (!snapshot)
321
+ return false;
322
+ const negativeKey = `${hash}|${generation}`;
323
+ const negative = negativeCache.get(negativeKey);
324
+ if (negative !== undefined && negative.version === storeVersion && negative.until > nowMs) {
325
+ negativeHits += 1;
326
+ return false;
327
+ }
328
+ const hashBuf = Buffer.from(hash, 'utf8');
329
+ let matched;
330
+ for (const entry of snapshot.entries) {
331
+ const entryBuf = Buffer.from(entry.h, 'utf8');
332
+ if (entryBuf.length !== hashBuf.length)
333
+ continue;
334
+ // 不 break:把 hash 命中位置从响应时间里抹掉。条目数有上限,全量扫描便宜。
335
+ if (timingSafeEqual(entryBuf, hashBuf)
336
+ && entry.g === generation
337
+ && (matched === undefined || entry.exp > matched.exp)) {
338
+ matched = entry;
339
+ }
340
+ }
341
+ if (matched !== undefined && matched.exp > nowMs) {
342
+ liveTickets.set(hash, { exp: matched.exp, g: matched.g });
343
+ ensurePruneTimer();
344
+ return true;
345
+ }
346
+ rememberNegative(negativeKey, nowMs);
347
+ return false;
348
+ }
349
+ /**
350
+ * 定期清理:进程内 Map 直接清;落盘文件只在真有过期条目时才持锁重写(避免每个
351
+ * 节拍都空转写盘)。文件不存在 / 目录形状不安全时静默跳过——prune 是保洁工作,
352
+ * 不能因为存储异常把进程打崩。
353
+ */
354
+ export function pruneExpiredWorkbenchTickets(nowMs = Date.now()) {
355
+ pruneLiveMap(nowMs);
356
+ try {
357
+ const current = parsePersisted(readSecureHostFileSync(ticketsFilePath()));
358
+ if (!current.some((e) => e.exp <= nowMs))
359
+ return;
360
+ withSecureHostParentSync(ticketsFilePath(), (parent) => parent.withLeafLock(() => {
361
+ // 锁内重读:以持锁瞬间的真实内容为准,避免覆盖并发 mint 刚追加的条目。
362
+ const entries = parsePersisted(parent.readLeaf()).filter((e) => e.exp > nowMs);
363
+ parent.writeLeaf(JSON.stringify(entries));
364
+ }));
365
+ invalidateStoreSnapshot();
366
+ }
367
+ catch {
368
+ /* best effort */
369
+ }
370
+ }
371
+ /**
372
+ * 作废「不属于 `generation` 这一代」的全部票据(P1-6)。`botmux dashboard rotate`
373
+ * 落盘成功后调用,传入**新** token 的 generation。
374
+ *
375
+ * 这是保洁,不是防线:真正的防线是验票时的 generation 相等判定,即使这里一次都
376
+ * 没跑过(进程崩了、文件临时不可写),旧票也一样兑不出新 cookie。所以整段吞异常
377
+ * ——rotate 绝不能因为清理失败而失败。
378
+ */
379
+ export function revokeWorkbenchTicketsOutsideGeneration(generation, nowMs = Date.now()) {
380
+ for (const [h, entry] of liveTickets) {
381
+ if (entry.g !== generation)
382
+ liveTickets.delete(h);
383
+ }
384
+ try {
385
+ withSecureHostParentSync(ticketsFilePath(), (parent) => parent.withLeafLock(() => {
386
+ const raw = parent.readLeaf();
387
+ if (raw === null)
388
+ return; // 还没有票据文件:无需(也不该)凭空创建
389
+ const entries = parsePersisted(raw).filter((e) => e.g === generation && e.exp > nowMs);
390
+ parent.writeLeaf(JSON.stringify(entries));
391
+ }));
392
+ }
393
+ catch {
394
+ /* best effort:generation 判定已经让旧票验不过 */
395
+ }
396
+ invalidateStoreSnapshot();
397
+ }
398
+ /** 测试专用:清空进程内缓存、限流闸与定时器,模拟进程重启(文件保留)。 */
399
+ export function resetWorkbenchTicketStoreForTests() {
400
+ liveTickets.clear();
401
+ negativeCache.clear();
402
+ storeSnapshot = null;
403
+ storeRaw = null;
404
+ storeVersion = 0;
405
+ diskReads = 0;
406
+ negativeHits = 0;
407
+ redemptionGate = createRedemptionGate();
408
+ if (pruneTimer) {
409
+ clearInterval(pruneTimer);
410
+ pruneTimer = null;
411
+ }
412
+ }
413
+ /** 测试专用诊断:真正打盘次数与负缓存命中次数。`diskReads` 必须随请求量保持
414
+ * 平坦,否则说明请求路径又退回到「每次同步读凭证文件」。 */
415
+ export function workbenchTicketStoreStatsForTests() {
416
+ return { diskReads, negativeHits, negativeEntries: negativeCache.size };
417
+ }
418
+ // ─── 兑换端点 ────────────────────────────────────────────────────────────────
419
+ /** 过期 / 无效票据的提示页正文(测试断言用同一常量)。零凭据、零回显:不含
420
+ * token、不含来访票据本身,只告诉用户下一步怎么拿新入口。 */
421
+ export const WORKBENCH_TICKET_EXPIRED_MESSAGE = '链接已过期,请在会话里重新发送 /dashboard 获取新入口';
422
+ /** 触发限流时的提示页正文。同样零凭据、零回显,且不透露票据是否存在。 */
423
+ export const WORKBENCH_TICKET_RATE_LIMITED_MESSAGE = '兑换请求过于频繁,请稍后再试';
424
+ function noticePageHtml(title, message) {
425
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">`
426
+ + `<meta name="viewport" content="width=device-width, initial-scale=1">`
427
+ + `<title>${title}</title></head>`
428
+ + `<body style="font-family:system-ui,sans-serif;margin:0;display:flex;align-items:center;justify-content:center;min-height:100vh;background:#0b0e14;color:#e6e6e6">`
429
+ + `<p style="padding:24px;text-align:center;line-height:1.8">${message}</p>`
430
+ + `</body></html>`;
431
+ }
432
+ /**
433
+ * `GET /workbench-ticket/<ticket>` 兑换处理器。命中路径返回 true(响应已写完),
434
+ * 未命中返回 false 交还路由。语义对齐既有 `?t=` 流程(auth.ts 的
435
+ * `allow+set-cookie` 分支):验票通过 → 种同一个 legacy cookie → 302 进工作台。
436
+ *
437
+ * - 触发限流:429 + Retry-After + 无凭据提示页(在读任何盘之前就返回,见文件
438
+ * 顶部 P1-10)。名额按尝试消耗,与 LocateRateLimiter 一致。
439
+ * - 票据有效(含 generation 命中)且有活跃 token:
440
+ * `Set-Cookie: botmux_dashboard_token=<active>` + 302 `/#/agent-workbench`。
441
+ * - 票据有效但当前没有活跃 token(dashboard 从未发号):302 进工作台但不种
442
+ * cookie,用户面对正常登录墙。这是旧「读不到 token 就发裸链接」行为的对位,
443
+ * 绝不在匿名请求侧顺手铸造新 token。
444
+ * - 票据无效 / 过期 / 属于 rotate 之前那一代:410 + 无凭据中文提示页。
445
+ *
446
+ * 所有响应一律 no-store:兑换 URL 本身携带凭据性质的票据,任何中间缓存都不该
447
+ * 存它的响应。
448
+ */
449
+ export function handleWorkbenchTicketRedemption(req, res, url, deps) {
450
+ if (req.method !== 'GET')
451
+ return false;
452
+ const match = url.pathname.match(WORKBENCH_TICKET_ROUTE_RE);
453
+ if (!match)
454
+ return false;
455
+ const admission = redemptionGate.admit(dashboardH5ClientIp(req, deps.trustedProxyHops ?? 0));
456
+ if (!admission.ok) {
457
+ res.writeHead(429, {
458
+ 'content-type': 'text/html; charset=utf-8',
459
+ 'cache-control': 'no-store',
460
+ 'retry-after': String(Math.max(1, Math.ceil(admission.retryAfterMs / 1000))),
461
+ });
462
+ res.end(noticePageHtml('请求过于频繁', WORKBENCH_TICKET_RATE_LIMITED_MESSAGE));
463
+ return true;
464
+ }
465
+ let ticket = match[1];
466
+ try {
467
+ ticket = decodeURIComponent(ticket);
468
+ }
469
+ catch { /* 保留原样进验票(会被格式门拒掉) */ }
470
+ let token = null;
471
+ try {
472
+ token = deps.activeToken();
473
+ }
474
+ catch {
475
+ token = null;
476
+ }
477
+ // 绑定的是「此刻真正要交出去的这份 token」的 generation:rotate 之后旧票据既
478
+ // 兑不出新 cookie,也不会退化成「无 cookie 但仍然 302」的半通过。
479
+ if (verifyWorkbenchTicket(ticket, Date.now(), workbenchTicketGeneration(token))) {
480
+ res.writeHead(302, {
481
+ location: '/#/agent-workbench',
482
+ 'cache-control': 'no-store',
483
+ ...(token ? { 'set-cookie': buildSetCookie(token) } : {}),
484
+ });
485
+ res.end();
486
+ return true;
487
+ }
488
+ res.writeHead(410, {
489
+ 'content-type': 'text/html; charset=utf-8',
490
+ 'cache-control': 'no-store',
491
+ });
492
+ res.end(noticePageHtml('入口已过期', WORKBENCH_TICKET_EXPIRED_MESSAGE));
493
+ return true;
494
+ }
495
+ //# sourceMappingURL=workbench-ticket.js.map