botmux 3.4.3 → 3.5.2

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 (415) hide show
  1. package/README.en.md +10 -7
  2. package/README.md +11 -6
  3. package/dist/adapters/backend/herdr-backend.d.ts +43 -6
  4. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  5. package/dist/adapters/backend/herdr-backend.js +362 -28
  6. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  7. package/dist/adapters/backend/reproduce-command.d.ts +39 -0
  8. package/dist/adapters/backend/reproduce-command.d.ts.map +1 -0
  9. package/dist/adapters/backend/reproduce-command.js +63 -0
  10. package/dist/adapters/backend/reproduce-command.js.map +1 -0
  11. package/dist/adapters/backend/sandbox.d.ts +99 -279
  12. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  13. package/dist/adapters/backend/sandbox.js +424 -826
  14. package/dist/adapters/backend/sandbox.js.map +1 -1
  15. package/dist/adapters/backend/session-backend-selector.d.ts +10 -1
  16. package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -1
  17. package/dist/adapters/backend/session-backend-selector.js +73 -4
  18. package/dist/adapters/backend/session-backend-selector.js.map +1 -1
  19. package/dist/adapters/backend/types.d.ts +16 -0
  20. package/dist/adapters/backend/types.d.ts.map +1 -1
  21. package/dist/adapters/backend/types.js.map +1 -1
  22. package/dist/adapters/cli/codex.d.ts.map +1 -1
  23. package/dist/adapters/cli/codex.js +4 -0
  24. package/dist/adapters/cli/codex.js.map +1 -1
  25. package/dist/adapters/cli/fs-policy.d.ts +244 -0
  26. package/dist/adapters/cli/fs-policy.d.ts.map +1 -0
  27. package/dist/adapters/cli/fs-policy.js +539 -0
  28. package/dist/adapters/cli/fs-policy.js.map +1 -0
  29. package/dist/adapters/cli/pi-initial-prompt.d.ts.map +1 -1
  30. package/dist/adapters/cli/pi-initial-prompt.js +5 -1
  31. package/dist/adapters/cli/pi-initial-prompt.js.map +1 -1
  32. package/dist/adapters/cli/read-isolation.d.ts +14 -200
  33. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  34. package/dist/adapters/cli/read-isolation.js +18 -477
  35. package/dist/adapters/cli/read-isolation.js.map +1 -1
  36. package/dist/adapters/cli/traex.d.ts.map +1 -1
  37. package/dist/adapters/cli/traex.js +5 -0
  38. package/dist/adapters/cli/traex.js.map +1 -1
  39. package/dist/adapters/cli/types.d.ts +3 -3
  40. package/dist/adapters/cli/types.d.ts.map +1 -1
  41. package/dist/adapters/hook-installer.d.ts +7 -0
  42. package/dist/adapters/hook-installer.d.ts.map +1 -1
  43. package/dist/adapters/hook-installer.js +56 -0
  44. package/dist/adapters/hook-installer.js.map +1 -1
  45. package/dist/bot-registry.d.ts +39 -23
  46. package/dist/bot-registry.d.ts.map +1 -1
  47. package/dist/bot-registry.js +134 -2
  48. package/dist/bot-registry.js.map +1 -1
  49. package/dist/cli/capabilities.d.ts +24 -0
  50. package/dist/cli/capabilities.d.ts.map +1 -0
  51. package/dist/cli/capabilities.js +25 -0
  52. package/dist/cli/capabilities.js.map +1 -0
  53. package/dist/cli/create-group-resolver.d.ts +24 -0
  54. package/dist/cli/create-group-resolver.d.ts.map +1 -1
  55. package/dist/cli/create-group-resolver.js +23 -0
  56. package/dist/cli/create-group-resolver.js.map +1 -1
  57. package/dist/cli/daemon-lifecycle-env.d.ts +5 -7
  58. package/dist/cli/daemon-lifecycle-env.d.ts.map +1 -1
  59. package/dist/cli/daemon-lifecycle-env.js +13 -7
  60. package/dist/cli/daemon-lifecycle-env.js.map +1 -1
  61. package/dist/cli/exact-chat-grant-client.d.ts +48 -0
  62. package/dist/cli/exact-chat-grant-client.d.ts.map +1 -0
  63. package/dist/cli/exact-chat-grant-client.js +108 -0
  64. package/dist/cli/exact-chat-grant-client.js.map +1 -0
  65. package/dist/cli/exact-chat-grant.d.ts +18 -0
  66. package/dist/cli/exact-chat-grant.d.ts.map +1 -0
  67. package/dist/cli/exact-chat-grant.js +97 -0
  68. package/dist/cli/exact-chat-grant.js.map +1 -0
  69. package/dist/cli.d.ts +10 -1
  70. package/dist/cli.d.ts.map +1 -1
  71. package/dist/cli.js +795 -144
  72. package/dist/cli.js.map +1 -1
  73. package/dist/codex-rpc-engine.d.ts +26 -0
  74. package/dist/codex-rpc-engine.d.ts.map +1 -1
  75. package/dist/codex-rpc-engine.js +113 -2
  76. package/dist/codex-rpc-engine.js.map +1 -1
  77. package/dist/config.d.ts +16 -0
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/config.js +16 -0
  80. package/dist/config.js.map +1 -1
  81. package/dist/core/bot-live-control.d.ts +41 -0
  82. package/dist/core/bot-live-control.d.ts.map +1 -0
  83. package/dist/core/bot-live-control.js +135 -0
  84. package/dist/core/bot-live-control.js.map +1 -0
  85. package/dist/core/command-handler.d.ts.map +1 -1
  86. package/dist/core/command-handler.js +44 -66
  87. package/dist/core/command-handler.js.map +1 -1
  88. package/dist/core/daemon-config-fence.d.ts +8 -0
  89. package/dist/core/daemon-config-fence.d.ts.map +1 -0
  90. package/dist/core/daemon-config-fence.js +13 -0
  91. package/dist/core/daemon-config-fence.js.map +1 -0
  92. package/dist/core/dashboard-events.d.ts +5 -0
  93. package/dist/core/dashboard-events.d.ts.map +1 -1
  94. package/dist/core/dashboard-events.js.map +1 -1
  95. package/dist/core/dashboard-ipc-server.d.ts +21 -2
  96. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  97. package/dist/core/dashboard-ipc-server.js +258 -32
  98. package/dist/core/dashboard-ipc-server.js.map +1 -1
  99. package/dist/core/dispatch-registry.d.ts +12 -0
  100. package/dist/core/dispatch-registry.d.ts.map +1 -0
  101. package/dist/core/dispatch-registry.js +33 -0
  102. package/dist/core/dispatch-registry.js.map +1 -0
  103. package/dist/core/dispatch.d.ts +99 -0
  104. package/dist/core/dispatch.d.ts.map +1 -1
  105. package/dist/core/dispatch.js +136 -0
  106. package/dist/core/dispatch.js.map +1 -1
  107. package/dist/core/maintenance.d.ts.map +1 -1
  108. package/dist/core/maintenance.js +10 -3
  109. package/dist/core/maintenance.js.map +1 -1
  110. package/dist/core/passthrough-commands.d.ts.map +1 -1
  111. package/dist/core/passthrough-commands.js +1 -1
  112. package/dist/core/passthrough-commands.js.map +1 -1
  113. package/dist/core/persistent-backend.d.ts +16 -2
  114. package/dist/core/persistent-backend.d.ts.map +1 -1
  115. package/dist/core/persistent-backend.js +40 -0
  116. package/dist/core/persistent-backend.js.map +1 -1
  117. package/dist/core/plugins/mcp/gateway-installer.d.ts.map +1 -1
  118. package/dist/core/plugins/mcp/gateway-installer.js +14 -2
  119. package/dist/core/plugins/mcp/gateway-installer.js.map +1 -1
  120. package/dist/core/session-discovery.d.ts +8 -1
  121. package/dist/core/session-discovery.d.ts.map +1 -1
  122. package/dist/core/session-discovery.js +140 -8
  123. package/dist/core/session-discovery.js.map +1 -1
  124. package/dist/core/session-manager.d.ts.map +1 -1
  125. package/dist/core/session-manager.js +102 -68
  126. package/dist/core/session-manager.js.map +1 -1
  127. package/dist/core/session-title.d.ts +8 -0
  128. package/dist/core/session-title.d.ts.map +1 -1
  129. package/dist/core/session-title.js +54 -0
  130. package/dist/core/session-title.js.map +1 -1
  131. package/dist/core/terminal-write-auth.d.ts +15 -0
  132. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  133. package/dist/core/terminal-write-auth.js +20 -0
  134. package/dist/core/terminal-write-auth.js.map +1 -1
  135. package/dist/core/trigger-session.d.ts.map +1 -1
  136. package/dist/core/trigger-session.js +3 -2
  137. package/dist/core/trigger-session.js.map +1 -1
  138. package/dist/core/types.d.ts +33 -0
  139. package/dist/core/types.d.ts.map +1 -1
  140. package/dist/core/types.js.map +1 -1
  141. package/dist/core/worker-pool.d.ts +51 -8
  142. package/dist/core/worker-pool.d.ts.map +1 -1
  143. package/dist/core/worker-pool.js +439 -25
  144. package/dist/core/worker-pool.js.map +1 -1
  145. package/dist/daemon.d.ts +4 -2
  146. package/dist/daemon.d.ts.map +1 -1
  147. package/dist/daemon.js +403 -26
  148. package/dist/daemon.js.map +1 -1
  149. package/dist/dashboard/bot-onboarding.d.ts +127 -1
  150. package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
  151. package/dist/dashboard/bot-onboarding.js +1104 -25
  152. package/dist/dashboard/bot-onboarding.js.map +1 -1
  153. package/dist/dashboard/bot-payload.d.ts +5 -0
  154. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  155. package/dist/dashboard/bot-payload.js +7 -0
  156. package/dist/dashboard/bot-payload.js.map +1 -1
  157. package/dist/dashboard/debug-terminal.d.ts +18 -0
  158. package/dist/dashboard/debug-terminal.d.ts.map +1 -0
  159. package/dist/dashboard/debug-terminal.js +338 -0
  160. package/dist/dashboard/debug-terminal.js.map +1 -0
  161. package/dist/dashboard/public-redact.d.ts +2 -0
  162. package/dist/dashboard/public-redact.d.ts.map +1 -1
  163. package/dist/dashboard/public-redact.js +12 -3
  164. package/dist/dashboard/public-redact.js.map +1 -1
  165. package/dist/dashboard/registry.d.ts +8 -0
  166. package/dist/dashboard/registry.d.ts.map +1 -1
  167. package/dist/dashboard/registry.js +13 -0
  168. package/dist/dashboard/registry.js.map +1 -1
  169. package/dist/dashboard/settings-write-applier.d.ts +47 -1
  170. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  171. package/dist/dashboard/settings-write-applier.js +102 -1
  172. package/dist/dashboard/settings-write-applier.js.map +1 -1
  173. package/dist/dashboard/web/app.d.ts.map +1 -1
  174. package/dist/dashboard/web/app.js +2 -0
  175. package/dist/dashboard/web/app.js.map +1 -1
  176. package/dist/dashboard/web/bot-defaults-page.d.ts +17 -0
  177. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  178. package/dist/dashboard/web/bot-defaults-page.js +249 -11
  179. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  180. package/dist/dashboard/web/bot-defaults.d.ts +22 -0
  181. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  182. package/dist/dashboard/web/bot-defaults.js +19 -0
  183. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  184. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  185. package/dist/dashboard/web/i18n.js +114 -28
  186. package/dist/dashboard/web/i18n.js.map +1 -1
  187. package/dist/dashboard/web/icon-tooltip.d.ts +3 -0
  188. package/dist/dashboard/web/icon-tooltip.d.ts.map +1 -0
  189. package/dist/dashboard/web/icon-tooltip.js +108 -0
  190. package/dist/dashboard/web/icon-tooltip.js.map +1 -0
  191. package/dist/dashboard/web/sessions-kanban.js +2 -2
  192. package/dist/dashboard/web/sessions-kanban.js.map +1 -1
  193. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  194. package/dist/dashboard/web/sessions-page.js +49 -53
  195. package/dist/dashboard/web/sessions-page.js.map +1 -1
  196. package/dist/dashboard/web/sessions.d.ts +2 -0
  197. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  198. package/dist/dashboard/web/sessions.js +46 -2
  199. package/dist/dashboard/web/sessions.js.map +1 -1
  200. package/dist/dashboard/web/settings-page.d.ts +78 -0
  201. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  202. package/dist/dashboard/web/settings-page.js +88 -1
  203. package/dist/dashboard/web/settings-page.js.map +1 -1
  204. package/dist/dashboard/web/store.d.ts +2 -0
  205. package/dist/dashboard/web/store.d.ts.map +1 -1
  206. package/dist/dashboard/web/store.js +13 -1
  207. package/dist/dashboard/web/store.js.map +1 -1
  208. package/dist/dashboard-web/app.js +1 -1
  209. package/dist/dashboard-web/chunks/bot-defaults-page-AUKV7P4L.js +10 -0
  210. package/dist/dashboard-web/chunks/{chunk-P6GO5KT4.js → chunk-KPQAUX7V.js} +1 -1
  211. package/dist/dashboard-web/chunks/{chunk-UBOLHQCK.js → chunk-NRL6CVAS.js} +1 -1
  212. package/dist/dashboard-web/chunks/{chunk-JNRSPKLS.js → chunk-R7IAKAYX.js} +1 -1
  213. package/dist/dashboard-web/chunks/{chunk-CUV65BIQ.js → chunk-X2L65IOM.js} +8 -8
  214. package/dist/dashboard-web/chunks/{connectors-page-KTC2QWNW.js → connectors-page-HDQFEXZI.js} +1 -1
  215. package/dist/dashboard-web/chunks/{groups-page-B3EKGOLY.js → groups-page-6DKXBYOM.js} +1 -1
  216. package/dist/dashboard-web/chunks/{insights-page-X6RXNCWX.js → insights-page-NWARTJ6J.js} +1 -1
  217. package/dist/dashboard-web/chunks/{monitor-room-LLRA5LQW.js → monitor-room-AGX3XRJX.js} +1 -1
  218. package/dist/dashboard-web/chunks/{monitoring-page-7MT5FEOS.js → monitoring-page-GGGIWN4C.js} +1 -1
  219. package/dist/dashboard-web/chunks/{office-page-KD46D5TD.js → office-page-6SIVKSK3.js} +1 -1
  220. package/dist/dashboard-web/chunks/{overview-page-JUWNH32O.js → overview-page-FVR3NKAF.js} +1 -1
  221. package/dist/dashboard-web/chunks/{roles-page-P6F7NLOI.js → roles-page-WE2YB7KN.js} +1 -1
  222. package/dist/dashboard-web/chunks/{schedules-page-XIHWZST4.js → schedules-page-TB3I24XN.js} +1 -1
  223. package/dist/dashboard-web/chunks/sessions-page-KOOOASIL.js +2 -0
  224. package/dist/dashboard-web/chunks/settings-page-IEBR7TGN.js +2 -0
  225. package/dist/dashboard-web/chunks/{skills-page-A46KVWBL.js → skills-page-3QAT2IWD.js} +1 -1
  226. package/dist/dashboard-web/chunks/{team-federation-page-SDUC56DF.js → team-federation-page-K4VVAVAK.js} +1 -1
  227. package/dist/dashboard-web/chunks/{v3-page-J5JOTUSQ.js → v3-page-V6IOJR2B.js} +1 -1
  228. package/dist/dashboard-web/chunks/{whiteboards-page-U7LSOAWI.js → whiteboards-page-V6CGKRNX.js} +1 -1
  229. package/dist/dashboard-web/style.css +218 -10
  230. package/dist/dashboard.js +380 -8
  231. package/dist/dashboard.js.map +1 -1
  232. package/dist/features/codex-notifier/adoption.d.ts +11 -0
  233. package/dist/features/codex-notifier/adoption.d.ts.map +1 -0
  234. package/dist/features/codex-notifier/adoption.js +11 -0
  235. package/dist/features/codex-notifier/adoption.js.map +1 -0
  236. package/dist/features/codex-notifier/app-opener.d.ts +21 -0
  237. package/dist/features/codex-notifier/app-opener.d.ts.map +1 -0
  238. package/dist/features/codex-notifier/app-opener.js +33 -0
  239. package/dist/features/codex-notifier/app-opener.js.map +1 -0
  240. package/dist/features/codex-notifier/card-action.d.ts +27 -0
  241. package/dist/features/codex-notifier/card-action.d.ts.map +1 -0
  242. package/dist/features/codex-notifier/card-action.js +84 -0
  243. package/dist/features/codex-notifier/card-action.js.map +1 -0
  244. package/dist/features/codex-notifier/card.d.ts +12 -0
  245. package/dist/features/codex-notifier/card.d.ts.map +1 -0
  246. package/dist/features/codex-notifier/card.js +150 -0
  247. package/dist/features/codex-notifier/card.js.map +1 -0
  248. package/dist/features/codex-notifier/codex-context.d.ts +12 -0
  249. package/dist/features/codex-notifier/codex-context.d.ts.map +1 -0
  250. package/dist/features/codex-notifier/codex-context.js +161 -0
  251. package/dist/features/codex-notifier/codex-context.js.map +1 -0
  252. package/dist/features/codex-notifier/config.d.ts +9 -0
  253. package/dist/features/codex-notifier/config.d.ts.map +1 -0
  254. package/dist/features/codex-notifier/config.js +11 -0
  255. package/dist/features/codex-notifier/config.js.map +1 -0
  256. package/dist/features/codex-notifier/confirmed-turn.d.ts +20 -0
  257. package/dist/features/codex-notifier/confirmed-turn.d.ts.map +1 -0
  258. package/dist/features/codex-notifier/confirmed-turn.js +130 -0
  259. package/dist/features/codex-notifier/confirmed-turn.js.map +1 -0
  260. package/dist/features/codex-notifier/emitter.d.ts +13 -0
  261. package/dist/features/codex-notifier/emitter.d.ts.map +1 -0
  262. package/dist/features/codex-notifier/emitter.js +33 -0
  263. package/dist/features/codex-notifier/emitter.js.map +1 -0
  264. package/dist/features/codex-notifier/event-store.d.ts +29 -0
  265. package/dist/features/codex-notifier/event-store.d.ts.map +1 -0
  266. package/dist/features/codex-notifier/event-store.js +217 -0
  267. package/dist/features/codex-notifier/event-store.js.map +1 -0
  268. package/dist/features/codex-notifier/event.d.ts +46 -0
  269. package/dist/features/codex-notifier/event.d.ts.map +1 -0
  270. package/dist/features/codex-notifier/event.js +188 -0
  271. package/dist/features/codex-notifier/event.js.map +1 -0
  272. package/dist/features/codex-notifier/hook-cli.d.ts +23 -0
  273. package/dist/features/codex-notifier/hook-cli.d.ts.map +1 -0
  274. package/dist/features/codex-notifier/hook-cli.js +130 -0
  275. package/dist/features/codex-notifier/hook-cli.js.map +1 -0
  276. package/dist/features/codex-notifier/hook-installer.d.ts +19 -0
  277. package/dist/features/codex-notifier/hook-installer.d.ts.map +1 -0
  278. package/dist/features/codex-notifier/hook-installer.js +158 -0
  279. package/dist/features/codex-notifier/hook-installer.js.map +1 -0
  280. package/dist/features/codex-notifier/index.d.ts +21 -0
  281. package/dist/features/codex-notifier/index.d.ts.map +1 -0
  282. package/dist/features/codex-notifier/index.js +19 -0
  283. package/dist/features/codex-notifier/index.js.map +1 -0
  284. package/dist/features/codex-notifier/internal-turn.d.ts +5 -0
  285. package/dist/features/codex-notifier/internal-turn.d.ts.map +1 -0
  286. package/dist/features/codex-notifier/internal-turn.js +43 -0
  287. package/dist/features/codex-notifier/internal-turn.js.map +1 -0
  288. package/dist/features/codex-notifier/outbox-worker.d.ts +71 -0
  289. package/dist/features/codex-notifier/outbox-worker.d.ts.map +1 -0
  290. package/dist/features/codex-notifier/outbox-worker.js +290 -0
  291. package/dist/features/codex-notifier/outbox-worker.js.map +1 -0
  292. package/dist/features/codex-notifier/outbox.d.ts +25 -0
  293. package/dist/features/codex-notifier/outbox.d.ts.map +1 -0
  294. package/dist/features/codex-notifier/outbox.js +225 -0
  295. package/dist/features/codex-notifier/outbox.js.map +1 -0
  296. package/dist/features/codex-notifier/paths.d.ts +7 -0
  297. package/dist/features/codex-notifier/paths.d.ts.map +1 -0
  298. package/dist/features/codex-notifier/paths.js +20 -0
  299. package/dist/features/codex-notifier/paths.js.map +1 -0
  300. package/dist/features/codex-notifier/screen-lock.d.ts +12 -0
  301. package/dist/features/codex-notifier/screen-lock.d.ts.map +1 -0
  302. package/dist/features/codex-notifier/screen-lock.js +47 -0
  303. package/dist/features/codex-notifier/screen-lock.js.map +1 -0
  304. package/dist/features/codex-notifier/side-conversation-monitor.d.ts +102 -0
  305. package/dist/features/codex-notifier/side-conversation-monitor.d.ts.map +1 -0
  306. package/dist/features/codex-notifier/side-conversation-monitor.js +774 -0
  307. package/dist/features/codex-notifier/side-conversation-monitor.js.map +1 -0
  308. package/dist/features/codex-notifier/types.d.ts +42 -0
  309. package/dist/features/codex-notifier/types.d.ts.map +1 -0
  310. package/dist/features/codex-notifier/types.js +2 -0
  311. package/dist/features/codex-notifier/types.js.map +1 -0
  312. package/dist/features/codex-notifier/worker-lock.d.ts +8 -0
  313. package/dist/features/codex-notifier/worker-lock.d.ts.map +1 -0
  314. package/dist/features/codex-notifier/worker-lock.js +108 -0
  315. package/dist/features/codex-notifier/worker-lock.js.map +1 -0
  316. package/dist/global-config.d.ts +13 -0
  317. package/dist/global-config.d.ts.map +1 -1
  318. package/dist/global-config.js +34 -1
  319. package/dist/global-config.js.map +1 -1
  320. package/dist/i18n/en.d.ts.map +1 -1
  321. package/dist/i18n/en.js +1 -19
  322. package/dist/i18n/en.js.map +1 -1
  323. package/dist/i18n/zh.d.ts.map +1 -1
  324. package/dist/i18n/zh.js +1 -19
  325. package/dist/i18n/zh.js.map +1 -1
  326. package/dist/im/lark/card-builder.d.ts +0 -13
  327. package/dist/im/lark/card-builder.d.ts.map +1 -1
  328. package/dist/im/lark/card-builder.js +2 -36
  329. package/dist/im/lark/card-builder.js.map +1 -1
  330. package/dist/im/lark/card-handler.d.ts +2 -0
  331. package/dist/im/lark/card-handler.d.ts.map +1 -1
  332. package/dist/im/lark/card-handler.js +166 -64
  333. package/dist/im/lark/card-handler.js.map +1 -1
  334. package/dist/im/lark/client.d.ts +98 -4
  335. package/dist/im/lark/client.d.ts.map +1 -1
  336. package/dist/im/lark/client.js +317 -29
  337. package/dist/im/lark/client.js.map +1 -1
  338. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  339. package/dist/im/lark/event-dispatcher.js +48 -33
  340. package/dist/im/lark/event-dispatcher.js.map +1 -1
  341. package/dist/services/codex-app-threads.d.ts +47 -0
  342. package/dist/services/codex-app-threads.d.ts.map +1 -1
  343. package/dist/services/codex-app-threads.js +502 -10
  344. package/dist/services/codex-app-threads.js.map +1 -1
  345. package/dist/services/exact-chat-grant.d.ts +83 -0
  346. package/dist/services/exact-chat-grant.d.ts.map +1 -0
  347. package/dist/services/exact-chat-grant.js +249 -0
  348. package/dist/services/exact-chat-grant.js.map +1 -0
  349. package/dist/services/group-creator.d.ts +11 -0
  350. package/dist/services/group-creator.d.ts.map +1 -1
  351. package/dist/services/group-creator.js +18 -9
  352. package/dist/services/group-creator.js.map +1 -1
  353. package/dist/services/local-cli-opener.d.ts.map +1 -1
  354. package/dist/services/local-cli-opener.js +10 -5
  355. package/dist/services/local-cli-opener.js.map +1 -1
  356. package/dist/services/sandbox-migration.d.ts +14 -0
  357. package/dist/services/sandbox-migration.d.ts.map +1 -0
  358. package/dist/services/sandbox-migration.js +85 -0
  359. package/dist/services/sandbox-migration.js.map +1 -0
  360. package/dist/services/sandbox-store.d.ts +28 -0
  361. package/dist/services/sandbox-store.d.ts.map +1 -1
  362. package/dist/services/sandbox-store.js +82 -0
  363. package/dist/services/sandbox-store.js.map +1 -1
  364. package/dist/services/traex-user-input.d.ts +19 -0
  365. package/dist/services/traex-user-input.d.ts.map +1 -0
  366. package/dist/services/traex-user-input.js +57 -0
  367. package/dist/services/traex-user-input.js.map +1 -0
  368. package/dist/setup/open-platform-automation.d.ts +24 -3
  369. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  370. package/dist/setup/open-platform-automation.js +45 -8
  371. package/dist/setup/open-platform-automation.js.map +1 -1
  372. package/dist/setup/verify-permissions.d.ts +18 -0
  373. package/dist/setup/verify-permissions.d.ts.map +1 -1
  374. package/dist/setup/verify-permissions.js +60 -0
  375. package/dist/setup/verify-permissions.js.map +1 -1
  376. package/dist/types.d.ts +83 -5
  377. package/dist/types.d.ts.map +1 -1
  378. package/dist/utils/child-env.d.ts +2 -2
  379. package/dist/utils/child-env.d.ts.map +1 -1
  380. package/dist/utils/child-env.js +14 -0
  381. package/dist/utils/child-env.js.map +1 -1
  382. package/dist/utils/stuck-detector.d.ts +45 -0
  383. package/dist/utils/stuck-detector.d.ts.map +1 -0
  384. package/dist/utils/stuck-detector.js +188 -0
  385. package/dist/utils/stuck-detector.js.map +1 -0
  386. package/dist/utils/stuck-key-guard.d.ts +75 -0
  387. package/dist/utils/stuck-key-guard.d.ts.map +1 -0
  388. package/dist/utils/stuck-key-guard.js +77 -0
  389. package/dist/utils/stuck-key-guard.js.map +1 -0
  390. package/dist/worker.js +1119 -588
  391. package/dist/worker.js.map +1 -1
  392. package/dist/workflows/events/payloads.d.ts +56 -0
  393. package/dist/workflows/events/payloads.d.ts.map +1 -1
  394. package/dist/workflows/events/payloads.js +9 -0
  395. package/dist/workflows/events/payloads.js.map +1 -1
  396. package/dist/workflows/events/schema.d.ts +86 -0
  397. package/dist/workflows/events/schema.d.ts.map +1 -1
  398. package/dist/workflows/shared/sandbox-policy.d.ts +10 -1
  399. package/dist/workflows/shared/sandbox-policy.d.ts.map +1 -1
  400. package/dist/workflows/shared/sandbox-policy.js +12 -0
  401. package/dist/workflows/shared/sandbox-policy.js.map +1 -1
  402. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
  403. package/dist/workflows/v3/bot-resolve.js +36 -0
  404. package/dist/workflows/v3/bot-resolve.js.map +1 -1
  405. package/dist/workflows/v3/contract.d.ts +8 -0
  406. package/dist/workflows/v3/contract.d.ts.map +1 -1
  407. package/dist/workflows/v3/contract.js.map +1 -1
  408. package/package.json +1 -1
  409. package/dist/dashboard-web/chunks/bot-defaults-page-B5AY4B2J.js +0 -5
  410. package/dist/dashboard-web/chunks/sessions-page-2VECQ27T.js +0 -3
  411. package/dist/dashboard-web/chunks/settings-page-HMIUE2JA.js +0 -2
  412. package/dist/services/sandbox-land.d.ts +0 -45
  413. package/dist/services/sandbox-land.d.ts.map +0 -1
  414. package/dist/services/sandbox-land.js +0 -394
  415. package/dist/services/sandbox-land.js.map +0 -1
package/dist/daemon.js CHANGED
@@ -8,20 +8,22 @@ import { fileURLToPath } from 'node:url';
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = dirname(__filename);
10
10
  import { config, getDashboardExternalHost, isVcMeetingAgentGloballyEnabled, vcMeetingAgentGlobalListenerBotAppId, } from './config.js';
11
- import { repoPickerScanOptions } from './global-config.js';
11
+ import { readGlobalConfig, repoPickerScanOptions } from './global-config.js';
12
12
  import { buildDashboardUrls } from './core/dashboard-url.js';
13
13
  import { resolveBotmuxDataDir } from './core/data-dir.js';
14
+ import { reloadExactDaemonBotConfig } from './core/daemon-config-fence.js';
14
15
  import { writeHeartbeat } from './core/daemon-heartbeat.js';
15
16
  import { botmuxWrapperFiles } from './core/botmux-wrapper.js';
16
17
  import { startMaintenance, stopMaintenance } from './core/maintenance.js';
17
18
  import { selectCodexRuntimeUpdateTargets, startCliRuntimeUpdateMonitor, stopCliRuntimeUpdateMonitor, } from './core/cli-runtime-update.js';
18
19
  import { sendRestartReportIfPending } from './core/restart-report.js';
19
20
  import { statSync } from 'node:fs';
20
- import { addReaction, getChatMode, getMessageChatId, listChatMemberOpenIds, MessageWithdrawnError, replyMessage, resolveAllowedUsersWithMap, sendMessage, sendUserMessage, updateMessage } from './im/lark/client.js';
21
+ import { addReaction, getChatMode, getChatNameAndMode, getMessageChatId, listChatMemberOpenIds, MessageWithdrawnError, replyMessage, resolveAllowedUsersWithMap, sendMessage, sendUserMessage, updateMessage } from './im/lark/client.js';
21
22
  import { resolveGroupJoinPrompt, waitForAllowedUserInChat } from './core/auto-start.js';
22
- import { loadBotConfigs, registerBot, getBot, getAllBots, getOwnerOpenId, findOncallChat, effectiveDefaultWorkingDir, effectiveBotDisplayName, resolveVcMeetingConsumerProfiles, } from './bot-registry.js';
23
+ import { loadBotConfigAtIndex, loadBotConfigs, isManagedActivationStartingAtIndex, registerBot, getBot, getAllBots, getOwnerOpenId, findOncallChat, effectiveDefaultWorkingDir, effectiveBotDisplayName, resolveVcMeetingConsumerProfiles, } from './bot-registry.js';
23
24
  import { setDisplayNameRefresher, findConfigField, applyConfigField } from './services/bot-config-store.js';
24
25
  import { renameBotOnOpenPlatform, changeBotAvatarOnOpenPlatform } from './services/open-platform-rename.js';
26
+ import { migrateSandboxConfigAtStartup } from './services/sandbox-migration.js';
25
27
  import * as sessionStore from './services/session-store.js';
26
28
  import * as chatFirstSeenStore from './services/chat-first-seen-store.js';
27
29
  import { ensureDefaultOncallBound } from './services/oncall-store.js';
@@ -53,7 +55,7 @@ import { RECEIVED_REACTION_EMOJI_TYPE, SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE }
53
55
  import { t as tr, localeForBot } from './i18n/index.js';
54
56
  import { createCliAdapterSync } from './adapters/cli/registry.js';
55
57
  import { initWorkerPool, setActiveSessionsRegistry, forkWorker, sendWorkerInput, killWorker, reapOrphanWorkers, scheduleCardPatch, setCurrentCliVersion, getCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, ensureCliEnv, sweepGlobalBotmuxSkills, writableTerminalLinkFor, findActiveBySessionId, getDaemonBootId, } from './core/worker-pool.js';
56
- import { ipcRoute, isTrustedHostIpcRequest, jsonRes, readJsonBody, setBotName, setLarkAppId, startIpcServer, setBotRenamer, setBotAvatarChanger } from './core/dashboard-ipc-server.js';
58
+ import { AbortDeadlineError, hasExactSafeJsonKeys, ipcRoute, isTrustedHostIpcRequest, JsonBodyTooLargeError, jsonRes, readJsonBody, runWithAbortDeadline, setBotName, setLarkAppId, startIpcServer, setBotRenamer, setBotAvatarChanger } from './core/dashboard-ipc-server.js';
57
59
  import { setDeviceIsolationDaemonIdentity } from './core/device-isolation-daemon.js';
58
60
  import { cancelSessionReadyAck, waitForSessionReadyAck, } from './core/session-ready-handshake.js';
59
61
  import { loadOrCreateDashboardSecret } from './dashboard/auth.js';
@@ -73,13 +75,14 @@ import { applyQueuedCodexAppLegacyFallback, mergeQueuedCodexAppTurn } from './co
73
75
  import { findOnlineDaemon, listOnlineDaemons } from './utils/daemon-discovery.js';
74
76
  import { beginReplyTargetTurn, fallbackTurnId, isSubstituteTurn, resolveSessionReplyTarget, syncReplyTargetState } from './core/reply-target.js';
75
77
  import { readDeferredTopicBinding } from './core/deferred-topic-binding.js';
78
+ import { buildBotmuxLarkNativeSessionTitle, extractBotmuxLarkNativeSessionTitlePrompt, } from './core/session-title.js';
76
79
  import { settleDeferredScheduleRun } from './core/deferred-schedule-settlement.js';
77
80
  import { sweepOrphanSandboxes } from './adapters/backend/sandbox.js';
78
81
  import { TmuxBackend } from './adapters/backend/tmux-backend.js';
79
82
  import { HerdrBackend } from './adapters/backend/herdr-backend.js';
80
83
  import { ZellijBackend } from './adapters/backend/zellij-backend.js';
81
84
  import { sweepIdleWorkers, DEFAULT_MAX_LIVE_WORKERS } from './core/idle-worker-sweeper.js';
82
- import { getSessionPersistentBackendType, killPersistentSession, persistentSessionName, probePersistentSession, resolvePairedSpawnBackendType, } from './core/persistent-backend.js';
85
+ import { getSessionPersistentBackendType, killPersistentBackendTarget, killPersistentSession, probePersistentBackendTarget, probePersistentSession, resolvePersistentBackendTarget, resolvePairedSpawnBackendType, } from './core/persistent-backend.js';
83
86
  import { handleCardAction, runAutoWorktreeCommit } from './im/lark/card-handler.js';
84
87
  import { parseWorkflowGrillTrigger, buildWorkflowGrillPrompt, isLegacyTemplateCommand, LEGACY_TEMPLATE_RETIRED_MESSAGE, WORKFLOW_USAGE, } from './im/lark/workflow-slash-command.js';
85
88
  import { parseV3SavedWorkflowCommand, v3SavedWorkflowUsage, } from './im/lark/v3-saved-workflow-command.js';
@@ -104,6 +107,8 @@ import { defaultBaseDir as v3DefaultBaseDir } from './workflows/v3/grill-state.j
104
107
  import { persistV3StartIntent } from './workflows/v3/start-intent.js';
105
108
  import { createWorkflowDaemonIpcNonceStore, generateWorkflowDaemonBootInstanceId, loadWorkflowDaemonIpcSecret, signWorkflowDaemonIpcResponse, verifyWorkflowDaemonIpcRequest, WORKFLOW_DAEMON_IPC_ROUTE_PREFIX, } from './workflows/v3/daemon-ipc-auth.js';
106
109
  import { parseWorkflowDaemonMutationBody, } from './workflows/v3/daemon-ipc-body.js';
110
+ import { resolveEffectivePluginIds } from './core/plugins/effective.js';
111
+ import { buildCodexCompletionCard, buildCodexNotifierResultCard, CODEX_NOTIFIER_PLUGIN_ID, CodexNotifierEventStore, CodexNotifierEventValidationError, codexNotifierMessageUuid, createCodexNotifierCardActionHandler, materializeCodexNotifierOutboxEvent, openCodexAppThread, parseCodexNotifierEvent, parseCodexNotifierPluginEvent, parseCodexNotifierOutboxItem, startCodexNotifierAdoptionSession, } from './features/codex-notifier/index.js';
107
112
  /** This daemon process's bot larkAppId (set in startDaemon). Used to scope v3
108
113
  * humanGate cold-attach + start to runs this bot owns (codex blocker #1). */
109
114
  let selfV3LarkAppId;
@@ -248,7 +253,8 @@ function vcMeetingBootBackingMissing(sessionId, destroy) {
248
253
  }
249
254
  }
250
255
  const liveBackend = ds ? getSessionPersistentBackendType(ds) : undefined;
251
- const persistedBackend = liveBackend ?? sessionStore.getSession(sessionId)?.backendType;
256
+ const persistedSession = ds?.session ?? sessionStore.getSession(sessionId);
257
+ const persistedBackend = liveBackend ?? persistedSession?.backendType;
252
258
  if (persistedBackend === 'pty')
253
259
  return true;
254
260
  const backendTypes = persistedBackend === 'tmux' || persistedBackend === 'herdr' || persistedBackend === 'zellij'
@@ -256,10 +262,11 @@ function vcMeetingBootBackingMissing(sessionId, destroy) {
256
262
  : VC_MEETING_PERSISTENT_BACKENDS.filter(vcMeetingPersistentBackendAvailable);
257
263
  let allMissing = true;
258
264
  for (const backendType of backendTypes) {
259
- const name = persistentSessionName(backendType, sessionId);
265
+ const target = resolvePersistentBackendTarget(backendType, sessionId, persistedSession?.persistentBackendTarget);
266
+ const name = target.sessionName;
260
267
  if (destroy) {
261
268
  try {
262
- killPersistentSession(backendType, name);
269
+ killPersistentBackendTarget(target);
263
270
  }
264
271
  catch (err) {
265
272
  logger.warn(`[vc-delivery] boot recovery backing kill failed backend=${backendType} `
@@ -268,7 +275,7 @@ function vcMeetingBootBackingMissing(sessionId, destroy) {
268
275
  }
269
276
  let probe = 'unknown';
270
277
  try {
271
- probe = probePersistentSession(backendType, name);
278
+ probe = probePersistentBackendTarget(target);
272
279
  }
273
280
  catch {
274
281
  probe = 'unknown';
@@ -445,10 +452,12 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
445
452
  ? VC_MEETING_PERSISTENT_BACKENDS.filter(deps.backendAvailable)
446
453
  : [persistentScope];
447
454
  let allMissing = true;
455
+ const persistedTarget = deps.resolvePersistentTarget?.(fence.receiverSessionId, ds);
448
456
  for (const backendType of backendTypes) {
449
- const name = persistentSessionName(backendType, fence.receiverSessionId);
457
+ const target = resolvePersistentBackendTarget(backendType, fence.receiverSessionId, persistedTarget);
458
+ const name = target.sessionName;
450
459
  try {
451
- deps.killPersistent(backendType, name);
460
+ deps.killPersistent(backendType, name, target);
452
461
  }
453
462
  catch (err) {
454
463
  deps.warn(`[vc-delivery] runtime lease backing kill failed backend=${backendType} `
@@ -456,7 +465,7 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
456
465
  }
457
466
  let probe = 'unknown';
458
467
  try {
459
- probe = deps.probePersistent(backendType, name);
468
+ probe = deps.probePersistent(backendType, name, target);
460
469
  }
461
470
  catch {
462
471
  probe = 'unknown';
@@ -619,8 +628,9 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
619
628
  return false;
620
629
  }
621
630
  let probe = 'unknown';
631
+ const target = resolvePersistentBackendTarget(persistentScope, fence.receiverSessionId, ds.session.persistentBackendTarget);
622
632
  try {
623
- probe = deps.probePersistent(persistentScope, persistentSessionName(persistentScope, fence.receiverSessionId));
633
+ probe = deps.probePersistent(persistentScope, target.sessionName, target);
624
634
  }
625
635
  catch {
626
636
  probe = 'unknown';
@@ -684,9 +694,17 @@ const vcMeetingRuntimeLeaseRecovery = createVcMeetingRuntimeLeaseRecovery({
684
694
  }
685
695
  return backendType === 'pty' ? 'none' : 'unknown';
686
696
  },
697
+ resolvePersistentTarget(sessionId, ds) {
698
+ return ds?.session.persistentBackendTarget
699
+ ?? sessionStore.getSession(sessionId)?.persistentBackendTarget;
700
+ },
687
701
  backendAvailable: vcMeetingPersistentBackendAvailable,
688
- killPersistent: killPersistentSession,
689
- probePersistent: probePersistentSession,
702
+ killPersistent: (backendType, sessionName, target) => target
703
+ ? killPersistentBackendTarget(target)
704
+ : killPersistentSession(backendType, sessionName),
705
+ probePersistent: (backendType, sessionName, target) => target
706
+ ? probePersistentBackendTarget(target)
707
+ : probePersistentSession(backendType, sessionName),
690
708
  warn: message => logger.warn(message),
691
709
  error: message => logger.error(message),
692
710
  });
@@ -1593,6 +1611,29 @@ function setDirectChatDisplayNameFromSender(session, chatType, sender) {
1593
1611
  if (name)
1594
1612
  session.chatDisplayName = name;
1595
1613
  }
1614
+ const NATIVE_TITLE_CHAT_NAME_TIMEOUT_MS = 800;
1615
+ /** 首条只有机器人 mention 时,尽力取群名作为原生会话标题兜底。 */
1616
+ async function resolveGroupChatNameForNativeTitle(larkAppId, chatId, chatType, cliId, rawContent, mentions) {
1617
+ if (chatType !== 'group'
1618
+ || cliId !== 'codex'
1619
+ || extractBotmuxLarkNativeSessionTitlePrompt(rawContent, mentions)) {
1620
+ return undefined;
1621
+ }
1622
+ let timer;
1623
+ const timeout = new Promise(resolve => {
1624
+ timer = setTimeout(resolve, NATIVE_TITLE_CHAT_NAME_TIMEOUT_MS);
1625
+ });
1626
+ try {
1627
+ return await Promise.race([
1628
+ getChatNameAndMode(larkAppId, chatId).then(info => info.name ?? undefined),
1629
+ timeout,
1630
+ ]);
1631
+ }
1632
+ finally {
1633
+ if (timer)
1634
+ clearTimeout(timer);
1635
+ }
1636
+ }
1596
1637
  // Cache last /repo scan results per chat for /repo <number> fallback.
1597
1638
  // Bounded: this is a transient picker cache keyed by chatId (unbounded over a
1598
1639
  // long-lived daemon's chat set), so cap it instead of retaining one
@@ -2699,11 +2740,211 @@ const v3GateRunner = createV3GateRunner({
2699
2740
  // 每个 bot 的 EventHandlers,授权成功后重放消息时需要。
2700
2741
  // key = larkAppId,在 startLarkEventDispatcher 调用时写入。
2701
2742
  const botHandlers = new Map();
2743
+ const codexNotifierStores = new Map();
2744
+ const codexNotifierDeliveries = new Map();
2745
+ const CODEX_NOTIFIER_INGRESS_MAX_BYTES = 128 * 1024;
2746
+ const CODEX_NOTIFIER_DELIVERY_TIMEOUT_MS = 10_000;
2747
+ const CODEX_NOTIFIER_ADOPTION_TIMEOUT_MS = 2_200;
2748
+ const CODEX_NOTIFIER_MESSAGE_LOOKUP_TIMEOUT_MS = 1_200;
2749
+ function remainingCodexNotifierDeadline(deadlineAt, capMs) {
2750
+ return Math.max(1, Math.min(capMs, deadlineAt - Date.now()));
2751
+ }
2752
+ function codexNotifierStore(larkAppId) {
2753
+ const existing = codexNotifierStores.get(larkAppId);
2754
+ if (existing)
2755
+ return existing;
2756
+ const suffix = createHash('sha256').update(larkAppId).digest('hex').slice(0, 16);
2757
+ const store = new CodexNotifierEventStore(join(config.session.dataDir, 'plugin-events', `codex-notifier-${suffix}.json`));
2758
+ codexNotifierStores.set(larkAppId, store);
2759
+ return store;
2760
+ }
2761
+ function codexNotifierIngressEnabled(larkAppId, legacyPlugin = false) {
2762
+ const global = readGlobalConfig();
2763
+ if (global.codexNotifier !== undefined || !legacyPlugin) {
2764
+ return global.codexNotifier?.enabled === true;
2765
+ }
2766
+ try {
2767
+ return resolveEffectivePluginIds(getBot(larkAppId).config, global)
2768
+ .includes(CODEX_NOTIFIER_PLUGIN_ID);
2769
+ }
2770
+ catch {
2771
+ return false;
2772
+ }
2773
+ }
2774
+ /** 用 Codex 原生线程名补全通知标题;失败时保留插件事件里的安全兜底信息。 */
2775
+ async function enrichCodexNotifierEvent(larkAppId, event) {
2776
+ if (event.title)
2777
+ return event;
2778
+ try {
2779
+ const { readCodexAppThreadMetadata } = await import('./services/codex-app-threads.js');
2780
+ const metadata = await readCodexAppThreadMetadata({
2781
+ threadId: event.threadId,
2782
+ codexBin: getBot(larkAppId).config.cliPathOverride,
2783
+ cwd: event.cwd,
2784
+ timeoutMs: 3_000,
2785
+ });
2786
+ const title = metadata.name?.trim();
2787
+ return title ? { ...event, title: Array.from(title).slice(0, 300).join('') } : event;
2788
+ }
2789
+ catch (error) {
2790
+ logger.warn(`[codex-notifier] thread title lookup failed: ${error instanceof Error ? error.message : String(error)}`);
2791
+ return event;
2792
+ }
2793
+ }
2794
+ async function deliverCodexNotifierEvent(larkAppId, event) {
2795
+ const store = codexNotifierStore(larkAppId);
2796
+ const enrichedEvent = store.get(event.eventId) ? event : await enrichCodexNotifierEvent(larkAppId, event);
2797
+ const recorded = store.record(enrichedEvent);
2798
+ const deliveryEvent = recorded.record.event;
2799
+ if (!recorded.inserted) {
2800
+ if (deliveryEvent.type !== event.type
2801
+ || deliveryEvent.source !== event.source
2802
+ || deliveryEvent.threadId !== event.threadId
2803
+ || deliveryEvent.nativeTurnId !== event.nativeTurnId
2804
+ || deliveryEvent.status !== event.status) {
2805
+ throw new Error('codex_notifier_event_id_conflict');
2806
+ }
2807
+ if (recorded.record.delivery.status === 'delivered' && recorded.record.delivery.messageId) {
2808
+ return { status: 'duplicate', messageId: recorded.record.delivery.messageId };
2809
+ }
2810
+ }
2811
+ const deliveryKey = `${larkAppId}:${event.eventId}`;
2812
+ const current = codexNotifierDeliveries.get(deliveryKey);
2813
+ if (current)
2814
+ return current;
2815
+ const delivery = (async () => {
2816
+ const ownerOpenId = getOwnerOpenId(larkAppId) ?? resolvePrimaryOwnerOpenId(larkAppId);
2817
+ if (!ownerOpenId)
2818
+ throw new Error('codex_notifier_owner_unavailable');
2819
+ store.updateDelivery(event.eventId, { status: 'pending' });
2820
+ try {
2821
+ const messageId = await runWithAbortDeadline('codex_notifier_delivery', CODEX_NOTIFIER_DELIVERY_TIMEOUT_MS, signal => sendUserMessage(larkAppId, ownerOpenId, buildCodexCompletionCard(deliveryEvent), 'interactive', codexNotifierMessageUuid(event.eventId), {
2822
+ timeoutMs: CODEX_NOTIFIER_DELIVERY_TIMEOUT_MS,
2823
+ signal,
2824
+ }));
2825
+ store.updateDelivery(event.eventId, { status: 'delivered', messageId, incrementAttempts: false });
2826
+ return { status: 'accepted', messageId };
2827
+ }
2828
+ catch (error) {
2829
+ const detail = error instanceof Error ? error.message : String(error);
2830
+ store.updateDelivery(event.eventId, {
2831
+ status: 'failed',
2832
+ lastError: detail,
2833
+ incrementAttempts: false,
2834
+ });
2835
+ throw error;
2836
+ }
2837
+ })();
2838
+ codexNotifierDeliveries.set(deliveryKey, delivery);
2839
+ try {
2840
+ return await delivery;
2841
+ }
2842
+ finally {
2843
+ codexNotifierDeliveries.delete(deliveryKey);
2844
+ }
2845
+ }
2846
+ async function adoptCodexNotifierEvent(larkAppId, event, cardMessageId, ownerOpenId, signal, deadlineAt) {
2847
+ signal.throwIfAborted();
2848
+ const chatId = await getMessageChatId(larkAppId, cardMessageId, {
2849
+ timeoutMs: remainingCodexNotifierDeadline(deadlineAt, CODEX_NOTIFIER_MESSAGE_LOOKUP_TIMEOUT_MS),
2850
+ signal,
2851
+ });
2852
+ if (!chatId)
2853
+ throw new Error('无法定位完成通知所在的飞书私聊');
2854
+ signal.throwIfAborted();
2855
+ const botCfg = getBot(larkAppId).config;
2856
+ const scope = botCfg.p2pMode === 'chat' ? 'chat' : 'thread';
2857
+ const anchor = scope === 'chat' ? chatId : cardMessageId;
2858
+ const activeKey = sessionKey(anchor, larkAppId);
2859
+ let ds = activeSessions.get(activeKey);
2860
+ if (!ds) {
2861
+ const fallbackTitle = event.cwd.split(/[\\/]/).filter(Boolean).pop() ?? 'Codex App';
2862
+ const title = (event.title || `Codex App: ${fallbackTitle}`).slice(0, 50);
2863
+ const session = sessionStore.createSession(chatId, cardMessageId, title, 'p2p');
2864
+ const now = Date.now();
2865
+ session.larkAppId = larkAppId;
2866
+ session.scope = scope;
2867
+ session.ownerOpenId = ownerOpenId;
2868
+ session.lastCallerOpenId = ownerOpenId;
2869
+ session.lastMessageAt = new Date(now).toISOString();
2870
+ session.workingDir = event.cwd;
2871
+ session.cliId = 'codex-app';
2872
+ sessionStore.updateSession(session);
2873
+ messageQueue.ensureQueue(anchor);
2874
+ ds = {
2875
+ session,
2876
+ worker: null,
2877
+ workerPort: null,
2878
+ workerToken: null,
2879
+ larkAppId,
2880
+ chatId,
2881
+ chatType: 'p2p',
2882
+ scope,
2883
+ spawnedAt: Date.parse(session.createdAt) || now,
2884
+ cliVersion: getCurrentCliVersion(),
2885
+ lastMessageAt: now,
2886
+ hasHistory: false,
2887
+ workingDir: event.cwd,
2888
+ ownerOpenId,
2889
+ };
2890
+ activeSessions.set(activeKey, ds);
2891
+ }
2892
+ if (ds.session.cliSessionId !== event.threadId || !ds.worker || ds.worker.killed) {
2893
+ // 接管原生 Codex App 线程时固定为纯 codex-app 启动,不能继承通知 Bot 的
2894
+ // wrapper/model;这些配置针对普通 CLI,会错误包装 app-server runner。
2895
+ ds.session.cliId = 'codex-app';
2896
+ ds.session.cliPathOverride = botCfg.cliPathOverride;
2897
+ delete ds.session.wrapperCli;
2898
+ delete ds.session.model;
2899
+ ds.session.agentFrozen = true;
2900
+ sessionStore.updateSession(ds.session);
2901
+ ds.pendingRepo = false;
2902
+ ds.pendingPrompt = undefined;
2903
+ ds.pendingTurnId = undefined;
2904
+ ds.pendingCodexAppText = undefined;
2905
+ ds.pendingCodexAppApplicationContext = undefined;
2906
+ ds.pendingCodexAppMessageContext = undefined;
2907
+ // 完成事件已经携带恢复所需的原生 threadId/cwd。按钮回调不再额外启动一次
2908
+ // app-server 做非必要的元数据刷新,避免子进程把飞书回调拖过截止时间。
2909
+ const target = {
2910
+ threadId: event.threadId,
2911
+ name: event.title,
2912
+ preview: event.finalPreview ?? '',
2913
+ cwd: event.cwd,
2914
+ status: event.status,
2915
+ };
2916
+ const { startCodexAppThreadSession } = await import('./core/command-handler.js');
2917
+ signal.throwIfAborted();
2918
+ await startCodexNotifierAdoptionSession(startCodexAppThreadSession, target, ds, {
2919
+ activeSessions,
2920
+ sessionReply,
2921
+ getActiveCount,
2922
+ lastRepoScan,
2923
+ }, larkAppId, cardMessageId);
2924
+ }
2925
+ return buildCodexNotifierResultCard('已接管 Codex App 任务', scope === 'chat'
2926
+ ? '现在可以直接在当前私聊继续发送指令;需要操作终端时,请点击会话卡内的「获取操作链接」。'
2927
+ : '请在本卡片的话题中继续发送指令;需要操作终端时,请点击话题会话卡内的「获取操作链接」。', 'green');
2928
+ }
2929
+ const handleCodexNotifierCardAction = createCodexNotifierCardActionHandler({
2930
+ getExpectedOwnerOpenId: larkAppId => getOwnerOpenId(larkAppId) ?? resolvePrimaryOwnerOpenId(larkAppId),
2931
+ getEventRecord: (larkAppId, eventId) => codexNotifierStore(larkAppId).get(eventId),
2932
+ readConfig: () => readGlobalConfig().codexNotifier,
2933
+ openAppThread: openCodexAppThread,
2934
+ adoptEvent: adoptCodexNotifierEvent,
2935
+ runWithAbortDeadline,
2936
+ isAbortDeadlineError: error => error instanceof AbortDeadlineError,
2937
+ adoptionTimeoutMs: CODEX_NOTIFIER_ADOPTION_TIMEOUT_MS,
2938
+ logInfo: message => logger.info(message),
2939
+ logWarn: message => logger.warn(message),
2940
+ logError: message => logger.error(message),
2941
+ });
2702
2942
  const cardDeps = {
2703
2943
  activeSessions,
2704
2944
  sessionReply,
2705
2945
  lastRepoScan,
2706
2946
  vcMeetingCardAction: (data, appId) => handleVcMeetingCardAction(data, appId),
2947
+ codexNotifierCardAction: (data, appId) => handleCodexNotifierCardAction(data, appId),
2707
2948
  v3GateDeps: {
2708
2949
  driveRun: (runId) => v3GateRunner.driveDetached(runId),
2709
2950
  // 审批权限:复用 canOperate(话题 owner / allowedUsers / oncall)。无 binding(corrupt /
@@ -3328,6 +3569,98 @@ ipcRoute('POST', '/api/session-ready', async (req, res) => {
3328
3569
  }
3329
3570
  return jsonRes(res, 200, { ok: true });
3330
3571
  });
3572
+ async function respondCodexNotifierIngress(res, larkAppId, rawEvent, pluginId) {
3573
+ if (!codexNotifierIngressEnabled(larkAppId, pluginId === CODEX_NOTIFIER_PLUGIN_ID)) {
3574
+ return jsonRes(res, 403, { ok: false, error: 'codex_notifier_disabled' });
3575
+ }
3576
+ let event;
3577
+ try {
3578
+ event = pluginId === undefined
3579
+ ? parseCodexNotifierEvent(rawEvent)
3580
+ : parseCodexNotifierPluginEvent(pluginId, rawEvent);
3581
+ }
3582
+ catch (error) {
3583
+ const code = error instanceof CodexNotifierEventValidationError
3584
+ ? error.code
3585
+ : 'invalid_event';
3586
+ return jsonRes(res, 400, { ok: false, error: code });
3587
+ }
3588
+ try {
3589
+ const result = await deliverCodexNotifierEvent(larkAppId, event);
3590
+ return jsonRes(res, 200, { ok: true, status: result.status, messageId: result.messageId });
3591
+ }
3592
+ catch (error) {
3593
+ const detail = error instanceof Error ? error.message : String(error);
3594
+ if (detail === 'codex_notifier_event_id_conflict') {
3595
+ return jsonRes(res, 409, { ok: false, error: 'event_id_conflict' });
3596
+ }
3597
+ logger.warn(`[codex-notifier] delivery failed event=${event.eventId.slice(0, 12)}: ${detail}`);
3598
+ return jsonRes(res, 502, { ok: false, error: 'delivery_failed' });
3599
+ }
3600
+ }
3601
+ // ─── 内建 Codex 完成事件入口 ────────────────────────────────────────────────
3602
+ // Dashboard 单例 worker 持有可靠 outbox,通过 host HMAC 投递到入队时选定的 Bot。
3603
+ ipcRoute('POST', '/api/codex-notifier/events', async (req, res) => {
3604
+ if (!isTrustedHostIpcRequest(req)) {
3605
+ return jsonRes(res, 403, { ok: false, error: 'trusted_host_required' });
3606
+ }
3607
+ const larkAppId = selfDaemonLarkAppId;
3608
+ if (!larkAppId) {
3609
+ return jsonRes(res, 503, { ok: false, error: 'daemon_not_ready' });
3610
+ }
3611
+ let raw;
3612
+ try {
3613
+ raw = await readJsonBody(req, CODEX_NOTIFIER_INGRESS_MAX_BYTES);
3614
+ }
3615
+ catch (error) {
3616
+ if (error instanceof JsonBodyTooLargeError) {
3617
+ return jsonRes(res, 413, { ok: false, error: 'payload_too_large' });
3618
+ }
3619
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3620
+ }
3621
+ let item;
3622
+ try {
3623
+ item = parseCodexNotifierOutboxItem(raw);
3624
+ }
3625
+ catch {
3626
+ return jsonRes(res, 400, { ok: false, error: 'invalid_outbox_item' });
3627
+ }
3628
+ if (item.targetBotAppId !== larkAppId) {
3629
+ return jsonRes(res, 403, { ok: false, error: 'target_bot_mismatch' });
3630
+ }
3631
+ return respondCodexNotifierIngress(res, larkAppId, materializeCodexNotifierOutboxEvent(item));
3632
+ });
3633
+ // 旧独立插件的兼容入口保留一个迁移周期,只负责排空已经落盘的历史 outbox。
3634
+ ipcRoute('POST', '/api/plugin-events', async (req, res) => {
3635
+ if (!isTrustedHostIpcRequest(req)) {
3636
+ return jsonRes(res, 403, { ok: false, error: 'trusted_host_required' });
3637
+ }
3638
+ const larkAppId = selfDaemonLarkAppId;
3639
+ if (!larkAppId) {
3640
+ return jsonRes(res, 503, { ok: false, error: 'daemon_not_ready' });
3641
+ }
3642
+ let raw;
3643
+ try {
3644
+ raw = await readJsonBody(req, CODEX_NOTIFIER_INGRESS_MAX_BYTES);
3645
+ }
3646
+ catch (error) {
3647
+ if (error instanceof JsonBodyTooLargeError) {
3648
+ return jsonRes(res, 413, { ok: false, error: 'payload_too_large' });
3649
+ }
3650
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3651
+ }
3652
+ if (!hasExactSafeJsonKeys(raw, ['pluginId', 'targetBotAppId', 'event'])) {
3653
+ return jsonRes(res, 400, { ok: false, error: 'bad_body' });
3654
+ }
3655
+ const { pluginId, targetBotAppId, event: rawEvent, } = raw;
3656
+ if (pluginId !== CODEX_NOTIFIER_PLUGIN_ID) {
3657
+ return jsonRes(res, 400, { ok: false, error: 'unsupported_plugin' });
3658
+ }
3659
+ if (targetBotAppId !== larkAppId) {
3660
+ return jsonRes(res, 403, { ok: false, error: 'target_bot_mismatch' });
3661
+ }
3662
+ return respondCodexNotifierIngress(res, larkAppId, rawEvent, pluginId);
3663
+ });
3331
3664
  // ─── hooks emit 转发端点 ────────────────────────────────────────────────────
3332
3665
  // CLI side(botmux send 等)调用 emitHookEvent 时,把事件转发到 daemon 这条
3333
3666
  // 接口;daemon 在自己的长寿命事件循环里负责 spawn hook、跑 timeout、超时杀
@@ -12288,6 +12621,7 @@ async function handleNewTopic(data, ctx) {
12288
12621
  // Resolve sender identity for <sender> tag injection. The first call to
12289
12622
  // resolveSender for an unseen open_id may await contact.v3.user.get with a
12290
12623
  // short budget; subsequent calls hit the cache and are sync-fast.
12624
+ const groupChatNamePromise = resolveGroupChatNameForNativeTitle(larkAppId, chatId, chatType, botCfg.cliId, parsed.content, parsed.mentions);
12291
12625
  const newTopicSender = await resolveSender(larkAppId, senderOpenId, parsed.senderType);
12292
12626
  refreshCliVersion(botCfg.cliId, botCfg.cliPathOverride);
12293
12627
  // Pin the working dir via the layered oncall / inherit / default lookup
@@ -12310,6 +12644,9 @@ async function handleNewTopic(data, ctx) {
12310
12644
  const session = sessionStore.createSession(chatId, rootIdForStore, parsed.content.substring(0, 50), chatType);
12311
12645
  const now = Date.now();
12312
12646
  setDirectChatDisplayNameFromSender(session, chatType, newTopicSender);
12647
+ const groupChatName = await groupChatNamePromise;
12648
+ if (groupChatName)
12649
+ session.chatDisplayName = groupChatName;
12313
12650
  session.larkAppId = larkAppId;
12314
12651
  session.ownerOpenId = senderOpenId;
12315
12652
  session.ownerUnionId = senderUnionId;
@@ -12323,6 +12660,7 @@ async function handleNewTopic(data, ctx) {
12323
12660
  session.quoteTargetSenderIsBot = parsed.senderType === 'app' || parsed.senderType === 'bot';
12324
12661
  session.lastMessageAt = new Date(now).toISOString();
12325
12662
  session.scope = scope;
12663
+ session.nativeSessionTitle = buildBotmuxLarkNativeSessionTitle(parsed.content, parsed.mentions, groupChatName);
12326
12664
  sessionStore.updateSession(session);
12327
12665
  messageQueue.ensureQueue(anchor);
12328
12666
  messageQueue.appendMessage(anchor, parsed);
@@ -13222,6 +13560,7 @@ async function handleThreadReply(data, ctx) {
13222
13560
  const autoCreateChatId = ctxChatId ?? data?.message?.chat_id ?? '';
13223
13561
  const autoCreateChatType = ctxChatType ?? (data?.message?.chat_type === 'p2p' ? 'p2p' : 'group');
13224
13562
  const botCfg = getBot(larkAppId).config;
13563
+ const groupChatNamePromise = resolveGroupChatNameForNativeTitle(larkAppId, autoCreateChatId, autoCreateChatType, botCfg.cliId, parsed.content, parsed.mentions);
13225
13564
  logger.info(`No active session for ${scope}-scope ${anchor}, auto-creating new session...`);
13226
13565
  refreshCliVersion(botCfg.cliId, botCfg.cliPathOverride);
13227
13566
  const senderOId = data.sender?.sender_id?.open_id;
@@ -13249,6 +13588,10 @@ async function handleThreadReply(data, ctx) {
13249
13588
  session.quoteTargetSenderIsBot = isForeignBot;
13250
13589
  session.lastMessageAt = new Date(now).toISOString();
13251
13590
  session.scope = scope;
13591
+ const groupChatName = await groupChatNamePromise;
13592
+ if (groupChatName)
13593
+ session.chatDisplayName = groupChatName;
13594
+ session.nativeSessionTitle = buildBotmuxLarkNativeSessionTitle(parsed.content, parsed.mentions, groupChatName);
13252
13595
  sessionStore.updateSession(session);
13253
13596
  // chat-scope only — see the handleNewTopic twin above (topic substitute
13254
13597
  // sessions keep their streaming card, no control-card compensation).
@@ -13877,6 +14220,25 @@ function dashboardUrlForReport() {
13877
14220
  return {};
13878
14221
  }
13879
14222
  }
14223
+ async function waitForManagedActivationCommit(index, appId) {
14224
+ const activationAppId = process.env.BOTMUX_MANAGED_ACTIVATION_APP_ID;
14225
+ if (activationAppId === undefined)
14226
+ return;
14227
+ if (activationAppId !== appId) {
14228
+ throw new Error(`Managed activation App drifted at BOTMUX_BOT_INDEX=${index}`);
14229
+ }
14230
+ const activationJobId = process.env.BOTMUX_MANAGED_ACTIVATION_JOB_ID;
14231
+ if (!activationJobId) {
14232
+ throw new Error(`Managed activation receipt is missing at BOTMUX_BOT_INDEX=${index}`);
14233
+ }
14234
+ while (isManagedActivationStartingAtIndex(index, appId, activationJobId)) {
14235
+ await new Promise(resolve => setTimeout(resolve, 100));
14236
+ }
14237
+ const committed = loadBotConfigAtIndex(index);
14238
+ if (committed.larkAppId !== appId) {
14239
+ throw new Error(`Managed activation target drifted at BOTMUX_BOT_INDEX=${index}`);
14240
+ }
14241
+ }
13880
14242
  export async function startDaemon(botIndex) {
13881
14243
  // Repair a shared tmux server polluted by an older botmux immediately on
13882
14244
  // daemon startup. This must not depend on restoring/spawning a bmx-* session:
@@ -13892,27 +14254,36 @@ export async function startDaemon(botIndex) {
13892
14254
  // 首次启动时后台尝试安装 CJK 字体(Debian/Ubuntu),避免截图中文显示豆腐块。
13893
14255
  // 不阻塞:首张截图可能仍是豆腐块,装完重启 daemon 即可正常。
13894
14256
  ensureCjkFontsInstalled();
14257
+ // Auto-migrate legacy sandbox fields (readIsolation / sandboxHidePaths /
14258
+ // sandboxReadonlyPaths / readDenyExtraPaths → sandbox + sandboxPaths) BEFORE
14259
+ // loading, so the parsed configs below already carry the new model. Writes
14260
+ // new fields, keeps old ones (downgrade = zero-op), backs up once. Idempotent.
14261
+ await migrateSandboxConfigAtStartup();
13895
14262
  // Load the assigned bot (one daemon per bot)
13896
14263
  let botConfigs = loadBotConfigs();
13897
14264
  const idx = botIndex ?? 0;
13898
- if (idx < 0 || idx >= botConfigs.length) {
13899
- throw new Error(`Invalid BOTMUX_BOT_INDEX=${idx}, only ${botConfigs.length} bot(s) configured`);
14265
+ let cfg = botIndex === undefined
14266
+ ? botConfigs[idx]
14267
+ : loadBotConfigAtIndex(idx);
14268
+ if (!cfg) {
14269
+ throw new Error(`Invalid BOTMUX_BOT_INDEX=${idx}, only ${botConfigs.length} active bot(s) configured`);
14270
+ }
14271
+ if (botIndex !== undefined) {
14272
+ // During managed activation PM2 may report this process online before it
14273
+ // is allowed to register a bot or receive traffic. The dashboard clears
14274
+ // the exact startup marker only after it has re-read the PM2 receipt ACK.
14275
+ await waitForManagedActivationCommit(idx, cfg.larkAppId);
14276
+ botConfigs = loadBotConfigs();
14277
+ cfg = loadBotConfigAtIndex(idx);
13900
14278
  }
13901
- let cfg = botConfigs[idx];
13902
14279
  // One-time, lock-protected catalog bootstrap. This runs only after the
13903
14280
  // complete bots.json has parsed successfully, and the helper re-reads the
13904
14281
  // latest file under its lock before deciding. Explicit [] and legacy agent
13905
14282
  // policy are durable opt-outs. Reload the selected config after a write so
13906
14283
  // this daemon exposes the seeded selection card immediately on the same boot.
13907
- const profileBootstrap = await bootstrapVcMeetingDefaultConsumerProfile(cfg.larkAppId);
14284
+ const selectedAppId = cfg.larkAppId;
14285
+ const profileBootstrap = await bootstrapVcMeetingDefaultConsumerProfile(selectedAppId);
13908
14286
  if (profileBootstrap.ok) {
13909
- const selectedAppId = cfg.larkAppId;
13910
- // Reload even when another concurrent daemon won the one-time write. Both
13911
- // processes may have loaded the old file before taking the config lock;
13912
- // the loser still needs the winner's catalog on this boot.
13913
- botConfigs = loadBotConfigs();
13914
- cfg = botConfigs.find(candidate => candidate.larkAppId === selectedAppId)
13915
- ?? botConfigs[idx];
13916
14287
  if (profileBootstrap.seeded) {
13917
14288
  logger.info(`[vc-agent] seeded default meeting minutes profile listener=${selectedAppId} `
13918
14289
  + `agent=${profileBootstrap.agentAppId}`);
@@ -13922,6 +14293,12 @@ export async function startDaemon(botIndex) {
13922
14293
  logger.warn(`[vc-agent] default consumer profile bootstrap skipped: ${profileBootstrap.reason}`
13923
14294
  + `${profileBootstrap.error ? ` (${profileBootstrap.error})` : ''}`);
13924
14295
  }
14296
+ // A bootstrap failure is not authority to keep an earlier in-memory config.
14297
+ // Every explicit PM2 daemon must prove its same raw slot and App identity
14298
+ // immediately before registerBot, regardless of the bootstrap result.
14299
+ if (botIndex !== undefined) {
14300
+ cfg = reloadExactDaemonBotConfig(idx, selectedAppId, loadBotConfigAtIndex);
14301
+ }
13925
14302
  registerBot(cfg);
13926
14303
  selfDaemonLarkAppId = cfg.larkAppId;
13927
14304
  // Establish the target-scoped daemon control credential before publishing