botmux 3.13.0 → 3.14.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 (508) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +25 -1
  3. package/dist/.runtime-build-id +1 -1
  4. package/dist/adapters/adopt-route.d.ts +58 -0
  5. package/dist/adapters/adopt-route.d.ts.map +1 -1
  6. package/dist/adapters/adopt-route.js +136 -0
  7. package/dist/adapters/adopt-route.js.map +1 -1
  8. package/dist/adapters/backend/capabilities.js +1 -1
  9. package/dist/adapters/backend/capabilities.js.map +1 -1
  10. package/dist/adapters/backend/herdr-backend.d.ts +1 -1
  11. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  12. package/dist/adapters/backend/herdr-backend.js +2 -1
  13. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  14. package/dist/adapters/backend/riff-backend.d.ts +97 -0
  15. package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
  16. package/dist/adapters/backend/riff-backend.js +380 -66
  17. package/dist/adapters/backend/riff-backend.js.map +1 -1
  18. package/dist/adapters/backend/sandbox.d.ts +8 -0
  19. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  20. package/dist/adapters/backend/sandbox.js +16 -2
  21. package/dist/adapters/backend/sandbox.js.map +1 -1
  22. package/dist/adapters/backend/tmux-backend.d.ts +12 -13
  23. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  24. package/dist/adapters/backend/tmux-backend.js +113 -53
  25. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  26. package/dist/adapters/backend/tmux-pipe-backend.d.ts +4 -3
  27. package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
  28. package/dist/adapters/backend/tmux-pipe-backend.js +12 -9
  29. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  30. package/dist/adapters/backend/zellij-backend.d.ts +2 -3
  31. package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
  32. package/dist/adapters/backend/zellij-backend.js +6 -13
  33. package/dist/adapters/backend/zellij-backend.js.map +1 -1
  34. package/dist/adapters/backend/zellij-observe-backend.d.ts +2 -1
  35. package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
  36. package/dist/adapters/backend/zellij-observe-backend.js +6 -3
  37. package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
  38. package/dist/adapters/backend/zmx-backend.d.ts.map +1 -1
  39. package/dist/adapters/backend/zmx-backend.js +40 -18
  40. package/dist/adapters/backend/zmx-backend.js.map +1 -1
  41. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  42. package/dist/adapters/cli/claude-code.js +12 -1
  43. package/dist/adapters/cli/claude-code.js.map +1 -1
  44. package/dist/adapters/cli/codex.d.ts.map +1 -1
  45. package/dist/adapters/cli/codex.js +3 -2
  46. package/dist/adapters/cli/codex.js.map +1 -1
  47. package/dist/adapters/cli/dsh.d.ts +4 -0
  48. package/dist/adapters/cli/dsh.d.ts.map +1 -0
  49. package/dist/adapters/cli/dsh.js +96 -0
  50. package/dist/adapters/cli/dsh.js.map +1 -0
  51. package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
  52. package/dist/adapters/cli/fs-policy.js +5 -0
  53. package/dist/adapters/cli/fs-policy.js.map +1 -1
  54. package/dist/adapters/cli/opencode.d.ts +52 -1
  55. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  56. package/dist/adapters/cli/opencode.js +117 -76
  57. package/dist/adapters/cli/opencode.js.map +1 -1
  58. package/dist/adapters/cli/opencode2.d.ts +4 -0
  59. package/dist/adapters/cli/opencode2.d.ts.map +1 -0
  60. package/dist/adapters/cli/opencode2.js +137 -0
  61. package/dist/adapters/cli/opencode2.js.map +1 -0
  62. package/dist/adapters/cli/read-isolation.d.ts +1 -1
  63. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  64. package/dist/adapters/cli/read-isolation.js +5 -2
  65. package/dist/adapters/cli/read-isolation.js.map +1 -1
  66. package/dist/adapters/cli/registry.d.ts +7 -1
  67. package/dist/adapters/cli/registry.d.ts.map +1 -1
  68. package/dist/adapters/cli/registry.js +19 -6
  69. package/dist/adapters/cli/registry.js.map +1 -1
  70. package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
  71. package/dist/adapters/cli/shared-hints.js +13 -0
  72. package/dist/adapters/cli/shared-hints.js.map +1 -1
  73. package/dist/adapters/cli/types.d.ts +24 -3
  74. package/dist/adapters/cli/types.d.ts.map +1 -1
  75. package/dist/adapters/hook-command.d.ts +8 -0
  76. package/dist/adapters/hook-command.d.ts.map +1 -1
  77. package/dist/adapters/hook-command.js +11 -0
  78. package/dist/adapters/hook-command.js.map +1 -1
  79. package/dist/adapters/hook-installer.d.ts +16 -1
  80. package/dist/adapters/hook-installer.d.ts.map +1 -1
  81. package/dist/adapters/hook-installer.js +232 -2
  82. package/dist/adapters/hook-installer.js.map +1 -1
  83. package/dist/bot-registry.d.ts +116 -8
  84. package/dist/bot-registry.d.ts.map +1 -1
  85. package/dist/bot-registry.js +52 -4
  86. package/dist/bot-registry.js.map +1 -1
  87. package/dist/cli/pm2-start-transaction.d.ts +14 -0
  88. package/dist/cli/pm2-start-transaction.d.ts.map +1 -1
  89. package/dist/cli/pm2-start-transaction.js +25 -9
  90. package/dist/cli/pm2-start-transaction.js.map +1 -1
  91. package/dist/cli/restart-failure-notification.d.ts +54 -0
  92. package/dist/cli/restart-failure-notification.d.ts.map +1 -0
  93. package/dist/cli/restart-failure-notification.js +142 -0
  94. package/dist/cli/restart-failure-notification.js.map +1 -0
  95. package/dist/cli/restart-failure-owner.d.ts +20 -0
  96. package/dist/cli/restart-failure-owner.d.ts.map +1 -0
  97. package/dist/cli/restart-failure-owner.js +27 -0
  98. package/dist/cli/restart-failure-owner.js.map +1 -0
  99. package/dist/cli/restart-shutdown-preflight.d.ts +24 -0
  100. package/dist/cli/restart-shutdown-preflight.d.ts.map +1 -0
  101. package/dist/cli/restart-shutdown-preflight.js +105 -0
  102. package/dist/cli/restart-shutdown-preflight.js.map +1 -0
  103. package/dist/cli/send-dispatch.d.ts +26 -0
  104. package/dist/cli/send-dispatch.d.ts.map +1 -1
  105. package/dist/cli/send-dispatch.js +30 -0
  106. package/dist/cli/send-dispatch.js.map +1 -1
  107. package/dist/cli.d.ts +4 -1
  108. package/dist/cli.d.ts.map +1 -1
  109. package/dist/cli.js +665 -399
  110. package/dist/cli.js.map +1 -1
  111. package/dist/codex-app-runner.js +38 -15
  112. package/dist/codex-app-runner.js.map +1 -1
  113. package/dist/codex-rpc-lifecycle.d.ts +14 -2
  114. package/dist/codex-rpc-lifecycle.d.ts.map +1 -1
  115. package/dist/codex-rpc-lifecycle.js +13 -3
  116. package/dist/codex-rpc-lifecycle.js.map +1 -1
  117. package/dist/core/ask-broker.d.ts +3 -0
  118. package/dist/core/ask-broker.d.ts.map +1 -1
  119. package/dist/core/ask-broker.js +29 -7
  120. package/dist/core/ask-broker.js.map +1 -1
  121. package/dist/core/ask-hook/registry.d.ts.map +1 -1
  122. package/dist/core/ask-hook/registry.js +4 -0
  123. package/dist/core/ask-hook/registry.js.map +1 -1
  124. package/dist/core/ask-types.d.ts +5 -1
  125. package/dist/core/ask-types.d.ts.map +1 -1
  126. package/dist/core/ask-types.js.map +1 -1
  127. package/dist/core/browser-restart.d.ts +112 -0
  128. package/dist/core/browser-restart.d.ts.map +1 -0
  129. package/dist/core/browser-restart.js +233 -0
  130. package/dist/core/browser-restart.js.map +1 -0
  131. package/dist/core/command-handler.d.ts +19 -11
  132. package/dist/core/command-handler.d.ts.map +1 -1
  133. package/dist/core/command-handler.js +237 -43
  134. package/dist/core/command-handler.js.map +1 -1
  135. package/dist/core/current-turn-provenance.d.ts.map +1 -1
  136. package/dist/core/current-turn-provenance.js +7 -27
  137. package/dist/core/current-turn-provenance.js.map +1 -1
  138. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  139. package/dist/core/dashboard-ipc-server.js +317 -10
  140. package/dist/core/dashboard-ipc-server.js.map +1 -1
  141. package/dist/core/dispatch-registry.d.ts.map +1 -1
  142. package/dist/core/dispatch-registry.js +6 -0
  143. package/dist/core/dispatch-registry.js.map +1 -1
  144. package/dist/core/dispatch-report-binding.d.ts +31 -0
  145. package/dist/core/dispatch-report-binding.d.ts.map +1 -0
  146. package/dist/core/dispatch-report-binding.js +88 -0
  147. package/dist/core/dispatch-report-binding.js.map +1 -0
  148. package/dist/core/doc-comment-prompt.d.ts +2 -0
  149. package/dist/core/doc-comment-prompt.d.ts.map +1 -1
  150. package/dist/core/doc-comment-prompt.js +6 -0
  151. package/dist/core/doc-comment-prompt.js.map +1 -1
  152. package/dist/core/host-overload-alert.d.ts +25 -1
  153. package/dist/core/host-overload-alert.d.ts.map +1 -1
  154. package/dist/core/host-overload-alert.js +69 -8
  155. package/dist/core/host-overload-alert.js.map +1 -1
  156. package/dist/core/local-terminal-opener.js +1 -1
  157. package/dist/core/local-terminal-opener.js.map +1 -1
  158. package/dist/core/managed-origin-capability.d.ts +7 -6
  159. package/dist/core/managed-origin-capability.d.ts.map +1 -1
  160. package/dist/core/managed-origin-capability.js +32 -1
  161. package/dist/core/managed-origin-capability.js.map +1 -1
  162. package/dist/core/passthrough-commands.d.ts.map +1 -1
  163. package/dist/core/passthrough-commands.js +3 -2
  164. package/dist/core/passthrough-commands.js.map +1 -1
  165. package/dist/core/plugins/materializer.d.ts.map +1 -1
  166. package/dist/core/plugins/materializer.js +1 -0
  167. package/dist/core/plugins/materializer.js.map +1 -1
  168. package/dist/core/producer-quiescence.d.ts +70 -0
  169. package/dist/core/producer-quiescence.d.ts.map +1 -0
  170. package/dist/core/producer-quiescence.js +90 -0
  171. package/dist/core/producer-quiescence.js.map +1 -0
  172. package/dist/core/raw-command-write-options.d.ts +10 -0
  173. package/dist/core/raw-command-write-options.d.ts.map +1 -0
  174. package/dist/core/raw-command-write-options.js +23 -0
  175. package/dist/core/raw-command-write-options.js.map +1 -0
  176. package/dist/core/raw-command-writer.d.ts +4 -0
  177. package/dist/core/raw-command-writer.d.ts.map +1 -1
  178. package/dist/core/raw-command-writer.js +15 -6
  179. package/dist/core/raw-command-writer.js.map +1 -1
  180. package/dist/core/reply-target.d.ts +11 -0
  181. package/dist/core/reply-target.d.ts.map +1 -1
  182. package/dist/core/reply-target.js +22 -7
  183. package/dist/core/reply-target.js.map +1 -1
  184. package/dist/core/report-session-relay.d.ts +53 -0
  185. package/dist/core/report-session-relay.d.ts.map +1 -0
  186. package/dist/core/report-session-relay.js +116 -0
  187. package/dist/core/report-session-relay.js.map +1 -0
  188. package/dist/core/session-discovery.d.ts +5 -0
  189. package/dist/core/session-discovery.d.ts.map +1 -1
  190. package/dist/core/session-discovery.js +13 -0
  191. package/dist/core/session-discovery.js.map +1 -1
  192. package/dist/core/session-group-birth.d.ts +7 -0
  193. package/dist/core/session-group-birth.d.ts.map +1 -0
  194. package/dist/core/session-group-birth.js +145 -0
  195. package/dist/core/session-group-birth.js.map +1 -0
  196. package/dist/core/session-manager.d.ts +16 -21
  197. package/dist/core/session-manager.d.ts.map +1 -1
  198. package/dist/core/session-manager.js +140 -21
  199. package/dist/core/session-manager.js.map +1 -1
  200. package/dist/core/trigger-session.d.ts.map +1 -1
  201. package/dist/core/trigger-session.js +18 -3
  202. package/dist/core/trigger-session.js.map +1 -1
  203. package/dist/core/types.d.ts +18 -0
  204. package/dist/core/types.d.ts.map +1 -1
  205. package/dist/core/types.js.map +1 -1
  206. package/dist/core/worker-pool.d.ts +63 -11
  207. package/dist/core/worker-pool.d.ts.map +1 -1
  208. package/dist/core/worker-pool.js +241 -13
  209. package/dist/core/worker-pool.js.map +1 -1
  210. package/dist/daemon.d.ts +33 -0
  211. package/dist/daemon.d.ts.map +1 -1
  212. package/dist/daemon.js +900 -137
  213. package/dist/daemon.js.map +1 -1
  214. package/dist/dashboard/auth.d.ts +20 -0
  215. package/dist/dashboard/auth.d.ts.map +1 -1
  216. package/dist/dashboard/auth.js +86 -1
  217. package/dist/dashboard/auth.js.map +1 -1
  218. package/dist/dashboard/bot-payload.d.ts +5 -0
  219. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  220. package/dist/dashboard/bot-payload.js +4 -1
  221. package/dist/dashboard/bot-payload.js.map +1 -1
  222. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
  223. package/dist/dashboard/federation-spoke-api.js +27 -3
  224. package/dist/dashboard/federation-spoke-api.js.map +1 -1
  225. package/dist/dashboard/feedback-analytics-api.d.ts +6 -0
  226. package/dist/dashboard/feedback-analytics-api.d.ts.map +1 -0
  227. package/dist/dashboard/feedback-analytics-api.js +39 -0
  228. package/dist/dashboard/feedback-analytics-api.js.map +1 -0
  229. package/dist/dashboard/session-action-timeout.d.ts +3 -0
  230. package/dist/dashboard/session-action-timeout.d.ts.map +1 -0
  231. package/dist/dashboard/session-action-timeout.js +12 -0
  232. package/dist/dashboard/session-action-timeout.js.map +1 -0
  233. package/dist/dashboard/vc-consumer-profiles-api.d.ts +9 -3
  234. package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
  235. package/dist/dashboard/vc-consumer-profiles-api.js +2 -1
  236. package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
  237. package/dist/dashboard/web/app.d.ts.map +1 -1
  238. package/dist/dashboard/web/app.js +48 -5
  239. package/dist/dashboard/web/app.js.map +1 -1
  240. package/dist/dashboard/web/bot-defaults-page.d.ts +4 -0
  241. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  242. package/dist/dashboard/web/bot-defaults-page.js +273 -36
  243. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  244. package/dist/dashboard/web/bot-defaults.d.ts +6 -0
  245. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  246. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  247. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  248. package/dist/dashboard/web/dashboard-routes.js +1 -0
  249. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  250. package/dist/dashboard/web/feedback-page.d.ts +3 -0
  251. package/dist/dashboard/web/feedback-page.d.ts.map +1 -0
  252. package/dist/dashboard/web/feedback-page.js +34 -0
  253. package/dist/dashboard/web/feedback-page.js.map +1 -0
  254. package/dist/dashboard/web/groups-page.d.ts.map +1 -1
  255. package/dist/dashboard/web/groups-page.js +7 -2
  256. package/dist/dashboard/web/groups-page.js.map +1 -1
  257. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  258. package/dist/dashboard/web/i18n.js +114 -22
  259. package/dist/dashboard/web/i18n.js.map +1 -1
  260. package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
  261. package/dist/dashboard/web/team-federation-page.js +26 -2
  262. package/dist/dashboard/web/team-federation-page.js.map +1 -1
  263. package/dist/dashboard/web/team-federation.d.ts +19 -0
  264. package/dist/dashboard/web/team-federation.d.ts.map +1 -1
  265. package/dist/dashboard/web/team-federation.js +3 -0
  266. package/dist/dashboard/web/team-federation.js.map +1 -1
  267. package/dist/dashboard/web/update-action.d.ts +8 -0
  268. package/dist/dashboard/web/update-action.d.ts.map +1 -1
  269. package/dist/dashboard/web/update-action.js +10 -0
  270. package/dist/dashboard/web/update-action.js.map +1 -1
  271. package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
  272. package/dist/dashboard/web/vc-consumer-profiles-section.js +58 -9
  273. package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
  274. package/dist/dashboard-web/app.js +1 -1
  275. package/dist/dashboard-web/chunks/bot-defaults-page-4RENHE7J.js +10 -0
  276. package/dist/dashboard-web/chunks/chunk-2WQDS65D.js +1 -0
  277. package/dist/dashboard-web/chunks/{chunk-CU4SUKK3.js → chunk-6O7KXFD2.js} +1 -1
  278. package/dist/dashboard-web/chunks/chunk-G5XGBCM6.js +1 -0
  279. package/dist/dashboard-web/chunks/{chunk-6JTZJRQJ.js → chunk-Q2MT4VWH.js} +15 -15
  280. package/dist/dashboard-web/chunks/{chunk-5QJB24I2.js → chunk-U3ZFSO7E.js} +1 -1
  281. package/dist/dashboard-web/chunks/connectors-page-2KZO5KSJ.js +1 -0
  282. package/dist/dashboard-web/chunks/feedback-page-CLVTOLLO.js +1 -0
  283. package/dist/dashboard-web/chunks/groups-page-HLASRTSY.js +8 -0
  284. package/dist/dashboard-web/chunks/{insights-page-EVGGJI5L.js → insights-page-4RPU2CRU.js} +1 -1
  285. package/dist/dashboard-web/chunks/{monitor-room-HRGR2ENP.js → monitor-room-OTKQ2CXK.js} +1 -1
  286. package/dist/dashboard-web/chunks/monitoring-page-IJPUB6JT.js +2 -0
  287. package/dist/dashboard-web/chunks/office-page-QSR3J44Y.js +1 -0
  288. package/dist/dashboard-web/chunks/overview-page-6OK63V4V.js +1 -0
  289. package/dist/dashboard-web/chunks/roles-page-6NWJMOB5.js +1 -0
  290. package/dist/dashboard-web/chunks/schedules-page-6I3LNXD4.js +1 -0
  291. package/dist/dashboard-web/chunks/{sessions-page-DXBCDWCS.js → sessions-page-B2TXGJDO.js} +1 -1
  292. package/dist/dashboard-web/chunks/settings-page-6KJADSC6.js +2 -0
  293. package/dist/dashboard-web/chunks/{skills-page-2QAVB2SA.js → skills-page-M2Q6L5CB.js} +1 -1
  294. package/dist/dashboard-web/chunks/team-federation-page-7I7FDE3B.js +1 -0
  295. package/dist/dashboard-web/chunks/{v3-page-AY35LKCX.js → v3-page-HQXRL65L.js} +1 -1
  296. package/dist/dashboard-web/chunks/whiteboards-page-LQKC4TAZ.js +1 -0
  297. package/dist/dashboard-web/style.css +35 -0
  298. package/dist/dashboard.js +199 -12
  299. package/dist/dashboard.js.map +1 -1
  300. package/dist/desktop/shared/shell-path-probes.d.ts +1 -1
  301. package/dist/desktop/shared/shell-path-probes.js +2 -2
  302. package/dist/desktop/shared/shell-path-probes.js.map +1 -1
  303. package/dist/dsh-runner.d.ts +3 -0
  304. package/dist/dsh-runner.d.ts.map +1 -0
  305. package/dist/dsh-runner.js +666 -0
  306. package/dist/dsh-runner.js.map +1 -0
  307. package/dist/global-config.d.ts +24 -0
  308. package/dist/global-config.d.ts.map +1 -1
  309. package/dist/global-config.js +35 -0
  310. package/dist/global-config.js.map +1 -1
  311. package/dist/i18n/en.d.ts.map +1 -1
  312. package/dist/i18n/en.js +25 -6
  313. package/dist/i18n/en.js.map +1 -1
  314. package/dist/i18n/zh.d.ts.map +1 -1
  315. package/dist/i18n/zh.js +25 -6
  316. package/dist/i18n/zh.js.map +1 -1
  317. package/dist/im/lark/ask-card.d.ts +3 -1
  318. package/dist/im/lark/ask-card.d.ts.map +1 -1
  319. package/dist/im/lark/ask-card.js +61 -5
  320. package/dist/im/lark/ask-card.js.map +1 -1
  321. package/dist/im/lark/card-builder.d.ts.map +1 -1
  322. package/dist/im/lark/card-builder.js +13 -6
  323. package/dist/im/lark/card-builder.js.map +1 -1
  324. package/dist/im/lark/card-handler.d.ts +2 -1
  325. package/dist/im/lark/card-handler.d.ts.map +1 -1
  326. package/dist/im/lark/card-handler.js +145 -5
  327. package/dist/im/lark/card-handler.js.map +1 -1
  328. package/dist/im/lark/event-dispatcher.d.ts +18 -0
  329. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  330. package/dist/im/lark/event-dispatcher.js +36 -9
  331. package/dist/im/lark/event-dispatcher.js.map +1 -1
  332. package/dist/im/lark/md-card.d.ts +18 -0
  333. package/dist/im/lark/md-card.d.ts.map +1 -1
  334. package/dist/im/lark/md-card.js +21 -0
  335. package/dist/im/lark/md-card.js.map +1 -1
  336. package/dist/im/lark/relay-target-routing.d.ts.map +1 -1
  337. package/dist/im/lark/relay-target-routing.js +3 -2
  338. package/dist/im/lark/relay-target-routing.js.map +1 -1
  339. package/dist/im/lark/reply-mode-command.d.ts.map +1 -1
  340. package/dist/im/lark/reply-mode-command.js +19 -8
  341. package/dist/im/lark/reply-mode-command.js.map +1 -1
  342. package/dist/im/lark/skill-feedback-card.d.ts +15 -0
  343. package/dist/im/lark/skill-feedback-card.d.ts.map +1 -0
  344. package/dist/im/lark/skill-feedback-card.js +149 -0
  345. package/dist/im/lark/skill-feedback-card.js.map +1 -0
  346. package/dist/services/bot-config-store.d.ts +10 -1
  347. package/dist/services/bot-config-store.d.ts.map +1 -1
  348. package/dist/services/bot-config-store.js +103 -3
  349. package/dist/services/bot-config-store.js.map +1 -1
  350. package/dist/services/bridge-fallback-gate.d.ts +14 -0
  351. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  352. package/dist/services/bridge-fallback-gate.js +15 -0
  353. package/dist/services/bridge-fallback-gate.js.map +1 -1
  354. package/dist/services/codex-reasoning-effort.d.ts +9 -0
  355. package/dist/services/codex-reasoning-effort.d.ts.map +1 -0
  356. package/dist/services/codex-reasoning-effort.js +23 -0
  357. package/dist/services/codex-reasoning-effort.js.map +1 -0
  358. package/dist/services/codex-service-tier.d.ts +1 -1
  359. package/dist/services/codex-service-tier.d.ts.map +1 -1
  360. package/dist/services/codex-transcript.d.ts +9 -0
  361. package/dist/services/codex-transcript.d.ts.map +1 -1
  362. package/dist/services/codex-transcript.js +13 -6
  363. package/dist/services/codex-transcript.js.map +1 -1
  364. package/dist/services/feed-group-tagger.d.ts +15 -0
  365. package/dist/services/feed-group-tagger.d.ts.map +1 -0
  366. package/dist/services/feed-group-tagger.js +348 -0
  367. package/dist/services/feed-group-tagger.js.map +1 -0
  368. package/dist/services/feedback-analytics.d.ts +82 -0
  369. package/dist/services/feedback-analytics.d.ts.map +1 -0
  370. package/dist/services/feedback-analytics.js +95 -0
  371. package/dist/services/feedback-analytics.js.map +1 -0
  372. package/dist/services/feedback-outbox.d.ts +24 -0
  373. package/dist/services/feedback-outbox.d.ts.map +1 -0
  374. package/dist/services/feedback-outbox.js +12 -0
  375. package/dist/services/feedback-outbox.js.map +1 -0
  376. package/dist/services/feedback-policy-resolver.d.ts +56 -0
  377. package/dist/services/feedback-policy-resolver.d.ts.map +1 -0
  378. package/dist/services/feedback-policy-resolver.js +156 -0
  379. package/dist/services/feedback-policy-resolver.js.map +1 -0
  380. package/dist/services/feedback-policy.d.ts +41 -0
  381. package/dist/services/feedback-policy.d.ts.map +1 -0
  382. package/dist/services/feedback-policy.js +102 -0
  383. package/dist/services/feedback-policy.js.map +1 -0
  384. package/dist/services/feedback-webhook-dispatcher.d.ts +76 -0
  385. package/dist/services/feedback-webhook-dispatcher.d.ts.map +1 -0
  386. package/dist/services/feedback-webhook-dispatcher.js +237 -0
  387. package/dist/services/feedback-webhook-dispatcher.js.map +1 -0
  388. package/dist/services/grant-prefs-store.d.ts +3 -0
  389. package/dist/services/grant-prefs-store.d.ts.map +1 -1
  390. package/dist/services/grant-prefs-store.js +30 -1
  391. package/dist/services/grant-prefs-store.js.map +1 -1
  392. package/dist/services/groups-store.d.ts +14 -0
  393. package/dist/services/groups-store.d.ts.map +1 -1
  394. package/dist/services/groups-store.js +23 -0
  395. package/dist/services/groups-store.js.map +1 -1
  396. package/dist/services/local-cli-opener.d.ts +1 -1
  397. package/dist/services/local-cli-opener.d.ts.map +1 -1
  398. package/dist/services/local-cli-opener.js +2 -0
  399. package/dist/services/local-cli-opener.js.map +1 -1
  400. package/dist/services/prompt-context-store.d.ts +29 -0
  401. package/dist/services/prompt-context-store.d.ts.map +1 -0
  402. package/dist/services/prompt-context-store.js +205 -0
  403. package/dist/services/prompt-context-store.js.map +1 -0
  404. package/dist/services/session-group-avatar.d.ts +6 -0
  405. package/dist/services/session-group-avatar.d.ts.map +1 -0
  406. package/dist/services/session-group-avatar.js +96 -0
  407. package/dist/services/session-group-avatar.js.map +1 -0
  408. package/dist/services/session-group-title.d.ts +47 -0
  409. package/dist/services/session-group-title.d.ts.map +1 -0
  410. package/dist/services/session-group-title.js +226 -0
  411. package/dist/services/session-group-title.js.map +1 -0
  412. package/dist/services/session-groups-store.d.ts +30 -0
  413. package/dist/services/session-groups-store.d.ts.map +1 -0
  414. package/dist/services/session-groups-store.js +132 -0
  415. package/dist/services/session-groups-store.js.map +1 -0
  416. package/dist/services/session-store.d.ts +58 -0
  417. package/dist/services/session-store.d.ts.map +1 -1
  418. package/dist/services/session-store.js +174 -0
  419. package/dist/services/session-store.js.map +1 -1
  420. package/dist/services/skill-feedback-store.d.ts +252 -0
  421. package/dist/services/skill-feedback-store.d.ts.map +1 -0
  422. package/dist/services/skill-feedback-store.js +795 -0
  423. package/dist/services/skill-feedback-store.js.map +1 -0
  424. package/dist/services/skill-registry-store.d.ts +23 -0
  425. package/dist/services/skill-registry-store.d.ts.map +1 -1
  426. package/dist/services/skill-registry-store.js +93 -7
  427. package/dist/services/skill-registry-store.js.map +1 -1
  428. package/dist/services/team-store.d.ts +4 -0
  429. package/dist/services/team-store.d.ts.map +1 -1
  430. package/dist/services/team-store.js +16 -0
  431. package/dist/services/team-store.js.map +1 -1
  432. package/dist/services/traex-transcript.d.ts +32 -4
  433. package/dist/services/traex-transcript.d.ts.map +1 -1
  434. package/dist/services/traex-transcript.js +116 -8
  435. package/dist/services/traex-transcript.js.map +1 -1
  436. package/dist/services/trigger-types.d.ts +1 -1
  437. package/dist/services/trigger-types.d.ts.map +1 -1
  438. package/dist/services/trigger-types.js +2 -2
  439. package/dist/services/trigger-types.js.map +1 -1
  440. package/dist/services/turn-completion-events.d.ts +57 -0
  441. package/dist/services/turn-completion-events.d.ts.map +1 -0
  442. package/dist/services/turn-completion-events.js +179 -0
  443. package/dist/services/turn-completion-events.js.map +1 -0
  444. package/dist/services/vc-meeting-consumer-isolation.d.ts +21 -12
  445. package/dist/services/vc-meeting-consumer-isolation.d.ts.map +1 -1
  446. package/dist/services/vc-meeting-consumer-isolation.js +25 -19
  447. package/dist/services/vc-meeting-consumer-isolation.js.map +1 -1
  448. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +8 -2
  449. package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -1
  450. package/dist/services/vc-meeting-consumer-profile-bootstrap.js +18 -10
  451. package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -1
  452. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  453. package/dist/setup/bot-config-editor.js +6 -0
  454. package/dist/setup/bot-config-editor.js.map +1 -1
  455. package/dist/setup/cli-availability.d.ts +2 -1
  456. package/dist/setup/cli-availability.d.ts.map +1 -1
  457. package/dist/setup/cli-availability.js +2 -1
  458. package/dist/setup/cli-availability.js.map +1 -1
  459. package/dist/setup/cli-selection.d.ts +8 -0
  460. package/dist/setup/cli-selection.d.ts.map +1 -1
  461. package/dist/setup/cli-selection.js +31 -0
  462. package/dist/setup/cli-selection.js.map +1 -1
  463. package/dist/setup/ensure-fonts.d.ts +5 -0
  464. package/dist/setup/ensure-fonts.d.ts.map +1 -1
  465. package/dist/setup/ensure-fonts.js +26 -1
  466. package/dist/setup/ensure-fonts.js.map +1 -1
  467. package/dist/setup/lark-scopes.json +3 -1
  468. package/dist/setup/open-platform-automation.d.ts +1 -1
  469. package/dist/setup/open-platform-automation.d.ts.map +1 -1
  470. package/dist/setup/open-platform-automation.js +15 -3
  471. package/dist/setup/open-platform-automation.js.map +1 -1
  472. package/dist/skills/definitions.d.ts +1 -1
  473. package/dist/skills/definitions.d.ts.map +1 -1
  474. package/dist/skills/definitions.js +9 -2
  475. package/dist/skills/definitions.js.map +1 -1
  476. package/dist/types.d.ts +10 -4
  477. package/dist/types.d.ts.map +1 -1
  478. package/dist/utils/user-token.d.ts +38 -0
  479. package/dist/utils/user-token.d.ts.map +1 -1
  480. package/dist/utils/user-token.js +76 -1
  481. package/dist/utils/user-token.js.map +1 -1
  482. package/dist/utils/web-terminal-scroll.d.ts +27 -0
  483. package/dist/utils/web-terminal-scroll.d.ts.map +1 -0
  484. package/dist/utils/web-terminal-scroll.js +60 -0
  485. package/dist/utils/web-terminal-scroll.js.map +1 -0
  486. package/dist/vc-agent/polling-source.d.ts +70 -0
  487. package/dist/vc-agent/polling-source.d.ts.map +1 -1
  488. package/dist/vc-agent/polling-source.js +115 -0
  489. package/dist/vc-agent/polling-source.js.map +1 -1
  490. package/dist/worker.js +237 -76
  491. package/dist/worker.js.map +1 -1
  492. package/dist/workflows/definition.d.ts +22 -22
  493. package/dist/workflows/events/payloads.d.ts +8 -8
  494. package/dist/workflows/events/schema.d.ts +20 -20
  495. package/dist/workflows/migration/v2-run-archive-schema.d.ts +20 -20
  496. package/package.json +1 -1
  497. package/dist/dashboard-web/chunks/bot-defaults-page-NQJFJ45Z.js +0 -10
  498. package/dist/dashboard-web/chunks/chunk-KEEYQ3WF.js +0 -1
  499. package/dist/dashboard-web/chunks/connectors-page-HADHZXXZ.js +0 -1
  500. package/dist/dashboard-web/chunks/groups-page-5TYF46RS.js +0 -8
  501. package/dist/dashboard-web/chunks/monitoring-page-LBU7TTTW.js +0 -2
  502. package/dist/dashboard-web/chunks/office-page-DF6RRBMN.js +0 -1
  503. package/dist/dashboard-web/chunks/overview-page-ZB6QH2EX.js +0 -1
  504. package/dist/dashboard-web/chunks/roles-page-ZBZGHIIF.js +0 -1
  505. package/dist/dashboard-web/chunks/schedules-page-NQVQC3QY.js +0 -1
  506. package/dist/dashboard-web/chunks/settings-page-E7NN4NVQ.js +0 -2
  507. package/dist/dashboard-web/chunks/team-federation-page-VGWL53AE.js +0 -1
  508. package/dist/dashboard-web/chunks/whiteboards-page-BNWUU4KG.js +0 -1
package/dist/worker.js CHANGED
@@ -23,18 +23,20 @@ import { evaluateCredentialOnlyIsolationGate, credentialIsolationRequired, devic
23
23
  import { buildFsPolicy, compileToSeatbelt, migrateLegacySandboxFields, resolveRedirectedAdapterAuthPaths, FsPolicyConfigError } from './adapters/cli/fs-policy.js';
24
24
  import { killPersistentBackendTarget, killPersistentSession, probePersistentBackendTarget, probePersistentSession, shouldRejectPersistentPostKillProbe } from './core/persistent-backend.js';
25
25
  import { finalizeRawCommandDelivery, writeRawCommandLine } from './core/raw-command-writer.js';
26
+ import { rawCommandWriteOptionsFor } from './core/raw-command-write-options.js';
26
27
  import { publishCliSessionIdToDaemon } from './core/cli-session-id-publisher.js';
27
28
  import { readProcessStartIdentity } from './core/session-marker.js';
28
29
  import { roleLibraryRoot, roleLibrarySubtree } from './core/role-library.js';
29
30
  import { drainTranscript, joinAssistantText, trailingAssistantText, findJsonlContainingFingerprint, findJsonlsContainingExactContent, findLatestJsonl, extractLastAssistantTurn, extractTurnStartText, splitTranscriptEventsByCutoff, isTranscriptRateLimitEvent, apiErrorMessageText } from './services/claude-transcript.js';
30
31
  import { BridgeTurnQueue, makeFingerprint, normaliseForFingerprint } from './services/bridge-turn-queue.js';
31
- import { bridgePostText, isBridgeNothingToSendFinal, shouldEmitEmptyCompletedBridgeFallback, shouldEmitFailedBridgeFallback, shouldSuppressBridgeEmit, stripTrailingBridgeSentinelLine } from './services/bridge-fallback-gate.js';
32
+ import { bridgePostText, isBridgeNothingToSendFinal, shouldSuppressBridgeEmit, structuredFallbackKind, stripTrailingBridgeSentinelLine } from './services/bridge-fallback-gate.js';
32
33
  import { buildSubmitMessagePreview } from './services/submit-notification.js';
33
34
  import { decideHardTimeoutAction, decidePostHookPromptEvidence, decideSettleMarkReady, shouldArmPostHookPromptEvidenceFallback, shouldReleaseFirstPromptTimeout, shouldWaitForPostSessionStartPromptEvidence, shouldWriteNow, POST_HOOK_EVIDENCE_FALLBACK_MS, POST_HOOK_EVIDENCE_RETRY_MS, } from './utils/input-gate.js';
34
35
  import { decideCodexRunnerFreshness, CodexRunnerFreshnessInputQueue, shouldHoldCodexRunnerInput, } from './services/codex-runner-freshness.js';
35
36
  import { canStartInjectionFlush, shouldDeferUserFlush, shouldFlushInjectionsFirst } from './core/inject-queue-policy.js';
36
37
  import { decideRestartFollowup, settleDurableTurnForRestart } from './core/restart-followup-policy.js';
37
38
  import { stripAnsiForLog, tailChars } from './utils/crash-log.js';
39
+ import { parseReadOnlyRemoteScrollPayload, READ_ONLY_REMOTE_SCROLL_SESSION_BUDGET, READ_ONLY_REMOTE_SCROLL_WINDOW_MS, ReadOnlyRemoteScrollLimiter, } from './utils/web-terminal-scroll.js';
38
40
  import { CodexUpdateDialogGuard } from './utils/codex-update-dialog.js';
39
41
  import { EffortConfirmDialogGuard } from './utils/effort-confirm-dialog.js';
40
42
  import { installStdioEpipeGuard, isIgnorableStreamError } from './utils/stdio-epipe-guard.js';
@@ -63,7 +65,7 @@ import { CodexBridgeQueue, pruneExpiredPreStartHeadsAndEmit } from './services/c
63
65
  import { detectCodexComposerState } from './services/codex-composer-state.js';
64
66
  import { generateCodexAppThreadTitle, readCodexAppThreadMetadata, setCodexAppThreadName, } from './services/codex-app-threads.js';
65
67
  import { buildBotmuxLarkNativeSessionTitle } from './core/session-title.js';
66
- import { CODEX_AUTH_ERROR_CODE, CODEX_CONNECTION_ERROR_CODE, CODEX_INVALID_REQUEST_ERROR_CODE, CODEX_RATE_LIMIT_ERROR_CODE, drainCodexRollout, findCodexRolloutBySessionId, findCodexRolloutByPid, findCodexRolloutSetByPid, codexHistorySidIsOwned, splitCodexEventsByCutoff, extractLastCodexTurn, codexSessionIdFromRolloutPath, isCodexRateLimitEvent, scanCodexThreadSettings, readLatestCodexRuntime } from './services/codex-transcript.js';
68
+ import { CODEX_AUTH_ERROR_CODE, CODEX_CONNECTION_ERROR_CODE, CODEX_INVALID_REQUEST_ERROR_CODE, drainCodexRollout, findCodexRolloutBySessionId, findCodexRolloutByPid, findCodexRolloutSetByPid, codexHistorySidIsOwned, splitCodexEventsByCutoff, extractLastCodexTurn, codexSessionIdFromRolloutPath, isCodexRateLimitEvent, scanCodexThreadSettings, readLatestCodexRuntime } from './services/codex-transcript.js';
67
69
  import { CodexServiceTierTracker, resolveCodexServiceTierSnapshot } from './services/codex-service-tier.js';
68
70
  import { WORKER_IPC_HANDLER_READY_EVENT } from './worker-ipc-preload.js';
69
71
  import { drainTraexRollout, findTraexRolloutBySessionId, findTraexRolloutByPid, findTraexRolloutSetByPid, readLatestTraexRuntime, traexHistorySidIsOwned } from './services/traex-transcript.js';
@@ -91,9 +93,9 @@ import { t, setDefaultLocale } from './i18n/index.js';
91
93
  import { TerminalRenderer } from './utils/terminal-renderer.js';
92
94
  import { DEFAULT_RENDER_COLS, DEFAULT_RENDER_ROWS, MAX_RENDER_COLS, MAX_RENDER_ROWS, MIN_RENDER_COLS, MIN_RENDER_ROWS, clamp, resolveRenderDimensions, } from './utils/render-dimensions.js';
93
95
  import { createCliAdapterSync, locateOnPath } from './adapters/cli/registry.js';
94
- import { buildWrappedLaunch, parseWrapperCli, isTtadkWrapper } from './setup/cli-selection.js';
96
+ import { buildWrappedLaunch, parseWrapperCli, isTtadkWrapper, wrapperLaunchEnv } from './setup/cli-selection.js';
95
97
  import { cliUnavailableMessage } from './setup/cli-availability.js';
96
- import { findLaunchedCliPid, scheduleWrapperRealCliPid, readComm, isBareShellComm, bareShellLaunchKind, settleLaunchComm, } from './core/session-discovery.js';
98
+ import { findLaunchedCliPid, scheduleWrapperRealCliPid, readComm, isBareShellComm, bareShellLaunchKind, bareShellLaunchGuidance, settleLaunchComm, } from './core/session-discovery.js';
97
99
  import { CODEX_RPC_TERMINAL_HYDRATION_DELAYS_MS, RpcEngagementFence, codexRpcEligible, paneRunsRemoteTui, orchestrateCodexRpcInit, rolloutUserTurnMatches, decideStartupDialogAction, shouldQueueInitialPrompt, shouldPreMarkFirstTurn, killAndVerifyPersistentPane, rpcTranscriptIngestBlockedByAwaitingActivation } from './codex-rpc-lifecycle.js';
98
100
  import { delay } from './utils/timing.js';
99
101
  import { claudeJsonlPathForSession, resolveJsonlFromPid, findOpenClaudeSessionIds, syncClaudeResumeTargetToCwd, DEFAULT_CLAUDE_DATA_DIR } from './adapters/cli/claude-code.js';
@@ -143,7 +145,7 @@ import { withCodexAppContext } from './utils/codex-app-context.js';
143
145
  import { resolveCodexAppFinalTurnIdentity } from './adapters/cli/codex-app-turn.js';
144
146
  import { RunnerControlDecoder } from './adapters/cli/runner-control-channel.js';
145
147
  import { normalizeCodexAppLifecycleEvent, normalizeFinalUsage, } from './services/codex-app-runner-protocol.js';
146
- import { hasMatchingManagedOriginCapability, ensureManagedOriginAttestationDirectory, ensureManagedOriginCapabilityLeafSafe, ensureManagedOriginDataRootProbe, ensureManagedOriginIsolationSentinel, ensureManagedOriginRootLocator, managedOriginLegacyIsolationProbeAccess, managedOriginDataRootProbeAccess, managedOriginIsolationSentinelAccess, managedOriginAttestationDirectory, managedOriginCapabilityPath, managedOriginRootLocatorPath, readManagedOriginAuthorityFile, RELAY_ORIGIN_CAPABILITY_BASENAME, replaceManagedOriginCapabilityFile, sweepManagedOriginAttestationProofs, } from './core/managed-origin-capability.js';
148
+ import { hasMatchingManagedOriginCapability, ensureManagedOriginAttestationDirectory, ensureManagedOriginCapabilityLeafSafe, ensureManagedOriginDataRootProbe, ensureManagedOriginIsolationSentinel, ensureManagedOriginRootLocator, managedOriginLegacyIsolationProbeAccess, managedOriginDataRootProbeAccess, managedOriginIsolationSentinelAccess, managedOriginAttestationDirectory, managedOriginCapabilityDirectory, managedOriginCapabilityPath, managedOriginRootLocatorPath, readManagedOriginAuthorityFile, RELAY_ORIGIN_CAPABILITY_BASENAME, replaceManagedOriginCapabilityFile, sweepManagedOriginAttestationProofs, } from './core/managed-origin-capability.js';
147
149
  import { CodexRpcEngine, } from './codex-rpc-engine.js';
148
150
  import { beginRuntimeWriteCycle, isCliBackendGenerationCurrent, PtyOutputGeneration, projectRuntimeScreenStatus, } from './utils/runtime-screen-status.js';
149
151
  import { AsyncSerialQueue } from './utils/async-serial-queue.js';
@@ -422,14 +424,22 @@ function persistentPaneInfo(backendType, sessionId) {
422
424
  : HerdrBackend.hasSession(name);
423
425
  return { name, live };
424
426
  }
425
- function persistentPaneLive(backendType, name) {
426
- if (backendType === 'tmux')
427
- return TmuxBackend.hasSession(name);
428
- if (backendType === 'zellij')
429
- return ZellijBackend.hasSession(name);
430
- if (backendType === 'herdr')
431
- return HerdrBackend.hasSession(name);
432
- return ZmxBackend.hasSession(name);
427
+ /** Tri-state pane liveness, for callers that must not read "no answer" as an
428
+ * answer. The `hasSession()` helpers collapse an unanswered probe into
429
+ * `false`, which is safe where a wrong guess just means "treat as fresh" but
430
+ * NOT where the boolean is consumed as proof that a kill succeeded. Every
431
+ * backend already classifies this correctly; only the boolean wrapper threw
432
+ * the distinction away. */
433
+ function persistentPaneProbe(backendType, name) {
434
+ const probe = backendType === 'tmux' ? TmuxBackend.probeSession(name)
435
+ : backendType === 'zellij' ? ZellijBackend.probeSession(name)
436
+ : backendType === 'herdr' ? HerdrBackend.probeSession(name)
437
+ : ZmxBackend.probeSession(name);
438
+ if (probe === 'exists')
439
+ return 'live';
440
+ if (probe === 'missing')
441
+ return 'gone';
442
+ return 'unknown';
433
443
  }
434
444
  function probeOwnedZmxSession(name, sessionId, expectedPid) {
435
445
  const managed = ZmxBackend.probeManagedSession(name, sessionId);
@@ -459,7 +469,7 @@ function probeOwnedZmxSession(name, sessionId, expectedPid) {
459
469
  async function killPersistentSessionVerified(backendType, name, sessionId) {
460
470
  return killAndVerifyPersistentPane(name, {
461
471
  kill: (resolvedName) => killPersistentSession(backendType, resolvedName, sessionId),
462
- isLive: (resolvedName) => persistentPaneLive(backendType, resolvedName),
472
+ probeLive: (resolvedName) => persistentPaneProbe(backendType, resolvedName),
463
473
  wait: delay,
464
474
  });
465
475
  }
@@ -1439,6 +1449,10 @@ const authedClients = new WeakSet();
1439
1449
  const clientPtys = new Map();
1440
1450
  /** Managed-Herdr viewers survive an in-worker /restart while backend changes. */
1441
1451
  const herdrWebBindings = new Map();
1452
+ const readOnlyRemoteScrollLimiter = new ReadOnlyRemoteScrollLimiter({
1453
+ budget: READ_ONLY_REMOTE_SCROLL_SESSION_BUDGET,
1454
+ windowMs: READ_ONLY_REMOTE_SCROLL_WINDOW_MS,
1455
+ });
1442
1456
  // Standalone/test fallback. Production replaces this after init with a stable
1443
1457
  // per-session HMAC derived from the host-only dashboard secret, so an
1444
1458
  // already-issued 「操作链接」/write link survives a worker restart (a silent
@@ -1511,7 +1525,7 @@ let closeRequested = false;
1511
1525
  let capturedSpawnCommand = null;
1512
1526
  let deferredTopicOutputTail = '';
1513
1527
  const reportedDeferredTopicRoots = new Set();
1514
- const CLI_DISPLAY_NAMES = { 'claude-code': 'Claude', seed: 'Seed', relay: 'Relay', aiden: 'Aiden', coco: 'CoCo', codex: 'Codex', 'codex-app': 'Codex App', cursor: 'Cursor', gemini: 'Gemini', genius: 'Genius', opencode: 'OpenCode', antigravity: 'Antigravity', mtr: 'MTR', hermes: 'Hermes', mira: 'Mira', mir: 'Mir CLI', traex: 'TRAE', pi: 'Pi', copilot: 'Copilot', 'oh-my-pi': 'Oh My Pi', kimi: 'Kimi', grok: 'Grok Build', 'kiro-cli': 'Kiro', riff: 'Riff', reasonix: 'Reasonix' };
1528
+ const CLI_DISPLAY_NAMES = { 'claude-code': 'Claude', seed: 'Seed', relay: 'Relay', aiden: 'Aiden', coco: 'CoCo', codex: 'Codex', 'codex-app': 'Codex App', cursor: 'Cursor', gemini: 'Gemini', genius: 'Genius', opencode: 'OpenCode', opencode2: 'OpenCode 2', antigravity: 'Antigravity', mtr: 'MTR', hermes: 'Hermes', mira: 'Mira', mir: 'Mir CLI', traex: 'TRAE', pi: 'Pi', copilot: 'Copilot', 'oh-my-pi': 'Oh My Pi', kimi: 'Kimi', grok: 'Grok Build', 'kiro-cli': 'Kiro', riff: 'Riff', reasonix: 'Reasonix', dsh: 'DeepSeek Harness' };
1515
1529
  function cliName() {
1516
1530
  return (lastInitConfig?.cliRuntime?.source === 'configured'
1517
1531
  ? (lastInitConfig.cliRuntime.displayName?.trim() || lastInitConfig.cliRuntime.id)
@@ -1677,17 +1691,14 @@ function releaseReadyGate(reason, opts) {
1677
1691
  * the next command, capped so a slow/redrawing command can't stall the queue. */
1678
1692
  const STARTUP_CMD_QUIET_MS = 500;
1679
1693
  const STARTUP_CMD_CAP_MS = 4_000;
1680
- /** Inter-keystroke spacing when typing a slash command into CoCo char-by-char.
1681
- * CoCo (Trae CLI, Ink TUI) treats "several bytes delivered in one PTY read" as a
1682
- * paste, which skips command mode + the slash picker — so each char must land as
1683
- * its own keystroke. 40ms is comfortably above CoCo's coalescing window (verified
1684
- * against Trae CLI 0.120.45) while keeping a short command sub-second. */
1685
- const COCO_SLASH_TYPE_THROTTLE_MS = 40;
1686
1694
  /** Type one literal input LINE into the CLI exactly like a passthrough slash
1687
- * command: raw text a 200ms beat (so the TUI's slash-command picker registers
1688
- * the match before submit) a separate Enter. Non-TUI backends fall back to a
1689
- * single write + CR. Shared by the `raw_input` IPC handler and runStartupCommands
1690
- * so both stay in lockstep. */
1695
+ * command. Delivery is adapter-derived: adapters that declare a paste-line
1696
+ * input mode (e.g. OpenCode) paste the line up front, then wait out the
1697
+ * adapter's settle window before pressing Enter; generic backends keep the
1698
+ * classic raw text → a 200ms beat (so the TUI's slash-command picker
1699
+ * registers the match before submit) → a separate Enter, or fall back to a
1700
+ * single write + CR. Shared by the `raw_input` IPC handler and
1701
+ * runStartupCommands so both stay in lockstep. */
1691
1702
  async function sendRawCommandLine(be, content) {
1692
1703
  // PR #597 extracted the CoCo/pty keystroke choreography into the shared
1693
1704
  // writeRawCommandLine helper (unit-tested in raw-command-writer.ts). It
@@ -1695,11 +1706,7 @@ async function sendRawCommandLine(be, content) {
1695
1706
  // recovery-fence transaction detects a failed submission by a thrown error, so
1696
1707
  // bridge the two: turn an explicit `false` into the same throw the inline
1697
1708
  // implementation used, letting runAmbiguousSubmissionTransaction cancel the WAL.
1698
- const accepted = await writeRawCommandLine(be, content, {
1699
- coco: lastInitConfig?.cliId === 'coco',
1700
- cocoThrottleMs: COCO_SLASH_TYPE_THROTTLE_MS,
1701
- submitBeatMs: 200,
1702
- });
1709
+ const accepted = await writeRawCommandLine(be, content, rawCommandWriteOptionsFor(cliAdapter ?? undefined, lastInitConfig?.cliId));
1703
1710
  if (accepted === false) {
1704
1711
  throw new Error('backend rejected command text or submit key input');
1705
1712
  }
@@ -2090,6 +2097,7 @@ let currentBotmuxDispatchAttempt;
2090
2097
  let currentVcMeetingImTurnOrigin;
2091
2098
  let durableTurnInFlight = false;
2092
2099
  function publishSandboxRelayCapability(opts = {}) {
2100
+ const daemonIpcPort = parseDaemonIpcPort(process.env.BOTMUX_DAEMON_IPC_PORT);
2093
2101
  const capability = {
2094
2102
  token: randomBytes(32).toString('hex'),
2095
2103
  ...(currentBotmuxTurnId ? { turnId: currentBotmuxTurnId } : {}),
@@ -2104,6 +2112,21 @@ function publishSandboxRelayCapability(opts = {}) {
2104
2112
  body: JSON.stringify({ token: capability.token }),
2105
2113
  }]
2106
2114
  : []),
2115
+ ...(readIsolationOriginChannelId
2116
+ ? [{
2117
+ path: managedOriginCapabilityPath(process.env.SESSION_DATA_DIR ?? config.session.dataDir, sessionId, readIsolationOriginChannelId),
2118
+ body: JSON.stringify({
2119
+ sessionId,
2120
+ channelId: readIsolationOriginChannelId,
2121
+ capability: capability.token,
2122
+ ...(capability.turnId ? { turnId: capability.turnId } : {}),
2123
+ ...(capability.dispatchAttempt !== undefined
2124
+ ? { dispatchAttempt: capability.dispatchAttempt }
2125
+ : {}),
2126
+ ...(daemonIpcPort !== undefined ? { ipcPort: daemonIpcPort } : {}),
2127
+ }),
2128
+ }]
2129
+ : []),
2107
2130
  ];
2108
2131
  let publishError;
2109
2132
  for (const file of files) {
@@ -4800,8 +4823,11 @@ function currentHermesBridgeDbPath() {
4800
4823
  function structuredBridgeIngestPath(path, offset) {
4801
4824
  if (structuredBridgeIsCodex())
4802
4825
  return drainCodexRollout(path, offset);
4803
- if (structuredBridgeIsTraex())
4804
- return drainTraexRollout(path, offset);
4826
+ // adoptMode gates the drainer's bare-sentinel synthesis: adopt posts
4827
+ // transcript text verbatim, so a synthesised token would leak into Lark.
4828
+ if (structuredBridgeIsTraex()) {
4829
+ return drainTraexRollout(path, offset, { adoptMode: lastInitConfig?.adoptMode === true });
4830
+ }
4805
4831
  if (codexBridgeIsCursor())
4806
4832
  return drainCursorTranscript(path, offset);
4807
4833
  if (structuredBridgeIsPi())
@@ -6020,13 +6046,17 @@ function emitReadyCodexTurns() {
6020
6046
  isLocal: turn.isLocal,
6021
6047
  finalText: turn.finalText,
6022
6048
  terminalStatus: turn.terminalStatus,
6049
+ terminalErrorCode: turn.terminalErrorCode,
6023
6050
  };
6024
- const content = turn.terminalErrorCode !== CODEX_RATE_LIMIT_ERROR_CODE
6025
- && shouldEmitFailedBridgeFallback(gateInput, nextBoundaryMs, markers, adoptMode)
6051
+ // The rate-limit skip is narrowed to CLIs with a dedicated structured
6052
+ // rate-limit chain (Codex): TRAE 429 has no such chain, so skipping the
6053
+ // generic failed fallback would post nothing at all.
6054
+ const fallbackKind = structuredFallbackKind(gateInput, nextBoundaryMs, markers, adoptMode, structuredBridgeIsCodex());
6055
+ const content = fallbackKind === 'failed'
6026
6056
  ? failedBridgeFallbackContent(turn.terminalErrorCode, turn.terminalErrorSummary, turn.finalText)
6027
- : turn.finalText && turn.finalText.trim()
6028
- ? turn.finalText
6029
- : shouldEmitEmptyCompletedBridgeFallback(gateInput, nextBoundaryMs, markers, adoptMode)
6057
+ : fallbackKind === 'final'
6058
+ ? turn.finalText ?? ''
6059
+ : fallbackKind === 'empty_completed'
6030
6060
  ? emptyCompletedBridgeFallbackContent()
6031
6061
  : '';
6032
6062
  if (!content)
@@ -6295,6 +6325,10 @@ function restoreHerdrWebBindings() {
6295
6325
  applyHerdrWebBindingResult(ws, binding.restore());
6296
6326
  }
6297
6327
  }
6328
+ function canHandleReadOnlyRemoteScroll() {
6329
+ return cliAdapter?.readOnlyRemoteScroll === true
6330
+ && !(lastInitConfig?.adoptMode && lastInitConfig.adoptZellijPaneId);
6331
+ }
6298
6332
  function wireHerdrWebTerminalRelays(be) {
6299
6333
  be.onSnapshot(relayHerdrWebSnapshot);
6300
6334
  be.onWebTerminalCursor(relayHerdrWebCursor);
@@ -7548,11 +7582,11 @@ function handleVisibleStartupInteraction(data) {
7548
7582
  }
7549
7583
  return true;
7550
7584
  }
7551
- // Mira/Mir still send terminal OSC control messages. Codex App deliberately
7585
+ // Mira/Mir/dsh send terminal OSC control messages. Codex App deliberately
7552
7586
  // does not (PR #597): its signed Unix-socket channel is independent of the
7553
7587
  // terminal/backend rendering (including Herdr and Zellij), so it is no longer
7554
7588
  // in the terminal-OSC decode set.
7555
- const APP_RUNNER_OSC_CLI_IDS = new Set(['mira', 'mir']);
7589
+ const APP_RUNNER_OSC_CLI_IDS = new Set(['mira', 'mir', 'dsh']);
7556
7590
  const appRunnerControlDecoder = new RunnerControlDecoder();
7557
7591
  let kiroSessionIdCaptureArmed = false;
7558
7592
  let kiroSessionIdCaptureBuffer = '';
@@ -8706,7 +8740,17 @@ function markPromptReady() {
8706
8740
  // make the CLI busy, so the idle state is transient and shouldn't appear
8707
8741
  // in the card. This avoids a false "就绪" flash on daemon restart
8708
8742
  // (where the initial prompt is queued before the CLI becomes idle).
8709
- if (renderer && pendingMessages.length === 0 && pendingAdoptMessages.length === 0 && pendingRawInputs.length === 0 && pendingSessionRename === null && !isFlushing) {
8743
+ //
8744
+ // ALSO skip when the Grok-class busy arm is pending (spawnArgvInitialPromptBusy):
8745
+ // for these adapters the FIRST ready is a pre-execution SessionStart edge, not a
8746
+ // turn boundary — the argv-baked first prompt is still running. isPromptReady was
8747
+ // just set true above, so this generic snapshot would project 'idle' and reach the
8748
+ // daemon BEFORE the busy arm below re-publishes 'working'. Combined with the
8749
+ // first-turn working already sent by startScreenUpdates, the daemon would then see
8750
+ // working→idle and fire finishTurnReactions() — a premature ✅ DONE mid-turn (and a
8751
+ // 「工作中→等待输入→工作中」 flicker on the open card). The busy arm below owns the
8752
+ // correct 'working' publish for this path, so this idle must not escape first.
8753
+ if (renderer && !spawnArgvInitialPromptBusy && pendingMessages.length === 0 && pendingAdoptMessages.length === 0 && pendingRawInputs.length === 0 && pendingSessionRename === null && !isFlushing) {
8710
8754
  const { content } = renderer.snapshot();
8711
8755
  send({
8712
8756
  type: 'screen_update',
@@ -9079,7 +9123,10 @@ async function detectBareShellLaunch() {
9079
9123
  // rcfile may still finish and exec the CLI after this bounded check.
9080
9124
  const launchShell = (lastInitConfig?.launchShell || process.env.SHELL || '').trim();
9081
9125
  const expectedShell = launchShell ? basename(launchShell) : '';
9082
- const trampolined = bareShellLaunchKind(comm, expectedShell) === 'trampoline';
9126
+ if (!comm)
9127
+ return false;
9128
+ const shellComm = comm;
9129
+ const trampolined = bareShellLaunchKind(shellComm, expectedShell) === 'trampoline';
9083
9130
  bareShellLaunchBlocked = true;
9084
9131
  // Injection-first flushes can enter while isPromptReady is still true. Make
9085
9132
  // this a real busy/blocked transition so a later PTY-ready event re-enters
@@ -9094,17 +9141,18 @@ async function detectBareShellLaunch() {
9094
9141
  const cli = cliName();
9095
9142
  let message;
9096
9143
  if (trampolined) {
9144
+ const guidance = bareShellLaunchGuidance(shellComm, expectedShell);
9097
9145
  message =
9098
- `⚠️ 会话没能启动:pane 里现在是裸 \`${comm}\`,${cli} 没真正跑起来——所以我没把你的消息打进去(否则会被当 shell 命令执行,报 \`parse error\`)。\n\n` +
9099
- `最可能原因:botmux 用 \`${expectedShell}\` 启动 CLI,但 pane 落到了 \`${comm}\`。通常是 rc 文件(如 \`~/.${expectedShell}rc\`)里有 \`exec ${comm}\` 这类跳转——\`${expectedShell} -i\` 会 source rc,于是 shell 被顶替,CLI 的启动命令没机会跑。\n\n` +
9146
+ `⚠️ 会话没能启动:pane 里现在是裸 \`${shellComm}\`,${cli} 没真正跑起来——所以我没把你的消息打进去(否则会被当 shell 命令执行,报 \`parse error\`)。\n\n` +
9147
+ `最可能原因:botmux 用 \`${expectedShell}\` 启动 CLI,但 pane 落到了 \`${shellComm}\`。通常是 rc 文件(如 \`${guidance.rcFileHint}\`)里有 \`exec ${shellComm}\` 这类跳转——\`${expectedShell} -i\` 会 source rc,于是 shell 被顶替,CLI 的启动命令没机会跑。\n\n` +
9100
9148
  `两种修法(任选其一,改完重启 daemon 再发一条消息):\n` +
9101
- `① 给那行加守卫,只在手动开终端时切:\`[ -z "$BASH_EXECUTION_STRING" ] && [ -t 1 ] && exec ${comm}\`(注意 PATH/nvm 等导出放在它之前)\n` +
9102
- `② 给这个 bot 配 \`launchShell: ${comm}\`(dashboard 机器人配置,或 \`/config launchShell ${comm}\`),直接用 \`${comm}\` 启动绕开 \`${expectedShell}\` 的 rc——但要确保 PATH/nvm 在 \`${comm}\` 的 rc 里。`;
9149
+ `① 给那行加守卫,只在手动开终端时切:\`${guidance.manualTerminalGuard}\`(注意 PATH/nvm 等导出放在它之前)\n` +
9150
+ `② 给这个 bot 配 \`launchShell: ${shellComm}\`(dashboard 机器人配置,或 \`/config launchShell ${shellComm}\`),直接用 \`${shellComm}\` 启动绕开 \`${expectedShell}\` 的 rc——但要确保 PATH/nvm 在 \`${shellComm}\` 的 rc 里。`;
9103
9151
  }
9104
9152
  else {
9105
9153
  message =
9106
- `⚠️ ${cli} 启动时间较长:pane 里暂时仍是 \`${comm}\`。我没有把消息写进 shell,消息还在队列里;检测到真实输入框后会自动继续投递,无需重发。\n\n` +
9107
- `仅凭进程仍是 \`${comm}\` 无法判断具体原因,可能只是 rc 文件或机器负载让启动变慢。若长时间没有恢复,请打开 Web 终端查看当前提示,处理后等待自动继续,或使用 \`/restart\` 重启会话。`;
9154
+ `⚠️ ${cli} 启动时间较长:pane 里暂时仍是 \`${shellComm}\`。我没有把消息写进 shell,消息还在队列里;检测到真实输入框后会自动继续投递,无需重发。\n\n` +
9155
+ `仅凭进程仍是 \`${shellComm}\` 无法判断具体原因,可能只是 rc 文件或机器负载让启动变慢。若长时间没有恢复,请打开 Web 终端查看当前提示,处理后等待自动继续,或使用 \`/restart\` 重启会话。`;
9108
9156
  }
9109
9157
  const pendingTurn = pendingMessages[0];
9110
9158
  send({
@@ -9985,8 +10033,48 @@ function startScreenUpdates() {
9985
10033
  // watermark — there we must capture every tick (see shouldCaptureScreen).
9986
10034
  let lastSnapshotPtyActivity = -1;
9987
10035
  screenUpdateTimer = setInterval(() => {
9988
- if (awaitingFirstPrompt)
10036
+ if (awaitingFirstPrompt) {
10037
+ // First-turn 「工作中」 publisher. The async sampler below is fully gated
10038
+ // until the first turn ends (markPromptReady flips awaitingFirstPrompt) or
10039
+ // the 15s soft timeout, so an argv-baked first prompt (Pi/Grok/…, delivered
10040
+ // via the launch command — it never goes through flushPending) would emit
10041
+ // NO screen_update for the whole turn: the daemon card sits at 'starting'
10042
+ // and jumps straight to 「等待输入」 on the first idle, skipping 「工作中」.
10043
+ //
10044
+ // The status projection already reads 'working' during turn one (isPromptReady
10045
+ // is still false — same rule that makes every post-submit turn working), so we
10046
+ // simply PUBLISH that projection once instead of scraping the screen for a busy
10047
+ // marker. This is the general "sent to the CLI ⇒ working" model: it fires for
10048
+ // every argv-baked first prompt (spawnArgvNeedsWorkingSeed), not just CLIs that
10049
+ // happen to render a detectable busyPattern.
10050
+ //
10051
+ // Gate on spawnArgvNeedsWorkingSeed so it stays a no-op for a NON-argv first
10052
+ // turn (Claude/Codex/type-ahead): there the prompt is still queued and the CLI
10053
+ // is genuinely booting — not working — until flushPending() submits it after
10054
+ // the ready edge. Empty-prompt adopt sessions also don't arm the flag, so an
10055
+ // attach never falsely claims working.
10056
+ //
10057
+ // Pure publisher: it only send()s a status and updates the local lastSentStatus
10058
+ // dedup — it never touches isPromptReady, the idle detector, or the argv seed
10059
+ // flags (spawnArgvInitialPromptBusy / -NeedsWorkingSeed), so the first-prompt
10060
+ // evidence machinery and the end-of-turn seed are unchanged.
10061
+ if (spawnArgvNeedsWorkingSeed && lastSentStatus !== 'working' && renderer) {
10062
+ const projected = projectedRuntimeScreenStatus();
10063
+ if (projected === 'working') {
10064
+ const { content } = renderer.snapshot();
10065
+ lastSentStatus = 'working';
10066
+ send({
10067
+ type: 'screen_update',
10068
+ content,
10069
+ status: 'working',
10070
+ turnId: currentBotmuxTurnId,
10071
+ dispatchAttempt: currentBotmuxDispatchAttempt,
10072
+ });
10073
+ log('Argv-baked first prompt in flight — publishing projected working before first prompt');
10074
+ }
10075
+ }
9989
10076
  return;
10077
+ }
9990
10078
  void (async () => {
9991
10079
  const { snapshot, status } = await snapshotWithLatestRuntimeStatus(async () => {
9992
10080
  let content = lastContent;
@@ -10708,6 +10796,8 @@ async function spawnCli(cfg, opts = {}) {
10708
10796
  // Feishu. Thread the flag so the reconstructed config keeps the boundary.
10709
10797
  if (cfg.apiOnly)
10710
10798
  sessionEnv.BOTMUX_API_ONLY = '1';
10799
+ if (cfg.feedback)
10800
+ sessionEnv.BOTMUX_FEEDBACK_POLICY = JSON.stringify(cfg.feedback);
10711
10801
  // Session scope for `botmux send` inside the sandbox. Thread sessions
10712
10802
  // anchor on a real om_ message (reply_in_thread); chat-scope sessions use
10713
10803
  // the chat id as anchor (sessionAnchorId), which is NOT a message id —
@@ -10744,6 +10834,12 @@ async function spawnCli(cfg, opts = {}) {
10744
10834
  // Per-bot env (bots.json `env`) takes precedence over session context;
10745
10835
  // explicit riff config.env takes precedence over both.
10746
10836
  const mergedEnv = { ...sessionEnv, ...sanitizePerBotEnv(cfg.env), ...cfg.backendConfig.env };
10837
+ // The effective policy is a host-resolved snapshot, not a user-overridable
10838
+ // backend env knob. Re-freeze it after config.env/per-bot env merge.
10839
+ if (cfg.feedback)
10840
+ mergedEnv.BOTMUX_FEEDBACK_POLICY = JSON.stringify(cfg.feedback);
10841
+ else
10842
+ delete mergedEnv.BOTMUX_FEEDBACK_POLICY;
10747
10843
  // Re-freeze the no-transport capability keys AFTER the merge: a stale or
10748
10844
  // attacker-shaped backendConfig.env / per-bot env merges LAST and would
10749
10845
  // otherwise override the frozen values, restoring send capability for a
@@ -10896,6 +10992,19 @@ async function spawnCli(cfg, opts = {}) {
10896
10992
  resolvedBin: canonicalPolicyPath(cliAdapter.resolvedBin),
10897
10993
  })
10898
10994
  : undefined;
10995
+ const managedOriginChannelRequired = willReadIsolate
10996
+ || credentialOnlySeatbelt
10997
+ || credentialOnlyBwrap;
10998
+ const managedOriginChannelPolicyDigest = (willReadIsolate || willWriteSandbox)
10999
+ ? darwinIsolationPolicyDigest
11000
+ : managedOriginChannelRequired
11001
+ ? createHash('sha256').update(JSON.stringify({
11002
+ domain: 'botmux.credential-origin-channel.v1',
11003
+ platform: process.platform,
11004
+ configuredBotmuxHome: canonicalPolicyPath(configuredBotmuxHome),
11005
+ defaultBotmuxHome: canonicalPolicyPath(defaultBotmuxHome),
11006
+ })).digest('hex')
11007
+ : undefined;
10899
11008
  let mcpRuntimeManifest = readSessionMcpRuntimeManifest(cfg.sessionId, config.session.dataDir);
10900
11009
  const hasMcpRuntimeEntries = !!cliAdapter.mcpGateway && !!mcpRuntimeManifest?.entries.length;
10901
11010
  const reuseRecordedHerdrTarget = !sandboxRequested && !hasMcpRuntimeEntries;
@@ -11052,8 +11161,7 @@ async function spawnCli(cfg, opts = {}) {
11052
11161
  if (paneLive) {
11053
11162
  const markerPath = join(isolationRuntimeDataDir, 'read-isolation', `${cfg.sessionId}.boot`);
11054
11163
  const marker = readManagedOriginAuthorityFile(markerPath);
11055
- const darwinPolicyExpected = process.platform === 'darwin'
11056
- && (willReadIsolate || willWriteSandbox);
11164
+ const originChannelPolicyExpected = !!managedOriginChannelPolicyDigest;
11057
11165
  // A stamped pane must match even when the new policy is OFF. Otherwise a
11058
11166
  // disable followed by restart could reattach the still-confined process
11059
11167
  // without rebuilding its authority/profile. An unsafe planted marker
@@ -11062,16 +11170,16 @@ async function spawnCli(cfg, opts = {}) {
11062
11170
  ? isolatedPaneReattachSafe(marker, {
11063
11171
  requiredCapabilities: appliedIsolationCapabilities,
11064
11172
  exactCapabilities: true,
11065
- ...(darwinPolicyExpected ? {
11173
+ ...(originChannelPolicyExpected ? {
11066
11174
  readIsolation: willReadIsolate,
11067
11175
  writeSandbox: willWriteSandbox,
11068
11176
  requireOriginChannel: true,
11069
- policyDigest: darwinIsolationPolicyDigest,
11177
+ policyDigest: managedOriginChannelPolicyDigest,
11070
11178
  } : {}),
11071
11179
  })
11072
11180
  : marker === null && !hostEntryExistsNoFollow(markerPath);
11073
11181
  if (policyMatches) {
11074
- if (darwinPolicyExpected) {
11182
+ if (originChannelPolicyExpected) {
11075
11183
  persistentPaneOriginChannelId = isolatedPaneOriginChannel(marker);
11076
11184
  }
11077
11185
  // Pane was spawned under the current isolation policy → still confined
@@ -11132,7 +11240,7 @@ async function spawnCli(cfg, opts = {}) {
11132
11240
  }
11133
11241
  }
11134
11242
  }
11135
- readIsolationOriginChannelId = willReadIsolate
11243
+ readIsolationOriginChannelId = managedOriginChannelRequired
11136
11244
  ? (persistentPaneOriginChannelId ?? randomBytes(32).toString('hex'))
11137
11245
  : null;
11138
11246
  if (readIsolationOriginChannelId) {
@@ -11479,7 +11587,7 @@ async function spawnCli(cfg, opts = {}) {
11479
11587
  try {
11480
11588
  const credPath = sendCredFilePath(process.env.SESSION_DATA_DIR, cfg.larkAppId);
11481
11589
  mkdirSync(dirname(credPath), { recursive: true });
11482
- writeFileSync(credPath, JSON.stringify({ larkAppId: cfg.larkAppId, larkAppSecret: cfg.larkAppSecret, brand: cfg.brand, apiOnly: cfg.apiOnly }), { mode: 0o600 });
11590
+ writeFileSync(credPath, JSON.stringify({ larkAppId: cfg.larkAppId, larkAppSecret: cfg.larkAppSecret, brand: cfg.brand, apiOnly: cfg.apiOnly, feedback: cfg.feedback }), { mode: 0o600 });
11483
11591
  }
11484
11592
  catch (e) {
11485
11593
  log(`[sandbox] WARN could not write send-cred file: ${e.message}`);
@@ -11772,8 +11880,19 @@ async function spawnCli(cfg, opts = {}) {
11772
11880
  throw new Error('[read-isolation] origin channel is unavailable');
11773
11881
  }
11774
11882
  childEnv.BOTMUX_READ_ISOLATED = '1';
11883
+ }
11884
+ if (readIsolationOriginChannelId) {
11775
11885
  childEnv.BOTMUX_ORIGIN_CHANNEL_ID = readIsolationOriginChannelId;
11776
11886
  }
11887
+ // Credential-only children have no writable relay outbox. Publish the same
11888
+ // rotating managed-origin claim through a host-owned per-channel directory
11889
+ // before the Seatbelt/bwrap wrapper is compiled, then expose only that
11890
+ // directory read-only below.
11891
+ if (readIsolationOriginChannelId && !sandboxRequested) {
11892
+ readIsolationOriginCapabilityFile = managedOriginCapabilityPath(isolationRuntimeDataDir, cfg.sessionId, readIsolationOriginChannelId);
11893
+ ensureManagedOriginCapabilityLeafSafe(readIsolationOriginCapabilityFile);
11894
+ publishSandboxRelayCapability({ failClosed: true });
11895
+ }
11777
11896
  // Per-bot env (bots.json `env`): extra vars for THIS bot's CLI only — e.g.
11778
11897
  // ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN to run a bot on GLM/a 3rd-party
11779
11898
  // provider, an HTTPS_PROXY, or a CLI feature flag. Passed as injectEnv (NOT
@@ -11948,6 +12067,11 @@ async function spawnCli(cfg, opts = {}) {
11948
12067
  writeFileSync(tsFile, '');
11949
12068
  }
11950
12069
  catch { /* */ }
12070
+ // UserPromptSubmit sidecar 目录(#794):daemon 逐 turn 写入,沙盒内 hook 只读。
12071
+ try {
12072
+ mkdirSync(join(dataDir, 'prompt-ctx', cfg.sessionId), { recursive: true, mode: 0o700 });
12073
+ }
12074
+ catch { /* */ }
11951
12075
  try {
11952
12076
  mkdirSync(join(dataDir, 'attachments', cfg.larkAppId), { recursive: true });
11953
12077
  }
@@ -12002,7 +12126,7 @@ async function spawnCli(cfg, opts = {}) {
12002
12126
  if (readIsolationOriginCapabilityFile) {
12003
12127
  ensureManagedOriginCapabilityLeafSafe(readIsolationOriginCapabilityFile);
12004
12128
  publishSandboxRelayCapability({ failClosed: true });
12005
- mandatoryReadOnlyPaths.push(readIsolationOriginCapabilityFile);
12129
+ mandatoryReadOnlyPaths.push(managedOriginCapabilityDirectory(dataDir, cfg.sessionId, readIsolationOriginChannelId));
12006
12130
  mandatoryReadOnlyPaths.push(managedOriginAttestationDirectory(dataDir, cfg.sessionId, readIsolationOriginChannelId));
12007
12131
  mandatoryReadOnlyPaths.push(managedOriginRootLocatorPath(userInfo().homedir, cfg.sessionId));
12008
12132
  }
@@ -12288,12 +12412,12 @@ async function spawnCli(cfg, opts = {}) {
12288
12412
  try {
12289
12413
  const markerDir = join(isolationRuntimeDataDir, 'read-isolation');
12290
12414
  mkdirSync(markerDir, { recursive: true });
12291
- replaceManagedOriginCapabilityFile(join(markerDir, `${cfg.sessionId}.boot`), isolationPaneMarkerContent(cfg.daemonBootId ?? '', appliedIsolationCapabilities, willReadIsolate || willWriteSandbox
12415
+ replaceManagedOriginCapabilityFile(join(markerDir, `${cfg.sessionId}.boot`), isolationPaneMarkerContent(cfg.daemonBootId ?? '', appliedIsolationCapabilities, managedOriginChannelPolicyDigest
12292
12416
  ? {
12293
12417
  originChannelId: persistentPaneOriginChannelId,
12294
12418
  readIsolation: willReadIsolate,
12295
12419
  writeSandbox: willWriteSandbox,
12296
- policyDigest: darwinIsolationPolicyDigest,
12420
+ policyDigest: managedOriginChannelPolicyDigest,
12297
12421
  }
12298
12422
  : undefined));
12299
12423
  }
@@ -12337,11 +12461,13 @@ async function spawnCli(cfg, opts = {}) {
12337
12461
  // the input box). cjadk's own botmux integration (`cjadk feishu`, see its
12338
12462
  // botmux-wrapper-writer) sets CJADK_INTERACTIVE=0 to disable all of that.
12339
12463
  // We mirror it here so a `cjadk <agent>` wrapperCli is driven the way
12340
- // cjadk intends — no selector, clean soft-newline input. Keyed on the
12341
- // wrapper's leading token so only cjadk launches are affected.
12342
- if (parseWrapperCli(cfg.wrapperCli)[0] === 'cjadk') {
12343
- childEnv.CJADK_INTERACTIVE = '0';
12344
- log('cjadk launcher: set CJADK_INTERACTIVE=0 (non-interactive, mirrors cjadk feishu wrapper)');
12464
+ // cjadk intends — no selector, clean soft-newline input. The env set
12465
+ // comes from wrapperLaunchEnv the shared single source of truth also
12466
+ // used by one-shot children (session-group AI titling).
12467
+ const wrapperEnv = wrapperLaunchEnv(cfg.wrapperCli);
12468
+ if (wrapperEnv) {
12469
+ Object.assign(childEnv, wrapperEnv);
12470
+ log(`wrapper launcher env applied: ${Object.keys(wrapperEnv).join(', ')} (mirrors the wrapper's own non-interactive integration)`);
12345
12471
  }
12346
12472
  }
12347
12473
  }
@@ -12379,8 +12505,9 @@ async function spawnCli(cfg, opts = {}) {
12379
12505
  });
12380
12506
  const profileDir = join(isolationRuntimeDataDir, 'read-isolation');
12381
12507
  mkdirSync(profileDir, { recursive: true });
12508
+ const originDirectory = managedOriginCapabilityDirectory(isolationRuntimeDataDir, cfg.sessionId, readIsolationOriginChannelId);
12382
12509
  const profilePath = join(profileDir, `${cfg.sessionId}.sb`);
12383
- replaceManagedOriginCapabilityFile(profilePath, buildSeatbeltProfile(rules.denyPaths.map(canonical), [], [], [], rules.denyRegexes, undefined, {
12510
+ replaceManagedOriginCapabilityFile(profilePath, buildSeatbeltProfile([...rules.denyPaths.map(canonical), canonical(profileDir)], [canonical(originDirectory)], [], [canonical(profileDir)], rules.denyRegexes, undefined, {
12384
12511
  denyWritePaths: [...new Set([
12385
12512
  ...rules.denyWritePaths.map(canonical),
12386
12513
  canonical(profileDir),
@@ -12482,7 +12609,10 @@ async function spawnCli(cfg, opts = {}) {
12482
12609
  const credentialSandbox = prepareCredentialOnlySandbox({
12483
12610
  hideDirectories: [...hideDirectories],
12484
12611
  hideFiles: [...hideFiles],
12485
- readonlyPaths: [realpathSync(panePolicyDir)],
12612
+ privateReadonlyDirectories: [{
12613
+ parent: realpathSync(panePolicyDir),
12614
+ directory: realpathSync(managedOriginCapabilityDirectory(isolationRuntimeDataDir, cfg.sessionId, readIsolationOriginChannelId)),
12615
+ }],
12486
12616
  workingDir: spawnCwd,
12487
12617
  cliBin: credentialCliBin,
12488
12618
  cliArgs: spawnArgs,
@@ -13590,6 +13720,7 @@ function startWebServer(host, preferredPort) {
13590
13720
  // normal buffer until resize causes a redraw. Preserve that mode so
13591
13721
  // scroll gestures continue to target the CLI's own transcript.
13592
13722
  const forceRemoteScroll = effectiveBackendType === 'herdr' && cliAdapter?.altScreen === true;
13723
+ const allowReadOnlyRemoteScroll = canHandleReadOnlyRemoteScroll();
13593
13724
  // The wheel burst cap throttles backends where a forwarded wheel is
13594
13725
  // EXPENSIVE or has no local terminal to drive:
13595
13726
  // • Herdr — each forwarded wheel → pane send-text + snapshot re-render.
@@ -13607,7 +13738,7 @@ function startWebServer(host, preferredPort) {
13607
13738
  || effectiveBackendType === 'tmux'
13608
13739
  || effectiveBackendType === 'zellij';
13609
13740
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
13610
- res.end(getTerminalHtml(hasWrite, platformReadonly, loginUrl, forceRemoteScroll, localTerminalBackend));
13741
+ res.end(getTerminalHtml(hasWrite, platformReadonly, loginUrl, forceRemoteScroll, localTerminalBackend, allowReadOnlyRemoteScroll));
13611
13742
  });
13612
13743
  wss = new WebSocketServer({
13613
13744
  server: httpServer,
@@ -13639,6 +13770,7 @@ function startWebServer(host, preferredPort) {
13639
13770
  return;
13640
13771
  }
13641
13772
  const { hasWrite } = resolveTerminalAccessForReq(req, url);
13773
+ const allowReadOnlyRemoteScroll = canHandleReadOnlyRemoteScroll();
13642
13774
  if (hasWrite)
13643
13775
  authedClients.add(ws);
13644
13776
  log(`WS client connected (total: ${wsClients.size}, write: ${hasWrite})`);
@@ -13890,6 +14022,18 @@ function startWebServer(host, preferredPort) {
13890
14022
  }
13891
14023
  backend?.write(msg.data);
13892
14024
  }
14025
+ else if (msg.type === 'scroll' && typeof msg.data === 'string') {
14026
+ if (!allowReadOnlyRemoteScroll || authedClients.has(ws))
14027
+ return;
14028
+ const parsed = parseReadOnlyRemoteScrollPayload(msg.data);
14029
+ if (!parsed)
14030
+ return;
14031
+ if (!readOnlyRemoteScrollLimiter.tryConsume(parsed.eventCount))
14032
+ return;
14033
+ if (usesHerdrSnapshotWebHistory())
14034
+ herdrWebScrollDirection = parsed.direction;
14035
+ backend?.write(msg.data);
14036
+ }
13893
14037
  }
13894
14038
  catch { /* ignore non-JSON or bad messages */ }
13895
14039
  });
@@ -13912,7 +14056,7 @@ function startWebServer(host, preferredPort) {
13912
14056
  .then(resolve, reject);
13913
14057
  });
13914
14058
  }
13915
- function getTerminalHtml(hasWrite, platformReadonly = false, loginUrl = '', forceRemoteScroll = false, localTerminalBackend = false) {
14059
+ function getTerminalHtml(hasWrite, platformReadonly = false, loginUrl = '', forceRemoteScroll = false, localTerminalBackend = false, allowReadOnlyRemoteScroll = false) {
13916
14060
  const label = sessionId.substring(0, 8);
13917
14061
  return `<!DOCTYPE html>
13918
14062
  <html>
@@ -14050,6 +14194,7 @@ var hasToken=${hasWrite};
14050
14194
  var platformReadonly=${platformReadonly};
14051
14195
  var remoteScroll=${forceRemoteScroll};
14052
14196
  var localTerminalBackend=${localTerminalBackend};
14197
+ var readOnlyRemoteScroll=${allowReadOnlyRemoteScroll};
14053
14198
  if(!hasToken){
14054
14199
  if(platformReadonly){var _lb=document.getElementById('login-banner');_lb.classList.add('show');}
14055
14200
  else{var _rb=document.getElementById('readonly-banner');_rb.classList.add('show');_rb.addEventListener('click',function(){_rb.classList.remove('show')});}
@@ -14346,8 +14491,9 @@ window.addEventListener('resize',onViewportResize);
14346
14491
  // Alt-screen + mouse-mode CLIs (e.g. Claude Code) keep NO scrollback in xterm OR
14347
14492
  // tmux — their whole transcript is redrawn by the app inside the fixed alt-screen
14348
14493
  // grid, so term.scrollLines() reveals nothing. In the alternate buffer we forward
14349
- // scrolling as SGR mouse-wheel events so the CLI scrolls its own transcript and
14350
- // repaints. This is write-capability only; view links stay locally scrollable.
14494
+ // scrolling as SGR mouse-wheel events so the CLI scrolls its own transcript.
14495
+ // Read-only viewers get this remote path only for adapters that explicitly opt
14496
+ // in; the server then accepts only validated wheel events, never general input.
14351
14497
  // Normal-buffer CLIs keep xterm's native scrollback scroll. Capture-phase +
14352
14498
  // stopPropagation pre-empts xterm's own handler. Skipped for pure tmux/zellij
14353
14499
  // ATTACH (gate), where the attach client owns scrolling via copy-mode.
@@ -14407,7 +14553,7 @@ function _cellAt(clientX,clientY){
14407
14553
  return col+';'+row;
14408
14554
  }
14409
14555
  function _fwdScroll(px,coord){
14410
- if(!hasToken||!ws_||ws_.readyState!==1||!px)return;
14556
+ if((!hasToken&&!readOnlyRemoteScroll)||!ws_||ws_.readyState!==1||!px)return;
14411
14557
  coord=coord||(((term.cols>>1)+1)+';'+((term.rows>>1)+1)); // never (1,1)
14412
14558
  var dir=px<0?-1:1;
14413
14559
  if(_scrollBurstDir&&dir!==_scrollBurstDir){_scrollAccum=0;_scrollBurstTicks=0;}
@@ -14421,7 +14567,7 @@ function _fwdScroll(px,coord){
14421
14567
  _scrollAccum+=up?_SCROLL_STEP:-_SCROLL_STEP;n++;_scrollBurstTicks++;
14422
14568
  }
14423
14569
  if(_scrollBurstTicks>=_SCROLL_BURST_MAX)_scrollAccum=0;
14424
- if(data)ws_.send(JSON.stringify({type:'input',data:data}));
14570
+ if(data)ws_.send(JSON.stringify({type:hasToken?'input':'scroll',data:data}));
14425
14571
  }
14426
14572
  if(!${isTmuxMode && !isPipeMode}){
14427
14573
  document.getElementById('terminal').addEventListener('wheel',function(e){
@@ -14434,7 +14580,9 @@ if(!${isTmuxMode && !isPipeMode}){
14434
14580
  return;
14435
14581
  }
14436
14582
  if(!hasToken){
14437
- e.preventDefault();e.stopPropagation();term.scrollLines(e.deltaY>0?3:-3);return;
14583
+ e.preventDefault();e.stopPropagation();
14584
+ if(readOnlyRemoteScroll)_fwdScroll(px,_cellAt(e.clientX,e.clientY));
14585
+ else term.scrollLines(e.deltaY>0?3:-3);return;
14438
14586
  }
14439
14587
  e.preventDefault();e.stopPropagation();
14440
14588
  _fwdScroll(px,_cellAt(e.clientX,e.clientY)); // report the cell under the pointer
@@ -14755,8 +14903,7 @@ if(!${isTmuxMode && !isPipeMode}){
14755
14903
  if(e.touches.length===1)_tLastY=e.touches[0].clientY;
14756
14904
  },{capture:true,passive:true});
14757
14905
  _tTerm.addEventListener('touchmove',function(e){
14758
- // View links never forward input; let xterm/browser handle local scrolling.
14759
- if(!hasToken||_tLastY===null||e.touches.length!==1)return;
14906
+ if((!hasToken&&!readOnlyRemoteScroll)||_tLastY===null||e.touches.length!==1)return;
14760
14907
  e.preventDefault();e.stopPropagation();
14761
14908
  var y=e.touches[0].clientY;
14762
14909
  var px=_tLastY-y;
@@ -15934,7 +16081,17 @@ process.on('message', async (raw) => {
15934
16081
  break;
15935
16082
  }
15936
16083
  closeRequested = true;
15937
- send({ type: 'session_close_ready', sessionId });
16084
+ // This ACK is what resolves the daemon's close fence (worker-pool
16085
+ // resolveCloseFence) so `/close` can return. It MUST be flushed: a plain
16086
+ // send() only queues on process.send's async IPC buffer, and the fully
16087
+ // synchronous teardown + process.exit(0) below never yield the event loop
16088
+ // to drain it. Worse, process.exit(0) can wedge in node-pty's native
16089
+ // reader-thread join whenever a web-terminal client PTY was attached — so
16090
+ // the queued ACK would be lost entirely and the fence would only resolve
16091
+ // on the daemon's 7s SIGKILL backstop (the ~7s dashboard/card close stall).
16092
+ // closeRequested already fences bridge-marker reads, so ACKing before
16093
+ // teardown stays safe; sendAndFlush yields so the ACK truly departs.
16094
+ await sendAndFlush({ type: 'session_close_ready', sessionId });
15938
16095
  stopScreenshotLoop();
15939
16096
  stopBridgeWatcher();
15940
16097
  stopCodexBridge();
@@ -16115,7 +16272,11 @@ process.on('message', async (raw) => {
16115
16272
  lastAbortedCloseRequestId = null;
16116
16273
  backend?.commitDestroySession?.();
16117
16274
  closeRequested = true;
16118
- send({ type: 'session_close_ready', sessionId });
16275
+ // Flush the fence-resolving ACK before the synchronous teardown +
16276
+ // process.exit(0); see the local-close case for the node-pty exit-wedge
16277
+ // rationale (a queued send() would be dropped and strand `/close` behind
16278
+ // the daemon's 7s SIGKILL backstop).
16279
+ await sendAndFlush({ type: 'session_close_ready', sessionId });
16119
16280
  stopScreenshotLoop();
16120
16281
  stopBridgeWatcher();
16121
16282
  stopCodexBridge();