botmux 3.9.1 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/.runtime-build-id +1 -1
  4. package/dist/adapters/cli/codex.d.ts.map +1 -1
  5. package/dist/adapters/cli/codex.js +6 -0
  6. package/dist/adapters/cli/codex.js.map +1 -1
  7. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  8. package/dist/adapters/cli/opencode.js +7 -1
  9. package/dist/adapters/cli/opencode.js.map +1 -1
  10. package/dist/adapters/cli/reasonix.d.ts +35 -0
  11. package/dist/adapters/cli/reasonix.d.ts.map +1 -0
  12. package/dist/adapters/cli/reasonix.js +236 -0
  13. package/dist/adapters/cli/reasonix.js.map +1 -0
  14. package/dist/adapters/cli/registry.d.ts +2 -1
  15. package/dist/adapters/cli/registry.d.ts.map +1 -1
  16. package/dist/adapters/cli/registry.js +4 -1
  17. package/dist/adapters/cli/registry.js.map +1 -1
  18. package/dist/adapters/cli/traex.d.ts.map +1 -1
  19. package/dist/adapters/cli/traex.js +87 -87
  20. package/dist/adapters/cli/traex.js.map +1 -1
  21. package/dist/adapters/cli/types.d.ts +5 -1
  22. package/dist/adapters/cli/types.d.ts.map +1 -1
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js +253 -69
  25. package/dist/cli.js.map +1 -1
  26. package/dist/core/command-handler.d.ts +18 -4
  27. package/dist/core/command-handler.d.ts.map +1 -1
  28. package/dist/core/command-handler.js +274 -27
  29. package/dist/core/command-handler.js.map +1 -1
  30. package/dist/core/dashboard-ipc-server.d.ts +1 -0
  31. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  32. package/dist/core/dashboard-ipc-server.js +27 -3
  33. package/dist/core/dashboard-ipc-server.js.map +1 -1
  34. package/dist/core/dispatch.d.ts +54 -24
  35. package/dist/core/dispatch.d.ts.map +1 -1
  36. package/dist/core/dispatch.js +81 -27
  37. package/dist/core/dispatch.js.map +1 -1
  38. package/dist/core/input-turn-dedupe.d.ts +20 -0
  39. package/dist/core/input-turn-dedupe.d.ts.map +1 -0
  40. package/dist/core/input-turn-dedupe.js +57 -0
  41. package/dist/core/input-turn-dedupe.js.map +1 -0
  42. package/dist/core/local-terminal-opener.d.ts.map +1 -1
  43. package/dist/core/local-terminal-opener.js +10 -1
  44. package/dist/core/local-terminal-opener.js.map +1 -1
  45. package/dist/core/passthrough-commands.d.ts.map +1 -1
  46. package/dist/core/passthrough-commands.js +1 -1
  47. package/dist/core/passthrough-commands.js.map +1 -1
  48. package/dist/core/plugins/pm2.d.ts.map +1 -1
  49. package/dist/core/plugins/pm2.js +7 -1
  50. package/dist/core/plugins/pm2.js.map +1 -1
  51. package/dist/core/resource-monitor/attribution.d.ts.map +1 -1
  52. package/dist/core/resource-monitor/attribution.js +17 -1
  53. package/dist/core/resource-monitor/attribution.js.map +1 -1
  54. package/dist/core/resource-monitor/darwin.d.ts +145 -0
  55. package/dist/core/resource-monitor/darwin.d.ts.map +1 -0
  56. package/dist/core/resource-monitor/darwin.js +360 -0
  57. package/dist/core/resource-monitor/darwin.js.map +1 -0
  58. package/dist/core/resource-monitor/procfs.d.ts.map +1 -1
  59. package/dist/core/resource-monitor/procfs.js +6 -0
  60. package/dist/core/resource-monitor/procfs.js.map +1 -1
  61. package/dist/core/resource-monitor/types.d.ts +1 -1
  62. package/dist/core/resource-monitor/types.d.ts.map +1 -1
  63. package/dist/core/scheduler.d.ts.map +1 -1
  64. package/dist/core/scheduler.js +5 -2
  65. package/dist/core/scheduler.js.map +1 -1
  66. package/dist/core/session-discovery.d.ts.map +1 -1
  67. package/dist/core/session-discovery.js +3 -0
  68. package/dist/core/session-discovery.js.map +1 -1
  69. package/dist/core/session-manager.d.ts +3 -1
  70. package/dist/core/session-manager.d.ts.map +1 -1
  71. package/dist/core/session-manager.js +46 -0
  72. package/dist/core/session-manager.js.map +1 -1
  73. package/dist/core/session-marker.d.ts +1 -8
  74. package/dist/core/session-marker.d.ts.map +1 -1
  75. package/dist/core/session-marker.js +2 -50
  76. package/dist/core/session-marker.js.map +1 -1
  77. package/dist/core/types.d.ts +3 -1
  78. package/dist/core/types.d.ts.map +1 -1
  79. package/dist/core/types.js.map +1 -1
  80. package/dist/core/worker-pool.d.ts +17 -0
  81. package/dist/core/worker-pool.d.ts.map +1 -1
  82. package/dist/core/worker-pool.js +292 -9
  83. package/dist/core/worker-pool.js.map +1 -1
  84. package/dist/daemon.d.ts +11 -1
  85. package/dist/daemon.d.ts.map +1 -1
  86. package/dist/daemon.js +59 -15
  87. package/dist/daemon.js.map +1 -1
  88. package/dist/dashboard/daemon-internal-api.d.ts.map +1 -1
  89. package/dist/dashboard/daemon-internal-api.js +11 -2
  90. package/dist/dashboard/daemon-internal-api.js.map +1 -1
  91. package/dist/dashboard/groups-action-helpers.d.ts +2 -0
  92. package/dist/dashboard/groups-action-helpers.d.ts.map +1 -1
  93. package/dist/dashboard/groups-action-helpers.js +9 -0
  94. package/dist/dashboard/groups-action-helpers.js.map +1 -1
  95. package/dist/dashboard/groups-matrix-snapshot.d.ts +56 -0
  96. package/dist/dashboard/groups-matrix-snapshot.d.ts.map +1 -0
  97. package/dist/dashboard/groups-matrix-snapshot.js +127 -0
  98. package/dist/dashboard/groups-matrix-snapshot.js.map +1 -0
  99. package/dist/dashboard/resource-monitor-service.d.ts.map +1 -1
  100. package/dist/dashboard/resource-monitor-service.js +18 -2
  101. package/dist/dashboard/resource-monitor-service.js.map +1 -1
  102. package/dist/dashboard/web/app.d.ts.map +1 -1
  103. package/dist/dashboard/web/app.js +45 -4
  104. package/dist/dashboard/web/app.js.map +1 -1
  105. package/dist/dashboard/web/groups-api.js +1 -1
  106. package/dist/dashboard/web/groups-api.js.map +1 -1
  107. package/dist/dashboard/web/i18n.js +10 -10
  108. package/dist/dashboard/web/i18n.js.map +1 -1
  109. package/dist/dashboard/web/roles-page.d.ts.map +1 -1
  110. package/dist/dashboard/web/roles-page.js +26 -11
  111. package/dist/dashboard/web/roles-page.js.map +1 -1
  112. package/dist/dashboard-web/app.js +1 -1
  113. package/dist/dashboard-web/chunks/{bot-defaults-page-BHTQEWCH.js → bot-defaults-page-LTVOUDIS.js} +1 -1
  114. package/dist/dashboard-web/chunks/{chunk-KLZCQAHF.js → chunk-3UE7S77S.js} +1 -1
  115. package/dist/dashboard-web/chunks/{chunk-W77TPKZH.js → chunk-DCS35UMD.js} +1 -1
  116. package/dist/dashboard-web/chunks/{chunk-E3HZZXK5.js → chunk-MFQPCVHY.js} +4 -4
  117. package/dist/dashboard-web/chunks/{chunk-EZH56JCI.js → chunk-ZU3UUKAR.js} +1 -1
  118. package/dist/dashboard-web/chunks/{connectors-page-BP255CAX.js → connectors-page-5KWDIMKC.js} +1 -1
  119. package/dist/dashboard-web/chunks/{groups-page-CDHVXBUT.js → groups-page-FHOKYXMW.js} +1 -1
  120. package/dist/dashboard-web/chunks/{insights-page-57BFE6GT.js → insights-page-T2ZX2RWL.js} +1 -1
  121. package/dist/dashboard-web/chunks/{monitor-room-UTOYGQVF.js → monitor-room-YNVBAGR6.js} +1 -1
  122. package/dist/dashboard-web/chunks/{monitoring-page-WTHYAIUM.js → monitoring-page-LHM55YWN.js} +1 -1
  123. package/dist/dashboard-web/chunks/{office-page-JSMIB353.js → office-page-ATXVP7PW.js} +1 -1
  124. package/dist/dashboard-web/chunks/{overview-page-3VDBOH7L.js → overview-page-QYI3KBDD.js} +1 -1
  125. package/dist/dashboard-web/chunks/roles-page-56VWM6CD.js +1 -0
  126. package/dist/dashboard-web/chunks/{schedules-page-HHN736H6.js → schedules-page-S5K6U4EO.js} +1 -1
  127. package/dist/dashboard-web/chunks/{sessions-page-EIWOZD7A.js → sessions-page-WBP4N7D2.js} +1 -1
  128. package/dist/dashboard-web/chunks/{settings-page-2IUT5LS4.js → settings-page-QUZDQARR.js} +1 -1
  129. package/dist/dashboard-web/chunks/{skills-page-JKFKMUEM.js → skills-page-IFY7AEND.js} +1 -1
  130. package/dist/dashboard-web/chunks/{team-federation-page-Q2PXC3UY.js → team-federation-page-C7FJQPFZ.js} +1 -1
  131. package/dist/dashboard-web/chunks/{v3-page-EBQCD4AO.js → v3-page-2LMF3WWR.js} +1 -1
  132. package/dist/dashboard-web/chunks/{whiteboards-page-QZRMVNZN.js → whiteboards-page-3XC6QRMY.js} +1 -1
  133. package/dist/dashboard-web/style.css +2 -4
  134. package/dist/dashboard.js +65 -9
  135. package/dist/dashboard.js.map +1 -1
  136. package/dist/i18n/en.d.ts.map +1 -1
  137. package/dist/i18n/en.js +34 -7
  138. package/dist/i18n/en.js.map +1 -1
  139. package/dist/i18n/zh.d.ts.map +1 -1
  140. package/dist/i18n/zh.js +32 -7
  141. package/dist/i18n/zh.js.map +1 -1
  142. package/dist/im/lark/card-builder.d.ts +7 -0
  143. package/dist/im/lark/card-builder.d.ts.map +1 -1
  144. package/dist/im/lark/card-builder.js +56 -0
  145. package/dist/im/lark/card-builder.js.map +1 -1
  146. package/dist/im/lark/card-handler.d.ts.map +1 -1
  147. package/dist/im/lark/card-handler.js +51 -19
  148. package/dist/im/lark/card-handler.js.map +1 -1
  149. package/dist/im/lark/client.d.ts +10 -0
  150. package/dist/im/lark/client.d.ts.map +1 -1
  151. package/dist/im/lark/client.js +79 -0
  152. package/dist/im/lark/client.js.map +1 -1
  153. package/dist/im/lark/event-dispatcher.d.ts +14 -1
  154. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  155. package/dist/im/lark/event-dispatcher.js +171 -15
  156. package/dist/im/lark/event-dispatcher.js.map +1 -1
  157. package/dist/im/lark/issue-card.d.ts +223 -0
  158. package/dist/im/lark/issue-card.d.ts.map +1 -0
  159. package/dist/im/lark/issue-card.js +542 -0
  160. package/dist/im/lark/issue-card.js.map +1 -0
  161. package/dist/im/lark/issue-command-deps.d.ts +41 -0
  162. package/dist/im/lark/issue-command-deps.d.ts.map +1 -0
  163. package/dist/im/lark/issue-command-deps.js +195 -0
  164. package/dist/im/lark/issue-command-deps.js.map +1 -0
  165. package/dist/im/lark/issue-command.d.ts +137 -0
  166. package/dist/im/lark/issue-command.d.ts.map +1 -0
  167. package/dist/im/lark/issue-command.js +335 -0
  168. package/dist/im/lark/issue-command.js.map +1 -0
  169. package/dist/im/lark/lark-hosts.d.ts +5 -0
  170. package/dist/im/lark/lark-hosts.d.ts.map +1 -1
  171. package/dist/im/lark/lark-hosts.js +10 -0
  172. package/dist/im/lark/lark-hosts.js.map +1 -1
  173. package/dist/im/lark/message-parser.d.ts.map +1 -1
  174. package/dist/im/lark/message-parser.js +24 -7
  175. package/dist/im/lark/message-parser.js.map +1 -1
  176. package/dist/platform/issue-client.d.ts +201 -0
  177. package/dist/platform/issue-client.d.ts.map +1 -0
  178. package/dist/platform/issue-client.js +142 -0
  179. package/dist/platform/issue-client.js.map +1 -0
  180. package/dist/platform/platform-http.d.ts +4 -0
  181. package/dist/platform/platform-http.d.ts.map +1 -1
  182. package/dist/platform/platform-http.js +38 -2
  183. package/dist/platform/platform-http.js.map +1 -1
  184. package/dist/pm2-graceful-exit.d.ts +28 -0
  185. package/dist/pm2-graceful-exit.d.ts.map +1 -0
  186. package/dist/pm2-graceful-exit.js +39 -0
  187. package/dist/pm2-graceful-exit.js.map +1 -0
  188. package/dist/services/bridge-fallback-gate.d.ts +9 -2
  189. package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
  190. package/dist/services/bridge-fallback-gate.js +31 -19
  191. package/dist/services/bridge-fallback-gate.js.map +1 -1
  192. package/dist/services/issue-board-store.d.ts +214 -0
  193. package/dist/services/issue-board-store.d.ts.map +1 -0
  194. package/dist/services/issue-board-store.js +472 -0
  195. package/dist/services/issue-board-store.js.map +1 -0
  196. package/dist/services/issue-claim-flow.d.ts +160 -0
  197. package/dist/services/issue-claim-flow.d.ts.map +1 -0
  198. package/dist/services/issue-claim-flow.js +222 -0
  199. package/dist/services/issue-claim-flow.js.map +1 -0
  200. package/dist/services/issue-outbox-pump.d.ts +25 -0
  201. package/dist/services/issue-outbox-pump.d.ts.map +1 -0
  202. package/dist/services/issue-outbox-pump.js +102 -0
  203. package/dist/services/issue-outbox-pump.js.map +1 -0
  204. package/dist/services/issue-release.d.ts +78 -0
  205. package/dist/services/issue-release.d.ts.map +1 -0
  206. package/dist/services/issue-release.js +89 -0
  207. package/dist/services/issue-release.js.map +1 -0
  208. package/dist/services/issue-report.d.ts +72 -0
  209. package/dist/services/issue-report.d.ts.map +1 -0
  210. package/dist/services/issue-report.js +84 -0
  211. package/dist/services/issue-report.js.map +1 -0
  212. package/dist/services/issue-status-view.d.ts +52 -0
  213. package/dist/services/issue-status-view.d.ts.map +1 -0
  214. package/dist/services/issue-status-view.js +42 -0
  215. package/dist/services/issue-status-view.js.map +1 -0
  216. package/dist/services/issue-status-writer.d.ts +98 -0
  217. package/dist/services/issue-status-writer.d.ts.map +1 -0
  218. package/dist/services/issue-status-writer.js +123 -0
  219. package/dist/services/issue-status-writer.js.map +1 -0
  220. package/dist/services/message-listener-store.d.ts +18 -0
  221. package/dist/services/message-listener-store.d.ts.map +1 -1
  222. package/dist/services/message-listener-store.js +35 -10
  223. package/dist/services/message-listener-store.js.map +1 -1
  224. package/dist/services/message-listener.d.ts +17 -0
  225. package/dist/services/message-listener.d.ts.map +1 -1
  226. package/dist/services/message-listener.js +26 -0
  227. package/dist/services/message-listener.js.map +1 -1
  228. package/dist/services/traex-paths.d.ts +14 -2
  229. package/dist/services/traex-paths.d.ts.map +1 -1
  230. package/dist/services/traex-paths.js +16 -2
  231. package/dist/services/traex-paths.js.map +1 -1
  232. package/dist/services/traex-transcript.d.ts +33 -0
  233. package/dist/services/traex-transcript.d.ts.map +1 -1
  234. package/dist/services/traex-transcript.js +135 -28
  235. package/dist/services/traex-transcript.js.map +1 -1
  236. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  237. package/dist/setup/bot-config-editor.js +2 -0
  238. package/dist/setup/bot-config-editor.js.map +1 -1
  239. package/dist/setup/lark-scopes.json +1 -2
  240. package/dist/setup/verify-permissions.d.ts.map +1 -1
  241. package/dist/setup/verify-permissions.js +8 -0
  242. package/dist/setup/verify-permissions.js.map +1 -1
  243. package/dist/types.d.ts +34 -0
  244. package/dist/types.d.ts.map +1 -1
  245. package/dist/utils/child-env.d.ts +1 -1
  246. package/dist/utils/child-env.d.ts.map +1 -1
  247. package/dist/utils/child-env.js +13 -0
  248. package/dist/utils/child-env.js.map +1 -1
  249. package/dist/utils/file-lock.d.ts.map +1 -1
  250. package/dist/utils/file-lock.js +1 -1
  251. package/dist/utils/file-lock.js.map +1 -1
  252. package/dist/utils/global-install.d.ts.map +1 -1
  253. package/dist/utils/global-install.js +56 -10
  254. package/dist/utils/global-install.js.map +1 -1
  255. package/dist/utils/idle-detector.d.ts +4 -0
  256. package/dist/utils/idle-detector.d.ts.map +1 -1
  257. package/dist/utils/idle-detector.js +25 -0
  258. package/dist/utils/idle-detector.js.map +1 -1
  259. package/dist/utils/process-identity.d.ts +7 -0
  260. package/dist/utils/process-identity.d.ts.map +1 -0
  261. package/dist/utils/process-identity.js +62 -0
  262. package/dist/utils/process-identity.js.map +1 -0
  263. package/dist/worker.js +264 -24
  264. package/dist/worker.js.map +1 -1
  265. package/dist/workflows/events/payloads.d.ts +10 -10
  266. package/dist/workflows/events/schema.d.ts +28 -28
  267. package/dist/workflows/hostExecutors/registry.d.ts +2 -7
  268. package/dist/workflows/hostExecutors/registry.d.ts.map +1 -1
  269. package/dist/workflows/hostExecutors/registry.js.map +1 -1
  270. package/dist/workflows/shared/provider-reconciler.d.ts +1 -30
  271. package/dist/workflows/shared/provider-reconciler.d.ts.map +1 -1
  272. package/dist/workflows/shared/provider-reconciler.js.map +1 -1
  273. package/dist/workflows/v3/artifact-contract.d.ts +41 -0
  274. package/dist/workflows/v3/artifact-contract.d.ts.map +1 -0
  275. package/dist/workflows/v3/artifact-contract.js +20 -0
  276. package/dist/workflows/v3/artifact-contract.js.map +1 -0
  277. package/dist/workflows/v3/botmux-attempt-lease.d.ts +7 -0
  278. package/dist/workflows/v3/botmux-attempt-lease.d.ts.map +1 -0
  279. package/dist/workflows/v3/botmux-attempt-lease.js +189 -0
  280. package/dist/workflows/v3/botmux-attempt-lease.js.map +1 -0
  281. package/dist/workflows/v3/botmux-host-policy.d.ts +7 -0
  282. package/dist/workflows/v3/botmux-host-policy.d.ts.map +1 -0
  283. package/dist/workflows/v3/botmux-host-policy.js +34 -0
  284. package/dist/workflows/v3/botmux-host-policy.js.map +1 -0
  285. package/dist/workflows/v3/cli-run.d.ts +1 -1
  286. package/dist/workflows/v3/cli-run.d.ts.map +1 -1
  287. package/dist/workflows/v3/cli-run.js +1 -1
  288. package/dist/workflows/v3/cli-run.js.map +1 -1
  289. package/dist/workflows/v3/contract.d.ts +8 -89
  290. package/dist/workflows/v3/contract.d.ts.map +1 -1
  291. package/dist/workflows/v3/contract.js +2 -8
  292. package/dist/workflows/v3/contract.js.map +1 -1
  293. package/dist/workflows/v3/core-control.d.ts +16 -0
  294. package/dist/workflows/v3/core-control.d.ts.map +1 -0
  295. package/dist/workflows/v3/core-control.js +60 -0
  296. package/dist/workflows/v3/core-control.js.map +1 -0
  297. package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
  298. package/dist/workflows/v3/daemon-run.js +2 -1
  299. package/dist/workflows/v3/daemon-run.js.map +1 -1
  300. package/dist/workflows/v3/dag-loader.d.ts +5 -0
  301. package/dist/workflows/v3/dag-loader.d.ts.map +1 -0
  302. package/dist/workflows/v3/dag-loader.js +22 -0
  303. package/dist/workflows/v3/dag-loader.js.map +1 -0
  304. package/dist/workflows/v3/dag.d.ts +2 -6
  305. package/dist/workflows/v3/dag.d.ts.map +1 -1
  306. package/dist/workflows/v3/dag.js +2 -24
  307. package/dist/workflows/v3/dag.js.map +1 -1
  308. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
  309. package/dist/workflows/v3/ephemeral-pool.js +22 -12
  310. package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
  311. package/dist/workflows/v3/event-contract.d.ts +273 -0
  312. package/dist/workflows/v3/event-contract.d.ts.map +1 -0
  313. package/dist/workflows/v3/event-contract.js +8 -0
  314. package/dist/workflows/v3/event-contract.js.map +1 -0
  315. package/dist/workflows/v3/gate-policy.d.ts +12 -0
  316. package/dist/workflows/v3/gate-policy.d.ts.map +1 -0
  317. package/dist/workflows/v3/gate-policy.js +20 -0
  318. package/dist/workflows/v3/gate-policy.js.map +1 -0
  319. package/dist/workflows/v3/gate-wait-store.d.ts +99 -0
  320. package/dist/workflows/v3/gate-wait-store.d.ts.map +1 -0
  321. package/dist/workflows/v3/gate-wait-store.js +263 -0
  322. package/dist/workflows/v3/gate-wait-store.js.map +1 -0
  323. package/dist/workflows/v3/host.js +1 -1
  324. package/dist/workflows/v3/host.js.map +1 -1
  325. package/dist/workflows/v3/human-gate.d.ts +4 -99
  326. package/dist/workflows/v3/human-gate.d.ts.map +1 -1
  327. package/dist/workflows/v3/human-gate.js +4 -275
  328. package/dist/workflows/v3/human-gate.js.map +1 -1
  329. package/dist/workflows/v3/in-process-attempt-lease.d.ts +10 -0
  330. package/dist/workflows/v3/in-process-attempt-lease.d.ts.map +1 -0
  331. package/dist/workflows/v3/in-process-attempt-lease.js +47 -0
  332. package/dist/workflows/v3/in-process-attempt-lease.js.map +1 -0
  333. package/dist/workflows/v3/journal.d.ts +2 -275
  334. package/dist/workflows/v3/journal.d.ts.map +1 -1
  335. package/dist/workflows/v3/journal.js.map +1 -1
  336. package/dist/workflows/v3/library-service.js +1 -1
  337. package/dist/workflows/v3/library-service.js.map +1 -1
  338. package/dist/workflows/v3/orchestrator.d.ts +1 -2
  339. package/dist/workflows/v3/orchestrator.d.ts.map +1 -1
  340. package/dist/workflows/v3/orchestrator.js.map +1 -1
  341. package/dist/workflows/v3/portable-artifact-snapshot.d.ts +15 -0
  342. package/dist/workflows/v3/portable-artifact-snapshot.d.ts.map +1 -0
  343. package/dist/workflows/v3/portable-artifact-snapshot.js +76 -0
  344. package/dist/workflows/v3/portable-artifact-snapshot.js.map +1 -0
  345. package/dist/workflows/v3/portable-final-outputs.d.ts +37 -0
  346. package/dist/workflows/v3/portable-final-outputs.d.ts.map +1 -0
  347. package/dist/workflows/v3/portable-final-outputs.js +137 -0
  348. package/dist/workflows/v3/portable-final-outputs.js.map +1 -0
  349. package/dist/workflows/v3/portable-run-snapshot.d.ts +14 -0
  350. package/dist/workflows/v3/portable-run-snapshot.d.ts.map +1 -0
  351. package/dist/workflows/v3/portable-run-snapshot.js +176 -0
  352. package/dist/workflows/v3/portable-run-snapshot.js.map +1 -0
  353. package/dist/workflows/v3/portable-runtime.d.ts +83 -0
  354. package/dist/workflows/v3/portable-runtime.d.ts.map +1 -0
  355. package/dist/workflows/v3/portable-runtime.js +135 -0
  356. package/dist/workflows/v3/portable-runtime.js.map +1 -0
  357. package/dist/workflows/v3/runtime-host-contract.d.ts +182 -0
  358. package/dist/workflows/v3/runtime-host-contract.d.ts.map +1 -0
  359. package/dist/workflows/v3/runtime-host-contract.js +9 -0
  360. package/dist/workflows/v3/runtime-host-contract.js.map +1 -0
  361. package/dist/workflows/v3/runtime.d.ts +12 -226
  362. package/dist/workflows/v3/runtime.d.ts.map +1 -1
  363. package/dist/workflows/v3/runtime.js +14 -3173
  364. package/dist/workflows/v3/runtime.js.map +1 -1
  365. package/dist/workflows/v3/shared-node-runtime.d.ts +203 -0
  366. package/dist/workflows/v3/shared-node-runtime.d.ts.map +1 -0
  367. package/dist/workflows/v3/shared-node-runtime.js +2978 -0
  368. package/dist/workflows/v3/shared-node-runtime.js.map +1 -0
  369. package/dist/workflows/v3/shared-runtime.d.ts +17 -0
  370. package/dist/workflows/v3/shared-runtime.d.ts.map +1 -0
  371. package/dist/workflows/v3/shared-runtime.js +12 -0
  372. package/dist/workflows/v3/shared-runtime.js.map +1 -0
  373. package/package.json +4 -1
  374. package/dist/dashboard-web/chunks/roles-page-LHVAU2BI.js +0 -1
package/dist/worker.js CHANGED
@@ -52,6 +52,7 @@ import { deriveTerminalViewToken, deriveTerminalWriteToken, resolveTerminalAcces
52
52
  import { readPlatformBinding } from './platform/binding.js';
53
53
  import { loadDashboardSecret, loadPersistedToken } from './dashboard/auth.js';
54
54
  import { InflightInputTracker } from './core/inflight-input-tracker.js';
55
+ import { InputTurnDeduper } from './core/input-turn-dedupe.js';
55
56
  import { shouldRunQuietRotation, evaluatePidResolverPullback, decideFingerprintSwitch, shouldHealAbsentBaseline, sessionIdFromJsonlPath, SESSION_ID_FILENAME_RE, } from './services/bridge-rotation-policy.js';
56
57
  import { CodexBridgeQueue } from './services/codex-bridge-queue.js';
57
58
  import { detectCodexComposerState } from './services/codex-composer-state.js';
@@ -59,7 +60,7 @@ import { generateCodexAppThreadTitle, readCodexAppThreadMetadata, setCodexAppThr
59
60
  import { buildBotmuxLarkNativeSessionTitle } from './core/session-title.js';
60
61
  import { drainCodexRollout, findCodexRolloutBySessionId, findCodexRolloutByPid, findCodexRolloutSetByPid, codexHistorySidIsOwned, splitCodexEventsByCutoff, extractLastCodexTurn, codexSessionIdFromRolloutPath, scanCodexThreadSettings } from './services/codex-transcript.js';
61
62
  import { CodexServiceTierTracker, resolveCodexServiceTierSnapshot } from './services/codex-service-tier.js';
62
- import { drainTraexRollout, findTraexRolloutBySessionId, findTraexRolloutByPid } from './services/traex-transcript.js';
63
+ import { drainTraexRollout, findTraexRolloutBySessionId, findTraexRolloutByPid, findTraexRolloutSetByPid, traexHistorySidIsOwned } from './services/traex-transcript.js';
63
64
  import { parseTraexUserInputQuestions } from './services/traex-user-input.js';
64
65
  import { cocoEventsPathForSession, drainCocoEvents, findCocoSessionByPid } from './services/coco-transcript.js';
65
66
  import { currentHermesStateOffset, drainHermesStateDb, resolveHermesStateDbPath } from './services/hermes-transcript.js';
@@ -1027,6 +1028,11 @@ let lastSpawnEffectiveCliSessionId;
1027
1028
  let lastSpawnDeferInitialPrompt = false;
1028
1029
  let lastSpawnQueuedInitialPrompt;
1029
1030
  let lastSpawnQueuedInitialPromptLogicalContent;
1031
+ // True when this session runs under an outer bwrap supervisor (file sandbox OR
1032
+ // Linux credential-only bwrap) — both make getChildPid() the supervisor, not the
1033
+ // CLI leaf. credentialOnlyBwrap needs host probes so it can't be recomputed from
1034
+ // cfg at gate-check time; capture the spawn-time verdict for currentTraexObservedPid.
1035
+ let lastSpawnOuterBwrapActive = false;
1030
1036
  /**
1031
1037
  * True only when {@link shouldArmSpawnArgvInitialPromptBusy} says so: argv-
1032
1038
  * baked first prompt + SessionStart ready (Grok-class). First markPromptReady
@@ -1155,7 +1161,7 @@ let closeRequested = false;
1155
1161
  let capturedSpawnCommand = null;
1156
1162
  let deferredTopicOutputTail = '';
1157
1163
  const reportedDeferredTopicRoots = new Set();
1158
- 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' };
1164
+ 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' };
1159
1165
  function cliName() {
1160
1166
  return (lastInitConfig?.cliRuntime?.source === 'configured'
1161
1167
  ? (lastInitConfig.cliRuntime.displayName?.trim() || lastInitConfig.cliRuntime.id)
@@ -1166,6 +1172,10 @@ function cliName() {
1166
1172
  let isPromptReady = false;
1167
1173
  /** Mutex for async flushPending — prevents concurrent flush loops. */
1168
1174
  let isFlushing = false;
1175
+ /** An init prompt exists but spawn/RPC policy has not yet established whether
1176
+ * it is argv-baked, RPC-owned, or queued. Concurrent follow-ups may enter the
1177
+ * queue during async init, but must not flush ahead of this first turn. */
1178
+ let initialInputOwnershipPending = false;
1169
1179
  /** True from the moment an owned CLI restart begins until the replacement
1170
1180
  * backend has been synchronously installed. Async backends (notably Riff)
1171
1181
  * keep the old backend object alive while destroySession() awaits remote
@@ -1471,6 +1481,13 @@ async function runStartupCommands() {
1471
1481
  }
1472
1482
  const freshnessInputQueue = new CodexRunnerFreshnessInputQueue(() => codexRunnerFreshness, state => { codexRunnerFreshness = state; });
1473
1483
  const pendingMessages = freshnessInputQueue.normal;
1484
+ /** Ordinary Lark IM turns may be retransmitted by the daemon when the exact
1485
+ * receipt ACK times out. Fence those retries before any renderer / adapter side
1486
+ * effects so one Lark message can enter the CLI input queue at most once per
1487
+ * worker generation. Durable receiver attempts already have their own lease
1488
+ * protocol and adopt writes have an ambiguity journal, so this gate stays on
1489
+ * non-adopt `om_` turns without dispatchAttempt. */
1490
+ const ordinaryImTurnDedupe = new InputTurnDeduper(256);
1474
1491
  /** Correlation ids that this worker actually wrote into the owned Codex App
1475
1492
  * runner. Runner lifecycle/final markers may route only to ids in this bounded
1476
1493
  * local set; model/user display bytes cannot add entries. */
@@ -3515,18 +3532,21 @@ function codexBridgeStartTimer() {
3515
3532
  cwd: lastInitConfig?.workingDir,
3516
3533
  pid: codexAdoptPendingPid,
3517
3534
  });
3518
- // Codex defense-in-depth: resolveFileBridgePath resolves sessionId-first,
3519
- // so a pending sid that is actually a shared-CODEX_HOME sibling's would
3520
- // resolve to that foreign rollout. Only attach when the resolved rollout's
3521
- // sid is one the observed pid actually holds open. This poller re-runs
3522
- // every 1s, so a lazily-opened owned fd is picked up on a later tick.
3523
- // Skip the gate only when we have no pid to prove ownership with (keeps
3524
- // the sid/pid resolution working for non-adopt / pid-less flows).
3525
- const attachOk = !(structuredBridgeIsCodex() && lastInitConfig?.adoptMode && path && currentCodexObservedPid())
3526
- || (() => {
3527
- const sid = codexSessionIdFromRolloutPath(path);
3528
- return !!sid && codexHistorySidOwnedByCurrentPid(sid);
3529
- })();
3535
+ // Codex/TRAE defense-in-depth: resolveFileBridgePath resolves
3536
+ // sessionId-first, so a pending sid that is actually a shared-home
3537
+ // sibling's (CODEX_HOME / TRAE_HOME) would resolve to that foreign
3538
+ // rollout. Only attach when the resolved rollout's sid is one the
3539
+ // observed pid actually holds open. This poller re-runs every 1s, so a
3540
+ // lazily-opened owned fd is picked up on a later tick. Skip the gate
3541
+ // only when we have no pid to prove ownership with (keeps the sid/pid
3542
+ // resolution working for non-adopt / pid-less flows).
3543
+ const codexAttachGated = structuredBridgeIsCodex() && lastInitConfig?.adoptMode && path && currentCodexObservedPid();
3544
+ const traexAttachGated = structuredBridgeIsTraex() && lastInitConfig?.adoptMode && path && currentTraexObservedPid();
3545
+ const attachOk = codexAttachGated
3546
+ ? (() => { const sid = codexSessionIdFromRolloutPath(path); return !!sid && codexHistorySidOwnedByCurrentPid(sid); })()
3547
+ : traexAttachGated
3548
+ ? (() => { const sid = codexSessionIdFromRolloutPath(path); return !!sid && traexHistorySidOwnedByCurrentPid(sid); })()
3549
+ : true;
3530
3550
  if (path && attachOk) {
3531
3551
  if (codexAdoptPendingPid && (lastInitConfig?.cliId === 'codex' || lastInitConfig?.cliId === 'traex')) {
3532
3552
  const discoveredSessionId = codexSessionIdFromRolloutPath(path);
@@ -3804,6 +3824,54 @@ function codexHistorySidOwnedByCurrentPid(cliSessionId) {
3804
3824
  }
3805
3825
  return owned;
3806
3826
  }
3827
+ /** Resolve the pid that actually holds a TRAE rollout open, given a candidate
3828
+ * that may be a bwrap supervisor. Under the file sandbox, botmux launches
3829
+ * `bwrap --unshare-pid -- traex`, so the tmux pane leaf / getChildPid() is the
3830
+ * bwrap process — its /proc/<pid>/fd holds no rollout, and the ownership gate
3831
+ * would always fail. The real traex leaf is host-visible across the pid ns
3832
+ * (ps -A ppid links), so a comm-based BFS descends to it. Outside the sandbox
3833
+ * (or if traex hasn't been forked yet) the candidate already is the leaf, so
3834
+ * we return it unchanged — fail closed to the launcher pid rather than guess. */
3835
+ function resolveTraexOwnershipPid(candidatePid, sandbox) {
3836
+ if (!sandbox || !candidatePid)
3837
+ return candidatePid;
3838
+ return findLaunchedCliPid(candidatePid, 'traex') ?? candidatePid;
3839
+ }
3840
+ /** TRAE counterpart of currentCodexObservedPid: the pid of the TRAE process
3841
+ * this worker observes (spawned child or adopted pane). Same resolution order
3842
+ * — the wired backend.cliPid first, then the live pane child pid, then the
3843
+ * adopt-pending pid (which is populated for TRAE too, see the codex/traex
3844
+ * branch around line 3674). backend.cliPid is already sandbox-resolved at wire
3845
+ * time; the getChildPid() fallback is not, so descend it here too (no-op
3846
+ * outside the sandbox / when already a leaf). */
3847
+ function currentTraexObservedPid() {
3848
+ const wired = backend?.cliPid;
3849
+ if (wired)
3850
+ return wired;
3851
+ const child = backend?.getChildPid?.();
3852
+ if (child)
3853
+ return resolveTraexOwnershipPid(child, lastSpawnOuterBwrapActive);
3854
+ return codexAdoptPendingPid;
3855
+ }
3856
+ /** Ownership gate for binding a TRAE session id that came from the GLOBAL
3857
+ * history.jsonl (shared by every TRAE pane under one TRAE_HOME). A concurrent
3858
+ * sibling pane submitting identical text — e.g. a bare "继续" in adopt mode,
3859
+ * which carries no unique <session_id> — can make writeInput's history match
3860
+ * surface a FOREIGN session id. Before persisting it (resume target) or
3861
+ * (re-)attaching the transcript bridge, require the id to be one THIS pid
3862
+ * actually holds open. FAIL CLOSED: unavailable fd enumeration (undefined set)
3863
+ * or a non-member id → false, so the caller keeps its current binding. Mirrors
3864
+ * codexHistorySidOwnedByCurrentPid; the pure decision lives in
3865
+ * traexHistorySidIsOwned for unit testing without a live pid. */
3866
+ function traexHistorySidOwnedByCurrentPid(cliSessionId) {
3867
+ const pid = currentTraexObservedPid();
3868
+ const ownedRollouts = pid ? findTraexRolloutSetByPid(pid) : undefined;
3869
+ const owned = traexHistorySidIsOwned(cliSessionId, ownedRollouts);
3870
+ if (!owned) {
3871
+ log(`TRAE session id ${cliSessionId} not owned by pid ${pid ?? '?'} (open rollouts: ${ownedRollouts ? [...ownedRollouts].join(',') || 'none' : 'unknown'})`);
3872
+ }
3873
+ return owned;
3874
+ }
3807
3875
  /** Called from flushPending after writeInput first returns a cliSessionId.
3808
3876
  * Tries to locate the rollout file immediately; if it's not on disk yet,
3809
3877
  * remembers the sid so the 1s poller can keep retrying. */
@@ -3863,6 +3931,15 @@ function codexBridgeNotifyCliSessionId(cliSessionId) {
3863
3931
  const currentSid = codexSessionIdFromRolloutPath(codexBridgeRolloutPath);
3864
3932
  if (currentSid && currentSid.toLowerCase() === cliSessionId.toLowerCase())
3865
3933
  return;
3934
+ // Ownership gate: the reported id came from the GLOBAL history.jsonl, so a
3935
+ // sibling pane's identical text (e.g. a bare adopt-mode reply with no
3936
+ // unique <session_id>) could surface a foreign id. Only rotate the bridge
3937
+ // to a rollout THIS pid holds open; otherwise keep the current binding
3938
+ // (fail closed on unknown/unowned). Mirrors the codex branch above.
3939
+ if (!traexHistorySidOwnedByCurrentPid(cliSessionId)) {
3940
+ log(`Keeping current TRAE bridge ${currentSid ?? '?'} — refusing history-only re-attach to ${cliSessionId}`);
3941
+ return;
3942
+ }
3866
3943
  const next = resolveFileBridgePath('traex', { sessionId: cliSessionId });
3867
3944
  // Close any terminal already committed to the retired rollout before
3868
3945
  // switching. A durable turn is a worker HOL barrier, so a legitimate
@@ -3982,6 +4059,19 @@ function codexBridgeNotifyCliSessionId(cliSessionId) {
3982
4059
  return;
3983
4060
  }
3984
4061
  }
4062
+ // TRAE INITIAL attach: same shared-history.jsonl hazard as codex above. The
4063
+ // TRAE adapter only returns an owned sid, but keep a defense-in-depth gate so
4064
+ // a foreign sid from any other path can't first-attach the bridge in adopt
4065
+ // mode. Fail closed identically: keep the poller armed on the adopt pid rather
4066
+ // than pinning an unverified sid (which would wedge the bridge).
4067
+ if (structuredBridgeIsTraex() && lastInitConfig?.adoptMode && currentTraexObservedPid()) {
4068
+ if (!traexHistorySidOwnedByCurrentPid(cliSessionId)) {
4069
+ log(`TRAE initial-attach refused for unverified session ${cliSessionId}; keeping poller armed on pid ${currentTraexObservedPid()}`);
4070
+ codexBridgePendingSessionId = undefined;
4071
+ codexBridgeStartTimer();
4072
+ return;
4073
+ }
4074
+ }
3985
4075
  const path = resolveFileBridgePath(lastInitConfig?.cliId, {
3986
4076
  sessionId: cliSessionId,
3987
4077
  cwd: lastInitConfig?.workingDir,
@@ -6441,6 +6531,8 @@ async function flushPending() {
6441
6531
  // backend's idle/task-done callback) write across that restart boundary.
6442
6532
  if (cliRestartInProgress)
6443
6533
  return;
6534
+ if (initialInputOwnershipPending)
6535
+ return;
6444
6536
  if (shouldHoldCodexRunnerInput(codexRunnerFreshness))
6445
6537
  return;
6446
6538
  if (isFlushing)
@@ -6845,8 +6937,6 @@ async function flushPending() {
6845
6937
  }
6846
6938
  }
6847
6939
  function sendToPty(content, turnId, opts = {}) {
6848
- if (!cliAdapter)
6849
- return false;
6850
6940
  const next = {
6851
6941
  content,
6852
6942
  turnId,
@@ -6865,6 +6955,8 @@ function sendToPty(content, turnId, opts = {}) {
6865
6955
  log(`Queued message while CLI backend is restarting (${pendingMessages.length} pending)`);
6866
6956
  return true;
6867
6957
  }
6958
+ if (!cliAdapter)
6959
+ return false;
6868
6960
  const supportsTypeAhead = pendingInputAllowsTypeAhead(cliAdapter.supportsTypeAhead === true, durableTurnInFlight, next);
6869
6961
  const shouldMergeQueued = opts.dispatchAttempt === undefined && !durableTurnInFlight
6870
6962
  && !isFlushing && !shouldWriteNow({
@@ -7194,8 +7286,18 @@ function setupAdoptInputAdapter(cfg) {
7194
7286
  cliAdapter = createCliAdapterSync(cfg.cliId, cfg.cliPathOverride);
7195
7287
  }
7196
7288
  }
7289
+ function wireIdleDetectorBusyTransition(detector, label) {
7290
+ detector.onBusy(() => {
7291
+ if (!isPromptReady)
7292
+ return;
7293
+ isPromptReady = false;
7294
+ log(`Explicit busy marker detected — ${label}`);
7295
+ publishScreenStatus('working', { force: true });
7296
+ });
7297
+ }
7197
7298
  function setupAdoptIdleDetection(cfg, label) {
7198
7299
  idleDetector = new IdleDetector(adoptIdleAdapter(cfg));
7300
+ wireIdleDetectorBusyTransition(idleDetector, `${label} adopt mode`);
7199
7301
  idleDetector.onIdle(() => {
7200
7302
  if (backend && deferPromptReadyWhileBusy(`${label} adopt-idle`, backend))
7201
7303
  return;
@@ -9360,17 +9462,63 @@ async function spawnCli(cfg, opts = {}) {
9360
9462
  startWrapperRealPidResolve(cliPid);
9361
9463
  if (cliPid)
9362
9464
  observeCursorCliSessionId(cliPid);
9465
+ // File sandbox / Linux credential-only bwrap launches `bwrap --unshare-pid --
9466
+ // traex`, so the pane leaf (getChildPid) is the bwrap SUPERVISOR — its
9467
+ // /proc/<pid>/fd holds no rollout and the TRAE ownership gate can never admit
9468
+ // a session id (fresh sandbox TRAE then never captures its SID, the bridge
9469
+ // never attaches, and because reliableTurnTerminal disables screen-idle the
9470
+ // durable turn can wedge — it does NOT self-heal). The real traex leaf is
9471
+ // host-visible across the pid ns (ps -A ppid links), so BFS-descend to it and
9472
+ // rewire backend.cliPid. Bounded retry (not one-shot): bwrap may not have
9473
+ // forked traex yet at spawn. Reuses scheduleWrapperRealCliPid's stale-backend
9474
+ // guard so a mid-retry worker restart can't rewire the new session. Gated on
9475
+ // outerBwrapActive — sandboxRequested OR the Linux credential-only bwrap path,
9476
+ // both of which produce an outer supervisor pid. */
9477
+ const outerBwrapActive = sandboxRequested || credentialOnlyBwrap;
9478
+ lastSpawnOuterBwrapActive = outerBwrapActive;
9479
+ const startTraexSandboxPidResolve = (launcherPid) => {
9480
+ if (cfg.cliId !== 'traex' || !outerBwrapActive)
9481
+ return;
9482
+ scheduleWrapperRealCliPid(launcherPid, {
9483
+ findRealPid: (lp) => findLaunchedCliPid(lp, 'traex'),
9484
+ getBackend: () => backend,
9485
+ getChildPid: () => backend?.getChildPid?.(),
9486
+ applyRealPid: (realPid) => {
9487
+ log(`TRAE sandbox: resolved real traex leaf pid ${realPid} under bwrap supervisor ${launcherPid}; rewiring ownership pid`);
9488
+ backend.cliPid = realPid;
9489
+ backend.cliCwd = cfg.workingDir;
9490
+ publishLocalProcessAttestation(realPid);
9491
+ },
9492
+ schedule: (fn, ms) => { setTimeout(fn, ms); },
9493
+ });
9494
+ };
9363
9495
  // Wire pid + cwd so adapters' writeInput can bind submits to this process:
9364
9496
  // - claude-code: ~/.claude/sessions/<pid>.json
9365
9497
  // - grok: findGrokSessionByPid → preferSessionId against shared
9366
9498
  // prompt_history (concurrent same-cwd workers must not cross-claim)
9499
+ // - traex: findTraexRolloutSetByPid → ownership gate for the shared global
9500
+ // history.jsonl (concurrent same-TRAE_HOME panes must not cross-claim a
9501
+ // sibling's session id from an identical-text submit). getChildPid() is
9502
+ // normally the traex process itself, EXCEPT under the file sandbox: bwrap
9503
+ // runs `--unshare-pid -- traex`, so the pane leaf is the bwrap supervisor
9504
+ // and /proc/<bwrap>/fd holds no rollout. resolveTraexOwnershipPid() BFS-
9505
+ // descends to the real traex leaf (host-visible across the pid ns via
9506
+ // `ps -A` ppid links) so the ownership gate can actually admit the id;
9507
+ // it fails closed to the launcher pid when no leaf is found yet (the async
9508
+ // retry below re-resolves once bwrap has forked traex).
9509
+ // - reasonix: identify the lease owned by this process tree
9367
9510
  // Claude's sessionId is set ONCE at process start (2.1.123); a `--resume`
9368
9511
  // lookup will surface here, but in-pane `/clear` won't. The pinned
9369
9512
  // claudeJsonlPath above is still the initial guess; the resolver corrects
9370
9513
  // it on first write when Claude was started with `--resume`.
9371
- if (cliPid && (claudeDataDir || cfg.cliId === 'grok')) {
9372
- backend.cliPid = cliPid;
9514
+ if (cliPid && (claudeDataDir || cfg.cliId === 'grok' || cfg.cliId === 'traex' || cfg.cliId === 'reasonix')) {
9515
+ // TRAE under outer bwrap: best-effort immediate resolve (leaf may already be
9516
+ // forked), then a bounded retry below covers the not-yet-forked case.
9517
+ const wiredPid = cfg.cliId === 'traex' ? resolveTraexOwnershipPid(cliPid, outerBwrapActive) : cliPid;
9518
+ backend.cliPid = wiredPid;
9373
9519
  backend.cliCwd = cfg.workingDir;
9520
+ if (cfg.cliId === 'traex' && outerBwrapActive)
9521
+ startTraexSandboxPidResolve(cliPid);
9374
9522
  }
9375
9523
  // Async pid fallback: tmux/pty resolve the CLI pid synchronously above, but
9376
9524
  // zellij's CLI subprocess starts AFTER spawn() returns (the zellij server
@@ -9399,9 +9547,12 @@ async function spawnCli(cfg, opts = {}) {
9399
9547
  log(`Failed to write CLI PID marker (async): ${err.message}`);
9400
9548
  }
9401
9549
  }
9402
- if (claudeDataDir || cfg.cliId === 'grok') {
9403
- backend.cliPid = pid;
9550
+ if (claudeDataDir || cfg.cliId === 'grok' || cfg.cliId === 'traex' || cfg.cliId === 'reasonix') {
9551
+ const wiredPid = cfg.cliId === 'traex' ? resolveTraexOwnershipPid(pid, outerBwrapActive) : pid;
9552
+ backend.cliPid = wiredPid;
9404
9553
  backend.cliCwd = cfg.workingDir;
9554
+ if (cfg.cliId === 'traex' && outerBwrapActive)
9555
+ startTraexSandboxPidResolve(pid);
9405
9556
  }
9406
9557
  // wrapperCli under a late-pid backend (zellij): `pid` here is still the
9407
9558
  // LAUNCHER. Kick the descendant resolver so the bridge gets the real CLI
@@ -9628,6 +9779,7 @@ async function spawnCli(cfg, opts = {}) {
9628
9779
  // quiescence, repeatedly triggering markPromptReady() and duplicate cards.
9629
9780
  if (effectiveBackendType !== 'riff') {
9630
9781
  idleDetector = new IdleDetector(cliAdapter);
9782
+ wireIdleDetectorBusyTransition(idleDetector, `${cliName()} PTY`);
9631
9783
  idleDetector.onIdle(async (evidenceSource) => {
9632
9784
  log('Prompt detected (idle)');
9633
9785
  // Snapshot-only backends (ZMX) must complete one authoritative refresh
@@ -11401,8 +11553,23 @@ function send(msg) {
11401
11553
  process.send?.(payload);
11402
11554
  }
11403
11555
  function acknowledgeTurnInputCommitted(turnId) {
11556
+ if (!turnId)
11557
+ return;
11558
+ ordinaryImTurnDedupe.commit(turnId);
11559
+ send({ type: 'turn_input_committed', turnId });
11560
+ }
11561
+ function acknowledgeTurnInputReceived(turnId) {
11404
11562
  if (turnId)
11405
- send({ type: 'turn_input_committed', turnId });
11563
+ send({ type: 'turn_input_received', turnId });
11564
+ }
11565
+ function receiveOrdinaryImTurn(turnId) {
11566
+ const state = ordinaryImTurnDedupe.begin(turnId);
11567
+ acknowledgeTurnInputReceived(turnId);
11568
+ return state;
11569
+ }
11570
+ function rejectOrdinaryImTurn(turnId, reason) {
11571
+ ordinaryImTurnDedupe.release(turnId);
11572
+ send({ type: 'turn_input_rejected', turnId, reason });
11406
11573
  }
11407
11574
  function publishLocalProcessAttestation(cliPid) {
11408
11575
  const cliProcStart = cliPid ? readProcessStartIdentity(cliPid) : undefined;
@@ -11492,9 +11659,44 @@ process.on('message', async (raw) => {
11492
11659
  switch (msg.type) {
11493
11660
  case 'init': {
11494
11661
  const initStartedAtMs = Date.now();
11495
- if (lastInitConfig)
11496
- return; // already initialized
11662
+ const ordinaryImTurnId = !msg.adoptMode
11663
+ && msg.dispatchAttempt === undefined
11664
+ && !!msg.prompt
11665
+ && msg.turnId?.startsWith('om_')
11666
+ ? msg.turnId
11667
+ : undefined;
11668
+ if (lastInitConfig) {
11669
+ // Only an exact retry of this generation's init may be acknowledged.
11670
+ // A different init is still rejected as an invalid re-initialization.
11671
+ if (ordinaryImTurnId && lastInitConfig.turnId === ordinaryImTurnId) {
11672
+ const duplicateState = receiveOrdinaryImTurn(ordinaryImTurnId);
11673
+ if (duplicateState === 'committed') {
11674
+ log(`Re-ACKing committed duplicate init turn ${ordinaryImTurnId.substring(0, 16)}`);
11675
+ acknowledgeTurnInputCommitted(ordinaryImTurnId);
11676
+ }
11677
+ else {
11678
+ log(`Re-ACKing received duplicate init turn ${ordinaryImTurnId.substring(0, 16)}`);
11679
+ }
11680
+ }
11681
+ return;
11682
+ }
11683
+ if (ordinaryImTurnId) {
11684
+ const duplicateState = receiveOrdinaryImTurn(ordinaryImTurnId);
11685
+ // Receipt is the daemon ↔ worker transport boundary. Publish it before
11686
+ // startup work can await a slow backend, plugin gateway, or Codex
11687
+ // metadata read. The later committed ACK keeps its existing meaning.
11688
+ if (duplicateState === 'committed') {
11689
+ log(`Re-ACKing committed duplicate init turn ${ordinaryImTurnId.substring(0, 16)}`);
11690
+ acknowledgeTurnInputCommitted(ordinaryImTurnId);
11691
+ break;
11692
+ }
11693
+ if (duplicateState === 'inflight') {
11694
+ log(`Re-ACKing received duplicate init turn ${ordinaryImTurnId.substring(0, 16)}`);
11695
+ break;
11696
+ }
11697
+ }
11497
11698
  lastInitConfig = msg;
11699
+ initialInputOwnershipPending = !!msg.prompt;
11498
11700
  activeRestartAttemptId = msg.restartAttemptId;
11499
11701
  sessionId = msg.sessionId;
11500
11702
  refreshTerminalViewToken();
@@ -11649,7 +11851,10 @@ process.on('message', async (raw) => {
11649
11851
  passesInitialPromptViaArgs: cliAdapter?.passesInitialPromptViaArgs === true,
11650
11852
  deferInitialPrompt,
11651
11853
  })) {
11652
- pendingMessages.push({
11854
+ // Follow-up IPC handlers can run while this async init is awaiting
11855
+ // backend startup. They queue safely behind !backend above, but the
11856
+ // original init prompt must remain first in logical turn order.
11857
+ pendingMessages.unshift({
11653
11858
  content: lastSpawnQueuedInitialPrompt ?? msg.prompt,
11654
11859
  ...(lastSpawnQueuedInitialPromptLogicalContent
11655
11860
  ? { logicalContent: lastSpawnQueuedInitialPromptLogicalContent }
@@ -11666,6 +11871,10 @@ process.on('message', async (raw) => {
11666
11871
  // it into argv or the RPC engine already accepted it.
11667
11872
  initialInputCommitted = true;
11668
11873
  }
11874
+ // The first turn is now either at queue head or already owned by the
11875
+ // argv/RPC startup path. Only now may an early idle edge drain
11876
+ // follow-ups that arrived while init was awaiting slow startup work.
11877
+ initialInputOwnershipPending = false;
11669
11878
  if (initialInputCommitted)
11670
11879
  acknowledgeTurnInputCommitted(msg.turnId);
11671
11880
  // A backend may become prompt-ready before spawnCli() returns. The
@@ -11692,6 +11901,7 @@ process.on('message', async (raw) => {
11692
11901
  });
11693
11902
  }
11694
11903
  catch (err) {
11904
+ initialInputOwnershipPending = false;
11695
11905
  await sendFatalWorkerErrorAndExit(err);
11696
11906
  return;
11697
11907
  }
@@ -11699,6 +11909,25 @@ process.on('message', async (raw) => {
11699
11909
  }
11700
11910
  case 'message': {
11701
11911
  const messageAdoptMode = lastInitConfig?.adoptMode === true;
11912
+ const ordinaryImTurnId = !messageAdoptMode
11913
+ && msg.dispatchAttempt === undefined
11914
+ && msg.turnId?.startsWith('om_')
11915
+ ? msg.turnId
11916
+ : undefined;
11917
+ if (ordinaryImTurnId) {
11918
+ const duplicateState = receiveOrdinaryImTurn(ordinaryImTurnId);
11919
+ // ACK process ownership synchronously, before crash recovery or any
11920
+ // other awaited work. Actual queue ownership remains committed below.
11921
+ if (duplicateState === 'committed') {
11922
+ log(`Re-ACKing committed duplicate IM turn ${ordinaryImTurnId.substring(0, 16)}`);
11923
+ acknowledgeTurnInputCommitted(ordinaryImTurnId);
11924
+ break;
11925
+ }
11926
+ if (duplicateState === 'inflight') {
11927
+ log(`Re-ACKing received duplicate IM turn ${ordinaryImTurnId.substring(0, 16)}`);
11928
+ break;
11929
+ }
11930
+ }
11702
11931
  // Adopt IPC handlers can overlap. Delay their turn baseline until the
11703
11932
  // submission mutex is held so a queued message cannot steal attribution
11704
11933
  // from the write/verification already in flight.
@@ -11746,6 +11975,8 @@ process.on('message', async (raw) => {
11746
11975
  await prepareCodexNativeTitleGeneration(restartCfg, codexRpcEngine);
11747
11976
  }
11748
11977
  catch (err) {
11978
+ if (ordinaryImTurnId)
11979
+ ordinaryImTurnDedupe.release(ordinaryImTurnId);
11749
11980
  // Pass the message's own attempt (not the stale currentBotmux* from a
11750
11981
  // prior IM turn) so a durable delivery relaunch failure carries the
11751
11982
  // right attribution for the daemon's receipt/lease gate.
@@ -11936,6 +12167,8 @@ process.on('message', async (raw) => {
11936
12167
  });
11937
12168
  if (inputCommitted)
11938
12169
  acknowledgeTurnInputCommitted(msg.turnId);
12170
+ else if (ordinaryImTurnId)
12171
+ rejectOrdinaryImTurn(ordinaryImTurnId, 'cli_input_unavailable');
11939
12172
  }
11940
12173
  break;
11941
12174
  }
@@ -12383,6 +12616,13 @@ process.on('message', async (raw) => {
12383
12616
  killCli({ preserveSandbox: true });
12384
12617
  cleanup();
12385
12618
  await flushTransferDetachAck(msg.requestId);
12619
+ // NOTE: process.exit(0) can wedge in node-pty's native teardown when a
12620
+ // web-terminal client PTY was attached (the reader-thread join blocks and
12621
+ // the JS event loop is already stopped, so this process cannot self-kill
12622
+ // via a timer). killCli() above already detached the observer and the ACK
12623
+ // just flushed, so the daemon force-kills this now-disposable process
12624
+ // shortly after the ACK (see detachWorkerForTransfer's post-ACK kill).
12625
+ // We still request a clean exit; the daemon SIGKILL is the hard backstop.
12386
12626
  process.exit(0);
12387
12627
  }
12388
12628
  case 'suspend': {