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