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
@@ -139,6 +139,47 @@ describe('generate-release-body', () => {
139
139
  });
140
140
 
141
141
 
142
+ it('skips off-ancestry semver-previous tags when auto-resolving the compare base', async () => {
143
+ const root = await mkdtemp(join(tmpdir(), 'omx-generate-release-body-off-ancestry-'));
144
+ try {
145
+ git(root, ['init']);
146
+ git(root, ['config', 'user.name', 'Release Bot']);
147
+ git(root, ['config', 'user.email', 'release@example.com']);
148
+ await writeFile(join(root, 'notes.txt'), 'base\n');
149
+ git(root, ['add', '.']);
150
+ git(root, ['commit', '-m', 'base']);
151
+ git(root, ['tag', 'v0.14.3']);
152
+
153
+ await writeFile(join(root, 'notes.txt'), 'dev train\n');
154
+ git(root, ['add', 'notes.txt']);
155
+ git(root, ['commit', '-m', 'dev train']);
156
+ git(root, ['tag', 'v0.15.1']);
157
+
158
+ git(root, ['checkout', '-b', 'side-release', 'v0.14.3']);
159
+ await writeFile(join(root, 'side.txt'), 'side release\n');
160
+ git(root, ['add', 'side.txt']);
161
+ git(root, ['commit', '-m', 'side release']);
162
+ git(root, ['tag', 'v0.15.0']);
163
+ git(root, ['checkout', 'v0.15.1']);
164
+
165
+ await writeFile(join(root, 'RELEASE_BODY.md'), TEMPLATE);
166
+ await generateReleaseBody({
167
+ cwd: root,
168
+ templatePath: 'RELEASE_BODY.md',
169
+ outPath: 'RELEASE_BODY.generated.md',
170
+ currentTag: 'v0.15.1',
171
+ repo: 'example/oh-my-codex',
172
+ });
173
+
174
+ const generated = await readFile(join(root, 'RELEASE_BODY.generated.md'), 'utf-8');
175
+ assert.match(generated, /`v0\.14\.3\.\.\.v0\.15\.1`/);
176
+ assert.doesNotMatch(generated, /`v0\.15\.0\.\.\.v0\.15\.1`/);
177
+ } finally {
178
+ await rm(root, { recursive: true, force: true });
179
+ }
180
+ });
181
+
182
+
142
183
  it('rejects missing or inverted compare refs before rendering a compare link', async () => {
143
184
  const root = await mkdtemp(join(tmpdir(), 'omx-generate-release-body-range-'));
144
185
  try {
@@ -0,0 +1,64 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { describe, it } from 'node:test';
6
+ import { buildPromptInventory, listPromptSurfacePaths, renderPromptInventoryMarkdown } from '../prompt-inventory.js';
7
+
8
+ describe('prompt inventory', () => {
9
+ it('counts prompt surfaces, absolute directives, markers, and duplicate fragments', async () => {
10
+ const root = await mkdtemp(join(tmpdir(), 'omx-prompt-inventory-'));
11
+ try {
12
+ await mkdir(join(root, 'templates'), { recursive: true });
13
+ await mkdir(join(root, 'prompts'), { recursive: true });
14
+ await mkdir(join(root, 'skills', 'worker'), { recursive: true });
15
+ await mkdir(join(root, 'docs', 'prompt-guidance-fragments'), { recursive: true });
16
+ await mkdir(join(root, 'src', 'hooks'), { recursive: true });
17
+ await mkdir(join(root, 'src', 'config'), { recursive: true });
18
+ await mkdir(join(root, 'src', 'cli'), { recursive: true });
19
+
20
+ const repeated = 'AUTO-CONTINUE for clear, already-requested, low-risk, reversible local work with evidence.';
21
+ await writeFile(join(root, 'AGENTS.md'), `# Root\n${repeated}\n<!-- omx:generated:agents-md -->\n`);
22
+ await writeFile(
23
+ join(root, 'templates', 'AGENTS.md'),
24
+ `# Template\nMUST preserve markers.\n${repeated}\n<!-- OMX:RUNTIME:START -->\n<!-- OMX:RUNTIME:END -->\n`,
25
+ );
26
+ await writeFile(join(root, 'prompts', 'executor.md'), `# Executor\nDO NOT stop early.\n${repeated}\n`);
27
+ await writeFile(join(root, 'skills', 'worker', 'SKILL.md'), '# Worker\nALWAYS claim tasks.\n');
28
+ await writeFile(join(root, 'docs', 'prompt-guidance-contract.md'), '# Contract\n');
29
+ await writeFile(join(root, 'docs', 'guidance-schema.md'), '# Schema\n');
30
+ await writeFile(join(root, 'docs', 'prompt-guidance-fragments', 'core.md'), 'fragment\n');
31
+ await writeFile(join(root, 'src', 'hooks', 'prompt-guidance-contract.ts'), 'export {};\n');
32
+ await writeFile(join(root, 'src', 'config', 'generator.ts'), 'export {};\n');
33
+ await writeFile(join(root, 'src', 'cli', 'setup.ts'), 'export {};\n');
34
+
35
+ const paths = listPromptSurfacePaths(root);
36
+ assert.deepEqual(paths, [
37
+ 'AGENTS.md',
38
+ 'docs/guidance-schema.md',
39
+ 'docs/prompt-guidance-contract.md',
40
+ 'docs/prompt-guidance-fragments/core.md',
41
+ 'prompts/executor.md',
42
+ 'skills/worker/SKILL.md',
43
+ 'src/cli/setup.ts',
44
+ 'src/config/generator.ts',
45
+ 'src/hooks/prompt-guidance-contract.ts',
46
+ 'templates/AGENTS.md',
47
+ ]);
48
+
49
+ const report = buildPromptInventory(root, '2026-01-01T00:00:00.000Z');
50
+ assert.equal(report.totals.files, paths.length);
51
+ assert.ok(report.totals.lines > 0);
52
+ assert.ok(report.totals.approximateTokens > 0);
53
+ assert.equal(report.totals.absoluteDirectiveCount, 6);
54
+ assert.equal(
55
+ report.surfaces.find((surface) => surface.path === 'templates/AGENTS.md')?.markers['<!-- OMX:RUNTIME:START -->'],
56
+ 1,
57
+ );
58
+ assert.equal(report.duplicateFragmentFamilies[0]?.count, 3);
59
+ assert.match(renderPromptInventoryMarkdown(report), /# Prompt Inventory/);
60
+ } finally {
61
+ await rm(root, { recursive: true, force: true });
62
+ }
63
+ });
64
+ });
@@ -1,20 +1,25 @@
1
1
  import { execFileSync } from "child_process";
2
- import { existsSync, readFileSync } from "fs";
2
+ import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
3
3
  import { mkdir, readFile, readdir, writeFile } from "fs/promises";
4
- import { join, resolve } from "path";
4
+ import { join, relative, resolve } from "path";
5
5
  import { pathToFileURL } from "url";
6
6
  import { readModeState, readModeStateForSession, updateModeState } from "../modes/base.js";
7
7
  import {
8
8
  listActiveSkills,
9
9
  readVisibleSkillActiveState,
10
10
  } from "../state/skill-active.js";
11
- import { readSubagentSessionSummary } from "../subagents/tracker.js";
12
- import { resolveCanonicalTeamStateRoot } from "../team/state-root.js";
13
11
  import {
12
+ readSubagentSessionSummary,
13
+ recordSubagentTurnForSession,
14
+ } from "../subagents/tracker.js";
15
+ import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
16
+ import {
17
+ appendToLog,
14
18
  isSessionStateUsable,
15
19
  readSessionState,
16
20
  readUsableSessionState,
17
21
  reconcileNativeSessionStart,
22
+ type SessionState,
18
23
  } from "../hooks/session.js";
19
24
  import {
20
25
  appendTeamEvent,
@@ -25,6 +30,7 @@ import {
25
30
  writeTeamPhase,
26
31
  } from "../team/state.js";
27
32
  import { omxNotepadPath, omxProjectMemoryPath } from "../utils/paths.js";
33
+ import { findGitLayout } from "../utils/git-layout.js";
28
34
  import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
29
35
  import {
30
36
  detectKeywords,
@@ -43,6 +49,7 @@ import {
43
49
  buildNativePreToolUseOutput,
44
50
  detectMcpTransportFailure,
45
51
  } from "./codex-native-pre-post.js";
52
+ import { handleTeamWorkerPostToolUseSuccess } from "./notify-hook/team-worker-posttooluse.js";
46
53
  import {
47
54
  resolveCodexExecutionSurface,
48
55
  type CodexLauncherKind,
@@ -56,7 +63,8 @@ import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
56
63
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
57
64
  import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
58
65
  import { readAutoresearchCompletionStatus, readAutoresearchModeState } from "../autoresearch/skill-validation.js";
59
- import { shouldContinueRun } from "../runtime/run-loop.js";
66
+ import { readRunState } from "../runtime/run-state.js";
67
+ import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
60
68
  import { triagePrompt } from "../hooks/triage-heuristic.js";
61
69
  import { readTriageConfig } from "../hooks/triage-config.js";
62
70
  import {
@@ -75,6 +83,7 @@ import {
75
83
  evaluateFinalHandoffDocumentRefresh,
76
84
  isFinalHandoffDocumentRefreshCandidate,
77
85
  } from "../document-refresh/enforcer.js";
86
+ import { buildExecFollowupStopOutput } from "../exec/followup.js";
78
87
 
79
88
  type CodexHookEventName =
80
89
  | "SessionStart"
@@ -122,6 +131,7 @@ const SHORT_FOLLOWUP_PRIORITY_PATTERNS = [
122
131
  /(?:按照|按|基于)(?:这个|上述|当前)?(?:plan|计划|方案)/u,
123
132
  /\b(?:follow up|latest request|this turn|current turn|newest request)\b/i,
124
133
  ] as const;
134
+ const MAX_SESSION_META_LINE_BYTES = 256 * 1024;
125
135
 
126
136
  function safeString(value: unknown): string {
127
137
  return typeof value === "string" ? value : "";
@@ -131,6 +141,144 @@ function safeObject(value: unknown): Record<string, unknown> {
131
141
  return value && typeof value === "object" ? value as Record<string, unknown> : {};
132
142
  }
133
143
 
144
+ interface NativeSubagentSessionStartMetadata {
145
+ parentThreadId: string;
146
+ agentNickname?: string;
147
+ agentRole?: string;
148
+ }
149
+
150
+ function readBoundedFirstLineSync(path: string): string {
151
+ const fd = openSync(path, "r");
152
+ try {
153
+ const chunks: Buffer[] = [];
154
+ const buffer = Buffer.alloc(Math.min(8192, MAX_SESSION_META_LINE_BYTES));
155
+ let totalBytesRead = 0;
156
+
157
+ while (totalBytesRead < MAX_SESSION_META_LINE_BYTES) {
158
+ const bytesToRead = Math.min(buffer.length, MAX_SESSION_META_LINE_BYTES - totalBytesRead);
159
+ const bytesRead = readSync(fd, buffer, 0, bytesToRead, totalBytesRead);
160
+ if (bytesRead <= 0) break;
161
+
162
+ totalBytesRead += bytesRead;
163
+ const chunk = buffer.subarray(0, bytesRead);
164
+ const newlineOffset = chunk.indexOf(0x0a);
165
+ if (newlineOffset >= 0) {
166
+ chunks.push(Buffer.from(chunk.subarray(0, newlineOffset)));
167
+ break;
168
+ }
169
+ chunks.push(Buffer.from(chunk));
170
+ }
171
+
172
+ return Buffer.concat(chunks).toString("utf-8").replace(/\r$/, "");
173
+ } finally {
174
+ closeSync(fd);
175
+ }
176
+ }
177
+
178
+ function readNativeSubagentSessionStartMetadata(transcriptPath: string): NativeSubagentSessionStartMetadata | null {
179
+ const normalizedPath = transcriptPath.trim();
180
+ if (!normalizedPath) return null;
181
+
182
+ try {
183
+ const firstLine = readBoundedFirstLineSync(normalizedPath).trim();
184
+ if (!firstLine) return null;
185
+ const firstRecord = safeObject(JSON.parse(firstLine));
186
+ if (safeString(firstRecord.type) !== "session_meta") return null;
187
+
188
+ const payload = safeObject(firstRecord.payload);
189
+ const source = safeObject(payload.source);
190
+ const subagent = safeObject(source.subagent);
191
+ const threadSpawn = safeObject(subagent.thread_spawn);
192
+ const parentThreadId = safeString(threadSpawn.parent_thread_id).trim();
193
+ if (!parentThreadId) return null;
194
+
195
+ const agentNickname = safeString(threadSpawn.agent_nickname ?? payload.agent_nickname).trim();
196
+ const agentRole = safeString(threadSpawn.agent_role ?? payload.agent_role).trim();
197
+ return {
198
+ parentThreadId,
199
+ ...(agentNickname ? { agentNickname } : {}),
200
+ ...(agentRole ? { agentRole } : {}),
201
+ };
202
+ } catch {
203
+ return null;
204
+ }
205
+ }
206
+
207
+ async function recordNativeSubagentSessionStart(
208
+ cwd: string,
209
+ canonicalSessionId: string,
210
+ childSessionId: string,
211
+ metadata: NativeSubagentSessionStartMetadata,
212
+ transcriptPath: string,
213
+ ): Promise<void> {
214
+ const trackingSessionIds = [...new Set([
215
+ canonicalSessionId.trim(),
216
+ metadata.parentThreadId.trim(),
217
+ ].filter(Boolean))];
218
+ for (const sessionId of trackingSessionIds) {
219
+ await recordSubagentTurnForSession(cwd, {
220
+ sessionId,
221
+ threadId: metadata.parentThreadId,
222
+ }).catch(() => {});
223
+ await recordSubagentTurnForSession(cwd, {
224
+ sessionId,
225
+ threadId: childSessionId,
226
+ mode: metadata.agentRole,
227
+ }).catch(() => {});
228
+ }
229
+ await appendToLog(cwd, {
230
+ event: "subagent_session_start",
231
+ session_id: canonicalSessionId,
232
+ native_owner_session_id: metadata.parentThreadId,
233
+ native_session_id: childSessionId,
234
+ parent_thread_id: metadata.parentThreadId,
235
+ ...(metadata.agentNickname ? { agent_nickname: metadata.agentNickname } : {}),
236
+ ...(metadata.agentRole ? { agent_role: metadata.agentRole } : {}),
237
+ ...(transcriptPath ? { transcript_path: transcriptPath } : {}),
238
+ timestamp: new Date().toISOString(),
239
+ }).catch(() => {});
240
+ }
241
+
242
+ async function nativeSubagentSessionStartBelongsToCanonicalSession(
243
+ cwd: string,
244
+ canonicalSessionId: string,
245
+ currentSessionState: SessionState | null,
246
+ metadata: NativeSubagentSessionStartMetadata,
247
+ ): Promise<boolean> {
248
+ const parentThreadId = metadata.parentThreadId.trim();
249
+ if (!parentThreadId) return false;
250
+
251
+ const currentNativeSessionId = safeString(currentSessionState?.native_session_id).trim();
252
+ if (currentNativeSessionId && currentNativeSessionId === parentThreadId) {
253
+ return true;
254
+ }
255
+
256
+ const summary = await readSubagentSessionSummary(cwd, canonicalSessionId).catch(() => null);
257
+ if (!summary) return false;
258
+ if (summary.leaderThreadId === parentThreadId) return true;
259
+ return summary.allThreadIds.includes(parentThreadId);
260
+ }
261
+
262
+ async function recordIgnoredNativeSubagentSessionStart(
263
+ cwd: string,
264
+ canonicalSessionId: string,
265
+ childSessionId: string,
266
+ metadata: NativeSubagentSessionStartMetadata,
267
+ transcriptPath: string,
268
+ ): Promise<void> {
269
+ await appendToLog(cwd, {
270
+ event: "subagent_session_start_ignored",
271
+ reason: "parent_not_in_canonical_session",
272
+ session_id: canonicalSessionId,
273
+ native_session_id: childSessionId,
274
+ parent_thread_id: metadata.parentThreadId,
275
+ ...(metadata.agentNickname ? { agent_nickname: metadata.agentNickname } : {}),
276
+ ...(metadata.agentRole ? { agent_role: metadata.agentRole } : {}),
277
+ ...(transcriptPath ? { transcript_path: transcriptPath } : {}),
278
+ timestamp: new Date().toISOString(),
279
+ }).catch(() => {});
280
+ }
281
+
134
282
  function safePositiveInteger(value: unknown): number | null {
135
283
  if (typeof value === "number" && Number.isInteger(value) && value > 0) return value;
136
284
  if (typeof value === "string" && value.trim() !== "") {
@@ -291,10 +439,49 @@ async function readActiveAutoresearchState(
291
439
  return state;
292
440
  }
293
441
 
442
+ interface ActiveRalphStopState {
443
+ state: Record<string, unknown>;
444
+ path: string;
445
+ }
446
+
447
+ function isRalphStartingPhase(state: Record<string, unknown>): boolean {
448
+ return safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase() === "starting";
449
+ }
450
+
451
+ function shouldHonorCanonicalTerminalRunState(
452
+ runState: Record<string, unknown> | null,
453
+ mode: string,
454
+ ): boolean {
455
+ if (!runState) return false;
456
+ const runMode = safeString(runState.mode).trim();
457
+ if (runMode && runMode !== mode) return false;
458
+ return getRunContinuationSnapshot(runState)?.terminal === true;
459
+ }
460
+
461
+ async function readCanonicalTerminalRunStateForStop(
462
+ cwd: string,
463
+ sessionId: string | undefined,
464
+ mode: string,
465
+ ): Promise<Record<string, unknown> | null> {
466
+ if (!safeString(sessionId).trim()) return null;
467
+ const runState = await readRunState(cwd, sessionId).catch(() => null);
468
+ const runRecord = runState as unknown as Record<string, unknown> | null;
469
+ return shouldHonorCanonicalTerminalRunState(runRecord, mode) ? runRecord : null;
470
+ }
471
+
472
+ async function isVisibleRalphActiveForSession(cwd: string, sessionId: string): Promise<boolean> {
473
+ const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
474
+ if (!canonicalState) return false;
475
+ return listActiveSkills(canonicalState).some((entry) => (
476
+ entry.skill === "ralph"
477
+ && matchesSkillStopContext(entry, canonicalState, sessionId, "")
478
+ ));
479
+ }
480
+
294
481
  async function readActiveRalphState(
295
482
  stateDir: string,
296
483
  preferredSessionId?: string,
297
- ): Promise<Record<string, unknown> | null> {
484
+ ): Promise<ActiveRalphStopState | null> {
298
485
  const cwd = resolve(stateDir, "..", "..");
299
486
  const [rawSessionInfo, usableSessionInfo] = await Promise.all([
300
487
  readSessionState(cwd),
@@ -316,17 +503,29 @@ async function readActiveRalphState(
316
503
  if (staleCurrentSessionId && sessionId === staleCurrentSessionId) {
317
504
  continue;
318
505
  }
319
- const sessionScoped = await readStopSessionPinnedState("ralph-state.json", cwd, sessionId);
506
+ if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "ralph")) {
507
+ continue;
508
+ }
509
+ const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
510
+ const sessionScoped = await readJsonIfExists(sessionScopedPath);
511
+ if (
512
+ sessionScoped?.active === true
513
+ && isRalphStartingPhase(sessionScoped)
514
+ && !(await isVisibleRalphActiveForSession(cwd, sessionId))
515
+ ) {
516
+ continue;
517
+ }
320
518
  if (sessionScoped?.active === true && shouldContinueRun(sessionScoped)) {
321
- return sessionScoped;
519
+ return { state: sessionScoped, path: sessionScopedPath };
322
520
  }
323
521
  }
324
522
 
325
523
  if (sessionCandidates.length > 0) return null;
326
524
 
327
- const direct = await readJsonIfExists(join(stateDir, "ralph-state.json"));
525
+ const directPath = join(stateDir, "ralph-state.json");
526
+ const direct = await readJsonIfExists(directPath);
328
527
  if (direct?.active === true && shouldContinueRun(direct)) {
329
- return direct;
528
+ return { state: direct, path: directPath };
330
529
  }
331
530
 
332
531
  return null;
@@ -444,6 +643,22 @@ function tryReadGitValue(cwd: string, args: string[]): string | null {
444
643
  }
445
644
  }
446
645
 
646
+
647
+ function localExcludeAlreadyIgnoresOmx(cwd: string): boolean {
648
+ const layout = findGitLayout(cwd);
649
+ if (!layout) return false;
650
+ const excludePath = join(layout.gitDir, "info", "exclude");
651
+ try {
652
+ const lines = readFileSync(excludePath, "utf-8")
653
+ .split(/\r?\n/)
654
+ .map((line) => line.trim())
655
+ .filter((line) => line && !line.startsWith("#"));
656
+ return lines.includes(".omx/") || lines.includes(".omx");
657
+ } catch {
658
+ return false;
659
+ }
660
+ }
661
+
447
662
  function isPathIgnoredByGit(cwd: string, path: string): boolean {
448
663
  try {
449
664
  execFileSync("git", ["check-ignore", "-q", path], {
@@ -460,7 +675,7 @@ function isPathIgnoredByGit(cwd: string, path: string): boolean {
460
675
  async function ensureOmxLocalIgnoreEntry(cwd: string): Promise<{ changed: boolean; excludePath?: string }> {
461
676
  const repoRoot = tryReadGitValue(cwd, ["rev-parse", "--show-toplevel"]);
462
677
  if (!repoRoot) return { changed: false };
463
- if (isPathIgnoredByGit(repoRoot, ".omx/")) {
678
+ if (localExcludeAlreadyIgnoresOmx(repoRoot) || isPathIgnoredByGit(repoRoot, ".omx/")) {
464
679
  return { changed: false };
465
680
  }
466
681
 
@@ -631,10 +846,10 @@ function resolveExecutionEnvironment(
631
846
  transport: executionSurface.transport,
632
847
  surface: "attached tmux runtime - tmux",
633
848
  tmuxWorkflowGuidance: "omx team, omx hud, and omx question are directly usable in this session",
634
- questionGuidance: "visible renderer available from the current pane",
849
+ questionGuidance: "visible temporary renderer available from the current pane; primary success JSON is answers[]",
635
850
  teamRuntimeInstruction: "Use the durable OMX team runtime via `omx team ...` for coordinated execution; do not replace it with in-process fanout.",
636
851
  teamHelpInstruction: "If you need runtime syntax, run `omx team --help` yourself.",
637
- deepInterviewInstruction: "Deep-interview must ask each interview round via `omx question`; do not fall back to `request_user_input` or plain-text questioning. This session is already attached to tmux, so `omx question` can open its visible renderer directly. After starting `omx question` in a background terminal, wait for that terminal to finish and read the JSON answer before continuing the interview. Stop remains blocked while a deep-interview question obligation is pending.",
852
+ deepInterviewInstruction: "Deep-interview must ask each interview round via `omx question`; do not fall back to `request_user_input` or plain-text questioning. This session is already attached to tmux, so `omx question` can open its temporary renderer directly over the leader pane. After starting `omx question` in a background terminal, wait for that terminal to finish and read the JSON answer before continuing the interview. Prefer `answers[0].answer` / `answers[]`; use legacy `answer` only as fallback. Deep-interview remains one question per round, so do not batch multiple interview rounds into one `questions[]` form. Stop remains blocked while a deep-interview question obligation is pending.",
638
853
  leaderPaneHint,
639
854
  };
640
855
  }
@@ -905,48 +1120,14 @@ function parseTeamWorkerEnv(rawValue: string): { teamName: string; workerName: s
905
1120
  };
906
1121
  }
907
1122
 
908
- async function readTeamStateRootFromJson(path: string): Promise<string | null> {
909
- const parsed = await readJsonIfExists(path);
910
- const value = safeString(parsed?.team_state_root).trim();
911
- return value || null;
912
- }
913
-
914
1123
  async function resolveTeamStateDirForWorkerContext(
915
1124
  cwd: string,
916
1125
  workerContext: { teamName: string; workerName: string },
917
- ): Promise<string> {
918
- const explicitStateRoot = safeString(process.env.OMX_TEAM_STATE_ROOT).trim();
919
- if (explicitStateRoot) {
920
- return resolve(cwd, explicitStateRoot);
921
- }
922
-
923
- const leaderCwd = safeString(process.env.OMX_TEAM_LEADER_CWD).trim();
924
- const candidateStateDirs = [
925
- ...(leaderCwd ? [join(resolve(leaderCwd), ".omx", "state")] : []),
926
- join(cwd, ".omx", "state"),
927
- ];
928
-
929
- for (const candidateStateDir of candidateStateDirs) {
930
- const teamRoot = join(candidateStateDir, "team", workerContext.teamName);
931
- if (!existsSync(teamRoot)) continue;
932
-
933
- const identityRoot = await readTeamStateRootFromJson(
934
- join(teamRoot, "workers", workerContext.workerName, "identity.json"),
935
- );
936
- if (identityRoot) return resolve(cwd, identityRoot);
937
-
938
- const manifestRoot = await readTeamStateRootFromJson(join(teamRoot, "manifest.v2.json"));
939
- if (manifestRoot) return resolve(cwd, manifestRoot);
940
-
941
- const configRoot = await readTeamStateRootFromJson(join(teamRoot, "config.json"));
942
- if (configRoot) return resolve(cwd, configRoot);
943
-
944
- return candidateStateDir;
945
- }
946
-
947
- return join(cwd, ".omx", "state");
1126
+ ): Promise<string | null> {
1127
+ return resolveWorkerNotifyTeamStateRootPath(cwd, workerContext, process.env);
948
1128
  }
949
1129
 
1130
+
950
1131
  async function buildTeamWorkerStopOutput(
951
1132
  cwd: string,
952
1133
  ): Promise<Record<string, unknown> | null> {
@@ -954,6 +1135,7 @@ async function buildTeamWorkerStopOutput(
954
1135
  if (!workerContext) return null;
955
1136
 
956
1137
  const stateDir = await resolveTeamStateDirForWorkerContext(cwd, workerContext);
1138
+ if (!stateDir) return null;
957
1139
  const workerRoot = join(stateDir, "team", workerContext.teamName, "workers", workerContext.workerName);
958
1140
  const [identity, status] = await Promise.all([
959
1141
  readJsonIfExists(join(workerRoot, "identity.json")),
@@ -1053,6 +1235,9 @@ async function readTeamModeStateForStop(
1053
1235
  }
1054
1236
 
1055
1237
  async function buildTeamStopOutput(cwd: string, sessionId?: string): Promise<Record<string, unknown> | null> {
1238
+ if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
1239
+ return null;
1240
+ }
1056
1241
  const teamState = await readTeamModeStateForStop(cwd, sessionId);
1057
1242
  if (teamState?.active !== true) return null;
1058
1243
  const teamName = safeString(teamState.team_name).trim();
@@ -1303,7 +1488,7 @@ async function buildDeepInterviewQuestionStopOutput(
1303
1488
  if (!obligationId) return null;
1304
1489
 
1305
1490
  const systemMessage =
1306
- `OMX deep-interview is still active (phase: ${phase}) and requires a structured question via omx question before stopping.`;
1491
+ `OMX deep-interview is still active (phase: ${phase}) and requires a structured question via omx question before stopping; read the returned answers[] JSON before continuing.`;
1307
1492
 
1308
1493
  return {
1309
1494
  obligationId,
@@ -1359,6 +1544,12 @@ function buildRepeatableStopSignature(
1359
1544
  ].join("|");
1360
1545
  }
1361
1546
 
1547
+ function formatStopStatePath(cwd: string, statePath: string): string {
1548
+ const relativePath = relative(cwd, statePath);
1549
+ if (!relativePath || relativePath.startsWith("..")) return statePath;
1550
+ return relativePath.replace(/\\/g, "/");
1551
+ }
1552
+
1362
1553
  function readNativeStopSessionKey(
1363
1554
  payload: CodexHookPayload,
1364
1555
  canonicalSessionId?: string,
@@ -1672,6 +1863,8 @@ async function buildStopHookOutput(
1672
1863
  const sessionId = readPayloadSessionId(payload);
1673
1864
  const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
1674
1865
  const threadId = readPayloadThreadId(payload);
1866
+ const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
1867
+ if (execFollowupOutput) return execFollowupOutput;
1675
1868
  const ralphState = await readActiveRalphState(stateDir, canonicalSessionId);
1676
1869
  if (!ralphState) {
1677
1870
  const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
@@ -1784,7 +1977,9 @@ async function buildStopHookOutput(
1784
1977
  );
1785
1978
  }
1786
1979
 
1787
- const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
1980
+ const canonicalTeam = await readCanonicalTerminalRunStateForStop(cwd, canonicalSessionId, "team")
1981
+ ? null
1982
+ : await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
1788
1983
  if (canonicalTeam) {
1789
1984
  const canonicalTeamOutput = buildTeamStopOutputForPhase(
1790
1985
  canonicalTeam.teamName,
@@ -1864,10 +2059,11 @@ async function buildStopHookOutput(
1864
2059
  return null;
1865
2060
  }
1866
2061
 
1867
- const currentPhase = safeString(ralphState?.current_phase).trim() || "executing";
2062
+ const currentPhase = safeString(ralphState.state.current_phase).trim() || "executing";
2063
+ const blockingPath = formatStopStatePath(cwd, ralphState.path);
1868
2064
  const stopReason = `ralph_${currentPhase}`;
1869
2065
  const systemMessage =
1870
- `OMX Ralph is still active (phase: ${currentPhase}); continue the task and gather fresh verification evidence before stopping.`;
2066
+ `OMX Ralph is still active (phase: ${currentPhase}; state: ${blockingPath}); continue the task and gather fresh verification evidence before stopping.`;
1871
2067
 
1872
2068
  return await returnPersistentStopBlock(
1873
2069
  payload,
@@ -1903,13 +2099,46 @@ export async function dispatchCodexNativeHook(
1903
2099
  const currentSessionState = await readUsableSessionState(cwd);
1904
2100
  let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
1905
2101
  let resolvedNativeSessionId = nativeSessionId;
2102
+ let skipCanonicalSessionStartContext = false;
1906
2103
 
1907
2104
  if (hookEventName === "SessionStart" && nativeSessionId) {
1908
- const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
1909
- pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
1910
- });
1911
- canonicalSessionId = safeString(sessionState.session_id).trim();
1912
- resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
2105
+ const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
2106
+ const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
2107
+ if (subagentSessionStart && canonicalSessionId) {
2108
+ const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(
2109
+ cwd,
2110
+ canonicalSessionId,
2111
+ currentSessionState,
2112
+ subagentSessionStart,
2113
+ );
2114
+ if (belongsToCanonicalSession) {
2115
+ resolvedNativeSessionId = nativeSessionId;
2116
+ await recordNativeSubagentSessionStart(
2117
+ cwd,
2118
+ canonicalSessionId,
2119
+ nativeSessionId,
2120
+ subagentSessionStart,
2121
+ transcriptPath,
2122
+ );
2123
+ } else {
2124
+ skipCanonicalSessionStartContext = true;
2125
+ resolvedNativeSessionId =
2126
+ safeString(currentSessionState?.native_session_id).trim() || nativeSessionId;
2127
+ await recordIgnoredNativeSubagentSessionStart(
2128
+ cwd,
2129
+ canonicalSessionId,
2130
+ nativeSessionId,
2131
+ subagentSessionStart,
2132
+ transcriptPath,
2133
+ );
2134
+ }
2135
+ } else {
2136
+ const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
2137
+ pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
2138
+ });
2139
+ canonicalSessionId = safeString(sessionState.session_id).trim();
2140
+ resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
2141
+ }
1913
2142
  } else if (!canonicalSessionId) {
1914
2143
  canonicalSessionId = safeString(currentSessionState?.session_id).trim();
1915
2144
  }
@@ -2024,7 +2253,7 @@ export async function dispatchCodexNativeHook(
2024
2253
  await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => {});
2025
2254
  }
2026
2255
 
2027
- if (omxEventName) {
2256
+ if (omxEventName && !skipCanonicalSessionStartContext) {
2028
2257
  const baseContext = buildBaseContext(cwd, payload, hookEventName!, canonicalSessionId);
2029
2258
  if (resolvedNativeSessionId) {
2030
2259
  baseContext.native_session_id = resolvedNativeSessionId;
@@ -2046,7 +2275,7 @@ export async function dispatchCodexNativeHook(
2046
2275
  await dispatchHookEvent(event, { cwd });
2047
2276
  }
2048
2277
 
2049
- if (hookEventName === "SessionStart" || hookEventName === "UserPromptSubmit") {
2278
+ if ((hookEventName === "SessionStart" && !skipCanonicalSessionStartContext) || hookEventName === "UserPromptSubmit") {
2050
2279
  const additionalContext = hookEventName === "SessionStart"
2051
2280
  ? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId, {
2052
2281
  hookEventName,
@@ -2070,6 +2299,7 @@ export async function dispatchCodexNativeHook(
2070
2299
  await markTeamTransportFailure(cwd, payload);
2071
2300
  }
2072
2301
  outputJson = buildNativePostToolUseOutput(payload);
2302
+ await handleTeamWorkerPostToolUseSuccess(payload, cwd);
2073
2303
  } else if (hookEventName === "Stop") {
2074
2304
  outputJson = await buildStopHookOutput(payload, cwd, stateDir);
2075
2305
  }
@@ -2163,6 +2393,8 @@ export async function runCodexNativeHookCli(): Promise<void> {
2163
2393
  const result = await dispatchCodexNativeHook(payload);
2164
2394
  if (result.outputJson) {
2165
2395
  writeNativeHookJsonStdout(result.outputJson);
2396
+ } else if (result.hookEventName === "Stop") {
2397
+ writeNativeHookJsonStdout({});
2166
2398
  }
2167
2399
  } catch (error) {
2168
2400
  if (readHookEventName(payload) !== "Stop") {