botmux 3.9.2 → 3.10.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 (314) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/.runtime-build-id +1 -1
  4. package/dist/adapters/cli/codex.d.ts.map +1 -1
  5. package/dist/adapters/cli/codex.js +6 -0
  6. package/dist/adapters/cli/codex.js.map +1 -1
  7. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  8. package/dist/adapters/cli/opencode.js +7 -1
  9. package/dist/adapters/cli/opencode.js.map +1 -1
  10. package/dist/adapters/cli/reasonix.d.ts +35 -0
  11. package/dist/adapters/cli/reasonix.d.ts.map +1 -0
  12. package/dist/adapters/cli/reasonix.js +236 -0
  13. package/dist/adapters/cli/reasonix.js.map +1 -0
  14. package/dist/adapters/cli/registry.d.ts +2 -1
  15. package/dist/adapters/cli/registry.d.ts.map +1 -1
  16. package/dist/adapters/cli/registry.js +4 -1
  17. package/dist/adapters/cli/registry.js.map +1 -1
  18. package/dist/adapters/cli/types.d.ts +5 -1
  19. package/dist/adapters/cli/types.d.ts.map +1 -1
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +168 -62
  22. package/dist/cli.js.map +1 -1
  23. package/dist/core/command-handler.d.ts +18 -4
  24. package/dist/core/command-handler.d.ts.map +1 -1
  25. package/dist/core/command-handler.js +234 -26
  26. package/dist/core/command-handler.js.map +1 -1
  27. package/dist/core/dashboard-ipc-server.d.ts +1 -0
  28. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  29. package/dist/core/dashboard-ipc-server.js +27 -3
  30. package/dist/core/dashboard-ipc-server.js.map +1 -1
  31. package/dist/core/dispatch.d.ts +54 -24
  32. package/dist/core/dispatch.d.ts.map +1 -1
  33. package/dist/core/dispatch.js +81 -27
  34. package/dist/core/dispatch.js.map +1 -1
  35. package/dist/core/input-turn-dedupe.d.ts +20 -0
  36. package/dist/core/input-turn-dedupe.d.ts.map +1 -0
  37. package/dist/core/input-turn-dedupe.js +57 -0
  38. package/dist/core/input-turn-dedupe.js.map +1 -0
  39. package/dist/core/local-terminal-opener.d.ts.map +1 -1
  40. package/dist/core/local-terminal-opener.js +10 -1
  41. package/dist/core/local-terminal-opener.js.map +1 -1
  42. package/dist/core/passthrough-commands.d.ts.map +1 -1
  43. package/dist/core/passthrough-commands.js +1 -1
  44. package/dist/core/passthrough-commands.js.map +1 -1
  45. package/dist/core/plugins/pm2.d.ts.map +1 -1
  46. package/dist/core/plugins/pm2.js +7 -1
  47. package/dist/core/plugins/pm2.js.map +1 -1
  48. package/dist/core/resource-monitor/attribution.d.ts.map +1 -1
  49. package/dist/core/resource-monitor/attribution.js +17 -1
  50. package/dist/core/resource-monitor/attribution.js.map +1 -1
  51. package/dist/core/resource-monitor/darwin.d.ts +145 -0
  52. package/dist/core/resource-monitor/darwin.d.ts.map +1 -0
  53. package/dist/core/resource-monitor/darwin.js +360 -0
  54. package/dist/core/resource-monitor/darwin.js.map +1 -0
  55. package/dist/core/resource-monitor/procfs.d.ts.map +1 -1
  56. package/dist/core/resource-monitor/procfs.js +6 -0
  57. package/dist/core/resource-monitor/procfs.js.map +1 -1
  58. package/dist/core/resource-monitor/types.d.ts +1 -1
  59. package/dist/core/resource-monitor/types.d.ts.map +1 -1
  60. package/dist/core/scheduler.d.ts.map +1 -1
  61. package/dist/core/scheduler.js +5 -2
  62. package/dist/core/scheduler.js.map +1 -1
  63. package/dist/core/session-discovery.d.ts.map +1 -1
  64. package/dist/core/session-discovery.js +3 -0
  65. package/dist/core/session-discovery.js.map +1 -1
  66. package/dist/core/session-manager.d.ts +3 -1
  67. package/dist/core/session-manager.d.ts.map +1 -1
  68. package/dist/core/session-manager.js +46 -0
  69. package/dist/core/session-manager.js.map +1 -1
  70. package/dist/core/session-marker.d.ts +1 -8
  71. package/dist/core/session-marker.d.ts.map +1 -1
  72. package/dist/core/session-marker.js +2 -50
  73. package/dist/core/session-marker.js.map +1 -1
  74. package/dist/core/types.d.ts +3 -1
  75. package/dist/core/types.d.ts.map +1 -1
  76. package/dist/core/types.js.map +1 -1
  77. package/dist/core/worker-pool.d.ts +17 -0
  78. package/dist/core/worker-pool.d.ts.map +1 -1
  79. package/dist/core/worker-pool.js +292 -9
  80. package/dist/core/worker-pool.js.map +1 -1
  81. package/dist/daemon.d.ts.map +1 -1
  82. package/dist/daemon.js +27 -12
  83. package/dist/daemon.js.map +1 -1
  84. package/dist/dashboard/daemon-internal-api.d.ts.map +1 -1
  85. package/dist/dashboard/daemon-internal-api.js +11 -2
  86. package/dist/dashboard/daemon-internal-api.js.map +1 -1
  87. package/dist/dashboard/groups-action-helpers.d.ts +2 -0
  88. package/dist/dashboard/groups-action-helpers.d.ts.map +1 -1
  89. package/dist/dashboard/groups-action-helpers.js +9 -0
  90. package/dist/dashboard/groups-action-helpers.js.map +1 -1
  91. package/dist/dashboard/groups-matrix-snapshot.d.ts +56 -0
  92. package/dist/dashboard/groups-matrix-snapshot.d.ts.map +1 -0
  93. package/dist/dashboard/groups-matrix-snapshot.js +127 -0
  94. package/dist/dashboard/groups-matrix-snapshot.js.map +1 -0
  95. package/dist/dashboard/resource-monitor-service.d.ts.map +1 -1
  96. package/dist/dashboard/resource-monitor-service.js +18 -2
  97. package/dist/dashboard/resource-monitor-service.js.map +1 -1
  98. package/dist/dashboard/web/app.d.ts.map +1 -1
  99. package/dist/dashboard/web/app.js +45 -4
  100. package/dist/dashboard/web/app.js.map +1 -1
  101. package/dist/dashboard/web/groups-api.js +1 -1
  102. package/dist/dashboard/web/groups-api.js.map +1 -1
  103. package/dist/dashboard/web/i18n.js +10 -10
  104. package/dist/dashboard/web/i18n.js.map +1 -1
  105. package/dist/dashboard/web/roles-page.d.ts.map +1 -1
  106. package/dist/dashboard/web/roles-page.js +26 -11
  107. package/dist/dashboard/web/roles-page.js.map +1 -1
  108. package/dist/dashboard-web/app.js +1 -1
  109. package/dist/dashboard-web/chunks/{bot-defaults-page-BHTQEWCH.js → bot-defaults-page-LTVOUDIS.js} +1 -1
  110. package/dist/dashboard-web/chunks/{chunk-KLZCQAHF.js → chunk-3UE7S77S.js} +1 -1
  111. package/dist/dashboard-web/chunks/{chunk-W77TPKZH.js → chunk-DCS35UMD.js} +1 -1
  112. package/dist/dashboard-web/chunks/{chunk-E3HZZXK5.js → chunk-MFQPCVHY.js} +4 -4
  113. package/dist/dashboard-web/chunks/{chunk-EZH56JCI.js → chunk-ZU3UUKAR.js} +1 -1
  114. package/dist/dashboard-web/chunks/{connectors-page-BP255CAX.js → connectors-page-5KWDIMKC.js} +1 -1
  115. package/dist/dashboard-web/chunks/{groups-page-CDHVXBUT.js → groups-page-FHOKYXMW.js} +1 -1
  116. package/dist/dashboard-web/chunks/{insights-page-57BFE6GT.js → insights-page-T2ZX2RWL.js} +1 -1
  117. package/dist/dashboard-web/chunks/{monitor-room-UTOYGQVF.js → monitor-room-YNVBAGR6.js} +1 -1
  118. package/dist/dashboard-web/chunks/{monitoring-page-WTHYAIUM.js → monitoring-page-LHM55YWN.js} +1 -1
  119. package/dist/dashboard-web/chunks/{office-page-JSMIB353.js → office-page-ATXVP7PW.js} +1 -1
  120. package/dist/dashboard-web/chunks/{overview-page-3VDBOH7L.js → overview-page-QYI3KBDD.js} +1 -1
  121. package/dist/dashboard-web/chunks/roles-page-56VWM6CD.js +1 -0
  122. package/dist/dashboard-web/chunks/{schedules-page-HHN736H6.js → schedules-page-S5K6U4EO.js} +1 -1
  123. package/dist/dashboard-web/chunks/{sessions-page-EIWOZD7A.js → sessions-page-WBP4N7D2.js} +1 -1
  124. package/dist/dashboard-web/chunks/{settings-page-2IUT5LS4.js → settings-page-QUZDQARR.js} +1 -1
  125. package/dist/dashboard-web/chunks/{skills-page-JKFKMUEM.js → skills-page-IFY7AEND.js} +1 -1
  126. package/dist/dashboard-web/chunks/{team-federation-page-Q2PXC3UY.js → team-federation-page-C7FJQPFZ.js} +1 -1
  127. package/dist/dashboard-web/chunks/{v3-page-EBQCD4AO.js → v3-page-2LMF3WWR.js} +1 -1
  128. package/dist/dashboard-web/chunks/{whiteboards-page-QZRMVNZN.js → whiteboards-page-3XC6QRMY.js} +1 -1
  129. package/dist/dashboard-web/style.css +2 -4
  130. package/dist/dashboard.js +65 -9
  131. package/dist/dashboard.js.map +1 -1
  132. package/dist/i18n/en.d.ts.map +1 -1
  133. package/dist/i18n/en.js +33 -7
  134. package/dist/i18n/en.js.map +1 -1
  135. package/dist/i18n/zh.d.ts.map +1 -1
  136. package/dist/i18n/zh.js +31 -7
  137. package/dist/i18n/zh.js.map +1 -1
  138. package/dist/im/lark/card-builder.d.ts +7 -0
  139. package/dist/im/lark/card-builder.d.ts.map +1 -1
  140. package/dist/im/lark/card-builder.js +56 -0
  141. package/dist/im/lark/card-builder.js.map +1 -1
  142. package/dist/im/lark/card-handler.d.ts.map +1 -1
  143. package/dist/im/lark/card-handler.js +42 -19
  144. package/dist/im/lark/card-handler.js.map +1 -1
  145. package/dist/im/lark/client.d.ts +10 -0
  146. package/dist/im/lark/client.d.ts.map +1 -1
  147. package/dist/im/lark/client.js +79 -0
  148. package/dist/im/lark/client.js.map +1 -1
  149. package/dist/im/lark/event-dispatcher.d.ts +14 -1
  150. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  151. package/dist/im/lark/event-dispatcher.js +171 -15
  152. package/dist/im/lark/event-dispatcher.js.map +1 -1
  153. package/dist/im/lark/lark-hosts.d.ts +5 -0
  154. package/dist/im/lark/lark-hosts.d.ts.map +1 -1
  155. package/dist/im/lark/lark-hosts.js +10 -0
  156. package/dist/im/lark/lark-hosts.js.map +1 -1
  157. package/dist/im/lark/message-parser.d.ts.map +1 -1
  158. package/dist/im/lark/message-parser.js +24 -7
  159. package/dist/im/lark/message-parser.js.map +1 -1
  160. package/dist/pm2-graceful-exit.d.ts +28 -0
  161. package/dist/pm2-graceful-exit.d.ts.map +1 -0
  162. package/dist/pm2-graceful-exit.js +39 -0
  163. package/dist/pm2-graceful-exit.js.map +1 -0
  164. package/dist/services/bridge-fallback-gate.d.ts +9 -2
  165. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  166. package/dist/services/bridge-fallback-gate.js +31 -19
  167. package/dist/services/bridge-fallback-gate.js.map +1 -1
  168. package/dist/services/message-listener-store.d.ts +18 -0
  169. package/dist/services/message-listener-store.d.ts.map +1 -1
  170. package/dist/services/message-listener-store.js +35 -10
  171. package/dist/services/message-listener-store.js.map +1 -1
  172. package/dist/services/message-listener.d.ts +17 -0
  173. package/dist/services/message-listener.d.ts.map +1 -1
  174. package/dist/services/message-listener.js +26 -0
  175. package/dist/services/message-listener.js.map +1 -1
  176. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  177. package/dist/setup/bot-config-editor.js +2 -0
  178. package/dist/setup/bot-config-editor.js.map +1 -1
  179. package/dist/setup/lark-scopes.json +1 -0
  180. package/dist/setup/verify-permissions.d.ts.map +1 -1
  181. package/dist/setup/verify-permissions.js +8 -0
  182. package/dist/setup/verify-permissions.js.map +1 -1
  183. package/dist/types.d.ts +34 -0
  184. package/dist/types.d.ts.map +1 -1
  185. package/dist/utils/child-env.d.ts +1 -1
  186. package/dist/utils/child-env.d.ts.map +1 -1
  187. package/dist/utils/child-env.js +13 -0
  188. package/dist/utils/child-env.js.map +1 -1
  189. package/dist/utils/file-lock.d.ts.map +1 -1
  190. package/dist/utils/file-lock.js +1 -1
  191. package/dist/utils/file-lock.js.map +1 -1
  192. package/dist/utils/global-install.d.ts.map +1 -1
  193. package/dist/utils/global-install.js +56 -10
  194. package/dist/utils/global-install.js.map +1 -1
  195. package/dist/utils/idle-detector.d.ts +4 -0
  196. package/dist/utils/idle-detector.d.ts.map +1 -1
  197. package/dist/utils/idle-detector.js +25 -0
  198. package/dist/utils/idle-detector.js.map +1 -1
  199. package/dist/utils/process-identity.d.ts +7 -0
  200. package/dist/utils/process-identity.d.ts.map +1 -0
  201. package/dist/utils/process-identity.js +62 -0
  202. package/dist/utils/process-identity.js.map +1 -0
  203. package/dist/worker.js +123 -9
  204. package/dist/worker.js.map +1 -1
  205. package/dist/workflows/events/payloads.d.ts +10 -10
  206. package/dist/workflows/events/schema.d.ts +28 -28
  207. package/dist/workflows/hostExecutors/registry.d.ts +2 -7
  208. package/dist/workflows/hostExecutors/registry.d.ts.map +1 -1
  209. package/dist/workflows/hostExecutors/registry.js.map +1 -1
  210. package/dist/workflows/shared/provider-reconciler.d.ts +1 -30
  211. package/dist/workflows/shared/provider-reconciler.d.ts.map +1 -1
  212. package/dist/workflows/shared/provider-reconciler.js.map +1 -1
  213. package/dist/workflows/v3/artifact-contract.d.ts +41 -0
  214. package/dist/workflows/v3/artifact-contract.d.ts.map +1 -0
  215. package/dist/workflows/v3/artifact-contract.js +20 -0
  216. package/dist/workflows/v3/artifact-contract.js.map +1 -0
  217. package/dist/workflows/v3/botmux-attempt-lease.d.ts +7 -0
  218. package/dist/workflows/v3/botmux-attempt-lease.d.ts.map +1 -0
  219. package/dist/workflows/v3/botmux-attempt-lease.js +189 -0
  220. package/dist/workflows/v3/botmux-attempt-lease.js.map +1 -0
  221. package/dist/workflows/v3/botmux-host-policy.d.ts +7 -0
  222. package/dist/workflows/v3/botmux-host-policy.d.ts.map +1 -0
  223. package/dist/workflows/v3/botmux-host-policy.js +34 -0
  224. package/dist/workflows/v3/botmux-host-policy.js.map +1 -0
  225. package/dist/workflows/v3/cli-run.d.ts +1 -1
  226. package/dist/workflows/v3/cli-run.d.ts.map +1 -1
  227. package/dist/workflows/v3/cli-run.js +1 -1
  228. package/dist/workflows/v3/cli-run.js.map +1 -1
  229. package/dist/workflows/v3/contract.d.ts +8 -89
  230. package/dist/workflows/v3/contract.d.ts.map +1 -1
  231. package/dist/workflows/v3/contract.js +2 -8
  232. package/dist/workflows/v3/contract.js.map +1 -1
  233. package/dist/workflows/v3/core-control.d.ts +16 -0
  234. package/dist/workflows/v3/core-control.d.ts.map +1 -0
  235. package/dist/workflows/v3/core-control.js +60 -0
  236. package/dist/workflows/v3/core-control.js.map +1 -0
  237. package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
  238. package/dist/workflows/v3/daemon-run.js +2 -1
  239. package/dist/workflows/v3/daemon-run.js.map +1 -1
  240. package/dist/workflows/v3/dag-loader.d.ts +5 -0
  241. package/dist/workflows/v3/dag-loader.d.ts.map +1 -0
  242. package/dist/workflows/v3/dag-loader.js +22 -0
  243. package/dist/workflows/v3/dag-loader.js.map +1 -0
  244. package/dist/workflows/v3/dag.d.ts +2 -6
  245. package/dist/workflows/v3/dag.d.ts.map +1 -1
  246. package/dist/workflows/v3/dag.js +2 -24
  247. package/dist/workflows/v3/dag.js.map +1 -1
  248. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
  249. package/dist/workflows/v3/ephemeral-pool.js +22 -12
  250. package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
  251. package/dist/workflows/v3/event-contract.d.ts +273 -0
  252. package/dist/workflows/v3/event-contract.d.ts.map +1 -0
  253. package/dist/workflows/v3/event-contract.js +8 -0
  254. package/dist/workflows/v3/event-contract.js.map +1 -0
  255. package/dist/workflows/v3/gate-policy.d.ts +12 -0
  256. package/dist/workflows/v3/gate-policy.d.ts.map +1 -0
  257. package/dist/workflows/v3/gate-policy.js +20 -0
  258. package/dist/workflows/v3/gate-policy.js.map +1 -0
  259. package/dist/workflows/v3/gate-wait-store.d.ts +99 -0
  260. package/dist/workflows/v3/gate-wait-store.d.ts.map +1 -0
  261. package/dist/workflows/v3/gate-wait-store.js +263 -0
  262. package/dist/workflows/v3/gate-wait-store.js.map +1 -0
  263. package/dist/workflows/v3/host.js +1 -1
  264. package/dist/workflows/v3/host.js.map +1 -1
  265. package/dist/workflows/v3/human-gate.d.ts +4 -99
  266. package/dist/workflows/v3/human-gate.d.ts.map +1 -1
  267. package/dist/workflows/v3/human-gate.js +4 -275
  268. package/dist/workflows/v3/human-gate.js.map +1 -1
  269. package/dist/workflows/v3/in-process-attempt-lease.d.ts +10 -0
  270. package/dist/workflows/v3/in-process-attempt-lease.d.ts.map +1 -0
  271. package/dist/workflows/v3/in-process-attempt-lease.js +47 -0
  272. package/dist/workflows/v3/in-process-attempt-lease.js.map +1 -0
  273. package/dist/workflows/v3/journal.d.ts +2 -275
  274. package/dist/workflows/v3/journal.d.ts.map +1 -1
  275. package/dist/workflows/v3/journal.js.map +1 -1
  276. package/dist/workflows/v3/library-service.js +1 -1
  277. package/dist/workflows/v3/library-service.js.map +1 -1
  278. package/dist/workflows/v3/orchestrator.d.ts +1 -2
  279. package/dist/workflows/v3/orchestrator.d.ts.map +1 -1
  280. package/dist/workflows/v3/orchestrator.js.map +1 -1
  281. package/dist/workflows/v3/portable-artifact-snapshot.d.ts +15 -0
  282. package/dist/workflows/v3/portable-artifact-snapshot.d.ts.map +1 -0
  283. package/dist/workflows/v3/portable-artifact-snapshot.js +76 -0
  284. package/dist/workflows/v3/portable-artifact-snapshot.js.map +1 -0
  285. package/dist/workflows/v3/portable-final-outputs.d.ts +37 -0
  286. package/dist/workflows/v3/portable-final-outputs.d.ts.map +1 -0
  287. package/dist/workflows/v3/portable-final-outputs.js +137 -0
  288. package/dist/workflows/v3/portable-final-outputs.js.map +1 -0
  289. package/dist/workflows/v3/portable-run-snapshot.d.ts +14 -0
  290. package/dist/workflows/v3/portable-run-snapshot.d.ts.map +1 -0
  291. package/dist/workflows/v3/portable-run-snapshot.js +176 -0
  292. package/dist/workflows/v3/portable-run-snapshot.js.map +1 -0
  293. package/dist/workflows/v3/portable-runtime.d.ts +83 -0
  294. package/dist/workflows/v3/portable-runtime.d.ts.map +1 -0
  295. package/dist/workflows/v3/portable-runtime.js +135 -0
  296. package/dist/workflows/v3/portable-runtime.js.map +1 -0
  297. package/dist/workflows/v3/runtime-host-contract.d.ts +182 -0
  298. package/dist/workflows/v3/runtime-host-contract.d.ts.map +1 -0
  299. package/dist/workflows/v3/runtime-host-contract.js +9 -0
  300. package/dist/workflows/v3/runtime-host-contract.js.map +1 -0
  301. package/dist/workflows/v3/runtime.d.ts +12 -226
  302. package/dist/workflows/v3/runtime.d.ts.map +1 -1
  303. package/dist/workflows/v3/runtime.js +14 -3173
  304. package/dist/workflows/v3/runtime.js.map +1 -1
  305. package/dist/workflows/v3/shared-node-runtime.d.ts +203 -0
  306. package/dist/workflows/v3/shared-node-runtime.d.ts.map +1 -0
  307. package/dist/workflows/v3/shared-node-runtime.js +2978 -0
  308. package/dist/workflows/v3/shared-node-runtime.js.map +1 -0
  309. package/dist/workflows/v3/shared-runtime.d.ts +17 -0
  310. package/dist/workflows/v3/shared-runtime.d.ts.map +1 -0
  311. package/dist/workflows/v3/shared-runtime.js +12 -0
  312. package/dist/workflows/v3/shared-runtime.js.map +1 -0
  313. package/package.json +4 -1
  314. package/dist/dashboard-web/chunks/roles-page-LHVAU2BI.js +0 -1
@@ -8,7 +8,7 @@ import { ProxyAgent } from 'proxy-agent';
8
8
  import { readFileSync, mkdirSync, existsSync } from 'node:fs';
9
9
  import { atomicWriteFileSync } from '../../utils/atomic-write.js';
10
10
  import { join } from 'node:path';
11
- import { getBot, getAllBots, findOncallChat, getOwnerOpenId } from '../../bot-registry.js';
11
+ import { getBot, getAllBots, findOncallChat, getOwnerOpenId, loadBotConfigs } from '../../bot-registry.js';
12
12
  import { config, isVcMeetingAgentGloballyEnabled, vcMeetingAgentGlobalListenerBotAppId } from '../../config.js';
13
13
  import { getChatInfo, getChatMode, getCachedChatMode, getUserProfile, listChatMessagesUntil, resolveSiblingBotBySenderOpenId, replyMessage, sendMessage, sendUserMessage, isHumanOpenId, updateMessage } from './client.js';
14
14
  import { logger } from '../../utils/logger.js';
@@ -21,7 +21,7 @@ import { recordObservedBots, listObservedBots } from '../../services/observed-bo
21
21
  import { isTeamBot, recordTeamBot } from '../../services/team-bots-store.js';
22
22
  import { isTeamGroupChat } from '../../services/team-groups-store.js';
23
23
  import { isPlatformTeamBot, isPlatformHallChat, isPlatformTeamMemberChat } from '../../services/platform-team-store.js';
24
- import { recordBotUnionId, recordBotUnionIdFromMentions } from '../../services/bot-union-ids-store.js';
24
+ import { getBotUnionId, recordBotUnionId, recordBotUnionIdFromMentions } from '../../services/bot-union-ids-store.js';
25
25
  import { getDocSubscription, putDocSubscription, removeDocSubscription, listAllDocSubscriptions } from '../../services/doc-subs-store.js';
26
26
  import { getDocComment, isBotAuthoredReply, hasBotSentinel, commentTriggerAllowed, BOT_REPLY_SENTINEL } from './doc-comment.js';
27
27
  import { BOTMUX_REQUIRED_SCOPES, DOC_FEATURE_SCOPES, DOC_WATCH_SCOPES, DOC_COMMENT_EVENT, VC_MEETING_BOT_EVENTS, VC_MEETING_FEATURE_SCOPES, VC_MEETING_REALTIME_VOICE_SCOPES, buildEventSubDeepLink, buildScopeDeepLink, } from '../../setup/verify-permissions.js';
@@ -198,16 +198,27 @@ async function dmAdmin(larkAppId, adminOpenId, content, contextTag) {
198
198
  *
199
199
  * Returns `true` if scopes were successfully applied (caller should stop),
200
200
  * `false` to fall through to the manual DM warning.
201
+ *
202
+ * `opts.disableQrLogin` — when the only thing missing is a non-critical scope,
203
+ * we still try to grab it (the automation imports the full manifest), but must
204
+ * NOT pop a second QR code if the cached session is gone. Passing this makes a
205
+ * missing/expired session fail cleanly (reason `invalid_session`) instead of
206
+ * prompting a login.
207
+ * `opts.silent` — suppress the admin success DM (used for the opt-in / optional
208
+ * path so a bot that never asked for the feature isn't pinged; the log line is
209
+ * enough). Failures are always silent here regardless.
201
210
  */
202
- async function tryAutoFixScopes(larkAppId, bot, brand, missingCritical, missingOptional) {
211
+ async function tryAutoFixScopes(larkAppId, bot, brand, missingCritical, missingOptional, opts) {
203
212
  if (brand !== 'feishu')
204
213
  return false;
205
214
  try {
206
- logger.info(`[${larkAppId}] attempting auto-fix for ${missingCritical.length} missing scopes via Open Platform...`);
215
+ const totalMissing = missingCritical.length + missingOptional.length;
216
+ logger.info(`[${larkAppId}] attempting auto-fix for ${totalMissing} missing scopes via Open Platform...`);
207
217
  const result = await automateOpenPlatformSetup({
208
218
  appId: bot.config.larkAppId,
209
219
  brand,
210
220
  maxWaitMs: 60_000,
221
+ disableQrLogin: opts?.disableQrLogin,
211
222
  onStatus: (msg) => logger.info(`[${larkAppId}] auto-fix: ${msg}`),
212
223
  onQrCode: (info) => {
213
224
  logger.warn(`[${larkAppId}] auto-fix: cached Feishu web session expired, QR login needed. ` +
@@ -222,21 +233,26 @@ async function tryAutoFixScopes(larkAppId, bot, brand, missingCritical, missingO
222
233
  logger.info(`[${larkAppId}] auto-fix succeeded: ${scopeDetail}, ` +
223
234
  `version ${result.versionId ?? 'n/a'} published, ` +
224
235
  `${result.subscribedEventCount} events subscribed`);
236
+ // opt-in / optional-only path: succeeded silently, no admin DM (a bot that
237
+ // never enabled the feature must not be pinged just because a non-critical
238
+ // scope was topped up in the background). The log line above is the record.
239
+ if (opts?.silent)
240
+ return true;
225
241
  // Notify admin that auto-fix worked — even if im:message was missing before,
226
242
  // the newly published version should now have it.
227
243
  const adminOpenId = getAdminOpenId(bot);
228
244
  if (adminOpenId) {
229
- const missingList = missingCritical.map(s => `• ${s.desc} (\`${s.name}\`)`).join('\n');
230
- const optionalNote = missingOptional.length > 0
231
- ? `\n\n另有 ${missingOptional.length} 项可选权限未开通:${missingOptional.map(s => s.name).join('、')}`
232
- : '';
245
+ const fixedList = [...missingCritical, ...missingOptional];
246
+ const missingList = fixedList.map(s => `• ${s.desc} (\`${s.name}\`)`).join('\n');
233
247
  await dmAdmin(larkAppId, adminOpenId, `✅ botmux 已自动为机器人 "${bot.botName ?? larkAppId}" 修复了缺失的权限:\n\n${missingList}\n\n` +
234
248
  `${scopeDetail},新版本已发布。\n` +
235
- `权限变更可能需要 1-2 分钟生效。如仍有问题执行 \`botmux restart\`。${optionalNote}`, `auto-fixed ${missingCritical.length} scopes`);
249
+ `权限变更可能需要 1-2 分钟生效。如仍有问题执行 \`botmux restart\`。`, `auto-fixed ${fixedList.length} scopes`);
236
250
  }
237
251
  return true;
238
252
  }
239
- // Auto-fix failed — log reason and fall through to manual DM.
253
+ // Auto-fix failed — log reason. Critical path falls through to a manual
254
+ // deep-link DM; the silent optional-scope top-up path does NOT DM (it just
255
+ // leaves the opt-in scope ungranted), so don't claim a DM fallback there.
240
256
  const reasons = {
241
257
  missing_session: '无可用的 Feishu Web session',
242
258
  invalid_session: 'Web session 已失效',
@@ -250,11 +266,12 @@ async function tryAutoFixScopes(larkAppId, bot, brand, missingCritical, missingO
250
266
  api_error: '开放平台 API 错误',
251
267
  };
252
268
  logger.warn(`[${larkAppId}] auto-fix not possible (${result.reason}: ${reasons[result.reason] ?? result.message}). ` +
253
- `Falling back to manual deep-link DM.`);
269
+ (opts?.silent ? 'Leaving opt-in scope ungranted (no DM).' : 'Falling back to manual deep-link DM.'));
254
270
  return false;
255
271
  }
256
272
  catch (err) {
257
- logger.warn(`[${larkAppId}] auto-fix error: ${err?.message ?? err} — falling back to manual DM`);
273
+ logger.warn(`[${larkAppId}] auto-fix error: ${err?.message ?? err}` +
274
+ (opts?.silent ? ' — leaving opt-in scope ungranted (no DM)' : ' — falling back to manual DM'));
258
275
  return false;
259
276
  }
260
277
  }
@@ -403,6 +420,22 @@ export async function checkRequiredScopes(larkAppId) {
403
420
  const missingCritical = BOTMUX_REQUIRED_SCOPES.filter(s => s.critical && !grantedScopes.has(s.name));
404
421
  const missingOptional = BOTMUX_REQUIRED_SCOPES.filter(s => !s.critical && !grantedScopes.has(s.name));
405
422
  if (missingCritical.length === 0) {
423
+ // All critical scopes present. If an opt-in feature added a non-critical
424
+ // scope that isn't granted yet, top it up SILENTLY — but only when a cached
425
+ // Feishu web session already exists (disableQrLogin makes a missing session
426
+ // fail cleanly with no second QR code and no DM). This makes `botmux restart`
427
+ // actually pick up newly-declared optional scopes (e.g. the foreign-bot
428
+ // group-message scope) without the admin having to visit the Open Platform,
429
+ // while a bot with nothing missing — or no web session — behaves exactly as
430
+ // before (no API call / no prompt / no nag).
431
+ if (missingOptional.length > 0 && brand === 'feishu') {
432
+ const toppedUp = await tryAutoFixScopes(larkAppId, bot, brand, [], missingOptional, { disableQrLogin: true, silent: true });
433
+ if (toppedUp) {
434
+ logger.info(`[${larkAppId}] auto-topped-up ${missingOptional.length} optional scope(s): ${missingOptional.map(s => s.name).join('、')}`);
435
+ return;
436
+ }
437
+ logger.debug(`[${larkAppId}] optional scope(s) missing (${missingOptional.map(s => s.name).join('、')}); no cached web session to auto-apply — leaving to opt-in feature owner`);
438
+ }
406
439
  logger.info(`[${larkAppId}] all critical scopes granted (${BOTMUX_REQUIRED_SCOPES.filter(s => s.critical).length} checked)`);
407
440
  return;
408
441
  }
@@ -732,6 +765,38 @@ export function isKnownPeerBot(dataDir, larkAppId, senderOpenId) {
732
765
  }
733
766
  return false;
734
767
  }
768
+ /**
769
+ * Auth-grade local sibling check for the narrow `/repo` exception.
770
+ *
771
+ * Cross-ref proves only "this receiver has seen this sender open_id as some
772
+ * peer" and may be stale or name-poisoned. For authorization we additionally
773
+ * require the Lark-stamped sender union_id to match exactly one currently
774
+ * configured, transport-enabled sibling app's learned own union_id.
775
+ */
776
+ export function isVerifiedLocalSiblingBot(dataDir, larkAppId, senderOpenId, senderUnionId) {
777
+ const openId = (senderOpenId ?? '').trim();
778
+ const unionId = (senderUnionId ?? '').trim();
779
+ if (!openId || !unionId)
780
+ return false;
781
+ if (!isKnownPeerBot(dataDir, larkAppId, openId))
782
+ return false;
783
+ let matchingConfiguredSiblings = 0;
784
+ try {
785
+ for (const cfg of loadBotConfigs()) {
786
+ const appId = (cfg.larkAppId ?? '').trim();
787
+ if (!appId || appId === larkAppId || cfg.apiOnly === true)
788
+ continue;
789
+ if (getBotUnionId(dataDir, appId) === unionId)
790
+ matchingConfiguredSiblings += 1;
791
+ if (matchingConfiguredSiblings > 1)
792
+ return false;
793
+ }
794
+ }
795
+ catch {
796
+ return false;
797
+ }
798
+ return matchingConfiguredSiblings === 1;
799
+ }
735
800
  /**
736
801
  * Should a FOREIGN bot sender be trusted to collaborate (route/spawn a session)
737
802
  * WITHOUT `/grant`, because it's a teammate? Two trust sources, both rooted in
@@ -1304,10 +1369,18 @@ export function canOperate(larkAppId, _chatId, senderOpenId, senderUnionId) {
1304
1369
  * union_id 的情况);否则「团队拉群里外部 bot 能 talk 却执行不了降权到 canTalk 的命令
1305
1370
  * (如 /status)」——单一 talk 谓词在这道 daemon 命令闸继续分叉。不传(人的路径)→
1306
1371
  * 原样走 canTalk / evaluateTalk,语义不变。canOperate 那段人/bot 通用,不受影响。
1372
+ *
1373
+ * `/repo` 另有一个更窄的同部署 sibling bot 例外:仅当飞书事件把发送方盖章为 bot,
1374
+ * receiver cross-ref 命中 sender open_id,且 sender union_id 精确匹配当前仍配置的唯一
1375
+ * 本机 sibling app 已学习的自身 union_id 时放行;不把 sibling 提升为 canOperate,也不把其他 daemon 命令降权。
1307
1376
  */
1308
- export function canRunDaemonCommand(larkAppId, chatId, senderOpenId, senderUnionId, cmd, memberUnionId, chatType, botSender) {
1377
+ export function canRunDaemonCommand(larkAppId, chatId, senderOpenId, senderUnionId, cmd, memberUnionId, chatType, botSender, larkStampedBotSender) {
1309
1378
  if (canOperate(larkAppId, chatId, senderOpenId, senderUnionId))
1310
1379
  return true;
1380
+ if (cmd === '/repo' && larkStampedBotSender === true
1381
+ && isVerifiedLocalSiblingBot(config.session.dataDir, larkAppId, senderOpenId, senderUnionId)) {
1382
+ return true;
1383
+ }
1311
1384
  const list = getBot(larkAppId).config.canTalkDaemonCommands;
1312
1385
  if (!list?.includes(cmd))
1313
1386
  return false;
@@ -2256,9 +2329,92 @@ export function startLarkEventDispatcher(larkAppId, larkAppSecret, handlers, bra
2256
2329
  })).catch(err => logger.error(`Error handling bot message listener event: ${err}`));
2257
2330
  return;
2258
2331
  }
2259
- // Foreign bot: only route on @mention of us.
2260
- if (!isBotMentioned(larkAppId, message, undefined))
2332
+ // Foreign bot: only route on @mention of us — with one exception.
2333
+ //
2334
+ // 主动开工 — 场景② (bot sender): 「话题群新话题自动开工」(autoStartOnNewTopic)
2335
+ // 覆盖到「其他机器人开的新话题」。人分支在 3271 对非 @ 的话题群新话题种子做
2336
+ // 同一判定;bot 消息走本分支,若不在这里补一个等价出口,就会在下面这行 return
2337
+ // 掉——所以 bot 开的新话题永远到不了人分支的场景②。判定复用同一个纯函数
2338
+ // shouldAutoStartOnNewTopic(形态门:thread-scope + anchor===本消息 + 无会话
2339
+ // 占用,天然只认「全新话题种子」,不认话题内回复,故不会自我循环——回复锚定在
2340
+ // 话题根 anchor≠messageId),并要求飞书真的把这条非 @ 的 bot 消息推过来
2341
+ //(依赖 im:message.group_msg.include_bot:read scope;缺则事件根本不到,静默降级)。
2342
+ // sender 受授权门约束(与人分支 + 下游 enforceMessageQuotaForCliInput 同源):
2343
+ // 授权/peer/团队/oncall/开放腿放行的 sender 才自动开工,restricted 下未授权陌生
2344
+ // bot 改发授权卡(详见下方 autoTopic 分支)。
2345
+ //
2346
+ // 收到 im:message.group_msg.include_bot:read 推来的「其他用户/机器人发的群消息」后,
2347
+ // 只有满足形态门才免 @ 自动开工;否则保持原有「未 @ 即忽略」语义。
2348
+ if (!isBotMentioned(larkAppId, message, undefined)) {
2349
+ if (getBot(larkAppId).config.autoStartOnNewTopic === true && chatType === 'group') {
2350
+ const seedDecision = await decideRoutingWithSource(larkAppId, message);
2351
+ // P3 — 镜像人分支「话题群 → 普通群 (reverse conversion)」那道 forceRefresh
2352
+ // 守卫:decideRoutingWithSource 判 topic-chat 种子靠的是**缓存** chat_mode
2353
+ //(5min TTL)。管理员把话题群翻回普通群后缓存可能仍是 'topic',于是一条本该
2354
+ // 是普通群顶层的 bot 消息被误判成话题种子,起 thread-scope 会话把回复裹进
2355
+ //「其实已是普通群」的新 Lark 话题。无真实 thread_id(= 种子形态,非既有话题内
2356
+ // 回复,权威信号不会 stale)时用 forceRefresh 再确认;飞书现在报 'group' 就当
2357
+ // 它不是话题种子(降级),不自动开工。这道 API 往返只落在「已呈现 topic 种子
2358
+ // 形态的 opt-in 候选」上——与人分支同样的成本取舍(宁可多一次调用,也不用
2359
+ // 一个 5min 错建 session 的窗口换省一次调用)。
2360
+ let seedIsTopicChat = seedDecision.source === 'topic-chat';
2361
+ if (seedIsTopicChat && !message.thread_id) {
2362
+ const freshMode = await getChatMode(larkAppId, chatId, { forceRefresh: true });
2363
+ if (freshMode === 'group') {
2364
+ logger.info(`[chat-mode-converted] ${chatId.substring(0, 12)} chat_mode flipped 'topic' → 'group'; ` +
2365
+ `跳过 bot 新话题自动开工 msg=${messageId.substring(0, 12)}`);
2366
+ seedIsTopicChat = false;
2367
+ }
2368
+ }
2369
+ // 与人分支同源:只有真正的话题群顶层种子(source==='topic-chat' 且经 forceRefresh
2370
+ // 复核仍是话题群)才是自动开工候选;普通群 /t / 新话题模式产生的同形
2371
+ // {thread, anchor=msg} 不算。
2372
+ const seedScope = seedIsTopicChat ? seedDecision.scope : 'chat';
2373
+ const seedAnchor = seedIsTopicChat ? seedDecision.anchor : chatId;
2374
+ const seedOwnsSession = seedScope === 'thread'
2375
+ ? (handlers.isSessionOwner?.(seedAnchor, larkAppId) ?? false)
2376
+ : false;
2377
+ const autoTopic = shouldAutoStartOnNewTopic({
2378
+ enabled: true,
2379
+ scope: seedScope,
2380
+ anchor: seedAnchor,
2381
+ messageId,
2382
+ chatType,
2383
+ ownsSession: seedOwnsSession,
2384
+ });
2385
+ // Sender 授权门(与人分支 + 下游 enforceMessageQuotaForCliInput 一致):
2386
+ // 自动开工最终仍要经 handleNewTopic 里的 enforceMessageQuotaForCliInput →
2387
+ // evaluateBotTalk 复查,restricted 模式(配了 allowlist)下未授权的陌生 bot
2388
+ // 会在那里被静默 drop、session 根本不建。所以在这里**先判同一个谓词**:
2389
+ // • allowed → 正常免 @ 自动开工(open 模式 / oncall / 整群授权 / peer /
2390
+ // 团队 bot 等任一放行腿命中,与人/下游同源)。
2391
+ // • !allowed(restricted 下的陌生 bot)→ 不建 session,改发一次授权申请卡
2392
+ // 给 owner(节流复用 maybeSendGrantRequestCard 内的 isThrottled),让
2393
+ // owner 决定是否把它加进 allowlist——与人分支 @bot 被挡时的 not_allowed
2394
+ // 体验一致、可发现,而不是静默吞掉。
2395
+ // 只在「真未授权」发卡;已授权但额度耗尽是另一回事(走下游 quota exhausted
2396
+ // 语义),不在这里混。授权卡的申请对象是触发 bot 的 open_id,但审批/操作权限
2397
+ // 仍只归 owner;此刻不建 session,绝不把触发 bot 写成 owner,也不 --mention-back
2398
+ // 回唤它(dispatchHumanMessage 那条才建 session,本分支只发卡后 return)。
2399
+ if (autoTopic) {
2400
+ const seedBotTalk = evaluateBotTalk(larkAppId, chatId, senderOpenId, senderUnionId);
2401
+ if (!seedBotTalk.allowed) {
2402
+ logger.info(`[auto-start:新话题] ${chatId.substring(0, 12)} 其他机器人开新话题但未授权(restricted)→ 发授权卡不自动开工 ` +
2403
+ `msg=${messageId.substring(0, 12)} sender=${senderOpenId?.substring(0, 12) ?? '-'}`);
2404
+ await maybeSendGrantRequestCard(larkAppId, message, chatId, senderOpenId, data)
2405
+ .catch(err => logger.error(`Error sending grant card for foreign-bot new topic: ${err}`));
2406
+ return;
2407
+ }
2408
+ logger.info(`[auto-start:新话题] ${chatId.substring(0, 12)} 其他机器人开新话题免@自动开工 ` +
2409
+ `msg=${messageId.substring(0, 12)} sender=${senderOpenId?.substring(0, 12) ?? '-'} reason=${seedBotTalk.reason}`);
2410
+ const seedCtx = { chatId, messageId, chatType, larkAppId, scope: seedScope, anchor: seedAnchor };
2411
+ await dispatchHumanMessage({ data, ctx: seedCtx, ownsSession: false })
2412
+ .catch(err => logger.error(`Error auto-starting on foreign-bot new topic: ${err}`));
2413
+ return;
2414
+ }
2415
+ }
2261
2416
  return;
2417
+ }
2262
2418
  const decision = await decideRoutingWithSource(larkAppId, message);
2263
2419
  const ctx = { scope: decision.scope, anchor: decision.anchor };
2264
2420
  // Honor `/t` / `/topic` from bot senders too, aligning with the human