oh-my-codex 0.15.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +36 -5
  4. package/crates/omx-explore/src/main.rs +222 -12
  5. package/dist/agents/__tests__/native-config.test.js +40 -0
  6. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  7. package/dist/agents/native-config.d.ts +1 -0
  8. package/dist/agents/native-config.d.ts.map +1 -1
  9. package/dist/agents/native-config.js +6 -1
  10. package/dist/agents/native-config.js.map +1 -1
  11. package/dist/agents/policy.d.ts +1 -0
  12. package/dist/agents/policy.d.ts.map +1 -1
  13. package/dist/agents/policy.js +4 -0
  14. package/dist/agents/policy.js.map +1 -1
  15. package/dist/cli/__tests__/autoresearch-guided.test.js +37 -13
  16. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  17. package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -1
  18. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  19. package/dist/cli/__tests__/doctor-team.test.js +46 -1
  20. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  21. package/dist/cli/__tests__/doctor-warning-copy.test.js +225 -111
  22. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  23. package/dist/cli/__tests__/exec.test.js +96 -1
  24. package/dist/cli/__tests__/exec.test.js.map +1 -1
  25. package/dist/cli/__tests__/explore.test.js +15 -2
  26. package/dist/cli/__tests__/explore.test.js.map +1 -1
  27. package/dist/cli/__tests__/index.test.js +292 -3
  28. package/dist/cli/__tests__/index.test.js.map +1 -1
  29. package/dist/cli/__tests__/launch-fallback.test.js +223 -0
  30. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  31. package/dist/cli/__tests__/mcp-parity.test.js +86 -0
  32. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  33. package/dist/cli/__tests__/package-bin-contract.test.js +23 -0
  34. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  35. package/dist/cli/__tests__/question.test.js +76 -11
  36. package/dist/cli/__tests__/question.test.js.map +1 -1
  37. package/dist/cli/__tests__/setup-agents-overwrite.test.js +140 -1
  38. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  39. package/dist/cli/__tests__/setup-install-mode.test.js +310 -4
  40. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  41. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +78 -19
  42. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
  43. package/dist/cli/__tests__/setup-refresh.test.js +79 -2
  44. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  45. package/dist/cli/__tests__/sidecar.test.d.ts +2 -0
  46. package/dist/cli/__tests__/sidecar.test.d.ts.map +1 -0
  47. package/dist/cli/__tests__/sidecar.test.js +24 -0
  48. package/dist/cli/__tests__/sidecar.test.js.map +1 -0
  49. package/dist/cli/__tests__/team.test.js +54 -7
  50. package/dist/cli/__tests__/team.test.js.map +1 -1
  51. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  52. package/dist/cli/autoresearch-guided.js +12 -4
  53. package/dist/cli/autoresearch-guided.js.map +1 -1
  54. package/dist/cli/codex-home.d.ts +4 -6
  55. package/dist/cli/codex-home.d.ts.map +1 -1
  56. package/dist/cli/codex-home.js +9 -41
  57. package/dist/cli/codex-home.js.map +1 -1
  58. package/dist/cli/doctor.d.ts +1 -1
  59. package/dist/cli/doctor.d.ts.map +1 -1
  60. package/dist/cli/doctor.js +509 -279
  61. package/dist/cli/doctor.js.map +1 -1
  62. package/dist/cli/index.d.ts +6 -4
  63. package/dist/cli/index.d.ts.map +1 -1
  64. package/dist/cli/index.js +284 -25
  65. package/dist/cli/index.js.map +1 -1
  66. package/dist/cli/omx.js +3 -1
  67. package/dist/cli/omx.js.map +1 -1
  68. package/dist/cli/plugin-marketplace.d.ts +13 -0
  69. package/dist/cli/plugin-marketplace.d.ts.map +1 -0
  70. package/dist/cli/plugin-marketplace.js +77 -0
  71. package/dist/cli/plugin-marketplace.js.map +1 -0
  72. package/dist/cli/question.d.ts +1 -1
  73. package/dist/cli/question.d.ts.map +1 -1
  74. package/dist/cli/question.js +26 -12
  75. package/dist/cli/question.js.map +1 -1
  76. package/dist/cli/setup-preferences.d.ts +20 -0
  77. package/dist/cli/setup-preferences.d.ts.map +1 -0
  78. package/dist/cli/setup-preferences.js +71 -0
  79. package/dist/cli/setup-preferences.js.map +1 -0
  80. package/dist/cli/setup.d.ts +7 -5
  81. package/dist/cli/setup.d.ts.map +1 -1
  82. package/dist/cli/setup.js +271 -152
  83. package/dist/cli/setup.js.map +1 -1
  84. package/dist/cli/team.d.ts +1 -0
  85. package/dist/cli/team.d.ts.map +1 -1
  86. package/dist/cli/team.js +70 -15
  87. package/dist/cli/team.js.map +1 -1
  88. package/dist/config/__tests__/generator-idempotent.test.js +100 -3
  89. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  90. package/dist/config/__tests__/generator-notify.test.js +6 -5
  91. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  92. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +2 -0
  93. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +1 -0
  94. package/dist/config/__tests__/generator-status-line-presets.test.js +203 -0
  95. package/dist/config/__tests__/generator-status-line-presets.test.js.map +1 -0
  96. package/dist/config/__tests__/models.test.js +23 -1
  97. package/dist/config/__tests__/models.test.js.map +1 -1
  98. package/dist/config/generator.d.ts +9 -1
  99. package/dist/config/generator.d.ts.map +1 -1
  100. package/dist/config/generator.js +184 -16
  101. package/dist/config/generator.js.map +1 -1
  102. package/dist/config/models.d.ts +5 -1
  103. package/dist/config/models.d.ts.map +1 -1
  104. package/dist/config/models.js +12 -2
  105. package/dist/config/models.js.map +1 -1
  106. package/dist/exec/followup.d.ts +44 -0
  107. package/dist/exec/followup.d.ts.map +1 -0
  108. package/dist/exec/followup.js +349 -0
  109. package/dist/exec/followup.js.map +1 -0
  110. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +2 -0
  111. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +1 -0
  112. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +37 -0
  113. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -0
  114. package/dist/hooks/__tests__/codebase-map.test.js +63 -1
  115. package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
  116. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
  117. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +5 -5
  118. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  119. package/dist/hooks/__tests__/deep-interview-contract.test.js +12 -9
  120. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  121. package/dist/hooks/__tests__/keyword-detector.test.js +25 -18
  122. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  123. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +23 -2
  124. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  125. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +45 -2
  126. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  127. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +17 -0
  128. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  129. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +121 -0
  130. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  131. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +4 -4
  132. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  133. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +103 -0
  134. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  135. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +2 -2
  136. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  137. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +27 -13
  138. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  139. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +2 -0
  140. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +1 -0
  141. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +35 -0
  142. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -0
  143. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +215 -0
  144. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  145. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +70 -3
  146. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  147. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +5 -0
  148. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  149. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +3 -2
  150. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
  151. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +9 -0
  152. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  153. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +2 -0
  154. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +1 -0
  155. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +22 -0
  156. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +1 -0
  157. package/dist/hooks/codebase-map.d.ts.map +1 -1
  158. package/dist/hooks/codebase-map.js +83 -6
  159. package/dist/hooks/codebase-map.js.map +1 -1
  160. package/dist/hooks/keyword-detector.d.ts +1 -1
  161. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  162. package/dist/hooks/keyword-detector.js +35 -4
  163. package/dist/hooks/keyword-detector.js.map +1 -1
  164. package/dist/hooks/prompt-guidance-contract.d.ts +6 -0
  165. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  166. package/dist/hooks/prompt-guidance-contract.js +117 -13
  167. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  168. package/dist/hooks/session.d.ts +2 -0
  169. package/dist/hooks/session.d.ts.map +1 -1
  170. package/dist/hooks/session.js +6 -0
  171. package/dist/hooks/session.js.map +1 -1
  172. package/dist/hud/__tests__/index.test.js +4 -4
  173. package/dist/hud/__tests__/index.test.js.map +1 -1
  174. package/dist/hud/__tests__/state.test.js +4 -0
  175. package/dist/hud/__tests__/state.test.js.map +1 -1
  176. package/dist/hud/__tests__/types.test.js +27 -0
  177. package/dist/hud/__tests__/types.test.js.map +1 -1
  178. package/dist/hud/state.d.ts.map +1 -1
  179. package/dist/hud/state.js +8 -0
  180. package/dist/hud/state.js.map +1 -1
  181. package/dist/hud/types.d.ts +9 -0
  182. package/dist/hud/types.d.ts.map +1 -1
  183. package/dist/hud/types.js +3 -0
  184. package/dist/hud/types.js.map +1 -1
  185. package/dist/mcp/__tests__/bootstrap.test.js +23 -5
  186. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  187. package/dist/mcp/__tests__/server-lifecycle.test.js +50 -7
  188. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  189. package/dist/mcp/__tests__/state-server.test.js +70 -12
  190. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  191. package/dist/mcp/bootstrap.d.ts +10 -1
  192. package/dist/mcp/bootstrap.d.ts.map +1 -1
  193. package/dist/mcp/bootstrap.js +71 -26
  194. package/dist/mcp/bootstrap.js.map +1 -1
  195. package/dist/mcp/state-server.d.ts +5 -11
  196. package/dist/mcp/state-server.d.ts.map +1 -1
  197. package/dist/mcp/state-server.js +16 -432
  198. package/dist/mcp/state-server.js.map +1 -1
  199. package/dist/modes/__tests__/base-autoresearch-contract.test.js +1 -1
  200. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
  201. package/dist/pipeline/__tests__/orchestrator.test.js +89 -5
  202. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  203. package/dist/pipeline/__tests__/stages.test.js +98 -1
  204. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  205. package/dist/pipeline/index.d.ts +5 -3
  206. package/dist/pipeline/index.d.ts.map +1 -1
  207. package/dist/pipeline/index.js +4 -3
  208. package/dist/pipeline/index.js.map +1 -1
  209. package/dist/pipeline/orchestrator.d.ts +7 -6
  210. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  211. package/dist/pipeline/orchestrator.js +90 -11
  212. package/dist/pipeline/orchestrator.js.map +1 -1
  213. package/dist/pipeline/review-verdict.d.ts +3 -0
  214. package/dist/pipeline/review-verdict.d.ts.map +1 -0
  215. package/dist/pipeline/review-verdict.js +14 -0
  216. package/dist/pipeline/review-verdict.js.map +1 -0
  217. package/dist/pipeline/stages/code-review.d.ts +33 -0
  218. package/dist/pipeline/stages/code-review.d.ts.map +1 -0
  219. package/dist/pipeline/stages/code-review.js +51 -0
  220. package/dist/pipeline/stages/code-review.js.map +1 -0
  221. package/dist/pipeline/stages/ralph-verify.d.ts +12 -2
  222. package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
  223. package/dist/pipeline/stages/ralph-verify.js +24 -6
  224. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  225. package/dist/pipeline/stages/ralplan.d.ts +1 -1
  226. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  227. package/dist/pipeline/stages/ralplan.js +21 -1
  228. package/dist/pipeline/stages/ralplan.js.map +1 -1
  229. package/dist/pipeline/types.d.ts +14 -7
  230. package/dist/pipeline/types.d.ts.map +1 -1
  231. package/dist/pipeline/types.js +2 -2
  232. package/dist/planning/__tests__/artifacts.test.js +152 -1
  233. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  234. package/dist/planning/artifacts.d.ts +9 -0
  235. package/dist/planning/artifacts.d.ts.map +1 -1
  236. package/dist/planning/artifacts.js +60 -1
  237. package/dist/planning/artifacts.js.map +1 -1
  238. package/dist/question/__tests__/client.test.js +23 -3
  239. package/dist/question/__tests__/client.test.js.map +1 -1
  240. package/dist/question/__tests__/renderer.test.js +148 -37
  241. package/dist/question/__tests__/renderer.test.js.map +1 -1
  242. package/dist/question/__tests__/types.test.js +21 -0
  243. package/dist/question/__tests__/types.test.js.map +1 -1
  244. package/dist/question/__tests__/ui.test.js +155 -7
  245. package/dist/question/__tests__/ui.test.js.map +1 -1
  246. package/dist/question/client.d.ts +14 -4
  247. package/dist/question/client.d.ts.map +1 -1
  248. package/dist/question/client.js.map +1 -1
  249. package/dist/question/renderer.d.ts +11 -1
  250. package/dist/question/renderer.d.ts.map +1 -1
  251. package/dist/question/renderer.js +102 -7
  252. package/dist/question/renderer.js.map +1 -1
  253. package/dist/question/state.d.ts +2 -2
  254. package/dist/question/state.d.ts.map +1 -1
  255. package/dist/question/state.js +26 -17
  256. package/dist/question/state.js.map +1 -1
  257. package/dist/question/types.d.ts +25 -1
  258. package/dist/question/types.d.ts.map +1 -1
  259. package/dist/question/types.js +48 -13
  260. package/dist/question/types.js.map +1 -1
  261. package/dist/question/ui.d.ts +15 -2
  262. package/dist/question/ui.d.ts.map +1 -1
  263. package/dist/question/ui.js +268 -162
  264. package/dist/question/ui.js.map +1 -1
  265. package/dist/scripts/__tests__/codex-native-hook.test.js +415 -94
  266. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  267. package/dist/scripts/__tests__/generate-release-body.test.js +36 -0
  268. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
  269. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +2 -0
  270. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +1 -0
  271. package/dist/scripts/__tests__/prompt-inventory.test.js +56 -0
  272. package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -0
  273. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  274. package/dist/scripts/codex-native-hook.js +232 -54
  275. package/dist/scripts/codex-native-hook.js.map +1 -1
  276. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  277. package/dist/scripts/codex-native-pre-post.js +12 -9
  278. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  279. package/dist/scripts/generate-release-body.d.ts.map +1 -1
  280. package/dist/scripts/generate-release-body.js +12 -3
  281. package/dist/scripts/generate-release-body.js.map +1 -1
  282. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +2 -0
  283. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +1 -0
  284. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +153 -0
  285. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +1 -0
  286. package/dist/scripts/notify-hook/managed-tmux.d.ts +4 -2
  287. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  288. package/dist/scripts/notify-hook/managed-tmux.js +188 -6
  289. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  290. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
  291. package/dist/scripts/notify-hook/process-runner.js +7 -3
  292. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  293. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  294. package/dist/scripts/notify-hook/team-dispatch.js +96 -11
  295. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  296. package/dist/scripts/notify-hook/team-tmux-guard.js +3 -3
  297. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts +34 -0
  298. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts.map +1 -0
  299. package/dist/scripts/notify-hook/team-worker-posttooluse.js +434 -0
  300. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -0
  301. package/dist/scripts/notify-hook/team-worker.d.ts +1 -1
  302. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  303. package/dist/scripts/notify-hook/team-worker.js +3 -43
  304. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  305. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  306. package/dist/scripts/notify-hook/tmux-injection.js +25 -4
  307. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  308. package/dist/scripts/notify-hook.js +36 -5
  309. package/dist/scripts/notify-hook.js.map +1 -1
  310. package/dist/scripts/prompt-inventory.d.ts +29 -0
  311. package/dist/scripts/prompt-inventory.d.ts.map +1 -0
  312. package/dist/scripts/prompt-inventory.js +178 -0
  313. package/dist/scripts/prompt-inventory.js.map +1 -0
  314. package/dist/scripts/run-test-files.js +1 -0
  315. package/dist/scripts/run-test-files.js.map +1 -1
  316. package/dist/sidecar/__tests__/boundary.test.d.ts +2 -0
  317. package/dist/sidecar/__tests__/boundary.test.d.ts.map +1 -0
  318. package/dist/sidecar/__tests__/boundary.test.js +48 -0
  319. package/dist/sidecar/__tests__/boundary.test.js.map +1 -0
  320. package/dist/sidecar/__tests__/collector.test.d.ts +2 -0
  321. package/dist/sidecar/__tests__/collector.test.d.ts.map +1 -0
  322. package/dist/sidecar/__tests__/collector.test.js +162 -0
  323. package/dist/sidecar/__tests__/collector.test.js.map +1 -0
  324. package/dist/sidecar/__tests__/render.test.d.ts +2 -0
  325. package/dist/sidecar/__tests__/render.test.d.ts.map +1 -0
  326. package/dist/sidecar/__tests__/render.test.js +67 -0
  327. package/dist/sidecar/__tests__/render.test.js.map +1 -0
  328. package/dist/sidecar/__tests__/tmux.test.d.ts +2 -0
  329. package/dist/sidecar/__tests__/tmux.test.d.ts.map +1 -0
  330. package/dist/sidecar/__tests__/tmux.test.js +30 -0
  331. package/dist/sidecar/__tests__/tmux.test.js.map +1 -0
  332. package/dist/sidecar/__tests__/watch.test.d.ts +2 -0
  333. package/dist/sidecar/__tests__/watch.test.d.ts.map +1 -0
  334. package/dist/sidecar/__tests__/watch.test.js +42 -0
  335. package/dist/sidecar/__tests__/watch.test.js.map +1 -0
  336. package/dist/sidecar/collector.d.ts +4 -0
  337. package/dist/sidecar/collector.d.ts.map +1 -0
  338. package/dist/sidecar/collector.js +377 -0
  339. package/dist/sidecar/collector.js.map +1 -0
  340. package/dist/sidecar/index.d.ts +25 -0
  341. package/dist/sidecar/index.d.ts.map +1 -0
  342. package/dist/sidecar/index.js +165 -0
  343. package/dist/sidecar/index.js.map +1 -0
  344. package/dist/sidecar/render.d.ts +3 -0
  345. package/dist/sidecar/render.d.ts.map +1 -0
  346. package/dist/sidecar/render.js +72 -0
  347. package/dist/sidecar/render.js.map +1 -0
  348. package/dist/sidecar/tmux.d.ts +13 -0
  349. package/dist/sidecar/tmux.d.ts.map +1 -0
  350. package/dist/sidecar/tmux.js +44 -0
  351. package/dist/sidecar/tmux.js.map +1 -0
  352. package/dist/sidecar/types.d.ts +125 -0
  353. package/dist/sidecar/types.d.ts.map +1 -0
  354. package/dist/sidecar/types.js +2 -0
  355. package/dist/sidecar/types.js.map +1 -0
  356. package/dist/state/__tests__/operations.test.js +50 -22
  357. package/dist/state/__tests__/operations.test.js.map +1 -1
  358. package/dist/state/__tests__/workflow-transition.test.js +9 -1
  359. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  360. package/dist/state/operations.d.ts +1 -1
  361. package/dist/state/operations.d.ts.map +1 -1
  362. package/dist/state/operations.js +19 -7
  363. package/dist/state/operations.js.map +1 -1
  364. package/dist/state/workflow-transition.d.ts.map +1 -1
  365. package/dist/state/workflow-transition.js +1 -0
  366. package/dist/state/workflow-transition.js.map +1 -1
  367. package/dist/team/__tests__/commit-hygiene.test.d.ts +2 -0
  368. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +1 -0
  369. package/dist/team/__tests__/commit-hygiene.test.js +93 -0
  370. package/dist/team/__tests__/commit-hygiene.test.js.map +1 -0
  371. package/dist/team/__tests__/delegation-policy.test.d.ts +2 -0
  372. package/dist/team/__tests__/delegation-policy.test.d.ts.map +1 -0
  373. package/dist/team/__tests__/delegation-policy.test.js +69 -0
  374. package/dist/team/__tests__/delegation-policy.test.js.map +1 -0
  375. package/dist/team/__tests__/events.test.js +54 -4
  376. package/dist/team/__tests__/events.test.js.map +1 -1
  377. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +2 -0
  378. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +1 -0
  379. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +78 -0
  380. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +1 -0
  381. package/dist/team/__tests__/model-contract.test.js +16 -0
  382. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  383. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +2 -0
  384. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +1 -0
  385. package/dist/team/__tests__/repo-aware-decomposition.test.js +95 -0
  386. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -0
  387. package/dist/team/__tests__/runtime.test.js +623 -14
  388. package/dist/team/__tests__/runtime.test.js.map +1 -1
  389. package/dist/team/__tests__/state-root.test.js +177 -1
  390. package/dist/team/__tests__/state-root.test.js.map +1 -1
  391. package/dist/team/__tests__/state.test.js +110 -0
  392. package/dist/team/__tests__/state.test.js.map +1 -1
  393. package/dist/team/__tests__/tmux-session.test.js +399 -2
  394. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  395. package/dist/team/__tests__/worker-bootstrap.test.js +94 -0
  396. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  397. package/dist/team/commit-hygiene.d.ts +22 -3
  398. package/dist/team/commit-hygiene.d.ts.map +1 -1
  399. package/dist/team/commit-hygiene.js +134 -2
  400. package/dist/team/commit-hygiene.js.map +1 -1
  401. package/dist/team/contracts.d.ts +1 -1
  402. package/dist/team/contracts.d.ts.map +1 -1
  403. package/dist/team/contracts.js +2 -0
  404. package/dist/team/contracts.js.map +1 -1
  405. package/dist/team/dag-schema.d.ts +38 -0
  406. package/dist/team/dag-schema.d.ts.map +1 -0
  407. package/dist/team/dag-schema.js +221 -0
  408. package/dist/team/dag-schema.js.map +1 -0
  409. package/dist/team/delegation-policy.d.ts +3 -0
  410. package/dist/team/delegation-policy.d.ts.map +1 -0
  411. package/dist/team/delegation-policy.js +82 -0
  412. package/dist/team/delegation-policy.js.map +1 -0
  413. package/dist/team/model-contract.d.ts +3 -1
  414. package/dist/team/model-contract.d.ts.map +1 -1
  415. package/dist/team/model-contract.js +44 -5
  416. package/dist/team/model-contract.js.map +1 -1
  417. package/dist/team/repo-aware-decomposition.d.ts +60 -0
  418. package/dist/team/repo-aware-decomposition.d.ts.map +1 -0
  419. package/dist/team/repo-aware-decomposition.js +229 -0
  420. package/dist/team/repo-aware-decomposition.js.map +1 -0
  421. package/dist/team/runtime.d.ts +27 -0
  422. package/dist/team/runtime.d.ts.map +1 -1
  423. package/dist/team/runtime.js +172 -52
  424. package/dist/team/runtime.js.map +1 -1
  425. package/dist/team/state/tasks.d.ts.map +1 -1
  426. package/dist/team/state/tasks.js +33 -0
  427. package/dist/team/state/tasks.js.map +1 -1
  428. package/dist/team/state/types.d.ts +23 -1
  429. package/dist/team/state/types.d.ts.map +1 -1
  430. package/dist/team/state/types.js.map +1 -1
  431. package/dist/team/state-root.d.ts +35 -0
  432. package/dist/team/state-root.d.ts.map +1 -1
  433. package/dist/team/state-root.js +281 -1
  434. package/dist/team/state-root.js.map +1 -1
  435. package/dist/team/state.d.ts +27 -1
  436. package/dist/team/state.d.ts.map +1 -1
  437. package/dist/team/state.js +6 -0
  438. package/dist/team/state.js.map +1 -1
  439. package/dist/team/tmux-session.d.ts +1 -0
  440. package/dist/team/tmux-session.d.ts.map +1 -1
  441. package/dist/team/tmux-session.js +105 -6
  442. package/dist/team/tmux-session.js.map +1 -1
  443. package/dist/team/worker-bootstrap.d.ts +3 -0
  444. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  445. package/dist/team/worker-bootstrap.js +77 -4
  446. package/dist/team/worker-bootstrap.js.map +1 -1
  447. package/dist/utils/agents-md.d.ts +3 -0
  448. package/dist/utils/agents-md.d.ts.map +1 -1
  449. package/dist/utils/agents-md.js +25 -0
  450. package/dist/utils/agents-md.js.map +1 -1
  451. package/package.json +3 -2
  452. package/plugins/oh-my-codex/.codex-plugin/plugin.json +2 -2
  453. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
  454. package/plugins/oh-my-codex/skills/analyze/SKILL.md +1 -1
  455. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +134 -205
  456. package/plugins/oh-my-codex/skills/code-review/SKILL.md +4 -4
  457. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +14 -7
  458. package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
  459. package/plugins/oh-my-codex/skills/help/SKILL.md +1 -1
  460. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +41 -10
  461. package/plugins/oh-my-codex/skills/plan/SKILL.md +12 -14
  462. package/plugins/oh-my-codex/skills/ralph/SKILL.md +2 -4
  463. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -9
  464. package/plugins/oh-my-codex/skills/security-review/SKILL.md +4 -4
  465. package/plugins/oh-my-codex/skills/team/SKILL.md +2 -5
  466. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +2 -5
  467. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -3
  468. package/prompts/analyst.md +2 -2
  469. package/prompts/api-reviewer.md +2 -2
  470. package/prompts/architect.md +2 -2
  471. package/prompts/build-fixer.md +2 -2
  472. package/prompts/code-reviewer.md +15 -5
  473. package/prompts/code-simplifier.md +1 -1
  474. package/prompts/critic.md +35 -83
  475. package/prompts/debugger.md +2 -2
  476. package/prompts/dependency-expert.md +2 -2
  477. package/prompts/designer.md +2 -2
  478. package/prompts/executor.md +40 -114
  479. package/prompts/explore-harness.md +1 -1
  480. package/prompts/explore.md +37 -90
  481. package/prompts/git-master.md +2 -2
  482. package/prompts/information-architect.md +1 -1
  483. package/prompts/performance-reviewer.md +2 -2
  484. package/prompts/planner.md +35 -62
  485. package/prompts/product-analyst.md +2 -2
  486. package/prompts/product-manager.md +2 -2
  487. package/prompts/qa-tester.md +2 -2
  488. package/prompts/quality-reviewer.md +2 -2
  489. package/prompts/quality-strategist.md +2 -2
  490. package/prompts/researcher.md +46 -78
  491. package/prompts/security-reviewer.md +2 -2
  492. package/prompts/sisyphus-lite.md +2 -2
  493. package/prompts/style-reviewer.md +2 -2
  494. package/prompts/team-executor.md +1 -1
  495. package/prompts/test-engineer.md +2 -2
  496. package/prompts/ux-researcher.md +2 -2
  497. package/prompts/verifier.md +29 -34
  498. package/prompts/vision.md +2 -2
  499. package/prompts/writer.md +2 -2
  500. package/skills/ai-slop-cleaner/SKILL.md +1 -1
  501. package/skills/analyze/SKILL.md +1 -1
  502. package/skills/autopilot/SKILL.md +134 -205
  503. package/skills/build-fix/SKILL.md +4 -4
  504. package/skills/code-review/SKILL.md +4 -4
  505. package/skills/deep-interview/SKILL.md +14 -7
  506. package/skills/doctor/SKILL.md +1 -1
  507. package/skills/help/SKILL.md +1 -1
  508. package/skills/omx-setup/SKILL.md +41 -10
  509. package/skills/plan/SKILL.md +12 -14
  510. package/skills/ralph/SKILL.md +2 -4
  511. package/skills/ralplan/SKILL.md +5 -9
  512. package/skills/security-review/SKILL.md +4 -4
  513. package/skills/team/SKILL.md +2 -5
  514. package/skills/ultraqa/SKILL.md +2 -5
  515. package/skills/ultrawork/SKILL.md +2 -3
  516. package/src/scripts/__tests__/codex-native-hook.test.ts +502 -94
  517. package/src/scripts/__tests__/generate-release-body.test.ts +41 -0
  518. package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
  519. package/src/scripts/codex-native-hook.ts +293 -61
  520. package/src/scripts/codex-native-pre-post.ts +10 -8
  521. package/src/scripts/generate-release-body.ts +13 -2
  522. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
  523. package/src/scripts/notify-hook/managed-tmux.ts +196 -9
  524. package/src/scripts/notify-hook/process-runner.ts +7 -3
  525. package/src/scripts/notify-hook/team-dispatch.ts +103 -11
  526. package/src/scripts/notify-hook/team-tmux-guard.ts +3 -3
  527. package/src/scripts/notify-hook/team-worker-posttooluse.ts +536 -0
  528. package/src/scripts/notify-hook/team-worker.ts +4 -48
  529. package/src/scripts/notify-hook/tmux-injection.ts +24 -6
  530. package/src/scripts/notify-hook.ts +36 -5
  531. package/src/scripts/prompt-inventory.ts +218 -0
  532. package/src/scripts/run-test-files.ts +1 -0
  533. package/templates/AGENTS.md +34 -95
@@ -6,8 +6,8 @@ import { join } from 'path';
6
6
  import { tmpdir } from 'os';
7
7
  import { existsSync } from 'fs';
8
8
  import { HUD_TMUX_TEAM_HEIGHT_LINES } from '../../hud/constants.js';
9
- import { initTeamState, createTask, readTeamConfig, saveTeamConfig, listMailboxMessages, listDispatchRequests, transitionDispatchRequest, updateWorkerHeartbeat, writeAtomic, readTask, readMonitorSnapshot, claimTask, transitionTaskStatus, readWorkerStatus, writeWorkerStatus, } from '../state.js';
10
- import { monitorTeam, shutdownTeam, resumeTeam, startTeam, assignTask, sendWorkerMessage, applyCreatedInteractiveSessionToConfig, resolveWorkerLaunchArgsFromEnv, shouldPrekillInteractiveShutdownProcessTrees, waitForWorkerStartupEvidence, waitForClaudeStartupEvidence, cleanupTeamWorkerLaunchOrphanedMcpProcesses, } from '../runtime.js';
9
+ import { initTeamState, createTask, writeWorkerInbox, readTeamConfig, saveTeamConfig, listMailboxMessages, listDispatchRequests, transitionDispatchRequest, updateWorkerHeartbeat, writeAtomic, readTask, readMonitorSnapshot, claimTask, transitionTaskStatus, readWorkerStatus, writeWorkerStatus, } from '../state.js';
10
+ import { monitorTeam, shutdownTeam, resumeTeam, startTeam, assignTask, sendWorkerMessage, applyCreatedInteractiveSessionToConfig, resolveWorkerLaunchArgsFromEnv, shouldPrekillInteractiveShutdownProcessTrees, waitForWorkerStartupEvidence, waitForClaudeStartupEvidence, cleanupTeamWorkerLaunchOrphanedMcpProcesses, settleStartupAttemptResults, } from '../runtime.js';
11
11
  import { resolveAgentReasoningEffort, resolveTeamLowComplexityDefaultModel } from '../model-contract.js';
12
12
  import { readTeamEvents } from '../state/events.js';
13
13
  import { sanitizeTeamName } from '../tmux-session.js';
@@ -56,6 +56,31 @@ async function readTeamDeliveryLog(cwd) {
56
56
  .filter(Boolean)
57
57
  .map((line) => JSON.parse(line));
58
58
  }
59
+ async function markPendingInboxDispatchesDelivered(teamName, cwd, opts = {}) {
60
+ const requests = await listDispatchRequests(teamName, cwd, { kind: 'inbox' }).catch(() => []);
61
+ for (const request of requests) {
62
+ if (request.status !== 'pending')
63
+ continue;
64
+ if (opts.toWorker && request.to_worker !== opts.toWorker)
65
+ continue;
66
+ await opts.beforeDeliver?.();
67
+ const notified = await transitionDispatchRequest(teamName, request.request_id, 'pending', 'notified', { last_reason: opts.lastReason ?? 'test_delivered_receipt' }, cwd).catch(() => null);
68
+ if (!notified)
69
+ continue;
70
+ await transitionDispatchRequest(teamName, request.request_id, 'notified', 'delivered', { last_reason: opts.lastReason ?? 'test_delivered_receipt' }, cwd).catch(() => { });
71
+ await opts.afterDeliver?.();
72
+ }
73
+ }
74
+ async function markPendingInboxDispatchesNotified(teamName, cwd, opts = {}) {
75
+ const requests = await listDispatchRequests(teamName, cwd, { kind: 'inbox' }).catch(() => []);
76
+ for (const request of requests) {
77
+ if (request.status !== 'pending')
78
+ continue;
79
+ if (opts.toWorker && request.to_worker !== opts.toWorker)
80
+ continue;
81
+ await transitionDispatchRequest(teamName, request.request_id, 'pending', 'notified', { last_reason: opts.lastReason ?? 'test_notified_receipt' }, cwd).catch(() => { });
82
+ }
83
+ }
59
84
  function withEmptyPath(fn) {
60
85
  const prev = process.env.PATH;
61
86
  process.env.PATH = '';
@@ -564,6 +589,161 @@ describe('runtime', () => {
564
589
  await rm(cwd, { recursive: true, force: true });
565
590
  }
566
591
  });
592
+ it('uses a production startup evidence window that can tolerate slow Codex startup', async () => {
593
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-startup-window-'));
594
+ const prevTmux = process.env.TMUX;
595
+ const prevTmuxPane = process.env.TMUX_PANE;
596
+ const prevLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
597
+ const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
598
+ const prevSkipReadyWait = process.env.OMX_TEAM_SKIP_READY_WAIT;
599
+ const prevStartupEvidenceTimeout = process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
600
+ const prevStartupDispatchRetries = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
601
+ const prevStartupDispatchRetryDelay = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRY_DELAY_MS;
602
+ let receiptNotifier = null;
603
+ let progressWriter = null;
604
+ try {
605
+ await withMockTmuxFixture({
606
+ dirPrefix: 'omx-runtime-startup-window-bin-',
607
+ tmuxScript: (tmuxLogPath) => `#!/bin/sh
608
+ set -eu
609
+ printf '%s\\n' "$*" >> "${tmuxLogPath}"
610
+ case "$1" in
611
+ -V)
612
+ echo "tmux 3.4"
613
+ exit 0
614
+ ;;
615
+ display-message)
616
+ case "$*" in
617
+ *"#{window_width}"*)
618
+ echo "120"
619
+ ;;
620
+ *)
621
+ echo "leader:0 %1"
622
+ ;;
623
+ esac
624
+ exit 0
625
+ ;;
626
+ list-panes)
627
+ case "$*" in
628
+ *"-F #{pane_id}"*"#{pane_current_command}"*)
629
+ printf "%%1\\tzsh\\tzsh\\n"
630
+ exit 0
631
+ ;;
632
+ *"#{pane_pid}"*)
633
+ echo "4321"
634
+ exit 0
635
+ ;;
636
+ *"#{pane_dead} #{pane_pid}"*)
637
+ echo "0 4321"
638
+ exit 0
639
+ ;;
640
+ *)
641
+ exit 0
642
+ ;;
643
+ esac
644
+ ;;
645
+ split-window)
646
+ case "$*" in
647
+ *" -h "*)
648
+ echo "%2"
649
+ ;;
650
+ *)
651
+ echo "%3"
652
+ ;;
653
+ esac
654
+ exit 0
655
+ ;;
656
+ capture-pane)
657
+ printf 'OpenAI Codex\\n> '
658
+ exit 0
659
+ ;;
660
+ send-keys|resize-pane|select-layout|set-window-option|select-pane|set-hook|run-shell|kill-pane|kill-session)
661
+ exit 0
662
+ ;;
663
+ *)
664
+ exit 0
665
+ ;;
666
+ esac
667
+ `,
668
+ binaries: [
669
+ {
670
+ name: 'codex',
671
+ content: '#!/bin/sh\nsleep 30\n',
672
+ },
673
+ ],
674
+ }, async () => {
675
+ process.env.TMUX = 'leader-session';
676
+ process.env.TMUX_PANE = '%1';
677
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
678
+ process.env.OMX_TEAM_WORKER_CLI = 'codex';
679
+ process.env.OMX_TEAM_SKIP_READY_WAIT = '1';
680
+ delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
681
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = '1';
682
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRY_DELAY_MS = '50';
683
+ receiptNotifier = setInterval(() => {
684
+ void markPendingInboxDispatchesNotified('team-startup-window', cwd, {
685
+ toWorker: 'worker-1',
686
+ lastReason: 'test_notified_receipt',
687
+ }).catch(() => { });
688
+ }, 20);
689
+ progressWriter = setTimeout(() => {
690
+ void writeWorkerStatus('team-startup-window', 'worker-1', {
691
+ state: 'working',
692
+ current_task_id: '1',
693
+ updated_at: new Date().toISOString(),
694
+ }, cwd).catch(() => { });
695
+ }, 6_000);
696
+ const runtime = await withoutTeamWorkerEnv(() => startTeam('team-startup-window', 'interactive startup should wait for slow Codex evidence', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd));
697
+ assert.equal(runtime.teamName, 'team-startup-window');
698
+ assert.ok(await readTeamConfig('team-startup-window', cwd));
699
+ });
700
+ }
701
+ finally {
702
+ if (receiptNotifier)
703
+ clearInterval(receiptNotifier);
704
+ if (progressWriter)
705
+ clearTimeout(progressWriter);
706
+ if (typeof prevTmux === 'string')
707
+ process.env.TMUX = prevTmux;
708
+ else
709
+ delete process.env.TMUX;
710
+ if (typeof prevTmuxPane === 'string')
711
+ process.env.TMUX_PANE = prevTmuxPane;
712
+ else
713
+ delete process.env.TMUX_PANE;
714
+ if (typeof prevLaunchMode === 'string')
715
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
716
+ else
717
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
718
+ if (typeof prevWorkerCli === 'string')
719
+ process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
720
+ else
721
+ delete process.env.OMX_TEAM_WORKER_CLI;
722
+ if (typeof prevSkipReadyWait === 'string')
723
+ process.env.OMX_TEAM_SKIP_READY_WAIT = prevSkipReadyWait;
724
+ else
725
+ delete process.env.OMX_TEAM_SKIP_READY_WAIT;
726
+ if (typeof prevStartupEvidenceTimeout === 'string') {
727
+ process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = prevStartupEvidenceTimeout;
728
+ }
729
+ else {
730
+ delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
731
+ }
732
+ if (typeof prevStartupDispatchRetries === 'string') {
733
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = prevStartupDispatchRetries;
734
+ }
735
+ else {
736
+ delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
737
+ }
738
+ if (typeof prevStartupDispatchRetryDelay === 'string') {
739
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRY_DELAY_MS = prevStartupDispatchRetryDelay;
740
+ }
741
+ else {
742
+ delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRY_DELAY_MS;
743
+ }
744
+ await rm(cwd, { recursive: true, force: true });
745
+ }
746
+ });
567
747
  it('startTeam rejects interactive startup when tmux fallback never produces worker startup evidence', async () => {
568
748
  const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-startup-no-evidence-'));
569
749
  const prevTmux = process.env.TMUX;
@@ -809,10 +989,6 @@ sleep 5
809
989
  process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
810
990
  else
811
991
  delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
812
- if (typeof prevWorkerCli === 'string')
813
- process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
814
- else
815
- delete process.env.OMX_TEAM_WORKER_CLI;
816
992
  await rm(cwd, { recursive: true, force: true });
817
993
  }
818
994
  });
@@ -828,6 +1004,7 @@ sleep 5
828
1004
  process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
829
1005
  else
830
1006
  delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
1007
+ delete process.env.OMX_TEAM_WORKER_CLI;
831
1008
  await rm(cwd, { recursive: true, force: true });
832
1009
  }
833
1010
  });
@@ -956,7 +1133,7 @@ esac
956
1133
  delete process.env.WSL_DISTRO_NAME;
957
1134
  delete process.env.WSL_INTEROP;
958
1135
  Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
959
- runtime = await withoutTeamWorkerEnv(() => startTeam('team-win32-no-env', 'native windows current-client detection', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd));
1136
+ const runtime = await withoutTeamWorkerEnv(() => startTeam('team-win32-no-env', 'native windows current-client detection', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd));
960
1137
  teamNameForCleanup = runtime.teamName;
961
1138
  assert.equal(runtime.config.tmux_session, 'leader:0');
962
1139
  assert.equal(runtime.config.leader_pane_id, '%1');
@@ -967,7 +1144,6 @@ esac
967
1144
  if (teamNameForCleanup) {
968
1145
  await shutdownTeam(teamNameForCleanup, cwd, { force: true });
969
1146
  }
970
- runtime = null;
971
1147
  });
972
1148
  }
973
1149
  finally {
@@ -1274,11 +1450,11 @@ esac
1274
1450
  await rm(cwd, { recursive: true, force: true });
1275
1451
  }
1276
1452
  });
1277
- it('startTeam saves interactive pane ids before readiness waits in source order', async () => {
1453
+ it('startTeam saves interactive pane ids before concurrent readiness attempts', async () => {
1278
1454
  const source = await readFile(join(process.cwd(), 'src', 'team', 'runtime.ts'), 'utf-8');
1279
1455
  const applyMatch = source.match(/applyCreatedInteractiveSessionToConfig\(\s*config,\s*createdSession,\s*workerPaneIds\s*\);/m);
1280
1456
  const saveMatch = source.match(/await saveTeamConfig\(config, leaderCwd\);/m);
1281
- const readyMatch = source.match(/const ready = waitForWorkerReady\(/m);
1457
+ const readyMatch = source.match(/waitForWorkerReadyAsync\(/m);
1282
1458
  const applyIndex = applyMatch?.index ?? -1;
1283
1459
  const saveIndex = saveMatch?.index ?? -1;
1284
1460
  const readyIndex = readyMatch?.index ?? -1;
@@ -1288,6 +1464,148 @@ esac
1288
1464
  assert.equal(applyIndex < saveIndex, true);
1289
1465
  assert.equal(saveIndex < readyIndex, true);
1290
1466
  });
1467
+ it('startTeam starts worker-2 readiness before delayed worker-1 readiness settles', async () => {
1468
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-parallel-ready-'));
1469
+ const previousTmux = process.env.TMUX;
1470
+ const previousTmuxPane = process.env.TMUX_PANE;
1471
+ const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
1472
+ const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
1473
+ const previousReadyTimeout = process.env.OMX_TEAM_READY_TIMEOUT_MS;
1474
+ const previousStartupEvidenceTimeout = process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
1475
+ const previousStartupDispatchRetries = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
1476
+ let receiptDeliverer = null;
1477
+ let runtimeTeamName = null;
1478
+ try {
1479
+ await withMockTmuxFixture({
1480
+ dirPrefix: 'omx-runtime-parallel-ready-bin-',
1481
+ tmuxScript: () => `#!/bin/sh
1482
+ set -eu
1483
+ order_file="${cwd}/ready-order.log"
1484
+ case "$1" in
1485
+ -V)
1486
+ echo "tmux 3.4"
1487
+ exit 0
1488
+ ;;
1489
+ display-message)
1490
+ case "$*" in
1491
+ *"#{window_width}"*) echo "120" ;;
1492
+ *) echo "leader:0 %1" ;;
1493
+ esac
1494
+ exit 0
1495
+ ;;
1496
+ list-panes)
1497
+ case "$*" in
1498
+ *"pane_current_command"*) printf "%%1\tnode\t'codex'\n" ;;
1499
+ *"#{pane_dead} #{pane_pid}"*) echo "0 4242" ;;
1500
+ *"#{pane_dead}"*) echo "0" ;;
1501
+ *"-t %2"*"#{pane_pid}"*) echo "4242" ;;
1502
+ *"-t %3"*"#{pane_pid}"*) echo "4343" ;;
1503
+ *"#{pane_pid}"*) echo "4141" ;;
1504
+ *) exit 0 ;;
1505
+ esac
1506
+ exit 0
1507
+ ;;
1508
+ capture-pane)
1509
+ case "$*" in
1510
+ *"-t %2"*)
1511
+ printf '%s\n' w1-ready-start >> "$order_file"
1512
+ sleep 0.4
1513
+ printf '%s\n' w1-ready-done >> "$order_file"
1514
+ printf 'OpenAI Codex\nmodel: test\n› \n'
1515
+ ;;
1516
+ *"-t %3"*)
1517
+ printf '%s\n' w2-ready-start >> "$order_file"
1518
+ printf 'OpenAI Codex\nmodel: test\n› \n'
1519
+ ;;
1520
+ *)
1521
+ printf 'OpenAI Codex\nmodel: test\n› \n'
1522
+ ;;
1523
+ esac
1524
+ exit 0
1525
+ ;;
1526
+ split-window)
1527
+ count_file="${cwd}/split-window-count"
1528
+ count=0
1529
+ if [ -f "$count_file" ]; then count=$(cat "$count_file"); fi
1530
+ count=$((count + 1))
1531
+ printf '%s' "$count" > "$count_file"
1532
+ case "$count" in
1533
+ 1) echo "%2" ;;
1534
+ 2) echo "%3" ;;
1535
+ *) echo "%4" ;;
1536
+ esac
1537
+ exit 0
1538
+ ;;
1539
+ set-hook|run-shell|select-layout|set-window-option|select-pane|send-keys|kill-pane|kill-session|resize-pane)
1540
+ exit 0
1541
+ ;;
1542
+ *)
1543
+ exit 0
1544
+ ;;
1545
+ esac
1546
+ `,
1547
+ binaries: [{ name: 'codex', content: '#!/usr/bin/env node\nprocess.stdin.resume();\n' }],
1548
+ }, async () => {
1549
+ delete process.env.TMUX;
1550
+ process.env.TMUX_PANE = '%1';
1551
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
1552
+ process.env.OMX_TEAM_WORKER_CLI = 'codex';
1553
+ process.env.OMX_TEAM_READY_TIMEOUT_MS = '2000';
1554
+ process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = '50';
1555
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = '1';
1556
+ receiptDeliverer = setInterval(() => {
1557
+ void (async () => {
1558
+ await markPendingInboxDispatchesDelivered('team-parallel-ready', cwd);
1559
+ })();
1560
+ }, 20);
1561
+ const runtime = await withoutTeamWorkerEnv(() => startTeam('team-parallel-ready', 'worker-2 readiness should not wait for worker-1 readiness settle', 'executor', 2, [
1562
+ { subject: 'w1', description: 'worker one', owner: 'worker-1' },
1563
+ { subject: 'w2', description: 'worker two', owner: 'worker-2' },
1564
+ ], cwd));
1565
+ runtimeTeamName = runtime.teamName;
1566
+ const order = (await readFile(join(cwd, 'ready-order.log'), 'utf-8')).trim().split('\n');
1567
+ assert.ok(order.includes('w1-ready-start'));
1568
+ assert.ok(order.includes('w2-ready-start'));
1569
+ assert.ok(order.includes('w1-ready-done'));
1570
+ assert.equal(order.indexOf('w2-ready-start') < order.indexOf('w1-ready-done'), true, `expected worker-2 readiness attempt before worker-1 readiness settled, got ${order.join(',')}`);
1571
+ });
1572
+ }
1573
+ finally {
1574
+ if (receiptDeliverer)
1575
+ clearInterval(receiptDeliverer);
1576
+ if (runtimeTeamName)
1577
+ await shutdownTeam(runtimeTeamName, cwd, { force: true }).catch(() => { });
1578
+ if (typeof previousTmux === 'string')
1579
+ process.env.TMUX = previousTmux;
1580
+ else
1581
+ delete process.env.TMUX;
1582
+ if (typeof previousTmuxPane === 'string')
1583
+ process.env.TMUX_PANE = previousTmuxPane;
1584
+ else
1585
+ delete process.env.TMUX_PANE;
1586
+ if (typeof previousLaunchMode === 'string')
1587
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
1588
+ else
1589
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
1590
+ if (typeof previousWorkerCli === 'string')
1591
+ process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
1592
+ else
1593
+ delete process.env.OMX_TEAM_WORKER_CLI;
1594
+ if (typeof previousReadyTimeout === 'string')
1595
+ process.env.OMX_TEAM_READY_TIMEOUT_MS = previousReadyTimeout;
1596
+ else
1597
+ delete process.env.OMX_TEAM_READY_TIMEOUT_MS;
1598
+ if (typeof previousStartupEvidenceTimeout === 'string')
1599
+ process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = previousStartupEvidenceTimeout;
1600
+ else
1601
+ delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
1602
+ if (typeof previousStartupDispatchRetries === 'string')
1603
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = previousStartupDispatchRetries;
1604
+ else
1605
+ delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
1606
+ await rm(cwd, { recursive: true, force: true });
1607
+ }
1608
+ });
1291
1609
  it('startTeam records recoverable startup issues per worker instead of failing launch early when panes stay alive', async () => {
1292
1610
  const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-no-startup-evidence-'));
1293
1611
  const previousTmux = process.env.TMUX;
@@ -1457,6 +1775,164 @@ process.on('SIGTERM', () => process.exit(0));
1457
1775
  await rm(cwd, { recursive: true, force: true });
1458
1776
  }
1459
1777
  });
1778
+ it('startTeam attempts worker-2 before rejecting lowest-index unrecoverable startup failure', async () => {
1779
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-parallel-dead-pane-'));
1780
+ const previousTmux = process.env.TMUX;
1781
+ const previousTmuxPane = process.env.TMUX_PANE;
1782
+ const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
1783
+ const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
1784
+ const previousReadyTimeout = process.env.OMX_TEAM_READY_TIMEOUT_MS;
1785
+ const previousStartupEvidenceTimeout = process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
1786
+ const previousStartupDispatchRetries = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
1787
+ let receiptFailer = null;
1788
+ try {
1789
+ await withMockTmuxFixture({
1790
+ dirPrefix: 'omx-runtime-parallel-dead-pane-bin-',
1791
+ tmuxScript: () => `#!/bin/sh
1792
+ set -eu
1793
+ order_file="${cwd}/dead-pane-order.log"
1794
+ case "$1" in
1795
+ -V)
1796
+ echo "tmux 3.4"
1797
+ exit 0
1798
+ ;;
1799
+ display-message)
1800
+ case "$*" in
1801
+ *"#{window_width}"*) echo "120" ;;
1802
+ *) echo "leader:0 %1" ;;
1803
+ esac
1804
+ exit 0
1805
+ ;;
1806
+ list-panes)
1807
+ case "$*" in
1808
+ *"pane_current_command"*) printf "%%1\tnode\t'codex'\n" ;;
1809
+ *"-t %2"*"#{pane_dead} #{pane_pid}"*) echo "1 4242" ;;
1810
+ *"-t %3"*"#{pane_dead} #{pane_pid}"*) echo "0 4343" ;;
1811
+ *"#{pane_dead} #{pane_pid}"*) echo "0 4141" ;;
1812
+ *"-t %2"*"#{pane_pid}"*) echo "4242" ;;
1813
+ *"-t %3"*"#{pane_pid}"*) echo "4343" ;;
1814
+ *"#{pane_pid}"*) echo "4141" ;;
1815
+ *) exit 0 ;;
1816
+ esac
1817
+ exit 0
1818
+ ;;
1819
+ capture-pane)
1820
+ case "$*" in
1821
+ *"-t %2"*) printf '%s\n' w1-ready-start >> "$order_file" ;;
1822
+ *"-t %3"*) printf '%s\n' w2-ready-start >> "$order_file"; printf 'OpenAI Codex\nmodel: test\n› \n' ;;
1823
+ *) printf 'OpenAI Codex\nmodel: test\n› \n' ;;
1824
+ esac
1825
+ exit 0
1826
+ ;;
1827
+ split-window)
1828
+ count_file="${cwd}/split-window-count"
1829
+ count=0
1830
+ if [ -f "$count_file" ]; then count=$(cat "$count_file"); fi
1831
+ count=$((count + 1))
1832
+ printf '%s' "$count" > "$count_file"
1833
+ case "$count" in
1834
+ 1) echo "%2" ;;
1835
+ 2) echo "%3" ;;
1836
+ *) echo "%4" ;;
1837
+ esac
1838
+ exit 0
1839
+ ;;
1840
+ set-hook|run-shell|select-layout|set-window-option|select-pane|send-keys|kill-pane|kill-session|resize-pane)
1841
+ exit 0
1842
+ ;;
1843
+ *)
1844
+ exit 0
1845
+ ;;
1846
+ esac
1847
+ `,
1848
+ binaries: [{ name: 'codex', content: '#!/usr/bin/env node\nprocess.stdin.resume();\n' }],
1849
+ }, async () => {
1850
+ delete process.env.TMUX;
1851
+ process.env.TMUX_PANE = '%1';
1852
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
1853
+ process.env.OMX_TEAM_WORKER_CLI = 'codex';
1854
+ process.env.OMX_TEAM_READY_TIMEOUT_MS = '300';
1855
+ process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = '50';
1856
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = '1';
1857
+ receiptFailer = setInterval(() => {
1858
+ void (async () => {
1859
+ const requests = await listDispatchRequests('team-parallel-dead-pane', cwd, { kind: 'inbox' }).catch(() => []);
1860
+ for (const request of requests) {
1861
+ if (request.status !== 'pending')
1862
+ continue;
1863
+ await transitionDispatchRequest('team-parallel-dead-pane', request.request_id, 'pending', 'failed', { last_reason: 'test_failed_receipt' }, cwd).catch(() => { });
1864
+ }
1865
+ })();
1866
+ }, 20);
1867
+ await assert.rejects(() => withoutTeamWorkerEnv(() => startTeam('team-parallel-dead-pane', 'worker-2 should be attempted despite worker-1 fatal readiness failure', 'executor', 2, [
1868
+ { subject: 'w1', description: 'worker one', owner: 'worker-1' },
1869
+ { subject: 'w2', description: 'worker two', owner: 'worker-2' },
1870
+ ], cwd)), /Worker worker-1 did not become ready/);
1871
+ const order = (await readFile(join(cwd, 'dead-pane-order.log'), 'utf-8')).trim().split('\n');
1872
+ assert.ok(order.includes('w1-ready-start'));
1873
+ assert.ok(order.includes('w2-ready-start'));
1874
+ });
1875
+ }
1876
+ finally {
1877
+ if (receiptFailer)
1878
+ clearInterval(receiptFailer);
1879
+ if (typeof previousTmux === 'string')
1880
+ process.env.TMUX = previousTmux;
1881
+ else
1882
+ delete process.env.TMUX;
1883
+ if (typeof previousTmuxPane === 'string')
1884
+ process.env.TMUX_PANE = previousTmuxPane;
1885
+ else
1886
+ delete process.env.TMUX_PANE;
1887
+ if (typeof previousLaunchMode === 'string')
1888
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
1889
+ else
1890
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
1891
+ if (typeof previousWorkerCli === 'string')
1892
+ process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
1893
+ else
1894
+ delete process.env.OMX_TEAM_WORKER_CLI;
1895
+ if (typeof previousReadyTimeout === 'string')
1896
+ process.env.OMX_TEAM_READY_TIMEOUT_MS = previousReadyTimeout;
1897
+ else
1898
+ delete process.env.OMX_TEAM_READY_TIMEOUT_MS;
1899
+ if (typeof previousStartupEvidenceTimeout === 'string')
1900
+ process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = previousStartupEvidenceTimeout;
1901
+ else
1902
+ delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
1903
+ if (typeof previousStartupDispatchRetries === 'string')
1904
+ process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = previousStartupDispatchRetries;
1905
+ else
1906
+ delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
1907
+ await rm(cwd, { recursive: true, force: true });
1908
+ }
1909
+ });
1910
+ it('settleStartupAttemptResults waits for sibling startup attempt to settle after worker startup throw', async () => {
1911
+ let worker2Settled = false;
1912
+ const startupAttemptResults = await settleStartupAttemptResults([
1913
+ {
1914
+ workerIndex: 1,
1915
+ workerName: 'worker-1',
1916
+ attempt: Promise.reject(new Error('test_startup_attempt_throw:worker-1')),
1917
+ },
1918
+ {
1919
+ workerIndex: 2,
1920
+ workerName: 'worker-2',
1921
+ attempt: new Promise((resolve) => {
1922
+ setTimeout(() => {
1923
+ worker2Settled = true;
1924
+ resolve({ ok: true, workerIndex: 2, workerName: 'worker-2' });
1925
+ }, 100);
1926
+ }),
1927
+ },
1928
+ ]);
1929
+ assert.equal(worker2Settled, true, 'worker-2 startup attempt should settle before results return');
1930
+ const firstStartupError = startupAttemptResults
1931
+ .filter((result) => !result.ok)
1932
+ .sort((a, b) => a.workerIndex - b.workerIndex)[0];
1933
+ assert.equal(firstStartupError?.workerName, 'worker-1');
1934
+ assert.match(String(firstStartupError?.error), /test_startup_attempt_throw:worker-1/);
1935
+ });
1460
1936
  it('startTeam still fails startup when the worker pane is dead/unrecoverable', async () => {
1461
1937
  const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-dead-startup-pane-'));
1462
1938
  const previousTmux = process.env.TMUX;
@@ -4263,8 +4739,19 @@ esac
4263
4739
  config.workers[0].pid = sleeperPid;
4264
4740
  config.workers[0].pane_id = null;
4265
4741
  await writeFile(configPath, JSON.stringify(config, null, 2));
4742
+ const manifestPath = join(cwd, '.omx', 'state', 'team', 'team-prompt-resume', 'manifest.v2.json');
4743
+ const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
4744
+ manifest.policy.worker_launch_mode = 'prompt';
4745
+ manifest.tmux_session = 'prompt-team-prompt-resume';
4746
+ manifest.leader_pane_id = null;
4747
+ manifest.hud_pane_id = null;
4748
+ manifest.workers[0].pid = sleeperPid;
4749
+ manifest.workers[0].pane_id = null;
4750
+ await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
4266
4751
  const runtime = await resumeTeam('team-prompt-resume', cwd);
4267
4752
  assert.equal(runtime, null);
4753
+ const events = await readTeamEvents('team-prompt-resume', cwd);
4754
+ assert.ok(events.some((event) => event.reason === `prompt_resume_unavailable:missing_handle:worker-1:${sleeperPid}`), 'resumeTeam should persist an explicit missing-handle diagnostic event');
4268
4755
  }
4269
4756
  finally {
4270
4757
  if (sleeperPid > 0) {
@@ -4365,6 +4852,119 @@ esac
4365
4852
  await rm(cwd, { recursive: true, force: true });
4366
4853
  }
4367
4854
  });
4855
+ it('startTeam persists synthesized delegation plans for broad tasks', async () => {
4856
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
4857
+ const binDir = join(cwd, 'bin');
4858
+ const fakeCodexPath = join(binDir, 'codex');
4859
+ await mkdir(binDir, { recursive: true });
4860
+ await writeFakePromptWorkerBinary(fakeCodexPath, `setTimeout(() => {}, 5000);`);
4861
+ let runtime = null;
4862
+ try {
4863
+ runtime = await withPromptModeCodexEnv(binDir, {}, () => withoutTeamWorkerEnv(() => startTeam('team-delegation-persist', 'delegation persistence test', 'executor', 1, [{ subject: 'Investigate runtime assignment', description: 'Search runtime and debug assignTask behavior' }], cwd)));
4864
+ const task = await readTask('team-delegation-persist', '1', cwd);
4865
+ assert.equal(task?.delegation?.mode, 'auto');
4866
+ assert.equal(task?.delegation?.child_model, 'gpt-5.4-mini');
4867
+ assert.equal(task?.delegation?.required_parallel_probe, true);
4868
+ }
4869
+ finally {
4870
+ if (runtime) {
4871
+ await shutdownTeam(runtime.teamName, cwd, { force: true }).catch(() => { });
4872
+ }
4873
+ await rm(cwd, { recursive: true, force: true });
4874
+ }
4875
+ });
4876
+ it('startTeam remaps repo-aware DAG dependencies after concrete task IDs are created', async () => {
4877
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
4878
+ const binDir = join(cwd, 'bin');
4879
+ const fakeCodexPath = join(binDir, 'codex');
4880
+ await mkdir(binDir, { recursive: true });
4881
+ await writeFakePromptWorkerBinary(fakeCodexPath, `setTimeout(() => {}, 5000);`);
4882
+ let runtime = null;
4883
+ try {
4884
+ runtime = await withPromptModeCodexEnv(binDir, {}, () => withoutTeamWorkerEnv(() => startTeam('team-dag-remap', 'repo-aware DAG remap test', 'executor', 2, [
4885
+ {
4886
+ subject: 'Implement runtime',
4887
+ description: 'Change runtime',
4888
+ owner: 'worker-1',
4889
+ role: 'executor',
4890
+ symbolic_id: 'impl',
4891
+ symbolic_depends_on: [],
4892
+ lane: 'implementation',
4893
+ filePaths: ['src/team/runtime.ts'],
4894
+ allocation_reason: 'balances current load',
4895
+ },
4896
+ {
4897
+ subject: 'Verify runtime',
4898
+ description: 'Test runtime',
4899
+ owner: 'worker-2',
4900
+ role: 'test-engineer',
4901
+ symbolic_id: 'verify',
4902
+ symbolic_depends_on: ['impl'],
4903
+ lane: 'verification',
4904
+ allocation_reason: 'keeps blocked work on a lighter lane',
4905
+ },
4906
+ ], cwd, {
4907
+ decompositionMetadata: {
4908
+ decomposition_source: 'dag_sidecar',
4909
+ worker_count_requested: 2,
4910
+ worker_count_effective: 2,
4911
+ worker_count_source: 'plan-suggested',
4912
+ ready_lane_count: 1,
4913
+ useful_lane_count: 2,
4914
+ allocation_reasons: {
4915
+ impl: 'balances current load',
4916
+ verify: 'keeps blocked work on a lighter lane',
4917
+ },
4918
+ node_dependencies: {
4919
+ impl: [],
4920
+ verify: ['impl'],
4921
+ },
4922
+ },
4923
+ })));
4924
+ const first = await readTask('team-dag-remap', '1', cwd);
4925
+ const second = await readTask('team-dag-remap', '2', cwd);
4926
+ assert.deepEqual(first?.depends_on, []);
4927
+ assert.deepEqual(first?.blocked_by, undefined);
4928
+ assert.deepEqual(second?.depends_on, ['1']);
4929
+ assert.deepEqual(second?.blocked_by, ['1']);
4930
+ const report = JSON.parse(await readFile(join(cwd, '.omx', 'state', 'team', 'team-dag-remap', 'decomposition-report.json'), 'utf-8'));
4931
+ assert.deepEqual(report.node_id_to_task_id, { impl: '1', verify: '2' });
4932
+ assert.deepEqual(report.task_hints?.['2']?.depends_on, ['1']);
4933
+ assert.deepEqual(report.task_hints?.['2']?.symbolic_depends_on, ['impl']);
4934
+ const inbox = await readFile(join(cwd, '.omx', 'state', 'team', 'team-dag-remap', 'workers', 'worker-2', 'inbox.md'), 'utf-8');
4935
+ assert.match(inbox, /Blocked by: 1/);
4936
+ assert.doesNotMatch(inbox, /Blocked by: impl/);
4937
+ assert.doesNotMatch(inbox, /Depends on: impl/);
4938
+ }
4939
+ finally {
4940
+ if (runtime) {
4941
+ await shutdownTeam(runtime.teamName, cwd, { force: true }).catch(() => { });
4942
+ }
4943
+ await rm(cwd, { recursive: true, force: true });
4944
+ }
4945
+ });
4946
+ it('assignTask synthesizes delegation before follow-up dispatch rollback', async () => {
4947
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
4948
+ try {
4949
+ await initTeamState('team-assign-delegation', 'assignment delegation test', 'executor', 1, cwd);
4950
+ const config = await readTeamConfig('team-assign-delegation', cwd);
4951
+ assert.ok(config);
4952
+ config.worker_launch_mode = 'prompt';
4953
+ await saveTeamConfig(config, cwd);
4954
+ const task = await createTask('team-assign-delegation', { subject: 'Investigate follow-up assignment', description: 'Search repo and debug follow-up assignment behavior', status: 'pending' }, cwd);
4955
+ await writeWorkerInbox('team-assign-delegation', 'worker-1', 'existing inbox', cwd);
4956
+ await assert.rejects(() => assignTask('team-assign-delegation', 'worker-1', task.id, cwd), /worker_notify_failed/);
4957
+ const reread = await readTask('team-assign-delegation', task.id, cwd);
4958
+ assert.equal(reread?.delegation?.mode, 'auto');
4959
+ assert.equal(reread?.delegation?.child_model, 'gpt-5.4-mini');
4960
+ const inbox = await readFile(join(cwd, '.omx', 'state', 'team', 'team-assign-delegation', 'workers', 'worker-1', 'inbox.md'), 'utf-8');
4961
+ assert.match(inbox, /Assignment Cancelled/);
4962
+ assert.match(inbox, /worker_notify_failed/);
4963
+ }
4964
+ finally {
4965
+ await rm(cwd, { recursive: true, force: true });
4966
+ }
4967
+ });
4368
4968
  it('monitorTeam does not re-notify already-notified mailbox messages (issue #116)', async () => {
4369
4969
  // Regression: deliverPendingMailboxMessages used to re-notify every 15 s via shouldRetry.
4370
4970
  // After the fix it must NOT re-notify messages that already have notified_at set.
@@ -4715,7 +5315,7 @@ esac
4715
5315
  await rm(cwd, { recursive: true, force: true });
4716
5316
  }
4717
5317
  });
4718
- it('sendWorkerMessage transport_direct keeps leader-fixed request pending when leader_pane_id missing', async () => {
5318
+ it('sendWorkerMessage transport_direct fails fast for leader-fixed when leader_pane_id missing', async () => {
4719
5319
  const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-leader-direct-'));
4720
5320
  try {
4721
5321
  await initTeamState('team-leader-direct', 'leader direct transport test', 'executor', 1, cwd);
@@ -4729,14 +5329,23 @@ esac
4729
5329
  const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
4730
5330
  manifest.policy = { ...(manifest.policy || {}), dispatch_mode: 'transport_direct' };
4731
5331
  await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
4732
- await sendWorkerMessage('team-leader-direct', 'worker-1', 'leader-fixed', 'hello leader direct', cwd);
5332
+ await assert.rejects(sendWorkerMessage('team-leader-direct', 'worker-1', 'leader-fixed', 'hello leader direct', cwd), /mailbox_notify_failed:leader_pane_missing_transport_direct_failed/);
4733
5333
  const mailbox = await listMailboxMessages('team-leader-direct', 'leader-fixed', cwd);
4734
5334
  assert.ok(mailbox.length >= 1, `expected at least 1 mailbox message, got ${mailbox.length}`);
4735
5335
  const requests = await listDispatchRequests('team-leader-direct', cwd, { kind: 'mailbox', to_worker: 'leader-fixed' });
4736
5336
  assert.ok(requests.length >= 1, `expected at least 1 leader-fixed dispatch request, got ${requests.length}`);
4737
5337
  const latest = requests[requests.length - 1];
4738
- assert.equal(latest?.status, 'pending');
4739
- assert.equal(latest?.last_reason, 'leader_pane_missing_deferred');
5338
+ assert.equal(latest?.status, 'failed');
5339
+ assert.equal(latest?.last_reason, 'leader_pane_missing_transport_direct_failed');
5340
+ assert.ok(latest?.failed_at, 'missing leader pane should fail fast with failed_at evidence');
5341
+ const deliveryLog = await readTeamDeliveryLog(cwd);
5342
+ const runtimeEntries = deliveryLog.filter((entry) => entry.event === 'dispatch_result'
5343
+ && entry.source === 'team.runtime'
5344
+ && entry.to_worker === 'leader-fixed'
5345
+ && entry.transport === 'mailbox'
5346
+ && entry.result === 'failed'
5347
+ && entry.reason === 'leader_pane_missing_transport_direct_failed');
5348
+ assert.equal(runtimeEntries.length, 1, 'leader direct missing-pane failure should emit exactly one runtime dispatch_result entry');
4740
5349
  }
4741
5350
  finally {
4742
5351
  await rm(cwd, { recursive: true, force: true });