botmux 3.4.3 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/README.en.md +10 -7
  2. package/README.md +11 -6
  3. package/dist/adapters/backend/herdr-backend.d.ts +43 -6
  4. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  5. package/dist/adapters/backend/herdr-backend.js +362 -28
  6. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  7. package/dist/adapters/backend/reproduce-command.d.ts +39 -0
  8. package/dist/adapters/backend/reproduce-command.d.ts.map +1 -0
  9. package/dist/adapters/backend/reproduce-command.js +63 -0
  10. package/dist/adapters/backend/reproduce-command.js.map +1 -0
  11. package/dist/adapters/backend/sandbox.d.ts +99 -279
  12. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  13. package/dist/adapters/backend/sandbox.js +424 -826
  14. package/dist/adapters/backend/sandbox.js.map +1 -1
  15. package/dist/adapters/backend/session-backend-selector.d.ts +10 -1
  16. package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -1
  17. package/dist/adapters/backend/session-backend-selector.js +73 -4
  18. package/dist/adapters/backend/session-backend-selector.js.map +1 -1
  19. package/dist/adapters/backend/types.d.ts +16 -0
  20. package/dist/adapters/backend/types.d.ts.map +1 -1
  21. package/dist/adapters/backend/types.js.map +1 -1
  22. package/dist/adapters/cli/codex.d.ts.map +1 -1
  23. package/dist/adapters/cli/codex.js +4 -0
  24. package/dist/adapters/cli/codex.js.map +1 -1
  25. package/dist/adapters/cli/fs-policy.d.ts +244 -0
  26. package/dist/adapters/cli/fs-policy.d.ts.map +1 -0
  27. package/dist/adapters/cli/fs-policy.js +539 -0
  28. package/dist/adapters/cli/fs-policy.js.map +1 -0
  29. package/dist/adapters/cli/pi-initial-prompt.d.ts.map +1 -1
  30. package/dist/adapters/cli/pi-initial-prompt.js +5 -1
  31. package/dist/adapters/cli/pi-initial-prompt.js.map +1 -1
  32. package/dist/adapters/cli/read-isolation.d.ts +14 -200
  33. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  34. package/dist/adapters/cli/read-isolation.js +18 -477
  35. package/dist/adapters/cli/read-isolation.js.map +1 -1
  36. package/dist/adapters/cli/traex.d.ts.map +1 -1
  37. package/dist/adapters/cli/traex.js +5 -0
  38. package/dist/adapters/cli/traex.js.map +1 -1
  39. package/dist/adapters/cli/types.d.ts +3 -3
  40. package/dist/adapters/cli/types.d.ts.map +1 -1
  41. package/dist/adapters/hook-installer.d.ts +7 -0
  42. package/dist/adapters/hook-installer.d.ts.map +1 -1
  43. package/dist/adapters/hook-installer.js +56 -0
  44. package/dist/adapters/hook-installer.js.map +1 -1
  45. package/dist/bot-registry.d.ts +39 -23
  46. package/dist/bot-registry.d.ts.map +1 -1
  47. package/dist/bot-registry.js +134 -2
  48. package/dist/bot-registry.js.map +1 -1
  49. package/dist/cli/capabilities.d.ts +24 -0
  50. package/dist/cli/capabilities.d.ts.map +1 -0
  51. package/dist/cli/capabilities.js +25 -0
  52. package/dist/cli/capabilities.js.map +1 -0
  53. package/dist/cli/create-group-resolver.d.ts +24 -0
  54. package/dist/cli/create-group-resolver.d.ts.map +1 -1
  55. package/dist/cli/create-group-resolver.js +23 -0
  56. package/dist/cli/create-group-resolver.js.map +1 -1
  57. package/dist/cli/daemon-lifecycle-env.d.ts +5 -7
  58. package/dist/cli/daemon-lifecycle-env.d.ts.map +1 -1
  59. package/dist/cli/daemon-lifecycle-env.js +13 -7
  60. package/dist/cli/daemon-lifecycle-env.js.map +1 -1
  61. package/dist/cli/exact-chat-grant-client.d.ts +48 -0
  62. package/dist/cli/exact-chat-grant-client.d.ts.map +1 -0
  63. package/dist/cli/exact-chat-grant-client.js +108 -0
  64. package/dist/cli/exact-chat-grant-client.js.map +1 -0
  65. package/dist/cli/exact-chat-grant.d.ts +18 -0
  66. package/dist/cli/exact-chat-grant.d.ts.map +1 -0
  67. package/dist/cli/exact-chat-grant.js +97 -0
  68. package/dist/cli/exact-chat-grant.js.map +1 -0
  69. package/dist/cli.d.ts +10 -1
  70. package/dist/cli.d.ts.map +1 -1
  71. package/dist/cli.js +795 -144
  72. package/dist/cli.js.map +1 -1
  73. package/dist/codex-rpc-engine.d.ts +26 -0
  74. package/dist/codex-rpc-engine.d.ts.map +1 -1
  75. package/dist/codex-rpc-engine.js +113 -2
  76. package/dist/codex-rpc-engine.js.map +1 -1
  77. package/dist/config.d.ts +16 -0
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/config.js +16 -0
  80. package/dist/config.js.map +1 -1
  81. package/dist/core/bot-live-control.d.ts +41 -0
  82. package/dist/core/bot-live-control.d.ts.map +1 -0
  83. package/dist/core/bot-live-control.js +135 -0
  84. package/dist/core/bot-live-control.js.map +1 -0
  85. package/dist/core/command-handler.d.ts.map +1 -1
  86. package/dist/core/command-handler.js +44 -66
  87. package/dist/core/command-handler.js.map +1 -1
  88. package/dist/core/daemon-config-fence.d.ts +8 -0
  89. package/dist/core/daemon-config-fence.d.ts.map +1 -0
  90. package/dist/core/daemon-config-fence.js +13 -0
  91. package/dist/core/daemon-config-fence.js.map +1 -0
  92. package/dist/core/dashboard-events.d.ts +5 -0
  93. package/dist/core/dashboard-events.d.ts.map +1 -1
  94. package/dist/core/dashboard-events.js.map +1 -1
  95. package/dist/core/dashboard-ipc-server.d.ts +21 -2
  96. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  97. package/dist/core/dashboard-ipc-server.js +258 -32
  98. package/dist/core/dashboard-ipc-server.js.map +1 -1
  99. package/dist/core/dispatch-registry.d.ts +12 -0
  100. package/dist/core/dispatch-registry.d.ts.map +1 -0
  101. package/dist/core/dispatch-registry.js +33 -0
  102. package/dist/core/dispatch-registry.js.map +1 -0
  103. package/dist/core/dispatch.d.ts +99 -0
  104. package/dist/core/dispatch.d.ts.map +1 -1
  105. package/dist/core/dispatch.js +136 -0
  106. package/dist/core/dispatch.js.map +1 -1
  107. package/dist/core/maintenance.d.ts.map +1 -1
  108. package/dist/core/maintenance.js +10 -3
  109. package/dist/core/maintenance.js.map +1 -1
  110. package/dist/core/passthrough-commands.d.ts.map +1 -1
  111. package/dist/core/passthrough-commands.js +1 -1
  112. package/dist/core/passthrough-commands.js.map +1 -1
  113. package/dist/core/persistent-backend.d.ts +16 -2
  114. package/dist/core/persistent-backend.d.ts.map +1 -1
  115. package/dist/core/persistent-backend.js +40 -0
  116. package/dist/core/persistent-backend.js.map +1 -1
  117. package/dist/core/plugins/mcp/gateway-installer.d.ts.map +1 -1
  118. package/dist/core/plugins/mcp/gateway-installer.js +14 -2
  119. package/dist/core/plugins/mcp/gateway-installer.js.map +1 -1
  120. package/dist/core/session-discovery.d.ts +8 -1
  121. package/dist/core/session-discovery.d.ts.map +1 -1
  122. package/dist/core/session-discovery.js +140 -8
  123. package/dist/core/session-discovery.js.map +1 -1
  124. package/dist/core/session-manager.d.ts.map +1 -1
  125. package/dist/core/session-manager.js +102 -68
  126. package/dist/core/session-manager.js.map +1 -1
  127. package/dist/core/session-title.d.ts +8 -0
  128. package/dist/core/session-title.d.ts.map +1 -1
  129. package/dist/core/session-title.js +54 -0
  130. package/dist/core/session-title.js.map +1 -1
  131. package/dist/core/terminal-write-auth.d.ts +15 -0
  132. package/dist/core/terminal-write-auth.d.ts.map +1 -1
  133. package/dist/core/terminal-write-auth.js +20 -0
  134. package/dist/core/terminal-write-auth.js.map +1 -1
  135. package/dist/core/trigger-session.d.ts.map +1 -1
  136. package/dist/core/trigger-session.js +3 -2
  137. package/dist/core/trigger-session.js.map +1 -1
  138. package/dist/core/types.d.ts +33 -0
  139. package/dist/core/types.d.ts.map +1 -1
  140. package/dist/core/types.js.map +1 -1
  141. package/dist/core/worker-pool.d.ts +51 -8
  142. package/dist/core/worker-pool.d.ts.map +1 -1
  143. package/dist/core/worker-pool.js +439 -25
  144. package/dist/core/worker-pool.js.map +1 -1
  145. package/dist/daemon.d.ts +4 -2
  146. package/dist/daemon.d.ts.map +1 -1
  147. package/dist/daemon.js +403 -26
  148. package/dist/daemon.js.map +1 -1
  149. package/dist/dashboard/bot-onboarding.d.ts +127 -1
  150. package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
  151. package/dist/dashboard/bot-onboarding.js +1104 -25
  152. package/dist/dashboard/bot-onboarding.js.map +1 -1
  153. package/dist/dashboard/bot-payload.d.ts +5 -0
  154. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  155. package/dist/dashboard/bot-payload.js +7 -0
  156. package/dist/dashboard/bot-payload.js.map +1 -1
  157. package/dist/dashboard/debug-terminal.d.ts +18 -0
  158. package/dist/dashboard/debug-terminal.d.ts.map +1 -0
  159. package/dist/dashboard/debug-terminal.js +338 -0
  160. package/dist/dashboard/debug-terminal.js.map +1 -0
  161. package/dist/dashboard/public-redact.d.ts +2 -0
  162. package/dist/dashboard/public-redact.d.ts.map +1 -1
  163. package/dist/dashboard/public-redact.js +12 -3
  164. package/dist/dashboard/public-redact.js.map +1 -1
  165. package/dist/dashboard/registry.d.ts +8 -0
  166. package/dist/dashboard/registry.d.ts.map +1 -1
  167. package/dist/dashboard/registry.js +13 -0
  168. package/dist/dashboard/registry.js.map +1 -1
  169. package/dist/dashboard/settings-write-applier.d.ts +47 -1
  170. package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
  171. package/dist/dashboard/settings-write-applier.js +102 -1
  172. package/dist/dashboard/settings-write-applier.js.map +1 -1
  173. package/dist/dashboard/web/app.d.ts.map +1 -1
  174. package/dist/dashboard/web/app.js +2 -0
  175. package/dist/dashboard/web/app.js.map +1 -1
  176. package/dist/dashboard/web/bot-defaults-page.d.ts +17 -0
  177. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  178. package/dist/dashboard/web/bot-defaults-page.js +249 -11
  179. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  180. package/dist/dashboard/web/bot-defaults.d.ts +22 -0
  181. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  182. package/dist/dashboard/web/bot-defaults.js +19 -0
  183. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  184. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  185. package/dist/dashboard/web/i18n.js +114 -28
  186. package/dist/dashboard/web/i18n.js.map +1 -1
  187. package/dist/dashboard/web/icon-tooltip.d.ts +3 -0
  188. package/dist/dashboard/web/icon-tooltip.d.ts.map +1 -0
  189. package/dist/dashboard/web/icon-tooltip.js +108 -0
  190. package/dist/dashboard/web/icon-tooltip.js.map +1 -0
  191. package/dist/dashboard/web/sessions-kanban.js +2 -2
  192. package/dist/dashboard/web/sessions-kanban.js.map +1 -1
  193. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  194. package/dist/dashboard/web/sessions-page.js +49 -53
  195. package/dist/dashboard/web/sessions-page.js.map +1 -1
  196. package/dist/dashboard/web/sessions.d.ts +2 -0
  197. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  198. package/dist/dashboard/web/sessions.js +46 -2
  199. package/dist/dashboard/web/sessions.js.map +1 -1
  200. package/dist/dashboard/web/settings-page.d.ts +78 -0
  201. package/dist/dashboard/web/settings-page.d.ts.map +1 -1
  202. package/dist/dashboard/web/settings-page.js +88 -1
  203. package/dist/dashboard/web/settings-page.js.map +1 -1
  204. package/dist/dashboard/web/store.d.ts +2 -0
  205. package/dist/dashboard/web/store.d.ts.map +1 -1
  206. package/dist/dashboard/web/store.js +13 -1
  207. package/dist/dashboard/web/store.js.map +1 -1
  208. package/dist/dashboard-web/app.js +1 -1
  209. package/dist/dashboard-web/chunks/bot-defaults-page-AUKV7P4L.js +10 -0
  210. package/dist/dashboard-web/chunks/{chunk-P6GO5KT4.js → chunk-KPQAUX7V.js} +1 -1
  211. package/dist/dashboard-web/chunks/{chunk-UBOLHQCK.js → chunk-NRL6CVAS.js} +1 -1
  212. package/dist/dashboard-web/chunks/{chunk-JNRSPKLS.js → chunk-R7IAKAYX.js} +1 -1
  213. package/dist/dashboard-web/chunks/{chunk-CUV65BIQ.js → chunk-X2L65IOM.js} +8 -8
  214. package/dist/dashboard-web/chunks/{connectors-page-KTC2QWNW.js → connectors-page-HDQFEXZI.js} +1 -1
  215. package/dist/dashboard-web/chunks/{groups-page-B3EKGOLY.js → groups-page-6DKXBYOM.js} +1 -1
  216. package/dist/dashboard-web/chunks/{insights-page-X6RXNCWX.js → insights-page-NWARTJ6J.js} +1 -1
  217. package/dist/dashboard-web/chunks/{monitor-room-LLRA5LQW.js → monitor-room-AGX3XRJX.js} +1 -1
  218. package/dist/dashboard-web/chunks/{monitoring-page-7MT5FEOS.js → monitoring-page-GGGIWN4C.js} +1 -1
  219. package/dist/dashboard-web/chunks/{office-page-KD46D5TD.js → office-page-6SIVKSK3.js} +1 -1
  220. package/dist/dashboard-web/chunks/{overview-page-JUWNH32O.js → overview-page-FVR3NKAF.js} +1 -1
  221. package/dist/dashboard-web/chunks/{roles-page-P6F7NLOI.js → roles-page-WE2YB7KN.js} +1 -1
  222. package/dist/dashboard-web/chunks/{schedules-page-XIHWZST4.js → schedules-page-TB3I24XN.js} +1 -1
  223. package/dist/dashboard-web/chunks/sessions-page-KOOOASIL.js +2 -0
  224. package/dist/dashboard-web/chunks/settings-page-IEBR7TGN.js +2 -0
  225. package/dist/dashboard-web/chunks/{skills-page-A46KVWBL.js → skills-page-3QAT2IWD.js} +1 -1
  226. package/dist/dashboard-web/chunks/{team-federation-page-SDUC56DF.js → team-federation-page-K4VVAVAK.js} +1 -1
  227. package/dist/dashboard-web/chunks/{v3-page-J5JOTUSQ.js → v3-page-V6IOJR2B.js} +1 -1
  228. package/dist/dashboard-web/chunks/{whiteboards-page-U7LSOAWI.js → whiteboards-page-V6CGKRNX.js} +1 -1
  229. package/dist/dashboard-web/style.css +218 -10
  230. package/dist/dashboard.js +380 -8
  231. package/dist/dashboard.js.map +1 -1
  232. package/dist/features/codex-notifier/adoption.d.ts +11 -0
  233. package/dist/features/codex-notifier/adoption.d.ts.map +1 -0
  234. package/dist/features/codex-notifier/adoption.js +11 -0
  235. package/dist/features/codex-notifier/adoption.js.map +1 -0
  236. package/dist/features/codex-notifier/app-opener.d.ts +21 -0
  237. package/dist/features/codex-notifier/app-opener.d.ts.map +1 -0
  238. package/dist/features/codex-notifier/app-opener.js +33 -0
  239. package/dist/features/codex-notifier/app-opener.js.map +1 -0
  240. package/dist/features/codex-notifier/card-action.d.ts +27 -0
  241. package/dist/features/codex-notifier/card-action.d.ts.map +1 -0
  242. package/dist/features/codex-notifier/card-action.js +84 -0
  243. package/dist/features/codex-notifier/card-action.js.map +1 -0
  244. package/dist/features/codex-notifier/card.d.ts +12 -0
  245. package/dist/features/codex-notifier/card.d.ts.map +1 -0
  246. package/dist/features/codex-notifier/card.js +150 -0
  247. package/dist/features/codex-notifier/card.js.map +1 -0
  248. package/dist/features/codex-notifier/codex-context.d.ts +12 -0
  249. package/dist/features/codex-notifier/codex-context.d.ts.map +1 -0
  250. package/dist/features/codex-notifier/codex-context.js +161 -0
  251. package/dist/features/codex-notifier/codex-context.js.map +1 -0
  252. package/dist/features/codex-notifier/config.d.ts +9 -0
  253. package/dist/features/codex-notifier/config.d.ts.map +1 -0
  254. package/dist/features/codex-notifier/config.js +11 -0
  255. package/dist/features/codex-notifier/config.js.map +1 -0
  256. package/dist/features/codex-notifier/confirmed-turn.d.ts +20 -0
  257. package/dist/features/codex-notifier/confirmed-turn.d.ts.map +1 -0
  258. package/dist/features/codex-notifier/confirmed-turn.js +130 -0
  259. package/dist/features/codex-notifier/confirmed-turn.js.map +1 -0
  260. package/dist/features/codex-notifier/emitter.d.ts +13 -0
  261. package/dist/features/codex-notifier/emitter.d.ts.map +1 -0
  262. package/dist/features/codex-notifier/emitter.js +33 -0
  263. package/dist/features/codex-notifier/emitter.js.map +1 -0
  264. package/dist/features/codex-notifier/event-store.d.ts +29 -0
  265. package/dist/features/codex-notifier/event-store.d.ts.map +1 -0
  266. package/dist/features/codex-notifier/event-store.js +217 -0
  267. package/dist/features/codex-notifier/event-store.js.map +1 -0
  268. package/dist/features/codex-notifier/event.d.ts +46 -0
  269. package/dist/features/codex-notifier/event.d.ts.map +1 -0
  270. package/dist/features/codex-notifier/event.js +188 -0
  271. package/dist/features/codex-notifier/event.js.map +1 -0
  272. package/dist/features/codex-notifier/hook-cli.d.ts +23 -0
  273. package/dist/features/codex-notifier/hook-cli.d.ts.map +1 -0
  274. package/dist/features/codex-notifier/hook-cli.js +130 -0
  275. package/dist/features/codex-notifier/hook-cli.js.map +1 -0
  276. package/dist/features/codex-notifier/hook-installer.d.ts +19 -0
  277. package/dist/features/codex-notifier/hook-installer.d.ts.map +1 -0
  278. package/dist/features/codex-notifier/hook-installer.js +158 -0
  279. package/dist/features/codex-notifier/hook-installer.js.map +1 -0
  280. package/dist/features/codex-notifier/index.d.ts +21 -0
  281. package/dist/features/codex-notifier/index.d.ts.map +1 -0
  282. package/dist/features/codex-notifier/index.js +19 -0
  283. package/dist/features/codex-notifier/index.js.map +1 -0
  284. package/dist/features/codex-notifier/internal-turn.d.ts +5 -0
  285. package/dist/features/codex-notifier/internal-turn.d.ts.map +1 -0
  286. package/dist/features/codex-notifier/internal-turn.js +43 -0
  287. package/dist/features/codex-notifier/internal-turn.js.map +1 -0
  288. package/dist/features/codex-notifier/outbox-worker.d.ts +71 -0
  289. package/dist/features/codex-notifier/outbox-worker.d.ts.map +1 -0
  290. package/dist/features/codex-notifier/outbox-worker.js +290 -0
  291. package/dist/features/codex-notifier/outbox-worker.js.map +1 -0
  292. package/dist/features/codex-notifier/outbox.d.ts +25 -0
  293. package/dist/features/codex-notifier/outbox.d.ts.map +1 -0
  294. package/dist/features/codex-notifier/outbox.js +225 -0
  295. package/dist/features/codex-notifier/outbox.js.map +1 -0
  296. package/dist/features/codex-notifier/paths.d.ts +7 -0
  297. package/dist/features/codex-notifier/paths.d.ts.map +1 -0
  298. package/dist/features/codex-notifier/paths.js +20 -0
  299. package/dist/features/codex-notifier/paths.js.map +1 -0
  300. package/dist/features/codex-notifier/screen-lock.d.ts +12 -0
  301. package/dist/features/codex-notifier/screen-lock.d.ts.map +1 -0
  302. package/dist/features/codex-notifier/screen-lock.js +47 -0
  303. package/dist/features/codex-notifier/screen-lock.js.map +1 -0
  304. package/dist/features/codex-notifier/side-conversation-monitor.d.ts +102 -0
  305. package/dist/features/codex-notifier/side-conversation-monitor.d.ts.map +1 -0
  306. package/dist/features/codex-notifier/side-conversation-monitor.js +774 -0
  307. package/dist/features/codex-notifier/side-conversation-monitor.js.map +1 -0
  308. package/dist/features/codex-notifier/types.d.ts +42 -0
  309. package/dist/features/codex-notifier/types.d.ts.map +1 -0
  310. package/dist/features/codex-notifier/types.js +2 -0
  311. package/dist/features/codex-notifier/types.js.map +1 -0
  312. package/dist/features/codex-notifier/worker-lock.d.ts +8 -0
  313. package/dist/features/codex-notifier/worker-lock.d.ts.map +1 -0
  314. package/dist/features/codex-notifier/worker-lock.js +108 -0
  315. package/dist/features/codex-notifier/worker-lock.js.map +1 -0
  316. package/dist/global-config.d.ts +13 -0
  317. package/dist/global-config.d.ts.map +1 -1
  318. package/dist/global-config.js +34 -1
  319. package/dist/global-config.js.map +1 -1
  320. package/dist/i18n/en.d.ts.map +1 -1
  321. package/dist/i18n/en.js +1 -19
  322. package/dist/i18n/en.js.map +1 -1
  323. package/dist/i18n/zh.d.ts.map +1 -1
  324. package/dist/i18n/zh.js +1 -19
  325. package/dist/i18n/zh.js.map +1 -1
  326. package/dist/im/lark/card-builder.d.ts +0 -13
  327. package/dist/im/lark/card-builder.d.ts.map +1 -1
  328. package/dist/im/lark/card-builder.js +2 -36
  329. package/dist/im/lark/card-builder.js.map +1 -1
  330. package/dist/im/lark/card-handler.d.ts +2 -0
  331. package/dist/im/lark/card-handler.d.ts.map +1 -1
  332. package/dist/im/lark/card-handler.js +166 -64
  333. package/dist/im/lark/card-handler.js.map +1 -1
  334. package/dist/im/lark/client.d.ts +98 -4
  335. package/dist/im/lark/client.d.ts.map +1 -1
  336. package/dist/im/lark/client.js +317 -29
  337. package/dist/im/lark/client.js.map +1 -1
  338. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  339. package/dist/im/lark/event-dispatcher.js +48 -33
  340. package/dist/im/lark/event-dispatcher.js.map +1 -1
  341. package/dist/services/codex-app-threads.d.ts +47 -0
  342. package/dist/services/codex-app-threads.d.ts.map +1 -1
  343. package/dist/services/codex-app-threads.js +502 -10
  344. package/dist/services/codex-app-threads.js.map +1 -1
  345. package/dist/services/exact-chat-grant.d.ts +83 -0
  346. package/dist/services/exact-chat-grant.d.ts.map +1 -0
  347. package/dist/services/exact-chat-grant.js +249 -0
  348. package/dist/services/exact-chat-grant.js.map +1 -0
  349. package/dist/services/group-creator.d.ts +11 -0
  350. package/dist/services/group-creator.d.ts.map +1 -1
  351. package/dist/services/group-creator.js +18 -9
  352. package/dist/services/group-creator.js.map +1 -1
  353. package/dist/services/local-cli-opener.d.ts.map +1 -1
  354. package/dist/services/local-cli-opener.js +10 -5
  355. package/dist/services/local-cli-opener.js.map +1 -1
  356. package/dist/services/sandbox-migration.d.ts +14 -0
  357. package/dist/services/sandbox-migration.d.ts.map +1 -0
  358. package/dist/services/sandbox-migration.js +85 -0
  359. package/dist/services/sandbox-migration.js.map +1 -0
  360. package/dist/services/sandbox-store.d.ts +28 -0
  361. package/dist/services/sandbox-store.d.ts.map +1 -1
  362. package/dist/services/sandbox-store.js +82 -0
  363. package/dist/services/sandbox-store.js.map +1 -1
  364. package/dist/services/traex-user-input.d.ts +19 -0
  365. package/dist/services/traex-user-input.d.ts.map +1 -0
  366. package/dist/services/traex-user-input.js +57 -0
  367. package/dist/services/traex-user-input.js.map +1 -0
  368. package/dist/setup/open-platform-automation.d.ts +24 -3
  369. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  370. package/dist/setup/open-platform-automation.js +45 -8
  371. package/dist/setup/open-platform-automation.js.map +1 -1
  372. package/dist/setup/verify-permissions.d.ts +18 -0
  373. package/dist/setup/verify-permissions.d.ts.map +1 -1
  374. package/dist/setup/verify-permissions.js +60 -0
  375. package/dist/setup/verify-permissions.js.map +1 -1
  376. package/dist/types.d.ts +83 -5
  377. package/dist/types.d.ts.map +1 -1
  378. package/dist/utils/child-env.d.ts +2 -2
  379. package/dist/utils/child-env.d.ts.map +1 -1
  380. package/dist/utils/child-env.js +14 -0
  381. package/dist/utils/child-env.js.map +1 -1
  382. package/dist/utils/stuck-detector.d.ts +45 -0
  383. package/dist/utils/stuck-detector.d.ts.map +1 -0
  384. package/dist/utils/stuck-detector.js +188 -0
  385. package/dist/utils/stuck-detector.js.map +1 -0
  386. package/dist/utils/stuck-key-guard.d.ts +75 -0
  387. package/dist/utils/stuck-key-guard.d.ts.map +1 -0
  388. package/dist/utils/stuck-key-guard.js +77 -0
  389. package/dist/utils/stuck-key-guard.js.map +1 -0
  390. package/dist/worker.js +1119 -588
  391. package/dist/worker.js.map +1 -1
  392. package/dist/workflows/events/payloads.d.ts +56 -0
  393. package/dist/workflows/events/payloads.d.ts.map +1 -1
  394. package/dist/workflows/events/payloads.js +9 -0
  395. package/dist/workflows/events/payloads.js.map +1 -1
  396. package/dist/workflows/events/schema.d.ts +86 -0
  397. package/dist/workflows/events/schema.d.ts.map +1 -1
  398. package/dist/workflows/shared/sandbox-policy.d.ts +10 -1
  399. package/dist/workflows/shared/sandbox-policy.d.ts.map +1 -1
  400. package/dist/workflows/shared/sandbox-policy.js +12 -0
  401. package/dist/workflows/shared/sandbox-policy.js.map +1 -1
  402. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -1
  403. package/dist/workflows/v3/bot-resolve.js +36 -0
  404. package/dist/workflows/v3/bot-resolve.js.map +1 -1
  405. package/dist/workflows/v3/contract.d.ts +8 -0
  406. package/dist/workflows/v3/contract.d.ts.map +1 -1
  407. package/dist/workflows/v3/contract.js.map +1 -1
  408. package/package.json +1 -1
  409. package/dist/dashboard-web/chunks/bot-defaults-page-B5AY4B2J.js +0 -5
  410. package/dist/dashboard-web/chunks/sessions-page-2VECQ27T.js +0 -3
  411. package/dist/dashboard-web/chunks/settings-page-HMIUE2JA.js +0 -2
  412. package/dist/services/sandbox-land.d.ts +0 -45
  413. package/dist/services/sandbox-land.d.ts.map +0 -1
  414. package/dist/services/sandbox-land.js +0 -394
  415. package/dist/services/sandbox-land.js.map +0 -1
package/dist/dashboard.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/dashboard.ts
2
2
  import { createServer, get as httpGet, request as httpRequest } from 'node:http';
3
3
  import { createServer as createTcpServer, connect as netConnect } from 'node:net';
4
- import { readFileSync, existsSync, mkdirSync, readdirSync, statSync, createReadStream, } from 'node:fs';
4
+ import { readFileSync, existsSync, mkdirSync, readdirSync, statSync, createReadStream, realpathSync, } from 'node:fs';
5
5
  import { atomicWriteFileSync } from './utils/atomic-write.js';
6
6
  import { join, dirname, extname, resolve, relative, isAbsolute } from 'node:path';
7
7
  import { homedir } from 'node:os';
@@ -11,8 +11,9 @@ import { logger } from './utils/logger.js';
11
11
  import { config } from './config.js';
12
12
  import { listenWithProbe } from './utils/listen-with-probe.js';
13
13
  import { generateToken, parseCookie, buildSetCookie, verifyHmac, cliAuthBind, decideDashboardAuth, loadPersistedToken, persistToken, loadDashboardSecret, loadOrCreateDashboardSecret, } from './dashboard/auth.js';
14
- import { DaemonRegistry } from './dashboard/registry.js';
14
+ import { DaemonRegistry, botsRosterSignature } from './dashboard/registry.js';
15
15
  import { Aggregator, subscribeDaemon } from './dashboard/aggregator.js';
16
+ import { createDebugTerminalManager } from './dashboard/debug-terminal.js';
16
17
  import { pickCreatorForGroup } from './dashboard/operator-selector.js';
17
18
  import { buildTeamGroupCreatePayload, planGroupCreator } from './dashboard/team-group.js';
18
19
  import { jsonRes } from './dashboard/http.js';
@@ -21,7 +22,7 @@ import { defaultRunsDir as v3RunsDir } from './workflows/v3/ops-projection.js';
21
22
  import { verifyWorkflowDaemonIpcResponse, workflowDaemonIpcHeaders, WORKFLOW_DAEMON_IPC_ROUTE_PREFIX, } from './workflows/v3/daemon-ipc-auth.js';
22
23
  import { handleDashboardTriggerApi } from './dashboard/trigger-api.js';
23
24
  import { handleConnectorApi } from './dashboard/connector-api.js';
24
- import { redactGroupsForPublic, redactSchedulesForPublic } from './dashboard/public-redact.js';
25
+ import { redactGroupsForPublic, redactSchedulesForPublic, redactSettingsForPublic, } from './dashboard/public-redact.js';
25
26
  import { handleWebhookRoute } from './dashboard/webhook-routes.js';
26
27
  import { handleFederationApi } from './dashboard/federation-api.js';
27
28
  import { handleFederationSpokeApi, syncAllMemberships, autoBindOwnerIfUnambiguous } from './dashboard/federation-spoke-api.js';
@@ -46,7 +47,7 @@ import { listCliRuntimeUpdateEntries } from './core/cli-runtime-update.js';
46
47
  import { claimRestartLease, clearRestartIntent, clearRestartLease, hasActiveRestartLease, writeManualIntentIfAbsent, writeRestartIntent, } from './services/restart-intent-store.js';
47
48
  import { withFileLock } from './utils/file-lock.js';
48
49
  import { spawn } from 'node:child_process';
49
- import { applySettingsWrite, defaultSettingsWriteApplierDeps, } from './dashboard/settings-write-applier.js';
50
+ import { applySettingsWrite, defaultSettingsWriteApplierDeps, hasResolvedCodexNotifierRecipient, resolveCodexNotifierRecipientView, } from './dashboard/settings-write-applier.js';
50
51
  import { addBotsToGroup, bindOncall, disbandGroup, leaveGroup, unbindOncall, } from './dashboard/groups-action-helpers.js';
51
52
  import { createDaemonInternalApi } from './dashboard/daemon-internal-api.js';
52
53
  import { listTeamReports, readTeamBoard, setTeamBoardEntry } from './services/team-board-store.js';
@@ -56,6 +57,7 @@ import { buildSkillInstallAuditSummary, installLocalSkillLinks, readSkillRegistr
56
57
  import { redactGitUrlCredentials } from './core/skills/sources.js';
57
58
  import { effectiveDefaultWorkingDir, getBot, loadBotConfigs, parseBotConfigsFromText } from './bot-registry.js';
58
59
  import { findEntryIndex, readRawConfig, requireConfigPath, writeRawConfigAtomic } from './services/config-store.js';
60
+ import { emitCodexNotifierOutboxItem, installCodexNotifierHook, isCodexNotifierWorkerStateFresh, isCodexNotifierHookInstalled, listCodexNotifierOutbox, readCodexNotifierWorkerState, resolveCodexNotifierConfig, runCodexSideConversationMonitor, runCodexNotifierWorkerSupervisor, } from './features/codex-notifier/index.js';
59
61
  import { discoverNativeCliSkillGroups } from './core/skills/discovery.js';
60
62
  import { analyzeSkillReferences } from './core/skills/references.js';
61
63
  import { discoverDashboardSkills, installDashboardSkill, parseDashboardSkillInstallRequest, parseInstallLocalLinksSources, MAX_LOCAL_LINK_SOURCES } from './dashboard/skill-install-request.js';
@@ -189,6 +191,20 @@ function verifyDashboardBinding(port) {
189
191
  mkdirSync(REGISTRY_DIR, { recursive: true });
190
192
  const registry = new DaemonRegistry(REGISTRY_DIR);
191
193
  const aggregator = new Aggregator();
194
+ // 调试终端(owner-only 裸 bash)。默认工作目录取当前所有 session 的工作目录去重,
195
+ // 让 owner 从熟悉的目录起终端复现问题;都没有时模块内退回 homedir。
196
+ const debugTerminalManager = createDebugTerminalManager({
197
+ getActiveToken: () => activeToken,
198
+ defaultWorkingDirs: () => {
199
+ const dirs = new Set();
200
+ for (const s of aggregator.getSessions()) {
201
+ const wd = s.workingDir;
202
+ if (typeof wd === 'string' && wd.trim())
203
+ dirs.add(wd.trim());
204
+ }
205
+ return [...dirs];
206
+ },
207
+ });
192
208
  /**
193
209
  * Resolve which daemon owns a schedule row. For rows with an explicit
194
210
  * `larkAppId`, returns that. For legacy rows (no owner stamp), falls back to
@@ -196,6 +212,64 @@ const aggregator = new Aggregator();
196
212
  * tasks (see scheduler.belongsToOwner). Returns undefined when the row is
197
213
  * genuinely unknown or no daemon is online.
198
214
  */
215
+ /**
216
+ * Read-only directory listing for the dashboard sandbox-paths tree picker.
217
+ * Served locally by the dashboard process (same host as the daemons). Returns
218
+ * immediate CHILD DIRECTORIES only — never file contents. Trust model matches
219
+ * validateWorkingDir: the caller is an authed admin and the daemon already runs
220
+ * prompts with full FS access, so this is a convenience browser, not a security
221
+ * boundary. Symlinks are realpath-resolved; a raw path is never echoed into an
222
+ * error the browser renders verbatim.
223
+ */
224
+ function listDirLocally(rawPath) {
225
+ // Canonicalize $HOME so the root entry + the `~` the frontend expands both use
226
+ // the SAME canonical form the child listings (realpathSync below) and the
227
+ // worker's sandbox binds use. On a symlinked-$HOME host (/home/u →
228
+ // /data00/home/u) the lexical homedir() would make `~/.claude` expand to
229
+ // /home/u/.claude while the tree's child nodes come back as /data00/... — the
230
+ // picker would then never match its own recommendation entries.
231
+ let home = homedir();
232
+ try {
233
+ home = realpathSync(home);
234
+ }
235
+ catch { /* lexical fallback if unresolvable */ }
236
+ if (!rawPath) {
237
+ // Root view: HOME first (the common case), then filesystem root. `home` is
238
+ // also returned explicitly so the frontend doesn't guess from entries[0].
239
+ const roots = [...new Set([home, '/'])];
240
+ return {
241
+ ok: true, path: null, parent: null, home,
242
+ entries: roots.map(p => ({ name: p, path: p, kind: 'dir' })),
243
+ };
244
+ }
245
+ const expanded = rawPath.startsWith('~') ? join(home, rawPath.slice(1)) : rawPath;
246
+ let resolved;
247
+ try {
248
+ resolved = realpathSync(expanded);
249
+ }
250
+ catch {
251
+ return { ok: false, path: null, parent: null, entries: [], error: 'path_not_found' };
252
+ }
253
+ let entries;
254
+ try {
255
+ entries = readdirSync(resolved, { withFileTypes: true })
256
+ .filter(d => {
257
+ try {
258
+ return d.isDirectory() || (d.isSymbolicLink() && statSync(join(resolved, d.name)).isDirectory());
259
+ }
260
+ catch {
261
+ return false;
262
+ }
263
+ })
264
+ .map(d => ({ name: d.name, path: join(resolved, d.name), kind: 'dir' }))
265
+ .sort((a, b) => a.name.localeCompare(b.name));
266
+ }
267
+ catch (e) {
268
+ return { ok: false, path: resolved, parent: null, entries: [], error: e?.code === 'EACCES' ? 'permission_denied' : 'cannot_read_dir' };
269
+ }
270
+ const parent = resolved === '/' ? null : dirname(resolved);
271
+ return { ok: true, path: resolved, parent, entries };
272
+ }
199
273
  function resolveScheduleOwner(id) {
200
274
  const explicit = aggregator.scheduleOwnerOf(id);
201
275
  if (explicit)
@@ -269,8 +343,58 @@ function spawnStartBotLive(appId) {
269
343
  }
270
344
  });
271
345
  }
346
+ function spawnStopBotLive(appId) {
347
+ return new Promise((resolve) => {
348
+ let out = '';
349
+ let err = '';
350
+ let settled = false;
351
+ const done = (r) => { if (!settled) {
352
+ settled = true;
353
+ resolve(r);
354
+ } };
355
+ try {
356
+ const child = spawn(process.execPath, [botmuxCliEntry(), 'stop-bot', appId, '--json'], {
357
+ stdio: ['ignore', 'pipe', 'pipe'],
358
+ env: process.env,
359
+ cwd: globalInstallUpdateCwd(),
360
+ });
361
+ const timer = setTimeout(() => {
362
+ try {
363
+ child.kill('SIGKILL');
364
+ }
365
+ catch { /* already gone */ }
366
+ done({ ok: false, message: 'stop-bot 超时(30s)' });
367
+ }, 30_000);
368
+ timer.unref?.();
369
+ child.stdout?.on('data', (d) => { out += String(d); });
370
+ child.stderr?.on('data', (d) => { err += String(d); });
371
+ child.on('error', (e) => {
372
+ clearTimeout(timer);
373
+ done({ ok: false, message: e instanceof Error ? e.message : String(e) });
374
+ });
375
+ child.on('exit', (code) => {
376
+ clearTimeout(timer);
377
+ let parsed;
378
+ try {
379
+ parsed = JSON.parse(out.trim());
380
+ }
381
+ catch { /* non-JSON */ }
382
+ if (code === 0) {
383
+ done({ ok: true, message: parsed?.processName ? `${parsed.processName} 已停止` : undefined });
384
+ }
385
+ else {
386
+ done({ ok: false, message: parsed?.message || err.trim() || `stop-bot 退出码 ${code}` });
387
+ }
388
+ });
389
+ }
390
+ catch (e) {
391
+ done({ ok: false, message: e instanceof Error ? e.message : String(e) });
392
+ }
393
+ });
394
+ }
272
395
  const botOnboarding = new BotOnboardingManager({
273
396
  botsJsonPath: BOTS_JSON_PATH,
397
+ stopBotLive: spawnStopBotLive,
274
398
  startBotLive: spawnStartBotLive,
275
399
  });
276
400
  // 飞书 Web 登录态刷新(机器人改名缺登录态时的 dashboard 扫码入口)。机器级单例,
@@ -306,6 +430,51 @@ async function validateVcMeetingListenerBotAppId(appId) {
306
430
  return { ok: false, error: 'vcMeetingAgent_listenerBot_unknown' };
307
431
  return { ok: true };
308
432
  }
433
+ async function validateCodexNotifierTargetBotAppId(appId, options = {}) {
434
+ try {
435
+ const bot = loadBotConfigs().find(candidate => candidate.larkAppId === appId);
436
+ if (!bot)
437
+ return { ok: false, error: 'codexNotifier_target_unknown' };
438
+ if (bot.cliId !== 'codex' && bot.cliId !== 'codex-app') {
439
+ return { ok: false, error: 'codexNotifier_target_cli_unsupported' };
440
+ }
441
+ if (!(bot.allowedUsers ?? []).some(user => typeof user === 'string' && user.trim())) {
442
+ return { ok: false, error: 'codexNotifier_target_owner_missing' };
443
+ }
444
+ if (options.requireReady !== true)
445
+ return { ok: true };
446
+ const daemon = registry.list().find(candidate => candidate.larkAppId === appId);
447
+ if (!daemon)
448
+ return { ok: false, error: 'codexNotifier_target_daemon_offline' };
449
+ const resolvedOwners = daemon.resolvedAllowedUsers ?? [];
450
+ if (!hasResolvedCodexNotifierRecipient(resolvedOwners)) {
451
+ return { ok: false, error: 'codexNotifier_target_owner_unverified' };
452
+ }
453
+ return { ok: true };
454
+ }
455
+ catch {
456
+ return { ok: false, error: 'codexNotifier_target_unknown' };
457
+ }
458
+ }
459
+ function codexNotifierBotOptions() {
460
+ try {
461
+ const onlineByAppId = new Map(registry.list().map(bot => [bot.larkAppId, bot]));
462
+ return loadBotConfigs()
463
+ .filter(bot => bot.cliId === 'codex' || bot.cliId === 'codex-app')
464
+ .map(bot => {
465
+ const resolvedOwners = onlineByAppId.get(bot.larkAppId)?.resolvedAllowedUsers ?? [];
466
+ return {
467
+ larkAppId: bot.larkAppId,
468
+ botName: bot.displayName ?? onlineByAppId.get(bot.larkAppId)?.botName ?? bot.name ?? null,
469
+ cliId: onlineByAppId.get(bot.larkAppId)?.cliId ?? bot.cliId,
470
+ ...resolveCodexNotifierRecipientView(bot.allowedUsers, resolvedOwners),
471
+ };
472
+ });
473
+ }
474
+ catch {
475
+ return [];
476
+ }
477
+ }
309
478
  function normalizeVcMeetingAgentRecord(raw) {
310
479
  return raw && typeof raw === 'object' && !Array.isArray(raw)
311
480
  ? { ...raw }
@@ -664,6 +833,9 @@ async function syncVcMeetingListenerBotConfig(listenerBotAppId, previousListener
664
833
  function resolveDashboardSettings() {
665
834
  const global = readGlobalConfig();
666
835
  const dashboard = global.dashboard ?? {};
836
+ const codexNotifier = resolveCodexNotifierConfig();
837
+ const codexNotifierBots = codexNotifierBotOptions();
838
+ const codexNotifierState = readCodexNotifierWorkerState(config.session.dataDir);
667
839
  const larkCli = checkLarkCliVersion();
668
840
  return {
669
841
  publicReadOnly: dashboard.publicReadOnly ?? config.dashboard.publicReadOnly,
@@ -679,6 +851,19 @@ function resolveDashboardSettings() {
679
851
  recommendedRef: TRAEX_RECOMMENDED_REF,
680
852
  },
681
853
  codexRpcInput: dashboard.codexRpcInput === true, // default OFF until live-verified
854
+ codexNotifier: {
855
+ enabled: codexNotifier.enabled,
856
+ targetBotAppId: codexNotifier.targetBotAppId ?? null,
857
+ notifyWhen: codexNotifier.notifyWhen,
858
+ platformSupported: process.platform === 'darwin',
859
+ hookInstalled: isCodexNotifierHookInstalled(),
860
+ botOptions: codexNotifierBots,
861
+ targetDaemonOnline: !!codexNotifier.targetBotAppId
862
+ && registry.list().some(bot => bot.larkAppId === codexNotifier.targetBotAppId),
863
+ pendingCount: listCodexNotifierOutbox(config.session.dataDir).length,
864
+ workerOnline: isCodexNotifierWorkerStateFresh(codexNotifierState),
865
+ lastError: codexNotifierState?.lastError ?? null,
866
+ },
682
867
  vcMeetingAgent: {
683
868
  enabled: global.vcMeetingAgent?.enabled !== false,
684
869
  listenerBotAppId: global.vcMeetingAgent?.listenerBotAppId ?? null,
@@ -707,6 +892,7 @@ async function reloadLocaleOnAllDaemons() {
707
892
  const settingsWriteApplierDeps = defaultSettingsWriteApplierDeps(resolveDashboardSettings, reloadLocaleOnAllDaemons);
708
893
  settingsWriteApplierDeps.syncVcMeetingListenerBotConfig = syncVcMeetingListenerBotConfig;
709
894
  settingsWriteApplierDeps.validateVcMeetingListenerBotAppId = validateVcMeetingListenerBotAppId;
895
+ settingsWriteApplierDeps.validateCodexNotifierTargetBotAppId = validateCodexNotifierTargetBotAppId;
710
896
  /** Helper to render a {status, body} HandlerResult through `res`. */
711
897
  function writeHandlerResult(res, result) {
712
898
  const headers = { 'content-type': 'application/json', ...(result.headers ?? {}) };
@@ -940,6 +1126,29 @@ registry.on(syncSubscriptions);
940
1126
  // Initial attach for every daemon already known. Run in parallel so a slow
941
1127
  // daemon doesn't block the others.
942
1128
  await Promise.all(registry.list().map(attachDaemon));
1129
+ const codexNotifierAbort = new AbortController();
1130
+ if (resolveCodexNotifierConfig().enabled) {
1131
+ try {
1132
+ installCodexNotifierHook();
1133
+ }
1134
+ catch (error) {
1135
+ logger.warn(`[codex-notifier] Hook reconcile failed: ${error instanceof Error ? error.message : String(error)}`);
1136
+ }
1137
+ }
1138
+ void runCodexNotifierWorkerSupervisor({
1139
+ dataDir: config.session.dataDir,
1140
+ signal: codexNotifierAbort.signal,
1141
+ emit: item => emitCodexNotifierOutboxItem(item, { signal: codexNotifierAbort.signal }),
1142
+ runProducer: signal => runCodexSideConversationMonitor({
1143
+ dataDir: config.session.dataDir,
1144
+ signal,
1145
+ logger,
1146
+ }),
1147
+ logger,
1148
+ onLeaseUnavailable: path => {
1149
+ logger.warn(`[codex-notifier] outbox worker 已由另一 Dashboard 持有,等待接管:${path}`);
1150
+ },
1151
+ });
943
1152
  const resourceMonitor = createResourceMonitorService({
944
1153
  intervalMs: 10_000,
945
1154
  topSessionLimit: 30,
@@ -2104,14 +2313,15 @@ const server = createServer(async (req, res) => {
2104
2313
  return jsonRes(res, 200, { ok: true });
2105
2314
  }
2106
2315
  const presentedToken = authedToken(req, url);
2107
- const dashboardSettings = resolveDashboardSettings();
2316
+ const globalDashboardConfig = readGlobalConfig().dashboard;
2108
2317
  const decision = decideDashboardAuth({
2109
2318
  method: req.method ?? 'GET',
2110
2319
  pathname: url.pathname,
2111
2320
  hasTokenParam: url.searchParams.has('t'),
2112
2321
  presentedToken,
2113
2322
  activeToken: activeToken ?? '',
2114
- publicReadOnly: dashboardSettings.publicReadOnly,
2323
+ publicReadOnly: globalDashboardConfig?.publicReadOnly
2324
+ ?? config.dashboard.publicReadOnly,
2115
2325
  });
2116
2326
  // `authed` is consumed by route handlers that distinguish the public-read
2117
2327
  // carve-out from a valid management cookie (notably v3 run details).
@@ -2160,6 +2370,16 @@ const server = createServer(async (req, res) => {
2160
2370
  && await handlePluginManagementApi(req, res, url)) {
2161
2371
  return;
2162
2372
  }
2373
+ // 调试终端(owner-only):HTTP 路由挂在 auth gate 之后 → 已确保是管理 token。
2374
+ // /api/debug-terminal(创建/关闭)+ /debug-terminal/<id>(xterm 页面)。
2375
+ // WS 升级 /debug-terminal/<id>/ws 在下方 server.on('upgrade') 里由本 manager
2376
+ // 自行校验 cookie(upgrade 不经这段 gate)。
2377
+ if (url.pathname === '/api/debug-terminal'
2378
+ || url.pathname.startsWith('/api/debug-terminal/')
2379
+ || url.pathname.startsWith('/debug-terminal/')) {
2380
+ if (debugTerminalManager.handleHttp(req, res, url))
2381
+ return;
2382
+ }
2163
2383
  if (req.method === 'GET' && url.pathname === '/api/plugins/dashboard') {
2164
2384
  return jsonRes(res, 200, { plugins: listDashboardPluginEntries() });
2165
2385
  }
@@ -2326,6 +2546,7 @@ const server = createServer(async (req, res) => {
2326
2546
  return jsonRes(res, 200, { schedules, timezone: scheduleTimeZone() });
2327
2547
  }
2328
2548
  if (req.method === 'GET' && url.pathname === '/api/settings') {
2549
+ const dashboardSettings = resolveDashboardSettings();
2329
2550
  // `authed` lets the Settings page disable toggles for read-only
2330
2551
  // visitors up front, instead of letting them flip a switch that
2331
2552
  // 401s + rolls back on save.
@@ -2335,7 +2556,7 @@ const server = createServer(async (req, res) => {
2335
2556
  // `bound` reflects central-platform binding; the Settings UI only shows the
2336
2557
  // 远程访问 toggle when bound (the central URLs are meaningless otherwise).
2337
2558
  return jsonRes(res, 200, {
2338
- settings: dashboardSettings,
2559
+ settings: authed ? dashboardSettings : redactSettingsForPublic(dashboardSettings),
2339
2560
  lang: readGlobalConfig().lang ?? null,
2340
2561
  authed,
2341
2562
  bound: readPlatformBinding() !== null,
@@ -3053,6 +3274,14 @@ const server = createServer(async (req, res) => {
3053
3274
  return jsonRes(res, 400, { ok: false, error: 'missing_expected_identity', message: '免扫码添加前必须确认当前账号与企业' });
3054
3275
  }
3055
3276
  const sessionMode = sessionModeRaw === 'reuse' ? 'reuse' : 'qr';
3277
+ if (parsed.requireCriticalScopesBeforeActivation !== undefined
3278
+ && typeof parsed.requireCriticalScopesBeforeActivation !== 'boolean') {
3279
+ return jsonRes(res, 400, {
3280
+ ok: false,
3281
+ error: 'invalid_critical_scope_activation_gate',
3282
+ message: 'requireCriticalScopesBeforeActivation 必须是 boolean',
3283
+ });
3284
+ }
3056
3285
  const job = botOnboarding.start({
3057
3286
  appName,
3058
3287
  registrationMode,
@@ -3062,9 +3291,93 @@ const server = createServer(async (req, res) => {
3062
3291
  workingDir,
3063
3292
  dirMode,
3064
3293
  model,
3294
+ ...(parsed.requireCriticalScopesBeforeActivation === true
3295
+ ? { requireCriticalScopesBeforeActivation: true }
3296
+ : {}),
3065
3297
  });
3066
3298
  return jsonRes(res, 202, { job: botOnboarding.get(job.id) });
3067
3299
  }
3300
+ if (req.method === 'POST' && url.pathname === '/api/bot-onboarding/recover-permissions') {
3301
+ let parsed;
3302
+ try {
3303
+ const chunks = [];
3304
+ for await (const c of req)
3305
+ chunks.push(c);
3306
+ const raw = Buffer.concat(chunks).toString('utf8');
3307
+ parsed = raw ? JSON.parse(raw) : {};
3308
+ }
3309
+ catch {
3310
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3311
+ }
3312
+ const workingDir = typeof parsed.workingDir === 'string' ? parsed.workingDir.trim() : '';
3313
+ const predecessorJobId = typeof parsed.predecessorJobId === 'string' ? parsed.predecessorJobId.trim() : '';
3314
+ const expectedAppId = typeof parsed.expectedAppId === 'string' ? parsed.expectedAppId.trim() : '';
3315
+ const priorRecoveryJobId = typeof parsed.priorRecoveryJobId === 'string' ? parsed.priorRecoveryJobId.trim() : undefined;
3316
+ if (parsed.requireCriticalScopesBeforeActivation !== undefined
3317
+ && typeof parsed.requireCriticalScopesBeforeActivation !== 'boolean') {
3318
+ return jsonRes(res, 400, {
3319
+ ok: false,
3320
+ error: 'invalid_critical_scope_activation_gate',
3321
+ message: 'requireCriticalScopesBeforeActivation 必须是 boolean',
3322
+ });
3323
+ }
3324
+ if (!workingDir || !predecessorJobId || !expectedAppId || invalidWorkingDirs({ workingDir }).length > 0) {
3325
+ return jsonRes(res, 400, { ok: false, error: 'permission_recovery_target_invalid' });
3326
+ }
3327
+ const recovered = botOnboarding.startPermissionRecovery({
3328
+ workingDir,
3329
+ predecessorJobId,
3330
+ expectedAppId,
3331
+ priorRecoveryJobId,
3332
+ ...(parsed.requireCriticalScopesBeforeActivation === true
3333
+ ? { requireCriticalScopesBeforeActivation: true }
3334
+ : {}),
3335
+ });
3336
+ if (!recovered.ok) {
3337
+ const status = recovered.error === 'permission_recovery_target_missing' ? 404
3338
+ : recovered.error === 'permission_recovery_target_ambiguous' ? 409
3339
+ : recovered.error === 'permission_recovery_state_unavailable' ? 503
3340
+ : 400;
3341
+ return jsonRes(res, status, recovered);
3342
+ }
3343
+ return jsonRes(res, 202, { job: botOnboarding.get(recovered.job.id) });
3344
+ }
3345
+ let mScopePropagation;
3346
+ if (req.method === 'POST'
3347
+ && (mScopePropagation = url.pathname.match(/^\/api\/bot-onboarding\/([^/]+)\/complete-scope-propagation$/))) {
3348
+ const onboardingId = decodeURIComponent(mScopePropagation[1]);
3349
+ let parsed;
3350
+ try {
3351
+ const chunks = [];
3352
+ for await (const c of req)
3353
+ chunks.push(c);
3354
+ const raw = Buffer.concat(chunks).toString('utf8');
3355
+ parsed = raw ? JSON.parse(raw) : {};
3356
+ }
3357
+ catch {
3358
+ return jsonRes(res, 400, { ok: false, error: 'bad_json' });
3359
+ }
3360
+ const workingDir = typeof parsed.workingDir === 'string' ? parsed.workingDir.trim() : '';
3361
+ const expectedAppId = typeof parsed.expectedAppId === 'string' ? parsed.expectedAppId.trim() : '';
3362
+ if (!workingDir || !expectedAppId || invalidWorkingDirs({ workingDir }).length > 0) {
3363
+ return jsonRes(res, 400, { ok: false, error: 'permission_recovery_target_invalid' });
3364
+ }
3365
+ const completed = await botOnboarding.completeScopePropagation({
3366
+ jobId: onboardingId,
3367
+ workingDir,
3368
+ expectedAppId,
3369
+ });
3370
+ if (!completed.ok) {
3371
+ const status = completed.error === 'permission_recovery_target_missing' ? 404
3372
+ : completed.error === 'permission_recovery_target_ambiguous' ? 409
3373
+ : completed.error === 'permission_recovery_scopes_pending' ? 425
3374
+ : (completed.error === 'permission_recovery_state_unavailable'
3375
+ || completed.error === 'permission_recovery_activation_failed') ? 503
3376
+ : 400;
3377
+ return jsonRes(res, status, completed);
3378
+ }
3379
+ return jsonRes(res, 200, { job: botOnboarding.get(onboardingId) });
3380
+ }
3068
3381
  let mOwner;
3069
3382
  if (req.method === 'POST' && (mOwner = url.pathname.match(/^\/api\/bot-onboarding\/([^/]+)\/owner$/))) {
3070
3383
  // needs_owner 状态下用户手动提交 owner:扫码人身份验证不了时的兜底入口。
@@ -3219,6 +3532,18 @@ const server = createServer(async (req, res) => {
3219
3532
  res.end(await upstream.text());
3220
3533
  return;
3221
3534
  }
3535
+ // Dashboard「复现命令」:透传到 owning daemon 取该 session 的真实 CLI 调用。
3536
+ // 与 write-link 同样只在管理 cookie(写权限)下可达:命令含 token/凭证。
3537
+ if (req.method === 'GET' && (m = url.pathname.match(/^\/api\/sessions\/([^/]+)\/spawn-command$/))) {
3538
+ const sid = decodeURIComponent(m[1]);
3539
+ const owner = aggregator.ownerOf(sid);
3540
+ if (!owner)
3541
+ return jsonRes(res, 404, { ok: false, error: 'unknown_session' });
3542
+ const upstream = await proxyToDaemon(owner, `/api/sessions/${sid}/spawn-command`, { method: 'GET' });
3543
+ res.writeHead(upstream.status, { 'content-type': 'application/json' });
3544
+ res.end(await upstream.text());
3545
+ return;
3546
+ }
3222
3547
  // Sandbox landing: review the clone's diff (GET) then apply/discard (POST).
3223
3548
  if (req.method === 'GET' && (m = url.pathname.match(/^\/api\/sessions\/([^/]+)\/sandbox-diff$/))) {
3224
3549
  const sid = decodeURIComponent(m[1]);
@@ -3805,6 +4130,33 @@ const server = createServer(async (req, res) => {
3805
4130
  res.end(await upstream.text());
3806
4131
  return;
3807
4132
  }
4133
+ // PUT /api/bots/:appId/sandbox-paths — proxy to that bot's daemon.
4134
+ // Body `{ readWrite?: string[]; readOnly?: string[]; deny?: string[] }`.
4135
+ let mBotSandboxPaths;
4136
+ if (req.method === 'PUT' && (mBotSandboxPaths = url.pathname.match(/^\/api\/bots\/([^/]+)\/sandbox-paths$/))) {
4137
+ const appId = decodeURIComponent(mBotSandboxPaths[1]);
4138
+ const chunks = [];
4139
+ for await (const c of req)
4140
+ chunks.push(c);
4141
+ const raw = Buffer.concat(chunks).toString('utf8') || '{}';
4142
+ const upstream = await proxyToDaemon(appId, `/api/bot-sandbox-paths`, {
4143
+ method: 'PUT',
4144
+ headers: { 'content-type': 'application/json' },
4145
+ body: raw,
4146
+ });
4147
+ res.writeHead(upstream.status, { 'content-type': 'application/json' });
4148
+ res.end(await upstream.text());
4149
+ return;
4150
+ }
4151
+ // GET /api/fs/list?path=… — read-only directory listing for the sandbox-paths
4152
+ // tree picker. Not bot-specific (the filesystem is shared with this host's
4153
+ // daemons — the dashboard process runs on the SAME machine), so serve it
4154
+ // locally instead of proxying. Returns immediate child directories only.
4155
+ if (req.method === 'GET' && url.pathname === '/api/fs/list') {
4156
+ res.writeHead(200, { 'content-type': 'application/json' });
4157
+ res.end(JSON.stringify(listDirLocally(url.searchParams.get('path') ?? '')));
4158
+ return;
4159
+ }
3808
4160
  // PUT /api/bots/:appId/sandbox — proxy to that bot's daemon. Body `{ enabled: boolean }`.
3809
4161
  let mBotSandbox;
3810
4162
  if (req.method === 'PUT' && (mBotSandbox = url.pathname.match(/^\/api\/bots\/([^/]+)\/sandbox$/))) {
@@ -4325,7 +4677,20 @@ const server = createServer(async (req, res) => {
4325
4677
  const hb = setInterval(() => {
4326
4678
  res.write(`event: heartbeat\ndata: ${JSON.stringify({ ts: Date.now() })}\n\n`);
4327
4679
  }, 15_000);
4328
- res.on('close', () => { off(); clearInterval(hb); });
4680
+ // Push a bots.changed frame whenever the online bot roster actually
4681
+ // changes (bot added / removed / renamed / re-indexed) so the Bot 配置
4682
+ // page can auto-refresh without a manual reload. registry.on fires on
4683
+ // every 15s poll and 30s heartbeat rewrite, so gate on a roster signature
4684
+ // that ignores lastHeartbeat — otherwise we'd spam a frame every poll.
4685
+ let lastRoster = botsRosterSignature(registry.list());
4686
+ const offRoster = registry.on(online => {
4687
+ const sig = botsRosterSignature(online);
4688
+ if (sig === lastRoster)
4689
+ return;
4690
+ lastRoster = sig;
4691
+ res.write(`event: bots.changed\ndata: ${JSON.stringify({ body: { signature: sig } })}\n\n`);
4692
+ });
4693
+ res.on('close', () => { off(); offRoster(); clearInterval(hb); });
4329
4694
  return;
4330
4695
  }
4331
4696
  // Public API + static frontend land in Task 17 / 18. For now: 404.
@@ -4346,6 +4711,11 @@ const server = createServer(async (req, res) => {
4346
4711
  server.on('upgrade', (req, clientSocket, head) => {
4347
4712
  try {
4348
4713
  const rawUrl = req.url ?? '/';
4714
+ // 调试终端 WS(owner-only):manager 内部自校验管理 cookie。命中即接管。
4715
+ if (rawUrl.startsWith('/debug-terminal/')) {
4716
+ if (debugTerminalManager.handleUpgrade(req, clientSocket, head))
4717
+ return;
4718
+ }
4349
4719
  if (!(rawUrl === '/s' || rawUrl.startsWith('/s/') || rawUrl.startsWith('/s?'))) {
4350
4720
  return clientSocket.destroy();
4351
4721
  }
@@ -4671,12 +5041,14 @@ async function maybeAnnounceHallPresence() {
4671
5041
  }
4672
5042
  // Graceful shutdown
4673
5043
  function shutdown() {
5044
+ codexNotifierAbort.abort();
4674
5045
  for (const off of subs.values())
4675
5046
  off();
4676
5047
  subs.clear();
4677
5048
  registry.stop();
4678
5049
  resourceMonitor.stop();
4679
5050
  platformTunnel?.stop();
5051
+ debugTerminalManager.shutdown();
4680
5052
  server.close(() => process.exit(0));
4681
5053
  // Hard-exit fallback after 5s
4682
5054
  setTimeout(() => process.exit(0), 5_000).unref();