botmux 3.5.0 → 3.6.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 (505) hide show
  1. package/README.en.md +56 -396
  2. package/README.md +55 -396
  3. package/dist/.runtime-build-id +1 -0
  4. package/dist/adapters/backend/sandbox.d.ts +99 -279
  5. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  6. package/dist/adapters/backend/sandbox.js +424 -826
  7. package/dist/adapters/backend/sandbox.js.map +1 -1
  8. package/dist/adapters/cli/claude-code.d.ts +6 -0
  9. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  10. package/dist/adapters/cli/claude-code.js +197 -11
  11. package/dist/adapters/cli/claude-code.js.map +1 -1
  12. package/dist/adapters/cli/coco.js +4 -4
  13. package/dist/adapters/cli/coco.js.map +1 -1
  14. package/dist/adapters/cli/codex-app.d.ts.map +1 -1
  15. package/dist/adapters/cli/codex-app.js +9 -6
  16. package/dist/adapters/cli/codex-app.js.map +1 -1
  17. package/dist/adapters/cli/codex.d.ts.map +1 -1
  18. package/dist/adapters/cli/codex.js +9 -5
  19. package/dist/adapters/cli/codex.js.map +1 -1
  20. package/dist/adapters/cli/fs-policy.d.ts +244 -0
  21. package/dist/adapters/cli/fs-policy.d.ts.map +1 -0
  22. package/dist/adapters/cli/fs-policy.js +537 -0
  23. package/dist/adapters/cli/fs-policy.js.map +1 -0
  24. package/dist/adapters/cli/grok.d.ts +2 -1
  25. package/dist/adapters/cli/grok.d.ts.map +1 -1
  26. package/dist/adapters/cli/grok.js +2 -1
  27. package/dist/adapters/cli/grok.js.map +1 -1
  28. package/dist/adapters/cli/hermes.d.ts.map +1 -1
  29. package/dist/adapters/cli/hermes.js +8 -4
  30. package/dist/adapters/cli/hermes.js.map +1 -1
  31. package/dist/adapters/cli/mtr.d.ts.map +1 -1
  32. package/dist/adapters/cli/mtr.js +3 -2
  33. package/dist/adapters/cli/mtr.js.map +1 -1
  34. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  35. package/dist/adapters/cli/opencode.js +5 -4
  36. package/dist/adapters/cli/opencode.js.map +1 -1
  37. package/dist/adapters/cli/read-isolation.d.ts +14 -200
  38. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  39. package/dist/adapters/cli/read-isolation.js +18 -477
  40. package/dist/adapters/cli/read-isolation.js.map +1 -1
  41. package/dist/adapters/cli/relay.js +2 -2
  42. package/dist/adapters/cli/relay.js.map +1 -1
  43. package/dist/adapters/cli/runner-input.d.ts +2 -2
  44. package/dist/adapters/cli/runner-input.d.ts.map +1 -1
  45. package/dist/adapters/cli/runner-input.js +9 -6
  46. package/dist/adapters/cli/runner-input.js.map +1 -1
  47. package/dist/adapters/cli/seed.d.ts.map +1 -1
  48. package/dist/adapters/cli/seed.js +2 -1
  49. package/dist/adapters/cli/seed.js.map +1 -1
  50. package/dist/adapters/cli/traex.d.ts.map +1 -1
  51. package/dist/adapters/cli/traex.js +3 -2
  52. package/dist/adapters/cli/traex.js.map +1 -1
  53. package/dist/adapters/cli/types.d.ts +25 -18
  54. package/dist/adapters/cli/types.d.ts.map +1 -1
  55. package/dist/bot-registry.d.ts +54 -23
  56. package/dist/bot-registry.d.ts.map +1 -1
  57. package/dist/bot-registry.js +91 -0
  58. package/dist/bot-registry.js.map +1 -1
  59. package/dist/cli.d.ts.map +1 -1
  60. package/dist/cli.js +297 -104
  61. package/dist/cli.js.map +1 -1
  62. package/dist/codex-app-runner.js +85 -192
  63. package/dist/codex-app-runner.js.map +1 -1
  64. package/dist/config.d.ts +0 -16
  65. package/dist/config.d.ts.map +1 -1
  66. package/dist/config.js +0 -30
  67. package/dist/config.js.map +1 -1
  68. package/dist/core/ask-broker.d.ts +12 -0
  69. package/dist/core/ask-broker.d.ts.map +1 -1
  70. package/dist/core/ask-broker.js +41 -0
  71. package/dist/core/ask-broker.js.map +1 -1
  72. package/dist/core/bot-turn-mutation-gate.d.ts +24 -0
  73. package/dist/core/bot-turn-mutation-gate.d.ts.map +1 -0
  74. package/dist/core/bot-turn-mutation-gate.js +369 -0
  75. package/dist/core/bot-turn-mutation-gate.js.map +1 -0
  76. package/dist/core/command-handler.d.ts +5 -0
  77. package/dist/core/command-handler.d.ts.map +1 -1
  78. package/dist/core/command-handler.js +53 -73
  79. package/dist/core/command-handler.js.map +1 -1
  80. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  81. package/dist/core/dashboard-ipc-server.js +356 -84
  82. package/dist/core/dashboard-ipc-server.js.map +1 -1
  83. package/dist/core/dashboard-rows.d.ts +8 -0
  84. package/dist/core/dashboard-rows.d.ts.map +1 -1
  85. package/dist/core/dashboard-rows.js.map +1 -1
  86. package/dist/core/host-overload-alert.d.ts +157 -0
  87. package/dist/core/host-overload-alert.d.ts.map +1 -0
  88. package/dist/core/host-overload-alert.js +251 -0
  89. package/dist/core/host-overload-alert.js.map +1 -0
  90. package/dist/core/passthrough-commands.d.ts +8 -0
  91. package/dist/core/passthrough-commands.d.ts.map +1 -1
  92. package/dist/core/passthrough-commands.js +20 -1
  93. package/dist/core/passthrough-commands.js.map +1 -1
  94. package/dist/core/plugins/mcp/gateway-installer.d.ts.map +1 -1
  95. package/dist/core/plugins/mcp/gateway-installer.js +14 -2
  96. package/dist/core/plugins/mcp/gateway-installer.js.map +1 -1
  97. package/dist/core/restart-coordinator.d.ts +28 -0
  98. package/dist/core/restart-coordinator.d.ts.map +1 -0
  99. package/dist/core/restart-coordinator.js +82 -0
  100. package/dist/core/restart-coordinator.js.map +1 -0
  101. package/dist/core/restart-followup-policy.d.ts +112 -0
  102. package/dist/core/restart-followup-policy.d.ts.map +1 -0
  103. package/dist/core/restart-followup-policy.js +49 -0
  104. package/dist/core/restart-followup-policy.js.map +1 -0
  105. package/dist/core/role-library.d.ts +1 -1
  106. package/dist/core/role-library.js +1 -1
  107. package/dist/core/session-cwd.d.ts.map +1 -1
  108. package/dist/core/session-cwd.js +8 -0
  109. package/dist/core/session-cwd.js.map +1 -1
  110. package/dist/core/session-discovery.d.ts +14 -0
  111. package/dist/core/session-discovery.d.ts.map +1 -1
  112. package/dist/core/session-discovery.js +25 -0
  113. package/dist/core/session-discovery.js.map +1 -1
  114. package/dist/core/session-liveness.d.ts +15 -0
  115. package/dist/core/session-liveness.d.ts.map +1 -0
  116. package/dist/core/session-liveness.js +76 -0
  117. package/dist/core/session-liveness.js.map +1 -0
  118. package/dist/core/session-manager.d.ts.map +1 -1
  119. package/dist/core/session-manager.js +90 -60
  120. package/dist/core/session-manager.js.map +1 -1
  121. package/dist/core/session-row-enrichment.d.ts +15 -0
  122. package/dist/core/session-row-enrichment.d.ts.map +1 -0
  123. package/dist/core/session-row-enrichment.js +93 -0
  124. package/dist/core/session-row-enrichment.js.map +1 -0
  125. package/dist/core/slash-inject.js +1 -1
  126. package/dist/core/slash-inject.js.map +1 -1
  127. package/dist/core/trigger-final-suppression.d.ts +24 -0
  128. package/dist/core/trigger-final-suppression.d.ts.map +1 -0
  129. package/dist/core/trigger-final-suppression.js +97 -0
  130. package/dist/core/trigger-final-suppression.js.map +1 -0
  131. package/dist/core/trigger-session.d.ts.map +1 -1
  132. package/dist/core/trigger-session.js +64 -4
  133. package/dist/core/trigger-session.js.map +1 -1
  134. package/dist/core/types.d.ts +6 -0
  135. package/dist/core/types.d.ts.map +1 -1
  136. package/dist/core/types.js.map +1 -1
  137. package/dist/core/worker-pool.d.ts +44 -0
  138. package/dist/core/worker-pool.d.ts.map +1 -1
  139. package/dist/core/worker-pool.js +333 -38
  140. package/dist/core/worker-pool.js.map +1 -1
  141. package/dist/daemon.d.ts +5 -1
  142. package/dist/daemon.d.ts.map +1 -1
  143. package/dist/daemon.js +526 -35
  144. package/dist/daemon.js.map +1 -1
  145. package/dist/dashboard/aggregator.d.ts +1 -0
  146. package/dist/dashboard/aggregator.d.ts.map +1 -1
  147. package/dist/dashboard/aggregator.js +34 -6
  148. package/dist/dashboard/aggregator.js.map +1 -1
  149. package/dist/dashboard/bot-payload.d.ts +8 -0
  150. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  151. package/dist/dashboard/bot-payload.js +10 -0
  152. package/dist/dashboard/bot-payload.js.map +1 -1
  153. package/dist/dashboard/compat.d.ts +102 -2
  154. package/dist/dashboard/compat.d.ts.map +1 -1
  155. package/dist/dashboard/compat.js +78 -14
  156. package/dist/dashboard/compat.js.map +1 -1
  157. package/dist/dashboard/connector-api.d.ts.map +1 -1
  158. package/dist/dashboard/connector-api.js +1 -0
  159. package/dist/dashboard/connector-api.js.map +1 -1
  160. package/dist/dashboard/desktop-asks.d.ts +21 -0
  161. package/dist/dashboard/desktop-asks.d.ts.map +1 -0
  162. package/dist/dashboard/desktop-asks.js +49 -0
  163. package/dist/dashboard/desktop-asks.js.map +1 -0
  164. package/dist/dashboard/public-redact.d.ts +7 -0
  165. package/dist/dashboard/public-redact.d.ts.map +1 -1
  166. package/dist/dashboard/public-redact.js +35 -3
  167. package/dist/dashboard/public-redact.js.map +1 -1
  168. package/dist/dashboard/session-presentation.d.ts +16 -0
  169. package/dist/dashboard/session-presentation.d.ts.map +1 -0
  170. package/dist/dashboard/session-presentation.js +62 -0
  171. package/dist/dashboard/session-presentation.js.map +1 -0
  172. package/dist/dashboard/settings-write-applier.d.ts +2 -1
  173. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  174. package/dist/dashboard/settings-write-applier.js +19 -1
  175. package/dist/dashboard/settings-write-applier.js.map +1 -1
  176. package/dist/dashboard/trigger-api.d.ts.map +1 -1
  177. package/dist/dashboard/trigger-api.js +19 -1
  178. package/dist/dashboard/trigger-api.js.map +1 -1
  179. package/dist/dashboard/vc-consumer-profiles-api.d.ts +7 -2
  180. package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
  181. package/dist/dashboard/vc-consumer-profiles-api.js +13 -0
  182. package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
  183. package/dist/dashboard/web/app.d.ts.map +1 -1
  184. package/dist/dashboard/web/app.js +18 -5
  185. package/dist/dashboard/web/app.js.map +1 -1
  186. package/dist/dashboard/web/bot-defaults-page.d.ts +16 -0
  187. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  188. package/dist/dashboard/web/bot-defaults-page.js +288 -7
  189. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  190. package/dist/dashboard/web/bot-defaults.d.ts +10 -0
  191. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  192. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  193. package/dist/dashboard/web/client-shell.d.ts +29 -0
  194. package/dist/dashboard/web/client-shell.d.ts.map +1 -0
  195. package/dist/dashboard/web/client-shell.js +89 -0
  196. package/dist/dashboard/web/client-shell.js.map +1 -0
  197. package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
  198. package/dist/dashboard/web/connectors-page.js +5 -1
  199. package/dist/dashboard/web/connectors-page.js.map +1 -1
  200. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  201. package/dist/dashboard/web/i18n.js +130 -22
  202. package/dist/dashboard/web/i18n.js.map +1 -1
  203. package/dist/dashboard/web/preferences.d.ts +7 -0
  204. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  205. package/dist/dashboard/web/preferences.js +32 -0
  206. package/dist/dashboard/web/preferences.js.map +1 -1
  207. package/dist/dashboard/web/sessions-kanban.d.ts +1 -1
  208. package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
  209. package/dist/dashboard/web/sessions-kanban.js +1 -1
  210. package/dist/dashboard/web/sessions-kanban.js.map +1 -1
  211. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  212. package/dist/dashboard/web/sessions-page.js +78 -67
  213. package/dist/dashboard/web/sessions-page.js.map +1 -1
  214. package/dist/dashboard/web/sessions.d.ts +4 -0
  215. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  216. package/dist/dashboard/web/sessions.js +14 -1
  217. package/dist/dashboard/web/sessions.js.map +1 -1
  218. package/dist/dashboard/web/settings-page.d.ts +6 -0
  219. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  220. package/dist/dashboard/web/settings-page.js +55 -30
  221. package/dist/dashboard/web/settings-page.js.map +1 -1
  222. package/dist/dashboard/web/store.d.ts +1 -2
  223. package/dist/dashboard/web/store.d.ts.map +1 -1
  224. package/dist/dashboard/web/store.js +69 -20
  225. package/dist/dashboard/web/store.js.map +1 -1
  226. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
  227. package/dist/dashboard/web/vc-consumer-profiles-section.js +128 -42
  228. package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
  229. package/dist/dashboard/webhook-routes.d.ts.map +1 -1
  230. package/dist/dashboard/webhook-routes.js +9 -2
  231. package/dist/dashboard/webhook-routes.js.map +1 -1
  232. package/dist/dashboard-web/app.js +1 -1
  233. package/dist/dashboard-web/chunks/bot-defaults-page-VQMPUJ4Y.js +10 -0
  234. package/dist/dashboard-web/chunks/chunk-AGCPF6MT.js +1 -0
  235. package/dist/dashboard-web/chunks/{chunk-QCPPKCX3.js → chunk-JMRGZQDB.js} +1 -1
  236. package/dist/dashboard-web/chunks/{chunk-EJDYUINZ.js → chunk-NP4JUBGS.js} +1 -1
  237. package/dist/dashboard-web/chunks/{chunk-WXPMNEYV.js → chunk-P327LXOT.js} +1 -1
  238. package/dist/dashboard-web/chunks/chunk-SNKATZWK.js +49 -0
  239. package/dist/dashboard-web/chunks/connectors-page-DOY4J3ZL.js +1 -0
  240. package/dist/dashboard-web/chunks/{groups-page-3P4TLUMF.js → groups-page-74TS2DIH.js} +1 -1
  241. package/dist/dashboard-web/chunks/{insights-page-TDCZV56A.js → insights-page-AYCO65JC.js} +1 -1
  242. package/dist/dashboard-web/chunks/{monitor-room-QWCWL3SX.js → monitor-room-YKYLTSAN.js} +1 -1
  243. package/dist/dashboard-web/chunks/{monitoring-page-IOWFSNVC.js → monitoring-page-QBIUNRBR.js} +1 -1
  244. package/dist/dashboard-web/chunks/{office-page-5AUPEHZP.js → office-page-4PH2A26P.js} +1 -1
  245. package/dist/dashboard-web/chunks/overview-page-H73D5UT4.js +1 -0
  246. package/dist/dashboard-web/chunks/{roles-page-WJVB52ET.js → roles-page-U4BTOQ7F.js} +1 -1
  247. package/dist/dashboard-web/chunks/{schedules-page-RVRWHP4V.js → schedules-page-RHRHX7R7.js} +1 -1
  248. package/dist/dashboard-web/chunks/sessions-page-VSC6AM5G.js +2 -0
  249. package/dist/dashboard-web/chunks/settings-page-LF3RKM5P.js +2 -0
  250. package/dist/dashboard-web/chunks/{skills-page-7YT5TIX5.js → skills-page-SYOIGGXH.js} +1 -1
  251. package/dist/dashboard-web/chunks/{team-federation-page-NJZKTU7A.js → team-federation-page-RMBLASTW.js} +1 -1
  252. package/dist/dashboard-web/chunks/{v3-page-NQ73UA2Q.js → v3-page-XJXKKJRN.js} +1 -1
  253. package/dist/dashboard-web/chunks/{whiteboards-page-DSM3MDMN.js → whiteboards-page-K3YVSTHJ.js} +1 -1
  254. package/dist/dashboard-web/style.css +571 -3
  255. package/dist/dashboard.js +238 -9
  256. package/dist/dashboard.js.map +1 -1
  257. package/dist/global-config.d.ts +11 -0
  258. package/dist/global-config.d.ts.map +1 -1
  259. package/dist/global-config.js +27 -1
  260. package/dist/global-config.js.map +1 -1
  261. package/dist/i18n/en.d.ts.map +1 -1
  262. package/dist/i18n/en.js +6 -19
  263. package/dist/i18n/en.js.map +1 -1
  264. package/dist/i18n/zh.d.ts.map +1 -1
  265. package/dist/i18n/zh.js +6 -19
  266. package/dist/i18n/zh.js.map +1 -1
  267. package/dist/im/lark/card-builder.d.ts +1 -14
  268. package/dist/im/lark/card-builder.d.ts.map +1 -1
  269. package/dist/im/lark/card-builder.js +1 -35
  270. package/dist/im/lark/card-builder.js.map +1 -1
  271. package/dist/im/lark/card-handler.d.ts +10 -0
  272. package/dist/im/lark/card-handler.d.ts.map +1 -1
  273. package/dist/im/lark/card-handler.js +161 -44
  274. package/dist/im/lark/card-handler.js.map +1 -1
  275. package/dist/im/lark/client.d.ts +47 -0
  276. package/dist/im/lark/client.d.ts.map +1 -1
  277. package/dist/im/lark/client.js +127 -18
  278. package/dist/im/lark/client.js.map +1 -1
  279. package/dist/im/lark/event-dispatcher.d.ts +13 -0
  280. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  281. package/dist/im/lark/event-dispatcher.js +48 -3
  282. package/dist/im/lark/event-dispatcher.js.map +1 -1
  283. package/dist/im/lark/identity-cache.d.ts +25 -1
  284. package/dist/im/lark/identity-cache.d.ts.map +1 -1
  285. package/dist/im/lark/identity-cache.js +47 -1
  286. package/dist/im/lark/identity-cache.js.map +1 -1
  287. package/dist/im/lark/overload-nonce.d.ts +19 -0
  288. package/dist/im/lark/overload-nonce.d.ts.map +1 -0
  289. package/dist/im/lark/overload-nonce.js +72 -0
  290. package/dist/im/lark/overload-nonce.js.map +1 -0
  291. package/dist/im/lark/v3-progress-card.d.ts.map +1 -1
  292. package/dist/im/lark/v3-progress-card.js +5 -0
  293. package/dist/im/lark/v3-progress-card.js.map +1 -1
  294. package/dist/services/async-trigger-state.d.ts +82 -0
  295. package/dist/services/async-trigger-state.d.ts.map +1 -0
  296. package/dist/services/async-trigger-state.js +95 -0
  297. package/dist/services/async-trigger-state.js.map +1 -0
  298. package/dist/services/async-trigger-store.d.ts +28 -0
  299. package/dist/services/async-trigger-store.d.ts.map +1 -0
  300. package/dist/services/async-trigger-store.js +120 -0
  301. package/dist/services/async-trigger-store.js.map +1 -0
  302. package/dist/services/bot-config-store.d.ts.map +1 -1
  303. package/dist/services/bot-config-store.js +34 -2
  304. package/dist/services/bot-config-store.js.map +1 -1
  305. package/dist/services/bridge-fallback-gate.d.ts +32 -0
  306. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  307. package/dist/services/bridge-fallback-gate.js +39 -0
  308. package/dist/services/bridge-fallback-gate.js.map +1 -1
  309. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  310. package/dist/services/bridge-turn-queue.js +15 -1
  311. package/dist/services/bridge-turn-queue.js.map +1 -1
  312. package/dist/services/card-prefs-store.d.ts +4 -0
  313. package/dist/services/card-prefs-store.d.ts.map +1 -1
  314. package/dist/services/card-prefs-store.js +8 -0
  315. package/dist/services/card-prefs-store.js.map +1 -1
  316. package/dist/services/claude-transcript.d.ts +23 -0
  317. package/dist/services/claude-transcript.d.ts.map +1 -1
  318. package/dist/services/claude-transcript.js +33 -0
  319. package/dist/services/claude-transcript.js.map +1 -1
  320. package/dist/services/codex-app-runner-protocol.d.ts +61 -0
  321. package/dist/services/codex-app-runner-protocol.d.ts.map +1 -0
  322. package/dist/services/codex-app-runner-protocol.js +170 -0
  323. package/dist/services/codex-app-runner-protocol.js.map +1 -0
  324. package/dist/services/codex-app-turn-controller.d.ts +72 -0
  325. package/dist/services/codex-app-turn-controller.d.ts.map +1 -0
  326. package/dist/services/codex-app-turn-controller.js +524 -0
  327. package/dist/services/codex-app-turn-controller.js.map +1 -0
  328. package/dist/services/codex-runner-freshness.d.ts +39 -0
  329. package/dist/services/codex-runner-freshness.d.ts.map +1 -0
  330. package/dist/services/codex-runner-freshness.js +78 -0
  331. package/dist/services/codex-runner-freshness.js.map +1 -0
  332. package/dist/services/connector-store.d.ts +6 -0
  333. package/dist/services/connector-store.d.ts.map +1 -1
  334. package/dist/services/connector-store.js.map +1 -1
  335. package/dist/services/grant-store.d.ts.map +1 -1
  336. package/dist/services/grant-store.js +16 -0
  337. package/dist/services/grant-store.js.map +1 -1
  338. package/dist/services/hermes-transcript.d.ts +1 -0
  339. package/dist/services/hermes-transcript.d.ts.map +1 -1
  340. package/dist/services/hermes-transcript.js +49 -0
  341. package/dist/services/hermes-transcript.js.map +1 -1
  342. package/dist/services/sandbox-migration.d.ts +14 -0
  343. package/dist/services/sandbox-migration.d.ts.map +1 -0
  344. package/dist/services/sandbox-migration.js +85 -0
  345. package/dist/services/sandbox-migration.js.map +1 -0
  346. package/dist/services/sandbox-store.d.ts +28 -0
  347. package/dist/services/sandbox-store.d.ts.map +1 -1
  348. package/dist/services/sandbox-store.js +82 -0
  349. package/dist/services/sandbox-store.js.map +1 -1
  350. package/dist/services/schedule-split-migration.d.ts +2 -0
  351. package/dist/services/schedule-split-migration.d.ts.map +1 -0
  352. package/dist/services/schedule-split-migration.js +159 -0
  353. package/dist/services/schedule-split-migration.js.map +1 -0
  354. package/dist/services/schedule-store.d.ts +28 -4
  355. package/dist/services/schedule-store.d.ts.map +1 -1
  356. package/dist/services/schedule-store.js +118 -33
  357. package/dist/services/schedule-store.js.map +1 -1
  358. package/dist/services/trigger-types.d.ts +18 -1
  359. package/dist/services/trigger-types.d.ts.map +1 -1
  360. package/dist/services/trigger-types.js +3 -0
  361. package/dist/services/trigger-types.js.map +1 -1
  362. package/dist/services/vc-meeting-consumer-profile-store.d.ts.map +1 -1
  363. package/dist/services/vc-meeting-consumer-profile-store.js +1 -0
  364. package/dist/services/vc-meeting-consumer-profile-store.js.map +1 -1
  365. package/dist/services/vc-meeting-consumer-profile-templates.d.ts +32 -0
  366. package/dist/services/vc-meeting-consumer-profile-templates.d.ts.map +1 -0
  367. package/dist/services/vc-meeting-consumer-profile-templates.js +106 -0
  368. package/dist/services/vc-meeting-consumer-profile-templates.js.map +1 -0
  369. package/dist/services/vc-meeting-delivery-feed.d.ts +1 -1
  370. package/dist/services/vc-meeting-delivery-feed.d.ts.map +1 -1
  371. package/dist/services/vc-meeting-delivery-feed.js +2 -1
  372. package/dist/services/vc-meeting-delivery-feed.js.map +1 -1
  373. package/dist/services/vc-meeting-delivery-hub-store.d.ts +3 -1
  374. package/dist/services/vc-meeting-delivery-hub-store.d.ts.map +1 -1
  375. package/dist/services/vc-meeting-delivery-hub-store.js +11 -0
  376. package/dist/services/vc-meeting-delivery-hub-store.js.map +1 -1
  377. package/dist/services/vc-meeting-delivery-protocol.d.ts +9 -2
  378. package/dist/services/vc-meeting-delivery-protocol.d.ts.map +1 -1
  379. package/dist/services/vc-meeting-delivery-protocol.js +10 -1
  380. package/dist/services/vc-meeting-delivery-protocol.js.map +1 -1
  381. package/dist/services/vc-meeting-delivery-receiver.d.ts.map +1 -1
  382. package/dist/services/vc-meeting-delivery-receiver.js +10 -1
  383. package/dist/services/vc-meeting-delivery-receiver.js.map +1 -1
  384. package/dist/services/vc-meeting-delivery-store.d.ts +12 -2
  385. package/dist/services/vc-meeting-delivery-store.d.ts.map +1 -1
  386. package/dist/services/vc-meeting-delivery-store.js +14 -2
  387. package/dist/services/vc-meeting-delivery-store.js.map +1 -1
  388. package/dist/services/vc-meeting-im-reply.d.ts +2 -1
  389. package/dist/services/vc-meeting-im-reply.d.ts.map +1 -1
  390. package/dist/services/vc-meeting-im-reply.js +19 -3
  391. package/dist/services/vc-meeting-im-reply.js.map +1 -1
  392. package/dist/services/vc-meeting-listener-output-protocol.d.ts +27 -0
  393. package/dist/services/vc-meeting-listener-output-protocol.d.ts.map +1 -0
  394. package/dist/services/vc-meeting-listener-output-protocol.js +58 -0
  395. package/dist/services/vc-meeting-listener-output-protocol.js.map +1 -0
  396. package/dist/services/vc-meeting-listener-topic-store.d.ts +31 -0
  397. package/dist/services/vc-meeting-listener-topic-store.d.ts.map +1 -0
  398. package/dist/services/vc-meeting-listener-topic-store.js +120 -0
  399. package/dist/services/vc-meeting-listener-topic-store.js.map +1 -0
  400. package/dist/services/vc-meeting-runtime-store.d.ts +2 -1
  401. package/dist/services/vc-meeting-runtime-store.d.ts.map +1 -1
  402. package/dist/services/vc-meeting-runtime-store.js +8 -0
  403. package/dist/services/vc-meeting-runtime-store.js.map +1 -1
  404. package/dist/services/vc-meeting-send-policy.d.ts +8 -1
  405. package/dist/services/vc-meeting-send-policy.d.ts.map +1 -1
  406. package/dist/services/vc-meeting-send-policy.js +8 -0
  407. package/dist/services/vc-meeting-send-policy.js.map +1 -1
  408. package/dist/types.d.ts +53 -4
  409. package/dist/types.d.ts.map +1 -1
  410. package/dist/utils/allowed-users-apply.d.ts +76 -0
  411. package/dist/utils/allowed-users-apply.d.ts.map +1 -0
  412. package/dist/utils/allowed-users-apply.js +123 -0
  413. package/dist/utils/allowed-users-apply.js.map +1 -0
  414. package/dist/utils/allowed-users-cache.d.ts +29 -0
  415. package/dist/utils/allowed-users-cache.d.ts.map +1 -0
  416. package/dist/utils/allowed-users-cache.js +82 -0
  417. package/dist/utils/allowed-users-cache.js.map +1 -0
  418. package/dist/utils/child-env.d.ts +4 -3
  419. package/dist/utils/child-env.d.ts.map +1 -1
  420. package/dist/utils/child-env.js +16 -1
  421. package/dist/utils/child-env.js.map +1 -1
  422. package/dist/utils/cli-usage-limit.d.ts +27 -1
  423. package/dist/utils/cli-usage-limit.d.ts.map +1 -1
  424. package/dist/utils/cli-usage-limit.js +92 -20
  425. package/dist/utils/cli-usage-limit.js.map +1 -1
  426. package/dist/utils/input-gate.d.ts +2 -0
  427. package/dist/utils/input-gate.d.ts.map +1 -1
  428. package/dist/utils/input-gate.js +2 -0
  429. package/dist/utils/input-gate.js.map +1 -1
  430. package/dist/utils/runtime-build-id.d.ts +21 -0
  431. package/dist/utils/runtime-build-id.d.ts.map +1 -0
  432. package/dist/utils/runtime-build-id.js +83 -0
  433. package/dist/utils/runtime-build-id.js.map +1 -0
  434. package/dist/utils/terminal-renderer.d.ts +3 -3
  435. package/dist/utils/terminal-renderer.js +3 -3
  436. package/dist/vc-agent/cards.d.ts.map +1 -1
  437. package/dist/vc-agent/cards.js +21 -1
  438. package/dist/vc-agent/cards.js.map +1 -1
  439. package/dist/worker.js +1010 -669
  440. package/dist/worker.js.map +1 -1
  441. package/dist/workflows/events/payloads.d.ts +56 -0
  442. package/dist/workflows/events/payloads.d.ts.map +1 -1
  443. package/dist/workflows/events/payloads.js +9 -0
  444. package/dist/workflows/events/payloads.js.map +1 -1
  445. package/dist/workflows/events/schema.d.ts +86 -0
  446. package/dist/workflows/events/schema.d.ts.map +1 -1
  447. package/dist/workflows/hostExecutors/botmux-schedule.d.ts.map +1 -1
  448. package/dist/workflows/hostExecutors/botmux-schedule.js +13 -1
  449. package/dist/workflows/hostExecutors/botmux-schedule.js.map +1 -1
  450. package/dist/workflows/migration/v2-run-archive-schema.d.ts +20 -20
  451. package/dist/workflows/migration/v2-to-v3.d.ts.map +1 -1
  452. package/dist/workflows/migration/v2-to-v3.js +5 -1
  453. package/dist/workflows/migration/v2-to-v3.js.map +1 -1
  454. package/dist/workflows/shared/sandbox-policy.d.ts +10 -1
  455. package/dist/workflows/shared/sandbox-policy.d.ts.map +1 -1
  456. package/dist/workflows/shared/sandbox-policy.js +12 -0
  457. package/dist/workflows/shared/sandbox-policy.js.map +1 -1
  458. package/dist/workflows/v3/architect.d.ts.map +1 -1
  459. package/dist/workflows/v3/architect.js +1 -0
  460. package/dist/workflows/v3/architect.js.map +1 -1
  461. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
  462. package/dist/workflows/v3/bot-resolve.js +36 -0
  463. package/dist/workflows/v3/bot-resolve.js.map +1 -1
  464. package/dist/workflows/v3/cli-run.d.ts +9 -0
  465. package/dist/workflows/v3/cli-run.d.ts.map +1 -1
  466. package/dist/workflows/v3/cli-run.js +17 -2
  467. package/dist/workflows/v3/cli-run.js.map +1 -1
  468. package/dist/workflows/v3/contract.d.ts +8 -0
  469. package/dist/workflows/v3/contract.d.ts.map +1 -1
  470. package/dist/workflows/v3/contract.js.map +1 -1
  471. package/dist/workflows/v3/goal-cli.d.ts +58 -0
  472. package/dist/workflows/v3/goal-cli.d.ts.map +1 -0
  473. package/dist/workflows/v3/goal-cli.js +430 -0
  474. package/dist/workflows/v3/goal-cli.js.map +1 -0
  475. package/dist/workflows/v3/library-materialize.d.ts.map +1 -1
  476. package/dist/workflows/v3/library-materialize.js +5 -1
  477. package/dist/workflows/v3/library-materialize.js.map +1 -1
  478. package/dist/workflows/v3/library-schema.d.ts +21 -0
  479. package/dist/workflows/v3/library-schema.d.ts.map +1 -1
  480. package/dist/workflows/v3/library-schema.js +95 -1
  481. package/dist/workflows/v3/library-schema.js.map +1 -1
  482. package/dist/workflows/v3/progress-projection.d.ts +3 -0
  483. package/dist/workflows/v3/progress-projection.d.ts.map +1 -1
  484. package/dist/workflows/v3/progress-projection.js +23 -1
  485. package/dist/workflows/v3/progress-projection.js.map +1 -1
  486. package/dist/workflows/v3/run-envelope.d.ts +46 -1
  487. package/dist/workflows/v3/run-envelope.d.ts.map +1 -1
  488. package/dist/workflows/v3/run-envelope.js +32 -1
  489. package/dist/workflows/v3/run-envelope.js.map +1 -1
  490. package/package.json +2 -2
  491. package/dist/dashboard-web/chunks/bot-defaults-page-O376WSER.js +0 -5
  492. package/dist/dashboard-web/chunks/chunk-H7P5UV4W.js +0 -49
  493. package/dist/dashboard-web/chunks/chunk-SZOB6VK2.js +0 -1
  494. package/dist/dashboard-web/chunks/connectors-page-IR54AOAI.js +0 -1
  495. package/dist/dashboard-web/chunks/overview-page-QJMI6NLW.js +0 -1
  496. package/dist/dashboard-web/chunks/sessions-page-KWLGBX6G.js +0 -3
  497. package/dist/dashboard-web/chunks/settings-page-TNZEPC7V.js +0 -2
  498. package/dist/services/sandbox-land.d.ts +0 -45
  499. package/dist/services/sandbox-land.d.ts.map +0 -1
  500. package/dist/services/sandbox-land.js +0 -394
  501. package/dist/services/sandbox-land.js.map +0 -1
  502. package/dist/utils/screen-analyzer.d.ts +0 -75
  503. package/dist/utils/screen-analyzer.d.ts.map +0 -1
  504. package/dist/utils/screen-analyzer.js +0 -333
  505. package/dist/utils/screen-analyzer.js.map +0 -1
package/dist/cli.js CHANGED
@@ -2888,30 +2888,37 @@ function loadSessions() {
2888
2888
  }
2889
2889
  catch { /* ignore */ }
2890
2890
  }
2891
- // Read per-bot session files (sessions-{appId}.json)
2891
+ // Read per-bot session files (sessions-{appId}.json).
2892
+ const loadPerBot = (appId) => {
2893
+ try {
2894
+ const data = JSON.parse(readFileSync(join(dataDir, `sessions-${appId}.json`), 'utf-8'));
2895
+ for (const [, v] of Object.entries(data)) {
2896
+ const session = v;
2897
+ if (!session || typeof session !== 'object' || !session.sessionId)
2898
+ continue;
2899
+ repairMissingChatScope(session);
2900
+ if (!session.larkAppId)
2901
+ session.larkAppId = appId; // stamp so saveSession writes back correctly
2902
+ sessions.set(session.sessionId, session);
2903
+ }
2904
+ }
2905
+ catch { /* ignore */ }
2906
+ };
2892
2907
  try {
2893
2908
  for (const file of readdirSync(dataDir)) {
2894
2909
  if (file.startsWith('sessions-') && file.endsWith('.json')) {
2895
- try {
2896
- // Extract appId from filename: sessions-{appId}.json
2897
- const appId = file.slice('sessions-'.length, -'.json'.length);
2898
- const data = JSON.parse(readFileSync(join(dataDir, file), 'utf-8'));
2899
- for (const [, v] of Object.entries(data)) {
2900
- const session = v;
2901
- if (!session || typeof session !== 'object' || !session.sessionId)
2902
- continue;
2903
- repairMissingChatScope(session);
2904
- // Stamp larkAppId so saveSession writes back to the correct file
2905
- if (!session.larkAppId)
2906
- session.larkAppId = appId;
2907
- sessions.set(session.sessionId, session);
2908
- }
2909
- }
2910
- catch { /* ignore */ }
2910
+ loadPerBot(file.slice('sessions-'.length, -'.json'.length));
2911
2911
  }
2912
2912
  }
2913
2913
  }
2914
- catch { /* ignore */ }
2914
+ catch {
2915
+ // readdir(dataDir) EPERMs under the file sandbox (the deny-by-default policy
2916
+ // exposes sessions-<self>.json but NOT a listing of data/). Fall back to the
2917
+ // OWN per-bot file directly via the injected appId — the sandboxed agent only
2918
+ // ever operates its own session, so no enumeration is needed.
2919
+ if (process.env.BOTMUX_LARK_APP_ID)
2920
+ loadPerBot(process.env.BOTMUX_LARK_APP_ID);
2921
+ }
2915
2922
  // Migrate: remove sessions from legacy file if they have larkAppId (belong in per-bot files)
2916
2923
  let legacyDirty = false;
2917
2924
  for (const [k, v] of Object.entries(legacyData)) {
@@ -3151,6 +3158,79 @@ function adoptedCliPid(s) {
3151
3158
  const pid = isAdoptedSession(s) ? s.adoptedFrom.originalCliPid : undefined;
3152
3159
  return typeof pid === 'number' && pid > 0 ? pid : undefined;
3153
3160
  }
3161
+ /** Offline-only fallback for `botmux delete`. When the owning daemon is live,
3162
+ * it must own the whole close transition so its activeSessions registry,
3163
+ * persistent row, lifecycle hooks, subscriptions, and backend teardown stay
3164
+ * coherent. This legacy local path is safe only when there is no daemon
3165
+ * process whose in-memory state could be stranded. */
3166
+ function closeSessionOffline(s) {
3167
+ const originalPid = adoptedCliPid(s);
3168
+ // Adopted sessions own only the botmux worker/viewer, never the user's CLI.
3169
+ if (s.pid && s.pid !== originalPid && isProcessAlive(s.pid)) {
3170
+ killProcess(s.pid);
3171
+ }
3172
+ // Adopted panes belong to the user. Ordinary bmx-* sessions are botmux-owned
3173
+ // and still need direct cleanup when no daemon exists to run killWorker().
3174
+ if (!isAdoptedSession(s)) {
3175
+ const tmuxName = `bmx-${s.sessionId.substring(0, 8)}`;
3176
+ try {
3177
+ execSync(`tmux kill-session -t '${tmuxName}' 2>/dev/null`, {
3178
+ stdio: 'ignore',
3179
+ env: tmuxEnv(),
3180
+ });
3181
+ }
3182
+ catch { /* no tmux session */ }
3183
+ }
3184
+ s.status = 'closed';
3185
+ s.closedAt = new Date().toISOString();
3186
+ saveSession(s);
3187
+ }
3188
+ /** Close through the owning daemon whenever it is online. The IPC request is
3189
+ * deliberately sent BEFORE any local kill: deleting the current bmx-* tmux
3190
+ * first would terminate this very CLI before it can evict daemon memory.
3191
+ *
3192
+ * Trusted host callers use the dashboard HMAC. A sandboxed/read-isolated CLI
3193
+ * can only authorize the exact current session with its rotating per-turn
3194
+ * capability, so `delete <other-id>` remains fail-closed. */
3195
+ async function closeSessionForDelete(s, online = listOnlineDaemons()) {
3196
+ // Legacy sessions without larkAppId live in sessions.json. A per-bot daemon
3197
+ // writes only its own sessions-<appId>.json and silently no-ops on close
3198
+ // (sessionStore.closeSession only touches the current file), so routing a
3199
+ // legacy session to it yields "200 OK" with no actual state change. This must
3200
+ // hold on BOTH ways a daemon port is discovered — the descriptor lookup AND
3201
+ // the injected-port current-session fallback below — so gate the whole daemon
3202
+ // path on larkAppId with one authoritative guard. A live daemon-spawned
3203
+ // session always carries larkAppId, so this never diverts the legitimate
3204
+ // sandboxed current-session close (which reaches its daemon via the injected
3205
+ // port); it only keeps larkAppId-less legacy records on the offline fallback,
3206
+ // whose saveSession() persists to the legacy file correctly.
3207
+ if (!s.larkAppId) {
3208
+ closeSessionOffline(s);
3209
+ return { ok: true, via: 'offline' };
3210
+ }
3211
+ const daemon = online.find(d => d.larkAppId === s.larkAppId);
3212
+ const isCurrentSession = process.env.BOTMUX_SESSION_ID === s.sessionId;
3213
+ const injectedPort = isCurrentSession
3214
+ ? resolveDaemonIpcPort(undefined, process.env.BOTMUX_DAEMON_IPC_PORT)
3215
+ : undefined;
3216
+ const ipcPort = daemon?.ipcPort ?? injectedPort;
3217
+ if (ipcPort) {
3218
+ try {
3219
+ const res = await postSessionCliIpc(ipcPort, s.sessionId, 'close', {});
3220
+ const body = await res.json().catch(() => ({}));
3221
+ if (res.ok && body?.ok)
3222
+ return { ok: true, via: 'daemon' };
3223
+ return { ok: false, error: body?.error ?? `HTTP ${res.status}` };
3224
+ }
3225
+ catch (err) {
3226
+ // A fresh daemon descriptor means there may still be authoritative
3227
+ // in-memory state. Never fall back to a partial local kill in this case.
3228
+ return { ok: false, error: `连接 daemon 失败: ${err?.message ?? err}` };
3229
+ }
3230
+ }
3231
+ closeSessionOffline(s);
3232
+ return { ok: true, via: 'offline' };
3233
+ }
3154
3234
  function adoptTargetLabel(s) {
3155
3235
  if (!isAdoptedSession(s))
3156
3236
  return '';
@@ -3330,26 +3410,15 @@ function interactiveSessionPicker(active) {
3330
3410
  process.stdout.write('\x1b[?25h'); // show cursor
3331
3411
  process.stdout.write('\x1b[?1049l'); // leave alt screen
3332
3412
  }
3333
- function deleteSession(idx) {
3413
+ let deleteInFlight = false;
3414
+ async function deleteSession(idx) {
3334
3415
  const r = rows[idx];
3335
3416
  const s = r.session;
3336
- // Kill botmux's worker process. For adopted sessions, never kill the
3337
- // user's original CLI pid if an old record stored it in `pid`.
3338
- const originalPid = adoptedCliPid(s);
3339
- if (s.pid && s.pid !== originalPid && isProcessAlive(s.pid)) {
3340
- killProcess(s.pid);
3341
- }
3342
- // Kill only botmux-owned tmux sessions. Adopted panes belong to the user.
3343
- if (!r.isAdopt && r.hasTmux) {
3344
- try {
3345
- execSync(`tmux kill-session -t '${r.tmuxName}' 2>/dev/null`, { stdio: 'ignore', env: tmuxEnv() });
3346
- }
3347
- catch { /* */ }
3417
+ const result = await closeSessionForDelete(s);
3418
+ if (!result.ok) {
3419
+ flashMsg = `\x1b[31m✗ 删除失败: ${result.error}\x1b[0m`;
3420
+ return;
3348
3421
  }
3349
- // Mark closed & persist
3350
- s.status = 'closed';
3351
- s.closedAt = new Date().toISOString();
3352
- saveSession(s);
3353
3422
  // Remove from active list and TUI rows
3354
3423
  const activeIdx = active.indexOf(s);
3355
3424
  if (activeIdx >= 0)
@@ -3357,14 +3426,24 @@ function interactiveSessionPicker(active) {
3357
3426
  rows.splice(idx, 1);
3358
3427
  if (cursor >= rows.length)
3359
3428
  cursor = Math.max(0, rows.length - 1);
3360
- flashMsg = `\x1b[32m✓ 已删除 ${s.sessionId.substring(0, 8)}\x1b[0m`;
3429
+ flashMsg = result.via === 'daemon'
3430
+ ? `\x1b[32m✓ 已删除 ${s.sessionId.substring(0, 8)}\x1b[0m`
3431
+ : `\x1b[33m✓ 已离线删除 ${s.sessionId.substring(0, 8)}\x1b[0m`;
3361
3432
  }
3362
- process.stdin.on('data', (key) => {
3433
+ process.stdin.on('data', async (key) => {
3434
+ if (deleteInFlight)
3435
+ return;
3363
3436
  // Delete confirmation mode
3364
3437
  if (confirmDelete) {
3365
3438
  confirmDelete = false;
3366
3439
  if (key === 'y' || key === 'Y') {
3367
- deleteSession(cursor);
3440
+ deleteInFlight = true;
3441
+ try {
3442
+ await deleteSession(cursor);
3443
+ }
3444
+ finally {
3445
+ deleteInFlight = false;
3446
+ }
3368
3447
  }
3369
3448
  else {
3370
3449
  flashMsg = '\x1b[2m取消删除\x1b[0m';
@@ -3493,7 +3572,7 @@ async function cmdList() {
3493
3572
  // Interactive TUI
3494
3573
  await interactiveSessionPicker(live);
3495
3574
  }
3496
- function cmdDelete() {
3575
+ async function cmdDelete() {
3497
3576
  const target = process.argv[3];
3498
3577
  if (!target) {
3499
3578
  console.error('用法: botmux delete <session-id|all>');
@@ -3511,6 +3590,13 @@ function cmdDelete() {
3511
3590
  }
3512
3591
  else if (target === 'stopped') {
3513
3592
  toDelete = active.filter(s => {
3593
+ // A deliberately cap-suspended session has neither pid nor backing pane
3594
+ // (that's how its memory is reclaimed) but must cold-resume on the next
3595
+ // message — never a zombie. Mirrors the server-side isSessionStopped guard
3596
+ // and the `list` prune disposition; without it `delete stopped` (which the
3597
+ // overload alert text recommends) would drop a live-but-parked session.
3598
+ if (isColdResumeDormant(s))
3599
+ return false;
3514
3600
  if (isAdoptedSession(s)) {
3515
3601
  const pid = adoptedCliPid(s);
3516
3602
  return pid ? !isProcessAlive(pid) : !(s.pid && isProcessAlive(s.pid));
@@ -3540,31 +3626,31 @@ function cmdDelete() {
3540
3626
  process.exit(1);
3541
3627
  }
3542
3628
  }
3629
+ // A self-delete may tear down the process running this loop. Put it last so
3630
+ // `delete all` still closes every other target before the current session.
3631
+ const currentSessionId = process.env.BOTMUX_SESSION_ID;
3632
+ if (currentSessionId && toDelete.length > 1) {
3633
+ toDelete.sort((a, b) => Number(a.sessionId === currentSessionId) - Number(b.sessionId === currentSessionId));
3634
+ }
3635
+ const online = listOnlineDaemons();
3636
+ let closed = 0;
3637
+ let offline = 0;
3638
+ let failed = 0;
3543
3639
  for (const s of toDelete) {
3544
- const originalPid = adoptedCliPid(s);
3545
- // Kill botmux's worker process if running. For adopted sessions, never
3546
- // kill the user's original CLI pid.
3547
- if (s.pid && s.pid !== originalPid && isProcessAlive(s.pid)) {
3548
- killProcess(s.pid);
3549
- console.log(` killed pid ${s.pid}`);
3550
- }
3551
- // Kill associated botmux-owned tmux session if it exists. Adopted panes
3552
- // belong to the user and must be left untouched.
3553
- const tmuxName = `bmx-${s.sessionId.substring(0, 8)}`;
3554
- if (!isAdoptedSession(s)) {
3555
- try {
3556
- execSync(`tmux kill-session -t '${tmuxName}' 2>/dev/null`, { stdio: 'ignore', env: tmuxEnv() });
3557
- console.log(` killed tmux ${tmuxName}`);
3558
- }
3559
- catch { /* no tmux session */ }
3640
+ const result = await closeSessionForDelete(s, online);
3641
+ if (!result.ok) {
3642
+ console.error(`✗ ${s.sessionId.substring(0, 8)} ${s.title}: ${result.error}`);
3643
+ failed++;
3644
+ continue;
3560
3645
  }
3561
- // Mark session as closed
3562
- s.status = 'closed';
3563
- s.closedAt = new Date().toISOString();
3564
- saveSession(s);
3565
- console.log(`✓ ${s.sessionId.substring(0, 8)} ${s.title}`);
3646
+ closed++;
3647
+ if (result.via === 'offline')
3648
+ offline++;
3649
+ console.log(`✓ ${s.sessionId.substring(0, 8)} ${s.title}${result.via === 'offline' ? '(daemon 离线,本地收口)' : ''}`);
3566
3650
  }
3567
- console.log(`\n已关闭 ${toDelete.length} 个会话`);
3651
+ console.log(`\n已关闭 ${closed} 个会话${offline ? `(${offline} 个离线收口)` : ''}${failed ? `,${failed} 个失败` : ''}`);
3652
+ if (failed > 0)
3653
+ process.exitCode = 1;
3568
3654
  }
3569
3655
  /**
3570
3656
  * `botmux suspend` — 手动挂起活跃会话:杀掉 worker + CLI/pane,但会话保持
@@ -3674,7 +3760,7 @@ async function cmdSuspend() {
3674
3760
  if (failed > 0)
3675
3761
  process.exitCode = 1;
3676
3762
  }
3677
- /** 会话级 CLI IPC(slash/cd)的 POST:与 postAsk 同款双路径——能读 host secret
3763
+ /** 会话级 CLI IPC(slash/cd/close)的 POST:与 postAsk 同款双路径——能读 host secret
3678
3764
  * (非隔离进程)走 trusted-host HMAC 签名;读不到(沙箱 BOTMUX_SEND_RELAY /
3679
3765
  * macOS 读隔离 carve-out)改带本会话当前轮换的 origin capability,由 daemon
3680
3766
  * handler 与活跃记录比对。两条路都不读 bots.json。 */
@@ -3746,18 +3832,18 @@ async function cmdSlash() {
3746
3832
  console.error(`✗ 被拒绝: ${body?.error ?? `HTTP ${res.status}`}`);
3747
3833
  process.exit(1);
3748
3834
  }
3749
- /** botmux cd <角色目录>:请求 daemon 重钉本话题工作目录(角色切换)。
3750
- * daemon 侧校验目录必须在 ~/botmux-roles 下;Claude 家族 idle 注入 /cd 不重启,
3751
- * 其余 CLI 杀进程冷启动。协议要求本命令是该轮最后一个动作。 */
3752
- async function cmdCd() {
3753
- const argv = process.argv.slice(3);
3835
+ /** 角色切换(`botmux role switch <角色目录>`,唯一入口)。daemon 侧硬校验目录必须在
3836
+ * ~/botmux-roles 下。名字→目录的解析由调用方(模型读 _role-protocol.md)完成,本命令
3837
+ * 只透传解析出的目标目录。argv dispatch 传入 `process.argv.slice(4)`(跳过 `switch`
3838
+ * 子命令词)。 */
3839
+ async function cmdRoleSwitch(argv) {
3754
3840
  const sIdx = argv.indexOf('--session');
3755
3841
  const explicitSid = sIdx >= 0 ? argv[sIdx + 1] : undefined;
3756
3842
  // 所有非 flag 位置参数 join(' '),而不是只取第一个——路径含空格且未加引号时
3757
- // (如 `botmux cd ~/botmux-roles/我的 角色`)此前会被截断。
3843
+ // (如 `botmux role switch ~/botmux-roles/我的 角色`)此前会被截断。
3758
3844
  const dir = argv.filter((a, i) => !a.startsWith('--') && !(sIdx >= 0 && i === sIdx + 1)).join(' ');
3759
3845
  if (!dir) {
3760
- console.error('用法: botmux cd <目标目录(含空格建议加引号)> [--session <id>]');
3846
+ console.error(`用法: botmux role switch <目标角色目录(含空格建议加引号)> [--session <id>]`);
3761
3847
  process.exit(1);
3762
3848
  }
3763
3849
  const ctx = explicitSid ? null : findAncestorSessionContext();
@@ -3780,9 +3866,11 @@ async function cmdCd() {
3780
3866
  const res = await postSessionCliIpc(daemon.ipcPort, s.sessionId, 'cd', { dir });
3781
3867
  const body = await res.json().catch(() => ({}));
3782
3868
  if (res.ok && body?.ok) {
3783
- console.log(body.mode === 'inject'
3784
- ? `✓ 已切换到 ${body.dir}(会话空闲时生效,进程不重启)`
3785
- : `✓ 已切换到 ${body.dir}(下条消息在新目录冷启动)`);
3869
+ console.log(body.mode === 'respawn-resume'
3870
+ ? `✓ 已切换到 ${body.dir}(进程即将在新目录重启并续回上下文)`
3871
+ : body.mode === 'inject' // 兼容旧 daemon 的注入模式
3872
+ ? `✓ 已切换到 ${body.dir}(会话空闲时生效,进程不重启)`
3873
+ : `✓ 已切换到 ${body.dir}(下条消息在新目录冷启动)`);
3786
3874
  return;
3787
3875
  }
3788
3876
  console.error(`✗ 切换被拒绝: ${body?.error ?? `HTTP ${res.status}`}`);
@@ -4396,7 +4484,7 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
4396
4484
  --isolated 挂起所有读隔离 bot(凭证轮换后用;下次冷启动自动同步最新凭证)
4397
4485
  --dry-run 只列出目标,不执行
4398
4486
  slash "<斜杠命令>" 会话空闲后向本会话 CLI 注入一条原生斜杠命令(需 bots.json 配 tuiSlashAllow;/cd 恒被拒)
4399
- cd <目录> (会话内)切换本话题工作目录到角色库内的目录——角色切换用;
4487
+ role switch <目录> (会话内)切换本话题到角色库内的角色目录——角色切换用;
4400
4488
  目录必须位于 ~/botmux-roles 之下
4401
4489
  term-link [id] 获取活跃会话的「可操作终端」(带写 token)。不回显链接,改由
4402
4490
  daemon 把可操作卡片私密发给 owner(群内仅你可见,话题/单聊回退 DM)。
@@ -4481,6 +4569,10 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
4481
4569
  skill show <name> 读取某技能的完整 SKILL.md 说明(prompt 注入模式下按需拉取内置技能全文)
4482
4570
 
4483
4571
  编排 / workflow(v3):
4572
+ goal run <goal> [--run-id <id>] [--bot <id|name>] [--working-dir <dir>]
4573
+ [--timeout <seconds>] [--json]
4574
+ 在现有 v3 沙箱/worker 路径运行一个 headless goal;
4575
+ 同一 run-id 可安全重放终态或接续崩溃运行
4484
4576
  workflow save [last|runId] [名称]
4485
4577
  把成功 run 固化为 chat scope Saved Workflow;
4486
4578
  发布当前 Bot 全局版本 / 确认 unsafe lint 请由用户在飞书显式发送 /workflow save ...
@@ -4894,8 +4986,41 @@ async function cmdSchedule(sub, rest) {
4894
4986
  process.env.SESSION_DATA_DIR ??= resolveDataDir();
4895
4987
  const scheduler = await import('./core/scheduler.js');
4896
4988
  const scheduleStore = await import('./services/schedule-store.js');
4989
+ // Per-bot stores: bind this invocation to one bot's store — explicit
4990
+ // --lark-app-id wins, else the surrounding session's bot (env/marker-derived;
4991
+ // always present inside sandboxed sessions). A bare terminal without either
4992
+ // binds to the primary bot (bots.json[0]) so mutations keep the legacy
4993
+ // "ownerless task runs on bot-0" semantics; `list` without a bound bot
4994
+ // aggregates every readable store instead.
4995
+ const cliScopeAppId = argValue(rest, '--lark-app-id')
4996
+ ?? detectCurrentSession()?.larkAppId
4997
+ ?? process.env.BOTMUX_LARK_APP_ID;
4998
+ // LAZY + sandbox-safe bots.json read: sandboxed sessions always carry a
4999
+ // scope (env-injected appId) and must never touch bots.json — it is denied
5000
+ // and `loadBotsJson()` process.exit(1)s on the read error. Only the bare
5001
+ // unsandboxed terminal (aggregate list / cross-store id lookup) reads it,
5002
+ // and even then failure degrades to "no other stores visible".
5003
+ const allBotAppIds = () => {
5004
+ try {
5005
+ return parseBotConfigsJson(readFileSync(BOTS_JSON_FILE, 'utf-8'), BOTS_JSON_FILE)
5006
+ .map((b) => b?.larkAppId)
5007
+ .filter((x) => typeof x === 'string');
5008
+ }
5009
+ catch {
5010
+ return [];
5011
+ } // absent OR sandbox-denied → own scope only
5012
+ };
5013
+ if (cliScopeAppId)
5014
+ scheduleStore.setScheduleScope(cliScopeAppId);
5015
+ else {
5016
+ const first = allBotAppIds()[0];
5017
+ if (first)
5018
+ scheduleStore.setScheduleScope(first);
5019
+ }
4897
5020
  if (!sub || sub === 'list' || sub === 'ls') {
4898
- const tasks = scheduleStore.listTasks();
5021
+ const tasks = cliScopeAppId
5022
+ ? scheduleStore.listTasks()
5023
+ : scheduleStore.listTasksForBots(allBotAppIds());
4899
5024
  if (tasks.length === 0) {
4900
5025
  console.log('暂无定时任务。\n\n用法:\n botmux schedule add "每日17:50" "帮我看AI新闻"\n botmux schedule add "every 2h" "检查构建"\n botmux schedule add "0 9 * * *" "每天早安"');
4901
5026
  return;
@@ -4936,7 +5061,12 @@ async function cmdSchedule(sub, rest) {
4936
5061
  const explicitRootMessageId = argValue(rest, '--root-msg-id');
4937
5062
  const rootMessageId = explicitRootMessageId
4938
5063
  ?? (chatId && chatId === cur?.chatId ? cur.rootMessageId : undefined);
4939
- const larkAppId = argValue(rest, '--lark-app-id') ?? cur?.larkAppId;
5064
+ // Owner resolution mirrors the store-scope resolution above (flag →
5065
+ // session marker → daemon-injected env): a sandboxed session without a
5066
+ // readable marker must still stamp its own bot as owner, or the task
5067
+ // would land in this bot's store as OWNERLESS — which only the primary
5068
+ // daemon executes — and never fire (codex review P1).
5069
+ const larkAppId = cliScopeAppId;
4940
5070
  const workingDir = argValue(rest, '--workdir') ?? cur?.workingDir ?? process.cwd();
4941
5071
  const name = argValue(rest, '--name') ?? (promptArg.length > 20 ? promptArg.slice(0, 20) + '…' : promptArg);
4942
5072
  const legacyDeliver = argValue(rest, '--deliver');
@@ -4985,25 +5115,37 @@ async function cmdSchedule(sub, rest) {
4985
5115
  console.error(`无法解析 schedule "${rawSchedule}": ${err.message}`);
4986
5116
  process.exit(1);
4987
5117
  }
4988
- const task = scheduler.addTask({
4989
- name,
4990
- schedule: rawSchedule,
4991
- parsed,
4992
- prompt: promptArg,
4993
- workingDir,
4994
- chatId,
4995
- rootMessageId,
4996
- larkAppId,
4997
- creatorChatId: cur?.chatId,
4998
- creatorRootMessageId: cur?.rootMessageId,
4999
- creatorLarkAppId: cur?.larkAppId,
5000
- chatType: cur?.chatType === 'p2p' ? 'p2p' : 'topic_group',
5001
- scope,
5002
- executionPosition,
5003
- topicTitle,
5004
- deliver,
5005
- silent,
5006
- });
5118
+ let task;
5119
+ try {
5120
+ task = scheduler.addTask({
5121
+ name,
5122
+ schedule: rawSchedule,
5123
+ parsed,
5124
+ prompt: promptArg,
5125
+ workingDir,
5126
+ chatId,
5127
+ rootMessageId,
5128
+ larkAppId,
5129
+ creatorChatId: cur?.chatId,
5130
+ creatorRootMessageId: cur?.rootMessageId,
5131
+ creatorLarkAppId: cur?.larkAppId,
5132
+ chatType: cur?.chatType === 'p2p' ? 'p2p' : 'topic_group',
5133
+ scope,
5134
+ executionPosition,
5135
+ topicTitle,
5136
+ deliver,
5137
+ silent,
5138
+ });
5139
+ }
5140
+ catch (err) {
5141
+ // Sandboxed sessions can only write their OWN bot's store — a cross-bot
5142
+ // `--lark-app-id` (or a scope pointing at another bot) fails closed here.
5143
+ if (/EPERM|EACCES|not permitted/i.test(String(err))) {
5144
+ console.error(`无法写入目标 bot 的定时任务存储(${larkAppId ?? '未指定'}):沙盒会话只能管理自己 bot 的任务。`);
5145
+ process.exit(1);
5146
+ }
5147
+ throw err;
5148
+ }
5007
5149
  const next = task.nextRunAt ? new Date(task.nextRunAt).toLocaleString('zh-CN', { timeZone: scheduleTimeZone() }) : '—';
5008
5150
  console.log(`✅ 已创建定时任务 [${task.id}] ${task.name}`);
5009
5151
  console.log(` 规则: ${parsed.display}`);
@@ -5021,41 +5163,67 @@ async function cmdSchedule(sub, rest) {
5021
5163
  console.error(`用法: botmux schedule ${sub} <id>`);
5022
5164
  process.exit(1);
5023
5165
  }
5166
+ // Id-addressed op missed the bound store: locate the id across every
5167
+ // READABLE bot store (bare-terminal admin usage) and rebind the scope to the
5168
+ // owning bot for this one-shot process. Sandboxed callers cannot read
5169
+ // sibling stores, so they stay confined to their own tasks by construction.
5170
+ const retargetIfElsewhere = () => {
5171
+ const hit = scheduleStore.findTaskAcrossBots(id, allBotAppIds());
5172
+ if (!hit || hit.appId === scheduleStore.getScheduleScope())
5173
+ return false;
5174
+ scheduleStore.setScheduleScope(hit.appId);
5175
+ console.log(`(任务属于 bot ${hit.appId} 的存储)`);
5176
+ return true;
5177
+ };
5024
5178
  switch (sub) {
5025
5179
  case 'remove':
5026
5180
  case 'rm':
5027
5181
  case 'delete':
5028
- case 'del':
5029
- if (scheduler.removeTask(id))
5182
+ case 'del': {
5183
+ let ok = scheduler.removeTask(id);
5184
+ if (!ok && retargetIfElsewhere())
5185
+ ok = scheduler.removeTask(id);
5186
+ if (ok)
5030
5187
  console.log(`已删除任务 ${id}`);
5031
5188
  else {
5032
5189
  console.error(`未找到任务 ${id}`);
5033
5190
  process.exit(1);
5034
5191
  }
5035
5192
  break;
5193
+ }
5036
5194
  case 'pause':
5037
- case 'disable':
5038
- if (scheduler.disableTask(id))
5195
+ case 'disable': {
5196
+ let ok = scheduler.disableTask(id);
5197
+ if (!ok && retargetIfElsewhere())
5198
+ ok = scheduler.disableTask(id);
5199
+ if (ok)
5039
5200
  console.log(`已暂停任务 ${id}`);
5040
5201
  else {
5041
5202
  console.error(`未找到任务 ${id}`);
5042
5203
  process.exit(1);
5043
5204
  }
5044
5205
  break;
5206
+ }
5045
5207
  case 'resume':
5046
- case 'enable':
5047
- if (scheduler.enableTask(id))
5208
+ case 'enable': {
5209
+ let ok = scheduler.enableTask(id);
5210
+ if (!ok && retargetIfElsewhere())
5211
+ ok = scheduler.enableTask(id);
5212
+ if (ok)
5048
5213
  console.log(`已恢复任务 ${id}`);
5049
5214
  else {
5050
5215
  console.error(`未找到任务 ${id}`);
5051
5216
  process.exit(1);
5052
5217
  }
5053
5218
  break;
5219
+ }
5054
5220
  case 'run':
5055
5221
  // Running requires the daemon (executeCallback is daemon-side).
5056
5222
  // CLI can only mark a task to run ASAP; daemon's next tick picks it up.
5057
5223
  {
5058
- const task = scheduleStore.getTask(id);
5224
+ let task = scheduleStore.getTask(id);
5225
+ if (!task && retargetIfElsewhere())
5226
+ task = scheduleStore.getTask(id);
5059
5227
  if (!task) {
5060
5228
  console.error(`未找到任务 ${id}`);
5061
5229
  process.exit(1);
@@ -9383,7 +9551,7 @@ switch (command) {
9383
9551
  case 'delete':
9384
9552
  case 'del':
9385
9553
  case 'rm':
9386
- cmdDelete();
9554
+ await cmdDelete();
9387
9555
  break;
9388
9556
  case 'resume':
9389
9557
  await cmdResume();
@@ -9394,9 +9562,29 @@ switch (command) {
9394
9562
  case 'slash':
9395
9563
  await cmdSlash();
9396
9564
  break;
9397
- case 'cd':
9398
- await cmdCd();
9565
+ case 'cd': {
9566
+ // Tombstone for the removed `botmux cd`(改名为 `botmux role switch`)。**必须
9567
+ // fail-loud**:存量部署里 _role-protocol.md 若还没刷新、模型仍发 `botmux cd`,
9568
+ // 静默 exit 0 会让它以为切换成功(实际什么都没做)——「假切换成功」比明确报错
9569
+ // 危险得多。所以这里打印迁移提示、退 1、绝不执行任何切换。
9570
+ console.error('✗ `botmux cd` 已移除,改用 `botmux role switch <角色目录>`(同一切换语义)。');
9571
+ console.error(' 本次未执行任何切换。若你是角色协议(_role-protocol.md)触发的,请把命令刷新为 `botmux role switch`。');
9572
+ process.exit(1);
9573
+ break;
9574
+ }
9575
+ case 'role': {
9576
+ // `botmux role switch <角色目录>` — 角色切换(唯一入口)。名字→目录的解析由
9577
+ // 调用方(模型读 _role-protocol.md)完成,本命令只透传解析出的目标目录,daemon
9578
+ // 侧硬校验目录必须在 ~/botmux-roles 下。
9579
+ const sub = process.argv[3] ?? '';
9580
+ if (sub === 'switch') {
9581
+ await cmdRoleSwitch(process.argv.slice(4));
9582
+ break;
9583
+ }
9584
+ console.error(`用法: botmux role switch <目标角色目录(含空格建议加引号)> [--session <id>]`);
9585
+ process.exit(1);
9399
9586
  break;
9587
+ }
9400
9588
  case 'term-link':
9401
9589
  await cmdTermLink(process.argv.slice(3));
9402
9590
  break;
@@ -9535,6 +9723,11 @@ switch (command) {
9535
9723
  await cmdV3(process.argv[3] ?? '', process.argv.slice(4));
9536
9724
  break;
9537
9725
  }
9726
+ case 'goal': {
9727
+ const { cmdGoal } = await import('./workflows/v3/goal-cli.js');
9728
+ process.exitCode = await cmdGoal(process.argv[3] ?? '', process.argv.slice(4));
9729
+ break;
9730
+ }
9538
9731
  case 'send':
9539
9732
  await cmdSend(process.argv.slice(3));
9540
9733
  break;