oh-my-codex 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (524) hide show
  1. package/Cargo.lock +10 -7
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -0
  4. package/crates/omx-explore/Cargo.toml +3 -0
  5. package/crates/omx-explore/src/main.rs +517 -16
  6. package/dist/agents/__tests__/native-config.test.js +33 -0
  7. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  8. package/dist/autoresearch/goal.d.ts +90 -0
  9. package/dist/autoresearch/goal.d.ts.map +1 -0
  10. package/dist/autoresearch/goal.js +237 -0
  11. package/dist/autoresearch/goal.js.map +1 -0
  12. package/dist/autoresearch/skill-validation.d.ts +1 -0
  13. package/dist/autoresearch/skill-validation.d.ts.map +1 -1
  14. package/dist/autoresearch/skill-validation.js +10 -3
  15. package/dist/autoresearch/skill-validation.js.map +1 -1
  16. package/dist/catalog/__tests__/generator.test.js +9 -4
  17. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  18. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +29 -2
  19. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  20. package/dist/catalog/__tests__/schema.test.js +14 -3
  21. package/dist/catalog/__tests__/schema.test.js.map +1 -1
  22. package/dist/catalog/schema.js +1 -1
  23. package/dist/catalog/schema.js.map +1 -1
  24. package/dist/cli/__tests__/autoresearch-goal.test.d.ts +2 -0
  25. package/dist/cli/__tests__/autoresearch-goal.test.d.ts.map +1 -0
  26. package/dist/cli/__tests__/autoresearch-goal.test.js +194 -0
  27. package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -0
  28. package/dist/cli/__tests__/cleanup.test.js +82 -1
  29. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  30. package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -4
  31. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  32. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts +2 -0
  33. package/dist/cli/__tests__/doctor-context-window-warning.test.d.ts.map +1 -0
  34. package/dist/cli/__tests__/doctor-context-window-warning.test.js +122 -0
  35. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -0
  36. package/dist/cli/__tests__/doctor-warning-copy.test.js +25 -2
  37. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  38. package/dist/cli/__tests__/exec.test.js +1 -0
  39. package/dist/cli/__tests__/exec.test.js.map +1 -1
  40. package/dist/cli/__tests__/explore.test.js +48 -18
  41. package/dist/cli/__tests__/explore.test.js.map +1 -1
  42. package/dist/cli/__tests__/index.test.js +222 -10
  43. package/dist/cli/__tests__/index.test.js.map +1 -1
  44. package/dist/cli/__tests__/launch-fallback.test.js +58 -0
  45. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  46. package/dist/cli/__tests__/mcp-serve.test.js +27 -1
  47. package/dist/cli/__tests__/mcp-serve.test.js.map +1 -1
  48. package/dist/cli/__tests__/native-assets.test.js +26 -1
  49. package/dist/cli/__tests__/native-assets.test.js.map +1 -1
  50. package/dist/cli/__tests__/package-bin-contract.test.js +2 -2
  51. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  52. package/dist/cli/__tests__/performance-goal.test.d.ts +2 -0
  53. package/dist/cli/__tests__/performance-goal.test.d.ts.map +1 -0
  54. package/dist/cli/__tests__/performance-goal.test.js +144 -0
  55. package/dist/cli/__tests__/performance-goal.test.js.map +1 -0
  56. package/dist/cli/__tests__/question.test.js +8 -0
  57. package/dist/cli/__tests__/question.test.js.map +1 -1
  58. package/dist/cli/__tests__/ralph-goal-mode-contract.test.d.ts +2 -0
  59. package/dist/cli/__tests__/ralph-goal-mode-contract.test.d.ts.map +1 -0
  60. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +31 -0
  61. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -0
  62. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +5 -4
  63. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
  64. package/dist/cli/__tests__/ralph-prd-smoke.test.js +7 -0
  65. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
  66. package/dist/cli/__tests__/ralph.test.js +59 -1
  67. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  68. package/dist/cli/__tests__/setup-install-mode.test.js +57 -21
  69. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  70. package/dist/cli/__tests__/setup-refresh.test.js +27 -8
  71. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  72. package/dist/cli/__tests__/setup-scope.test.js +20 -10
  73. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  74. package/dist/cli/__tests__/setup-skill-validation.test.js +11 -11
  75. package/dist/cli/__tests__/setup-skill-validation.test.js.map +1 -1
  76. package/dist/cli/__tests__/setup-skills-overwrite.test.js +12 -12
  77. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  78. package/dist/cli/__tests__/team.test.js +242 -10
  79. package/dist/cli/__tests__/team.test.js.map +1 -1
  80. package/dist/cli/__tests__/ultragoal.test.d.ts +2 -0
  81. package/dist/cli/__tests__/ultragoal.test.d.ts.map +1 -0
  82. package/dist/cli/__tests__/ultragoal.test.js +106 -0
  83. package/dist/cli/__tests__/ultragoal.test.js.map +1 -0
  84. package/dist/cli/__tests__/uninstall.test.js +11 -0
  85. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  86. package/dist/cli/autoresearch-goal.d.ts +3 -0
  87. package/dist/cli/autoresearch-goal.d.ts.map +1 -0
  88. package/dist/cli/autoresearch-goal.js +175 -0
  89. package/dist/cli/autoresearch-goal.js.map +1 -0
  90. package/dist/cli/cleanup.d.ts +3 -1
  91. package/dist/cli/cleanup.d.ts.map +1 -1
  92. package/dist/cli/cleanup.js +42 -2
  93. package/dist/cli/cleanup.js.map +1 -1
  94. package/dist/cli/doctor.d.ts.map +1 -1
  95. package/dist/cli/doctor.js +95 -3
  96. package/dist/cli/doctor.js.map +1 -1
  97. package/dist/cli/explore.d.ts.map +1 -1
  98. package/dist/cli/explore.js +10 -2
  99. package/dist/cli/explore.js.map +1 -1
  100. package/dist/cli/index.d.ts +21 -2
  101. package/dist/cli/index.d.ts.map +1 -1
  102. package/dist/cli/index.js +268 -30
  103. package/dist/cli/index.js.map +1 -1
  104. package/dist/cli/mcp-serve.d.ts +1 -0
  105. package/dist/cli/mcp-serve.d.ts.map +1 -1
  106. package/dist/cli/mcp-serve.js +8 -0
  107. package/dist/cli/mcp-serve.js.map +1 -1
  108. package/dist/cli/native-assets.js +1 -1
  109. package/dist/cli/native-assets.js.map +1 -1
  110. package/dist/cli/performance-goal.d.ts +3 -0
  111. package/dist/cli/performance-goal.d.ts.map +1 -0
  112. package/dist/cli/performance-goal.js +186 -0
  113. package/dist/cli/performance-goal.js.map +1 -0
  114. package/dist/cli/ralph.d.ts +2 -0
  115. package/dist/cli/ralph.d.ts.map +1 -1
  116. package/dist/cli/ralph.js +25 -1
  117. package/dist/cli/ralph.js.map +1 -1
  118. package/dist/cli/setup.d.ts.map +1 -1
  119. package/dist/cli/setup.js +13 -6
  120. package/dist/cli/setup.js.map +1 -1
  121. package/dist/cli/team.d.ts +6 -0
  122. package/dist/cli/team.d.ts.map +1 -1
  123. package/dist/cli/team.js +113 -33
  124. package/dist/cli/team.js.map +1 -1
  125. package/dist/cli/tmux-hook.d.ts.map +1 -1
  126. package/dist/cli/tmux-hook.js +2 -1
  127. package/dist/cli/tmux-hook.js.map +1 -1
  128. package/dist/cli/ultragoal.d.ts +3 -0
  129. package/dist/cli/ultragoal.d.ts.map +1 -0
  130. package/dist/cli/ultragoal.js +191 -0
  131. package/dist/cli/ultragoal.js.map +1 -0
  132. package/dist/cli/uninstall.d.ts.map +1 -1
  133. package/dist/cli/uninstall.js +4 -2
  134. package/dist/cli/uninstall.js.map +1 -1
  135. package/dist/config/__tests__/generator-idempotent.test.js +39 -6
  136. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  137. package/dist/config/__tests__/generator-notify.test.js +5 -0
  138. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  139. package/dist/config/commit-lore-guard.d.ts +3 -0
  140. package/dist/config/commit-lore-guard.d.ts.map +1 -0
  141. package/dist/config/commit-lore-guard.js +9 -0
  142. package/dist/config/commit-lore-guard.js.map +1 -0
  143. package/dist/config/generator.d.ts +14 -4
  144. package/dist/config/generator.d.ts.map +1 -1
  145. package/dist/config/generator.js +166 -66
  146. package/dist/config/generator.js.map +1 -1
  147. package/dist/config/omx-first-party-mcp.d.ts +1 -0
  148. package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
  149. package/dist/config/omx-first-party-mcp.js +4 -1
  150. package/dist/config/omx-first-party-mcp.js.map +1 -1
  151. package/dist/goal-workflows/__tests__/artifacts.test.d.ts +2 -0
  152. package/dist/goal-workflows/__tests__/artifacts.test.d.ts.map +1 -0
  153. package/dist/goal-workflows/__tests__/artifacts.test.js +96 -0
  154. package/dist/goal-workflows/__tests__/artifacts.test.js.map +1 -0
  155. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.d.ts +2 -0
  156. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.d.ts.map +1 -0
  157. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +54 -0
  158. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -0
  159. package/dist/goal-workflows/artifacts.d.ts +62 -0
  160. package/dist/goal-workflows/artifacts.d.ts.map +1 -0
  161. package/dist/goal-workflows/artifacts.js +132 -0
  162. package/dist/goal-workflows/artifacts.js.map +1 -0
  163. package/dist/goal-workflows/codex-goal-snapshot.d.ts +28 -0
  164. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -0
  165. package/dist/goal-workflows/codex-goal-snapshot.js +110 -0
  166. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -0
  167. package/dist/goal-workflows/handoff.d.ts +10 -0
  168. package/dist/goal-workflows/handoff.d.ts.map +1 -0
  169. package/dist/goal-workflows/handoff.js +31 -0
  170. package/dist/goal-workflows/handoff.js.map +1 -0
  171. package/dist/goal-workflows/validation.d.ts +13 -0
  172. package/dist/goal-workflows/validation.d.ts.map +1 -0
  173. package/dist/goal-workflows/validation.js +36 -0
  174. package/dist/goal-workflows/validation.js.map +1 -0
  175. package/dist/hooks/__tests__/agents-overlay.test.js +59 -0
  176. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  177. package/dist/hooks/__tests__/anti-slop-workflow.test.js +109 -18
  178. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  179. package/dist/hooks/__tests__/keyword-detector.test.js +45 -32
  180. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  181. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +3 -3
  182. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  183. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +2 -1
  184. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  185. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +17 -24
  186. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  187. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +3 -3
  188. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  189. package/dist/hooks/__tests__/task-size-detector.test.js +1 -1
  190. package/dist/hooks/__tests__/task-size-detector.test.js.map +1 -1
  191. package/dist/hooks/__tests__/visual-ralph-skill.test.js +3 -3
  192. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
  193. package/dist/hooks/__tests__/visual-verdict-loop.test.js +7 -11
  194. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
  195. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  196. package/dist/hooks/agents-overlay.js +23 -2
  197. package/dist/hooks/agents-overlay.js.map +1 -1
  198. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  199. package/dist/hooks/keyword-detector.js +12 -13
  200. package/dist/hooks/keyword-detector.js.map +1 -1
  201. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  202. package/dist/hooks/keyword-registry.js +2 -10
  203. package/dist/hooks/keyword-registry.js.map +1 -1
  204. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  205. package/dist/hooks/prompt-guidance-contract.js +0 -4
  206. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  207. package/dist/hooks/session.js +2 -2
  208. package/dist/hooks/session.js.map +1 -1
  209. package/dist/hooks/task-size-detector.d.ts.map +1 -1
  210. package/dist/hooks/task-size-detector.js +1 -0
  211. package/dist/hooks/task-size-detector.js.map +1 -1
  212. package/dist/hud/__tests__/index.test.js +30 -14
  213. package/dist/hud/__tests__/index.test.js.map +1 -1
  214. package/dist/hud/__tests__/reconcile.test.js +29 -7
  215. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  216. package/dist/hud/reconcile.d.ts +2 -1
  217. package/dist/hud/reconcile.d.ts.map +1 -1
  218. package/dist/hud/reconcile.js +12 -0
  219. package/dist/hud/reconcile.js.map +1 -1
  220. package/dist/mcp/__tests__/bootstrap.test.js +15 -2
  221. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  222. package/dist/mcp/__tests__/state-paths.test.js +54 -0
  223. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  224. package/dist/mcp/__tests__/state-server.test.js +36 -0
  225. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  226. package/dist/mcp/bootstrap.d.ts +1 -1
  227. package/dist/mcp/bootstrap.d.ts.map +1 -1
  228. package/dist/mcp/bootstrap.js +9 -7
  229. package/dist/mcp/bootstrap.js.map +1 -1
  230. package/dist/mcp/state-paths.d.ts +17 -0
  231. package/dist/mcp/state-paths.d.ts.map +1 -1
  232. package/dist/mcp/state-paths.js +36 -2
  233. package/dist/mcp/state-paths.js.map +1 -1
  234. package/dist/modes/__tests__/base-session-scope.test.js +26 -0
  235. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  236. package/dist/modes/base.d.ts +1 -0
  237. package/dist/modes/base.d.ts.map +1 -1
  238. package/dist/modes/base.js +35 -5
  239. package/dist/modes/base.js.map +1 -1
  240. package/dist/notifications/__tests__/http-client.test.d.ts +2 -0
  241. package/dist/notifications/__tests__/http-client.test.d.ts.map +1 -0
  242. package/dist/notifications/__tests__/http-client.test.js +90 -0
  243. package/dist/notifications/__tests__/http-client.test.js.map +1 -0
  244. package/dist/notifications/__tests__/notifier.test.js +22 -60
  245. package/dist/notifications/__tests__/notifier.test.js.map +1 -1
  246. package/dist/notifications/dispatcher.d.ts.map +1 -1
  247. package/dist/notifications/dispatcher.js +35 -60
  248. package/dist/notifications/dispatcher.js.map +1 -1
  249. package/dist/notifications/http-client.d.ts +22 -0
  250. package/dist/notifications/http-client.d.ts.map +1 -0
  251. package/dist/notifications/http-client.js +298 -0
  252. package/dist/notifications/http-client.js.map +1 -0
  253. package/dist/notifications/notifier.d.ts +3 -2
  254. package/dist/notifications/notifier.d.ts.map +1 -1
  255. package/dist/notifications/notifier.js +17 -22
  256. package/dist/notifications/notifier.js.map +1 -1
  257. package/dist/openclaw/__tests__/dispatcher.test.js +63 -2
  258. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
  259. package/dist/openclaw/dispatcher.d.ts.map +1 -1
  260. package/dist/openclaw/dispatcher.js +3 -2
  261. package/dist/openclaw/dispatcher.js.map +1 -1
  262. package/dist/performance-goal/artifacts.d.ts +76 -0
  263. package/dist/performance-goal/artifacts.d.ts.map +1 -0
  264. package/dist/performance-goal/artifacts.js +221 -0
  265. package/dist/performance-goal/artifacts.js.map +1 -0
  266. package/dist/pipeline/__tests__/stages.test.js +423 -14
  267. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  268. package/dist/pipeline/stages/team-exec.d.ts +8 -4
  269. package/dist/pipeline/stages/team-exec.d.ts.map +1 -1
  270. package/dist/pipeline/stages/team-exec.js +181 -13
  271. package/dist/pipeline/stages/team-exec.js.map +1 -1
  272. package/dist/planning/__tests__/artifacts.test.js +261 -1
  273. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  274. package/dist/planning/artifact-names.d.ts +13 -0
  275. package/dist/planning/artifact-names.d.ts.map +1 -0
  276. package/dist/planning/artifact-names.js +108 -0
  277. package/dist/planning/artifact-names.js.map +1 -0
  278. package/dist/planning/artifacts.d.ts +23 -1
  279. package/dist/planning/artifacts.d.ts.map +1 -1
  280. package/dist/planning/artifacts.js +171 -59
  281. package/dist/planning/artifacts.js.map +1 -1
  282. package/dist/ralph/__tests__/persistence.test.js +21 -1
  283. package/dist/ralph/__tests__/persistence.test.js.map +1 -1
  284. package/dist/ralph/persistence.d.ts.map +1 -1
  285. package/dist/ralph/persistence.js +6 -4
  286. package/dist/ralph/persistence.js.map +1 -1
  287. package/dist/ralplan/__tests__/runtime.test.js +2 -0
  288. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  289. package/dist/ralplan/runtime.d.ts.map +1 -1
  290. package/dist/ralplan/runtime.js +6 -0
  291. package/dist/ralplan/runtime.js.map +1 -1
  292. package/dist/scripts/__tests__/codex-native-hook.test.js +1749 -88
  293. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  294. package/dist/scripts/__tests__/hook-derived-watcher.test.js +33 -1
  295. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
  296. package/dist/scripts/__tests__/run-test-files.test.js +36 -0
  297. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  298. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  299. package/dist/scripts/codex-native-hook.js +570 -45
  300. package/dist/scripts/codex-native-hook.js.map +1 -1
  301. package/dist/scripts/codex-native-pre-post.d.ts +7 -0
  302. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  303. package/dist/scripts/codex-native-pre-post.js +341 -15
  304. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  305. package/dist/scripts/hook-derived-watcher.js +2 -1
  306. package/dist/scripts/hook-derived-watcher.js.map +1 -1
  307. package/dist/scripts/notify-fallback-watcher.js +2 -1
  308. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  309. package/dist/scripts/notify-hook/orchestration-intent.d.ts +1 -2
  310. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
  311. package/dist/scripts/notify-hook/orchestration-intent.js +2 -3
  312. package/dist/scripts/notify-hook/orchestration-intent.js.map +1 -1
  313. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +0 -2
  314. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  315. package/dist/scripts/notify-hook/team-leader-nudge.js +8 -60
  316. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  317. package/dist/scripts/notify-hook/team-worker-posttooluse.js +1 -1
  318. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
  319. package/dist/scripts/notify-hook/team-worker-stop.d.ts +15 -0
  320. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -0
  321. package/dist/scripts/notify-hook/team-worker-stop.js +224 -0
  322. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -0
  323. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  324. package/dist/scripts/notify-hook/team-worker.js +26 -18
  325. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  326. package/dist/scripts/notify-hook.js +1 -1
  327. package/dist/scripts/notify-hook.js.map +1 -1
  328. package/dist/scripts/run-test-files.js +17 -1
  329. package/dist/scripts/run-test-files.js.map +1 -1
  330. package/dist/scripts/sync-plugin-mirror.d.ts +1 -0
  331. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  332. package/dist/scripts/sync-plugin-mirror.js +10 -4
  333. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  334. package/dist/state/__tests__/operations.test.js +26 -0
  335. package/dist/state/__tests__/operations.test.js.map +1 -1
  336. package/dist/state/__tests__/skill-active.test.js +76 -0
  337. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  338. package/dist/state/operations.d.ts +3 -1
  339. package/dist/state/operations.d.ts.map +1 -1
  340. package/dist/state/operations.js +8 -4
  341. package/dist/state/operations.js.map +1 -1
  342. package/dist/state/skill-active.d.ts +1 -0
  343. package/dist/state/skill-active.d.ts.map +1 -1
  344. package/dist/state/skill-active.js +54 -13
  345. package/dist/state/skill-active.js.map +1 -1
  346. package/dist/team/__tests__/api-interop.test.js +279 -0
  347. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  348. package/dist/team/__tests__/approved-execution.test.d.ts +2 -0
  349. package/dist/team/__tests__/approved-execution.test.d.ts.map +1 -0
  350. package/dist/team/__tests__/approved-execution.test.js +124 -0
  351. package/dist/team/__tests__/approved-execution.test.js.map +1 -0
  352. package/dist/team/__tests__/delivery-e2e-smoke.test.js +2 -4
  353. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  354. package/dist/team/__tests__/delivery-log.test.d.ts +2 -0
  355. package/dist/team/__tests__/delivery-log.test.d.ts.map +1 -0
  356. package/dist/team/__tests__/delivery-log.test.js +44 -0
  357. package/dist/team/__tests__/delivery-log.test.js.map +1 -0
  358. package/dist/team/__tests__/model-contract.test.js +40 -9
  359. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  360. package/dist/team/__tests__/repo-aware-decomposition.test.js +41 -0
  361. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -1
  362. package/dist/team/__tests__/role-router.test.js +4 -4
  363. package/dist/team/__tests__/role-router.test.js.map +1 -1
  364. package/dist/team/__tests__/runtime-boxed-state.test.d.ts +2 -0
  365. package/dist/team/__tests__/runtime-boxed-state.test.d.ts.map +1 -0
  366. package/dist/team/__tests__/runtime-boxed-state.test.js +39 -0
  367. package/dist/team/__tests__/runtime-boxed-state.test.js.map +1 -0
  368. package/dist/team/__tests__/runtime-cli.test.js +24 -0
  369. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  370. package/dist/team/__tests__/runtime.test.js +563 -72
  371. package/dist/team/__tests__/runtime.test.js.map +1 -1
  372. package/dist/team/__tests__/state-root.test.js +13 -0
  373. package/dist/team/__tests__/state-root.test.js.map +1 -1
  374. package/dist/team/__tests__/state.test.js +13 -0
  375. package/dist/team/__tests__/state.test.js.map +1 -1
  376. package/dist/team/__tests__/team-identity.test.d.ts +2 -0
  377. package/dist/team/__tests__/team-identity.test.d.ts.map +1 -0
  378. package/dist/team/__tests__/team-identity.test.js +166 -0
  379. package/dist/team/__tests__/team-identity.test.js.map +1 -0
  380. package/dist/team/__tests__/tmux-session.test.js +58 -1
  381. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  382. package/dist/team/__tests__/worker-bootstrap.test.js +62 -0
  383. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  384. package/dist/team/api-interop.d.ts +1 -0
  385. package/dist/team/api-interop.d.ts.map +1 -1
  386. package/dist/team/api-interop.js +163 -132
  387. package/dist/team/api-interop.js.map +1 -1
  388. package/dist/team/approved-execution.d.ts +37 -0
  389. package/dist/team/approved-execution.d.ts.map +1 -0
  390. package/dist/team/approved-execution.js +136 -0
  391. package/dist/team/approved-execution.js.map +1 -0
  392. package/dist/team/delivery-log.d.ts +1 -1
  393. package/dist/team/delivery-log.d.ts.map +1 -1
  394. package/dist/team/delivery-log.js +2 -1
  395. package/dist/team/delivery-log.js.map +1 -1
  396. package/dist/team/followup-planner.js +2 -2
  397. package/dist/team/followup-planner.js.map +1 -1
  398. package/dist/team/goal-workflow.d.ts +20 -0
  399. package/dist/team/goal-workflow.d.ts.map +1 -0
  400. package/dist/team/goal-workflow.js +57 -0
  401. package/dist/team/goal-workflow.js.map +1 -0
  402. package/dist/team/orchestrator.js +2 -2
  403. package/dist/team/orchestrator.js.map +1 -1
  404. package/dist/team/repo-aware-decomposition.d.ts +3 -0
  405. package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
  406. package/dist/team/repo-aware-decomposition.js +2 -0
  407. package/dist/team/repo-aware-decomposition.js.map +1 -1
  408. package/dist/team/role-router.js +5 -5
  409. package/dist/team/role-router.js.map +1 -1
  410. package/dist/team/runtime-cli.d.ts +32 -2
  411. package/dist/team/runtime-cli.d.ts.map +1 -1
  412. package/dist/team/runtime-cli.js +78 -26
  413. package/dist/team/runtime-cli.js.map +1 -1
  414. package/dist/team/runtime.d.ts +7 -1
  415. package/dist/team/runtime.d.ts.map +1 -1
  416. package/dist/team/runtime.js +383 -40
  417. package/dist/team/runtime.js.map +1 -1
  418. package/dist/team/scaling.d.ts.map +1 -1
  419. package/dist/team/scaling.js +2 -0
  420. package/dist/team/scaling.js.map +1 -1
  421. package/dist/team/state.d.ts +9 -0
  422. package/dist/team/state.d.ts.map +1 -1
  423. package/dist/team/state.js +21 -0
  424. package/dist/team/state.js.map +1 -1
  425. package/dist/team/team-identity.d.ts +26 -0
  426. package/dist/team/team-identity.d.ts.map +1 -0
  427. package/dist/team/team-identity.js +169 -0
  428. package/dist/team/team-identity.js.map +1 -0
  429. package/dist/team/tmux-session.d.ts +18 -0
  430. package/dist/team/tmux-session.d.ts.map +1 -1
  431. package/dist/team/tmux-session.js +65 -3
  432. package/dist/team/tmux-session.js.map +1 -1
  433. package/dist/team/worker-bootstrap.d.ts +4 -0
  434. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  435. package/dist/team/worker-bootstrap.js +28 -2
  436. package/dist/team/worker-bootstrap.js.map +1 -1
  437. package/dist/ultragoal/__tests__/artifacts.test.d.ts +2 -0
  438. package/dist/ultragoal/__tests__/artifacts.test.d.ts.map +1 -0
  439. package/dist/ultragoal/__tests__/artifacts.test.js +93 -0
  440. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -0
  441. package/dist/ultragoal/artifacts.d.ts +89 -0
  442. package/dist/ultragoal/artifacts.d.ts.map +1 -0
  443. package/dist/ultragoal/artifacts.js +233 -0
  444. package/dist/ultragoal/artifacts.js.map +1 -0
  445. package/dist/utils/__tests__/agents-model-table.test.js +3 -1
  446. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  447. package/dist/utils/__tests__/paths.test.js +31 -1
  448. package/dist/utils/__tests__/paths.test.js.map +1 -1
  449. package/dist/utils/agents-model-table.d.ts.map +1 -1
  450. package/dist/utils/agents-model-table.js +12 -1
  451. package/dist/utils/agents-model-table.js.map +1 -1
  452. package/dist/utils/paths.d.ts +2 -0
  453. package/dist/utils/paths.d.ts.map +1 -1
  454. package/dist/utils/paths.js +23 -7
  455. package/dist/utils/paths.js.map +1 -1
  456. package/dist/verification/__tests__/ci-rust-gates.test.js +30 -19
  457. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  458. package/package.json +5 -5
  459. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  460. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +30 -5
  461. package/plugins/oh-my-codex/skills/ask/SKILL.md +58 -0
  462. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +36 -0
  463. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +2 -2
  464. package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +65 -0
  465. package/plugins/oh-my-codex/skills/plan/SKILL.md +1 -1
  466. package/plugins/oh-my-codex/skills/ralph/SKILL.md +22 -3
  467. package/plugins/oh-my-codex/skills/team/SKILL.md +6 -2
  468. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +49 -0
  469. package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +9 -9
  470. package/prompts/api-reviewer.md +1 -1
  471. package/prompts/code-reviewer.md +2 -0
  472. package/prompts/performance-reviewer.md +1 -1
  473. package/prompts/quality-reviewer.md +1 -1
  474. package/prompts/quality-strategist.md +2 -2
  475. package/prompts/style-reviewer.md +1 -1
  476. package/prompts/test-engineer.md +1 -1
  477. package/skills/ai-slop-cleaner/SKILL.md +30 -5
  478. package/skills/ask/SKILL.md +58 -0
  479. package/skills/ask-claude/SKILL.md +3 -54
  480. package/skills/ask-gemini/SKILL.md +3 -54
  481. package/skills/autoresearch-goal/SKILL.md +36 -0
  482. package/skills/build-fix/SKILL.md +4 -139
  483. package/skills/deepsearch/SKILL.md +4 -32
  484. package/skills/ecomode/SKILL.md +4 -108
  485. package/skills/help/SKILL.md +4 -196
  486. package/skills/note/SKILL.md +4 -56
  487. package/skills/omx-setup/SKILL.md +2 -2
  488. package/skills/performance-goal/SKILL.md +65 -0
  489. package/skills/plan/SKILL.md +1 -1
  490. package/skills/ralph/SKILL.md +22 -3
  491. package/skills/ralph-init/SKILL.md +4 -40
  492. package/skills/review/SKILL.md +4 -32
  493. package/skills/security-review/SKILL.md +4 -294
  494. package/skills/swarm/SKILL.md +4 -19
  495. package/skills/tdd/SKILL.md +4 -100
  496. package/skills/team/SKILL.md +6 -2
  497. package/skills/trace/SKILL.md +4 -27
  498. package/skills/ultragoal/SKILL.md +49 -0
  499. package/skills/visual-ralph/SKILL.md +9 -9
  500. package/skills/visual-verdict/SKILL.md +4 -70
  501. package/skills/web-clone/SKILL.md +4 -18
  502. package/src/scripts/__tests__/codex-native-hook.test.ts +2923 -1030
  503. package/src/scripts/__tests__/hook-derived-watcher.test.ts +45 -1
  504. package/src/scripts/__tests__/run-test-files.test.ts +46 -0
  505. package/src/scripts/codex-native-hook.ts +696 -46
  506. package/src/scripts/codex-native-pre-post.ts +369 -16
  507. package/src/scripts/hook-derived-watcher.ts +2 -1
  508. package/src/scripts/notify-fallback-watcher.ts +2 -1
  509. package/src/scripts/notify-hook/orchestration-intent.ts +1 -3
  510. package/src/scripts/notify-hook/team-leader-nudge.ts +7 -63
  511. package/src/scripts/notify-hook/team-worker-posttooluse.ts +1 -1
  512. package/src/scripts/notify-hook/team-worker-stop.ts +246 -0
  513. package/src/scripts/notify-hook/team-worker.ts +23 -14
  514. package/src/scripts/notify-hook.ts +1 -1
  515. package/src/scripts/run-test-files.ts +20 -1
  516. package/src/scripts/sync-plugin-mirror.ts +13 -4
  517. package/templates/catalog-manifest.json +45 -27
  518. package/plugins/oh-my-codex/skills/ask-claude/SKILL.md +0 -61
  519. package/plugins/oh-my-codex/skills/ask-gemini/SKILL.md +0 -61
  520. package/plugins/oh-my-codex/skills/help/SKILL.md +0 -202
  521. package/plugins/oh-my-codex/skills/note/SKILL.md +0 -62
  522. package/plugins/oh-my-codex/skills/security-review/SKILL.md +0 -300
  523. package/plugins/oh-my-codex/skills/trace/SKILL.md +0 -33
  524. package/plugins/oh-my-codex/skills/visual-verdict/SKILL.md +0 -76
@@ -1,10 +1,10 @@
1
1
  import { execFileSync } from "child_process";
2
2
  import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
3
3
  import { mkdir, readFile, readdir, writeFile } from "fs/promises";
4
- import { join, relative, resolve } from "path";
4
+ import { extname, join, relative, resolve } from "path";
5
5
  import { pathToFileURL } from "url";
6
- import { readModeState, readModeStateForSession, updateModeState } from "../modes/base.js";
7
- import { listActiveSkills, readVisibleSkillActiveState, } from "../state/skill-active.js";
6
+ import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
7
+ import { extractSessionIdFromInitializedStatePath, listActiveSkills, readVisibleSkillActiveState, } from "../state/skill-active.js";
8
8
  import { readSubagentSessionSummary, recordSubagentTurnForSession, } from "../subagents/tracker.js";
9
9
  import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
10
10
  import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
@@ -14,14 +14,15 @@ import { findGitLayout } from "../utils/git-layout.js";
14
14
  import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
15
15
  import { detectKeywords, detectPrimaryKeyword, recordSkillActivation, } from "../hooks/keyword-detector.js";
16
16
  import { detectNativeStopStallPattern, loadAutoNudgeConfig, normalizeAutoNudgeSignatureText, resolveEffectiveAutoNudgeResponse, } from "./notify-hook/auto-nudge.js";
17
- import { buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTransportFailure, } from "./codex-native-pre-post.js";
17
+ import { SLOPPY_FALLBACK_GROUNDING_PATTERNS, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS, SLOPPY_FALLBACK_PHRASE_PATTERNS, buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTransportFailure, hasAnyPattern, } from "./codex-native-pre-post.js";
18
18
  import { handleTeamWorkerPostToolUseSuccess } from "./notify-hook/team-worker-posttooluse.js";
19
+ import { maybeNudgeLeaderForAllowedWorkerStop } from "./notify-hook/team-worker-stop.js";
19
20
  import { resolveCodexExecutionSurface, } from "./codex-execution-surface.js";
20
21
  import { buildNativeHookEvent, } from "../hooks/extensibility/events.js";
21
- import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
22
+ import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
22
23
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
23
24
  import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
24
- import { readAutoresearchCompletionStatus, readAutoresearchModeState } from "../autoresearch/skill-validation.js";
25
+ import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
25
26
  import { readRunState } from "../runtime/run-state.js";
26
27
  import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
27
28
  import { triagePrompt } from "../hooks/triage-heuristic.js";
@@ -30,9 +31,10 @@ import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignat
30
31
  import { isPendingDeepInterviewQuestionEnforcement, reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords, } from "../question/deep-interview.js";
31
32
  import { buildDocumentRefreshAdvisoryOutput, evaluateFinalHandoffDocumentRefresh, isFinalHandoffDocumentRefreshCandidate, } from "../document-refresh/enforcer.js";
32
33
  import { buildExecFollowupStopOutput } from "../exec/followup.js";
33
- const TERMINAL_MODE_PHASES = new Set(["complete", "failed", "cancelled"]);
34
+ const TERMINAL_MODE_PHASES = new Set(["complete", "completed", "failed", "cancelled"]);
34
35
  const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
35
- const TEAM_TERMINAL_TASK_STATUSES = new Set(["completed", "failed"]);
36
+ const TEAM_STOP_BLOCKING_TASK_STATUSES = new Set(["pending", "in_progress", "blocked"]);
37
+ const TEAM_WORKER_TERMINAL_RUN_STATES = new Set(["done", "complete", "completed", "failed", "stopped", "cancelled"]);
36
38
  const NATIVE_STOP_STATE_FILE = "native-stop-state.json";
37
39
  const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
38
40
  /^\s*(?:launch|release|ship)-?ready\s*:\s*(?:yes|no)\b[^\n\r]*/im,
@@ -159,6 +161,20 @@ async function nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonica
159
161
  return true;
160
162
  return summary.allThreadIds.includes(parentThreadId);
161
163
  }
164
+ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId) {
165
+ const sessionId = canonicalSessionId.trim();
166
+ if (!sessionId)
167
+ return false;
168
+ const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
169
+ if (!summary)
170
+ return false;
171
+ const candidateIds = [nativeSessionId, threadId]
172
+ .map((value) => value.trim())
173
+ .filter(Boolean);
174
+ if (candidateIds.length === 0)
175
+ return false;
176
+ return candidateIds.some((id) => summary.allSubagentThreadIds.includes(id));
177
+ }
162
178
  async function recordIgnoredNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
163
179
  await appendToLog(cwd, {
164
180
  event: "subagent_session_start_ignored",
@@ -302,7 +318,7 @@ async function readActiveAutoresearchState(cwd, sessionId) {
302
318
  const normalizedSessionId = sessionId?.trim() || undefined;
303
319
  if (!normalizedSessionId)
304
320
  return null;
305
- const state = await readAutoresearchModeState(cwd, normalizedSessionId);
321
+ const state = await readAutoresearchModeStateForActiveDecision(cwd, normalizedSessionId);
306
322
  if (state?.active !== true)
307
323
  return null;
308
324
  if (!isNonTerminalPhase(state.current_phase ?? state.currentPhase ?? 'executing'))
@@ -312,6 +328,38 @@ async function readActiveAutoresearchState(cwd, sessionId) {
312
328
  function isRalphStartingPhase(state) {
313
329
  return safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase() === "starting";
314
330
  }
331
+ function hasValue(values, value) {
332
+ return value !== "" && values.some((candidate) => candidate === value);
333
+ }
334
+ function activeRalphStateMatchesStopOwner(state, context) {
335
+ const ownerOmxSessionId = safeString(state.owner_omx_session_id).trim();
336
+ if (ownerOmxSessionId && ownerOmxSessionId !== context.sessionId) {
337
+ return false;
338
+ }
339
+ const stateSessionId = safeString(state.session_id).trim();
340
+ if (!ownerOmxSessionId && stateSessionId && stateSessionId !== context.sessionId) {
341
+ return false;
342
+ }
343
+ const codexOwnerSessionId = safeString(state.owner_codex_session_id).trim();
344
+ if (codexOwnerSessionId) {
345
+ const stopCodexSessionIds = [
346
+ context.payloadSessionId,
347
+ context.currentNativeSessionId,
348
+ context.sessionId,
349
+ ].filter(Boolean);
350
+ if (!hasValue(stopCodexSessionIds, codexOwnerSessionId))
351
+ return false;
352
+ }
353
+ const stateThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
354
+ if (stateThreadId && context.threadId && stateThreadId !== context.threadId) {
355
+ return false;
356
+ }
357
+ const statePaneId = safeString(state.tmux_pane_id).trim();
358
+ if (statePaneId && context.tmuxPaneId && statePaneId !== context.tmuxPaneId) {
359
+ return false;
360
+ }
361
+ return true;
362
+ }
315
363
  function shouldHonorCanonicalTerminalRunState(runState, mode) {
316
364
  if (!runState)
317
365
  return false;
@@ -334,13 +382,26 @@ async function isVisibleRalphActiveForSession(cwd, sessionId) {
334
382
  return listActiveSkills(canonicalState).some((entry) => (entry.skill === "ralph"
335
383
  && matchesSkillStopContext(entry, canonicalState, sessionId, "")));
336
384
  }
337
- async function readActiveRalphState(stateDir, preferredSessionId) {
385
+ async function hasConsistentRalphSkillActivation(cwd, sessionId) {
386
+ const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
387
+ if (!canonicalState)
388
+ return true;
389
+ const initializedMode = safeString(canonicalState.initialized_mode).trim();
390
+ if (initializedMode && initializedMode !== "ralph")
391
+ return true;
392
+ const initializedPathSessionId = extractSessionIdFromInitializedStatePath(canonicalState.initialized_state_path);
393
+ if (initializedPathSessionId && initializedPathSessionId !== sessionId)
394
+ return false;
395
+ return true;
396
+ }
397
+ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext) {
338
398
  const cwd = resolve(stateDir, "..", "..");
339
399
  const [rawSessionInfo, usableSessionInfo] = await Promise.all([
340
400
  readSessionState(cwd),
341
401
  readUsableSessionState(cwd),
342
402
  ]);
343
403
  const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
404
+ const currentNativeSessionId = safeString(usableSessionInfo?.native_session_id).trim();
344
405
  const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
345
406
  ? safeString(rawSessionInfo.session_id).trim()
346
407
  : "";
@@ -365,7 +426,16 @@ async function readActiveRalphState(stateDir, preferredSessionId) {
365
426
  && !(await isVisibleRalphActiveForSession(cwd, sessionId))) {
366
427
  continue;
367
428
  }
368
- if (sessionScoped?.active === true && shouldContinueRun(sessionScoped)) {
429
+ if (sessionScoped?.active === true
430
+ && shouldContinueRun(sessionScoped)
431
+ && activeRalphStateMatchesStopOwner(sessionScoped, {
432
+ sessionId,
433
+ payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
434
+ threadId: safeString(ownerContext?.threadId).trim(),
435
+ currentNativeSessionId,
436
+ tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
437
+ })
438
+ && await hasConsistentRalphSkillActivation(cwd, sessionId)) {
369
439
  return { state: sessionScoped, path: sessionScopedPath };
370
440
  }
371
441
  }
@@ -480,6 +550,182 @@ function tryReadGitValue(cwd, args) {
480
550
  return null;
481
551
  }
482
552
  }
553
+ const SOURCE_DIFF_EXTENSIONS = new Set([
554
+ ".c",
555
+ ".cc",
556
+ ".cjs",
557
+ ".cpp",
558
+ ".cs",
559
+ ".cts",
560
+ ".go",
561
+ ".h",
562
+ ".hpp",
563
+ ".java",
564
+ ".js",
565
+ ".jsx",
566
+ ".kt",
567
+ ".mjs",
568
+ ".mts",
569
+ ".php",
570
+ ".py",
571
+ ".rb",
572
+ ".rs",
573
+ ".sh",
574
+ ".swift",
575
+ ".ts",
576
+ ".tsx",
577
+ ]);
578
+ function gitOutput(cwd, args) {
579
+ try {
580
+ return execFileSync("git", args, {
581
+ cwd,
582
+ encoding: "utf-8",
583
+ stdio: ["ignore", "pipe", "ignore"],
584
+ windowsHide: true,
585
+ maxBuffer: 10 * 1024 * 1024,
586
+ });
587
+ }
588
+ catch {
589
+ return "";
590
+ }
591
+ }
592
+ function normalizeGitPath(path) {
593
+ return path.replace(/\\/g, "/").replace(/^\.\//, "");
594
+ }
595
+ function isDiffAuditableSourcePath(path) {
596
+ const normalized = normalizeGitPath(path).toLowerCase();
597
+ if (!normalized || normalized.startsWith(".git/") || normalized.startsWith(".omx/"))
598
+ return false;
599
+ if (/(^|\/)(?:docs?|documentation|changelog|changeset|\.github)(?:\/|$)/i.test(normalized))
600
+ return false;
601
+ if (/(^|\/)(?:__tests__|__test__|test|tests|spec|specs|fixtures?|mocks?)(?:\/|$)/i.test(normalized))
602
+ return false;
603
+ if (/(?:^|\/)[^\/]+\.(?:test|spec)\.[^.\/]+$/i.test(normalized))
604
+ return false;
605
+ if (/(?:^|\/)(?:readme|changelog|changes|license|notice)(?:\.[^\/]*)?$/i.test(normalized))
606
+ return false;
607
+ if (/\.(?:md|mdx|markdown|txt|rst|adoc|ya?ml|json|lock)$/i.test(normalized))
608
+ return false;
609
+ return SOURCE_DIFF_EXTENSIONS.has(extname(normalized));
610
+ }
611
+ function isDiffHeaderLine(line) {
612
+ return line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git ");
613
+ }
614
+ function isSuspiciousSloppyFallbackAddedLine(line, nearbyContext) {
615
+ const trimmed = line.trim();
616
+ if (!trimmed)
617
+ return false;
618
+ if (!hasAnyPattern(trimmed, SLOPPY_FALLBACK_PHRASE_PATTERNS))
619
+ return false;
620
+ if (!hasAnyPattern(trimmed, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS))
621
+ return false;
622
+ if (hasAnyPattern(nearbyContext, SLOPPY_FALLBACK_GROUNDING_PATTERNS))
623
+ return false;
624
+ if (/compatib(?:le|ility)|fail-?safe|tested|regression|coverage|because|issue|PR\s*#?\d|#\d/i.test(nearbyContext))
625
+ return false;
626
+ return true;
627
+ }
628
+ function collectFindingsFromCandidateLines(path, lines, source) {
629
+ if (!path || !isDiffAuditableSourcePath(path))
630
+ return [];
631
+ const findings = [];
632
+ for (let index = 0; index < lines.length; index += 1) {
633
+ const candidate = lines[index];
634
+ if (!candidate?.added)
635
+ continue;
636
+ const nearbyContext = lines
637
+ .slice(Math.max(0, index - 2), Math.min(lines.length, index + 3))
638
+ .map((line) => line.text)
639
+ .join("\n");
640
+ if (isSuspiciousSloppyFallbackAddedLine(candidate.text, nearbyContext)) {
641
+ findings.push({ path, line: candidate.text.trim(), source });
642
+ }
643
+ }
644
+ return findings;
645
+ }
646
+ function collectSloppyFallbackFindingsFromPatch(patch, source) {
647
+ const findings = [];
648
+ let currentPath = "";
649
+ let hunkLines = [];
650
+ const flushHunk = () => {
651
+ findings.push(...collectFindingsFromCandidateLines(currentPath, hunkLines, source));
652
+ hunkLines = [];
653
+ };
654
+ for (const rawLine of patch.split(/\r?\n/)) {
655
+ const fileMatch = rawLine.match(/^diff --git a\/(.*?) b\/(.*)$/);
656
+ if (fileMatch) {
657
+ flushHunk();
658
+ currentPath = normalizeGitPath(fileMatch[2] || fileMatch[1] || "");
659
+ continue;
660
+ }
661
+ const renameMatch = rawLine.match(/^\+\+\+ b\/(.*)$/);
662
+ if (renameMatch) {
663
+ currentPath = normalizeGitPath(renameMatch[1] || currentPath);
664
+ continue;
665
+ }
666
+ if (rawLine.startsWith("@@")) {
667
+ flushHunk();
668
+ continue;
669
+ }
670
+ if (!currentPath || !isDiffAuditableSourcePath(currentPath) || isDiffHeaderLine(rawLine))
671
+ continue;
672
+ if (rawLine.startsWith("+")) {
673
+ hunkLines.push({ text: rawLine.slice(1), added: true });
674
+ }
675
+ else if (rawLine.startsWith(" ")) {
676
+ hunkLines.push({ text: rawLine.slice(1), added: false });
677
+ }
678
+ }
679
+ flushHunk();
680
+ return findings;
681
+ }
682
+ function collectSloppyFallbackFindingsFromUntracked(cwd) {
683
+ const output = gitOutput(cwd, ["ls-files", "--others", "--exclude-standard", "-z"]);
684
+ if (!output)
685
+ return [];
686
+ const findings = [];
687
+ for (const rawPath of output.split("\0")) {
688
+ const path = normalizeGitPath(rawPath.trim());
689
+ if (!path || !isDiffAuditableSourcePath(path))
690
+ continue;
691
+ let content = "";
692
+ try {
693
+ content = readFileSync(join(cwd, path), "utf-8");
694
+ }
695
+ catch {
696
+ continue;
697
+ }
698
+ findings.push(...collectFindingsFromCandidateLines(path, content.split(/\r?\n/).map((text) => ({ text, added: true })), "untracked"));
699
+ }
700
+ return findings;
701
+ }
702
+ function findSloppyFallbackDiffFindings(cwd) {
703
+ const layout = findGitLayout(cwd);
704
+ if (!layout)
705
+ return [];
706
+ const auditRoot = layout.worktreeRoot;
707
+ return [
708
+ ...collectSloppyFallbackFindingsFromPatch(gitOutput(auditRoot, ["diff", "--cached", "--no-ext-diff", "--unified=3"]), "staged"),
709
+ ...collectSloppyFallbackFindingsFromPatch(gitOutput(auditRoot, ["diff", "--no-ext-diff", "--unified=3"]), "unstaged"),
710
+ ...collectSloppyFallbackFindingsFromUntracked(auditRoot),
711
+ ];
712
+ }
713
+ function buildSloppyFallbackDiffStopOutput(findings) {
714
+ if (findings.length === 0)
715
+ return null;
716
+ const preview = findings
717
+ .slice(0, 3)
718
+ .map((finding) => `${finding.path} (${finding.source}): ${finding.line}`)
719
+ .join("; ");
720
+ const systemMessage = `Sloppy fallback/workaround diff audit detected ungrounded fallback code in added source lines: ${preview}. `
721
+ + "Continue by replacing the bypass/workaround with a grounded design, or add explicit compatibility/fail-safe/tested/issue rationale near the code if the fallback is intentional.";
722
+ return {
723
+ decision: "block",
724
+ reason: systemMessage,
725
+ stopReason: "sloppy_fallback_diff_audit",
726
+ systemMessage,
727
+ };
728
+ }
483
729
  function localExcludeAlreadyIgnoresOmx(cwd) {
484
730
  const layout = findGitLayout(cwd);
485
731
  if (!layout)
@@ -803,6 +1049,9 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
803
1049
  const ultraworkPromptActivationNote = skillState?.initialized_mode === "ultrawork"
804
1050
  ? "Ultrawork protocol: ground the task before editing, define pass/fail acceptance criteria, keep shared-file work local, and use direct-tool plus background evidence lanes only for truly independent work. Direct ultrawork provides lightweight verification only; Ralph owns persistence and the full verified-completion promise."
805
1051
  : null;
1052
+ const ultragoalPromptActivationNote = match.skill === "ultragoal"
1053
+ ? "Ultragoal protocol: use `omx ultragoal create-goals` / `complete-goals` / `checkpoint` for `.omx/ultragoal` artifacts, then use Codex goal model tools only from the active agent handoff (`get_goal`, `create_goal`, `update_goal`) and never overwrite a different active Codex goal."
1054
+ : null;
806
1055
  const combinedTransitionMessage = (() => {
807
1056
  if (!skillState?.transition_message)
808
1057
  return null;
@@ -830,6 +1079,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
830
1079
  ? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
831
1080
  : null,
832
1081
  promptPriorityMessage,
1082
+ ultragoalPromptActivationNote,
833
1083
  skillState.initialized_mode && skillState.initialized_state_path
834
1084
  ? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
835
1085
  : null,
@@ -854,6 +1104,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
854
1104
  initializedStateMessage,
855
1105
  deepInterviewPromptActivationNote,
856
1106
  ultraworkPromptActivationNote,
1107
+ ultragoalPromptActivationNote,
857
1108
  buildTeamRuntimeInstruction(cwd, payload),
858
1109
  buildTeamHelpInstruction(cwd, payload),
859
1110
  "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
@@ -870,11 +1121,12 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
870
1121
  `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`,
871
1122
  deepInterviewPromptActivationNote,
872
1123
  ultraworkPromptActivationNote,
1124
+ ultragoalPromptActivationNote,
873
1125
  ralphPromptActivationNote,
874
1126
  "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
875
1127
  ].join(" ");
876
1128
  }
877
- return [detectedKeywordMessage, promptPriorityMessage, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
1129
+ return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
878
1130
  }
879
1131
  function parseTeamWorkerEnv(rawValue) {
880
1132
  const match = /^([a-z0-9][a-z0-9-]{0,29})\/(worker-\d+)$/.exec(rawValue.trim());
@@ -886,20 +1138,51 @@ function parseTeamWorkerEnv(rawValue) {
886
1138
  };
887
1139
  }
888
1140
  async function resolveTeamStateDirForWorkerContext(cwd, workerContext) {
889
- return resolveWorkerNotifyTeamStateRootPath(cwd, workerContext, process.env);
1141
+ const resolved = await resolveWorkerNotifyTeamStateRootPath(cwd, workerContext, process.env).catch(() => null);
1142
+ if (resolved)
1143
+ return resolved;
1144
+ const explicit = safeString(process.env.OMX_TEAM_STATE_ROOT).trim();
1145
+ if (explicit) {
1146
+ const candidate = resolve(cwd, explicit);
1147
+ const workerRoot = join(candidate, "team", workerContext.teamName, "workers", workerContext.workerName);
1148
+ if (existsSync(workerRoot))
1149
+ return candidate;
1150
+ return candidate;
1151
+ }
1152
+ return null;
890
1153
  }
891
- async function buildTeamWorkerStopOutput(cwd) {
892
- const workerContext = parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER));
1154
+ async function resolveTeamWorkerStopDecision(cwd) {
1155
+ const workerContext = parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_INTERNAL_WORKER))
1156
+ || parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER));
893
1157
  if (!workerContext)
894
- return null;
1158
+ return { kind: "unresolved", reason: "missing_worker_context" };
1159
+ const blockWorkerStop = (reasonCode, detail, stateDirForDecision = join(cwd, ".omx", "state")) => ({
1160
+ kind: "blocked",
1161
+ stateDir: stateDirForDecision,
1162
+ workerContext,
1163
+ allowRepeatDuringStopHook: false,
1164
+ output: {
1165
+ decision: "block",
1166
+ reason: `OMX team worker ${workerContext.workerName} Stop cannot be allowed for ${reasonCode}: ${detail}. ` +
1167
+ "Continue the assigned task, repair worker state, or report a concrete blocker before stopping.",
1168
+ stopReason: `team_worker_${workerContext.workerName}_${reasonCode}`,
1169
+ systemMessage: `OMX team worker ${workerContext.workerName} Stop lacks completed task evidence (${reasonCode}).`,
1170
+ },
1171
+ });
895
1172
  const stateDir = await resolveTeamStateDirForWorkerContext(cwd, workerContext);
896
- if (!stateDir)
897
- return null;
1173
+ if (!stateDir) {
1174
+ return blockWorkerStop("missing_state_dir", "team state root could not be resolved");
1175
+ }
898
1176
  const workerRoot = join(stateDir, "team", workerContext.teamName, "workers", workerContext.workerName);
899
1177
  const [identity, status] = await Promise.all([
900
1178
  readJsonIfExists(join(workerRoot, "identity.json")),
901
1179
  readJsonIfExists(join(workerRoot, "status.json")),
902
1180
  ]);
1181
+ const workerRunState = safeString(status?.state).trim().toLowerCase();
1182
+ const workerRunStateIsTerminal = TEAM_WORKER_TERMINAL_RUN_STATES.has(workerRunState);
1183
+ if (!identity && !status && !existsSync(workerRoot)) {
1184
+ return blockWorkerStop("missing_worker_state", "worker identity/status state is missing", stateDir);
1185
+ }
903
1186
  const candidateTaskIds = new Set();
904
1187
  const currentTaskId = safeString(status?.current_task_id).trim();
905
1188
  if (currentTaskId)
@@ -910,22 +1193,57 @@ async function buildTeamWorkerStopOutput(cwd) {
910
1193
  if (normalized)
911
1194
  candidateTaskIds.add(normalized);
912
1195
  }
1196
+ const tasksDir = join(stateDir, "team", workerContext.teamName, "tasks");
1197
+ if (existsSync(tasksDir)) {
1198
+ const taskFiles = await readdir(tasksDir).catch(() => []);
1199
+ for (const entry of taskFiles) {
1200
+ if (!/^task-\d+\.json$/.test(entry))
1201
+ continue;
1202
+ const task = await readJsonIfExists(join(tasksDir, entry));
1203
+ const taskOwner = safeString(task?.owner).trim();
1204
+ const taskClaimOwner = safeString(safeObject(task?.claim).owner).trim();
1205
+ if (taskOwner !== workerContext.workerName && taskClaimOwner !== workerContext.workerName)
1206
+ continue;
1207
+ const idFromFile = /^task-(\d+)\.json$/.exec(entry)?.[1] ?? "";
1208
+ const taskId = safeString(task?.id).trim() || idFromFile;
1209
+ if (taskId)
1210
+ candidateTaskIds.add(taskId);
1211
+ }
1212
+ }
1213
+ if (candidateTaskIds.size === 0) {
1214
+ return blockWorkerStop("missing_task_assignment", "no current_task_id or assigned_tasks are recorded", stateDir);
1215
+ }
1216
+ let completedTaskCount = 0;
913
1217
  for (const taskId of candidateTaskIds) {
914
1218
  const task = await readJsonIfExists(join(stateDir, "team", workerContext.teamName, "tasks", `task-${taskId}.json`));
915
1219
  const statusValue = safeString(task?.status).trim().toLowerCase();
916
- if (!statusValue || TEAM_TERMINAL_TASK_STATUSES.has(statusValue))
1220
+ if (!statusValue) {
1221
+ return blockWorkerStop(`missing_task_state_${taskId}`, `task ${taskId} has no readable status`, stateDir);
1222
+ }
1223
+ if (statusValue === "completed") {
1224
+ completedTaskCount += 1;
917
1225
  continue;
1226
+ }
1227
+ if (!TEAM_STOP_BLOCKING_TASK_STATUSES.has(statusValue)) {
1228
+ return blockWorkerStop(`non_completed_task_${taskId}_${statusValue}`, `task ${taskId} is ${statusValue}, not completed`, stateDir);
1229
+ }
918
1230
  return {
919
- decision: "block",
920
- reason: `OMX team worker ${workerContext.workerName} is still assigned non-terminal task ${taskId} (${statusValue}); continue the current assigned task or report a concrete blocker before stopping.`,
921
- stopReason: `team_worker_${workerContext.workerName}_${taskId}_${statusValue}`,
922
- systemMessage: `OMX team worker ${workerContext.workerName} is still assigned task ${taskId} (${statusValue}).`,
1231
+ kind: "blocked",
1232
+ stateDir,
1233
+ workerContext,
1234
+ allowRepeatDuringStopHook: !workerRunStateIsTerminal,
1235
+ output: {
1236
+ decision: "block",
1237
+ reason: `OMX team worker ${workerContext.workerName} is still assigned non-terminal task ${taskId} (${statusValue}); continue the current assigned task or report a concrete blocker before stopping.`,
1238
+ stopReason: `team_worker_${workerContext.workerName}_${taskId}_${statusValue}`,
1239
+ systemMessage: `OMX team worker ${workerContext.workerName} is still assigned task ${taskId} (${statusValue}).`,
1240
+ },
923
1241
  };
924
1242
  }
925
- return null;
926
- }
927
- function hasTeamWorkerContext() {
928
- return parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER)) !== null;
1243
+ if (completedTaskCount === candidateTaskIds.size) {
1244
+ return { kind: "allowed", stateDir, workerContext };
1245
+ }
1246
+ return blockWorkerStop("missing_completed_task_evidence", "no referenced worker task is completed", stateDir);
929
1247
  }
930
1248
  function isStopExempt(payload) {
931
1249
  const candidates = [
@@ -944,9 +1262,7 @@ function isStopExempt(payload) {
944
1262
  || value.includes("limit"));
945
1263
  }
946
1264
  async function buildModeBasedStopOutput(mode, cwd, sessionId) {
947
- const state = sessionId
948
- ? await readModeStateForSession(mode, sessionId, cwd)
949
- : await readModeState(mode, cwd);
1265
+ const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
950
1266
  if (!state || !shouldContinueRun(state))
951
1267
  return null;
952
1268
  const phase = formatPhase(state.current_phase);
@@ -957,6 +1273,76 @@ async function buildModeBasedStopOutput(mode, cwd, sessionId) {
957
1273
  systemMessage: `OMX ${mode} is still active (phase: ${phase}).`,
958
1274
  };
959
1275
  }
1276
+ function looksLikeGoalCompletionPrompt(text) {
1277
+ return /\b(?:complete|checkpoint|finish|close|mark)\b.{0,80}\b(?:goal|ultragoal|performance-goal|autoresearch-goal)\b/i.test(text)
1278
+ || /\bupdate_goal\s*\(/i.test(text)
1279
+ || /\bomx\s+(?:ultragoal|performance-goal|autoresearch-goal)\s+(?:checkpoint|complete)\b/i.test(text);
1280
+ }
1281
+ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1282
+ const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
1283
+ const ultragoals = Array.isArray(ultragoal?.goals) ? ultragoal.goals.map(safeObject) : [];
1284
+ const activeUltragoal = ultragoals.find((goal) => safeString(goal.status) === "in_progress" || safeString(goal.id) === safeString(ultragoal?.activeGoalId));
1285
+ if (activeUltragoal) {
1286
+ return {
1287
+ workflow: "ultragoal",
1288
+ command: `omx ultragoal checkpoint --goal-id ${safeString(activeUltragoal.id) || "<goal-id>"} --status complete --codex-goal-json '<get_goal JSON or path>' --evidence '<evidence>'`,
1289
+ };
1290
+ }
1291
+ const performanceRoot = join(cwd, ".omx", "goals", "performance");
1292
+ for (const entry of await readdir(performanceRoot, { withFileTypes: true }).catch(() => [])) {
1293
+ if (!entry.isDirectory())
1294
+ continue;
1295
+ const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
1296
+ const status = safeString(state?.status);
1297
+ if (state?.workflow === "performance-goal" && status && status !== "complete") {
1298
+ return {
1299
+ workflow: "performance-goal",
1300
+ command: `omx performance-goal complete --slug ${safeString(state.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>' --evidence '<evidence>'`,
1301
+ };
1302
+ }
1303
+ }
1304
+ const autoresearchRoot = join(cwd, ".omx", "goals", "autoresearch");
1305
+ for (const entry of await readdir(autoresearchRoot, { withFileTypes: true }).catch(() => [])) {
1306
+ if (!entry.isDirectory())
1307
+ continue;
1308
+ const mission = await readJsonIfExists(join(autoresearchRoot, entry.name, "mission.json"));
1309
+ const status = safeString(mission?.status);
1310
+ if (mission?.workflow === "autoresearch-goal" && status && status !== "complete") {
1311
+ return {
1312
+ workflow: "autoresearch-goal",
1313
+ command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
1314
+ };
1315
+ }
1316
+ }
1317
+ return null;
1318
+ }
1319
+ async function buildGoalWorkflowReconciliationPromptWarning(cwd, prompt) {
1320
+ if (!looksLikeGoalCompletionPrompt(prompt))
1321
+ return null;
1322
+ const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
1323
+ if (!requirement)
1324
+ return null;
1325
+ return [
1326
+ `OMX ${requirement.workflow} goal workflow requires Codex goal snapshot reconciliation before completion.`,
1327
+ "Call get_goal, pass the resulting JSON or a path with --codex-goal-json, and do not rely on hooks or shell commands to mutate Codex-owned goal state.",
1328
+ `Required command shape: ${requirement.command}.`,
1329
+ ].join(" ");
1330
+ }
1331
+ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
1332
+ const lastAssistantMessage = safeString(payload.last_assistant_message ?? payload.lastAssistantMessage);
1333
+ if (!looksLikeGoalCompletionPrompt(lastAssistantMessage))
1334
+ return null;
1335
+ const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
1336
+ if (!requirement)
1337
+ return null;
1338
+ const systemMessage = `OMX ${requirement.workflow} requires get_goal snapshot reconciliation before completion; call get_goal and pass --codex-goal-json to ${requirement.command}. Hooks must not mutate Codex goal state.`;
1339
+ return {
1340
+ decision: "block",
1341
+ reason: systemMessage,
1342
+ stopReason: `${requirement.workflow}_codex_goal_snapshot_required`,
1343
+ systemMessage,
1344
+ };
1345
+ }
960
1346
  async function readTeamModeStateForStop(cwd, sessionId) {
961
1347
  const normalizedSessionId = safeString(sessionId).trim();
962
1348
  if (!normalizedSessionId) {
@@ -1080,6 +1466,28 @@ function matchesSkillStopContext(entry, state, sessionId, threadId) {
1080
1466
  }
1081
1467
  return true;
1082
1468
  }
1469
+ function modeStateMatchesSkillStopContext(state, cwd, sessionId) {
1470
+ const stateSessionId = safeString(state.owner_omx_session_id
1471
+ ?? state.session_id
1472
+ ?? state.codex_session_id
1473
+ ?? state.owner_codex_session_id).trim();
1474
+ if (sessionId && stateSessionId && stateSessionId !== sessionId)
1475
+ return false;
1476
+ const stateCwd = safeString(state.cwd
1477
+ ?? state.workingDirectory
1478
+ ?? state.working_directory
1479
+ ?? state.project_path).trim();
1480
+ if (stateCwd) {
1481
+ try {
1482
+ if (resolve(stateCwd) !== resolve(cwd))
1483
+ return false;
1484
+ }
1485
+ catch {
1486
+ return false;
1487
+ }
1488
+ }
1489
+ return true;
1490
+ }
1083
1491
  async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill) {
1084
1492
  const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
1085
1493
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
@@ -1087,15 +1495,29 @@ async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill)
1087
1495
  ? [requiredSkill]
1088
1496
  : [...SKILL_STOP_BLOCKERS];
1089
1497
  for (const skill of candidateSkills) {
1498
+ const terminalRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, skill);
1499
+ if (terminalRunState)
1500
+ continue;
1090
1501
  const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId);
1091
1502
  if (!modeState || modeState.active !== true)
1092
1503
  continue;
1504
+ if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
1505
+ continue;
1506
+ const modeSnapshot = getRunContinuationSnapshot(modeState);
1507
+ if (modeSnapshot?.terminal === true)
1508
+ continue;
1093
1509
  const phase = formatPhase(modeState.current_phase, formatPhase(visibleEntries.find((entry) => entry.skill === skill)?.phase, "planning"));
1094
1510
  if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
1095
1511
  continue;
1096
1512
  }
1097
1513
  if (!canonicalState) {
1098
- return { skill, phase };
1514
+ return {
1515
+ skill,
1516
+ phase,
1517
+ latestPlanPath: safeString(modeState.latest_plan_path ?? modeState.latestPlanPath).trim() || undefined,
1518
+ planningComplete: modeState.planning_complete === true || modeState.planningComplete === true,
1519
+ runOutcome: safeString(modeState.run_outcome ?? modeState.outcome).trim() || undefined,
1520
+ };
1099
1521
  }
1100
1522
  const blocker = visibleEntries.find((entry) => (entry.skill === skill
1101
1523
  && matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
@@ -1104,10 +1526,47 @@ async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill)
1104
1526
  return {
1105
1527
  skill,
1106
1528
  phase: formatPhase(modeState.current_phase ?? blocker.phase ?? canonicalState.phase, "planning"),
1529
+ latestPlanPath: safeString(modeState.latest_plan_path ?? modeState.latestPlanPath).trim() || undefined,
1530
+ planningComplete: modeState.planning_complete === true || modeState.planningComplete === true,
1531
+ runOutcome: safeString(modeState.run_outcome ?? modeState.outcome).trim() || undefined,
1107
1532
  };
1108
1533
  }
1109
1534
  return null;
1110
1535
  }
1536
+ function buildRalplanContinuationStatus(blocker, activeSubagentCount) {
1537
+ const phase = blocker.phase || "planning";
1538
+ const artifact = blocker.latestPlanPath
1539
+ ? ` Artifact: ${blocker.latestPlanPath}.`
1540
+ : " Artifact: use the latest `.omx/plans/` ralplan artifact if present.";
1541
+ if (activeSubagentCount > 0) {
1542
+ return {
1543
+ reason: `Status: waiting — ralplan is waiting for ${activeSubagentCount} active native subagent thread(s) to finish (phase: ${phase}). Do not stop silently; wait for the subagent result, then continue from the current ralplan artifact and proceed to the next planning/review step.${artifact}`,
1544
+ stopReasonSuffix: "waiting_subagent",
1545
+ systemMessage: `OMX ralplan status: waiting for ${activeSubagentCount} active native subagent thread(s) at phase ${phase}; after they finish, continue from the current ralplan artifact and state the next status explicitly.`,
1546
+ };
1547
+ }
1548
+ const normalizedPhase = phase.toLowerCase();
1549
+ const normalizedOutcome = (blocker.runOutcome ?? "").toLowerCase();
1550
+ const waitingForInput = normalizedOutcome === "blocked_on_user"
1551
+ || normalizedPhase.includes("blocked")
1552
+ || normalizedPhase.includes("input")
1553
+ || normalizedPhase.includes("question");
1554
+ if (waitingForInput) {
1555
+ return {
1556
+ reason: `Status: waiting_for_input — ralplan is paused for required user/operator input (phase: ${phase}). Ask the missing question or present the review choice explicitly before stopping.${artifact}`,
1557
+ stopReasonSuffix: "waiting_input",
1558
+ systemMessage: `OMX ralplan status: waiting for input at phase ${phase}; ask the required question or present the explicit review choice before stopping.`,
1559
+ };
1560
+ }
1561
+ const completeHint = blocker.planningComplete
1562
+ ? " The planning artifacts are present; if consensus is approved, emit the final complete/approved handoff instead of stopping here."
1563
+ : "";
1564
+ return {
1565
+ reason: `Status: continue_from_artifact — ralplan is still active (phase: ${phase}) and has not emitted a terminal complete/paused/waiting status. Continue from the current ralplan artifact, resolve any review ambiguity conservatively or ask the user if needed, and proceed to the next planning/review step before stopping.${artifact}${completeHint}`,
1566
+ stopReasonSuffix: "continue_artifact",
1567
+ systemMessage: `OMX ralplan status: continue_from_artifact at phase ${phase}; continue from the current ralplan artifact and finish by stating whether ralplan is complete, paused for review, waiting for input, or still continuing.`,
1568
+ };
1569
+ }
1111
1570
  async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
1112
1571
  const normalizedSessionId = sessionId.trim();
1113
1572
  if (normalizedSessionId) {
@@ -1176,13 +1635,20 @@ async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
1176
1635
  };
1177
1636
  }
1178
1637
  function resolveRepeatableStopSessionId(payload, canonicalSessionId) {
1179
- return canonicalSessionId?.trim() || readPayloadSessionId(payload) || "";
1638
+ const inheritedSessionId = safeString(process.env.OMX_SESSION_ID || process.env.CODEX_SESSION_ID).trim();
1639
+ return canonicalSessionId?.trim() || readPayloadSessionId(payload) || inheritedSessionId || "";
1640
+ }
1641
+ function isStateLevelStopSignatureKind(kind) {
1642
+ return kind === "team-worker-stop" || kind === "team-stop";
1180
1643
  }
1181
1644
  function buildRepeatableStopSignature(payload, kind, detail = "", canonicalSessionId) {
1182
1645
  const sessionId = resolveRepeatableStopSessionId(payload, canonicalSessionId) || "no-session";
1183
1646
  const threadId = readPayloadThreadId(payload) || "no-thread";
1184
- const turnId = readPayloadTurnId(payload);
1185
1647
  const normalizedDetail = normalizeAutoNudgeSignatureText(detail) || safeString(detail).trim().toLowerCase();
1648
+ if (isStateLevelStopSignatureKind(kind)) {
1649
+ return [kind, sessionId, threadId, normalizedDetail || "no-detail"].join("|");
1650
+ }
1651
+ const turnId = readPayloadTurnId(payload);
1186
1652
  const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim() || "no-transcript";
1187
1653
  const lastAssistantMessage = normalizeAutoNudgeSignatureText(payload.last_assistant_message ?? payload.lastAssistantMessage) || "no-message";
1188
1654
  if (turnId) {
@@ -1327,7 +1793,17 @@ async function buildSkillStopOutput(cwd, sessionId, threadId) {
1327
1793
  if (!blocker)
1328
1794
  return null;
1329
1795
  const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
1330
- if (subagentSummary && subagentSummary.activeSubagentThreadIds.length > 0) {
1796
+ const activeSubagentCount = subagentSummary?.activeSubagentThreadIds.length ?? 0;
1797
+ if (blocker.skill === "ralplan") {
1798
+ const status = buildRalplanContinuationStatus(blocker, activeSubagentCount);
1799
+ return {
1800
+ decision: "block",
1801
+ reason: status.reason,
1802
+ stopReason: `skill_${blocker.skill}_${blocker.phase}_${status.stopReasonSuffix}`,
1803
+ systemMessage: status.systemMessage,
1804
+ };
1805
+ }
1806
+ if (activeSubagentCount > 0) {
1331
1807
  return null;
1332
1808
  }
1333
1809
  return {
@@ -1414,7 +1890,7 @@ async function markTeamTransportFailure(cwd, payload) {
1414
1890
  // Canonical team state already carries the preserved failure for coarse-state-missing sessions.
1415
1891
  }
1416
1892
  }
1417
- async function buildStopHookOutput(payload, cwd, stateDir) {
1893
+ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
1418
1894
  if (isStopExempt(payload)) {
1419
1895
  return null;
1420
1896
  }
@@ -1424,7 +1900,13 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
1424
1900
  const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
1425
1901
  if (execFollowupOutput)
1426
1902
  return execFollowupOutput;
1427
- const ralphState = await readActiveRalphState(stateDir, canonicalSessionId);
1903
+ const ralphState = options.skipRalphStopBlock === true
1904
+ ? null
1905
+ : await readActiveRalphState(stateDir, canonicalSessionId, {
1906
+ payloadSessionId: sessionId,
1907
+ threadId,
1908
+ tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
1909
+ });
1428
1910
  if (!ralphState) {
1429
1911
  const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
1430
1912
  if (autoresearchState) {
@@ -1440,9 +1922,22 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
1440
1922
  }, canonicalSessionId, { allowRepeatDuringStopHook: true });
1441
1923
  }
1442
1924
  }
1443
- const teamWorkerOutput = await buildTeamWorkerStopOutput(cwd);
1444
- if (hasTeamWorkerContext() && teamWorkerOutput) {
1445
- return await returnPersistentStopBlock(payload, stateDir, "team-worker-stop", safeString(teamWorkerOutput.stopReason), teamWorkerOutput, canonicalSessionId, { allowRepeatDuringStopHook: false });
1925
+ const teamWorkerDecision = await resolveTeamWorkerStopDecision(cwd);
1926
+ if (teamWorkerDecision.kind === "blocked") {
1927
+ return await returnPersistentStopBlock(payload, stateDir, "team-worker-stop", safeString(teamWorkerDecision.output.stopReason), teamWorkerDecision.output, canonicalSessionId, { allowRepeatDuringStopHook: teamWorkerDecision.allowRepeatDuringStopHook });
1928
+ }
1929
+ if (teamWorkerDecision.kind === "allowed") {
1930
+ try {
1931
+ await maybeNudgeLeaderForAllowedWorkerStop({
1932
+ stateDir: teamWorkerDecision.stateDir,
1933
+ logsDir: join(cwd, ".omx", "logs"),
1934
+ workerContext: teamWorkerDecision.workerContext,
1935
+ });
1936
+ }
1937
+ catch (err) {
1938
+ void err;
1939
+ }
1940
+ return null;
1446
1941
  }
1447
1942
  const autopilotOutput = await buildModeBasedStopOutput("autopilot", cwd, canonicalSessionId);
1448
1943
  if (autopilotOutput) {
@@ -1483,6 +1978,10 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
1483
1978
  }
1484
1979
  }
1485
1980
  const lastAssistantMessage = safeString(payload.last_assistant_message ?? payload.lastAssistantMessage);
1981
+ const goalWorkflowStopOutput = await buildGoalWorkflowReconciliationStopOutput(payload, cwd);
1982
+ if (goalWorkflowStopOutput) {
1983
+ return await returnPersistentStopBlock(payload, stateDir, "goal-workflow-reconciliation-stop", safeString(goalWorkflowStopOutput.stopReason), goalWorkflowStopOutput, canonicalSessionId, { allowRepeatDuringStopHook: true });
1984
+ }
1486
1985
  const autoNudgeConfig = await loadAutoNudgeConfig();
1487
1986
  const autoNudgePhase = await readStopAutoNudgePhase(cwd, canonicalSessionId, threadId);
1488
1987
  if (autoNudgeConfig.enabled
@@ -1495,6 +1994,11 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
1495
1994
  systemMessage: "OMX native Stop detected a stall/permission-style handoff and continued the turn automatically.",
1496
1995
  }, canonicalSessionId);
1497
1996
  }
1997
+ const sloppyFallbackDiffFindings = findSloppyFallbackDiffFindings(cwd);
1998
+ const sloppyFallbackDiffOutput = buildSloppyFallbackDiffStopOutput(sloppyFallbackDiffFindings);
1999
+ if (sloppyFallbackDiffOutput) {
2000
+ return await returnPersistentStopBlock(payload, stateDir, "sloppy-fallback-diff-stop", JSON.stringify(sloppyFallbackDiffFindings), sloppyFallbackDiffOutput, canonicalSessionId, { allowRepeatDuringStopHook: true });
2001
+ }
1498
2002
  if (isFinalHandoffDocumentRefreshCandidate(lastAssistantMessage)) {
1499
2003
  const documentRefreshWarning = evaluateFinalHandoffDocumentRefresh(cwd, lastAssistantMessage);
1500
2004
  if (documentRefreshWarning) {
@@ -1522,6 +2026,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1522
2026
  const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
1523
2027
  let skillState = null;
1524
2028
  let triageAdditionalContext = null;
2029
+ let goalWorkflowAdditionalContext = null;
1525
2030
  const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
1526
2031
  const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
1527
2032
  const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
@@ -1557,7 +2062,8 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1557
2062
  canonicalSessionId = safeString(currentSessionState?.session_id).trim();
1558
2063
  }
1559
2064
  if (hookEventName === "Stop") {
1560
- const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd, readPayloadSessionId(payload));
2065
+ const inheritedSessionId = safeString(process.env.OMX_SESSION_ID || process.env.CODEX_SESSION_ID).trim();
2066
+ const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd, readPayloadSessionId(payload) || inheritedSessionId);
1561
2067
  if (stopCanonicalSessionId) {
1562
2068
  canonicalSessionId = stopCanonicalSessionId;
1563
2069
  }
@@ -1569,9 +2075,20 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1569
2075
  const eventSessionId = canonicalSessionId || nativeSessionId || undefined;
1570
2076
  const sessionIdForState = canonicalSessionId || nativeSessionId;
1571
2077
  let outputJson = null;
2078
+ const isSubagentPromptSubmit = hookEventName === "UserPromptSubmit"
2079
+ ? await isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId)
2080
+ : false;
2081
+ const isSubagentStop = hookEventName === "Stop"
2082
+ ? (await Promise.all([...new Set([
2083
+ canonicalSessionId,
2084
+ safeString(currentSessionState?.session_id).trim(),
2085
+ ].filter(Boolean))]
2086
+ .map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)))).some(Boolean)
2087
+ : false;
1572
2088
  if (hookEventName === "UserPromptSubmit") {
1573
2089
  const prompt = readPromptText(payload);
1574
- if (prompt) {
2090
+ goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
2091
+ if (prompt && !isSubagentPromptSubmit) {
1575
2092
  skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
1576
2093
  stateDir,
1577
2094
  text: prompt,
@@ -1581,7 +2098,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1581
2098
  });
1582
2099
  }
1583
2100
  // --- Triage classifier (advisory-only, non-keyword prompts) ---
1584
- if (prompt && skillState === null) {
2101
+ if (prompt && skillState === null && !isSubagentPromptSubmit) {
1585
2102
  try {
1586
2103
  if (readTriageConfig().enabled) {
1587
2104
  const normalized = prompt.trim().toLowerCase();
@@ -1673,7 +2190,11 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1673
2190
  turn_id: turnId || undefined,
1674
2191
  mode: safeString(payload.mode).trim() || undefined,
1675
2192
  });
1676
- await dispatchHookEvent(event, { cwd });
2193
+ await dispatchHookEventRuntime({
2194
+ event,
2195
+ cwd,
2196
+ allowTeamWorkerSideEffects: false,
2197
+ });
1677
2198
  }
1678
2199
  if ((hookEventName === "SessionStart" && !skipCanonicalSessionStartContext) || hookEventName === "UserPromptSubmit") {
1679
2200
  const additionalContext = hookEventName === "SessionStart"
@@ -1683,7 +2204,9 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1683
2204
  canonicalSessionId,
1684
2205
  nativeSessionId: resolvedNativeSessionId || nativeSessionId,
1685
2206
  })
1686
- : (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload) ?? triageAdditionalContext);
2207
+ : isSubagentPromptSubmit
2208
+ ? null
2209
+ : (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload) ?? goalWorkflowAdditionalContext ?? triageAdditionalContext);
1687
2210
  if (additionalContext) {
1688
2211
  outputJson = {
1689
2212
  hookSpecificOutput: {
@@ -1704,7 +2227,9 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1704
2227
  await handleTeamWorkerPostToolUseSuccess(payload, cwd);
1705
2228
  }
1706
2229
  else if (hookEventName === "Stop") {
1707
- outputJson = await buildStopHookOutput(payload, cwd, stateDir);
2230
+ outputJson = await buildStopHookOutput(payload, cwd, stateDir, {
2231
+ skipRalphStopBlock: isSubagentStop,
2232
+ });
1708
2233
  }
1709
2234
  return {
1710
2235
  hookEventName,