botmux 2.47.0 → 2.47.1

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 (472) hide show
  1. package/README.en.md +10 -5
  2. package/README.md +10 -5
  3. package/dist/adapters/adopt-route.d.ts +63 -0
  4. package/dist/adapters/adopt-route.d.ts.map +1 -0
  5. package/dist/adapters/adopt-route.js +195 -0
  6. package/dist/adapters/adopt-route.js.map +1 -0
  7. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  8. package/dist/adapters/backend/tmux-backend.js +11 -0
  9. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  10. package/dist/adapters/backend/tmux-pipe-backend.d.ts +11 -0
  11. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  12. package/dist/adapters/backend/tmux-pipe-backend.js +17 -1
  13. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  14. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  15. package/dist/adapters/cli/claude-code.js +36 -9
  16. package/dist/adapters/cli/claude-code.js.map +1 -1
  17. package/dist/adapters/cli/coco.d.ts.map +1 -1
  18. package/dist/adapters/cli/coco.js +26 -1
  19. package/dist/adapters/cli/coco.js.map +1 -1
  20. package/dist/adapters/cli/codex-app.d.ts +4 -0
  21. package/dist/adapters/cli/codex-app.d.ts.map +1 -0
  22. package/dist/adapters/cli/codex-app.js +72 -0
  23. package/dist/adapters/cli/codex-app.js.map +1 -0
  24. package/dist/adapters/cli/codex.d.ts.map +1 -1
  25. package/dist/adapters/cli/codex.js +6 -1
  26. package/dist/adapters/cli/codex.js.map +1 -1
  27. package/dist/adapters/cli/cursor.d.ts.map +1 -1
  28. package/dist/adapters/cli/cursor.js +58 -12
  29. package/dist/adapters/cli/cursor.js.map +1 -1
  30. package/dist/adapters/cli/gemini.d.ts.map +1 -1
  31. package/dist/adapters/cli/gemini.js +5 -1
  32. package/dist/adapters/cli/gemini.js.map +1 -1
  33. package/dist/adapters/cli/hermes.d.ts +4 -0
  34. package/dist/adapters/cli/hermes.d.ts.map +1 -0
  35. package/dist/adapters/cli/hermes.js +40 -0
  36. package/dist/adapters/cli/hermes.js.map +1 -0
  37. package/dist/adapters/cli/mira.d.ts +4 -0
  38. package/dist/adapters/cli/mira.d.ts.map +1 -0
  39. package/dist/adapters/cli/mira.js +67 -0
  40. package/dist/adapters/cli/mira.js.map +1 -0
  41. package/dist/adapters/cli/mtr.d.ts +5 -0
  42. package/dist/adapters/cli/mtr.d.ts.map +1 -0
  43. package/dist/adapters/cli/mtr.js +62 -0
  44. package/dist/adapters/cli/mtr.js.map +1 -0
  45. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  46. package/dist/adapters/cli/opencode.js +19 -1
  47. package/dist/adapters/cli/opencode.js.map +1 -1
  48. package/dist/adapters/cli/registry.d.ts +5 -1
  49. package/dist/adapters/cli/registry.d.ts.map +1 -1
  50. package/dist/adapters/cli/registry.js +22 -2
  51. package/dist/adapters/cli/registry.js.map +1 -1
  52. package/dist/adapters/cli/shared-hints.d.ts +1 -1
  53. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  54. package/dist/adapters/cli/shared-hints.js +2 -1
  55. package/dist/adapters/cli/shared-hints.js.map +1 -1
  56. package/dist/adapters/cli/types.d.ts +35 -2
  57. package/dist/adapters/cli/types.d.ts.map +1 -1
  58. package/dist/adapters/hook-command.d.ts +18 -0
  59. package/dist/adapters/hook-command.d.ts.map +1 -0
  60. package/dist/adapters/hook-command.js +38 -0
  61. package/dist/adapters/hook-command.js.map +1 -0
  62. package/dist/adapters/hook-installer.d.ts +14 -0
  63. package/dist/adapters/hook-installer.d.ts.map +1 -0
  64. package/dist/adapters/hook-installer.js +192 -0
  65. package/dist/adapters/hook-installer.js.map +1 -0
  66. package/dist/bot-registry.d.ts +59 -0
  67. package/dist/bot-registry.d.ts.map +1 -1
  68. package/dist/bot-registry.js +67 -0
  69. package/dist/bot-registry.js.map +1 -1
  70. package/dist/cli/bots-list-output.d.ts +8 -0
  71. package/dist/cli/bots-list-output.d.ts.map +1 -1
  72. package/dist/cli/bots-list-output.js +9 -0
  73. package/dist/cli/bots-list-output.js.map +1 -1
  74. package/dist/cli.d.ts +15 -1
  75. package/dist/cli.d.ts.map +1 -1
  76. package/dist/cli.js +603 -106
  77. package/dist/cli.js.map +1 -1
  78. package/dist/codex-app-runner.d.ts +3 -0
  79. package/dist/codex-app-runner.d.ts.map +1 -0
  80. package/dist/codex-app-runner.js +512 -0
  81. package/dist/codex-app-runner.js.map +1 -0
  82. package/dist/config.d.ts +11 -2
  83. package/dist/config.d.ts.map +1 -1
  84. package/dist/config.js +17 -4
  85. package/dist/config.js.map +1 -1
  86. package/dist/core/ask-api.d.ts +47 -0
  87. package/dist/core/ask-api.d.ts.map +1 -0
  88. package/dist/core/ask-api.js +139 -0
  89. package/dist/core/ask-api.js.map +1 -0
  90. package/dist/core/ask-args.d.ts +53 -0
  91. package/dist/core/ask-args.d.ts.map +1 -0
  92. package/dist/core/ask-args.js +122 -0
  93. package/dist/core/ask-args.js.map +1 -0
  94. package/dist/core/ask-broker.d.ts +98 -0
  95. package/dist/core/ask-broker.d.ts.map +1 -0
  96. package/dist/core/ask-broker.js +329 -0
  97. package/dist/core/ask-broker.js.map +1 -0
  98. package/dist/core/ask-hook/claude-code.d.ts +50 -0
  99. package/dist/core/ask-hook/claude-code.d.ts.map +1 -0
  100. package/dist/core/ask-hook/claude-code.js +145 -0
  101. package/dist/core/ask-hook/claude-code.js.map +1 -0
  102. package/dist/core/ask-hook/codex.d.ts +43 -0
  103. package/dist/core/ask-hook/codex.d.ts.map +1 -0
  104. package/dist/core/ask-hook/codex.js +69 -0
  105. package/dist/core/ask-hook/codex.js.map +1 -0
  106. package/dist/core/ask-hook/opencode.d.ts +41 -0
  107. package/dist/core/ask-hook/opencode.d.ts.map +1 -0
  108. package/dist/core/ask-hook/opencode.js +108 -0
  109. package/dist/core/ask-hook/opencode.js.map +1 -0
  110. package/dist/core/ask-hook/registry.d.ts +3 -0
  111. package/dist/core/ask-hook/registry.d.ts.map +1 -0
  112. package/dist/core/ask-hook/registry.js +12 -0
  113. package/dist/core/ask-hook/registry.js.map +1 -0
  114. package/dist/core/ask-hook/types.d.ts +26 -0
  115. package/dist/core/ask-hook/types.d.ts.map +1 -0
  116. package/dist/core/ask-hook/types.js +2 -0
  117. package/dist/core/ask-hook/types.js.map +1 -0
  118. package/dist/core/ask-types.d.ts +146 -0
  119. package/dist/core/ask-types.d.ts.map +1 -0
  120. package/dist/core/ask-types.js +18 -0
  121. package/dist/core/ask-types.js.map +1 -0
  122. package/dist/core/command-handler.d.ts +20 -0
  123. package/dist/core/command-handler.d.ts.map +1 -1
  124. package/dist/core/command-handler.js +774 -311
  125. package/dist/core/command-handler.js.map +1 -1
  126. package/dist/core/dashboard-ipc-server.d.ts +2 -0
  127. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  128. package/dist/core/dashboard-ipc-server.js +222 -2
  129. package/dist/core/dashboard-ipc-server.js.map +1 -1
  130. package/dist/core/role-resolver.d.ts +17 -1
  131. package/dist/core/role-resolver.d.ts.map +1 -1
  132. package/dist/core/role-resolver.js +64 -10
  133. package/dist/core/role-resolver.js.map +1 -1
  134. package/dist/core/session-discovery.d.ts.map +1 -1
  135. package/dist/core/session-discovery.js +19 -5
  136. package/dist/core/session-discovery.js.map +1 -1
  137. package/dist/core/session-manager.d.ts +1 -1
  138. package/dist/core/session-manager.d.ts.map +1 -1
  139. package/dist/core/session-manager.js +37 -20
  140. package/dist/core/session-manager.js.map +1 -1
  141. package/dist/core/trigger-session.d.ts +9 -0
  142. package/dist/core/trigger-session.d.ts.map +1 -0
  143. package/dist/core/trigger-session.js +158 -0
  144. package/dist/core/trigger-session.js.map +1 -0
  145. package/dist/core/types.d.ts +5 -0
  146. package/dist/core/types.d.ts.map +1 -1
  147. package/dist/core/types.js.map +1 -1
  148. package/dist/core/worker-pool.d.ts +141 -0
  149. package/dist/core/worker-pool.d.ts.map +1 -1
  150. package/dist/core/worker-pool.js +543 -24
  151. package/dist/core/worker-pool.js.map +1 -1
  152. package/dist/daemon.d.ts.map +1 -1
  153. package/dist/daemon.js +213 -58
  154. package/dist/daemon.js.map +1 -1
  155. package/dist/dashboard/auth.d.ts +6 -1
  156. package/dist/dashboard/auth.d.ts.map +1 -1
  157. package/dist/dashboard/auth.js +9 -1
  158. package/dist/dashboard/auth.js.map +1 -1
  159. package/dist/dashboard/connector-api.d.ts +3 -0
  160. package/dist/dashboard/connector-api.d.ts.map +1 -0
  161. package/dist/dashboard/connector-api.js +351 -0
  162. package/dist/dashboard/connector-api.js.map +1 -0
  163. package/dist/dashboard/federated-group-core.d.ts +54 -0
  164. package/dist/dashboard/federated-group-core.d.ts.map +1 -0
  165. package/dist/dashboard/federated-group-core.js +165 -0
  166. package/dist/dashboard/federated-group-core.js.map +1 -0
  167. package/dist/dashboard/federation-api.d.ts +42 -0
  168. package/dist/dashboard/federation-api.d.ts.map +1 -0
  169. package/dist/dashboard/federation-api.js +408 -0
  170. package/dist/dashboard/federation-api.js.map +1 -0
  171. package/dist/dashboard/federation-spoke-api.d.ts +76 -0
  172. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
  173. package/dist/dashboard/federation-spoke-api.js +618 -0
  174. package/dist/dashboard/federation-spoke-api.js.map +1 -0
  175. package/dist/dashboard/team-group.d.ts +18 -0
  176. package/dist/dashboard/team-group.d.ts.map +1 -0
  177. package/dist/dashboard/team-group.js +7 -0
  178. package/dist/dashboard/team-group.js.map +1 -0
  179. package/dist/dashboard/trigger-api.d.ts +13 -0
  180. package/dist/dashboard/trigger-api.d.ts.map +1 -0
  181. package/dist/dashboard/trigger-api.js +77 -0
  182. package/dist/dashboard/trigger-api.js.map +1 -0
  183. package/dist/dashboard/web/app.js +8 -0
  184. package/dist/dashboard/web/app.js.map +1 -1
  185. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  186. package/dist/dashboard/web/bot-defaults.js +205 -21
  187. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  188. package/dist/dashboard/web/connectors.d.ts +2 -0
  189. package/dist/dashboard/web/connectors.d.ts.map +1 -0
  190. package/dist/dashboard/web/connectors.js +187 -0
  191. package/dist/dashboard/web/connectors.js.map +1 -0
  192. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  193. package/dist/dashboard/web/i18n.js +43 -5
  194. package/dist/dashboard/web/i18n.js.map +1 -1
  195. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  196. package/dist/dashboard/web/sessions.js +4 -0
  197. package/dist/dashboard/web/sessions.js.map +1 -1
  198. package/dist/dashboard/web/team-federation.d.ts +3 -0
  199. package/dist/dashboard/web/team-federation.d.ts.map +1 -0
  200. package/dist/dashboard/web/team-federation.js +487 -0
  201. package/dist/dashboard/web/team-federation.js.map +1 -0
  202. package/dist/dashboard/web/workflows.js +3 -3
  203. package/dist/dashboard/web/workflows.js.map +1 -1
  204. package/dist/dashboard/webhook-routes.d.ts +19 -0
  205. package/dist/dashboard/webhook-routes.d.ts.map +1 -0
  206. package/dist/dashboard/webhook-routes.js +321 -0
  207. package/dist/dashboard/webhook-routes.js.map +1 -0
  208. package/dist/dashboard/workflow-api.d.ts +8 -1
  209. package/dist/dashboard/workflow-api.d.ts.map +1 -1
  210. package/dist/dashboard/workflow-api.js +19 -4
  211. package/dist/dashboard/workflow-api.js.map +1 -1
  212. package/dist/dashboard-web/app.js +539 -375
  213. package/dist/dashboard-web/index.html +3 -1
  214. package/dist/dashboard-web/style.css +22 -0
  215. package/dist/dashboard.js +199 -2
  216. package/dist/dashboard.js.map +1 -1
  217. package/dist/i18n/en.d.ts.map +1 -1
  218. package/dist/i18n/en.js +104 -11
  219. package/dist/i18n/en.js.map +1 -1
  220. package/dist/i18n/zh.d.ts.map +1 -1
  221. package/dist/i18n/zh.js +104 -11
  222. package/dist/i18n/zh.js.map +1 -1
  223. package/dist/im/lark/ask-card.d.ts +55 -0
  224. package/dist/im/lark/ask-card.d.ts.map +1 -0
  225. package/dist/im/lark/ask-card.js +328 -0
  226. package/dist/im/lark/ask-card.js.map +1 -0
  227. package/dist/im/lark/card-builder.d.ts +108 -3
  228. package/dist/im/lark/card-builder.d.ts.map +1 -1
  229. package/dist/im/lark/card-builder.js +480 -50
  230. package/dist/im/lark/card-builder.js.map +1 -1
  231. package/dist/im/lark/card-handler.d.ts.map +1 -1
  232. package/dist/im/lark/card-handler.js +241 -18
  233. package/dist/im/lark/card-handler.js.map +1 -1
  234. package/dist/im/lark/client.d.ts +83 -0
  235. package/dist/im/lark/client.d.ts.map +1 -1
  236. package/dist/im/lark/client.js +286 -70
  237. package/dist/im/lark/client.js.map +1 -1
  238. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  239. package/dist/im/lark/event-dispatcher.js +29 -4
  240. package/dist/im/lark/event-dispatcher.js.map +1 -1
  241. package/dist/im/lark/grant-command.d.ts +2 -1
  242. package/dist/im/lark/grant-command.d.ts.map +1 -1
  243. package/dist/im/lark/grant-command.js +3 -2
  244. package/dist/im/lark/grant-command.js.map +1 -1
  245. package/dist/im/lark/identity-cache.d.ts.map +1 -1
  246. package/dist/im/lark/identity-cache.js +3 -3
  247. package/dist/im/lark/identity-cache.js.map +1 -1
  248. package/dist/im/lark/md-card.d.ts +20 -2
  249. package/dist/im/lark/md-card.d.ts.map +1 -1
  250. package/dist/im/lark/md-card.js +49 -17
  251. package/dist/im/lark/md-card.js.map +1 -1
  252. package/dist/im/lark/message-parser.d.ts.map +1 -1
  253. package/dist/im/lark/message-parser.js +87 -31
  254. package/dist/im/lark/message-parser.js.map +1 -1
  255. package/dist/im/lark/workflow-card-handler.d.ts +2 -2
  256. package/dist/im/lark/workflow-card-handler.d.ts.map +1 -1
  257. package/dist/im/lark/workflow-card-handler.js +12 -1
  258. package/dist/im/lark/workflow-card-handler.js.map +1 -1
  259. package/dist/im/lark/workflow-progress-card.d.ts.map +1 -1
  260. package/dist/im/lark/workflow-progress-card.js +53 -0
  261. package/dist/im/lark/workflow-progress-card.js.map +1 -1
  262. package/dist/mira-output.d.ts +3 -0
  263. package/dist/mira-output.d.ts.map +1 -0
  264. package/dist/mira-output.js +136 -0
  265. package/dist/mira-output.js.map +1 -0
  266. package/dist/mira-runner.d.ts +3 -0
  267. package/dist/mira-runner.d.ts.map +1 -0
  268. package/dist/mira-runner.js +534 -0
  269. package/dist/mira-runner.js.map +1 -0
  270. package/dist/services/bot-owner-store.d.ts +28 -0
  271. package/dist/services/bot-owner-store.d.ts.map +1 -0
  272. package/dist/services/bot-owner-store.js +82 -0
  273. package/dist/services/bot-owner-store.js.map +1 -0
  274. package/dist/services/bot-profile-store.d.ts +16 -0
  275. package/dist/services/bot-profile-store.d.ts.map +1 -0
  276. package/dist/services/bot-profile-store.js +98 -0
  277. package/dist/services/bot-profile-store.js.map +1 -0
  278. package/dist/services/brand-store.d.ts +15 -0
  279. package/dist/services/brand-store.d.ts.map +1 -0
  280. package/dist/services/brand-store.js +47 -0
  281. package/dist/services/brand-store.js.map +1 -0
  282. package/dist/services/card-prefs-store.d.ts +20 -0
  283. package/dist/services/card-prefs-store.d.ts.map +1 -0
  284. package/dist/services/card-prefs-store.js +82 -0
  285. package/dist/services/card-prefs-store.js.map +1 -0
  286. package/dist/services/codex-bridge-queue.d.ts +1 -0
  287. package/dist/services/codex-bridge-queue.d.ts.map +1 -1
  288. package/dist/services/codex-bridge-queue.js +23 -0
  289. package/dist/services/codex-bridge-queue.js.map +1 -1
  290. package/dist/services/codex-transcript.d.ts +1 -0
  291. package/dist/services/codex-transcript.d.ts.map +1 -1
  292. package/dist/services/codex-transcript.js.map +1 -1
  293. package/dist/services/connector-store.d.ts +58 -0
  294. package/dist/services/connector-store.d.ts.map +1 -0
  295. package/dist/services/connector-store.js +79 -0
  296. package/dist/services/connector-store.js.map +1 -0
  297. package/dist/services/deployment-identity.d.ts +22 -0
  298. package/dist/services/deployment-identity.d.ts.map +1 -0
  299. package/dist/services/deployment-identity.js +67 -0
  300. package/dist/services/deployment-identity.js.map +1 -0
  301. package/dist/services/federation-membership-store.d.ts +23 -0
  302. package/dist/services/federation-membership-store.d.ts.map +1 -0
  303. package/dist/services/federation-membership-store.js +66 -0
  304. package/dist/services/federation-membership-store.js.map +1 -0
  305. package/dist/services/federation-roster.d.ts +54 -0
  306. package/dist/services/federation-roster.d.ts.map +1 -0
  307. package/dist/services/federation-roster.js +51 -0
  308. package/dist/services/federation-roster.js.map +1 -0
  309. package/dist/services/federation-store.d.ts +76 -0
  310. package/dist/services/federation-store.d.ts.map +1 -0
  311. package/dist/services/federation-store.js +133 -0
  312. package/dist/services/federation-store.js.map +1 -0
  313. package/dist/services/grant-store.d.ts +12 -2
  314. package/dist/services/grant-store.d.ts.map +1 -1
  315. package/dist/services/grant-store.js +51 -4
  316. package/dist/services/grant-store.js.map +1 -1
  317. package/dist/services/group-creator.d.ts +10 -0
  318. package/dist/services/group-creator.d.ts.map +1 -1
  319. package/dist/services/group-creator.js +26 -1
  320. package/dist/services/group-creator.js.map +1 -1
  321. package/dist/services/groups-store.d.ts +30 -0
  322. package/dist/services/groups-store.d.ts.map +1 -1
  323. package/dist/services/groups-store.js +85 -12
  324. package/dist/services/groups-store.js.map +1 -1
  325. package/dist/services/hermes-transcript.d.ts +7 -0
  326. package/dist/services/hermes-transcript.d.ts.map +1 -0
  327. package/dist/services/hermes-transcript.js +117 -0
  328. package/dist/services/hermes-transcript.js.map +1 -0
  329. package/dist/services/invite-store.d.ts +28 -0
  330. package/dist/services/invite-store.d.ts.map +1 -0
  331. package/dist/services/invite-store.js +85 -0
  332. package/dist/services/invite-store.js.map +1 -0
  333. package/dist/services/pairing-store.d.ts +47 -0
  334. package/dist/services/pairing-store.d.ts.map +1 -0
  335. package/dist/services/pairing-store.js +132 -0
  336. package/dist/services/pairing-store.js.map +1 -0
  337. package/dist/services/project-scanner.d.ts +10 -0
  338. package/dist/services/project-scanner.d.ts.map +1 -1
  339. package/dist/services/project-scanner.js +11 -0
  340. package/dist/services/project-scanner.js.map +1 -1
  341. package/dist/services/relay-picker.d.ts +22 -0
  342. package/dist/services/relay-picker.d.ts.map +1 -0
  343. package/dist/services/relay-picker.js +62 -0
  344. package/dist/services/relay-picker.js.map +1 -0
  345. package/dist/services/send-policy.d.ts +55 -0
  346. package/dist/services/send-policy.d.ts.map +1 -0
  347. package/dist/services/send-policy.js +47 -0
  348. package/dist/services/send-policy.js.map +1 -0
  349. package/dist/services/session-store.js +1 -1
  350. package/dist/services/session-store.js.map +1 -1
  351. package/dist/services/team-roster.d.ts +38 -0
  352. package/dist/services/team-roster.d.ts.map +1 -0
  353. package/dist/services/team-roster.js +82 -0
  354. package/dist/services/team-roster.js.map +1 -0
  355. package/dist/services/team-store.d.ts +54 -0
  356. package/dist/services/team-store.d.ts.map +1 -0
  357. package/dist/services/team-store.js +156 -0
  358. package/dist/services/team-store.js.map +1 -0
  359. package/dist/services/trigger-log-store.d.ts +46 -0
  360. package/dist/services/trigger-log-store.d.ts.map +1 -0
  361. package/dist/services/trigger-log-store.js +132 -0
  362. package/dist/services/trigger-log-store.js.map +1 -0
  363. package/dist/services/trigger-types.d.ts +57 -0
  364. package/dist/services/trigger-types.d.ts.map +1 -0
  365. package/dist/services/trigger-types.js +28 -0
  366. package/dist/services/trigger-types.js.map +1 -0
  367. package/dist/services/webhook-key.d.ts +16 -0
  368. package/dist/services/webhook-key.d.ts.map +1 -0
  369. package/dist/services/webhook-key.js +123 -0
  370. package/dist/services/webhook-key.js.map +1 -0
  371. package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
  372. package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
  373. package/dist/services/webhook-lifecycle-extractors.js +59 -0
  374. package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
  375. package/dist/services/webhook-lifecycle-store.d.ts +45 -0
  376. package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
  377. package/dist/services/webhook-lifecycle-store.js +159 -0
  378. package/dist/services/webhook-lifecycle-store.js.map +1 -0
  379. package/dist/setup/bot-config-editor.d.ts +8 -1
  380. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  381. package/dist/setup/bot-config-editor.js +20 -2
  382. package/dist/setup/bot-config-editor.js.map +1 -1
  383. package/dist/setup/ensure-tmux.d.ts +0 -22
  384. package/dist/setup/ensure-tmux.d.ts.map +1 -1
  385. package/dist/setup/ensure-tmux.js +25 -1
  386. package/dist/setup/ensure-tmux.js.map +1 -1
  387. package/dist/setup/verify-permissions.d.ts.map +1 -1
  388. package/dist/setup/verify-permissions.js +15 -1
  389. package/dist/setup/verify-permissions.js.map +1 -1
  390. package/dist/skills/definitions.d.ts +2 -0
  391. package/dist/skills/definitions.d.ts.map +1 -1
  392. package/dist/skills/definitions.js +178 -12
  393. package/dist/skills/definitions.js.map +1 -1
  394. package/dist/skills/installer.d.ts +34 -0
  395. package/dist/skills/installer.d.ts.map +1 -1
  396. package/dist/skills/installer.js +119 -2
  397. package/dist/skills/installer.js.map +1 -1
  398. package/dist/types.d.ts +25 -0
  399. package/dist/types.d.ts.map +1 -1
  400. package/dist/utils/bot-routing.d.ts +50 -0
  401. package/dist/utils/bot-routing.d.ts.map +1 -1
  402. package/dist/utils/bot-routing.js +83 -0
  403. package/dist/utils/bot-routing.js.map +1 -1
  404. package/dist/utils/daemon-discovery.d.ts +11 -0
  405. package/dist/utils/daemon-discovery.d.ts.map +1 -0
  406. package/dist/utils/daemon-discovery.js +59 -0
  407. package/dist/utils/daemon-discovery.js.map +1 -0
  408. package/dist/utils/user-token.d.ts.map +1 -1
  409. package/dist/utils/user-token.js +0 -2
  410. package/dist/utils/user-token.js.map +1 -1
  411. package/dist/worker.js +198 -27
  412. package/dist/worker.js.map +1 -1
  413. package/dist/workflows/attempt-resume.d.ts.map +1 -1
  414. package/dist/workflows/attempt-resume.js +2 -2
  415. package/dist/workflows/attempt-resume.js.map +1 -1
  416. package/dist/workflows/definition.d.ts +412 -9
  417. package/dist/workflows/definition.d.ts.map +1 -1
  418. package/dist/workflows/definition.js +238 -3
  419. package/dist/workflows/definition.js.map +1 -1
  420. package/dist/workflows/events/payloads.d.ts +114 -11
  421. package/dist/workflows/events/payloads.d.ts.map +1 -1
  422. package/dist/workflows/events/payloads.js +46 -0
  423. package/dist/workflows/events/payloads.js.map +1 -1
  424. package/dist/workflows/events/replay.d.ts +21 -0
  425. package/dist/workflows/events/replay.d.ts.map +1 -1
  426. package/dist/workflows/events/replay.js +103 -0
  427. package/dist/workflows/events/replay.js.map +1 -1
  428. package/dist/workflows/events/schema.d.ts +1301 -606
  429. package/dist/workflows/events/schema.d.ts.map +1 -1
  430. package/dist/workflows/events/schema.js +37 -1
  431. package/dist/workflows/events/schema.js.map +1 -1
  432. package/dist/workflows/events/types.d.ts +5 -1
  433. package/dist/workflows/events/types.d.ts.map +1 -1
  434. package/dist/workflows/loader.d.ts +14 -0
  435. package/dist/workflows/loader.d.ts.map +1 -1
  436. package/dist/workflows/loader.js +27 -0
  437. package/dist/workflows/loader.js.map +1 -1
  438. package/dist/workflows/loop.js +58 -0
  439. package/dist/workflows/loop.js.map +1 -1
  440. package/dist/workflows/ops-projection.d.ts +58 -0
  441. package/dist/workflows/ops-projection.d.ts.map +1 -1
  442. package/dist/workflows/ops-projection.js +74 -0
  443. package/dist/workflows/ops-projection.js.map +1 -1
  444. package/dist/workflows/orchestrator.d.ts +65 -1
  445. package/dist/workflows/orchestrator.d.ts.map +1 -1
  446. package/dist/workflows/orchestrator.js +486 -74
  447. package/dist/workflows/orchestrator.js.map +1 -1
  448. package/dist/workflows/output-binding.d.ts +8 -1
  449. package/dist/workflows/output-binding.d.ts.map +1 -1
  450. package/dist/workflows/output-binding.js +75 -11
  451. package/dist/workflows/output-binding.js.map +1 -1
  452. package/dist/workflows/runtime.d.ts +1 -1
  453. package/dist/workflows/runtime.d.ts.map +1 -1
  454. package/dist/workflows/runtime.js +39 -4
  455. package/dist/workflows/runtime.js.map +1 -1
  456. package/dist/workflows/trigger-from-envelope.d.ts +13 -0
  457. package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
  458. package/dist/workflows/trigger-from-envelope.js +67 -0
  459. package/dist/workflows/trigger-from-envelope.js.map +1 -0
  460. package/dist/workflows/wait.d.ts +23 -2
  461. package/dist/workflows/wait.d.ts.map +1 -1
  462. package/dist/workflows/wait.js +39 -17
  463. package/dist/workflows/wait.js.map +1 -1
  464. package/package.json +1 -1
  465. package/dist/services/feishu-task-client.d.ts +0 -28
  466. package/dist/services/feishu-task-client.d.ts.map +0 -1
  467. package/dist/services/feishu-task-client.js +0 -123
  468. package/dist/services/feishu-task-client.js.map +0 -1
  469. package/dist/services/task-store.d.ts +0 -37
  470. package/dist/services/task-store.d.ts.map +0 -1
  471. package/dist/services/task-store.js +0 -115
  472. package/dist/services/task-store.js.map +0 -1
package/dist/daemon.js CHANGED
@@ -27,8 +27,8 @@ import { scanMultipleProjects } from './services/project-scanner.js';
27
27
  import { buildRepoSelectCard, buildStreamingCard, getCliDisplayName } from './im/lark/card-builder.js';
28
28
  import { t as tr, botLocale, localeForBot } from './i18n/index.js';
29
29
  import { createCliAdapterSync } from './adapters/cli/registry.js';
30
- import { initWorkerPool, setActiveSessionsRegistry, forkWorker, killWorker, scheduleCardPatch, setCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, } from './core/worker-pool.js';
31
- import { ipcRoute, jsonRes, readJsonBody, setBotName, setLarkAppId, startIpcServer } from './core/dashboard-ipc-server.js';
30
+ import { initWorkerPool, setActiveSessionsRegistry, forkWorker, killWorker, scheduleCardPatch, setCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, ensureCliEnv, writableTerminalLinkFor, } from './core/worker-pool.js';
31
+ import { ipcRoute, jsonRes, readJsonBody, setBotName, setLarkAppId, startIpcServer, setWorkflowRunner } from './core/dashboard-ipc-server.js';
32
32
  import { saveFrozenCards } from './services/frozen-card-store.js';
33
33
  import { DAEMON_COMMANDS, PASSTHROUGH_COMMANDS, handleCommand, parseSlashCommandInvocation, parseForceTopicInvocation } from './core/command-handler.js';
34
34
  import { findInheritablePeer } from './core/inherit-peer.js';
@@ -60,6 +60,9 @@ import { resolveWait } from './workflows/wait.js';
60
60
  import { replay } from './workflows/events/replay.js';
61
61
  import { isValidRunId, readRunSnapshot } from './workflows/ops-projection.js';
62
62
  import { AttemptResumeManager } from './workflows/attempt-resume.js';
63
+ import { setCardDispatcher as setAskCardDispatcher, registerAsk as registerAskBroker, } from './core/ask-broker.js';
64
+ import { parseAskBody, resolveAskApprovers } from './core/ask-api.js';
65
+ import { createLarkAskCardDispatcher } from './im/lark/ask-card.js';
63
66
  // ─── State ───────────────────────────────────────────────────────────────────
64
67
  const activeSessions = new Map();
65
68
  const workflowEventWatchers = new Map();
@@ -724,7 +727,11 @@ async function resolveDashboardWait(runId, resolution, comment) {
724
727
  resolution,
725
728
  by: 'dashboard',
726
729
  comment,
727
- });
730
+ },
731
+ // v0.2: pass def so resolveWait can write activitySucceeded for
732
+ // `decision` node reject instead of activityFailed. entry.ctx.def
733
+ // is the live, in-memory snapshot already loaded for this run.
734
+ { def: entry.ctx.def });
728
735
  const after = replay(await entry.ctx.log.readAll());
729
736
  // Fire-and-forget re-drive — same pattern as Lark card path
730
737
  // (workflowApprovalResolved hook). Don't await; the dashboard caller
@@ -929,7 +936,7 @@ function beginNewTurn(ds, title) {
929
936
  const dsBotCfg = getBot(ds.larkAppId).config;
930
937
  const prevTitle = ds.currentTurnTitle || ds.session.title || getCliDisplayName(dsBotCfg.cliId);
931
938
  const prevMode = ds.displayMode ?? 'hidden';
932
- const frozenCard = buildStreamingCard(ds.session.sessionId, sessionAnchorId(ds), readUrl, prevTitle, ds.lastScreenContent ?? '', previousStatus, dsBotCfg.cliId, prevMode, ds.streamCardNonce, ds.currentImageKey, !!ds.adoptedFrom, false, localeForBot(ds.larkAppId), previousUsageLimit);
939
+ const frozenCard = buildStreamingCard(ds.session.sessionId, sessionAnchorId(ds), readUrl, prevTitle, ds.lastScreenContent ?? '', previousStatus, dsBotCfg.cliId, prevMode, ds.streamCardNonce, ds.currentImageKey, !!ds.adoptedFrom, false, localeForBot(ds.larkAppId), previousUsageLimit, writableTerminalLinkFor(ds));
933
940
  scheduleCardPatch(ds, frozenCard);
934
941
  if (ds.streamCardNonce && ds.streamCardId !== CARD_POSTING_SENTINEL) {
935
942
  if (!ds.frozenCards)
@@ -1074,6 +1081,28 @@ ipcRoute('POST', '/api/workflows/runs/:runId/cancel', async (req, res, params) =
1074
1081
  }
1075
1082
  return jsonRes(res, 200, result);
1076
1083
  });
1084
+ /** Heavy deps for triggerWorkflowRun, shared by the catalog `…/run` route and
1085
+ * the `/api/trigger` (kind=workflow) thin layer. */
1086
+ function workflowTriggerDeps() {
1087
+ return {
1088
+ spawnSubagent: workflowSpawnFn(),
1089
+ botResolver: resolveBotSnapshot,
1090
+ makeRuntimeContext: (log, def, spawnSubagent) => ({
1091
+ log,
1092
+ def,
1093
+ spawnSubagent,
1094
+ hostExecutors: createDefaultHostExecutorRegistry(),
1095
+ reconcilers: createDefaultProviderReconcilers(),
1096
+ loadEffectInput: (activityId, attemptId) => loadEffectInputSidecar(log, activityId, attemptId),
1097
+ }),
1098
+ attachRuntime: (runId, ctx) => attachWorkflowEventWatcher(runId, ctx),
1099
+ driveRun: (runId) => {
1100
+ driveWorkflowRun(runId).catch((err) => {
1101
+ logger.warn(`[workflow:${runId}] trigger drive failed: ${err instanceof Error ? err.message : String(err)}`);
1102
+ });
1103
+ },
1104
+ };
1105
+ }
1077
1106
  ipcRoute('POST', '/api/workflows/definitions/:id/run', async (req, res, params) => {
1078
1107
  const workflowId = params.id;
1079
1108
  if (!isValidWorkflowId(workflowId)) {
@@ -1106,24 +1135,7 @@ ipcRoute('POST', '/api/workflows/definitions/:id/run', async (req, res, params)
1106
1135
  rawParams,
1107
1136
  chatBinding,
1108
1137
  initiator: 'dashboard',
1109
- }, {
1110
- spawnSubagent: workflowSpawnFn(),
1111
- botResolver: resolveBotSnapshot,
1112
- makeRuntimeContext: (log, def, spawnSubagent) => ({
1113
- log,
1114
- def,
1115
- spawnSubagent,
1116
- hostExecutors: createDefaultHostExecutorRegistry(),
1117
- reconcilers: createDefaultProviderReconcilers(),
1118
- loadEffectInput: (activityId, attemptId) => loadEffectInputSidecar(log, activityId, attemptId),
1119
- }),
1120
- attachRuntime: (runId, ctx) => attachWorkflowEventWatcher(runId, ctx),
1121
- driveRun: (runId) => {
1122
- driveWorkflowRun(runId).catch((err) => {
1123
- logger.warn(`[workflow:${runId}] dashboard-trigger drive failed: ${err instanceof Error ? err.message : String(err)}`);
1124
- });
1125
- },
1126
- });
1138
+ }, workflowTriggerDeps());
1127
1139
  if (!result.ok) {
1128
1140
  const status = result.error === 'unknown_workflow' ? 404 :
1129
1141
  result.error === 'invalid_params' ? 400 :
@@ -1132,6 +1144,83 @@ ipcRoute('POST', '/api/workflows/definitions/:id/run', async (req, res, params)
1132
1144
  }
1133
1145
  return jsonRes(res, 200, result);
1134
1146
  });
1147
+ // ─── botmux ask v0.1.7 IPC route ─────────────────────────────────────────────
1148
+ //
1149
+ // CLI side: `botmux ask buttons --options "..."` POSTs here and keeps the
1150
+ // connection open until the broker settles the ask. Long keep-alive is OK —
1151
+ // the request's lifetime is bounded by `body.timeoutMs` which the broker
1152
+ // enforces. Default fetch on the CLI side has no read timeout.
1153
+ ipcRoute('POST', '/api/asks', async (req, res) => {
1154
+ let raw;
1155
+ try {
1156
+ raw = await readJsonBody(req);
1157
+ }
1158
+ catch {
1159
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
1160
+ }
1161
+ const parsed = parseAskBody(raw);
1162
+ if ('error' in parsed)
1163
+ return jsonRes(res, 400, { ok: false, error: parsed.error });
1164
+ const approvers = resolveAskApprovers({
1165
+ larkAppId: parsed.larkAppId,
1166
+ sessionId: parsed.sessionId,
1167
+ explicit: parsed.approvers,
1168
+ getBotAllowedUsers: (id) => {
1169
+ try {
1170
+ return getBot(id).resolvedAllowedUsers;
1171
+ }
1172
+ catch {
1173
+ return [];
1174
+ }
1175
+ },
1176
+ getSessionOwner: (sid) => {
1177
+ for (const ds of activeSessions.values()) {
1178
+ if (ds.session.sessionId === sid)
1179
+ return ds.ownerOpenId;
1180
+ }
1181
+ return undefined;
1182
+ },
1183
+ });
1184
+ if (approvers.size === 0) {
1185
+ // Nobody can answer — fail loud rather than registering a
1186
+ // guaranteed-timeout. CLI side maps this to exit 2.
1187
+ return jsonRes(res, 400, { ok: false, error: 'no_approvers' });
1188
+ }
1189
+ const result = await registerAskBroker({
1190
+ larkAppId: parsed.larkAppId,
1191
+ chatId: parsed.chatId,
1192
+ rootMessageId: parsed.rootMessageId,
1193
+ sessionId: parsed.sessionId,
1194
+ approvers,
1195
+ questions: parsed.questions,
1196
+ timeoutMs: parsed.timeoutMs,
1197
+ });
1198
+ return jsonRes(res, 200, result);
1199
+ });
1200
+ // ─── adopt-session 查询端点 ───────────────────────────────────────────────────
1201
+ // CLI side(botmux hook)通过祖先 PID 匹配 adopt 会话,路由 askUserQuestion。
1202
+ // GET /api/adopt-session/:pid — 返回该 pid 对应的 adopt 会话路由信息。
1203
+ // 仅匹配**当前活跃**的 adopt 会话(按 originalCliPid)。残留风险:OS 的 PID 复用——
1204
+ // 若原 adopt 的 Claude 已退出、同号 PID 被别的进程复用,理论上可能误命中;但 hook
1205
+ // 进程是该 Claude 的子孙,只有 Claude 仍在跑时其祖先链里才会出现这个 PID,且 session
1206
+ // 必须仍在 activeSessions 里,复用窗口极小,可接受(不为此引入进程级鉴权)。
1207
+ ipcRoute('GET', '/api/adopt-session/:pid', (_req, res, params) => {
1208
+ const pid = Number(params.pid);
1209
+ if (!Number.isInteger(pid) || pid <= 0) {
1210
+ return jsonRes(res, 400, { ok: false, error: 'bad_pid' });
1211
+ }
1212
+ for (const ds of activeSessions.values()) {
1213
+ if (ds.adoptedFrom?.originalCliPid === pid) {
1214
+ return jsonRes(res, 200, {
1215
+ sessionId: ds.session.sessionId,
1216
+ chatId: ds.chatId,
1217
+ larkAppId: ds.larkAppId,
1218
+ rootMessageId: sessionAnchorId(ds),
1219
+ });
1220
+ }
1221
+ }
1222
+ return jsonRes(res, 404, { ok: false, error: 'no_adopt_session' });
1223
+ });
1135
1224
  function parseTriggerChatBinding(raw) {
1136
1225
  if (!raw || typeof raw !== 'object' || Array.isArray(raw))
1137
1226
  return undefined;
@@ -1222,6 +1311,31 @@ function resolveBotDefaultWorkingDir(larkAppId) {
1222
1311
  `falling back to repo-select card`);
1223
1312
  return undefined;
1224
1313
  }
1314
+ /**
1315
+ * Resolve the pinned working dir for a brand-new topic via the layered lookup:
1316
+ * 1) an existing oncall binding (this bot or a sibling)
1317
+ * 2) this bot's defaultOncall — auto-binds a brand-new chat when the flag is on
1318
+ * (this WRITES state, so it must run identically on every spawn path)
1319
+ * 3) a sibling session's workingDir (cross-bot / chat-scope inheritance)
1320
+ * 4) this bot's `defaultWorkingDir` (pure runtime fallback)
1321
+ * Returns the dir plus the oncall / inherited source so callers can log the reason.
1322
+ * Shared by the normal spawn path and the first-message `/repo` command branch so
1323
+ * both honor the defaultOncall auto-bind the same way.
1324
+ */
1325
+ async function resolvePinnedWorkingDir(ctx) {
1326
+ let oncallEntry = findOncallChatForAnyBot(ctx.chatId);
1327
+ if (!oncallEntry) {
1328
+ oncallEntry = await maybeAutoBindDefaultOncall(ctx.larkAppId, ctx.chatId, ctx.chatType);
1329
+ }
1330
+ const inheritedFrom = !oncallEntry
1331
+ ? findInheritablePeer({ scope: ctx.scope, anchor: ctx.anchor, chatId: ctx.chatId, chatType: ctx.chatType, selfAppId: ctx.larkAppId })
1332
+ : null;
1333
+ const botDefaultWorkingDir = (!oncallEntry && !inheritedFrom)
1334
+ ? resolveBotDefaultWorkingDir(ctx.larkAppId)
1335
+ : undefined;
1336
+ const pinnedWorkingDir = oncallEntry?.workingDir ?? inheritedFrom?.workingDir ?? botDefaultWorkingDir;
1337
+ return { pinnedWorkingDir, oncallEntry, inheritedFrom };
1338
+ }
1225
1339
  async function replyInvalidWorkingDirs(anchor, larkAppId, ds) {
1226
1340
  const bot = getBot(larkAppId);
1227
1341
  const invalid = invalidWorkingDirs({
@@ -1279,6 +1393,7 @@ async function handleNewTopic(data, ctx) {
1279
1393
  logger.info(`[/t] Force-topic invocation: prompt="${forceTopic.prompt.substring(0, 60)}" (scope=${scope}, anchor=${anchor.substring(0, 12)})`);
1280
1394
  }
1281
1395
  const senderOpenId = data.sender?.sender_id?.open_id;
1396
+ const senderUnionId = data.sender?.sender_id?.union_id;
1282
1397
  const botCfg = getBot(larkAppId).config;
1283
1398
  logger.info(`New session: "${content.substring(0, 60)}" (scope=${scope}, anchor=${anchor.substring(0, 12)}, resources: ${resources.length}, active: ${getActiveCount()}, messageId: ${messageId}, chatId: ${chatId})`);
1284
1399
  if (await handleWorkflowCommandIfAny(cmdContent, anchor, chatId, larkAppId, senderOpenId)) {
@@ -1311,9 +1426,26 @@ async function handleNewTopic(data, ctx) {
1311
1426
  const now = Date.now();
1312
1427
  session.larkAppId = larkAppId;
1313
1428
  session.ownerOpenId = senderOpenId;
1429
+ session.ownerUnionId = senderUnionId;
1314
1430
  session.lastCallerOpenId = senderOpenId;
1315
1431
  session.lastMessageAt = new Date(now).toISOString();
1316
1432
  session.scope = scope;
1433
+ // First-message `/repo`: seed the same pending-repo state the card flow
1434
+ // uses, so the `/repo` handler launches the CLI straight away —
1435
+ // `/repo <arg>` in that repo, bare `/repo` in the default workingDir —
1436
+ // instead of taking the mid-session close+recreate path or re-showing the
1437
+ // card. Use the SAME pinned-dir resolver as the normal spawn path (incl.
1438
+ // defaultOncall auto-bind) so a bound/auto-bound chat still launches in the
1439
+ // right place when no arg is given.
1440
+ let cmdPending;
1441
+ if (cmd === '/repo') {
1442
+ const { pinnedWorkingDir } = await resolvePinnedWorkingDir({ scope, anchor, chatId, chatType, larkAppId });
1443
+ if (pinnedWorkingDir)
1444
+ session.workingDir = pinnedWorkingDir;
1445
+ // pendingPrompt is empty (the message *is* the command), so the CLI just
1446
+ // boots and waits for the user's next message; no sender tag needed.
1447
+ cmdPending = { pendingRepo: true, pendingPrompt: '', workingDir: pinnedWorkingDir };
1448
+ }
1317
1449
  sessionStore.updateSession(session);
1318
1450
  activeSessions.set(sessionKey(anchor, larkAppId), {
1319
1451
  session,
@@ -1329,6 +1461,7 @@ async function handleNewTopic(data, ctx) {
1329
1461
  lastMessageAt: now,
1330
1462
  hasHistory: false,
1331
1463
  ownerOpenId: senderOpenId,
1464
+ ...cmdPending,
1332
1465
  });
1333
1466
  // Pass mention-stripped content so /command argument parsing works.
1334
1467
  await handleCommand(cmd, anchor, { ...parsed, content: commandContent }, commandDeps, larkAppId);
@@ -1370,36 +1503,24 @@ async function handleNewTopic(data, ctx) {
1370
1503
  const now = Date.now();
1371
1504
  session.larkAppId = larkAppId;
1372
1505
  session.ownerOpenId = senderOpenId;
1506
+ session.ownerUnionId = senderUnionId;
1507
+ session.lastCallerOpenId = senderOpenId;
1508
+ // First turn of a brand-new topic: seed quoteTarget* so the very first
1509
+ // `botmux send` can --mention-back / 引用 the triggering message (chat scope).
1510
+ // Without this the first reply hits hasQuoteTargetSender=false (exit 2) and
1511
+ // chat-scope首条不引用. Use the event's sender open_id (correct app scope).
1512
+ session.quoteTargetId = parsed.messageId;
1513
+ session.quoteTargetSenderOpenId = senderOpenId;
1514
+ session.quoteTargetSenderIsBot = parsed.senderType === 'app' || parsed.senderType === 'bot';
1373
1515
  session.lastMessageAt = new Date(now).toISOString();
1374
1516
  session.scope = scope;
1375
1517
  sessionStore.updateSession(session);
1376
1518
  messageQueue.ensureQueue(anchor);
1377
1519
  messageQueue.appendMessage(anchor, parsed);
1378
- // Oncall group: pin working dir from the chat-level binding, even if a
1379
- // sibling bot (running in another daemon) is the one that persisted it.
1380
- // Layered lookup:
1381
- // 1) any existing binding (this bot or sibling)
1382
- // 2) this bot's defaultOncall — auto-binds the chat if it's brand new
1383
- // and the flag is on. Once auto-bound, the chat appears in oncallChats
1384
- // so the next handleNewTopic sees it via (1).
1385
- let oncallEntry = findOncallChatForAnyBot(chatId);
1386
- if (!oncallEntry) {
1387
- oncallEntry = await maybeAutoBindDefaultOncall(larkAppId, chatId, chatType);
1388
- }
1389
- // Cross-bot / chat-scope inheritance: reuse a sibling session's workingDir
1390
- // and skip the repo card. Same block lives in handleThreadReply's auto-create
1391
- // branch — both handlers land unowned messages after the 4fec43c routing
1392
- // change. Helper is shared.
1393
- const inheritedFrom = !oncallEntry
1394
- ? findInheritablePeer({ scope, anchor, chatId, chatType, selfAppId: larkAppId })
1395
- : null;
1396
- // Last-resort fallback: this bot's `defaultWorkingDir`. Pure runtime — no
1397
- // oncall binding written, no permission-model change. Lets a single-repo
1398
- // bot skip the repo-select card without committing to oncall semantics.
1399
- const botDefaultWorkingDir = (!oncallEntry && !inheritedFrom)
1400
- ? resolveBotDefaultWorkingDir(larkAppId)
1401
- : undefined;
1402
- const pinnedWorkingDir = oncallEntry?.workingDir ?? inheritedFrom?.workingDir ?? botDefaultWorkingDir;
1520
+ // Pin the working dir via the layered oncall / inherit / default lookup
1521
+ // (auto-binds a defaultOncall chat as a side effect). Shared with the
1522
+ // first-message `/repo` command branch so both paths stay consistent.
1523
+ const { pinnedWorkingDir, oncallEntry, inheritedFrom } = await resolvePinnedWorkingDir({ scope, anchor, chatId, chatType, larkAppId });
1403
1524
  const ds = {
1404
1525
  session,
1405
1526
  worker: null,
@@ -1650,10 +1771,16 @@ async function handleThreadReply(data, ctx) {
1650
1771
  if (ds) {
1651
1772
  markSessionActivity(ds);
1652
1773
  const callerOpenId = parsed.senderId || data?.sender?.sender_id?.open_id;
1774
+ // quoteTargetId changes every inbound message (always a new message_id), so
1775
+ // — unlike lastCallerOpenId — persist unconditionally. Powers `botmux send`'s
1776
+ // default chat-scope quote chain + --mention-back.
1777
+ ds.session.quoteTargetId = parsed.messageId;
1778
+ ds.session.quoteTargetSenderOpenId = callerOpenId;
1779
+ ds.session.quoteTargetSenderIsBot = isForeignBot;
1653
1780
  if (callerOpenId && ds.session.lastCallerOpenId !== callerOpenId) {
1654
1781
  ds.session.lastCallerOpenId = callerOpenId;
1655
- sessionStore.updateSession(ds.session);
1656
1782
  }
1783
+ sessionStore.updateSession(ds.session);
1657
1784
  }
1658
1785
  // If waiting for repo selection, buffer the message and remind user
1659
1786
  if (ds?.pendingRepo) {
@@ -1668,13 +1795,18 @@ async function handleThreadReply(data, ctx) {
1668
1795
  });
1669
1796
  enriched += `\n\n${tr('daemon.enriched_mentions_label', undefined, localeForBot(larkAppId))}\n${mentionLines.join('\n')}`;
1670
1797
  }
1671
- // Stamp each buffered follow-up with its own <sender> tag pendingFollowUps
1672
- // can contain messages from multiple users while a single ds.pendingSender
1673
- // is fixed at the first message, so without per-message attribution the
1674
- // CLI can't tell which user said what after repo selection unlocks the spawn.
1675
- const followUpSenderTag = renderSenderTag(await getThreadSender());
1676
- if (followUpSenderTag)
1677
- enriched = `${followUpSenderTag}\n${enriched}`;
1798
+ // Stamp a buffered follow-up with its own <sender> tag ONLY when it comes
1799
+ // from a different user than the first message (ds.pendingSender) — the
1800
+ // deferred spawn already carries that sender's <sender> block, and the
1801
+ // follow-ups now fold into the same <user_message>, so a same-user tag is
1802
+ // pure duplication. A differing sender still gets attributed so the CLI can
1803
+ // tell multi-user buffered messages apart after repo selection unlocks.
1804
+ const followUpSender = await getThreadSender();
1805
+ if (followUpSender?.openId && followUpSender.openId !== ds.pendingSender?.openId) {
1806
+ const followUpSenderTag = renderSenderTag(followUpSender);
1807
+ if (followUpSenderTag)
1808
+ enriched = `${followUpSenderTag}\n${enriched}`;
1809
+ }
1678
1810
  if (!ds.pendingFollowUps)
1679
1811
  ds.pendingFollowUps = [];
1680
1812
  ds.pendingFollowUps.push(enriched);
@@ -1699,15 +1831,24 @@ async function handleThreadReply(data, ctx) {
1699
1831
  logger.info(`No active session for ${scope}-scope ${anchor}, auto-creating new session...`);
1700
1832
  refreshCliVersion(botCfg.cliId, botCfg.cliPathOverride);
1701
1833
  const senderOId = data.sender?.sender_id?.open_id;
1834
+ const senderUId = data.sender?.sender_id?.union_id;
1702
1835
  // For thread-scope: rootMessageId = anchor (real thread root).
1703
1836
  // For chat-scope: rootMessageId = the message_id that triggered this auto-create
1704
1837
  // (used as audit trail; routing key is chatId).
1705
1838
  const rootIdForStore = scope === 'thread' ? anchor : parsed.messageId;
1706
1839
  const session = sessionStore.createSession(autoCreateChatId, rootIdForStore, parsed.content.substring(0, 50), autoCreateChatType);
1707
1840
  const now = Date.now();
1841
+ // Bot-started handoff sessions have no human owner; keeping the bot as
1842
+ // owner makes daemon-generated footers wake that bot again.
1843
+ const ownerOpenId = isForeignBot ? undefined : senderOId;
1844
+ const ownerUnionId = isForeignBot ? undefined : senderUId;
1708
1845
  session.larkAppId = larkAppId;
1709
- session.ownerOpenId = senderOId;
1846
+ session.ownerOpenId = ownerOpenId;
1847
+ session.ownerUnionId = ownerUnionId;
1710
1848
  session.lastCallerOpenId = senderOId;
1849
+ session.quoteTargetId = parsed.messageId;
1850
+ session.quoteTargetSenderOpenId = senderOId;
1851
+ session.quoteTargetSenderIsBot = isForeignBot;
1711
1852
  session.lastMessageAt = new Date(now).toISOString();
1712
1853
  session.scope = scope;
1713
1854
  sessionStore.updateSession(session);
@@ -1759,7 +1900,7 @@ async function handleThreadReply(data, ctx) {
1759
1900
  pendingAttachments: attachments.length > 0 ? attachments : undefined,
1760
1901
  pendingMentions: parsed.mentions,
1761
1902
  pendingSender: autoCreateSender,
1762
- ownerOpenId: senderOId,
1903
+ ownerOpenId,
1763
1904
  currentTurnTitle: parsed.content.substring(0, 50),
1764
1905
  workingDir: pinnedWorkingDir,
1765
1906
  };
@@ -1905,12 +2046,23 @@ export async function startDaemon(botIndex) {
1905
2046
  }
1906
2047
  const cfg = botConfigs[idx];
1907
2048
  registerBot(cfg);
2049
+ // 启动即为本 bot 的 CLI 预装环境(skills + askUserQuestion hook + 兜底 skill)。
2050
+ // 关键:adopt 路径会跳过 ensureCliSkills,若重启后第一次就是 adopt 一个外部
2051
+ // claude 会话,必须保证此时全局 ~/.claude/settings.json 已带 hook——否则"全局
2052
+ // hook 适配 adopt"不成立。这里幂等、best-effort,不阻塞启动。
2053
+ try {
2054
+ ensureCliEnv(cfg.cliId, cfg.cliPathOverride);
2055
+ }
2056
+ catch (err) {
2057
+ logger.warn(`[hook] startup ensureCliEnv failed for ${cfg.cliId}: ${err instanceof Error ? err.message : String(err)}`);
2058
+ }
1908
2059
  sessionStore.init(cfg.larkAppId);
1909
2060
  chatFirstSeenStore.init(cfg.larkAppId);
1910
2061
  // Watch schedules.json for external writes (e.g. `botmux schedule add`
1911
2062
  // running in a separate node process) so dashboard event bus stays in sync.
1912
2063
  scheduleStore.startExternalWriteWatcher();
1913
2064
  logger.info(`Bot ${idx}/${botConfigs.length}: ${cfg.larkAppId} (cli: ${cfg.cliId})`);
2065
+ setAskCardDispatcher(createLarkAskCardDispatcher());
1914
2066
  writePidFile();
1915
2067
  const memoryDiagnostics = startMemoryDiagnostics();
1916
2068
  // Publish self-descriptor for the dashboard registry. The dashboard sibling
@@ -1945,6 +2097,9 @@ export async function startDaemon(botIndex) {
1945
2097
  // Expose the activeSessions Map (owned by daemon) to worker-pool readers,
1946
2098
  // so dashboard IPC and other consumers can list/lookup live sessions.
1947
2099
  setActiveSessionsRegistry(activeSessions);
2100
+ // Wire the workflow runner for /api/trigger (kind=workflow): reuse the same
2101
+ // heavy deps as the catalog run route.
2102
+ setWorkflowRunner((input) => triggerWorkflowRun(input, workflowTriggerDeps()));
1948
2103
  // Seed dashboard IPC botName with the bot's config id; the friendly name from
1949
2104
  // /bot/v3/info is wired into the registry descriptor (below) but the IPC server
1950
2105
  // also needs its own copy for SessionRow.botName.
@@ -2048,7 +2203,7 @@ export async function startDaemon(botIndex) {
2048
2203
  });
2049
2204
  }
2050
2205
  // Restore active sessions from previous run
2051
- restoreActiveSessions(activeSessions);
2206
+ await restoreActiveSessions(activeSessions);
2052
2207
  await attachColdWorkflowRuns(cfg.larkAppId);
2053
2208
  // Start scheduler in every daemon. Each daemon owns exactly one bot, so
2054
2209
  // each filters to only execute tasks whose `larkAppId` matches its bot