oh-my-codex 0.16.0 → 0.16.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 (357) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +2 -2
  4. package/crates/omx-explore/src/main.rs +434 -28
  5. package/dist/agents/__tests__/native-config.test.js +50 -0
  6. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  7. package/dist/agents/native-config.d.ts.map +1 -1
  8. package/dist/agents/native-config.js +3 -2
  9. package/dist/agents/native-config.js.map +1 -1
  10. package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -0
  11. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  12. package/dist/cli/__tests__/doctor-warning-copy.test.js +1 -1
  13. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  14. package/dist/cli/__tests__/explore.test.js +120 -3
  15. package/dist/cli/__tests__/explore.test.js.map +1 -1
  16. package/dist/cli/__tests__/imagegen-continuation.test.d.ts +2 -0
  17. package/dist/cli/__tests__/imagegen-continuation.test.d.ts.map +1 -0
  18. package/dist/cli/__tests__/imagegen-continuation.test.js +135 -0
  19. package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -0
  20. package/dist/cli/__tests__/index.test.js +182 -18
  21. package/dist/cli/__tests__/index.test.js.map +1 -1
  22. package/dist/cli/__tests__/launch-fallback.test.js +88 -2
  23. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  24. package/dist/cli/__tests__/ralph.test.js +62 -0
  25. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  26. package/dist/cli/__tests__/setup-install-mode.test.js +48 -0
  27. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  28. package/dist/cli/__tests__/setup-scope.test.js +12 -0
  29. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  30. package/dist/cli/__tests__/team.test.js +465 -12
  31. package/dist/cli/__tests__/team.test.js.map +1 -1
  32. package/dist/cli/__tests__/ultragoal.test.js +50 -5
  33. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  34. package/dist/cli/__tests__/uninstall.test.js +6 -2
  35. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  36. package/dist/cli/explore.d.ts.map +1 -1
  37. package/dist/cli/explore.js +211 -12
  38. package/dist/cli/explore.js.map +1 -1
  39. package/dist/cli/index.d.ts +11 -3
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +124 -18
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/cli/ralph.d.ts.map +1 -1
  44. package/dist/cli/ralph.js +37 -3
  45. package/dist/cli/ralph.js.map +1 -1
  46. package/dist/cli/setup.d.ts.map +1 -1
  47. package/dist/cli/setup.js +100 -9
  48. package/dist/cli/setup.js.map +1 -1
  49. package/dist/cli/team.d.ts +1 -0
  50. package/dist/cli/team.d.ts.map +1 -1
  51. package/dist/cli/team.js +42 -7
  52. package/dist/cli/team.js.map +1 -1
  53. package/dist/cli/ultragoal.d.ts +1 -1
  54. package/dist/cli/ultragoal.d.ts.map +1 -1
  55. package/dist/cli/ultragoal.js +29 -8
  56. package/dist/cli/ultragoal.js.map +1 -1
  57. package/dist/cli/uninstall.d.ts.map +1 -1
  58. package/dist/cli/uninstall.js +2 -1
  59. package/dist/cli/uninstall.js.map +1 -1
  60. package/dist/config/__tests__/codex-hooks.test.js +97 -2
  61. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  62. package/dist/config/__tests__/generator-idempotent.test.js +1 -1
  63. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  64. package/dist/config/__tests__/generator-notify.test.js +22 -0
  65. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  66. package/dist/config/__tests__/models.test.js +18 -1
  67. package/dist/config/__tests__/models.test.js.map +1 -1
  68. package/dist/config/__tests__/wiki-config-contract.test.js +2 -1
  69. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  70. package/dist/config/codex-hooks.d.ts +17 -3
  71. package/dist/config/codex-hooks.d.ts.map +1 -1
  72. package/dist/config/codex-hooks.js +102 -2
  73. package/dist/config/codex-hooks.js.map +1 -1
  74. package/dist/config/generator.d.ts +4 -1
  75. package/dist/config/generator.d.ts.map +1 -1
  76. package/dist/config/generator.js +69 -12
  77. package/dist/config/generator.js.map +1 -1
  78. package/dist/config/models.d.ts +6 -0
  79. package/dist/config/models.d.ts.map +1 -1
  80. package/dist/config/models.js +37 -0
  81. package/dist/config/models.js.map +1 -1
  82. package/dist/exec/followup.d.ts +1 -0
  83. package/dist/exec/followup.d.ts.map +1 -1
  84. package/dist/exec/followup.js +9 -3
  85. package/dist/exec/followup.js.map +1 -1
  86. package/dist/hooks/__tests__/anti-slop-workflow.test.js +19 -0
  87. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  88. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +19 -2
  89. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  90. package/dist/hooks/__tests__/deep-interview-contract.test.js +40 -0
  91. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  92. package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts +2 -0
  93. package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts.map +1 -0
  94. package/dist/hooks/__tests__/foreground-isolation-contract.test.js +28 -0
  95. package/dist/hooks/__tests__/foreground-isolation-contract.test.js.map +1 -0
  96. package/dist/hooks/__tests__/keyword-detector.test.js +37 -25
  97. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  98. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -4
  99. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  100. package/dist/hooks/__tests__/session.test.js +32 -0
  101. package/dist/hooks/__tests__/session.test.js.map +1 -1
  102. package/dist/hooks/__tests__/wiki-docs-contract.test.js +6 -4
  103. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -1
  104. package/dist/hooks/codebase-map.d.ts.map +1 -1
  105. package/dist/hooks/codebase-map.js +3 -2
  106. package/dist/hooks/codebase-map.js.map +1 -1
  107. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  108. package/dist/hooks/extensibility/dispatcher.js +6 -4
  109. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  110. package/dist/hooks/extensibility/logging.d.ts.map +1 -1
  111. package/dist/hooks/extensibility/logging.js +3 -2
  112. package/dist/hooks/extensibility/logging.js.map +1 -1
  113. package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
  114. package/dist/hooks/extensibility/sdk/paths.js +4 -3
  115. package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
  116. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  117. package/dist/hooks/keyword-detector.js +2 -4
  118. package/dist/hooks/keyword-detector.js.map +1 -1
  119. package/dist/hooks/session.d.ts.map +1 -1
  120. package/dist/hooks/session.js +22 -12
  121. package/dist/hooks/session.js.map +1 -1
  122. package/dist/hud/__tests__/hud-tmux-injection.test.js +8 -7
  123. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  124. package/dist/hud/__tests__/reconcile.test.js +1 -1
  125. package/dist/hud/__tests__/state.test.js +24 -0
  126. package/dist/hud/__tests__/state.test.js.map +1 -1
  127. package/dist/hud/index.js +1 -1
  128. package/dist/hud/index.js.map +1 -1
  129. package/dist/hud/state.d.ts.map +1 -1
  130. package/dist/hud/state.js +22 -8
  131. package/dist/hud/state.js.map +1 -1
  132. package/dist/hud/tmux.js +1 -1
  133. package/dist/hud/tmux.js.map +1 -1
  134. package/dist/imagegen/continuation.d.ts +44 -0
  135. package/dist/imagegen/continuation.d.ts.map +1 -0
  136. package/dist/imagegen/continuation.js +220 -0
  137. package/dist/imagegen/continuation.js.map +1 -0
  138. package/dist/mcp/__tests__/bootstrap.test.js +47 -2
  139. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  140. package/dist/mcp/__tests__/server-lifecycle.test.js +49 -1
  141. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  142. package/dist/mcp/__tests__/state-server.test.js +145 -6
  143. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  144. package/dist/mcp/__tests__/wiki-server.test.js +97 -1
  145. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  146. package/dist/mcp/bootstrap.d.ts +2 -0
  147. package/dist/mcp/bootstrap.d.ts.map +1 -1
  148. package/dist/mcp/bootstrap.js +95 -15
  149. package/dist/mcp/bootstrap.js.map +1 -1
  150. package/dist/mcp/lifecycle-telemetry.d.ts +16 -0
  151. package/dist/mcp/lifecycle-telemetry.d.ts.map +1 -0
  152. package/dist/mcp/lifecycle-telemetry.js +95 -0
  153. package/dist/mcp/lifecycle-telemetry.js.map +1 -0
  154. package/dist/mcp/wiki-server.d.ts.map +1 -1
  155. package/dist/mcp/wiki-server.js +11 -2
  156. package/dist/mcp/wiki-server.js.map +1 -1
  157. package/dist/pipeline/__tests__/stages.test.js +274 -5
  158. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  159. package/dist/pipeline/stages/team-exec.d.ts +2 -0
  160. package/dist/pipeline/stages/team-exec.d.ts.map +1 -1
  161. package/dist/pipeline/stages/team-exec.js +51 -26
  162. package/dist/pipeline/stages/team-exec.js.map +1 -1
  163. package/dist/planning/__tests__/artifacts.test.js +138 -3
  164. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  165. package/dist/planning/__tests__/context-pack-status.test.d.ts +2 -0
  166. package/dist/planning/__tests__/context-pack-status.test.d.ts.map +1 -0
  167. package/dist/planning/__tests__/context-pack-status.test.js +271 -0
  168. package/dist/planning/__tests__/context-pack-status.test.js.map +1 -0
  169. package/dist/planning/artifacts.d.ts +12 -1
  170. package/dist/planning/artifacts.d.ts.map +1 -1
  171. package/dist/planning/artifacts.js +32 -9
  172. package/dist/planning/artifacts.js.map +1 -1
  173. package/dist/planning/context-pack-status.d.ts +42 -0
  174. package/dist/planning/context-pack-status.d.ts.map +1 -0
  175. package/dist/planning/context-pack-status.js +479 -0
  176. package/dist/planning/context-pack-status.js.map +1 -0
  177. package/dist/runtime/__tests__/process-tree.test.d.ts +2 -0
  178. package/dist/runtime/__tests__/process-tree.test.d.ts.map +1 -0
  179. package/dist/runtime/__tests__/process-tree.test.js +107 -0
  180. package/dist/runtime/__tests__/process-tree.test.js.map +1 -0
  181. package/dist/runtime/process-tree.d.ts +28 -0
  182. package/dist/runtime/process-tree.d.ts.map +1 -0
  183. package/dist/runtime/process-tree.js +230 -0
  184. package/dist/runtime/process-tree.js.map +1 -0
  185. package/dist/scripts/__tests__/codex-native-hook.test.js +267 -2
  186. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  187. package/dist/scripts/__tests__/notify-state-io.test.d.ts +2 -0
  188. package/dist/scripts/__tests__/notify-state-io.test.d.ts.map +1 -0
  189. package/dist/scripts/__tests__/notify-state-io.test.js +40 -0
  190. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -0
  191. package/dist/scripts/codex-execution-surface.d.ts +1 -1
  192. package/dist/scripts/codex-execution-surface.d.ts.map +1 -1
  193. package/dist/scripts/codex-execution-surface.js.map +1 -1
  194. package/dist/scripts/codex-native-hook.d.ts +1 -1
  195. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  196. package/dist/scripts/codex-native-hook.js +141 -9
  197. package/dist/scripts/codex-native-hook.js.map +1 -1
  198. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  199. package/dist/scripts/notify-hook/managed-tmux.js +6 -9
  200. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  201. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
  202. package/dist/scripts/notify-hook/process-runner.js +4 -1
  203. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  204. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  205. package/dist/scripts/notify-hook/state-io.js +4 -7
  206. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  207. package/dist/scripts/notify-hook.js +25 -3
  208. package/dist/scripts/notify-hook.js.map +1 -1
  209. package/dist/scripts/verify-native-agents.d.ts.map +1 -1
  210. package/dist/scripts/verify-native-agents.js +3 -1
  211. package/dist/scripts/verify-native-agents.js.map +1 -1
  212. package/dist/sidecar/__tests__/tmux.test.js +1 -1
  213. package/dist/sidecar/__tests__/tmux.test.js.map +1 -1
  214. package/dist/sidecar/tmux.js +1 -1
  215. package/dist/sidecar/tmux.js.map +1 -1
  216. package/dist/state/__tests__/operations.test.js +79 -0
  217. package/dist/state/__tests__/operations.test.js.map +1 -1
  218. package/dist/state/__tests__/skill-active.test.js +10 -18
  219. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  220. package/dist/state/__tests__/workflow-transition.test.js +45 -1
  221. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  222. package/dist/state/operations.d.ts.map +1 -1
  223. package/dist/state/operations.js +1 -20
  224. package/dist/state/operations.js.map +1 -1
  225. package/dist/state/skill-active.d.ts +1 -0
  226. package/dist/state/skill-active.d.ts.map +1 -1
  227. package/dist/state/skill-active.js +28 -18
  228. package/dist/state/skill-active.js.map +1 -1
  229. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  230. package/dist/state/workflow-transition-reconcile.js +3 -2
  231. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  232. package/dist/state/workflow-transition.js +2 -2
  233. package/dist/state/workflow-transition.js.map +1 -1
  234. package/dist/team/__tests__/approved-execution.test.js +96 -0
  235. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  236. package/dist/team/__tests__/followup-planner.test.js +16 -0
  237. package/dist/team/__tests__/followup-planner.test.js.map +1 -1
  238. package/dist/team/__tests__/model-contract.test.js +16 -0
  239. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  240. package/dist/team/__tests__/repo-aware-decomposition.test.js +20 -0
  241. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -1
  242. package/dist/team/__tests__/runtime-cli.test.js +16 -0
  243. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  244. package/dist/team/__tests__/runtime.test.js +209 -11
  245. package/dist/team/__tests__/runtime.test.js.map +1 -1
  246. package/dist/team/__tests__/scaling.test.js +110 -0
  247. package/dist/team/__tests__/scaling.test.js.map +1 -1
  248. package/dist/team/__tests__/tmux-session.test.js +9 -0
  249. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  250. package/dist/team/__tests__/worker-runtime-identity.test.js +6 -0
  251. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  252. package/dist/team/approved-execution.d.ts +13 -0
  253. package/dist/team/approved-execution.d.ts.map +1 -1
  254. package/dist/team/approved-execution.js +40 -22
  255. package/dist/team/approved-execution.js.map +1 -1
  256. package/dist/team/followup-planner.d.ts +1 -0
  257. package/dist/team/followup-planner.d.ts.map +1 -1
  258. package/dist/team/followup-planner.js +9 -9
  259. package/dist/team/followup-planner.js.map +1 -1
  260. package/dist/team/model-contract.d.ts +1 -1
  261. package/dist/team/model-contract.d.ts.map +1 -1
  262. package/dist/team/model-contract.js +4 -3
  263. package/dist/team/model-contract.js.map +1 -1
  264. package/dist/team/repo-aware-decomposition.d.ts +1 -0
  265. package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
  266. package/dist/team/repo-aware-decomposition.js +5 -1
  267. package/dist/team/repo-aware-decomposition.js.map +1 -1
  268. package/dist/team/runtime-cli.d.ts +4 -0
  269. package/dist/team/runtime-cli.d.ts.map +1 -1
  270. package/dist/team/runtime-cli.js +14 -1
  271. package/dist/team/runtime-cli.js.map +1 -1
  272. package/dist/team/runtime.d.ts +1 -0
  273. package/dist/team/runtime.d.ts.map +1 -1
  274. package/dist/team/runtime.js +46 -16
  275. package/dist/team/runtime.js.map +1 -1
  276. package/dist/team/scaling.d.ts.map +1 -1
  277. package/dist/team/scaling.js +13 -6
  278. package/dist/team/scaling.js.map +1 -1
  279. package/dist/team/tmux-session.d.ts.map +1 -1
  280. package/dist/team/tmux-session.js +7 -0
  281. package/dist/team/tmux-session.js.map +1 -1
  282. package/dist/ultragoal/__tests__/artifacts.test.js +129 -4
  283. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  284. package/dist/ultragoal/__tests__/docs-contract.test.d.ts +2 -0
  285. package/dist/ultragoal/__tests__/docs-contract.test.d.ts.map +1 -0
  286. package/dist/ultragoal/__tests__/docs-contract.test.js +31 -0
  287. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -0
  288. package/dist/ultragoal/artifacts.d.ts +6 -2
  289. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  290. package/dist/ultragoal/artifacts.js +108 -4
  291. package/dist/ultragoal/artifacts.js.map +1 -1
  292. package/dist/utils/paths.d.ts +3 -1
  293. package/dist/utils/paths.d.ts.map +1 -1
  294. package/dist/utils/paths.js +6 -2
  295. package/dist/utils/paths.js.map +1 -1
  296. package/dist/verification/__tests__/ci-rust-gates.test.js +44 -14
  297. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  298. package/dist/wiki/__tests__/ingest.test.js +35 -1
  299. package/dist/wiki/__tests__/ingest.test.js.map +1 -1
  300. package/dist/wiki/__tests__/lint.test.js +14 -1
  301. package/dist/wiki/__tests__/lint.test.js.map +1 -1
  302. package/dist/wiki/__tests__/query.test.js +28 -3
  303. package/dist/wiki/__tests__/query.test.js.map +1 -1
  304. package/dist/wiki/__tests__/session-hooks.test.js +30 -2
  305. package/dist/wiki/__tests__/session-hooks.test.js.map +1 -1
  306. package/dist/wiki/__tests__/storage.test.js +62 -22
  307. package/dist/wiki/__tests__/storage.test.js.map +1 -1
  308. package/dist/wiki/index.d.ts +2 -2
  309. package/dist/wiki/index.d.ts.map +1 -1
  310. package/dist/wiki/index.js +2 -2
  311. package/dist/wiki/index.js.map +1 -1
  312. package/dist/wiki/ingest.js +2 -2
  313. package/dist/wiki/ingest.js.map +1 -1
  314. package/dist/wiki/lifecycle.d.ts +5 -0
  315. package/dist/wiki/lifecycle.d.ts.map +1 -1
  316. package/dist/wiki/lifecycle.js +31 -4
  317. package/dist/wiki/lifecycle.js.map +1 -1
  318. package/dist/wiki/lint.d.ts.map +1 -1
  319. package/dist/wiki/lint.js +12 -8
  320. package/dist/wiki/lint.js.map +1 -1
  321. package/dist/wiki/query.d.ts.map +1 -1
  322. package/dist/wiki/query.js +3 -2
  323. package/dist/wiki/query.js.map +1 -1
  324. package/dist/wiki/storage.d.ts +4 -0
  325. package/dist/wiki/storage.d.ts.map +1 -1
  326. package/dist/wiki/storage.js +54 -18
  327. package/dist/wiki/storage.js.map +1 -1
  328. package/package.json +1 -1
  329. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  330. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +9 -0
  331. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +25 -2
  332. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
  333. package/plugins/oh-my-codex/skills/plan/SKILL.md +7 -4
  334. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +13 -3
  335. package/plugins/oh-my-codex/skills/team/SKILL.md +2 -2
  336. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +11 -7
  337. package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +8 -0
  338. package/plugins/oh-my-codex/skills/wiki/SKILL.md +5 -5
  339. package/prompts/planner.md +1 -1
  340. package/skills/ai-slop-cleaner/SKILL.md +9 -0
  341. package/skills/deep-interview/SKILL.md +25 -2
  342. package/skills/omx-setup/SKILL.md +1 -1
  343. package/skills/plan/SKILL.md +7 -4
  344. package/skills/ralplan/SKILL.md +13 -3
  345. package/skills/team/SKILL.md +2 -2
  346. package/skills/ultragoal/SKILL.md +11 -7
  347. package/skills/visual-ralph/SKILL.md +8 -0
  348. package/skills/wiki/SKILL.md +5 -5
  349. package/src/scripts/__tests__/codex-native-hook.test.ts +302 -2
  350. package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
  351. package/src/scripts/codex-execution-surface.ts +2 -0
  352. package/src/scripts/codex-native-hook.ts +163 -16
  353. package/src/scripts/notify-hook/managed-tmux.ts +6 -7
  354. package/src/scripts/notify-hook/process-runner.ts +4 -1
  355. package/src/scripts/notify-hook/state-io.ts +5 -7
  356. package/src/scripts/notify-hook.ts +26 -3
  357. package/src/scripts/verify-native-agents.ts +3 -1
@@ -1,16 +1,19 @@
1
1
  import { execFileSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
2
3
  import { afterEach, beforeEach, describe, it } from 'node:test';
3
4
  import assert from 'node:assert/strict';
4
5
  import { existsSync } from 'node:fs';
5
6
  import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
6
7
  import { spawn } from 'node:child_process';
7
- import { join } from 'node:path';
8
+ import { join, relative } from 'node:path';
8
9
  import { tmpdir } from 'node:os';
9
10
  import { fileURLToPath } from 'node:url';
10
11
  import { buildLeaderMonitoringHints, parseTeamStartArgs, teamCommand } from '../team.js';
11
12
  import { readModeState } from '../../modes/base.js';
12
13
  import { readApprovedExecutionLaunchHint } from '../../planning/artifacts.js';
14
+ import { buildRepoAwareTeamExecutionPlan } from '../../team/repo-aware-decomposition.js';
13
15
  import { DEFAULT_MAX_WORKERS } from '../../team/state.js';
16
+ import { shutdownTeam } from '../../team/runtime.js';
14
17
  import { sameFilePath } from '../../utils/paths.js';
15
18
  import { appendTeamEvent, createTask, initTeamState, readTeamConfig, saveTeamConfig, updateWorkerHeartbeat, writeMonitorSnapshot, writeTaskApproval, writeWorkerStatus, } from '../../team/state.js';
16
19
  import { buildApprovedTeamExecutionBinding, writePersistedApprovedTeamExecutionBinding, } from '../../team/approved-execution.js';
@@ -23,6 +26,48 @@ function encodeApprovedExecutionTask(task, quote) {
23
26
  ? `'${task.replace(/'/g, "\\'")}'`
24
27
  : `"${task.replace(/"/g, '\\"')}"`;
25
28
  }
29
+ function computeGitBlobSha1(content) {
30
+ const buffer = Buffer.from(content, 'utf-8');
31
+ const header = Buffer.from(`blob ${buffer.length}\0`, 'utf-8');
32
+ return createHash('sha1').update(header).update(buffer).digest('hex');
33
+ }
34
+ function canonicalContextPackRelativePath(slug) {
35
+ return `.omx/context/context-20260507T120000Z-${slug}.json`;
36
+ }
37
+ function buildContextPackOutcome(relativePackPath) {
38
+ return [
39
+ '## Context Pack Outcome',
40
+ '',
41
+ `- pack: created \`${relativePackPath}\``,
42
+ ].join('\n');
43
+ }
44
+ async function writeContextPack(cwd, slug, prdPath, testSpecPath, roles) {
45
+ const contextDir = join(cwd, '.omx', 'context');
46
+ const packPath = join(cwd, canonicalContextPackRelativePath(slug));
47
+ const prdContent = await readFile(prdPath, 'utf-8');
48
+ const testSpecContent = await readFile(testSpecPath, 'utf-8');
49
+ await mkdir(contextDir, { recursive: true });
50
+ await writeFile(packPath, JSON.stringify({
51
+ slug,
52
+ basis: {
53
+ prd: {
54
+ path: relative(cwd, prdPath).replaceAll('\\', '/'),
55
+ sha1: computeGitBlobSha1(prdContent),
56
+ },
57
+ testSpecs: [{
58
+ path: relative(cwd, testSpecPath).replaceAll('\\', '/'),
59
+ sha1: computeGitBlobSha1(testSpecContent),
60
+ }],
61
+ },
62
+ entries: roles.map((role, index) => ({
63
+ path: `src/${role}-${index}.ts`,
64
+ roles: [role],
65
+ })),
66
+ }, null, 2));
67
+ }
68
+ async function writeReadyContextPack(cwd, slug, prdPath, testSpecPath) {
69
+ await writeContextPack(cwd, slug, prdPath, testSpecPath, ['scope', 'build', 'verify']);
70
+ }
26
71
  beforeEach(() => {
27
72
  delete process.env.OMX_TEAM_WORKER;
28
73
  delete process.env.OMX_TEAM_STATE_ROOT;
@@ -226,8 +271,16 @@ describe('parseTeamStartArgs', () => {
226
271
  const plansDir = join(wd, '.omx', 'plans');
227
272
  await mkdir(plansDir, { recursive: true });
228
273
  const boundPrdPath = join(plansDir, 'prd-20260501T010203Z-issue-831.md');
229
- await writeFile(boundPrdPath, '# Approved plan\n\nLaunch via omx team 2:executor "Execute approved issue 831 plan"\n');
230
- await writeFile(join(plansDir, 'test-spec-20260501T010203Z-issue-831.md'), '# Test spec\n');
274
+ const boundTestSpecPath = join(plansDir, 'test-spec-20260501T010203Z-issue-831.md');
275
+ await writeFile(boundPrdPath, [
276
+ '# Approved plan',
277
+ '',
278
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-831')),
279
+ '',
280
+ 'Launch via omx team 2:executor "Execute approved issue 831 plan"',
281
+ ].join('\n'));
282
+ await writeFile(boundTestSpecPath, '# Test spec\n');
283
+ await writeReadyContextPack(wd, 'issue-831', boundPrdPath, boundTestSpecPath);
231
284
  await writeFile(join(plansDir, 'prd-20260502T010203Z-issue-999.md'), '# Approved plan\n\nLaunch via omx team 5:debugger "Execute newer approved issue 999 plan"\n');
232
285
  await writeFile(join(plansDir, 'test-spec-20260502T010203Z-issue-999.md'), '# Test spec\n');
233
286
  await mkdir(join(wd, '.omx', 'state'), { recursive: true });
@@ -260,8 +313,16 @@ describe('parseTeamStartArgs', () => {
260
313
  const boundTask = "Fix Bob's regression in C:\\\\tmp";
261
314
  const boundCommand = `omx team 2:executor ${encodeApprovedExecutionTask(boundTask, 'single')}`;
262
315
  const boundPrdPath = join(plansDir, 'prd-issue-831-quoted.md');
263
- await writeFile(boundPrdPath, `# Approved plan\n\nLaunch via ${boundCommand}\n`);
264
- await writeFile(join(plansDir, 'test-spec-issue-831-quoted.md'), '# Test spec\n');
316
+ const boundTestSpecPath = join(plansDir, 'test-spec-issue-831-quoted.md');
317
+ await writeFile(boundPrdPath, [
318
+ '# Approved plan',
319
+ '',
320
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-831-quoted')),
321
+ '',
322
+ `Launch via ${boundCommand}`,
323
+ ].join('\n'));
324
+ await writeFile(boundTestSpecPath, '# Test spec\n');
325
+ await writeReadyContextPack(wd, 'issue-831-quoted', boundPrdPath, boundTestSpecPath);
265
326
  await mkdir(join(wd, '.omx', 'state'), { recursive: true });
266
327
  await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-team-quoted' }, null, 2));
267
328
  const approvedHint = readApprovedExecutionLaunchHint(wd, 'team');
@@ -291,8 +352,16 @@ describe('parseTeamStartArgs', () => {
291
352
  const boundTask = String.raw `Use C:\tmp and keep \n literal plus "quotes"`;
292
353
  const boundCommand = `omx team 2:executor ${encodeApprovedExecutionTask(boundTask, 'double')}`;
293
354
  const boundPrdPath = join(plansDir, 'prd-issue-831-double-quoted.md');
294
- await writeFile(boundPrdPath, `# Approved plan\n\nLaunch via ${boundCommand}\n`);
295
- await writeFile(join(plansDir, 'test-spec-issue-831-double-quoted.md'), '# Test spec\n');
355
+ const boundTestSpecPath = join(plansDir, 'test-spec-issue-831-double-quoted.md');
356
+ await writeFile(boundPrdPath, [
357
+ '# Approved plan',
358
+ '',
359
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-831-double-quoted')),
360
+ '',
361
+ `Launch via ${boundCommand}`,
362
+ ].join('\n'));
363
+ await writeFile(boundTestSpecPath, '# Test spec\n');
364
+ await writeReadyContextPack(wd, 'issue-831-double-quoted', boundPrdPath, boundTestSpecPath);
296
365
  await mkdir(join(wd, '.omx', 'state'), { recursive: true });
297
366
  await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-team-double-quoted' }, null, 2));
298
367
  const approvedHint = readApprovedExecutionLaunchHint(wd, 'team');
@@ -346,6 +415,99 @@ describe('parseTeamStartArgs', () => {
346
415
  await rm(wd, { recursive: true, force: true });
347
416
  }
348
417
  });
418
+ it('keeps plan-only short follow-ups on the generic path even when a persisted approved binding exists', async () => {
419
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-plan-only-'));
420
+ const previousCwd = process.cwd();
421
+ try {
422
+ process.chdir(wd);
423
+ const plansDir = join(wd, '.omx', 'plans');
424
+ await mkdir(plansDir, { recursive: true });
425
+ const prdPath = join(plansDir, 'prd-issue-2085.md');
426
+ const command = 'omx team 3:executor "Execute approved issue 2085 plan"';
427
+ await writeFile(prdPath, `# Approved plan\n\nLaunch via ${command}\n`);
428
+ await writeFile(join(plansDir, 'test-spec-issue-2085.md'), '# Test spec\n');
429
+ await mkdir(join(wd, '.omx', 'state'), { recursive: true });
430
+ await writeFile(join(wd, '.omx', 'state', 'team-state.json'), JSON.stringify({ active: true, team_name: 'bound-plan-only-team' }, null, 2));
431
+ await writePersistedApprovedTeamExecutionBinding('bound-plan-only-team', wd, {
432
+ prd_path: prdPath,
433
+ task: 'Execute approved issue 2085 plan',
434
+ command,
435
+ });
436
+ const result = parseTeamStartArgs(['team']);
437
+ assert.equal(result.parsed.task, 'Execute approved issue 2085 plan');
438
+ assert.equal(result.parsed.workerCount, 3);
439
+ assert.equal(result.parsed.agentType, 'executor');
440
+ assert.equal(result.parsed.approvedExecution, undefined);
441
+ }
442
+ finally {
443
+ process.chdir(previousCwd);
444
+ await rm(wd, { recursive: true, force: true });
445
+ }
446
+ });
447
+ it('fails short follow-up reuse when the latest approved handoff is nonready', async () => {
448
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-nonready-'));
449
+ const previousCwd = process.cwd();
450
+ try {
451
+ process.chdir(wd);
452
+ const plansDir = join(wd, '.omx', 'plans');
453
+ await mkdir(plansDir, { recursive: true });
454
+ await writeFile(join(plansDir, 'prd-issue-2086.md'), [
455
+ '# Approved plan',
456
+ '',
457
+ '## Context Pack Outcome',
458
+ '',
459
+ '- pack: created `.omx/context/context-20260507T120000Z-other.json`',
460
+ '',
461
+ 'Launch via omx team 3:executor "Execute approved issue 2086 plan"',
462
+ ].join('\n'));
463
+ await writeFile(join(plansDir, 'test-spec-issue-2086.md'), '# Test spec\n');
464
+ assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:invalid/);
465
+ }
466
+ finally {
467
+ process.chdir(previousCwd);
468
+ await rm(wd, { recursive: true, force: true });
469
+ }
470
+ });
471
+ it('fails short follow-up reuse when the latest approved handoff is missing its baseline', async () => {
472
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-missing-baseline-'));
473
+ const previousCwd = process.cwd();
474
+ try {
475
+ process.chdir(wd);
476
+ const plansDir = join(wd, '.omx', 'plans');
477
+ await mkdir(plansDir, { recursive: true });
478
+ await writeFile(join(plansDir, 'prd-issue-2086-missing-baseline.md'), '# Approved plan\n\nLaunch via omx team 3:executor "Execute approved issue 2086 missing-baseline plan"\n');
479
+ assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:missing-baseline/);
480
+ }
481
+ finally {
482
+ process.chdir(previousCwd);
483
+ await rm(wd, { recursive: true, force: true });
484
+ }
485
+ });
486
+ it('fails short follow-up reuse when the latest approved handoff is incomplete', async () => {
487
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-incomplete-'));
488
+ const previousCwd = process.cwd();
489
+ try {
490
+ process.chdir(wd);
491
+ const plansDir = join(wd, '.omx', 'plans');
492
+ await mkdir(plansDir, { recursive: true });
493
+ const prdPath = join(plansDir, 'prd-issue-2086-incomplete.md');
494
+ const testSpecPath = join(plansDir, 'test-spec-issue-2086-incomplete.md');
495
+ await writeFile(prdPath, [
496
+ '# Approved plan',
497
+ '',
498
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-2086-incomplete')),
499
+ '',
500
+ 'Launch via omx team 3:executor "Execute approved issue 2086 incomplete plan"',
501
+ ].join('\n'));
502
+ await writeFile(testSpecPath, '# Test spec\n');
503
+ await writeContextPack(wd, 'issue-2086-incomplete', prdPath, testSpecPath, ['scope']);
504
+ assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_hint_nonready:team:incomplete/);
505
+ }
506
+ finally {
507
+ process.chdir(previousCwd);
508
+ await rm(wd, { recursive: true, force: true });
509
+ }
510
+ });
349
511
  it('fails closed for a short follow-up when the persisted approved binding is malformed', async () => {
350
512
  const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-malformed-binding-'));
351
513
  const previousCwd = process.cwd();
@@ -397,6 +559,40 @@ describe('parseTeamStartArgs', () => {
397
559
  await rm(wd, { recursive: true, force: true });
398
560
  }
399
561
  });
562
+ it('fails closed for a short follow-up when the persisted approved binding is ambiguous', async () => {
563
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-bound-ambiguous-'));
564
+ const previousCwd = process.cwd();
565
+ const approvedTask = 'Execute approved issue 956 plan';
566
+ try {
567
+ process.chdir(wd);
568
+ const plansDir = join(wd, '.omx', 'plans');
569
+ const stateDir = join(wd, '.omx', 'state');
570
+ await mkdir(plansDir, { recursive: true });
571
+ await writeFile(join(plansDir, 'prd-issue-956.md'), [
572
+ '# Approved plan',
573
+ '',
574
+ `Launch via omx team 4:executor "${approvedTask}"`,
575
+ `Launch via omx team 6:debugger "${approvedTask}"`,
576
+ ].join('\n'));
577
+ await writeFile(join(plansDir, 'test-spec-issue-956.md'), '# Test spec\n');
578
+ await mkdir(stateDir, { recursive: true });
579
+ await writeFile(join(stateDir, 'team-state.json'), JSON.stringify({
580
+ active: true,
581
+ team_name: 'bound-team-ambiguous',
582
+ task_description: approvedTask,
583
+ agent_count: 4,
584
+ }, null, 2));
585
+ await writePersistedApprovedTeamExecutionBinding('bound-team-ambiguous', wd, {
586
+ prd_path: join(plansDir, 'prd-issue-956.md'),
587
+ task: approvedTask,
588
+ });
589
+ assert.throws(() => parseTeamStartArgs(['team']), /approved_execution_binding_ambiguous:.*Execute approved issue 956 plan/);
590
+ }
591
+ finally {
592
+ process.chdir(previousCwd);
593
+ await rm(wd, { recursive: true, force: true });
594
+ }
595
+ });
400
596
  it('fails closed for a short team follow-up when the selected PRD lists multiple team launch hints', async () => {
401
597
  const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-ambiguous-'));
402
598
  const previousCwd = process.cwd();
@@ -451,15 +647,25 @@ describe('parseTeamStartArgs', () => {
451
647
  await rm(wd, { recursive: true, force: true });
452
648
  }
453
649
  });
454
- it('attaches approved repository context summary only for matching team launches', async () => {
650
+ it('attaches approved repository context summary only for matching ready team launches', async () => {
455
651
  const wd = await mkdtemp(join(tmpdir(), 'omx-team-context-approved-'));
456
652
  const previousCwd = process.cwd();
457
653
  try {
458
654
  process.chdir(wd);
459
- await mkdir(join(wd, '.omx', 'plans'), { recursive: true });
460
- await writeFile(join(wd, '.omx', 'plans', 'prd-issue-2039.md'), '# Approved plan\n\nLaunch via omx team 3:executor "Execute approved issue 2039 plan"\n');
461
- await writeFile(join(wd, '.omx', 'plans', 'test-spec-issue-2039.md'), '# Test spec\n');
462
- await writeFile(join(wd, '.omx', 'plans', 'repo-context-issue-2039.md'), 'Key boundary: latest approved handoff only.\n');
655
+ const plansDir = join(wd, '.omx', 'plans');
656
+ await mkdir(plansDir, { recursive: true });
657
+ const prdPath = join(plansDir, 'prd-issue-2039.md');
658
+ const testSpecPath = join(plansDir, 'test-spec-issue-2039.md');
659
+ await writeFile(prdPath, [
660
+ '# Approved plan',
661
+ '',
662
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-2039')),
663
+ '',
664
+ 'Launch via omx team 3:executor "Execute approved issue 2039 plan"',
665
+ ].join('\n'));
666
+ await writeFile(testSpecPath, '# Test spec\n');
667
+ await writeReadyContextPack(wd, 'issue-2039', prdPath, testSpecPath);
668
+ await writeFile(join(plansDir, 'repo-context-issue-2039.md'), 'Key boundary: latest approved handoff only.\n');
463
669
  const approved = parseTeamStartArgs(['3:executor', 'Execute', 'approved', 'issue', '2039', 'plan']);
464
670
  assert.equal(approved.parsed.approvedRepositoryContextSummary?.content, 'Key boundary: latest approved handoff only.');
465
671
  const unrelated = parseTeamStartArgs(['3:executor', 'fix', 'unrelated', 'bug']);
@@ -470,6 +676,139 @@ describe('parseTeamStartArgs', () => {
470
676
  await rm(wd, { recursive: true, force: true });
471
677
  }
472
678
  });
679
+ it('keeps ready approved execution generic when staffing no longer matches the approved launch hint', async () => {
680
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-context-ready-mismatch-'));
681
+ const previousCwd = process.cwd();
682
+ try {
683
+ process.chdir(wd);
684
+ const plansDir = join(wd, '.omx', 'plans');
685
+ await mkdir(plansDir, { recursive: true });
686
+ const prdPath = join(plansDir, 'prd-issue-2040.md');
687
+ const testSpecPath = join(plansDir, 'test-spec-issue-2040.md');
688
+ await writeFile(prdPath, [
689
+ '# Approved plan',
690
+ '',
691
+ buildContextPackOutcome(canonicalContextPackRelativePath('issue-2040')),
692
+ '',
693
+ 'Launch via omx team 3:executor "Execute approved issue 2040 plan"',
694
+ ].join('\n'));
695
+ await writeFile(testSpecPath, '# Test spec\n');
696
+ await writeReadyContextPack(wd, 'issue-2040', prdPath, testSpecPath);
697
+ await writeFile(join(plansDir, 'repo-context-issue-2040.md'), 'Keep approved context off generic mismatches.\n');
698
+ const result = parseTeamStartArgs(['2:debugger', 'Execute', 'approved', 'issue', '2040', 'plan']);
699
+ assert.equal(result.parsed.allowRepoAwareDagHandoff, false);
700
+ assert.equal(result.parsed.approvedExecution, undefined);
701
+ assert.equal(result.parsed.approvedRepositoryContextSummary, undefined);
702
+ }
703
+ finally {
704
+ process.chdir(previousCwd);
705
+ await rm(wd, { recursive: true, force: true });
706
+ }
707
+ });
708
+ it('does not carry approved execution for explicit plan-only team launches', async () => {
709
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-explicit-plan-only-'));
710
+ const previousCwd = process.cwd();
711
+ try {
712
+ process.chdir(wd);
713
+ await mkdir(join(wd, '.omx', 'plans'), { recursive: true });
714
+ await writeFile(join(wd, '.omx', 'plans', 'prd-issue-2087.md'), '# Approved plan\n\nLaunch via omx team 3:executor "Execute approved issue 2087 plan"\n');
715
+ await writeFile(join(wd, '.omx', 'plans', 'test-spec-issue-2087.md'), '# Test spec\n');
716
+ await writeFile(join(wd, '.omx', 'plans', 'repo-context-issue-2087.md'), 'Do not widen plan-only context.\n');
717
+ const result = parseTeamStartArgs(['3:executor', 'Execute', 'approved', 'issue', '2087', 'plan']);
718
+ assert.equal(result.parsed.allowRepoAwareDagHandoff, true);
719
+ assert.equal(result.parsed.approvedExecution, undefined);
720
+ assert.equal(result.parsed.approvedRepositoryContextSummary, undefined);
721
+ }
722
+ finally {
723
+ process.chdir(previousCwd);
724
+ await rm(wd, { recursive: true, force: true });
725
+ }
726
+ });
727
+ it('preserves lifecycle-specific DAG fallback reasons for explicit nonready approved launches', async () => {
728
+ const previousCwd = process.cwd();
729
+ const cases = [
730
+ {
731
+ name: 'missing-baseline',
732
+ slug: 'issue-2090-missing-baseline',
733
+ includeOutcome: false,
734
+ writeTestSpec: false,
735
+ packSetup: async (_wd, _prdPath, _testSpecPath) => { },
736
+ expected: 'context_pack_not_followup_ready:missing-baseline',
737
+ },
738
+ {
739
+ name: 'incomplete',
740
+ slug: 'issue-2090-incomplete',
741
+ includeOutcome: true,
742
+ writeTestSpec: true,
743
+ packSetup: async (wd, prdPath, testSpecPath) => {
744
+ await writeContextPack(wd, 'issue-2090-incomplete', prdPath, testSpecPath, ['scope']);
745
+ },
746
+ expected: 'context_pack_not_followup_ready:incomplete',
747
+ },
748
+ {
749
+ name: 'invalid',
750
+ slug: 'issue-2090-invalid',
751
+ includeOutcome: true,
752
+ writeTestSpec: true,
753
+ packSetup: async (_wd, _prdPath, _testSpecPath) => { },
754
+ expected: 'context_pack_not_followup_ready:invalid',
755
+ },
756
+ ];
757
+ try {
758
+ for (const scenario of cases) {
759
+ const wd = await mkdtemp(join(tmpdir(), `omx-team-dag-fallback-${scenario.name}-`));
760
+ try {
761
+ process.chdir(wd);
762
+ const plansDir = join(wd, '.omx', 'plans');
763
+ await mkdir(plansDir, { recursive: true });
764
+ const prdPath = join(plansDir, `prd-${scenario.slug}.md`);
765
+ const testSpecPath = join(plansDir, `test-spec-${scenario.slug}.md`);
766
+ const outcomePath = scenario.name === 'invalid'
767
+ ? canonicalContextPackRelativePath('other')
768
+ : canonicalContextPackRelativePath(scenario.slug);
769
+ const prdSections = ['# Approved plan', ''];
770
+ if (scenario.includeOutcome) {
771
+ prdSections.push(buildContextPackOutcome(outcomePath), '');
772
+ }
773
+ prdSections.push(`Launch via omx team 3:executor "Execute approved ${scenario.name} DAG plan"`);
774
+ await writeFile(prdPath, prdSections.join('\n'));
775
+ if (scenario.writeTestSpec) {
776
+ await writeFile(testSpecPath, '# Test spec\n');
777
+ }
778
+ await writeFile(join(plansDir, `team-dag-${scenario.slug}.json`), '{"schema_version":1,"nodes":[{"id":"impl","subject":"Impl","description":"Impl"}]}\n');
779
+ await scenario.packSetup(wd, prdPath, testSpecPath);
780
+ const parsed = parseTeamStartArgs(['3:executor', 'Execute', 'approved', scenario.name, 'DAG', 'plan']);
781
+ const executionPlan = buildRepoAwareTeamExecutionPlan({
782
+ task: parsed.parsed.task,
783
+ workerCount: parsed.parsed.workerCount,
784
+ agentType: parsed.parsed.agentType,
785
+ explicitAgentType: parsed.parsed.explicitAgentType,
786
+ explicitWorkerCount: parsed.parsed.explicitWorkerCount,
787
+ cwd: wd,
788
+ buildLegacyPlan: (task, workerCount, agentType) => ({
789
+ workerCount,
790
+ tasks: [{ subject: task, description: task, owner: 'worker-1', role: agentType }],
791
+ }),
792
+ allowDagHandoff: parsed.parsed.allowRepoAwareDagHandoff,
793
+ dagFallbackReason: parsed.parsed.dagFallbackReason,
794
+ approvedRepositoryContextSummary: parsed.parsed.approvedRepositoryContextSummary,
795
+ });
796
+ assert.equal(parsed.parsed.allowRepoAwareDagHandoff, false);
797
+ assert.equal(parsed.parsed.dagFallbackReason, scenario.expected);
798
+ assert.equal(parsed.parsed.approvedExecution, undefined);
799
+ assert.equal(executionPlan.metadata?.decomposition_source, 'legacy_text');
800
+ assert.equal(executionPlan.metadata?.fallback_reason, scenario.expected);
801
+ }
802
+ finally {
803
+ process.chdir(previousCwd);
804
+ await rm(wd, { recursive: true, force: true });
805
+ }
806
+ }
807
+ }
808
+ finally {
809
+ process.chdir(previousCwd);
810
+ }
811
+ });
473
812
  it('preserves explicit team staffing overrides while reusing the approved plan task', async () => {
474
813
  const wd = await mkdtemp(join(tmpdir(), 'omx-team-followup-override-'));
475
814
  const previousCwd = process.cwd();
@@ -1764,6 +2103,120 @@ describe('teamCommand status', () => {
1764
2103
  });
1765
2104
  });
1766
2105
  describe('teamCommand await', () => {
2106
+ it('applies project-scope agentReasoning overrides when CODEX_HOME is unset', async () => {
2107
+ const wd = await mkdtemp(join(tmpdir(), 'omx-team-project-reasoning-'));
2108
+ const binDir = join(wd, 'bin');
2109
+ const fakeCodexPath = join(binDir, 'codex');
2110
+ const captureDir = join(wd, 'captures');
2111
+ const previousCwd = process.cwd();
2112
+ const previousPath = process.env.PATH;
2113
+ const previousCodexHome = process.env.CODEX_HOME;
2114
+ const previousTmux = process.env.TMUX;
2115
+ const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
2116
+ const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
2117
+ const previousCaptureDir = process.env.OMX_ARGV_CAPTURE_DIR;
2118
+ const previousLaunchArgs = process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
2119
+ const previousSkipReadyWait = process.env.OMX_TEAM_SKIP_READY_WAIT;
2120
+ const logs = [];
2121
+ const originalLog = console.log;
2122
+ const teamTask = 'project scoped architect reasoning override';
2123
+ let displayTeamName = '';
2124
+ await mkdir(binDir, { recursive: true });
2125
+ await mkdir(captureDir, { recursive: true });
2126
+ await mkdir(join(wd, '.omx'), { recursive: true });
2127
+ await mkdir(join(wd, '.codex', 'prompts'), { recursive: true });
2128
+ await writeFile(join(wd, '.omx', 'setup-scope.json'), JSON.stringify({ scope: 'project' }, null, 2));
2129
+ await writeFile(join(wd, '.codex', '.omx-config.json'), JSON.stringify({
2130
+ agentReasoning: {
2131
+ architect: 'xhigh',
2132
+ },
2133
+ }, null, 2));
2134
+ await writeFile(join(wd, '.codex', 'prompts', 'architect.md'), '<identity>You are Architect.</identity>');
2135
+ await writeFile(fakeCodexPath, `#!/usr/bin/env node
2136
+ const fs = require('fs');
2137
+ const path = require('path');
2138
+ const worker = String(process.env.OMX_TEAM_WORKER || 'unknown').replace(/[^a-zA-Z0-9_-]+/g, '__');
2139
+ const out = path.join(process.env.OMX_ARGV_CAPTURE_DIR, worker + '.json');
2140
+ fs.writeFileSync(out, JSON.stringify({
2141
+ argv: process.argv.slice(2),
2142
+ codexHome: process.env.CODEX_HOME || null,
2143
+ worker,
2144
+ }, null, 2));
2145
+ process.stdin.resume();
2146
+ setTimeout(() => process.exit(0), 5000);
2147
+ process.on('SIGTERM', () => process.exit(0));
2148
+ `, { mode: 0o755 });
2149
+ let runtimeTeamName = null;
2150
+ try {
2151
+ process.chdir(wd);
2152
+ process.env.PATH = `${binDir}:${previousPath ?? ''}`;
2153
+ delete process.env.CODEX_HOME;
2154
+ delete process.env.TMUX;
2155
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
2156
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'prompt';
2157
+ process.env.OMX_TEAM_WORKER_CLI = 'codex';
2158
+ process.env.OMX_ARGV_CAPTURE_DIR = captureDir;
2159
+ process.env.OMX_TEAM_SKIP_READY_WAIT = '1';
2160
+ console.log = (...args) => logs.push(args.map(String).join(' '));
2161
+ displayTeamName = parseTeamStartArgs(['1:architect', teamTask]).parsed.teamName;
2162
+ await withMockPromptModeCodexAllowed(() => withoutTeamTestWorkerEnv(() => teamCommand(['1:architect', teamTask])));
2163
+ const startedState = await readModeState('team', wd);
2164
+ runtimeTeamName = String(startedState?.team_name ?? parseTeamStartArgs(['1:architect', teamTask]).parsed.teamName);
2165
+ let captured = null;
2166
+ for (let attempt = 0; attempt < 50; attempt += 1) {
2167
+ const capturePath = join(captureDir, `${displayTeamName}__worker-1.json`);
2168
+ if (existsSync(capturePath)) {
2169
+ captured = JSON.parse(await readFile(capturePath, 'utf-8'));
2170
+ break;
2171
+ }
2172
+ await new Promise((resolve) => setTimeout(resolve, 100));
2173
+ }
2174
+ assert.ok(captured, 'worker argv capture file should be written');
2175
+ assert.equal(captured.codexHome, join(process.cwd(), '.codex'));
2176
+ assert.match(captured.argv.join(' '), /model_reasoning_effort="xhigh"/);
2177
+ assert.match(logs.join('\n'), /architect x1 .*xhigh reasoning/);
2178
+ }
2179
+ finally {
2180
+ console.log = originalLog;
2181
+ if (runtimeTeamName) {
2182
+ await shutdownTeam(runtimeTeamName, wd, { force: true }).catch(() => { });
2183
+ }
2184
+ process.chdir(previousCwd);
2185
+ if (typeof previousPath === 'string')
2186
+ process.env.PATH = previousPath;
2187
+ else
2188
+ delete process.env.PATH;
2189
+ if (typeof previousCodexHome === 'string')
2190
+ process.env.CODEX_HOME = previousCodexHome;
2191
+ else
2192
+ delete process.env.CODEX_HOME;
2193
+ if (typeof previousTmux === 'string')
2194
+ process.env.TMUX = previousTmux;
2195
+ else
2196
+ delete process.env.TMUX;
2197
+ if (typeof previousLaunchMode === 'string')
2198
+ process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
2199
+ else
2200
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
2201
+ if (typeof previousWorkerCli === 'string')
2202
+ process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
2203
+ else
2204
+ delete process.env.OMX_TEAM_WORKER_CLI;
2205
+ if (typeof previousCaptureDir === 'string')
2206
+ process.env.OMX_ARGV_CAPTURE_DIR = previousCaptureDir;
2207
+ else
2208
+ delete process.env.OMX_ARGV_CAPTURE_DIR;
2209
+ if (typeof previousLaunchArgs === 'string')
2210
+ process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = previousLaunchArgs;
2211
+ else
2212
+ delete process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
2213
+ if (typeof previousSkipReadyWait === 'string')
2214
+ process.env.OMX_TEAM_SKIP_READY_WAIT = previousSkipReadyWait;
2215
+ else
2216
+ delete process.env.OMX_TEAM_SKIP_READY_WAIT;
2217
+ await rm(wd, { recursive: true, force: true });
2218
+ }
2219
+ });
1767
2220
  it('returns next canonical event for a team in JSON mode', async () => {
1768
2221
  const wd = await mkdtemp(join(tmpdir(), 'omx-team-await-'));
1769
2222
  const previousCwd = process.cwd();