botmux 2.111.0 → 2.112.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 (1041) hide show
  1. package/README.en.md +19 -7
  2. package/README.md +19 -7
  3. package/dist/adapters/adopt-route.d.ts.map +1 -1
  4. package/dist/adapters/adopt-route.js +2 -1
  5. package/dist/adapters/adopt-route.js.map +1 -1
  6. package/dist/adapters/backend/herdr-backend.d.ts +29 -0
  7. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  8. package/dist/adapters/backend/herdr-backend.js +167 -0
  9. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  10. package/dist/adapters/backend/riff-backend.js +2 -2
  11. package/dist/adapters/backend/sandbox.d.ts +61 -6
  12. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  13. package/dist/adapters/backend/sandbox.js +235 -43
  14. package/dist/adapters/backend/sandbox.js.map +1 -1
  15. package/dist/adapters/backend/tmux-backend.d.ts +1 -0
  16. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  17. package/dist/adapters/backend/tmux-backend.js +1 -0
  18. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  19. package/dist/adapters/cli/claude-code.d.ts +2 -0
  20. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  21. package/dist/adapters/cli/claude-code.js +7 -0
  22. package/dist/adapters/cli/claude-code.js.map +1 -1
  23. package/dist/adapters/cli/codex-app-turn.d.ts +16 -0
  24. package/dist/adapters/cli/codex-app-turn.d.ts.map +1 -1
  25. package/dist/adapters/cli/codex-app-turn.js +26 -0
  26. package/dist/adapters/cli/codex-app-turn.js.map +1 -1
  27. package/dist/adapters/cli/codex.d.ts.map +1 -1
  28. package/dist/adapters/cli/codex.js +1 -0
  29. package/dist/adapters/cli/codex.js.map +1 -1
  30. package/dist/adapters/cli/grok.d.ts +8 -6
  31. package/dist/adapters/cli/grok.d.ts.map +1 -1
  32. package/dist/adapters/cli/grok.js +14 -6
  33. package/dist/adapters/cli/grok.js.map +1 -1
  34. package/dist/adapters/cli/read-isolation.d.ts +40 -14
  35. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  36. package/dist/adapters/cli/read-isolation.js +116 -19
  37. package/dist/adapters/cli/read-isolation.js.map +1 -1
  38. package/dist/adapters/cli/runner-control-channel.d.ts +32 -0
  39. package/dist/adapters/cli/runner-control-channel.d.ts.map +1 -0
  40. package/dist/adapters/cli/runner-control-channel.js +104 -0
  41. package/dist/adapters/cli/runner-control-channel.js.map +1 -0
  42. package/dist/adapters/cli/shared-hints.d.ts +1 -1
  43. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  44. package/dist/adapters/cli/shared-hints.js +9 -0
  45. package/dist/adapters/cli/shared-hints.js.map +1 -1
  46. package/dist/adapters/cli/traex.d.ts.map +1 -1
  47. package/dist/adapters/cli/traex.js +100 -64
  48. package/dist/adapters/cli/traex.js.map +1 -1
  49. package/dist/adapters/cli/types.d.ts +13 -0
  50. package/dist/adapters/cli/types.d.ts.map +1 -1
  51. package/dist/bot-registry.d.ts +36 -27
  52. package/dist/bot-registry.d.ts.map +1 -1
  53. package/dist/bot-registry.js +354 -8
  54. package/dist/bot-registry.js.map +1 -1
  55. package/dist/cli/saved-workflow.d.ts +25 -0
  56. package/dist/cli/saved-workflow.d.ts.map +1 -0
  57. package/dist/cli/saved-workflow.js +338 -0
  58. package/dist/cli/saved-workflow.js.map +1 -0
  59. package/dist/cli/send-dispatch.d.ts +18 -3
  60. package/dist/cli/send-dispatch.d.ts.map +1 -1
  61. package/dist/cli/send-dispatch.js +22 -3
  62. package/dist/cli/send-dispatch.js.map +1 -1
  63. package/dist/cli/v3-run-cancel.d.ts +47 -0
  64. package/dist/cli/v3-run-cancel.d.ts.map +1 -0
  65. package/dist/cli/v3-run-cancel.js +96 -0
  66. package/dist/cli/v3-run-cancel.js.map +1 -0
  67. package/dist/cli/vc-agent.d.ts.map +1 -1
  68. package/dist/cli/vc-agent.js +54 -1
  69. package/dist/cli/vc-agent.js.map +1 -1
  70. package/dist/cli/workflow-migration.d.ts +39 -0
  71. package/dist/cli/workflow-migration.d.ts.map +1 -0
  72. package/dist/cli/workflow-migration.js +302 -0
  73. package/dist/cli/workflow-migration.js.map +1 -0
  74. package/dist/cli/workflow-run-archive.d.ts +29 -0
  75. package/dist/cli/workflow-run-archive.d.ts.map +1 -0
  76. package/dist/cli/workflow-run-archive.js +183 -0
  77. package/dist/cli/workflow-run-archive.js.map +1 -0
  78. package/dist/cli/workflow.d.ts +5 -10
  79. package/dist/cli/workflow.d.ts.map +1 -1
  80. package/dist/cli/workflow.js +85 -764
  81. package/dist/cli/workflow.js.map +1 -1
  82. package/dist/cli.d.ts.map +1 -1
  83. package/dist/cli.js +1018 -191
  84. package/dist/cli.js.map +1 -1
  85. package/dist/codex-app-runner.js +30 -21
  86. package/dist/codex-app-runner.js.map +1 -1
  87. package/dist/core/command-handler.d.ts.map +1 -1
  88. package/dist/core/command-handler.js +21 -9
  89. package/dist/core/command-handler.js.map +1 -1
  90. package/dist/core/current-turn-provenance.d.ts +39 -0
  91. package/dist/core/current-turn-provenance.d.ts.map +1 -0
  92. package/dist/core/current-turn-provenance.js +122 -0
  93. package/dist/core/current-turn-provenance.js.map +1 -0
  94. package/dist/core/daemon-ipc-auth.d.ts +20 -0
  95. package/dist/core/daemon-ipc-auth.d.ts.map +1 -0
  96. package/dist/core/daemon-ipc-auth.js +44 -0
  97. package/dist/core/daemon-ipc-auth.js.map +1 -0
  98. package/dist/core/daemon-ipc-session-auth.d.ts +37 -0
  99. package/dist/core/daemon-ipc-session-auth.d.ts.map +1 -0
  100. package/dist/core/daemon-ipc-session-auth.js +35 -0
  101. package/dist/core/daemon-ipc-session-auth.js.map +1 -0
  102. package/dist/core/dashboard-command/index.d.ts +0 -2
  103. package/dist/core/dashboard-command/index.d.ts.map +1 -1
  104. package/dist/core/dashboard-command/index.js +2 -2
  105. package/dist/core/dashboard-command/index.js.map +1 -1
  106. package/dist/core/dashboard-command/stub.d.ts +1 -1
  107. package/dist/core/dashboard-command/stub.d.ts.map +1 -1
  108. package/dist/core/dashboard-command/stub.js +0 -1
  109. package/dist/core/dashboard-command/stub.js.map +1 -1
  110. package/dist/core/dashboard-ipc-server.d.ts +11 -2
  111. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  112. package/dist/core/dashboard-ipc-server.js +266 -41
  113. package/dist/core/dashboard-ipc-server.js.map +1 -1
  114. package/dist/core/dashboard-secret.d.ts +3 -0
  115. package/dist/core/dashboard-secret.d.ts.map +1 -0
  116. package/dist/core/dashboard-secret.js +7 -0
  117. package/dist/core/dashboard-secret.js.map +1 -0
  118. package/dist/core/data-dir.d.ts +24 -0
  119. package/dist/core/data-dir.d.ts.map +1 -0
  120. package/dist/core/data-dir.js +48 -0
  121. package/dist/core/data-dir.js.map +1 -0
  122. package/dist/core/inflight-input-tracker.d.ts +4 -2
  123. package/dist/core/inflight-input-tracker.d.ts.map +1 -1
  124. package/dist/core/inflight-input-tracker.js +6 -5
  125. package/dist/core/inflight-input-tracker.js.map +1 -1
  126. package/dist/core/inject-queue-policy.d.ts +70 -0
  127. package/dist/core/inject-queue-policy.d.ts.map +1 -0
  128. package/dist/core/inject-queue-policy.js +30 -0
  129. package/dist/core/inject-queue-policy.js.map +1 -0
  130. package/dist/core/maintenance.d.ts +1 -1
  131. package/dist/core/maintenance.d.ts.map +1 -1
  132. package/dist/core/maintenance.js +3 -2
  133. package/dist/core/maintenance.js.map +1 -1
  134. package/dist/core/managed-origin-capability.d.ts +30 -0
  135. package/dist/core/managed-origin-capability.d.ts.map +1 -0
  136. package/dist/core/managed-origin-capability.js +88 -0
  137. package/dist/core/managed-origin-capability.js.map +1 -0
  138. package/dist/core/role-library.d.ts +15 -0
  139. package/dist/core/role-library.d.ts.map +1 -0
  140. package/dist/core/role-library.js +75 -0
  141. package/dist/core/role-library.js.map +1 -0
  142. package/dist/core/session-cwd.d.ts +14 -0
  143. package/dist/core/session-cwd.d.ts.map +1 -0
  144. package/dist/core/session-cwd.js +17 -0
  145. package/dist/core/session-cwd.js.map +1 -0
  146. package/dist/core/session-manager.d.ts +4 -1
  147. package/dist/core/session-manager.d.ts.map +1 -1
  148. package/dist/core/session-manager.js +27 -8
  149. package/dist/core/session-manager.js.map +1 -1
  150. package/dist/core/session-marker.d.ts +22 -0
  151. package/dist/core/session-marker.d.ts.map +1 -1
  152. package/dist/core/session-marker.js +185 -20
  153. package/dist/core/session-marker.js.map +1 -1
  154. package/dist/core/slash-inject.d.ts +15 -0
  155. package/dist/core/slash-inject.d.ts.map +1 -0
  156. package/dist/core/slash-inject.js +25 -0
  157. package/dist/core/slash-inject.js.map +1 -0
  158. package/dist/core/terminal-url.d.ts +1 -0
  159. package/dist/core/terminal-url.d.ts.map +1 -1
  160. package/dist/core/terminal-url.js +14 -8
  161. package/dist/core/terminal-url.js.map +1 -1
  162. package/dist/core/terminal-write-auth.d.ts +26 -0
  163. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  164. package/dist/core/terminal-write-auth.js +48 -3
  165. package/dist/core/terminal-write-auth.js.map +1 -1
  166. package/dist/core/trigger-session.d.ts +24 -1
  167. package/dist/core/trigger-session.d.ts.map +1 -1
  168. package/dist/core/trigger-session.js +106 -15
  169. package/dist/core/trigger-session.js.map +1 -1
  170. package/dist/core/types.d.ts +26 -1
  171. package/dist/core/types.d.ts.map +1 -1
  172. package/dist/core/types.js +10 -0
  173. package/dist/core/types.js.map +1 -1
  174. package/dist/core/worker-pool.d.ts +65 -2
  175. package/dist/core/worker-pool.d.ts.map +1 -1
  176. package/dist/core/worker-pool.js +459 -39
  177. package/dist/core/worker-pool.js.map +1 -1
  178. package/dist/daemon.d.ts +249 -8
  179. package/dist/daemon.d.ts.map +1 -1
  180. package/dist/daemon.js +7383 -1195
  181. package/dist/daemon.js.map +1 -1
  182. package/dist/dashboard/aggregator.d.ts +1 -1
  183. package/dist/dashboard/aggregator.d.ts.map +1 -1
  184. package/dist/dashboard/aggregator.js +2 -2
  185. package/dist/dashboard/aggregator.js.map +1 -1
  186. package/dist/dashboard/auth.d.ts +3 -8
  187. package/dist/dashboard/auth.d.ts.map +1 -1
  188. package/dist/dashboard/auth.js +63 -22
  189. package/dist/dashboard/auth.js.map +1 -1
  190. package/dist/dashboard/bot-onboarding.d.ts +5 -0
  191. package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
  192. package/dist/dashboard/bot-onboarding.js +37 -0
  193. package/dist/dashboard/bot-onboarding.js.map +1 -1
  194. package/dist/dashboard/connector-api.d.ts.map +1 -1
  195. package/dist/dashboard/connector-api.js +42 -2
  196. package/dist/dashboard/connector-api.js.map +1 -1
  197. package/dist/dashboard/daemon-internal-api.d.ts +0 -2
  198. package/dist/dashboard/daemon-internal-api.d.ts.map +1 -1
  199. package/dist/dashboard/daemon-internal-api.js +26 -93
  200. package/dist/dashboard/daemon-internal-api.js.map +1 -1
  201. package/dist/dashboard/daemon-internal-client.d.ts.map +1 -1
  202. package/dist/dashboard/daemon-internal-client.js +2 -3
  203. package/dist/dashboard/daemon-internal-client.js.map +1 -1
  204. package/dist/dashboard/federation-api.js +1 -1
  205. package/dist/dashboard/federation-api.js.map +1 -1
  206. package/dist/dashboard/federation-spoke-api.js +1 -1
  207. package/dist/dashboard/federation-spoke-api.js.map +1 -1
  208. package/dist/dashboard/history-senders.d.ts +3 -0
  209. package/dist/dashboard/history-senders.d.ts.map +1 -1
  210. package/dist/dashboard/history-senders.js.map +1 -1
  211. package/dist/dashboard/http.d.ts +4 -0
  212. package/dist/dashboard/http.d.ts.map +1 -0
  213. package/dist/dashboard/http.js +6 -0
  214. package/dist/dashboard/http.js.map +1 -0
  215. package/dist/dashboard/registry.d.ts +4 -0
  216. package/dist/dashboard/registry.d.ts.map +1 -1
  217. package/dist/dashboard/registry.js.map +1 -1
  218. package/dist/dashboard/trigger-api.js +1 -1
  219. package/dist/dashboard/trigger-api.js.map +1 -1
  220. package/dist/dashboard/v3-runs-api.d.ts +13 -10
  221. package/dist/dashboard/v3-runs-api.d.ts.map +1 -1
  222. package/dist/dashboard/v3-runs-api.js +121 -4
  223. package/dist/dashboard/v3-runs-api.js.map +1 -1
  224. package/dist/dashboard/vc-consumer-profiles-api.d.ts +105 -0
  225. package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -0
  226. package/dist/dashboard/vc-consumer-profiles-api.js +312 -0
  227. package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -0
  228. package/dist/dashboard/web/app.d.ts.map +1 -1
  229. package/dist/dashboard/web/app.js +7 -6
  230. package/dist/dashboard/web/app.js.map +1 -1
  231. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  232. package/dist/dashboard/web/bot-defaults-page.js +9 -14
  233. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  234. package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
  235. package/dist/dashboard/web/bot-onboarding.js +7 -3
  236. package/dist/dashboard/web/bot-onboarding.js.map +1 -1
  237. package/dist/dashboard/web/connectors-page.d.ts +5 -0
  238. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  239. package/dist/dashboard/web/connectors-page.js +16 -12
  240. package/dist/dashboard/web/connectors-page.js.map +1 -1
  241. package/dist/dashboard/web/create-session-entry.d.ts +4 -0
  242. package/dist/dashboard/web/create-session-entry.d.ts.map +1 -0
  243. package/dist/dashboard/web/create-session-entry.js +17 -0
  244. package/dist/dashboard/web/create-session-entry.js.map +1 -0
  245. package/dist/dashboard/web/dashboard-components.d.ts +5 -0
  246. package/dist/dashboard/web/dashboard-components.d.ts.map +1 -1
  247. package/dist/dashboard/web/dashboard-components.js +29 -4
  248. package/dist/dashboard/web/dashboard-components.js.map +1 -1
  249. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  250. package/dist/dashboard/web/dashboard-routes.js +0 -1
  251. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  252. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  253. package/dist/dashboard/web/i18n.js +192 -382
  254. package/dist/dashboard/web/i18n.js.map +1 -1
  255. package/dist/dashboard/web/preferences.d.ts +3 -0
  256. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  257. package/dist/dashboard/web/preferences.js +18 -0
  258. package/dist/dashboard/web/preferences.js.map +1 -1
  259. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  260. package/dist/dashboard/web/schedules-page.js +4 -1
  261. package/dist/dashboard/web/schedules-page.js.map +1 -1
  262. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  263. package/dist/dashboard/web/sessions-page.js +64 -18
  264. package/dist/dashboard/web/sessions-page.js.map +1 -1
  265. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  266. package/dist/dashboard/web/settings-page.js +2 -1
  267. package/dist/dashboard/web/settings-page.js.map +1 -1
  268. package/dist/dashboard/web/v3-api.d.ts +12 -2
  269. package/dist/dashboard/web/v3-api.d.ts.map +1 -1
  270. package/dist/dashboard/web/v3-api.js +34 -6
  271. package/dist/dashboard/web/v3-api.js.map +1 -1
  272. package/dist/dashboard/web/v3-components.d.ts +6 -0
  273. package/dist/dashboard/web/v3-components.d.ts.map +1 -1
  274. package/dist/dashboard/web/v3-components.js +66 -23
  275. package/dist/dashboard/web/v3-components.js.map +1 -1
  276. package/dist/dashboard/web/v3-model.js +1 -1
  277. package/dist/dashboard/web/v3-model.js.map +1 -1
  278. package/dist/dashboard/web/v3-terminal.js +2 -2
  279. package/dist/dashboard/web/v3-terminal.js.map +1 -1
  280. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts +19 -0
  281. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -0
  282. package/dist/dashboard/web/vc-consumer-profiles-section.js +382 -0
  283. package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -0
  284. package/dist/dashboard/webhook-routes.d.ts.map +1 -1
  285. package/dist/dashboard/webhook-routes.js +29 -6
  286. package/dist/dashboard/webhook-routes.js.map +1 -1
  287. package/dist/dashboard-web/app.js +1 -1
  288. package/dist/dashboard-web/chunks/bot-defaults-page-RYBL4ZYE.js +4 -0
  289. package/dist/dashboard-web/chunks/{chunk-OEJIT66L.js → chunk-CMDPZOPK.js} +1 -1
  290. package/dist/dashboard-web/chunks/chunk-I35DXGM4.js +1 -0
  291. package/dist/dashboard-web/chunks/chunk-NYZHARIU.js +47 -0
  292. package/dist/dashboard-web/chunks/chunk-SZOB6VK2.js +1 -0
  293. package/dist/dashboard-web/chunks/{chunk-YQFXGRSD.js → chunk-YBOHL7T7.js} +1 -1
  294. package/dist/dashboard-web/chunks/chunk-YWCPDL4S.js +1 -0
  295. package/dist/dashboard-web/chunks/connectors-page-DAMP7TTV.js +1 -0
  296. package/dist/dashboard-web/chunks/{groups-page-5AJPPJH2.js → groups-page-BPFA356N.js} +1 -1
  297. package/dist/dashboard-web/chunks/{insights-page-R3DFECX4.js → insights-page-SHOPHTWY.js} +1 -1
  298. package/dist/dashboard-web/chunks/{monitor-room-NLMKJLDY.js → monitor-room-PXPJGZCN.js} +1 -1
  299. package/dist/dashboard-web/chunks/{monitoring-page-EHSOX4GV.js → monitoring-page-4DF54M5Y.js} +1 -1
  300. package/dist/dashboard-web/chunks/{office-page-OXJKFJ4R.js → office-page-6OHU6KMZ.js} +1 -1
  301. package/dist/dashboard-web/chunks/{overview-page-GJHIVXJF.js → overview-page-IHIZ6F5M.js} +1 -1
  302. package/dist/dashboard-web/chunks/{roles-page-6ZODQISW.js → roles-page-JYTBYKEF.js} +1 -1
  303. package/dist/dashboard-web/chunks/{schedules-page-DAGMHVCH.js → schedules-page-WJ72T7KV.js} +1 -1
  304. package/dist/dashboard-web/chunks/sessions-page-QC56OIAI.js +3 -0
  305. package/dist/dashboard-web/chunks/settings-page-TCKWEXTN.js +2 -0
  306. package/dist/dashboard-web/chunks/{skills-page-J7EVUHXP.js → skills-page-RJJNIECW.js} +1 -1
  307. package/dist/dashboard-web/chunks/{team-federation-page-YM5JBIII.js → team-federation-page-ZMDX3E7K.js} +1 -1
  308. package/dist/dashboard-web/chunks/v3-page-VLLAUQ33.js +94 -0
  309. package/dist/dashboard-web/chunks/{whiteboards-page-75N2U6W4.js → whiteboards-page-NAO53CKM.js} +1 -1
  310. package/dist/dashboard-web/style.css +363 -274
  311. package/dist/dashboard.js +194 -78
  312. package/dist/dashboard.js.map +1 -1
  313. package/dist/global-config.d.ts +1 -1
  314. package/dist/i18n/en.d.ts.map +1 -1
  315. package/dist/i18n/en.js +12 -87
  316. package/dist/i18n/en.js.map +1 -1
  317. package/dist/i18n/zh.d.ts.map +1 -1
  318. package/dist/i18n/zh.js +12 -87
  319. package/dist/i18n/zh.js.map +1 -1
  320. package/dist/im/lark/brand-template.d.ts +15 -0
  321. package/dist/im/lark/brand-template.d.ts.map +1 -0
  322. package/dist/im/lark/brand-template.js +114 -0
  323. package/dist/im/lark/brand-template.js.map +1 -0
  324. package/dist/im/lark/card-handler.d.ts +6 -3
  325. package/dist/im/lark/card-handler.d.ts.map +1 -1
  326. package/dist/im/lark/card-handler.js +23 -39
  327. package/dist/im/lark/card-handler.js.map +1 -1
  328. package/dist/im/lark/client.d.ts +8 -2
  329. package/dist/im/lark/client.d.ts.map +1 -1
  330. package/dist/im/lark/client.js +33 -31
  331. package/dist/im/lark/client.js.map +1 -1
  332. package/dist/im/lark/doc-comment.d.ts +18 -0
  333. package/dist/im/lark/doc-comment.d.ts.map +1 -1
  334. package/dist/im/lark/doc-comment.js +119 -5
  335. package/dist/im/lark/doc-comment.js.map +1 -1
  336. package/dist/im/lark/event-dispatcher.d.ts +18 -2
  337. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  338. package/dist/im/lark/event-dispatcher.js +41 -19
  339. package/dist/im/lark/event-dispatcher.js.map +1 -1
  340. package/dist/im/lark/merge-forward.d.ts.map +1 -1
  341. package/dist/im/lark/merge-forward.js +7 -2
  342. package/dist/im/lark/merge-forward.js.map +1 -1
  343. package/dist/im/lark/message-parser.d.ts.map +1 -1
  344. package/dist/im/lark/message-parser.js +7 -0
  345. package/dist/im/lark/message-parser.js.map +1 -1
  346. package/dist/im/lark/overview-card.d.ts +1 -2
  347. package/dist/im/lark/overview-card.d.ts.map +1 -1
  348. package/dist/im/lark/overview-card.js +1 -48
  349. package/dist/im/lark/overview-card.js.map +1 -1
  350. package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -1
  351. package/dist/im/lark/v3-blocked-card-handler.js +5 -5
  352. package/dist/im/lark/v3-blocked-card-handler.js.map +1 -1
  353. package/dist/im/lark/v3-blocked-card.d.ts +1 -0
  354. package/dist/im/lark/v3-blocked-card.d.ts.map +1 -1
  355. package/dist/im/lark/v3-blocked-card.js +19 -2
  356. package/dist/im/lark/v3-blocked-card.js.map +1 -1
  357. package/dist/im/lark/v3-distillation-card-handler.d.ts +12 -0
  358. package/dist/im/lark/v3-distillation-card-handler.d.ts.map +1 -0
  359. package/dist/im/lark/v3-distillation-card-handler.js +107 -0
  360. package/dist/im/lark/v3-distillation-card-handler.js.map +1 -0
  361. package/dist/im/lark/v3-distillation-card.d.ts +42 -0
  362. package/dist/im/lark/v3-distillation-card.d.ts.map +1 -0
  363. package/dist/im/lark/v3-distillation-card.js +206 -0
  364. package/dist/im/lark/v3-distillation-card.js.map +1 -0
  365. package/dist/im/lark/v3-gate-card-handler.d.ts +1 -1
  366. package/dist/im/lark/v3-gate-card-handler.d.ts.map +1 -1
  367. package/dist/im/lark/v3-gate-card-handler.js +6 -5
  368. package/dist/im/lark/v3-gate-card-handler.js.map +1 -1
  369. package/dist/im/lark/v3-gate-card.d.ts +8 -1
  370. package/dist/im/lark/v3-gate-card.d.ts.map +1 -1
  371. package/dist/im/lark/v3-gate-card.js +38 -7
  372. package/dist/im/lark/v3-gate-card.js.map +1 -1
  373. package/dist/im/lark/v3-loop-grant-card-handler.d.ts.map +1 -1
  374. package/dist/im/lark/v3-loop-grant-card-handler.js +3 -4
  375. package/dist/im/lark/v3-loop-grant-card-handler.js.map +1 -1
  376. package/dist/im/lark/v3-loop-grant-card.js +1 -1
  377. package/dist/im/lark/v3-loop-grant-card.js.map +1 -1
  378. package/dist/im/lark/v3-progress-card-manager.d.ts +79 -0
  379. package/dist/im/lark/v3-progress-card-manager.d.ts.map +1 -0
  380. package/dist/im/lark/v3-progress-card-manager.js +444 -0
  381. package/dist/im/lark/v3-progress-card-manager.js.map +1 -0
  382. package/dist/im/lark/v3-progress-card.d.ts +26 -0
  383. package/dist/im/lark/v3-progress-card.d.ts.map +1 -0
  384. package/dist/im/lark/v3-progress-card.js +211 -0
  385. package/dist/im/lark/v3-progress-card.js.map +1 -0
  386. package/dist/im/lark/v3-revisit-grant-card-handler.d.ts.map +1 -1
  387. package/dist/im/lark/v3-revisit-grant-card-handler.js +3 -4
  388. package/dist/im/lark/v3-revisit-grant-card-handler.js.map +1 -1
  389. package/dist/im/lark/v3-revisit-grant-card.js +1 -1
  390. package/dist/im/lark/v3-revisit-grant-card.js.map +1 -1
  391. package/dist/im/lark/v3-run-save-card-handler.d.ts +12 -0
  392. package/dist/im/lark/v3-run-save-card-handler.d.ts.map +1 -0
  393. package/dist/im/lark/v3-run-save-card-handler.js +160 -0
  394. package/dist/im/lark/v3-run-save-card-handler.js.map +1 -0
  395. package/dist/im/lark/v3-run-save-card.d.ts +38 -0
  396. package/dist/im/lark/v3-run-save-card.d.ts.map +1 -0
  397. package/dist/im/lark/v3-run-save-card.js +125 -0
  398. package/dist/im/lark/v3-run-save-card.js.map +1 -0
  399. package/dist/im/lark/v3-saved-workflow-command.d.ts +36 -0
  400. package/dist/im/lark/v3-saved-workflow-command.d.ts.map +1 -0
  401. package/dist/im/lark/v3-saved-workflow-command.js +186 -0
  402. package/dist/im/lark/v3-saved-workflow-command.js.map +1 -0
  403. package/dist/im/lark/v3-saved-workflow-handler.d.ts +89 -0
  404. package/dist/im/lark/v3-saved-workflow-handler.d.ts.map +1 -0
  405. package/dist/im/lark/v3-saved-workflow-handler.js +212 -0
  406. package/dist/im/lark/v3-saved-workflow-handler.js.map +1 -0
  407. package/dist/im/lark/workflow-slash-command.d.ts +7 -110
  408. package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
  409. package/dist/im/lark/workflow-slash-command.js +16 -230
  410. package/dist/im/lark/workflow-slash-command.js.map +1 -1
  411. package/dist/index-daemon.js +1 -1
  412. package/dist/index-daemon.js.map +1 -1
  413. package/dist/mir-runner.js +11 -15
  414. package/dist/mir-runner.js.map +1 -1
  415. package/dist/mira-runner.js +8 -12
  416. package/dist/mira-runner.js.map +1 -1
  417. package/dist/services/bridge-turn-queue.d.ts +29 -12
  418. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  419. package/dist/services/bridge-turn-queue.js +59 -23
  420. package/dist/services/bridge-turn-queue.js.map +1 -1
  421. package/dist/services/claude-transcript.d.ts +15 -0
  422. package/dist/services/claude-transcript.d.ts.map +1 -1
  423. package/dist/services/claude-transcript.js +24 -0
  424. package/dist/services/claude-transcript.js.map +1 -1
  425. package/dist/services/codex-bridge-queue.d.ts +13 -2
  426. package/dist/services/codex-bridge-queue.d.ts.map +1 -1
  427. package/dist/services/codex-bridge-queue.js +20 -3
  428. package/dist/services/codex-bridge-queue.js.map +1 -1
  429. package/dist/services/codex-transcript.d.ts +6 -0
  430. package/dist/services/codex-transcript.d.ts.map +1 -1
  431. package/dist/services/codex-transcript.js.map +1 -1
  432. package/dist/services/grok-transcript.d.ts +3 -2
  433. package/dist/services/grok-transcript.d.ts.map +1 -1
  434. package/dist/services/grok-transcript.js +73 -22
  435. package/dist/services/grok-transcript.js.map +1 -1
  436. package/dist/services/hook-runner.d.ts.map +1 -1
  437. package/dist/services/hook-runner.js +26 -3
  438. package/dist/services/hook-runner.js.map +1 -1
  439. package/dist/services/schedule-store.d.ts +37 -0
  440. package/dist/services/schedule-store.d.ts.map +1 -1
  441. package/dist/services/schedule-store.js +259 -141
  442. package/dist/services/schedule-store.js.map +1 -1
  443. package/dist/services/send-policy.d.ts +50 -0
  444. package/dist/services/send-policy.d.ts.map +1 -1
  445. package/dist/services/send-policy.js +65 -0
  446. package/dist/services/send-policy.js.map +1 -1
  447. package/dist/services/session-lifecycle-hooks.d.ts.map +1 -1
  448. package/dist/services/session-lifecycle-hooks.js +12 -0
  449. package/dist/services/session-lifecycle-hooks.js.map +1 -1
  450. package/dist/services/traex-transcript.d.ts +11 -2
  451. package/dist/services/traex-transcript.d.ts.map +1 -1
  452. package/dist/services/traex-transcript.js +142 -8
  453. package/dist/services/traex-transcript.js.map +1 -1
  454. package/dist/services/trigger-types.d.ts +6 -1
  455. package/dist/services/trigger-types.d.ts.map +1 -1
  456. package/dist/services/trigger-types.js.map +1 -1
  457. package/dist/services/turn-terminal-deduper.d.ts +14 -0
  458. package/dist/services/turn-terminal-deduper.d.ts.map +1 -0
  459. package/dist/services/turn-terminal-deduper.js +34 -0
  460. package/dist/services/turn-terminal-deduper.js.map +1 -0
  461. package/dist/services/vc-meeting-action-gate.d.ts +246 -0
  462. package/dist/services/vc-meeting-action-gate.d.ts.map +1 -0
  463. package/dist/services/vc-meeting-action-gate.js +756 -0
  464. package/dist/services/vc-meeting-action-gate.js.map +1 -0
  465. package/dist/services/vc-meeting-action-store.d.ts +222 -0
  466. package/dist/services/vc-meeting-action-store.d.ts.map +1 -0
  467. package/dist/services/vc-meeting-action-store.js +806 -0
  468. package/dist/services/vc-meeting-action-store.js.map +1 -0
  469. package/dist/services/vc-meeting-consumer-isolation.d.ts +27 -0
  470. package/dist/services/vc-meeting-consumer-isolation.d.ts.map +1 -0
  471. package/dist/services/vc-meeting-consumer-isolation.js +37 -0
  472. package/dist/services/vc-meeting-consumer-isolation.js.map +1 -0
  473. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +72 -0
  474. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -0
  475. package/dist/services/vc-meeting-consumer-profile-bootstrap.js +343 -0
  476. package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -0
  477. package/dist/services/vc-meeting-consumer-profile-store.d.ts +39 -0
  478. package/dist/services/vc-meeting-consumer-profile-store.d.ts.map +1 -0
  479. package/dist/services/vc-meeting-consumer-profile-store.js +190 -0
  480. package/dist/services/vc-meeting-consumer-profile-store.js.map +1 -0
  481. package/dist/services/vc-meeting-daemon-auth.d.ts +29 -0
  482. package/dist/services/vc-meeting-daemon-auth.d.ts.map +1 -0
  483. package/dist/services/vc-meeting-daemon-auth.js +117 -0
  484. package/dist/services/vc-meeting-daemon-auth.js.map +1 -0
  485. package/dist/services/vc-meeting-delivery-feed.d.ts +52 -0
  486. package/dist/services/vc-meeting-delivery-feed.d.ts.map +1 -0
  487. package/dist/services/vc-meeting-delivery-feed.js +231 -0
  488. package/dist/services/vc-meeting-delivery-feed.js.map +1 -0
  489. package/dist/services/vc-meeting-delivery-hub-store.d.ts +213 -0
  490. package/dist/services/vc-meeting-delivery-hub-store.d.ts.map +1 -0
  491. package/dist/services/vc-meeting-delivery-hub-store.js +1230 -0
  492. package/dist/services/vc-meeting-delivery-hub-store.js.map +1 -0
  493. package/dist/services/vc-meeting-delivery-protocol.d.ts +159 -0
  494. package/dist/services/vc-meeting-delivery-protocol.d.ts.map +1 -0
  495. package/dist/services/vc-meeting-delivery-protocol.js +443 -0
  496. package/dist/services/vc-meeting-delivery-protocol.js.map +1 -0
  497. package/dist/services/vc-meeting-delivery-receiver.d.ts +80 -0
  498. package/dist/services/vc-meeting-delivery-receiver.d.ts.map +1 -0
  499. package/dist/services/vc-meeting-delivery-receiver.js +543 -0
  500. package/dist/services/vc-meeting-delivery-receiver.js.map +1 -0
  501. package/dist/services/vc-meeting-delivery-store.d.ts +339 -0
  502. package/dist/services/vc-meeting-delivery-store.d.ts.map +1 -0
  503. package/dist/services/vc-meeting-delivery-store.js +1024 -0
  504. package/dist/services/vc-meeting-delivery-store.js.map +1 -0
  505. package/dist/services/vc-meeting-feed-metadata-store.d.ts +58 -0
  506. package/dist/services/vc-meeting-feed-metadata-store.d.ts.map +1 -0
  507. package/dist/services/vc-meeting-feed-metadata-store.js +356 -0
  508. package/dist/services/vc-meeting-feed-metadata-store.js.map +1 -0
  509. package/dist/services/vc-meeting-im-reply.d.ts +55 -0
  510. package/dist/services/vc-meeting-im-reply.d.ts.map +1 -0
  511. package/dist/services/vc-meeting-im-reply.js +279 -0
  512. package/dist/services/vc-meeting-im-reply.js.map +1 -0
  513. package/dist/services/vc-meeting-im-routing.d.ts +131 -0
  514. package/dist/services/vc-meeting-im-routing.d.ts.map +1 -0
  515. package/dist/services/vc-meeting-im-routing.js +449 -0
  516. package/dist/services/vc-meeting-im-routing.js.map +1 -0
  517. package/dist/services/vc-meeting-listener-message-store.d.ts +23 -0
  518. package/dist/services/vc-meeting-listener-message-store.d.ts.map +1 -0
  519. package/dist/services/vc-meeting-listener-message-store.js +142 -0
  520. package/dist/services/vc-meeting-listener-message-store.js.map +1 -0
  521. package/dist/services/vc-meeting-member-policy.d.ts +37 -0
  522. package/dist/services/vc-meeting-member-policy.d.ts.map +1 -0
  523. package/dist/services/vc-meeting-member-policy.js +102 -0
  524. package/dist/services/vc-meeting-member-policy.js.map +1 -0
  525. package/dist/services/vc-meeting-profile-instructions.d.ts +22 -0
  526. package/dist/services/vc-meeting-profile-instructions.d.ts.map +1 -0
  527. package/dist/services/vc-meeting-profile-instructions.js +64 -0
  528. package/dist/services/vc-meeting-profile-instructions.js.map +1 -0
  529. package/dist/services/vc-meeting-runtime-store.d.ts +63 -0
  530. package/dist/services/vc-meeting-runtime-store.d.ts.map +1 -1
  531. package/dist/services/vc-meeting-runtime-store.js +605 -116
  532. package/dist/services/vc-meeting-runtime-store.js.map +1 -1
  533. package/dist/services/vc-meeting-send-policy.d.ts +89 -0
  534. package/dist/services/vc-meeting-send-policy.d.ts.map +1 -0
  535. package/dist/services/vc-meeting-send-policy.js +150 -0
  536. package/dist/services/vc-meeting-send-policy.js.map +1 -0
  537. package/dist/services/vc-meeting-terminal-reconciler.d.ts +93 -0
  538. package/dist/services/vc-meeting-terminal-reconciler.d.ts.map +1 -0
  539. package/dist/services/vc-meeting-terminal-reconciler.js +198 -0
  540. package/dist/services/vc-meeting-terminal-reconciler.js.map +1 -0
  541. package/dist/setup/open-platform-automation.d.ts +2 -0
  542. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  543. package/dist/setup/open-platform-automation.js +1 -0
  544. package/dist/setup/open-platform-automation.js.map +1 -1
  545. package/dist/setup/open-platform-outcome.d.ts +50 -0
  546. package/dist/setup/open-platform-outcome.d.ts.map +1 -0
  547. package/dist/setup/open-platform-outcome.js +56 -0
  548. package/dist/setup/open-platform-outcome.js.map +1 -0
  549. package/dist/setup/setup-args.d.ts +7 -2
  550. package/dist/setup/setup-args.d.ts.map +1 -1
  551. package/dist/setup/setup-args.js +21 -5
  552. package/dist/setup/setup-args.js.map +1 -1
  553. package/dist/skills/definitions.d.ts.map +1 -1
  554. package/dist/skills/definitions.js +66 -54
  555. package/dist/skills/definitions.js.map +1 -1
  556. package/dist/skills/injection-mode.d.ts +5 -4
  557. package/dist/skills/injection-mode.d.ts.map +1 -1
  558. package/dist/skills/injection-mode.js +19 -10
  559. package/dist/skills/injection-mode.js.map +1 -1
  560. package/dist/types.d.ts +187 -0
  561. package/dist/types.d.ts.map +1 -1
  562. package/dist/utils/canonical-input-hash.d.ts +5 -0
  563. package/dist/utils/canonical-input-hash.d.ts.map +1 -0
  564. package/dist/utils/canonical-input-hash.js +43 -0
  565. package/dist/utils/canonical-input-hash.js.map +1 -0
  566. package/dist/utils/canonical-json.d.ts +10 -0
  567. package/dist/utils/canonical-json.d.ts.map +1 -0
  568. package/dist/utils/canonical-json.js +23 -0
  569. package/dist/utils/canonical-json.js.map +1 -0
  570. package/dist/utils/child-env.d.ts +1 -1
  571. package/dist/utils/child-env.d.ts.map +1 -1
  572. package/dist/utils/child-env.js +8 -0
  573. package/dist/utils/child-env.js.map +1 -1
  574. package/dist/utils/daemon-discovery.d.ts +4 -0
  575. package/dist/utils/daemon-discovery.d.ts.map +1 -1
  576. package/dist/utils/daemon-discovery.js +12 -6
  577. package/dist/utils/daemon-discovery.js.map +1 -1
  578. package/dist/utils/file-lock.d.ts.map +1 -1
  579. package/dist/utils/file-lock.js +696 -102
  580. package/dist/utils/file-lock.js.map +1 -1
  581. package/dist/utils/fs-durability.d.ts +20 -0
  582. package/dist/utils/fs-durability.d.ts.map +1 -0
  583. package/dist/utils/fs-durability.js +84 -0
  584. package/dist/utils/fs-durability.js.map +1 -0
  585. package/dist/utils/global-install.d.ts +5 -2
  586. package/dist/utils/global-install.d.ts.map +1 -1
  587. package/dist/utils/global-install.js +22 -4
  588. package/dist/utils/global-install.js.map +1 -1
  589. package/dist/utils/herdr-web-history.d.ts +12 -0
  590. package/dist/utils/herdr-web-history.d.ts.map +1 -0
  591. package/dist/utils/herdr-web-history.js +74 -0
  592. package/dist/utils/herdr-web-history.js.map +1 -0
  593. package/dist/utils/herdr-web-terminal-binding.d.ts +39 -0
  594. package/dist/utils/herdr-web-terminal-binding.d.ts.map +1 -0
  595. package/dist/utils/herdr-web-terminal-binding.js +56 -0
  596. package/dist/utils/herdr-web-terminal-binding.js.map +1 -0
  597. package/dist/utils/pending-input-queue.d.ts +30 -1
  598. package/dist/utils/pending-input-queue.d.ts.map +1 -1
  599. package/dist/utils/pending-input-queue.js +45 -5
  600. package/dist/utils/pending-input-queue.js.map +1 -1
  601. package/dist/vc-agent/cards.d.ts +49 -4
  602. package/dist/vc-agent/cards.d.ts.map +1 -1
  603. package/dist/vc-agent/cards.js +460 -70
  604. package/dist/vc-agent/cards.js.map +1 -1
  605. package/dist/vc-agent/polling-source.d.ts +6 -1
  606. package/dist/vc-agent/polling-source.d.ts.map +1 -1
  607. package/dist/vc-agent/polling-source.js +17 -4
  608. package/dist/vc-agent/polling-source.js.map +1 -1
  609. package/dist/worker.js +1333 -283
  610. package/dist/worker.js.map +1 -1
  611. package/dist/workflows/definition.d.ts +28 -35
  612. package/dist/workflows/definition.d.ts.map +1 -1
  613. package/dist/workflows/definition.js +7 -24
  614. package/dist/workflows/definition.js.map +1 -1
  615. package/dist/workflows/events/payloads.d.ts +28 -28
  616. package/dist/workflows/events/replay.d.ts +5 -0
  617. package/dist/workflows/events/replay.d.ts.map +1 -1
  618. package/dist/workflows/events/replay.js +6 -1
  619. package/dist/workflows/events/replay.js.map +1 -1
  620. package/dist/workflows/events/schema.d.ts +663 -663
  621. package/dist/workflows/events/schema.d.ts.map +1 -1
  622. package/dist/workflows/events/schema.js +1 -4
  623. package/dist/workflows/events/schema.js.map +1 -1
  624. package/dist/workflows/hostExecutors/botmux-schedule.d.ts +5 -4
  625. package/dist/workflows/hostExecutors/botmux-schedule.d.ts.map +1 -1
  626. package/dist/workflows/hostExecutors/botmux-schedule.js +80 -35
  627. package/dist/workflows/hostExecutors/botmux-schedule.js.map +1 -1
  628. package/dist/workflows/hostExecutors/feishu-im.d.ts +3 -3
  629. package/dist/workflows/hostExecutors/feishu-im.d.ts.map +1 -1
  630. package/dist/workflows/hostExecutors/feishu-im.js +3 -3
  631. package/dist/workflows/hostExecutors/feishu-im.js.map +1 -1
  632. package/dist/workflows/hostExecutors/feishu-reply.d.ts +1 -1
  633. package/dist/workflows/hostExecutors/feishu-reply.d.ts.map +1 -1
  634. package/dist/workflows/hostExecutors/feishu-reply.js +1 -1
  635. package/dist/workflows/hostExecutors/feishu-reply.js.map +1 -1
  636. package/dist/workflows/hostExecutors/feishu-send.d.ts +1 -1
  637. package/dist/workflows/hostExecutors/feishu-send.d.ts.map +1 -1
  638. package/dist/workflows/hostExecutors/feishu-send.js +1 -1
  639. package/dist/workflows/hostExecutors/feishu-send.js.map +1 -1
  640. package/dist/workflows/hostExecutors/index.d.ts +0 -1
  641. package/dist/workflows/hostExecutors/index.d.ts.map +1 -1
  642. package/dist/workflows/hostExecutors/index.js +0 -1
  643. package/dist/workflows/hostExecutors/index.js.map +1 -1
  644. package/dist/workflows/hostExecutors/registry.d.ts +1 -1
  645. package/dist/workflows/hostExecutors/registry.d.ts.map +1 -1
  646. package/dist/workflows/hostExecutors/types.d.ts +21 -29
  647. package/dist/workflows/hostExecutors/types.d.ts.map +1 -1
  648. package/dist/workflows/migration/v2-definition-paths.d.ts +3 -0
  649. package/dist/workflows/migration/v2-definition-paths.d.ts.map +1 -0
  650. package/dist/workflows/migration/v2-definition-paths.js +10 -0
  651. package/dist/workflows/migration/v2-definition-paths.js.map +1 -0
  652. package/dist/workflows/migration/v2-ledger.d.ts +138 -0
  653. package/dist/workflows/migration/v2-ledger.d.ts.map +1 -0
  654. package/dist/workflows/migration/v2-ledger.js +599 -0
  655. package/dist/workflows/migration/v2-ledger.js.map +1 -0
  656. package/dist/workflows/migration/v2-migration-service.d.ts +40 -0
  657. package/dist/workflows/migration/v2-migration-service.d.ts.map +1 -0
  658. package/dist/workflows/migration/v2-migration-service.js +454 -0
  659. package/dist/workflows/migration/v2-migration-service.js.map +1 -0
  660. package/dist/workflows/migration/v2-read-only-ids.d.ts +7 -0
  661. package/dist/workflows/migration/v2-read-only-ids.d.ts.map +1 -0
  662. package/dist/workflows/migration/v2-read-only-ids.js +9 -0
  663. package/dist/workflows/migration/v2-read-only-ids.js.map +1 -0
  664. package/dist/workflows/migration/v2-run-archive-schema.d.ts +976 -0
  665. package/dist/workflows/migration/v2-run-archive-schema.d.ts.map +1 -0
  666. package/dist/workflows/migration/v2-run-archive-schema.js +113 -0
  667. package/dist/workflows/migration/v2-run-archive-schema.js.map +1 -0
  668. package/dist/workflows/migration/v2-run-archive.d.ts +92 -0
  669. package/dist/workflows/migration/v2-run-archive.d.ts.map +1 -0
  670. package/dist/workflows/migration/v2-run-archive.js +1220 -0
  671. package/dist/workflows/migration/v2-run-archive.js.map +1 -0
  672. package/dist/workflows/migration/v2-scanner.d.ts +22 -0
  673. package/dist/workflows/migration/v2-scanner.d.ts.map +1 -0
  674. package/dist/workflows/migration/v2-scanner.js +114 -0
  675. package/dist/workflows/migration/v2-scanner.js.map +1 -0
  676. package/dist/workflows/migration/v2-to-v3.d.ts +32 -0
  677. package/dist/workflows/migration/v2-to-v3.d.ts.map +1 -0
  678. package/dist/workflows/migration/v2-to-v3.js +494 -0
  679. package/dist/workflows/migration/v2-to-v3.js.map +1 -0
  680. package/dist/workflows/ops-projection.d.ts.map +1 -1
  681. package/dist/workflows/ops-projection.js +4 -3
  682. package/dist/workflows/ops-projection.js.map +1 -1
  683. package/dist/workflows/shared/idempotency-key.d.ts +19 -0
  684. package/dist/workflows/shared/idempotency-key.d.ts.map +1 -0
  685. package/dist/workflows/shared/idempotency-key.js +23 -0
  686. package/dist/workflows/shared/idempotency-key.js.map +1 -0
  687. package/dist/workflows/{params.d.ts → shared/params.d.ts} +42 -6
  688. package/dist/workflows/shared/params.d.ts.map +1 -0
  689. package/dist/workflows/{params.js → shared/params.js} +91 -4
  690. package/dist/workflows/shared/params.js.map +1 -0
  691. package/dist/workflows/shared/provider-reconciler.d.ts +47 -0
  692. package/dist/workflows/shared/provider-reconciler.d.ts.map +1 -0
  693. package/dist/workflows/shared/provider-reconciler.js +17 -0
  694. package/dist/workflows/shared/provider-reconciler.js.map +1 -0
  695. package/dist/workflows/{spawn-policy.d.ts → shared/sandbox-policy.d.ts} +2 -2
  696. package/dist/workflows/shared/sandbox-policy.d.ts.map +1 -0
  697. package/dist/workflows/{spawn-policy.js → shared/sandbox-policy.js} +1 -1
  698. package/dist/workflows/shared/sandbox-policy.js.map +1 -0
  699. package/dist/workflows/shared/worker-process.d.ts +29 -0
  700. package/dist/workflows/shared/worker-process.d.ts.map +1 -0
  701. package/dist/workflows/shared/worker-process.js +56 -0
  702. package/dist/workflows/shared/worker-process.js.map +1 -0
  703. package/dist/workflows/v3/architect.d.ts.map +1 -1
  704. package/dist/workflows/v3/architect.js +16 -4
  705. package/dist/workflows/v3/architect.js.map +1 -1
  706. package/dist/workflows/v3/attempt-ledger.d.ts +23 -0
  707. package/dist/workflows/v3/attempt-ledger.d.ts.map +1 -0
  708. package/dist/workflows/v3/attempt-ledger.js +74 -0
  709. package/dist/workflows/v3/attempt-ledger.js.map +1 -0
  710. package/dist/workflows/v3/bot-resolve.d.ts +19 -1
  711. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
  712. package/dist/workflows/v3/bot-resolve.js +129 -3
  713. package/dist/workflows/v3/bot-resolve.js.map +1 -1
  714. package/dist/workflows/v3/cli-daemon-command-authority.d.ts +59 -0
  715. package/dist/workflows/v3/cli-daemon-command-authority.d.ts.map +1 -0
  716. package/dist/workflows/v3/cli-daemon-command-authority.js +175 -0
  717. package/dist/workflows/v3/cli-daemon-command-authority.js.map +1 -0
  718. package/dist/workflows/v3/cli-run.d.ts +27 -0
  719. package/dist/workflows/v3/cli-run.d.ts.map +1 -1
  720. package/dist/workflows/v3/cli-run.js +113 -29
  721. package/dist/workflows/v3/cli-run.js.map +1 -1
  722. package/dist/workflows/v3/contract.d.ts +16 -16
  723. package/dist/workflows/v3/contract.d.ts.map +1 -1
  724. package/dist/workflows/v3/contract.js +15 -11
  725. package/dist/workflows/v3/contract.js.map +1 -1
  726. package/dist/workflows/v3/daemon-ipc-auth.d.ts +113 -0
  727. package/dist/workflows/v3/daemon-ipc-auth.d.ts.map +1 -0
  728. package/dist/workflows/v3/daemon-ipc-auth.js +294 -0
  729. package/dist/workflows/v3/daemon-ipc-auth.js.map +1 -0
  730. package/dist/workflows/v3/daemon-ipc-body.d.ts +30 -0
  731. package/dist/workflows/v3/daemon-ipc-body.d.ts.map +1 -0
  732. package/dist/workflows/v3/daemon-ipc-body.js +65 -0
  733. package/dist/workflows/v3/daemon-ipc-body.js.map +1 -0
  734. package/dist/workflows/v3/daemon-ipc-client.d.ts +32 -0
  735. package/dist/workflows/v3/daemon-ipc-client.d.ts.map +1 -0
  736. package/dist/workflows/v3/daemon-ipc-client.js +74 -0
  737. package/dist/workflows/v3/daemon-ipc-client.js.map +1 -0
  738. package/dist/workflows/v3/daemon-run.d.ts +87 -2
  739. package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
  740. package/dist/workflows/v3/daemon-run.js +863 -68
  741. package/dist/workflows/v3/daemon-run.js.map +1 -1
  742. package/dist/workflows/v3/dag.d.ts +22 -8
  743. package/dist/workflows/v3/dag.d.ts.map +1 -1
  744. package/dist/workflows/v3/dag.js +214 -22
  745. package/dist/workflows/v3/dag.js.map +1 -1
  746. package/dist/workflows/v3/distillation-compiler.d.ts +36 -0
  747. package/dist/workflows/v3/distillation-compiler.d.ts.map +1 -0
  748. package/dist/workflows/v3/distillation-compiler.js +704 -0
  749. package/dist/workflows/v3/distillation-compiler.js.map +1 -0
  750. package/dist/workflows/v3/distillation-private-root.d.ts +10 -0
  751. package/dist/workflows/v3/distillation-private-root.d.ts.map +1 -0
  752. package/dist/workflows/v3/distillation-private-root.js +34 -0
  753. package/dist/workflows/v3/distillation-private-root.js.map +1 -0
  754. package/dist/workflows/v3/distillation-runner.d.ts +64 -0
  755. package/dist/workflows/v3/distillation-runner.d.ts.map +1 -0
  756. package/dist/workflows/v3/distillation-runner.js +1028 -0
  757. package/dist/workflows/v3/distillation-runner.js.map +1 -0
  758. package/dist/workflows/v3/distillation-schema.d.ts +63 -0
  759. package/dist/workflows/v3/distillation-schema.d.ts.map +1 -0
  760. package/dist/workflows/v3/distillation-schema.js +184 -0
  761. package/dist/workflows/v3/distillation-schema.js.map +1 -0
  762. package/dist/workflows/v3/distillation-service.d.ts +78 -0
  763. package/dist/workflows/v3/distillation-service.d.ts.map +1 -0
  764. package/dist/workflows/v3/distillation-service.js +416 -0
  765. package/dist/workflows/v3/distillation-service.js.map +1 -0
  766. package/dist/workflows/v3/distillation-source.d.ts +35 -0
  767. package/dist/workflows/v3/distillation-source.d.ts.map +1 -0
  768. package/dist/workflows/v3/distillation-source.js +118 -0
  769. package/dist/workflows/v3/distillation-source.js.map +1 -0
  770. package/dist/workflows/v3/distillation-store.d.ts +185 -0
  771. package/dist/workflows/v3/distillation-store.d.ts.map +1 -0
  772. package/dist/workflows/v3/distillation-store.js +1127 -0
  773. package/dist/workflows/v3/distillation-store.js.map +1 -0
  774. package/dist/workflows/v3/drive-lease.d.ts +7 -0
  775. package/dist/workflows/v3/drive-lease.d.ts.map +1 -0
  776. package/dist/workflows/v3/drive-lease.js +10 -0
  777. package/dist/workflows/v3/drive-lease.js.map +1 -0
  778. package/dist/workflows/v3/ephemeral-pool.d.ts +1 -1
  779. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
  780. package/dist/workflows/v3/ephemeral-pool.js +222 -37
  781. package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
  782. package/dist/workflows/v3/grill-state.d.ts +18 -3
  783. package/dist/workflows/v3/grill-state.d.ts.map +1 -1
  784. package/dist/workflows/v3/grill-state.js +22 -5
  785. package/dist/workflows/v3/grill-state.js.map +1 -1
  786. package/dist/workflows/v3/host-bindings.d.ts +40 -0
  787. package/dist/workflows/v3/host-bindings.d.ts.map +1 -0
  788. package/dist/workflows/v3/host-bindings.js +272 -0
  789. package/dist/workflows/v3/host-bindings.js.map +1 -0
  790. package/dist/workflows/v3/host-effect-ledger.d.ts +22 -0
  791. package/dist/workflows/v3/host-effect-ledger.d.ts.map +1 -0
  792. package/dist/workflows/v3/host-effect-ledger.js +110 -0
  793. package/dist/workflows/v3/host-effect-ledger.js.map +1 -0
  794. package/dist/workflows/v3/host-execution.d.ts +142 -0
  795. package/dist/workflows/v3/host-execution.d.ts.map +1 -0
  796. package/dist/workflows/v3/host-execution.js +424 -0
  797. package/dist/workflows/v3/host-execution.js.map +1 -0
  798. package/dist/workflows/v3/host.d.ts +46 -10
  799. package/dist/workflows/v3/host.d.ts.map +1 -1
  800. package/dist/workflows/v3/host.js +419 -140
  801. package/dist/workflows/v3/host.js.map +1 -1
  802. package/dist/workflows/v3/human-gate.d.ts +19 -1
  803. package/dist/workflows/v3/human-gate.d.ts.map +1 -1
  804. package/dist/workflows/v3/human-gate.js +145 -19
  805. package/dist/workflows/v3/human-gate.js.map +1 -1
  806. package/dist/workflows/v3/journal.d.ts +125 -7
  807. package/dist/workflows/v3/journal.d.ts.map +1 -1
  808. package/dist/workflows/v3/journal.js +154 -38
  809. package/dist/workflows/v3/journal.js.map +1 -1
  810. package/dist/workflows/v3/library-materialize.d.ts +88 -0
  811. package/dist/workflows/v3/library-materialize.d.ts.map +1 -0
  812. package/dist/workflows/v3/library-materialize.js +294 -0
  813. package/dist/workflows/v3/library-materialize.js.map +1 -0
  814. package/dist/workflows/v3/library-schema.d.ts +138 -0
  815. package/dist/workflows/v3/library-schema.d.ts.map +1 -0
  816. package/dist/workflows/v3/library-schema.js +573 -0
  817. package/dist/workflows/v3/library-schema.js.map +1 -0
  818. package/dist/workflows/v3/library-service.d.ts +126 -0
  819. package/dist/workflows/v3/library-service.d.ts.map +1 -0
  820. package/dist/workflows/v3/library-service.js +542 -0
  821. package/dist/workflows/v3/library-service.js.map +1 -0
  822. package/dist/workflows/v3/library-store.d.ts +124 -0
  823. package/dist/workflows/v3/library-store.d.ts.map +1 -0
  824. package/dist/workflows/v3/library-store.js +665 -0
  825. package/dist/workflows/v3/library-store.js.map +1 -0
  826. package/dist/workflows/v3/orchestrator.d.ts +9 -1
  827. package/dist/workflows/v3/orchestrator.d.ts.map +1 -1
  828. package/dist/workflows/v3/orchestrator.js +2 -1
  829. package/dist/workflows/v3/orchestrator.js.map +1 -1
  830. package/dist/workflows/v3/progress-projection.d.ts +99 -0
  831. package/dist/workflows/v3/progress-projection.d.ts.map +1 -0
  832. package/dist/workflows/v3/progress-projection.js +197 -0
  833. package/dist/workflows/v3/progress-projection.js.map +1 -0
  834. package/dist/workflows/v3/run-envelope.d.ts +1279 -0
  835. package/dist/workflows/v3/run-envelope.d.ts.map +1 -0
  836. package/dist/workflows/v3/run-envelope.js +681 -0
  837. package/dist/workflows/v3/run-envelope.js.map +1 -0
  838. package/dist/workflows/v3/runtime.d.ts +39 -7
  839. package/dist/workflows/v3/runtime.d.ts.map +1 -1
  840. package/dist/workflows/v3/runtime.js +1992 -100
  841. package/dist/workflows/v3/runtime.js.map +1 -1
  842. package/dist/workflows/v3/session-relay-client.d.ts +61 -0
  843. package/dist/workflows/v3/session-relay-client.d.ts.map +1 -0
  844. package/dist/workflows/v3/session-relay-client.js +92 -0
  845. package/dist/workflows/v3/session-relay-client.js.map +1 -0
  846. package/dist/workflows/v3/session-relay.d.ts +66 -0
  847. package/dist/workflows/v3/session-relay.d.ts.map +1 -0
  848. package/dist/workflows/v3/session-relay.js +157 -0
  849. package/dist/workflows/v3/session-relay.js.map +1 -0
  850. package/dist/workflows/v3/start-intent.d.ts +8 -0
  851. package/dist/workflows/v3/start-intent.d.ts.map +1 -0
  852. package/dist/workflows/v3/start-intent.js +34 -0
  853. package/dist/workflows/v3/start-intent.js.map +1 -0
  854. package/dist/workflows/v3/state.d.ts +11 -2
  855. package/dist/workflows/v3/state.d.ts.map +1 -1
  856. package/dist/workflows/v3/state.js +182 -10
  857. package/dist/workflows/v3/state.js.map +1 -1
  858. package/dist/workflows/v3/template-bindings.d.ts +22 -0
  859. package/dist/workflows/v3/template-bindings.d.ts.map +1 -0
  860. package/dist/workflows/v3/template-bindings.js +204 -0
  861. package/dist/workflows/v3/template-bindings.js.map +1 -0
  862. package/dist/workflows/v3/worker-fence.d.ts +158 -0
  863. package/dist/workflows/v3/worker-fence.d.ts.map +1 -0
  864. package/dist/workflows/v3/worker-fence.js +685 -0
  865. package/dist/workflows/v3/worker-fence.js.map +1 -0
  866. package/package.json +3 -2
  867. package/dist/core/dashboard-command/workflows.d.ts +0 -20
  868. package/dist/core/dashboard-command/workflows.d.ts.map +0 -1
  869. package/dist/core/dashboard-command/workflows.js +0 -45
  870. package/dist/core/dashboard-command/workflows.js.map +0 -1
  871. package/dist/dashboard/web/legacy-workflow-link.d.ts +0 -2
  872. package/dist/dashboard/web/legacy-workflow-link.d.ts.map +0 -1
  873. package/dist/dashboard/web/legacy-workflow-link.js +0 -12
  874. package/dist/dashboard/web/legacy-workflow-link.js.map +0 -1
  875. package/dist/dashboard/web/legacy-workflow-page.d.ts +0 -3
  876. package/dist/dashboard/web/legacy-workflow-page.d.ts.map +0 -1
  877. package/dist/dashboard/web/legacy-workflow-page.js +0 -717
  878. package/dist/dashboard/web/legacy-workflow-page.js.map +0 -1
  879. package/dist/dashboard/web/workflow-version-switch.d.ts +0 -8
  880. package/dist/dashboard/web/workflow-version-switch.d.ts.map +0 -1
  881. package/dist/dashboard/web/workflow-version-switch.js +0 -9
  882. package/dist/dashboard/web/workflow-version-switch.js.map +0 -1
  883. package/dist/dashboard/web/workflows.d.ts +0 -273
  884. package/dist/dashboard/web/workflows.d.ts.map +0 -1
  885. package/dist/dashboard/web/workflows.js +0 -436
  886. package/dist/dashboard/web/workflows.js.map +0 -1
  887. package/dist/dashboard/workflow-api.d.ts +0 -30
  888. package/dist/dashboard/workflow-api.d.ts.map +0 -1
  889. package/dist/dashboard/workflow-api.js +0 -397
  890. package/dist/dashboard/workflow-api.js.map +0 -1
  891. package/dist/dashboard/workflow-card-model.d.ts +0 -127
  892. package/dist/dashboard/workflow-card-model.d.ts.map +0 -1
  893. package/dist/dashboard/workflow-card-model.js +0 -186
  894. package/dist/dashboard/workflow-card-model.js.map +0 -1
  895. package/dist/dashboard/workflows-action-helpers.d.ts +0 -105
  896. package/dist/dashboard/workflows-action-helpers.d.ts.map +0 -1
  897. package/dist/dashboard/workflows-action-helpers.js +0 -196
  898. package/dist/dashboard/workflows-action-helpers.js.map +0 -1
  899. package/dist/dashboard-web/chunks/bot-defaults-page-7T7DPOV6.js +0 -4
  900. package/dist/dashboard-web/chunks/chunk-IGXYYRYJ.js +0 -1
  901. package/dist/dashboard-web/chunks/chunk-ISOD7VDX.js +0 -1
  902. package/dist/dashboard-web/chunks/chunk-PNK3HQBI.js +0 -37
  903. package/dist/dashboard-web/chunks/chunk-SRIE4MLQ.js +0 -1
  904. package/dist/dashboard-web/chunks/connectors-page-UQ4QBE45.js +0 -1
  905. package/dist/dashboard-web/chunks/legacy-workflow-page-QMC7OZXH.js +0 -2
  906. package/dist/dashboard-web/chunks/sessions-page-NNZIDHZM.js +0 -3
  907. package/dist/dashboard-web/chunks/settings-page-LJIXX5LQ.js +0 -2
  908. package/dist/dashboard-web/chunks/v3-page-YLYVHGKD.js +0 -94
  909. package/dist/dashboard-web/terminal-replay.html +0 -227
  910. package/dist/im/lark/workflow-card-handler.d.ts +0 -51
  911. package/dist/im/lark/workflow-card-handler.d.ts.map +0 -1
  912. package/dist/im/lark/workflow-card-handler.js +0 -163
  913. package/dist/im/lark/workflow-card-handler.js.map +0 -1
  914. package/dist/im/lark/workflow-cards.d.ts +0 -47
  915. package/dist/im/lark/workflow-cards.d.ts.map +0 -1
  916. package/dist/im/lark/workflow-cards.js +0 -231
  917. package/dist/im/lark/workflow-cards.js.map +0 -1
  918. package/dist/im/lark/workflow-progress-card.d.ts +0 -81
  919. package/dist/im/lark/workflow-progress-card.d.ts.map +0 -1
  920. package/dist/im/lark/workflow-progress-card.js +0 -336
  921. package/dist/im/lark/workflow-progress-card.js.map +0 -1
  922. package/dist/im/lark/workflows-card.d.ts +0 -102
  923. package/dist/im/lark/workflows-card.d.ts.map +0 -1
  924. package/dist/im/lark/workflows-card.js +0 -737
  925. package/dist/im/lark/workflows-card.js.map +0 -1
  926. package/dist/workflows/attempt-resume.d.ts +0 -119
  927. package/dist/workflows/attempt-resume.d.ts.map +0 -1
  928. package/dist/workflows/attempt-resume.js +0 -392
  929. package/dist/workflows/attempt-resume.js.map +0 -1
  930. package/dist/workflows/blob.d.ts +0 -27
  931. package/dist/workflows/blob.d.ts.map +0 -1
  932. package/dist/workflows/blob.js +0 -40
  933. package/dist/workflows/blob.js.map +0 -1
  934. package/dist/workflows/cancel-run.d.ts +0 -45
  935. package/dist/workflows/cancel-run.d.ts.map +0 -1
  936. package/dist/workflows/cancel-run.js +0 -99
  937. package/dist/workflows/cancel-run.js.map +0 -1
  938. package/dist/workflows/cancel.d.ts +0 -111
  939. package/dist/workflows/cancel.d.ts.map +0 -1
  940. package/dist/workflows/cancel.js +0 -120
  941. package/dist/workflows/cancel.js.map +0 -1
  942. package/dist/workflows/catalog.d.ts +0 -60
  943. package/dist/workflows/catalog.d.ts.map +0 -1
  944. package/dist/workflows/catalog.js +0 -119
  945. package/dist/workflows/catalog.js.map +0 -1
  946. package/dist/workflows/cold-attach.d.ts +0 -30
  947. package/dist/workflows/cold-attach.d.ts.map +0 -1
  948. package/dist/workflows/cold-attach.js +0 -40
  949. package/dist/workflows/cold-attach.js.map +0 -1
  950. package/dist/workflows/cold-scan.d.ts +0 -21
  951. package/dist/workflows/cold-scan.d.ts.map +0 -1
  952. package/dist/workflows/cold-scan.js +0 -70
  953. package/dist/workflows/cold-scan.js.map +0 -1
  954. package/dist/workflows/daemon-spawn.d.ts +0 -119
  955. package/dist/workflows/daemon-spawn.d.ts.map +0 -1
  956. package/dist/workflows/daemon-spawn.js +0 -564
  957. package/dist/workflows/daemon-spawn.js.map +0 -1
  958. package/dist/workflows/effect-input.d.ts +0 -4
  959. package/dist/workflows/effect-input.d.ts.map +0 -1
  960. package/dist/workflows/effect-input.js +0 -19
  961. package/dist/workflows/effect-input.js.map +0 -1
  962. package/dist/workflows/events/append.d.ts +0 -77
  963. package/dist/workflows/events/append.d.ts.map +0 -1
  964. package/dist/workflows/events/append.js +0 -214
  965. package/dist/workflows/events/append.js.map +0 -1
  966. package/dist/workflows/events/idempotency.d.ts +0 -77
  967. package/dist/workflows/events/idempotency.d.ts.map +0 -1
  968. package/dist/workflows/events/idempotency.js +0 -116
  969. package/dist/workflows/events/idempotency.js.map +0 -1
  970. package/dist/workflows/events/index.d.ts +0 -7
  971. package/dist/workflows/events/index.d.ts.map +0 -1
  972. package/dist/workflows/events/index.js +0 -7
  973. package/dist/workflows/events/index.js.map +0 -1
  974. package/dist/workflows/fanout.d.ts +0 -36
  975. package/dist/workflows/fanout.d.ts.map +0 -1
  976. package/dist/workflows/fanout.js +0 -115
  977. package/dist/workflows/fanout.js.map +0 -1
  978. package/dist/workflows/hostExecutors/protocol.d.ts +0 -42
  979. package/dist/workflows/hostExecutors/protocol.d.ts.map +0 -1
  980. package/dist/workflows/hostExecutors/protocol.js +0 -181
  981. package/dist/workflows/hostExecutors/protocol.js.map +0 -1
  982. package/dist/workflows/loader.d.ts +0 -30
  983. package/dist/workflows/loader.d.ts.map +0 -1
  984. package/dist/workflows/loader.js +0 -84
  985. package/dist/workflows/loader.js.map +0 -1
  986. package/dist/workflows/loop.d.ts +0 -50
  987. package/dist/workflows/loop.d.ts.map +0 -1
  988. package/dist/workflows/loop.js +0 -408
  989. package/dist/workflows/loop.js.map +0 -1
  990. package/dist/workflows/orchestrator.d.ts +0 -171
  991. package/dist/workflows/orchestrator.d.ts.map +0 -1
  992. package/dist/workflows/orchestrator.js +0 -609
  993. package/dist/workflows/orchestrator.js.map +0 -1
  994. package/dist/workflows/output-binding.d.ts +0 -77
  995. package/dist/workflows/output-binding.d.ts.map +0 -1
  996. package/dist/workflows/output-binding.js +0 -329
  997. package/dist/workflows/output-binding.js.map +0 -1
  998. package/dist/workflows/params.d.ts.map +0 -1
  999. package/dist/workflows/params.js.map +0 -1
  1000. package/dist/workflows/resume.d.ts +0 -263
  1001. package/dist/workflows/resume.d.ts.map +0 -1
  1002. package/dist/workflows/resume.js +0 -808
  1003. package/dist/workflows/resume.js.map +0 -1
  1004. package/dist/workflows/run-id.d.ts +0 -2
  1005. package/dist/workflows/run-id.d.ts.map +0 -1
  1006. package/dist/workflows/run-id.js +0 -7
  1007. package/dist/workflows/run-id.js.map +0 -1
  1008. package/dist/workflows/run-init.d.ts +0 -48
  1009. package/dist/workflows/run-init.d.ts.map +0 -1
  1010. package/dist/workflows/run-init.js +0 -100
  1011. package/dist/workflows/run-init.js.map +0 -1
  1012. package/dist/workflows/runs-dir.d.ts +0 -4
  1013. package/dist/workflows/runs-dir.d.ts.map +0 -1
  1014. package/dist/workflows/runs-dir.js +0 -15
  1015. package/dist/workflows/runs-dir.js.map +0 -1
  1016. package/dist/workflows/runtime.d.ts +0 -215
  1017. package/dist/workflows/runtime.d.ts.map +0 -1
  1018. package/dist/workflows/runtime.js +0 -630
  1019. package/dist/workflows/runtime.js.map +0 -1
  1020. package/dist/workflows/spawn-bot.d.ts +0 -165
  1021. package/dist/workflows/spawn-bot.d.ts.map +0 -1
  1022. package/dist/workflows/spawn-bot.js +0 -215
  1023. package/dist/workflows/spawn-bot.js.map +0 -1
  1024. package/dist/workflows/spawn-policy.d.ts.map +0 -1
  1025. package/dist/workflows/spawn-policy.js.map +0 -1
  1026. package/dist/workflows/system.d.ts +0 -49
  1027. package/dist/workflows/system.d.ts.map +0 -1
  1028. package/dist/workflows/system.js +0 -48
  1029. package/dist/workflows/system.js.map +0 -1
  1030. package/dist/workflows/trigger-from-envelope.d.ts +0 -13
  1031. package/dist/workflows/trigger-from-envelope.d.ts.map +0 -1
  1032. package/dist/workflows/trigger-from-envelope.js +0 -68
  1033. package/dist/workflows/trigger-from-envelope.js.map +0 -1
  1034. package/dist/workflows/trigger-run.d.ts +0 -70
  1035. package/dist/workflows/trigger-run.d.ts.map +0 -1
  1036. package/dist/workflows/trigger-run.js +0 -88
  1037. package/dist/workflows/trigger-run.js.map +0 -1
  1038. package/dist/workflows/wait.d.ts +0 -141
  1039. package/dist/workflows/wait.d.ts.map +0 -1
  1040. package/dist/workflows/wait.js +0 -203
  1041. package/dist/workflows/wait.js.map +0 -1
package/dist/cli.js CHANGED
@@ -5,13 +5,13 @@
5
5
  * Usage:
6
6
  * botmux setup — interactive first-time configuration
7
7
  * botmux setup --no-open-platform-auto — skip Feishu Open Platform automation
8
- * botmux setup list|add|edit|remove — scripted (non-TUI) bot management, see `botmux setup help`
8
+ * botmux setup list|add|configure|edit|remove — scripted (non-TUI) bot management, see `botmux setup help`
9
9
  * botmux start — start daemon and auto plugin services
10
10
  * botmux stop [--with-plugin] — stop daemon (optionally stop auto plugin services)
11
11
  * botmux restart [--include-pm2] [--with-plugin] — restart daemon, then ensure auto plugin services
12
12
  * botmux logs [--lines] — view daemon logs
13
13
  * botmux status — show daemon status
14
- * botmux upgrade — upgrade to latest version
14
+ * botmux upgrade|update — upgrade to latest version
15
15
  * botmux list — interactive session picker (TUI), attach to tmux
16
16
  * botmux list --plain — plain table output (for piping / scripts)
17
17
  * botmux delete <id> — close a session by ID prefix
@@ -27,9 +27,11 @@ import { homedir } from 'node:os';
27
27
  import { fileURLToPath } from 'node:url';
28
28
  import { createInterface } from 'node:readline';
29
29
  import { createRequire } from 'node:module';
30
- import { createHmac, randomBytes } from 'node:crypto';
30
+ import { randomBytes } from 'node:crypto';
31
31
  import { validateWorkingDir } from './core/working-dir.js';
32
32
  import { resolveSessionContext } from './core/session-marker.js';
33
+ import { resolveBotmuxDataDir } from './core/data-dir.js';
34
+ import { dashboardSecretPath } from './core/dashboard-secret.js';
33
35
  import { parseDispatchBotSpec, buildDispatchMessages, buildRepoPrimeText, buildReportContent, eligibleAutoMentionAliases, offTopicSubBotTopic, resolveReportTarget, resolveSendTarget } from './core/dispatch.js';
34
36
  import { enableAutostart, disableAutostart, autostartStatus, refreshAutostart } from './autostart.js';
35
37
  import { tmuxEnv } from './setup/ensure-tmux.js';
@@ -38,6 +40,7 @@ import { applyBotConfigEdits, assertUniqueBotProcessNames, botProcessName, norma
38
40
  import { resolveCliSelection, selectionKeyForBot } from './setup/cli-selection.js';
39
41
  import { checkCliAvailability, hasAgentLaunchConfigChanged } from './setup/cli-availability.js';
40
42
  import { resolveSetupAppName } from './setup/app-name.js';
43
+ import { blocksSetupBotStart, classifySetupOpenPlatformOutcome, scriptedSetupOpenPlatformReuseOnly, setupOpenPlatformOutcomeJson, setupOpenPlatformRetryCommand, } from './setup/open-platform-outcome.js';
41
44
  import { buildBotFromAddFlags, editInputFromFlags, isScriptedSetupInvocation, maskAppSecret, parseSetupCommand, SETUP_CLI_USAGE, } from './setup/setup-args.js';
42
45
  import { interactiveSelect, pickChoice, pickCliSelection } from './setup/interactive-select.js';
43
46
  import { buildPreset, serializePreset, presetFilename } from './setup/agent-preset.js';
@@ -52,6 +55,10 @@ import { callDashboard } from './cli/dashboard-endpoint.js';
52
55
  import { installLatestBotmuxSync } from './core/maintenance.js';
53
56
  import { formatGlobalInstallCommand, resolveGlobalInstallPlan, UnsupportedGlobalInstallError, } from './utils/global-install.js';
54
57
  import { loadDashboardSecret } from './dashboard/auth.js';
58
+ import { postWorkflowDaemonMutation, } from './workflows/v3/daemon-ipc-client.js';
59
+ import { postWorkflowSessionRunMutation, readWorkflowSessionRelayContext, } from './workflows/v3/session-relay-client.js';
60
+ import { fetchDaemonIpc, loadDaemonIpcSecret } from './core/daemon-ipc-auth.js';
61
+ import { readManagedOriginCapability } from './core/managed-origin-capability.js';
55
62
  import { rejectLikelyWindowsStdinMojibake, decodeStdinBytes } from './cli/stdin-encoding.js';
56
63
  import { formatBotInfoEntriesForCli, formatChatBotsForCli, } from './cli/bots-list-output.js';
57
64
  import { buildFooterAddressing, hasKnownBotMention, knownBotOpenIdsFromCrossRef, orderedFooterRecipients, stripCodeSpans, } from './utils/bot-routing.js';
@@ -62,9 +69,13 @@ import { createWhiteboard, ensureDefaultWhiteboard, getWhiteboard, listWhiteboar
62
69
  import { buildBridgeSendMarkerContent } from './services/bridge-fallback-gate.js';
63
70
  import { writeManualIntentIfAbsentTo } from './services/restart-intent-store.js';
64
71
  import { stripLegacyPendingCardFields } from './services/session-store.js';
72
+ import { evaluateVcMeetingManagedSend, isTrustedVcMeetingHostRelayParent, resolveVcMeetingImTurnOrigin, } from './services/vc-meeting-send-policy.js';
73
+ import { finishVcMeetingImReply, prepareVcMeetingDeliveryReply, prepareVcMeetingImReply, } from './services/vc-meeting-im-reply.js';
74
+ import { recordVcMeetingListenerMessage } from './services/vc-meeting-listener-message-store.js';
65
75
  import { isValidPluginId, normalizePluginIdList } from './core/plugins/ids.js';
66
76
  import { resolveEffectivePluginIds, updateBotPluginOverride } from './core/plugins/effective.js';
67
77
  import { assertPluginBindingTransition, describePluginDependencyError, enabledPluginDependents, } from './core/plugins/dependencies.js';
78
+ import { authorizeV3DaemonCommand } from './workflows/v3/cli-daemon-command-authority.js';
68
79
  // Resolve the CLI's UI locale once from the global config file, so subsequent
69
80
  // CLI output (and any t() callers that don't pass an explicit locale) honour
70
81
  // the user's chosen language. Daemon entrypoint sets this separately for the
@@ -521,19 +532,23 @@ async function finishOpenPlatformSetup(appId, brand, options = {}) {
521
532
  say('\n已跳过开放平台自动配置 (--no-open-platform-auto)。');
522
533
  if (!options.quiet)
523
534
  printRemainingSteps(appId, brand);
524
- return;
535
+ return { status: 'skipped' };
525
536
  }
526
537
  say('\n── 开放平台自动配置 ──\n');
527
- say(options.reuseOnly
528
- ? '将复用创建应用时的 Feishu Web session,自动导入权限、配置 redirect URL 并创建/发布版本;本路径不会再显示二维码。'
529
- : '将获取或复用 Feishu Web session,自动导入权限、配置 redirect URL 并创建/发布版本。');
538
+ say(options.forceQrLogin
539
+ ? '将按 --switch-account 明确重新扫码,自动导入权限、配置 redirect URL 并创建/发布版本。'
540
+ : options.reuseOnly
541
+ ? '将复用创建应用时的 Feishu Web session,自动导入权限、配置 redirect URL 并创建/发布版本;本路径不会再显示二维码。'
542
+ : '将获取或复用 Feishu Web session,自动导入权限、配置 redirect URL 并创建/发布版本。');
530
543
  say('如失败会自动回退到手动步骤提示,不影响已写入的 botmux 配置。\n');
531
544
  const result = await automateOpenPlatformSetup({
532
545
  appId,
533
546
  brand,
547
+ forceQrLogin: options.forceQrLogin,
534
548
  disableQrLogin: options.reuseOnly,
535
- disableBytedcliFallback: options.reuseOnly,
549
+ disableBytedcliFallback: options.reuseOnly || options.forceQrLogin,
536
550
  });
551
+ const outcome = classifySetupOpenPlatformOutcome(result);
537
552
  if (result.ok) {
538
553
  say('✅ 开放平台自动配置完成');
539
554
  say(` Session 来源: ${result.sessionSource}`);
@@ -552,14 +567,15 @@ async function finishOpenPlatformSetup(appId, brand, options = {}) {
552
567
  else
553
568
  say(' 已创建版本;未从响应中解析到 versionId,请到开放平台确认是否需要手动发布。');
554
569
  say('');
555
- return;
570
+ return outcome;
556
571
  }
557
- say(`⚠️ 开放平台自动配置失败 (${result.reason}): ${result.message}`);
572
+ say(`${outcome.status === 'manual' ? 'ℹ️ ' : '⚠️ '} 开放平台自动配置${outcome.status === 'manual' ? '需要手动完成' : '失败'} (${result.reason}): ${result.message}`);
558
573
  if (result.sessionFile)
559
574
  say(` botmux session 文件: ${result.sessionFile}`);
560
575
  say(' 请按下面的手动步骤继续完成开放平台配置。');
561
576
  if (!options.quiet)
562
577
  printRemainingSteps(appId, brand);
578
+ return outcome;
563
579
  }
564
580
  /**
565
581
  * 「选择已有应用」路径:复用/扫码飞书 Web 登录态 → 拉当前账号可见的自建应用
@@ -1265,7 +1281,7 @@ function botJsonView(bot, index) {
1265
1281
  };
1266
1282
  }
1267
1283
  /**
1268
- * `botmux setup list|add|edit|remove` — 脚本化(非 TUI)bot 管理。
1284
+ * `botmux setup list|add|configure|edit|remove` — 脚本化(非 TUI)bot 管理。
1269
1285
  * 给 coding agent / 脚本一个字段级稳定接口,不依赖交互问答顺序(管道喂数字
1270
1286
  * 的老姿势在问题序列变化时会静默错位)。校验口径与 TUI 一致:目录存在性、
1271
1287
  * owner 必填、凭证变更时的 tenant_access_token 校验,任一失败不写盘。
@@ -1299,6 +1315,60 @@ async function cmdSetupScripted(argv) {
1299
1315
  }
1300
1316
  return;
1301
1317
  }
1318
+ if (cmd.action === 'configure') {
1319
+ const index = parseBotSelection(cmd.selector, bots);
1320
+ if (index === undefined) {
1321
+ failSetupScripted(cmd.json, `找不到机器人 "${cmd.selector}"(接受进程名 botmux-N 或 AppID,botmux setup list 可查)。`);
1322
+ return;
1323
+ }
1324
+ const bot = bots[index];
1325
+ const processName = botProcessName(bot, index, PM2_NAME);
1326
+ const openPlatform = await finishOpenPlatformSetup(bot.larkAppId, botBrand(bot), {
1327
+ // Machine-readable callers must never be surprised by an interactive QR.
1328
+ reuseOnly: cmd.json && !cmd.switchAccount,
1329
+ forceQrLogin: cmd.switchAccount,
1330
+ quiet: cmd.json,
1331
+ });
1332
+ if (openPlatform.status === 'failed' || openPlatform.status === 'manual') {
1333
+ const continueCommand = setupOpenPlatformRetryCommand(bot.larkAppId, openPlatform);
1334
+ const next = continueCommand ?? 'manual_open_platform_setup';
1335
+ failSetupScripted(cmd.json, openPlatform.status === 'manual'
1336
+ ? '该租户不支持自动配置,请按开放平台手动步骤完成。'
1337
+ : `开放平台自动配置未完成;机器人配置保留,未自动上线。请修复后重试 ${continueCommand}。`, {
1338
+ partial: true,
1339
+ action: 'configure',
1340
+ bot: botJsonView(bot, index),
1341
+ appId: bot.larkAppId,
1342
+ openPlatform: setupOpenPlatformOutcomeJson(openPlatform),
1343
+ ...(continueCommand ? { continueCommand } : {}),
1344
+ next,
1345
+ });
1346
+ return;
1347
+ }
1348
+ const live = ensureBotDaemonStarted(bot.larkAppId, { quiet: cmd.json });
1349
+ const next = live.ok ? 'live' : (live.reason === 'fleet_down' ? 'botmux start' : 'botmux restart');
1350
+ if (cmd.json) {
1351
+ console.log(JSON.stringify({
1352
+ ok: true,
1353
+ action: 'configure',
1354
+ bot: botJsonView(bot, index),
1355
+ appId: bot.larkAppId,
1356
+ openPlatform: setupOpenPlatformOutcomeJson(openPlatform),
1357
+ live,
1358
+ next,
1359
+ }, null, 2));
1360
+ }
1361
+ else {
1362
+ console.log(`✅ 已完成 ${processName} (${bot.larkAppId}) 的开放平台配置`);
1363
+ if (live.ok)
1364
+ console.log(`✅ 已自动上线(${live.processName})`);
1365
+ else if (live.reason === 'fleet_down')
1366
+ console.log('下一步: botmux start(daemon 尚未运行)');
1367
+ else
1368
+ console.log(`⚠️ 自动上线失败(${live.message})。下一步: botmux restart`);
1369
+ }
1370
+ return;
1371
+ }
1302
1372
  if (cmd.action === 'add') {
1303
1373
  // 单机器人 .env 老配置:与 TUI「添加新机器人」一致,先迁移进 bots.json 再追加。
1304
1374
  let existing = bots;
@@ -1487,13 +1557,40 @@ async function cmdSetupScripted(argv) {
1487
1557
  }
1488
1558
  }
1489
1559
  // 已有凭证模式默认跳过;--create-app 默认开启并复用刚才的 Web session。
1560
+ let openPlatform = { status: 'skipped' };
1490
1561
  if (cmd.openPlatformAuto) {
1491
- await finishOpenPlatformSetup(bot.larkAppId, botBrand(bot), {
1492
- reuseOnly: cmd.createApp && !cmd.compatibilityMode && botBrand(bot) === 'feishu',
1562
+ openPlatform = await finishOpenPlatformSetup(bot.larkAppId, botBrand(bot), {
1563
+ reuseOnly: scriptedSetupOpenPlatformReuseOnly({
1564
+ json: cmd.json,
1565
+ createApp: cmd.createApp,
1566
+ compatibilityMode: cmd.compatibilityMode,
1567
+ brand: botBrand(bot),
1568
+ }),
1493
1569
  quiet: cmd.json,
1494
1570
  });
1495
1571
  }
1496
1572
  const index = existing.length;
1573
+ if (blocksSetupBotStart(openPlatform)) {
1574
+ const continueCommand = setupOpenPlatformRetryCommand(bot.larkAppId, openPlatform);
1575
+ failSetupScripted(cmd.json, `机器人配置已写入,但开放平台自动配置未完成,未自动上线。修复后运行 ${continueCommand};不会重复创建应用。`, {
1576
+ partial: true,
1577
+ action: 'add',
1578
+ bot: botJsonView(bot, index),
1579
+ appId: bot.larkAppId,
1580
+ ...(createdAppName ? { appName: createdAppName } : {}),
1581
+ botsFile: BOTS_JSON_FILE,
1582
+ envMigrated: migratedEnv || undefined,
1583
+ openPlatform: setupOpenPlatformOutcomeJson(openPlatform),
1584
+ continueCommand,
1585
+ live: {
1586
+ ok: false,
1587
+ reason: 'open_platform_incomplete',
1588
+ message: '开放平台关键配置未完成,未启动新机器人',
1589
+ },
1590
+ next: continueCommand,
1591
+ });
1592
+ return;
1593
+ }
1497
1594
  // daemon 在跑就直接把新 bot 那一个进程拉起来,免整组 botmux restart。
1498
1595
  const live = ensureBotDaemonStarted(bot.larkAppId, { quiet: cmd.json });
1499
1596
  const next = live.ok ? 'live' : (live.reason === 'fleet_down' ? 'botmux start' : 'botmux restart');
@@ -1506,7 +1603,7 @@ async function cmdSetupScripted(argv) {
1506
1603
  ...(cmd.createApp && botBrand(bot) === 'feishu' && !cmd.compatibilityMode ? { appName: resolveSetupAppName(cmd.flags.appName, index) } : {}),
1507
1604
  botsFile: BOTS_JSON_FILE,
1508
1605
  envMigrated: migratedEnv || undefined,
1509
- openPlatform: cmd.openPlatformAuto ? 'attempted' : 'skipped',
1606
+ openPlatform: setupOpenPlatformOutcomeJson(openPlatform),
1510
1607
  live,
1511
1608
  next,
1512
1609
  }, null, 2));
@@ -2021,7 +2118,7 @@ async function cmdStart() {
2021
2118
  * the pm2 zombie-cleanup flow so the dashboard registry stays consistent.
2022
2119
  */
2023
2120
  function cleanupStaleDaemonDescriptors() {
2024
- const regDir = join(DATA_DIR, 'dashboard-daemons');
2121
+ const regDir = join(resolveDataDir(), 'dashboard-daemons');
2025
2122
  if (!existsSync(regDir))
2026
2123
  return;
2027
2124
  for (const f of readdirSync(regDir)) {
@@ -2598,28 +2695,7 @@ async function cmdDashboard() {
2598
2695
  * Priority: SESSION_DATA_DIR env > daemon breadcrumb (~/.botmux/.data-dir) > default (~/.botmux/data)
2599
2696
  */
2600
2697
  function resolveDataDir() {
2601
- if (process.env.SESSION_DATA_DIR)
2602
- return process.env.SESSION_DATA_DIR;
2603
- // Read breadcrumb written by the daemon at startup
2604
- const breadcrumb = join(CONFIG_DIR, '.data-dir');
2605
- if (existsSync(breadcrumb)) {
2606
- try {
2607
- const dir = readFileSync(breadcrumb, 'utf-8').trim();
2608
- if (dir && existsSync(dir)) {
2609
- // Check for any session file (legacy or per-bot)
2610
- if (existsSync(join(dir, 'sessions.json')))
2611
- return dir;
2612
- try {
2613
- const files = readdirSync(dir);
2614
- if (files.some(f => f.startsWith('sessions-') && f.endsWith('.json')))
2615
- return dir;
2616
- }
2617
- catch { /* ignore */ }
2618
- }
2619
- }
2620
- catch { /* ignore */ }
2621
- }
2622
- return DATA_DIR;
2698
+ return resolveBotmuxDataDir();
2623
2699
  }
2624
2700
  /** Load sessions from all session files (legacy + per-bot). */
2625
2701
  function loadSessions() {
@@ -3393,7 +3469,7 @@ async function cmdSuspend() {
3393
3469
  continue;
3394
3470
  }
3395
3471
  try {
3396
- const res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/sessions/${encodeURIComponent(s.sessionId)}/suspend`, { method: 'POST' });
3472
+ const res = await fetchDaemonIpc(daemon.ipcPort, `/api/sessions/${encodeURIComponent(s.sessionId)}/suspend`, { method: 'POST' });
3397
3473
  const body = await res.json().catch(() => ({}));
3398
3474
  if (res.ok && body?.ok) {
3399
3475
  if (body.suspended) {
@@ -3424,6 +3500,120 @@ async function cmdSuspend() {
3424
3500
  if (failed > 0)
3425
3501
  process.exitCode = 1;
3426
3502
  }
3503
+ /** 会话级 CLI IPC(slash/cd)的 POST:与 postAsk 同款双路径——能读 host secret
3504
+ * (非隔离进程)走 trusted-host HMAC 签名;读不到(沙箱 BOTMUX_SEND_RELAY /
3505
+ * macOS 读隔离 carve-out)改带本会话当前轮换的 origin capability,由 daemon
3506
+ * handler 与活跃记录比对。两条路都不读 bots.json。 */
3507
+ async function postSessionCliIpc(ipcPort, sessionId, route, payload) {
3508
+ const requestBody = { ...payload };
3509
+ let hostSecret;
3510
+ if (!process.env.BOTMUX_SEND_RELAY) {
3511
+ try {
3512
+ hostSecret = loadDaemonIpcSecret();
3513
+ }
3514
+ catch { /* sandboxed/read-isolated: capability fallback below */ }
3515
+ }
3516
+ if (!hostSecret) {
3517
+ const claim = readManagedOriginCapability(resolveDataDir(), sessionId, process.env.BOTMUX_SEND_RELAY);
3518
+ if (claim) {
3519
+ requestBody.originCapability = claim.capability;
3520
+ if (claim.turnId)
3521
+ requestBody.originTurnId = claim.turnId;
3522
+ if (claim.dispatchAttempt !== undefined)
3523
+ requestBody.originDispatchAttempt = claim.dispatchAttempt;
3524
+ }
3525
+ }
3526
+ const path = `/api/sessions/${encodeURIComponent(sessionId)}/${route}`;
3527
+ const init = {
3528
+ method: 'POST',
3529
+ headers: { 'content-type': 'application/json' },
3530
+ body: JSON.stringify(requestBody),
3531
+ };
3532
+ return hostSecret
3533
+ ? fetchDaemonIpc(ipcPort, path, init, hostSecret)
3534
+ : fetch(`http://127.0.0.1:${ipcPort}${path}`, init);
3535
+ }
3536
+ /** botmux slash "<斜杠命令>":请求 daemon 在本会话 idle 后把命令敲入自己的 CLI。
3537
+ * 自识别当前会话(pid marker → BOTMUX_SESSION_ID env),allowlist 由 daemon 侧校验。 */
3538
+ async function cmdSlash() {
3539
+ const argv = process.argv.slice(3);
3540
+ const sIdx = argv.indexOf('--session');
3541
+ const explicitSid = sIdx >= 0 ? argv[sIdx + 1] : undefined;
3542
+ // 所有非 flag 位置参数 join(' '),而不是只取第一个——未加引号的命令若含空格
3543
+ // (如 `botmux slash /model opus`)此前会被截断成 `/model`。
3544
+ const command = argv.filter((a, i) => !a.startsWith('--') && !(sIdx >= 0 && i === sIdx + 1)).join(' ');
3545
+ if (!command) {
3546
+ console.error('用法: botmux slash "/compact" [--session <id>]');
3547
+ process.exit(1);
3548
+ }
3549
+ const ctx = explicitSid ? null : findAncestorSessionContext();
3550
+ const sid = explicitSid ?? ctx?.sessionId;
3551
+ if (!sid) {
3552
+ console.error('❌ 无法定位当前会话(需在 bot 会话内执行,或用 --session 指定)');
3553
+ process.exit(1);
3554
+ }
3555
+ const sessions = loadSessions();
3556
+ const s = [...sessions.values()].find(x => x.sessionId === sid || x.sessionId.startsWith(sid));
3557
+ if (!s) {
3558
+ console.error(`❌ 未找到 session ${sid}`);
3559
+ process.exit(1);
3560
+ }
3561
+ const daemon = findDaemon(s.larkAppId);
3562
+ if (!daemon) {
3563
+ console.error('❌ daemon 不在线');
3564
+ process.exit(1);
3565
+ }
3566
+ const res = await postSessionCliIpc(daemon.ipcPort, s.sessionId, 'slash', { command });
3567
+ const body = await res.json().catch(() => ({}));
3568
+ if (res.ok && body?.ok) {
3569
+ console.log(`✓ 已排队注入: ${body.queued}(会话空闲时执行;CLI 进程若在执行前重启则丢弃)`);
3570
+ return;
3571
+ }
3572
+ console.error(`✗ 被拒绝: ${body?.error ?? `HTTP ${res.status}`}`);
3573
+ process.exit(1);
3574
+ }
3575
+ /** botmux cd <角色目录>:请求 daemon 重钉本话题工作目录(角色切换)。
3576
+ * daemon 侧校验目录必须在 ~/botmux-roles 下;Claude 家族 idle 注入 /cd 不重启,
3577
+ * 其余 CLI 杀进程冷启动。协议要求本命令是该轮最后一个动作。 */
3578
+ async function cmdCd() {
3579
+ const argv = process.argv.slice(3);
3580
+ const sIdx = argv.indexOf('--session');
3581
+ const explicitSid = sIdx >= 0 ? argv[sIdx + 1] : undefined;
3582
+ // 所有非 flag 位置参数 join(' '),而不是只取第一个——路径含空格且未加引号时
3583
+ // (如 `botmux cd ~/botmux-roles/我的 角色`)此前会被截断。
3584
+ const dir = argv.filter((a, i) => !a.startsWith('--') && !(sIdx >= 0 && i === sIdx + 1)).join(' ');
3585
+ if (!dir) {
3586
+ console.error('用法: botmux cd <目标目录(含空格建议加引号)> [--session <id>]');
3587
+ process.exit(1);
3588
+ }
3589
+ const ctx = explicitSid ? null : findAncestorSessionContext();
3590
+ const sid = explicitSid ?? ctx?.sessionId;
3591
+ if (!sid) {
3592
+ console.error('❌ 无法定位当前会话(需在 bot 会话内执行,或用 --session 指定)');
3593
+ process.exit(1);
3594
+ }
3595
+ const sessions = loadSessions();
3596
+ const s = [...sessions.values()].find(x => x.sessionId === sid || x.sessionId.startsWith(sid));
3597
+ if (!s) {
3598
+ console.error(`❌ 未找到 session ${sid}`);
3599
+ process.exit(1);
3600
+ }
3601
+ const daemon = findDaemon(s.larkAppId);
3602
+ if (!daemon) {
3603
+ console.error('❌ daemon 不在线');
3604
+ process.exit(1);
3605
+ }
3606
+ const res = await postSessionCliIpc(daemon.ipcPort, s.sessionId, 'cd', { dir });
3607
+ const body = await res.json().catch(() => ({}));
3608
+ if (res.ok && body?.ok) {
3609
+ console.log(body.mode === 'inject'
3610
+ ? `✓ 已切换到 ${body.dir}(会话空闲时生效,进程不重启)`
3611
+ : `✓ 已切换到 ${body.dir}(下条消息在新目录冷启动)`);
3612
+ return;
3613
+ }
3614
+ console.error(`✗ 切换被拒绝: ${body?.error ?? `HTTP ${res.status}`}`);
3615
+ process.exit(1);
3616
+ }
3427
3617
  /**
3428
3618
  * Discover online daemons. Mirrors the staleness rule used by
3429
3619
  * dashboard/registry.ts (90s heartbeat) so we don't try to talk to a daemon
@@ -3454,7 +3644,17 @@ function listOnlineDaemons() {
3454
3644
  continue;
3455
3645
  if (now - (d.lastHeartbeat ?? 0) > STALE_MS)
3456
3646
  continue;
3457
- all.push({ ipcPort: d.ipcPort, larkAppId: d.larkAppId, lastHeartbeat: d.lastHeartbeat });
3647
+ all.push({
3648
+ ipcPort: d.ipcPort,
3649
+ larkAppId: d.larkAppId,
3650
+ ...(typeof d.bootInstanceId === 'string' && d.bootInstanceId
3651
+ ? { bootInstanceId: d.bootInstanceId }
3652
+ : {}),
3653
+ ...(typeof d.workflowIpcProtocol === 'string' && d.workflowIpcProtocol
3654
+ ? { workflowIpcProtocol: d.workflowIpcProtocol }
3655
+ : {}),
3656
+ lastHeartbeat: d.lastHeartbeat,
3657
+ });
3458
3658
  }
3459
3659
  catch { /* skip malformed */ }
3460
3660
  }
@@ -3466,74 +3666,245 @@ function findDaemon(larkAppId) {
3466
3666
  return all.find(d => d.larkAppId === larkAppId) ?? null;
3467
3667
  return all[0] ?? null;
3468
3668
  }
3469
- /** `botmux workflow start <runId>` — POST the daemon's v3 start IPC so the run
3470
- * is daemon-driven (humanGate 飞书审批卡). The grill skill calls this after
3471
- * approve-dag instead of the standalone `botmux v3 run` (which has no card
3472
- * layer). Defaults the bot to the grill worker's BOTMUX_LARK_APP_ID env. */
3473
- async function cmdWorkflowStart(runId, rest) {
3669
+ /**
3670
+ * Authenticate the human who opened this exact turn against the target run,
3671
+ * then return the only daemon app that may receive the mutation. Inherited
3672
+ * BOTMUX_LARK_APP_ID is deliberately not an authority (long-lived sessions
3673
+ * keep it even when a different human opens a later turn).
3674
+ */
3675
+ function authorizeWorkflowDaemonCommand(runId, rest) {
3676
+ return authorizeV3DaemonCommand({
3677
+ runId,
3678
+ dataDir: resolveDataDir(),
3679
+ envSessionId: process.env.BOTMUX_SESSION_ID,
3680
+ requestedLarkAppId: argValue(rest, '--bot'),
3681
+ }).larkAppId;
3682
+ }
3683
+ /**
3684
+ * Isolated-session fallback for workflow daemon mutations. Inside a Linux
3685
+ * bwrap sandbox or a macOS read-isolated session every leg of the host path
3686
+ * above is masked by design (process-tree marker, run directory,
3687
+ * `.dashboard-secret`), so the CLI instead presents its per-turn rotating
3688
+ * capability and lets the daemon re-derive the caller/chat/bot tuple from its
3689
+ * own live session record (workflows/v3/session-relay.ts). Detection is
3690
+ * marker-first (a visible live process marker → host path, so a stale
3691
+ * capability file can never hijack a healthy host session), then falls back
3692
+ * to the worker-published capability file that only isolated sessions have.
3693
+ * `--bot` is meaningless here — the run must be bound to this very session's
3694
+ * chat tuple, which pins the daemon.
3695
+ */
3696
+ async function tryWorkflowSessionRelayMutation(runId, mutation, body) {
3697
+ const context = readWorkflowSessionRelayContext({
3698
+ env: process.env,
3699
+ dataDir: resolveDataDir(),
3700
+ });
3701
+ if (!context)
3702
+ return null;
3703
+ try {
3704
+ return await postWorkflowSessionRunMutation({
3705
+ context,
3706
+ runId,
3707
+ mutation,
3708
+ ...(body ? { body } : {}),
3709
+ resolveIpcPort: (larkAppId) => {
3710
+ // Daemon discovery is host state — masked in-sandbox, best-effort under
3711
+ // read isolation. The BOTMUX_DAEMON_IPC_PORT fallback inside the client
3712
+ // covers the masked case.
3713
+ try {
3714
+ return larkAppId ? findDaemon(larkAppId)?.ipcPort : undefined;
3715
+ }
3716
+ catch {
3717
+ return undefined;
3718
+ }
3719
+ },
3720
+ });
3721
+ }
3722
+ catch (err) {
3723
+ console.error(`❌ ${err instanceof Error ? err.message : String(err)}`);
3724
+ process.exit(1);
3725
+ }
3726
+ }
3727
+ /** `botmux workflow cancel <runId>` — authenticate the exact current caller
3728
+ * against the immutable run binding, then ask the owning daemon to durably
3729
+ * record cancellation before interrupting workers. */
3730
+ async function cmdWorkflowCancelV3(runId, rest) {
3474
3731
  if (!runId) {
3475
- console.error('用法: botmux workflow start <runId> [--bot <larkAppId>]');
3732
+ console.error('用法: botmux workflow cancel <runId> [--reason <text>] [--bot <larkAppId>]');
3476
3733
  process.exit(1);
3477
3734
  }
3478
- const larkAppId = argValue(rest, '--bot') ?? process.env.BOTMUX_LARK_APP_ID;
3479
- const daemon = findDaemon(larkAppId);
3735
+ const { formatV3RunCancelCliSuccess, parseV3RunCancelCliOptions, parseV3RunCancelDaemonResponse, } = await import('./cli/v3-run-cancel.js');
3736
+ const parsed = parseV3RunCancelCliOptions(rest);
3737
+ if (!parsed.ok) {
3738
+ console.error(`❌ ${parsed.error}`);
3739
+ console.error('用法: botmux workflow cancel <runId> [--reason <text>] [--bot <larkAppId>]');
3740
+ process.exit(1);
3741
+ }
3742
+ const reason = parsed.reason;
3743
+ // An isolated session can only cancel a daemon-bound chat run (a standalone
3744
+ // manual_cli run lives on masked host disk anyway), so relay short-circuits
3745
+ // ahead of the host authority/standalone branching.
3746
+ const relayed = await tryWorkflowSessionRelayMutation(runId, 'cancel', reason ? { reason } : {});
3747
+ if (relayed) {
3748
+ try {
3749
+ console.log(formatV3RunCancelCliSuccess(parseV3RunCancelDaemonResponse(relayed)));
3750
+ }
3751
+ catch (err) {
3752
+ console.error(`❌ ${err instanceof Error ? err.message : String(err)}`);
3753
+ process.exit(1);
3754
+ }
3755
+ return;
3756
+ }
3757
+ const authority = authorizeV3DaemonCommand({
3758
+ runId,
3759
+ dataDir: resolveDataDir(),
3760
+ envSessionId: process.env.BOTMUX_SESSION_ID,
3761
+ requestedLarkAppId: parsed.larkAppId,
3762
+ allowStandaloneLocal: true,
3763
+ });
3764
+ if (authority.mode === 'standalone') {
3765
+ // A manual_cli run is owned by its foreground/local runtime, not a daemon.
3766
+ // Persisting the shared journal intent is sufficient: runWorkflow polls the
3767
+ // durable cut while a worker is active and aborts it within one tick.
3768
+ const { requestV3RunCancel } = await import('./workflows/v3/daemon-run.js');
3769
+ let outcome;
3770
+ try {
3771
+ outcome = requestV3RunCancel(dirname(authority.runDir), runId, {
3772
+ by: 'standalone-cli',
3773
+ ...(reason ? { reason } : {}),
3774
+ });
3775
+ }
3776
+ catch (err) {
3777
+ console.error(`❌ ${err instanceof Error ? err.message : String(err)}`);
3778
+ process.exit(1);
3779
+ }
3780
+ if (outcome.kind === 'stale-run')
3781
+ throw new Error(`找不到 v3 run ${runId}`);
3782
+ if (outcome.kind === 'already-terminal') {
3783
+ console.log(formatV3RunCancelCliSuccess({
3784
+ ok: true, runId, status: outcome.status, alreadyTerminal: true,
3785
+ }));
3786
+ return;
3787
+ }
3788
+ if (outcome.kind === 'already-cancelled') {
3789
+ console.log(formatV3RunCancelCliSuccess({
3790
+ ok: true, runId, status: 'cancelled', alreadyTerminal: true,
3791
+ ...(outcome.cancelRequestId ? { cancelRequestId: outcome.cancelRequestId } : {}),
3792
+ }));
3793
+ return;
3794
+ }
3795
+ console.log(formatV3RunCancelCliSuccess({
3796
+ ok: true,
3797
+ runId,
3798
+ status: 'cancelling',
3799
+ cancelRequestId: outcome.cancelRequestId,
3800
+ alreadyRequested: outcome.kind === 'already-requested',
3801
+ }));
3802
+ return;
3803
+ }
3804
+ const daemon = findDaemon(authority.larkAppId);
3480
3805
  if (!daemon) {
3481
- console.error('❌ 没有在线 daemon;v3 humanGate run 需要 daemon 驱动(审批卡是 daemon 的活)。');
3806
+ console.error('❌ 没有在线的目标 daemon;v3 run 取消需要由所属 daemon 持久化并中断节点。');
3482
3807
  process.exit(1);
3483
3808
  }
3484
- let res;
3809
+ let secret = null;
3485
3810
  try {
3486
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/v3/runs/${encodeURIComponent(runId)}/start`, {
3487
- method: 'POST',
3488
- headers: { 'content-type': 'application/json' },
3489
- body: '{}',
3811
+ secret = loadDashboardSecret(dashboardSecretPath());
3812
+ }
3813
+ catch (err) {
3814
+ console.error(`❌ 无法读取 .dashboard-secret:${err instanceof Error ? err.message : String(err)}`);
3815
+ process.exit(1);
3816
+ }
3817
+ if (!secret) {
3818
+ console.error('❌ 缺少 .dashboard-secret,无法认证 v3 cancel daemon 请求;请先重启 botmux 初始化。');
3819
+ process.exit(1);
3820
+ }
3821
+ try {
3822
+ const { postV3RunCancel } = await import('./cli/v3-run-cancel.js');
3823
+ const result = await postV3RunCancel({
3824
+ daemon,
3825
+ runId,
3826
+ secret,
3827
+ ...(reason ? { reason } : {}),
3490
3828
  });
3829
+ console.log(formatV3RunCancelCliSuccess(result));
3491
3830
  }
3492
3831
  catch (err) {
3493
- console.error(`❌ 无法连接 daemon (port=${daemon.ipcPort}): ${err?.message ?? err}`);
3832
+ console.error(`❌ ${err instanceof Error ? err.message : String(err)}`);
3494
3833
  process.exit(1);
3495
3834
  }
3496
- const txt = await res.text();
3497
- if (!res.ok) {
3498
- console.error(`❌ start 失败 (HTTP ${res.status}): ${txt}`);
3835
+ }
3836
+ /** `botmux workflow start <runId>` — POST the daemon's v3 start IPC so the run
3837
+ * is daemon-driven (humanGate → 飞书审批卡). The grill skill calls this after
3838
+ * approve-dag instead of the standalone `botmux v3 run` (which has no card
3839
+ * layer). The daemon is selected from the authenticated run/current-turn
3840
+ * binding, never from the worker's static BOTMUX_LARK_APP_ID env. */
3841
+ async function cmdWorkflowStart(runId, rest) {
3842
+ if (!runId) {
3843
+ console.error('用法: botmux workflow start <runId> [--bot <larkAppId>]');
3844
+ process.exit(1);
3845
+ }
3846
+ let response = await tryWorkflowSessionRelayMutation(runId, 'start');
3847
+ if (!response) {
3848
+ const larkAppId = authorizeWorkflowDaemonCommand(runId, rest);
3849
+ const daemon = findDaemon(larkAppId);
3850
+ if (!daemon) {
3851
+ console.error('❌ 没有在线 daemon;v3 humanGate run 需要 daemon 驱动(审批卡是 daemon 的活)。');
3852
+ process.exit(1);
3853
+ }
3854
+ try {
3855
+ response = await postWorkflowDaemonMutation({
3856
+ daemon,
3857
+ runId,
3858
+ mutation: 'start',
3859
+ });
3860
+ }
3861
+ catch (err) {
3862
+ console.error(`❌ ${err?.message ?? err}`);
3863
+ process.exit(1);
3864
+ }
3865
+ }
3866
+ if (!response.ok) {
3867
+ console.error(`❌ start 失败 (HTTP ${response.status}): ${response.bodyRaw}`);
3499
3868
  process.exit(1);
3500
3869
  }
3501
3870
  console.log(`✅ v3 run "${runId}" 已交 daemon 驱动;humanGate 会在话题里弹审批卡,点了才继续。`);
3502
3871
  }
3503
3872
  /** `botmux workflow retry <runId> [--node <id>]` — blocked 节点重试入口(CLI 侧)。
3504
3873
  * 走 daemon 的 retry IPC(journal 写入留在 daemon 进程内,单写者),daemon append
3505
- * `nodeRetryRequested` 后以新 attempt 重驱动。`resume` 动词归 v0.2,v3 用 retry 避撞。 */
3874
+ * `nodeRetryRequested` 后以新 attempt 重驱动;已退休的 v2 `resume` 不再参与分发。 */
3506
3875
  async function cmdWorkflowRetry(runId, rest) {
3507
3876
  if (!runId) {
3508
3877
  console.error('用法: botmux workflow retry <runId> [--node <nodeId>] [--bot <larkAppId>]');
3509
3878
  process.exit(1);
3510
3879
  }
3511
- const larkAppId = argValue(rest, '--bot') ?? process.env.BOTMUX_LARK_APP_ID;
3512
3880
  const nodeId = argValue(rest, '--node');
3513
- const daemon = findDaemon(larkAppId);
3514
- if (!daemon) {
3515
- console.error('❌ 没有在线 daemon;blocked 重试需要 daemon 驱动。');
3516
- process.exit(1);
3517
- }
3518
- let res;
3519
- try {
3520
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/v3/runs/${encodeURIComponent(runId)}/retry`, {
3521
- method: 'POST',
3522
- headers: { 'content-type': 'application/json' },
3523
- body: JSON.stringify(nodeId ? { nodeId } : {}),
3524
- });
3525
- }
3526
- catch (err) {
3527
- console.error(`❌ 无法连接 daemon (port=${daemon.ipcPort}): ${err?.message ?? err}`);
3528
- process.exit(1);
3881
+ let response = await tryWorkflowSessionRelayMutation(runId, 'retry', nodeId ? { nodeId } : {});
3882
+ if (!response) {
3883
+ const larkAppId = authorizeWorkflowDaemonCommand(runId, rest);
3884
+ const daemon = findDaemon(larkAppId);
3885
+ if (!daemon) {
3886
+ console.error('❌ 没有在线 daemon;blocked 重试需要 daemon 驱动。');
3887
+ process.exit(1);
3888
+ }
3889
+ try {
3890
+ response = await postWorkflowDaemonMutation({
3891
+ daemon,
3892
+ runId,
3893
+ mutation: 'retry',
3894
+ body: nodeId ? { nodeId } : {},
3895
+ });
3896
+ }
3897
+ catch (err) {
3898
+ console.error(`❌ ${err?.message ?? err}`);
3899
+ process.exit(1);
3900
+ }
3529
3901
  }
3530
- const txt = await res.text();
3531
- if (!res.ok) {
3532
- if (txt.includes('loop_node_use_grant')) {
3902
+ if (!response.ok) {
3903
+ if (response.bodyRaw.includes('loop_node_use_grant')) {
3533
3904
  console.error(`❌ 该受阻的是一个 loop(轮数耗尽),不是节点 attempt——用 \`botmux workflow grant ${runId}\` 追加一轮。`);
3534
3905
  }
3535
3906
  else {
3536
- console.error(`❌ retry 失败 (HTTP ${res.status}): ${txt}`);
3907
+ console.error(`❌ retry 失败 (HTTP ${response.status}): ${response.bodyRaw}`);
3537
3908
  }
3538
3909
  process.exit(1);
3539
3910
  }
@@ -3547,28 +3918,30 @@ async function cmdWorkflowGrant(runId, rest) {
3547
3918
  console.error('用法: botmux workflow grant <runId> [--loop <loopId>] [--bot <larkAppId>]');
3548
3919
  process.exit(1);
3549
3920
  }
3550
- const larkAppId = argValue(rest, '--bot') ?? process.env.BOTMUX_LARK_APP_ID;
3551
3921
  const loopId = argValue(rest, '--loop');
3552
- const daemon = findDaemon(larkAppId);
3553
- if (!daemon) {
3554
- console.error('❌ 没有在线 daemon;loop 追加需要 daemon 驱动。');
3555
- process.exit(1);
3556
- }
3557
- let res;
3558
- try {
3559
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/v3/runs/${encodeURIComponent(runId)}/grant`, {
3560
- method: 'POST',
3561
- headers: { 'content-type': 'application/json' },
3562
- body: JSON.stringify(loopId ? { loopId } : {}),
3563
- });
3564
- }
3565
- catch (err) {
3566
- console.error(`❌ 无法连接 daemon (port=${daemon.ipcPort}): ${err?.message ?? err}`);
3567
- process.exit(1);
3922
+ let response = await tryWorkflowSessionRelayMutation(runId, 'grant', loopId ? { loopId } : {});
3923
+ if (!response) {
3924
+ const larkAppId = authorizeWorkflowDaemonCommand(runId, rest);
3925
+ const daemon = findDaemon(larkAppId);
3926
+ if (!daemon) {
3927
+ console.error('❌ 没有在线 daemon;loop 追加需要 daemon 驱动。');
3928
+ process.exit(1);
3929
+ }
3930
+ try {
3931
+ response = await postWorkflowDaemonMutation({
3932
+ daemon,
3933
+ runId,
3934
+ mutation: 'grant',
3935
+ body: loopId ? { loopId } : {},
3936
+ });
3937
+ }
3938
+ catch (err) {
3939
+ console.error(`❌ ${err?.message ?? err}`);
3940
+ process.exit(1);
3941
+ }
3568
3942
  }
3569
- const txt = await res.text();
3570
- if (!res.ok) {
3571
- console.error(`❌ grant 失败 (HTTP ${res.status}): ${txt}`);
3943
+ if (!response.ok) {
3944
+ console.error(`❌ grant 失败 (HTTP ${response.status}): ${response.bodyRaw}`);
3572
3945
  process.exit(1);
3573
3946
  }
3574
3947
  console.log(`➕ v3 run "${runId}" 已追加一轮,loop 将带上一轮反馈重跑。`);
@@ -3628,7 +4001,7 @@ async function cmdResume() {
3628
4001
  }
3629
4002
  let res;
3630
4003
  try {
3631
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/sessions/${encodeURIComponent(session.sessionId)}/resume`, { method: 'POST' });
4004
+ res = await fetchDaemonIpc(daemon.ipcPort, `/api/sessions/${encodeURIComponent(session.sessionId)}/resume`, { method: 'POST' });
3632
4005
  }
3633
4006
  catch (err) {
3634
4007
  console.error(`❌ 无法连接到 daemon (port=${daemon.ipcPort}): ${err?.message ?? err}`);
@@ -3727,25 +4100,9 @@ async function cmdTermLink(rest) {
3727
4100
  console.error('❌ 未找到在线 daemon。请确认 daemon 正在运行:botmux status');
3728
4101
  process.exit(1);
3729
4102
  }
3730
- const SECRET_PATH = join(CONFIG_DIR, '.dashboard-secret');
3731
- let secret;
3732
- try {
3733
- secret = loadDashboardSecret(SECRET_PATH);
3734
- }
3735
- catch (e) {
3736
- console.error(`❌ 无法读取 .dashboard-secret:${e.message}`);
3737
- process.exit(1);
3738
- }
3739
- if (!secret) {
3740
- console.error('❌ 缺少或为空 .dashboard-secret(daemon 未初始化)。先 `botmux restart`。');
3741
- process.exit(1);
3742
- }
3743
- const ts = Math.floor(Date.now() / 1000).toString();
3744
- const nonce = randomBytes(8).toString('hex');
3745
- const sig = createHmac('sha256', secret).update(`${ts}:${nonce}`).digest('base64url');
3746
4103
  let res;
3747
4104
  try {
3748
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/sessions/${encodeURIComponent(session.sessionId)}/write-link-card`, { method: 'POST', headers: { 'X-Botmux-Cli-Ts': ts, 'X-Botmux-Cli-Nonce': nonce, 'X-Botmux-Cli-Auth': sig } });
4105
+ res = await fetchDaemonIpc(daemon.ipcPort, `/api/sessions/${encodeURIComponent(session.sessionId)}/write-link-card`, { method: 'POST' });
3749
4106
  }
3750
4107
  catch (err) {
3751
4108
  console.error(`❌ 无法连接到 daemon (port=${daemon.ipcPort}): ${err?.message ?? err}`);
@@ -3799,7 +4156,7 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
3799
4156
  restart 重启 daemon(默认不停止插件 service,core 启动后确保 mode=auto 正在运行;--with-plugin 显式先停再启动 auto service;--include-pm2 同时重启 PM2 God)
3800
4157
  logs 查看 daemon 日志(--lines N, --bot <0-based-index|pm2-name|appId>)
3801
4158
  status 查看 daemon 状态
3802
- upgrade 升级到最新版本
4159
+ upgrade 升级到最新版本(别名:update)
3803
4160
  dashboard 打印新的 Web Dashboard 一次性登录 URL(旧 token 同时失效)
3804
4161
  list 列出活跃会话(交互式选择并连接 tmux)
3805
4162
  --plain 纯文本表格输出(管道/脚本场景)
@@ -3812,6 +4169,9 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
3812
4169
  --bot <appId> 挂起该 bot 的全部活跃会话
3813
4170
  --isolated 挂起所有读隔离 bot(凭证轮换后用;下次冷启动自动同步最新凭证)
3814
4171
  --dry-run 只列出目标,不执行
4172
+ slash "<斜杠命令>" 会话空闲后向本会话 CLI 注入一条原生斜杠命令(需 bots.json 配 tuiSlashAllow;/cd 恒被拒)
4173
+ cd <目录> (会话内)切换本话题工作目录到角色库内的目录——角色切换用;
4174
+ 目录必须位于 ~/botmux-roles 之下
3815
4175
  term-link [id] 获取活跃会话的「可操作终端」(带写 token)。不回显链接,改由
3816
4176
  daemon 把可操作卡片私密发给 owner(群内仅你可见,话题/单聊回退 DM)。
3817
4177
  单个活跃会话可省略 id
@@ -3891,9 +4251,23 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
3891
4251
  skill list 列出本会话可用的技能(用户自定义 + botmux 内置)及其描述
3892
4252
  skill show <name> 读取某技能的完整 SKILL.md 说明(prompt 注入模式下按需拉取内置技能全文)
3893
4253
 
3894
- 编排 / workflow(进阶,多为 v3/多话题协作场景):
3895
- workflow <run|resume|cancel|ls|tail|validate|show> [...]
3896
- 运行 / 管理 workflow(详见 \`botmux workflow help\`)
4254
+ 编排 / workflowv3):
4255
+ workflow save [last|runId] [名称]
4256
+ 把成功 run 固化为 chat scope Saved Workflow;
4257
+ 发布当前 Bot 全局版本 / 确认 unsafe lint 请由用户在飞书显式发送 /workflow save ...
4258
+ workflow run <名称|workflowId> [--param key=value ...]
4259
+ workflow list [--json] | show <名称|workflowId>
4260
+ 运行 / 查看 Saved Workflow
4261
+ workflow new|spec-finalize|approve-spec|revise-spec|architect|revise-dag [...]
4262
+ workflow approve-dag|start [...] 创建、修订并运行一次性即兴 Workflow
4263
+ workflow cancel <runId> [--reason <text>] [--bot <larkAppId>]
4264
+ 持久化取消 v3 run 并中断活动节点
4265
+ workflow retry|grant [...] 处理受阻节点 / loop
4266
+ template migrate-v3 [id|path ...] [--all] [--commit ...]
4267
+ v2 定义迁移:默认 dry-run,写入需显式 owner/app/scope
4268
+ template archive-runs [--commit|--verify <archive>|--retire <archive> --ack-daemon-stopped]
4269
+ v2 历史 run 私有静态归档;retire 在维护窗双验后原子迁入 quarantine
4270
+ (完整参数见 \`botmux workflow help\` / \`botmux template help\`)
3897
4271
  dispatch --bot <name> [...] 多话题编排:开子话题并把 bot 派进去(详见 \`botmux dispatch --help\`)
3898
4272
  report [...] v3/编排场景向上汇报进度或结果(详见 \`botmux report --help\`)
3899
4273
 
@@ -3930,7 +4304,17 @@ botmux skills 注入方式(仅影响 codex/gemini/opencode 等只支持全局
3930
4304
  * the env fallback is safe.
3931
4305
  */
3932
4306
  function findAncestorSessionContext() {
3933
- return resolveSessionContext(resolveDataDir(), process.env.BOTMUX_SESSION_ID);
4307
+ const resolved = resolveSessionContext(resolveDataDir(), process.env.BOTMUX_SESSION_ID);
4308
+ if (!resolved)
4309
+ return null;
4310
+ const envAttempt = Number(process.env.BOTMUX_DISPATCH_ATTEMPT);
4311
+ const dispatchAttempt = resolved.dispatchAttempt
4312
+ ?? (Number.isSafeInteger(envAttempt) && envAttempt > 0 ? envAttempt : undefined);
4313
+ return {
4314
+ ...resolved,
4315
+ turnId: resolved.turnId ?? process.env.BOTMUX_TURN_ID,
4316
+ ...(dispatchAttempt !== undefined ? { dispatchAttempt } : {}),
4317
+ };
3934
4318
  }
3935
4319
  function findAncestorSessionId() {
3936
4320
  return findAncestorSessionContext()?.sessionId ?? null;
@@ -4747,9 +5131,10 @@ function withCustomCardMentionFooter(card, mentionOpenIds, sentToLabel) {
4747
5131
  // keeps using `buildImageCardElements` from there.
4748
5132
  import { buildImageCardElements, brandFooterSegment, prepareCardMarkdown } from './im/lark/md-card.js';
4749
5133
  import { applyInlineMentions } from './im/lark/inline-mentions.js';
5134
+ import { renderBrandTemplate } from './im/lark/brand-template.js';
4750
5135
  import { resolveBrandLabel } from './bot-registry.js';
4751
5136
  import { config } from './config.js';
4752
- import { resolveQuoteTarget, validateMentionDecision, parseAttentionFlag, attentionUsageError } from './services/send-policy.js';
5137
+ import { resolveQuoteTarget, validateMentionDecision, parseAttentionFlag, attentionUsageError, managedVcQuoteError, managedVcCustomCardError, managedVcSendControlError, managedVcSendPayloadError, containsLarkAtTag, } from './services/send-policy.js';
4753
5138
  /**
4754
5139
  * Sandbox relay mode for `botmux send`. Inside a file-sandbox the CLI cannot
4755
5140
  * read bots.json or reach Lark directly (creds are deliberately absent), so we
@@ -4803,6 +5188,7 @@ async function relaySend(rest, relayDir) {
4803
5188
  ? prepareCardMarkdown(extractCardText(content), process.cwd(), 'filesystem')
4804
5189
  : undefined;
4805
5190
  const id = randomBytes(8).toString('hex');
5191
+ const originCapability = readManagedOriginCapability(resolveDataDir(), sid, relayDir)?.capability;
4806
5192
  // Structured request: the daemon-side watcher rebuilds the argv from these
4807
5193
  // validated fields (it NEVER executes raw argv — see buildRelayHostArgs).
4808
5194
  // Content + attachments are written into the shared outbox as plain
@@ -4873,6 +5259,7 @@ async function relaySend(rest, relayDir) {
4873
5259
  videos,
4874
5260
  videoCovers,
4875
5261
  flags,
5262
+ ...(originCapability ? { originCapability } : {}),
4876
5263
  }));
4877
5264
  const resPath = join(relayDir, `${id}.res.json`);
4878
5265
  const deadlineMs = Date.now() + 120_000;
@@ -5017,18 +5404,11 @@ function riffModeSession(opts = {}) {
5017
5404
  return { session, botConfig };
5018
5405
  }
5019
5406
  async function cmdSend(rest) {
5020
- // Sandbox relay: a file-sandboxed session has no creds/bots.json, so route
5021
- // the send through the daemon-side outbox instead of delivering directly.
5022
- const relayDir = process.env.BOTMUX_SEND_RELAY;
5023
- if (relayDir) {
5024
- await relaySend(rest, relayDir);
5025
- return;
5026
- }
5027
- // Safety gate: a CLI agent running inside a workflow subagent (Slice F)
5028
- // must not chat-post directly — chat-facing side effects are reserved
5029
- // for `hostExecutor` activities so they can be tracked via
5030
- // `effectAttempted` + reconciled across retries / resumes. Refuse loud
5031
- // so the agent (and any human reviewing logs) sees the boundary.
5407
+ const ancestorCtx = findAncestorSessionContext();
5408
+ // Workflow subagents cannot own chat-facing effects: those belong to a
5409
+ // hostExecutor so retries/resumes can reconcile them. Keep this gate ahead
5410
+ // of both the sandbox relay and VC-origin store reads; neither path may turn
5411
+ // a forbidden workflow send into an observable side effect.
5032
5412
  if (process.env.BOTMUX_WORKFLOW === '1') {
5033
5413
  const runId = process.env.BOTMUX_WORKFLOW_RUN_ID ?? '?';
5034
5414
  const nodeId = process.env.BOTMUX_WORKFLOW_NODE_ID ?? '?';
@@ -5037,11 +5417,106 @@ async function cmdSend(rest) {
5037
5417
  `chat-facing side effects belong in a hostExecutor activity, not a subagent.`);
5038
5418
  process.exit(2);
5039
5419
  }
5420
+ // Managed output attribution must come from the live process-tree marker,
5421
+ // whose turn/attempt is refreshed by the worker. BOTMUX_TURN_ID is a
5422
+ // spawn-time fallback and can be stale in a detached child after a later
5423
+ // delivery starts, so it is never authority for receiver policy.
5424
+ const liveMarkerCtx = resolveSessionContext(resolveDataDir(), process.env.BOTMUX_SESSION_ID);
5425
+ const trustedHostRelay = process.env.BOTMUX_HOST_RELAY_AUTHORIZED === '1';
5426
+ const trustedRelayAttemptRaw = Number(process.env.BOTMUX_DISPATCH_ATTEMPT);
5427
+ const trustedRelayCandidate = trustedHostRelay && process.env.BOTMUX_SESSION_ID
5428
+ ? {
5429
+ sessionId: process.env.BOTMUX_SESSION_ID,
5430
+ turnId: process.env.BOTMUX_TURN_ID,
5431
+ dispatchAttempt: Number.isSafeInteger(trustedRelayAttemptRaw) && trustedRelayAttemptRaw > 0
5432
+ ? trustedRelayAttemptRaw
5433
+ : undefined,
5434
+ }
5435
+ : undefined;
5436
+ const sessionIdArg = argValue(rest, '--session-id');
5437
+ // Inside bwrap the PID namespace makes host marker traversal impossible.
5438
+ // The relay watcher therefore binds a short-lived host-issued capability to
5439
+ // the worker's live turn and performs the authoritative policy check.
5440
+ const relayDir = process.env.BOTMUX_SEND_RELAY;
5441
+ if (relayDir) {
5442
+ await relaySend(rest, relayDir);
5443
+ return;
5444
+ }
5445
+ // Silent is an execution policy, not a prompt suggestion. During a durable
5446
+ // meeting turn, refuse botmux-mediated sends before either the direct-Lark or
5447
+ // sandbox-relay path can run. Explicit human IM turns have no dispatchAttempt
5448
+ // and therefore retain the normal reply path in the same receiver session.
5449
+ const sessionsForOrigin = loadSessions();
5450
+ const trustedRelaySession = trustedRelayCandidate
5451
+ ? sessionsForOrigin.get(trustedRelayCandidate.sessionId)
5452
+ : undefined;
5453
+ // The env marker is not authority by itself. A genuine host relay CLI is a
5454
+ // direct child of the session's durably recorded worker pid; sandboxed or
5455
+ // semi-trusted descendants cannot satisfy that parent binding.
5456
+ const trustedRelayCtx = trustedRelayCandidate && isTrustedVcMeetingHostRelayParent(trustedHostRelay, trustedRelaySession?.pid, process.ppid)
5457
+ ? trustedRelayCandidate
5458
+ : undefined;
5459
+ const originSessionId = trustedRelayCtx?.sessionId
5460
+ || liveMarkerCtx?.sessionId
5461
+ || ancestorCtx?.sessionId
5462
+ || sessionIdArg;
5463
+ let explicitVcMeetingImOrigin;
5464
+ let vcMeetingListenerOutputOwner;
5465
+ let vcMeetingManagedSendOrigin;
5466
+ let vcMeetingDeliveryReplyOrigin;
5467
+ if (originSessionId) {
5468
+ const originSession = sessionsForOrigin.get(originSessionId);
5469
+ const originTurnId = trustedRelayCtx?.turnId ?? liveMarkerCtx?.turnId;
5470
+ const imOrigin = resolveVcMeetingImTurnOrigin(originSession, originTurnId);
5471
+ const managedOrigin = {
5472
+ receiverSessionId: originSessionId,
5473
+ receiverSession: !!originSession?.vcMeetingReceiver,
5474
+ turnId: originTurnId,
5475
+ dispatchAttempt: trustedRelayCtx?.dispatchAttempt ?? liveMarkerCtx?.dispatchAttempt,
5476
+ currentImTurnOrigin: imOrigin,
5477
+ };
5478
+ const decision = evaluateVcMeetingManagedSend(resolveDataDir(), managedOrigin);
5479
+ if (!decision.ok) {
5480
+ console.error(`botmux send refused by VC managed-output policy (${decision.errorCode}): ${decision.error}`);
5481
+ process.exit(2);
5482
+ }
5483
+ if (decision.kind === 'listener_thread') {
5484
+ vcMeetingListenerOutputOwner = decision.meetingOwner;
5485
+ vcMeetingManagedSendOrigin = managedOrigin;
5486
+ if (managedOrigin.turnId && managedOrigin.dispatchAttempt !== undefined) {
5487
+ vcMeetingDeliveryReplyOrigin = {
5488
+ receiverSessionId: originSessionId,
5489
+ stableTurnId: managedOrigin.turnId,
5490
+ dispatchAttempt: managedOrigin.dispatchAttempt,
5491
+ };
5492
+ }
5493
+ }
5494
+ if (decision.kind === 'listener_thread'
5495
+ && (trustedRelayCtx?.dispatchAttempt ?? liveMarkerCtx?.dispatchAttempt) === undefined) {
5496
+ explicitVcMeetingImOrigin = imOrigin;
5497
+ }
5498
+ }
5499
+ const revalidateVcMeetingManagedSend = () => {
5500
+ if (!vcMeetingManagedSendOrigin)
5501
+ return;
5502
+ const decision = evaluateVcMeetingManagedSend(resolveDataDir(), vcMeetingManagedSendOrigin);
5503
+ if (!decision.ok) {
5504
+ throw new Error(`VC managed-output authority expired (${decision.errorCode}): ${decision.error}`);
5505
+ }
5506
+ if (decision.kind !== 'listener_thread') {
5507
+ throw new Error('VC managed-output authority no longer targets the listener thread');
5508
+ }
5509
+ vcMeetingListenerOutputOwner = decision.meetingOwner;
5510
+ };
5511
+ const prepareVcMeetingListenerReply = (proposedOutput) => explicitVcMeetingImOrigin
5512
+ ? prepareVcMeetingImReply(resolveDataDir(), explicitVcMeetingImOrigin, proposedOutput)
5513
+ : vcMeetingDeliveryReplyOrigin
5514
+ ? prepareVcMeetingDeliveryReply(resolveDataDir(), vcMeetingDeliveryReplyOrigin, proposedOutput)
5515
+ : undefined;
5040
5516
  process.env.SESSION_DATA_DIR ??= resolveDataDir();
5041
5517
  // Read isolation: the sandboxed CLI is denied bots.json → register this bot
5042
5518
  // from its own worker-written cred file instead (see registerSelfFromCredFile).
5043
5519
  await registerSelfFromCredFile();
5044
- const sessionIdArg = argValue(rest, '--session-id');
5045
5520
  for (const flag of ['--video', '--videos', '--video-cover', '--video-covers']) {
5046
5521
  if (flagPresentButValueMissing(rest, flag, true)) {
5047
5522
  console.error(`botmux send: ${flag} 需要路径参数`);
@@ -5059,6 +5534,11 @@ async function cmdSend(rest) {
5059
5534
  const cardJsonArg = argValue(rest, '--card-json');
5060
5535
  const cardFile = argValue(rest, '--card-file');
5061
5536
  const customCardRequested = cardJsonArg !== undefined || cardFile !== undefined;
5537
+ const managedCustomCardError = managedVcCustomCardError(!!vcMeetingManagedSendOrigin, customCardRequested);
5538
+ if (managedCustomCardError) {
5539
+ console.error(`botmux send refused for a managed VC turn: ${managedCustomCardError}`);
5540
+ process.exit(2);
5541
+ }
5062
5542
  if (cardJsonArg !== undefined && cardFile !== undefined) {
5063
5543
  console.error('botmux send: --card-json 与 --card-file 不能同时使用');
5064
5544
  process.exit(2);
@@ -5113,6 +5593,16 @@ async function cmdSend(rest) {
5113
5593
  // Quote chain (chat scope): --quote <message_id> overrides the auto target,
5114
5594
  // --no-quote forces a plain (un-quoted) send.
5115
5595
  const explicitQuote = argValue(rest, '--quote');
5596
+ const managedQuoteError = managedVcQuoteError({
5597
+ managed: !!vcMeetingManagedSendOrigin,
5598
+ durableDelivery: !!vcMeetingDeliveryReplyOrigin,
5599
+ explicitImMessageId: explicitVcMeetingImOrigin?.larkMessageId,
5600
+ explicitQuote,
5601
+ });
5602
+ if (managedQuoteError) {
5603
+ console.error(`botmux send refused for a managed VC turn: ${managedQuoteError}`);
5604
+ process.exit(2);
5605
+ }
5116
5606
  const noQuote = rest.includes('--no-quote');
5117
5607
  // @ hard-gate: every reply must explicitly choose one of these.
5118
5608
  const mentionBack = rest.includes('--mention-back');
@@ -5121,11 +5611,24 @@ async function cmdSend(rest) {
5121
5611
  // needs-you column for this session. Parsed specially (not argValue) so a bare
5122
5612
  // `--attention "我卡住了"` doesn't eat the message as the flag value.
5123
5613
  const attention = parseAttentionFlag(rest);
5614
+ const managedControlError = managedVcSendControlError({
5615
+ managed: !!vcMeetingManagedSendOrigin,
5616
+ sendTopLevel,
5617
+ overrideChatId,
5618
+ sendInto,
5619
+ attentionRequested: attention.requested,
5620
+ explicitMentionCount: mentionArgs.length,
5621
+ mentionBack,
5622
+ noMention,
5623
+ });
5624
+ if (managedControlError) {
5625
+ console.error(`botmux send refused for a managed VC turn: ${managedControlError}`);
5626
+ process.exit(2);
5627
+ }
5124
5628
  if (customCardRequested && asVoice) {
5125
5629
  console.error('botmux send: --card-file/--card-json 不能与 --voice 混用');
5126
5630
  process.exit(2);
5127
5631
  }
5128
- const ancestorCtx = findAncestorSessionContext();
5129
5632
  const sid = sessionIdArg ?? ancestorCtx?.sessionId ?? process.env.BOTMUX_SESSION_ID ?? null;
5130
5633
  if (!sid) {
5131
5634
  console.error('无法推断 session-id。请在 Lark 话题内的 CLI 会话中运行,或传 --session-id <id>。');
@@ -5209,6 +5712,19 @@ async function cmdSend(rest) {
5209
5712
  }
5210
5713
  if (!contentFile && !customCardRequested)
5211
5714
  rejectLikelyWindowsStdinMojibake(content);
5715
+ const managedPayloadError = managedVcSendPayloadError({
5716
+ managed: !!vcMeetingManagedSendOrigin,
5717
+ asVoice,
5718
+ hasBodyText: !!content.trim(),
5719
+ imageCount: images.length,
5720
+ fileCount: files.length,
5721
+ videoCount: videoAttachments.length,
5722
+ containsNativeAtTag: containsLarkAtTag(content),
5723
+ });
5724
+ if (managedPayloadError) {
5725
+ console.error(`botmux send refused for a managed VC turn: ${managedPayloadError}`);
5726
+ process.exit(2);
5727
+ }
5212
5728
  if (!customCard && !content.trim() && images.length === 0 && files.length === 0 && videoAttachments.length === 0) {
5213
5729
  console.error('没有内容可发送。用法:\n echo "消息" | botmux send\n botmux send "消息"\n botmux send --content-file /tmp/msg.md --images /tmp/chart.png\n botmux send --videos /tmp/replay.mp4 --video-covers /tmp/cover.png --no-mention "视频预览"');
5214
5730
  process.exit(1);
@@ -5227,6 +5743,25 @@ async function cmdSend(rest) {
5227
5743
  console.error(`botmux send: ${attentionErr}`);
5228
5744
  process.exit(2);
5229
5745
  }
5746
+ const recordVcMeetingPrimaryOutput = (messageId, outputChatId) => {
5747
+ if (!vcMeetingListenerOutputOwner || sendInto)
5748
+ return;
5749
+ try {
5750
+ const recorded = recordVcMeetingListenerMessage(resolveDataDir(), {
5751
+ ...vcMeetingListenerOutputOwner,
5752
+ targetChatId: outputChatId,
5753
+ messageId,
5754
+ });
5755
+ if (!recorded.ok) {
5756
+ console.error(`⚠️ VC 监听消息索引拒绝记录 ${messageId}(${recorded.reason})`);
5757
+ }
5758
+ }
5759
+ catch (error) {
5760
+ // The primary message already exists at Lark. Index failure must never
5761
+ // turn a successful send into exit!=0 (which would invite a duplicate).
5762
+ console.error(`⚠️ 消息已发送,但 VC 监听消息索引写入失败:${error instanceof Error ? error.message : String(error)}`);
5763
+ }
5764
+ };
5230
5765
  // ── Voice mode ──────────────────────────────────────────────────────────
5231
5766
  // Synthesize the (already-condensed, colloquial) content into a Feishu voice
5232
5767
  // bubble and return. Deliberately bypasses the text/card path's mentions,
@@ -5254,17 +5789,53 @@ async function cmdSend(rest) {
5254
5789
  const { rmSync } = await import('node:fs');
5255
5790
  const appId = s.larkAppId;
5256
5791
  const targetChatId = overrideChatId ?? s.chatId;
5257
- const target = resolveSendTarget({ into: sendInto, topLevel: sendTopLevel, chatScope: s.scope === 'chat', chatId: targetChatId, rootMessageId: s.rootMessageId, replyTargetRootId: s.currentReplyTarget?.rootMessageId, replyTargetTurnId: s.currentReplyTarget?.turnId, currentTurnId });
5258
- const sendAudio = (fileKey) => target.mode === 'plain'
5259
- ? sendMessage(appId, target.chatId, JSON.stringify({ file_key: fileKey }), 'audio')
5260
- : replyMessage(appId, target.rootMessageId, JSON.stringify({ file_key: fileKey }), 'audio', true);
5261
5792
  let dir;
5262
5793
  try {
5263
5794
  const out = await synthesizeVoiceOpus(appId, content);
5264
5795
  dir = out.dir;
5265
5796
  const fileKey = await uploadFile(appId, out.path, { duration: out.durationMs });
5266
5797
  const sentAtMs = Date.now();
5267
- const messageId = await sendAudio(fileKey);
5798
+ const proposedOutput = {
5799
+ targetChatId,
5800
+ msgType: 'audio',
5801
+ content: JSON.stringify({ file_key: fileKey }),
5802
+ };
5803
+ const prepared = prepareVcMeetingListenerReply(proposedOutput);
5804
+ if (prepared?.kind === 'conflict') {
5805
+ throw new Error(`VC listener assistant reply refused (${prepared.reason}): ${prepared.detail}`);
5806
+ }
5807
+ const canonicalOutput = prepared?.canonicalOutput ?? proposedOutput;
5808
+ if (prepared?.outputMismatch) {
5809
+ console.error(`⚠️ VC listener voice reply output_mismatch action=${prepared.ref.actionId}; `
5810
+ + 'reusing first canonical output');
5811
+ }
5812
+ let messageId;
5813
+ if (prepared?.kind === 'succeeded' && prepared.messageId) {
5814
+ messageId = prepared.messageId;
5815
+ }
5816
+ else {
5817
+ revalidateVcMeetingManagedSend();
5818
+ const canonicalTarget = resolveSendTarget({
5819
+ into: sendInto,
5820
+ topLevel: sendTopLevel,
5821
+ chatScope: s.scope === 'chat',
5822
+ chatId: canonicalOutput.targetChatId,
5823
+ rootMessageId: s.rootMessageId,
5824
+ replyTargetRootId: s.currentReplyTarget?.rootMessageId,
5825
+ replyTargetTurnId: s.currentReplyTarget?.turnId,
5826
+ currentTurnId,
5827
+ });
5828
+ const managedProviderOptions = prepared
5829
+ ? { suppressHook: true }
5830
+ : undefined;
5831
+ messageId = canonicalTarget.mode === 'plain'
5832
+ ? await sendMessage(appId, canonicalTarget.chatId, canonicalOutput.content, canonicalOutput.msgType, prepared?.providerKey, undefined, managedProviderOptions)
5833
+ : await replyMessage(appId, canonicalTarget.rootMessageId, canonicalOutput.content, canonicalOutput.msgType, true, prepared?.providerKey, undefined, managedProviderOptions);
5834
+ if (prepared?.kind === 'send' || prepared?.kind === 'succeeded') {
5835
+ finishVcMeetingImReply(resolveDataDir(), prepared.ref, messageId);
5836
+ }
5837
+ }
5838
+ recordVcMeetingPrimaryOutput(messageId, canonicalOutput.targetChatId);
5268
5839
  // 语音也是一次回复:写 bridge fallback marker,否则本轮会被判为"没发 botmux send"
5269
5840
  // 而触发兜底,多补一张文本卡。与文本/卡片路径同口径:仅同话题回复才记。
5270
5841
  if (!sendTopLevel && !overrideChatId && !sendInto) {
@@ -5383,6 +5954,8 @@ async function cmdSend(rest) {
5383
5954
  mentions.push({ open_id: m.trim(), name: '' });
5384
5955
  }
5385
5956
  }
5957
+ const replyTargetSenderOpenId = explicitVcMeetingImOrigin?.replyTargetSenderOpenId
5958
+ ?? s.quoteTargetSenderOpenId;
5386
5959
  // @ hard-gate (config.send.requireMentionDecision, default on): force the
5387
5960
  // model to make an explicit @ decision before sending. --top-level publish
5388
5961
  // is exempt. The error text adapts to who is being replied to (人 / bot).
@@ -5392,7 +5965,7 @@ async function cmdSend(rest) {
5392
5965
  hasMentionArgs: mentionArgs.length > 0,
5393
5966
  mentionBack,
5394
5967
  noMention,
5395
- hasQuoteTargetSender: !!s.quoteTargetSenderOpenId,
5968
+ hasQuoteTargetSender: !!replyTargetSenderOpenId,
5396
5969
  });
5397
5970
  if (!mentionGate.ok) {
5398
5971
  console.error(mentionGate.error);
@@ -5401,9 +5974,9 @@ async function cmdSend(rest) {
5401
5974
  // --mention-back: @ the sender of the message this turn is replying to
5402
5975
  // (open_id from the session — model needn't know it). Bare-name form so it
5403
5976
  // renders as a trailing <at>.
5404
- if (mentionBack && s.quoteTargetSenderOpenId
5405
- && !mentions.some(m => m.open_id === s.quoteTargetSenderOpenId)) {
5406
- mentions.push({ open_id: s.quoteTargetSenderOpenId, name: '' });
5977
+ if (mentionBack && replyTargetSenderOpenId
5978
+ && !mentions.some(m => m.open_id === replyTargetSenderOpenId)) {
5979
+ mentions.push({ open_id: replyTargetSenderOpenId, name: '' });
5407
5980
  }
5408
5981
  // Validate file paths
5409
5982
  for (const p of [...images, ...files, ...videos, ...videoCovers]) {
@@ -5463,7 +6036,7 @@ async function cmdSend(rest) {
5463
6036
  // Sub-topic seed if `openId` is a dispatched sub-bot in an active topic that is
5464
6037
  // NOT reachable in the current conversation; else null. The bot I'm replying to
5465
6038
  // here (quoteTargetSenderOpenId) is reachable, so it's never treated as off-topic.
5466
- const offTopicSubBotSeed = (openId) => offTopicSubBotTopic({ mentionOpenId: openId, quoteTargetSenderOpenId: s.quoteTargetSenderOpenId, chatId: targetChatId, registry: dispatchReg, activeSeeds: dispatchActiveSeeds });
6039
+ const offTopicSubBotSeed = (openId) => offTopicSubBotTopic({ mentionOpenId: openId, quoteTargetSenderOpenId: replyTargetSenderOpenId, chatId: targetChatId, registry: dispatchReg, activeSeeds: dispatchActiveSeeds });
5467
6040
  // Explicit --mention / --mention-back of an off-topic sub-bot → block + point to
5468
6041
  // the right command (--anyway overrides). Prose @Name injection is filtered
5469
6042
  // (dropped, not blocked) at its own site below.
@@ -5494,9 +6067,14 @@ async function cmdSend(rest) {
5494
6067
  // Dispatch helper: top-level / chat-scope send vs reply-in-thread, single
5495
6068
  // decision point. Used for file attachments (always plain in chat scope).
5496
6069
  const sendTarget = resolveSendTarget({ into: sendInto, topLevel: sendTopLevel, chatScope: isChatScope, chatId: targetChatId, rootMessageId: s.rootMessageId, replyTargetRootId: s.currentReplyTarget?.rootMessageId, replyTargetTurnId: s.currentReplyTarget?.turnId, currentTurnId });
5497
- const dispatch = (content, msgType) => sendTarget.mode === 'plain'
5498
- ? sendMessage(appId, sendTarget.chatId, content, msgType, undefined, hookContext)
5499
- : replyMessage(appId, sendTarget.rootMessageId, content, msgType, true, undefined, hookContext);
6070
+ const dispatch = (content, msgType, uuid, suppressHook) => {
6071
+ // This closure also carries attachments, so every Lark call re-checks the
6072
+ // exact durable attempt/member instead of inheriting the early cmd gate.
6073
+ revalidateVcMeetingManagedSend();
6074
+ return sendTarget.mode === 'plain'
6075
+ ? sendMessage(appId, sendTarget.chatId, content, msgType, uuid, hookContext, suppressHook ? { suppressHook: true } : undefined)
6076
+ : replyMessage(appId, sendTarget.rootMessageId, content, msgType, true, uuid, hookContext, suppressHook ? { suppressHook: true } : undefined);
6077
+ };
5500
6078
  const recordBridgeSendMarker = (sentAtMs, messageId, sentContent) => {
5501
6079
  try {
5502
6080
  const markerDir = join(resolveDataDir(), 'turn-sends');
@@ -5515,33 +6093,83 @@ async function cmdSend(rest) {
5515
6093
  // scope and --top-level never quote. Withdrawn target → fall back to plain.
5516
6094
  const quoteTargetId = sendInto || sendTarget.mode === 'thread' ? undefined : resolveQuoteTarget({
5517
6095
  isChatScope, sendTopLevel, noQuote, explicitQuote,
5518
- sessionQuoteTargetId: s.quoteTargetId,
6096
+ // A durable meeting delivery has no Lark-authored trigger message. Never
6097
+ // inherit the receiver session's latest human quote target: that state can
6098
+ // belong to another queued IM turn and is not part of the delivery action.
6099
+ sessionQuoteTargetId: vcMeetingDeliveryReplyOrigin
6100
+ ? undefined
6101
+ : explicitVcMeetingImOrigin?.larkMessageId ?? s.quoteTargetId,
5519
6102
  });
5520
6103
  let primaryQuotedId = null;
6104
+ let vcMeetingListenerReplyReplay = false;
5521
6105
  const dispatchPrimary = async (content, msgType) => {
5522
- const result = await dispatchPrimaryMessage({ sendMessage, replyMessage }, {
5523
- appId,
6106
+ // `dispatchPrimaryMessage` may call replyMessage directly for a quote, so
6107
+ // fence immediately before preparing/performing that primary effect too.
6108
+ revalidateVcMeetingManagedSend();
6109
+ const proposedOutput = {
5524
6110
  targetChatId,
5525
- quoteTargetId,
5526
- content,
6111
+ ...(quoteTargetId ? { quoteTargetId } : {}),
5527
6112
  msgType,
6113
+ content,
6114
+ };
6115
+ const prepared = prepareVcMeetingListenerReply(proposedOutput);
6116
+ if (prepared?.kind === 'conflict') {
6117
+ throw new Error(`VC listener assistant reply refused (${prepared.reason}): ${prepared.detail}`);
6118
+ }
6119
+ const canonicalOutput = prepared?.canonicalOutput ?? proposedOutput;
6120
+ if (prepared?.outputMismatch) {
6121
+ console.error(`⚠️ VC listener reply output_mismatch action=${prepared.ref.actionId} `
6122
+ + `turn=${explicitVcMeetingImOrigin?.larkMessageId ?? vcMeetingDeliveryReplyOrigin?.stableTurnId}; `
6123
+ + 'reusing first canonical output');
6124
+ }
6125
+ if (prepared?.kind === 'succeeded' && prepared.messageId) {
6126
+ vcMeetingListenerReplyReplay = true;
6127
+ primaryQuotedId = canonicalOutput.quoteTargetId ?? null;
6128
+ recordVcMeetingPrimaryOutput(prepared.messageId, canonicalOutput.targetChatId);
6129
+ return prepared.messageId;
6130
+ }
6131
+ if (prepared?.kind === 'succeeded') {
6132
+ // A legacy/incomplete terminal record without the provider message id is
6133
+ // still safe to reconcile through the same stable UUID.
6134
+ vcMeetingListenerReplyReplay = true;
6135
+ }
6136
+ else if (prepared?.kind === 'send') {
6137
+ vcMeetingListenerReplyReplay = prepared.replay;
6138
+ }
6139
+ const result = await dispatchPrimaryMessage({ sendMessage, replyMessage }, {
6140
+ appId,
6141
+ targetChatId: canonicalOutput.targetChatId,
6142
+ quoteTargetId: canonicalOutput.quoteTargetId,
6143
+ content: canonicalOutput.content,
6144
+ msgType: canonicalOutput.msgType,
6145
+ ...(prepared ? { uuid: prepared.providerKey } : {}),
6146
+ // Managed meeting output must never fan out through user-configured
6147
+ // outbound hooks, including its first provider attempt.
6148
+ ...(prepared ? { suppressHook: true } : {}),
5528
6149
  hookContext,
5529
6150
  MessageWithdrawnError,
5530
- dispatch,
6151
+ // Explicit VC IM --into is rejected above, so an unquoted first send
6152
+ // retains the normal chat-scope dispatch semantics. On a mismatch the
6153
+ // frozen canonical target remains authoritative.
6154
+ dispatch: prepared?.outputMismatch
6155
+ ? (body, type, uuid, suppressHook) => {
6156
+ revalidateVcMeetingManagedSend();
6157
+ return sendMessage(appId, canonicalOutput.targetChatId, body, type, uuid, hookContext, suppressHook ? { suppressHook: true } : undefined);
6158
+ }
6159
+ : dispatch,
6160
+ beforeQuoteFallback: revalidateVcMeetingManagedSend,
5531
6161
  onQuoteWithdrawn: (id) => {
5532
6162
  console.error(`引用目标 ${id} 已撤回,改为普通发送`);
5533
6163
  },
5534
6164
  });
5535
6165
  primaryQuotedId = result.primaryQuotedId;
6166
+ if (prepared?.kind === 'send' || prepared?.kind === 'succeeded') {
6167
+ finishVcMeetingImReply(resolveDataDir(), prepared.ref, result.messageId);
6168
+ }
6169
+ recordVcMeetingPrimaryOutput(result.messageId, canonicalOutput.targetChatId);
5536
6170
  return result.messageId;
5537
6171
  };
5538
6172
  try {
5539
- // Upload images in parallel
5540
- const imageKeys = [];
5541
- if (images.length > 0) {
5542
- const results = await Promise.all(images.map(p => uploadImage(appId, p)));
5543
- imageKeys.push(...results);
5544
- }
5545
6173
  // A file-sandbox relay supplies a host-private copy normalized inside the
5546
6174
  // sandbox namespace. Voice/doc-comment paths returned above and therefore
5547
6175
  // continue using the untouched raw content.
@@ -5553,6 +6181,31 @@ async function cmdSend(rest) {
5553
6181
  }
5554
6182
  catch { /* fall back safely below */ }
5555
6183
  }
6184
+ // `preparedContentFile` is presentation data produced inside an untrusted
6185
+ // sandbox and only TOCTOU-materialized by the host watcher. It is not an
6186
+ // authorization proof. Re-check the exact body/attachment shape that will
6187
+ // reach Lark after JSON extraction and prepared-content substitution, and
6188
+ // do so before even an image upload creates a provider-side effect.
6189
+ const managedRenderedPayloadError = managedVcSendPayloadError({
6190
+ managed: !!vcMeetingManagedSendOrigin,
6191
+ asVoice: false,
6192
+ hasBodyText: !!text.trim(),
6193
+ imageCount: images.length,
6194
+ fileCount: files.length,
6195
+ videoCount: videoAttachments.length,
6196
+ containsNativeAtTag: containsLarkAtTag(text),
6197
+ });
6198
+ if (managedRenderedPayloadError) {
6199
+ console.error(`botmux send refused for a managed VC turn: ${managedRenderedPayloadError}`);
6200
+ process.exit(2);
6201
+ }
6202
+ // Upload images only after the final rendered payload has passed the
6203
+ // managed side-effect gate above.
6204
+ const imageKeys = [];
6205
+ if (images.length > 0) {
6206
+ const results = await Promise.all(images.map(p => uploadImage(appId, p)));
6207
+ imageKeys.push(...results);
6208
+ }
5556
6209
  // Auto-detect @BotName in text and inject as mentions, using the sender
5557
6210
  // app's cross-ref file for per-app-scoped open_ids. Without this, a plain
5558
6211
  // "@Claude" in text only triggers IPC routing but Lark UI shows it as
@@ -5577,7 +6230,7 @@ async function cmdSend(rest) {
5577
6230
  // --no-mention 显式不 @ 任何人:跳过正文 @BotName 的自动注入,否则正文里
5578
6231
  // 出现的 @名字 仍会被注入成 <at>,破坏 --no-mention 语义、还可能误触发对方
5579
6232
  // bot(正是要避免的循环 @)。botEntries/crossRef 仍需加载供 footer 寻址用。
5580
- if (!noMention) {
6233
+ if (!noMention && !vcMeetingManagedSendOrigin) {
5581
6234
  const alreadyMentioned = new Set(mentions.map(m => m.open_id));
5582
6235
  // Scan a code-span-stripped copy so a bot name quoted inside backticks or a
5583
6236
  // fenced block (e.g. an example `botmux send --mention @Bot …` or an
@@ -5658,7 +6311,9 @@ async function cmdSend(rest) {
5658
6311
  // (Codex review P2)。--top-level 同样无特定收件人。
5659
6312
  const footerAddressing = (sendTopLevel || noMention)
5660
6313
  ? { sendTo: undefined, cc: [] }
5661
- : buildFooterAddressing(s, {
6314
+ : buildFooterAddressing(explicitVcMeetingImOrigin?.replyTargetSenderOpenId
6315
+ ? { ...s, lastCallerOpenId: explicitVcMeetingImOrigin.replyTargetSenderOpenId }
6316
+ : s, {
5662
6317
  isOncall: !!oncallEntry,
5663
6318
  hasExplicitBotMention: explicitKnownBotMention,
5664
6319
  knownBotOpenIds,
@@ -5711,7 +6366,13 @@ async function cmdSend(rest) {
5711
6366
  // and updates primaryQuotedId). Otherwise a bare `--videos … --no-mention`
5712
6367
  // reply in a 普通群 lands as a standalone message that doesn't quote the
5713
6368
  // trigger — unlike file-only/image-only sends whose primary card quotes.
5714
- const videoResult = await sendVideoAttachments({ uploadFile, uploadImage, dispatch, primaryDispatch: dispatchPrimary }, appId, videoAttachments);
6369
+ const videoResult = await sendVideoAttachments({
6370
+ uploadFile,
6371
+ uploadImage,
6372
+ dispatch,
6373
+ primaryDispatch: dispatchPrimary,
6374
+ ...(vcMeetingManagedSendOrigin ? { maxMessages: 1 } : {}),
6375
+ }, appId, videoAttachments);
5715
6376
  failedVideoAttachments = videoResult.failed;
5716
6377
  if (videoResult.sent.length === 0) {
5717
6378
  const first = failedVideoAttachments[0]?.error ?? 'unknown error';
@@ -5754,7 +6415,7 @@ async function cmdSend(rest) {
5754
6415
  // default botmux, '' → suppressed, else custom). Same resolver/rule as
5755
6416
  // the daemon's card builders so both send paths render identically.
5756
6417
  const footerParts = [];
5757
- const brandSeg = brandFooterSegment(resolveBrandLabel(appId));
6418
+ const brandSeg = brandFooterSegment(renderBrandTemplate(resolveBrandLabel(appId), s.workingDir));
5758
6419
  if (brandSeg)
5759
6420
  footerParts.push(brandSeg);
5760
6421
  // All real mentions land on one footer line: human addressee first, then
@@ -5776,7 +6437,9 @@ async function cmdSend(rest) {
5776
6437
  // v2 cards put buttons inside column_set/column — never the 1.x
5777
6438
  // `tag:'action'` container (Feishu rejects it, error 200861).
5778
6439
  let voiceOn = false;
5779
- if (!sendTopLevel) {
6440
+ // A managed receiver card has no callback controls: a voice-summary
6441
+ // button would open a second, unledgered model/output action when clicked.
6442
+ if (!sendTopLevel && !vcMeetingManagedSendOrigin) {
5780
6443
  try {
5781
6444
  const { isVoiceConfigured } = await import('./services/voice/index.js');
5782
6445
  voiceOn = isVoiceConfigured(appId);
@@ -5842,7 +6505,7 @@ async function cmdSend(rest) {
5842
6505
  // the success JSON. Pure-video sends have no text/card primary, so the media
5843
6506
  // message above is the primary and failures before any media is sent still
5844
6507
  // surface as command failure.
5845
- if (!pureVideoSend) {
6508
+ if (!pureVideoSend && !vcMeetingListenerReplyReplay) {
5846
6509
  ({ failed: failedAttachments } = await sendFileAttachments({ uploadFile, dispatch }, appId, files));
5847
6510
  const videoResult = await sendVideoAttachments({ uploadFile, uploadImage, dispatch }, appId, videoAttachments);
5848
6511
  failedVideoAttachments = videoResult.failed;
@@ -5874,11 +6537,29 @@ async function cmdSend(rest) {
5874
6537
  const daemon = findDaemon(appId);
5875
6538
  if (!daemon)
5876
6539
  throw new Error(`找不到 daemon (larkAppId=${appId})`);
5877
- const res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/attention`, {
6540
+ const originCapability = readManagedOriginCapability(resolveDataDir(), sid, process.env.BOTMUX_SEND_RELAY)?.capability;
6541
+ const request = {
5878
6542
  method: 'POST',
5879
6543
  headers: { 'content-type': 'application/json' },
5880
- body: JSON.stringify({ sessionId: sid, larkAppId: appId, action: 'raise', kind: attention.kind, reason: text.trim() }),
5881
- });
6544
+ body: JSON.stringify({
6545
+ sessionId: sid,
6546
+ larkAppId: appId,
6547
+ action: 'raise',
6548
+ kind: attention.kind,
6549
+ reason: text.trim(),
6550
+ originCapability,
6551
+ originTurnId: liveMarkerCtx?.turnId,
6552
+ originDispatchAttempt: liveMarkerCtx?.dispatchAttempt,
6553
+ }),
6554
+ };
6555
+ let secret;
6556
+ try {
6557
+ secret = loadDaemonIpcSecret();
6558
+ }
6559
+ catch { /* Seatbelt/read-isolated CLI */ }
6560
+ const res = secret
6561
+ ? await fetchDaemonIpc(daemon.ipcPort, '/api/attention', request, secret)
6562
+ : await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/attention`, request);
5882
6563
  if (!res.ok)
5883
6564
  throw new Error(`daemon HTTP ${res.status}`);
5884
6565
  attentionRaised = true;
@@ -6443,13 +7124,32 @@ async function postAsk(body) {
6443
7124
  }
6444
7125
  let res;
6445
7126
  try {
6446
- res = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/asks`, {
7127
+ const requestBody = { ...body };
7128
+ if (typeof requestBody.originCapability !== 'string') {
7129
+ const sessionId = typeof requestBody.sessionId === 'string'
7130
+ ? requestBody.sessionId
7131
+ : undefined;
7132
+ const claim = readManagedOriginCapability(resolveDataDir(), sessionId, process.env.BOTMUX_SEND_RELAY);
7133
+ if (claim)
7134
+ requestBody.originCapability = claim.capability;
7135
+ }
7136
+ const init = {
6447
7137
  method: 'POST',
6448
7138
  headers: { 'content-type': 'application/json' },
6449
- body: JSON.stringify(body),
7139
+ body: JSON.stringify(requestBody),
6450
7140
  // No client-side timeout — broker enforces `timeoutMs` and will respond
6451
7141
  // with `kind:'timedOut'` so this fetch always settles.
6452
- });
7142
+ };
7143
+ let hostSecret;
7144
+ if (!process.env.BOTMUX_SEND_RELAY) {
7145
+ try {
7146
+ hostSecret = loadDaemonIpcSecret();
7147
+ }
7148
+ catch { /* read-isolated CLI uses live marker auth */ }
7149
+ }
7150
+ res = hostSecret
7151
+ ? await fetchDaemonIpc(daemon.ipcPort, '/api/asks', init, hostSecret)
7152
+ : await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/asks`, init);
6453
7153
  }
6454
7154
  catch (fetchErr) {
6455
7155
  const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr);
@@ -6528,14 +7228,23 @@ async function cmdAsk(sub, rest) {
6528
7228
  process.exit(2);
6529
7229
  }
6530
7230
  const larkAppId = process.env.BOTMUX_LARK_APP_ID;
7231
+ const askSessionId = process.env.BOTMUX_SESSION_ID;
7232
+ const liveAskOrigin = resolveSessionContext(resolveDataDir(), askSessionId);
7233
+ const askRelayDir = process.env.BOTMUX_SEND_RELAY;
7234
+ const askOriginCapability = readManagedOriginCapability(resolveDataDir(), askSessionId, askRelayDir)?.capability;
6531
7235
  const body = {
6532
- sessionId: process.env.BOTMUX_SESSION_ID,
7236
+ sessionId: askSessionId,
6533
7237
  chatId: process.env.BOTMUX_CHAT_ID,
6534
7238
  larkAppId,
6535
7239
  rootMessageId: process.env.BOTMUX_ROOT_MESSAGE_ID || null,
6536
7240
  options,
6537
7241
  prompt,
6538
7242
  timeoutMs,
7243
+ ...(liveAskOrigin?.turnId ? { originTurnId: liveAskOrigin.turnId } : {}),
7244
+ ...(liveAskOrigin?.dispatchAttempt !== undefined
7245
+ ? { originDispatchAttempt: liveAskOrigin.dispatchAttempt }
7246
+ : {}),
7247
+ ...(askOriginCapability ? { originCapability: askOriginCapability } : {}),
6539
7248
  };
6540
7249
  let result;
6541
7250
  try {
@@ -6758,11 +7467,37 @@ async function cmdSessionReady() {
6758
7467
  const daemon = findDaemon(larkAppId);
6759
7468
  if (daemon) {
6760
7469
  try {
6761
- await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/session-ready`, {
7470
+ const relayDir = process.env.BOTMUX_SEND_RELAY;
7471
+ const originCapability = readManagedOriginCapability(resolveDataDir(), sessionId, relayDir)?.capability;
7472
+ const liveOrigin = resolveSessionContext(resolveDataDir(), sessionId);
7473
+ const envAttempt = Number(process.env.BOTMUX_DISPATCH_ATTEMPT);
7474
+ const originTurnId = liveOrigin?.turnId ?? process.env.BOTMUX_TURN_ID;
7475
+ const originDispatchAttempt = liveOrigin?.dispatchAttempt
7476
+ ?? (Number.isSafeInteger(envAttempt) && envAttempt > 0 ? envAttempt : undefined);
7477
+ const init = {
6762
7478
  method: 'POST',
6763
7479
  headers: { 'content-type': 'application/json' },
6764
- body: JSON.stringify({ sessionId, source }),
6765
- });
7480
+ body: JSON.stringify({
7481
+ sessionId,
7482
+ source,
7483
+ originCapability,
7484
+ originTurnId,
7485
+ originDispatchAttempt,
7486
+ }),
7487
+ };
7488
+ let hostSecret;
7489
+ if (!relayDir) {
7490
+ try {
7491
+ hostSecret = loadDaemonIpcSecret();
7492
+ }
7493
+ catch { /* Seatbelt/read-isolated CLI */ }
7494
+ }
7495
+ if (!hostSecret) {
7496
+ await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/session-ready`, init);
7497
+ }
7498
+ else {
7499
+ await fetchDaemonIpc(daemon.ipcPort, '/api/session-ready', init, hostSecret);
7500
+ }
6766
7501
  }
6767
7502
  catch { /* daemon 不可达 → 放弃,worker 走超时兜底 */ }
6768
7503
  }
@@ -6813,7 +7548,7 @@ async function notifyDaemonsReloadLocale() {
6813
7548
  let failed = 0;
6814
7549
  await Promise.all(daemons.map(async (d) => {
6815
7550
  try {
6816
- const r = await fetch(`http://127.0.0.1:${d.ipcPort}/api/locale/reload`, { method: 'POST' });
7551
+ const r = await fetchDaemonIpc(d.ipcPort, '/api/locale/reload', { method: 'POST' });
6817
7552
  if (r.ok)
6818
7553
  notified++;
6819
7554
  else
@@ -7102,13 +7837,44 @@ function getVersion() {
7102
7837
  }
7103
7838
  const command = process.argv[2];
7104
7839
  // Workflow safety gate (Slice C0): a CLI invoked inside a workflow
7105
- // subagent worker (BOTMUX_WORKFLOW=1, set by daemon-spawn) must not
7106
- // trigger chat-facing or schedule-mutation side effects. Those belong
7107
- // in `hostExecutor` activities so they get `effectAttempted` tracking +
7108
- // reconcile. Read-only commands (history, quoted, bots list, etc.)
7109
- // stay allowed because they're useful for agents to introspect.
7840
+ // subagent worker (BOTMUX_WORKFLOW=1, set by v3/ephemeral-pool) must not
7841
+ // trigger chat-facing effects, schedule mutations, or recursively authorize /
7842
+ // mutate workflows. Side effects belong in `hostExecutor` activities so they
7843
+ // get `effectAttempted` tracking + reconcile; workflow authorization belongs
7844
+ // to the host/user. Read-only commands stay allowed for introspection.
7110
7845
  if (process.env.BOTMUX_WORKFLOW === '1') {
7111
- const blockedRoot = new Set(['send', 'create-group', 'setup']);
7846
+ // Default-deny the root command surface. New botmux commands otherwise
7847
+ // silently become available to a bypass-permission workflow worker until
7848
+ // someone remembers to extend a blacklist. Keep only explicit read-only
7849
+ // introspection plus CLI startup plumbing; mutating subcommands under
7850
+ // schedule/workflow/template/v3 are filtered again below. `mcp serve` is
7851
+ // the stable, botmux-owned Plugin gateway configured for the parent CLI —
7852
+ // it must start inside workflow workers, while every other/future `mcp`
7853
+ // subcommand remains default-denied here.
7854
+ const allowedRoot = new Set([
7855
+ undefined,
7856
+ '--help',
7857
+ '-h',
7858
+ 'help',
7859
+ '--version',
7860
+ '-v',
7861
+ 'status',
7862
+ 'history',
7863
+ 'quoted',
7864
+ 'bots',
7865
+ 'skill',
7866
+ 'hook',
7867
+ 'session-ready',
7868
+ 'mcp',
7869
+ 'ask', // dedicated cmdAsk guard emits the humanGate-specific guidance
7870
+ 'schedule',
7871
+ 'workflow',
7872
+ 'template',
7873
+ 'v3',
7874
+ ]);
7875
+ const rootDenied = !allowedRoot.has(command);
7876
+ const mcpSub = command === 'mcp' ? (process.argv[3] ?? '') : '';
7877
+ const mcpDenied = command === 'mcp' && mcpSub !== 'serve';
7112
7878
  const isSchedule = command === 'schedule';
7113
7879
  const scheduleSub = isSchedule ? (process.argv[3] ?? '') : '';
7114
7880
  const blockedScheduleSub = new Set([
@@ -7123,12 +7889,56 @@ if (process.env.BOTMUX_WORKFLOW === '1') {
7123
7889
  'enable',
7124
7890
  'run',
7125
7891
  ]);
7126
- if (blockedRoot.has(command) || (isSchedule && blockedScheduleSub.has(scheduleSub))) {
7892
+ const workflowSub = command === 'workflow' ? (process.argv[3] ?? '') : '';
7893
+ const blockedWorkflowSub = new Set([
7894
+ // v3 grill / authorization state changes.
7895
+ 'new',
7896
+ 'spec-finalize',
7897
+ 'approve-spec',
7898
+ 'revise-spec',
7899
+ 'architect',
7900
+ 'revise-dag',
7901
+ 'approve-dag',
7902
+ // Saved Workflow creation / execution and live-run mutations.
7903
+ 'save',
7904
+ 'run',
7905
+ 'start',
7906
+ 'retry',
7907
+ 'grant',
7908
+ 'cancel',
7909
+ ]);
7910
+ const templateSub = command === 'template' ? (process.argv[3] ?? '') : '';
7911
+ const blockedTemplateSub = new Set(['migrate-v3', 'archive-runs']);
7912
+ const v3Sub = command === 'v3' ? (process.argv[3] ?? '') : '';
7913
+ const workflowMutation = (command === 'workflow' && blockedWorkflowSub.has(workflowSub)) ||
7914
+ (command === 'template' && blockedTemplateSub.has(templateSub)) ||
7915
+ (command === 'v3' && v3Sub === 'run');
7916
+ if (rootDenied ||
7917
+ mcpDenied ||
7918
+ (isSchedule && blockedScheduleSub.has(scheduleSub)) ||
7919
+ workflowMutation) {
7127
7920
  const runId = process.env.BOTMUX_WORKFLOW_RUN_ID ?? '?';
7128
7921
  const nodeId = process.env.BOTMUX_WORKFLOW_NODE_ID ?? '?';
7129
- console.error(`botmux ${command}${isSchedule ? ` ${scheduleSub}` : ''} refused inside workflow ` +
7130
- `subagent (run=${runId} node=${nodeId}). Chat-facing or schedule-mutating ` +
7131
- `effects belong in a hostExecutor activity, not a subagent.`);
7922
+ const sub = isSchedule
7923
+ ? scheduleSub
7924
+ : command === 'mcp'
7925
+ ? mcpSub
7926
+ : command === 'workflow'
7927
+ ? workflowSub
7928
+ : command === 'template'
7929
+ ? templateSub
7930
+ : command === 'v3'
7931
+ ? v3Sub
7932
+ : '';
7933
+ const guidance = mcpDenied
7934
+ ? 'Only the botmux-owned Plugin MCP gateway bootstrap (`mcp serve`) is available inside a workflow subagent.'
7935
+ : workflowMutation
7936
+ ? 'Workflow authorization and run mutations must be initiated by the host/user, not a subagent.'
7937
+ : rootDenied
7938
+ ? 'This root command is not in the workflow read-only allowlist; chat-facing effects belong in a hostExecutor activity.'
7939
+ : 'Chat-facing or schedule-mutating effects belong in a hostExecutor activity, not a subagent.';
7940
+ console.error(`botmux ${command}${sub ? ` ${sub}` : ''} refused inside workflow ` +
7941
+ `subagent (run=${runId} node=${nodeId}). ${guidance}`);
7132
7942
  process.exit(2);
7133
7943
  }
7134
7944
  }
@@ -7650,7 +8460,7 @@ switch (command) {
7650
8460
  console.log(getVersion());
7651
8461
  break;
7652
8462
  case 'setup': {
7653
- // 带子命令(list/add/edit/remove/help)走脚本化非 TUI 模式;空参数 / 纯
8463
+ // 带子命令(list/add/configure/edit/remove/help)走脚本化非 TUI 模式;空参数 / 纯
7654
8464
  // flag(如 --no-open-platform-auto)保持原交互 TUI,向后兼容。
7655
8465
  const setupArgs = process.argv.slice(3);
7656
8466
  if (isScriptedSetupInvocation(setupArgs))
@@ -7678,6 +8488,7 @@ switch (command) {
7678
8488
  cmdStatus();
7679
8489
  break;
7680
8490
  case 'upgrade':
8491
+ case 'update':
7681
8492
  cmdUpgrade();
7682
8493
  break;
7683
8494
  case 'dashboard':
@@ -7704,6 +8515,12 @@ switch (command) {
7704
8515
  case 'suspend':
7705
8516
  await cmdSuspend();
7706
8517
  break;
8518
+ case 'slash':
8519
+ await cmdSlash();
8520
+ break;
8521
+ case 'cd':
8522
+ await cmdCd();
8523
+ break;
7707
8524
  case 'term-link':
7708
8525
  await cmdTermLink(process.argv.slice(3));
7709
8526
  break;
@@ -7763,6 +8580,11 @@ switch (command) {
7763
8580
  }
7764
8581
  case 'workflow': {
7765
8582
  const wfSub = process.argv[3] ?? '';
8583
+ if (wfSub === 'cancel') {
8584
+ // Durable v3 run cancellation. The v2 runtime is retired.
8585
+ await cmdWorkflowCancelV3(process.argv[4], process.argv.slice(5));
8586
+ break;
8587
+ }
7766
8588
  if (wfSub === 'start') {
7767
8589
  // `botmux workflow start <runId>` — kick a daemon-driven v3 run (so
7768
8590
  // humanGate posts approval cards). Needs a live daemon; findDaemon is
@@ -7771,7 +8593,7 @@ switch (command) {
7771
8593
  break;
7772
8594
  }
7773
8595
  if (wfSub === 'retry') {
7774
- // v3 blocked-node retry (the `resume` verb belongs to v0.2).
8596
+ // v3 blocked-node retry; the former v2 `resume` verb is retired.
7775
8597
  await cmdWorkflowRetry(process.argv[4], process.argv.slice(5));
7776
8598
  break;
7777
8599
  }
@@ -7784,6 +8606,11 @@ switch (command) {
7784
8606
  await cmdWorkflow(wfSub, process.argv.slice(4));
7785
8607
  break;
7786
8608
  }
8609
+ case 'template': {
8610
+ const { cmdTemplate } = await import('./cli/workflow.js');
8611
+ await cmdTemplate(process.argv[3] ?? '', process.argv.slice(4));
8612
+ break;
8613
+ }
7787
8614
  case 'v3': {
7788
8615
  // `botmux v3 run <dag.json>` — run a hand-written next-gen (v3) DAG on the
7789
8616
  // real ephemeral worker pool, daemon-independent (dogfood path).