oh-my-codex 0.17.3 → 0.18.1

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 (381) hide show
  1. package/Cargo.lock +13 -5
  2. package/Cargo.toml +2 -1
  3. package/README.md +44 -19
  4. package/crates/omx-api/Cargo.toml +19 -0
  5. package/crates/omx-api/src/lib.rs +2997 -0
  6. package/crates/omx-api/src/main.rs +10 -0
  7. package/crates/omx-api/tests/cli.rs +558 -0
  8. package/crates/omx-explore/src/main.rs +4 -0
  9. package/crates/omx-sparkshell/src/codex_bridge.rs +437 -123
  10. package/crates/omx-sparkshell/src/exec.rs +127 -1
  11. package/crates/omx-sparkshell/src/main.rs +829 -30
  12. package/crates/omx-sparkshell/src/prompt.rs +25 -3
  13. package/crates/omx-sparkshell/src/redaction.rs +241 -0
  14. package/crates/omx-sparkshell/tests/execution.rs +702 -237
  15. package/dist/cli/__tests__/api.test.d.ts +2 -0
  16. package/dist/cli/__tests__/api.test.d.ts.map +1 -0
  17. package/dist/cli/__tests__/api.test.js +175 -0
  18. package/dist/cli/__tests__/api.test.js.map +1 -0
  19. package/dist/cli/__tests__/ask.test.js +72 -5
  20. package/dist/cli/__tests__/ask.test.js.map +1 -1
  21. package/dist/cli/__tests__/autoresearch-goal.test.js +14 -1
  22. package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
  23. package/dist/cli/__tests__/codex-plugin-layout.test.js +15 -7
  24. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  25. package/dist/cli/__tests__/doctor-warning-copy.test.js +76 -3
  26. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  27. package/dist/cli/__tests__/explore.test.js +23 -0
  28. package/dist/cli/__tests__/explore.test.js.map +1 -1
  29. package/dist/cli/__tests__/index.test.js +171 -5
  30. package/dist/cli/__tests__/index.test.js.map +1 -1
  31. package/dist/cli/__tests__/install-docs-contract.test.d.ts +2 -0
  32. package/dist/cli/__tests__/install-docs-contract.test.d.ts.map +1 -0
  33. package/dist/cli/__tests__/install-docs-contract.test.js +55 -0
  34. package/dist/cli/__tests__/install-docs-contract.test.js.map +1 -0
  35. package/dist/cli/__tests__/launch-fallback.test.js +191 -0
  36. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  37. package/dist/cli/__tests__/package-bin-contract.test.js +4 -3
  38. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  39. package/dist/cli/__tests__/question.test.js +27 -41
  40. package/dist/cli/__tests__/question.test.js.map +1 -1
  41. package/dist/cli/__tests__/setup-install-mode.test.js +232 -35
  42. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  43. package/dist/cli/__tests__/sparkshell-cli.test.js +25 -1
  44. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  45. package/dist/cli/__tests__/sparkshell-packaging.test.js +1 -0
  46. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -1
  47. package/dist/cli/__tests__/ultragoal.test.js +227 -4
  48. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  49. package/dist/cli/__tests__/update.test.js +72 -1
  50. package/dist/cli/__tests__/update.test.js.map +1 -1
  51. package/dist/cli/__tests__/version-sync-contract.test.js +4 -0
  52. package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
  53. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -1
  54. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  55. package/dist/cli/api.d.ts +26 -0
  56. package/dist/cli/api.d.ts.map +1 -0
  57. package/dist/cli/api.js +153 -0
  58. package/dist/cli/api.js.map +1 -0
  59. package/dist/cli/codex-feature-probe.d.ts +5 -0
  60. package/dist/cli/codex-feature-probe.d.ts.map +1 -1
  61. package/dist/cli/codex-feature-probe.js +13 -7
  62. package/dist/cli/codex-feature-probe.js.map +1 -1
  63. package/dist/cli/doctor.d.ts +7 -0
  64. package/dist/cli/doctor.d.ts.map +1 -1
  65. package/dist/cli/doctor.js +119 -10
  66. package/dist/cli/doctor.js.map +1 -1
  67. package/dist/cli/explore.d.ts +2 -0
  68. package/dist/cli/explore.d.ts.map +1 -1
  69. package/dist/cli/explore.js +43 -1
  70. package/dist/cli/explore.js.map +1 -1
  71. package/dist/cli/index.d.ts +12 -4
  72. package/dist/cli/index.d.ts.map +1 -1
  73. package/dist/cli/index.js +460 -87
  74. package/dist/cli/index.js.map +1 -1
  75. package/dist/cli/native-assets.d.ts +2 -1
  76. package/dist/cli/native-assets.d.ts.map +1 -1
  77. package/dist/cli/native-assets.js +1 -0
  78. package/dist/cli/native-assets.js.map +1 -1
  79. package/dist/cli/plugin-marketplace.d.ts +2 -0
  80. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  81. package/dist/cli/plugin-marketplace.js +15 -1
  82. package/dist/cli/plugin-marketplace.js.map +1 -1
  83. package/dist/cli/setup.d.ts.map +1 -1
  84. package/dist/cli/setup.js +71 -11
  85. package/dist/cli/setup.js.map +1 -1
  86. package/dist/cli/sparkshell.d.ts +7 -1
  87. package/dist/cli/sparkshell.d.ts.map +1 -1
  88. package/dist/cli/sparkshell.js +31 -4
  89. package/dist/cli/sparkshell.js.map +1 -1
  90. package/dist/cli/ultragoal.d.ts +1 -1
  91. package/dist/cli/ultragoal.d.ts.map +1 -1
  92. package/dist/cli/ultragoal.js +184 -10
  93. package/dist/cli/ultragoal.js.map +1 -1
  94. package/dist/cli/update.d.ts +2 -0
  95. package/dist/cli/update.d.ts.map +1 -1
  96. package/dist/cli/update.js +14 -3
  97. package/dist/cli/update.js.map +1 -1
  98. package/dist/compat/__tests__/doctor-contract.test.js +3 -0
  99. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  100. package/dist/config/__tests__/codex-feature-flags.test.js +11 -1
  101. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -1
  102. package/dist/config/__tests__/codex-hooks.test.js +19 -8
  103. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  104. package/dist/config/__tests__/commit-lore-guard.test.d.ts +2 -0
  105. package/dist/config/__tests__/commit-lore-guard.test.d.ts.map +1 -0
  106. package/dist/config/__tests__/commit-lore-guard.test.js +20 -0
  107. package/dist/config/__tests__/commit-lore-guard.test.js.map +1 -0
  108. package/dist/config/codex-feature-flags.d.ts +4 -0
  109. package/dist/config/codex-feature-flags.d.ts.map +1 -1
  110. package/dist/config/codex-feature-flags.js +4 -0
  111. package/dist/config/codex-feature-flags.js.map +1 -1
  112. package/dist/config/codex-hooks.js +6 -6
  113. package/dist/config/codex-hooks.js.map +1 -1
  114. package/dist/config/commit-lore-guard.d.ts +1 -0
  115. package/dist/config/commit-lore-guard.d.ts.map +1 -1
  116. package/dist/config/commit-lore-guard.js +29 -3
  117. package/dist/config/commit-lore-guard.js.map +1 -1
  118. package/dist/config/generator.d.ts +3 -1
  119. package/dist/config/generator.d.ts.map +1 -1
  120. package/dist/config/generator.js +114 -10
  121. package/dist/config/generator.js.map +1 -1
  122. package/dist/goal-workflows/codex-goal-snapshot.d.ts +1 -0
  123. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
  124. package/dist/goal-workflows/codex-goal-snapshot.js +5 -1
  125. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  126. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +10 -6
  127. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  128. package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts +2 -0
  129. package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts.map +1 -0
  130. package/dist/hooks/__tests__/best-practice-research-skill.test.js +27 -0
  131. package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -0
  132. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
  133. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +13 -11
  134. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  135. package/dist/hooks/__tests__/deep-interview-contract.test.js +4 -3
  136. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  137. package/dist/hooks/__tests__/keyword-detector.test.js +15 -3
  138. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  139. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +6 -0
  140. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  141. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +33 -0
  142. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  143. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +4 -0
  144. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  145. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +26 -3
  146. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
  147. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  148. package/dist/hooks/extensibility/dispatcher.js +29 -14
  149. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  150. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  151. package/dist/hooks/keyword-detector.js +8 -3
  152. package/dist/hooks/keyword-detector.js.map +1 -1
  153. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  154. package/dist/hooks/keyword-registry.js +1 -0
  155. package/dist/hooks/keyword-registry.js.map +1 -1
  156. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  157. package/dist/hooks/prompt-guidance-contract.js +3 -2
  158. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  159. package/dist/hud/__tests__/hud-tmux-injection.test.js +14 -8
  160. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  161. package/dist/hud/__tests__/reconcile.test.js +4 -4
  162. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  163. package/dist/hud/__tests__/resource-leak-watch.test.d.ts +2 -0
  164. package/dist/hud/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  165. package/dist/hud/__tests__/resource-leak-watch.test.js +28 -0
  166. package/dist/hud/__tests__/resource-leak-watch.test.js.map +1 -0
  167. package/dist/hud/__tests__/tmux.test.js +23 -18
  168. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  169. package/dist/hud/index.d.ts +1 -1
  170. package/dist/hud/index.d.ts.map +1 -1
  171. package/dist/hud/index.js +10 -4
  172. package/dist/hud/index.js.map +1 -1
  173. package/dist/hud/tmux.d.ts.map +1 -1
  174. package/dist/hud/tmux.js +9 -8
  175. package/dist/hud/tmux.js.map +1 -1
  176. package/dist/mcp/__tests__/bootstrap.test.js +75 -1
  177. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  178. package/dist/mcp/bootstrap.d.ts +3 -1
  179. package/dist/mcp/bootstrap.d.ts.map +1 -1
  180. package/dist/mcp/bootstrap.js +71 -2
  181. package/dist/mcp/bootstrap.js.map +1 -1
  182. package/dist/notifications/__tests__/http-client-resource.test.d.ts +2 -0
  183. package/dist/notifications/__tests__/http-client-resource.test.d.ts.map +1 -0
  184. package/dist/notifications/__tests__/http-client-resource.test.js +41 -0
  185. package/dist/notifications/__tests__/http-client-resource.test.js.map +1 -0
  186. package/dist/notifications/__tests__/verbosity.test.js +20 -0
  187. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  188. package/dist/notifications/config.d.ts.map +1 -1
  189. package/dist/notifications/config.js +6 -3
  190. package/dist/notifications/config.js.map +1 -1
  191. package/dist/notifications/http-client.d.ts.map +1 -1
  192. package/dist/notifications/http-client.js +78 -27
  193. package/dist/notifications/http-client.js.map +1 -1
  194. package/dist/notifications/types.d.ts +2 -0
  195. package/dist/notifications/types.d.ts.map +1 -1
  196. package/dist/openclaw/__tests__/dispatcher.test.js +49 -1
  197. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
  198. package/dist/openclaw/dispatcher.d.ts +7 -4
  199. package/dist/openclaw/dispatcher.d.ts.map +1 -1
  200. package/dist/openclaw/dispatcher.js +32 -69
  201. package/dist/openclaw/dispatcher.js.map +1 -1
  202. package/dist/pipeline/__tests__/orchestrator.test.js +65 -3
  203. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  204. package/dist/pipeline/__tests__/stages.test.js +50 -5
  205. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  206. package/dist/pipeline/index.d.ts +8 -2
  207. package/dist/pipeline/index.d.ts.map +1 -1
  208. package/dist/pipeline/index.js +5 -2
  209. package/dist/pipeline/index.js.map +1 -1
  210. package/dist/pipeline/orchestrator.d.ts +5 -4
  211. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  212. package/dist/pipeline/orchestrator.js +56 -15
  213. package/dist/pipeline/orchestrator.js.map +1 -1
  214. package/dist/pipeline/stages/code-review.d.ts +2 -2
  215. package/dist/pipeline/stages/code-review.d.ts.map +1 -1
  216. package/dist/pipeline/stages/code-review.js +5 -3
  217. package/dist/pipeline/stages/code-review.js.map +1 -1
  218. package/dist/pipeline/stages/deep-interview.d.ts +15 -0
  219. package/dist/pipeline/stages/deep-interview.d.ts.map +1 -0
  220. package/dist/pipeline/stages/deep-interview.js +32 -0
  221. package/dist/pipeline/stages/deep-interview.js.map +1 -0
  222. package/dist/pipeline/stages/ralph-verify.d.ts +5 -5
  223. package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
  224. package/dist/pipeline/stages/ralph-verify.js +2 -2
  225. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  226. package/dist/pipeline/stages/ultragoal.d.ts +19 -0
  227. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -0
  228. package/dist/pipeline/stages/ultragoal.js +38 -0
  229. package/dist/pipeline/stages/ultragoal.js.map +1 -0
  230. package/dist/pipeline/stages/ultraqa.d.ts +30 -0
  231. package/dist/pipeline/stages/ultraqa.d.ts.map +1 -0
  232. package/dist/pipeline/stages/ultraqa.js +46 -0
  233. package/dist/pipeline/stages/ultraqa.js.map +1 -0
  234. package/dist/pipeline/types.d.ts +8 -6
  235. package/dist/pipeline/types.d.ts.map +1 -1
  236. package/dist/pipeline/types.js +2 -2
  237. package/dist/scripts/__tests__/codex-native-hook.test.js +1488 -117
  238. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  239. package/dist/scripts/__tests__/notify-dispatcher.test.js +183 -1
  240. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  241. package/dist/scripts/__tests__/smoke-packed-install.test.js +27 -2
  242. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  243. package/dist/scripts/__tests__/verify-native-agents.test.js +16 -1
  244. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  245. package/dist/scripts/build-api.d.ts +2 -0
  246. package/dist/scripts/build-api.d.ts.map +1 -0
  247. package/dist/scripts/build-api.js +44 -0
  248. package/dist/scripts/build-api.js.map +1 -0
  249. package/dist/scripts/cleanup-explore-harness.js +1 -0
  250. package/dist/scripts/cleanup-explore-harness.js.map +1 -1
  251. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  252. package/dist/scripts/codex-native-hook.js +364 -16
  253. package/dist/scripts/codex-native-hook.js.map +1 -1
  254. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  255. package/dist/scripts/codex-native-pre-post.js +98 -25
  256. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  257. package/dist/scripts/notify-dispatcher.js +88 -0
  258. package/dist/scripts/notify-dispatcher.js.map +1 -1
  259. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
  260. package/dist/scripts/notify-hook/process-runner.js +39 -17
  261. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  262. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  263. package/dist/scripts/notify-hook/team-dispatch.js +36 -14
  264. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  265. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  266. package/dist/scripts/notify-hook/team-leader-nudge.js +26 -11
  267. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  268. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +2 -1
  269. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  270. package/dist/scripts/notify-hook/team-tmux-guard.js +45 -1
  271. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  272. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  273. package/dist/scripts/notify-hook/team-worker-stop.js +27 -14
  274. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  275. package/dist/scripts/run-provider-advisor.js +9 -3
  276. package/dist/scripts/run-provider-advisor.js.map +1 -1
  277. package/dist/scripts/smoke-packed-install.d.ts +4 -1
  278. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  279. package/dist/scripts/smoke-packed-install.js +101 -1
  280. package/dist/scripts/smoke-packed-install.js.map +1 -1
  281. package/dist/scripts/sync-plugin-mirror.js +2 -2
  282. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  283. package/dist/scripts/verify-native-agents.js +2 -2
  284. package/dist/scripts/verify-native-agents.js.map +1 -1
  285. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts +2 -0
  286. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  287. package/dist/sidecar/__tests__/resource-leak-watch.test.js +38 -0
  288. package/dist/sidecar/__tests__/resource-leak-watch.test.js.map +1 -0
  289. package/dist/sidecar/index.d.ts +1 -1
  290. package/dist/sidecar/index.d.ts.map +1 -1
  291. package/dist/sidecar/index.js +29 -12
  292. package/dist/sidecar/index.js.map +1 -1
  293. package/dist/state/__tests__/operations-ralph-phase.test.js +88 -1
  294. package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -1
  295. package/dist/state/operations.d.ts.map +1 -1
  296. package/dist/state/operations.js +11 -0
  297. package/dist/state/operations.js.map +1 -1
  298. package/dist/team/__tests__/runtime.test.js +2 -2
  299. package/dist/team/__tests__/runtime.test.js.map +1 -1
  300. package/dist/team/__tests__/tmux-session.test.js +207 -22
  301. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  302. package/dist/team/tmux-session.d.ts +1 -0
  303. package/dist/team/tmux-session.d.ts.map +1 -1
  304. package/dist/team/tmux-session.js +73 -28
  305. package/dist/team/tmux-session.js.map +1 -1
  306. package/dist/ultragoal/__tests__/artifacts.test.js +714 -10
  307. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  308. package/dist/ultragoal/__tests__/docs-contract.test.js +57 -1
  309. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  310. package/dist/ultragoal/__tests__/steering-fixtures.d.ts +68 -0
  311. package/dist/ultragoal/__tests__/steering-fixtures.d.ts.map +1 -0
  312. package/dist/ultragoal/__tests__/steering-fixtures.js +259 -0
  313. package/dist/ultragoal/__tests__/steering-fixtures.js.map +1 -0
  314. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts +2 -0
  315. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts.map +1 -0
  316. package/dist/ultragoal/__tests__/steering-fixtures.test.js +65 -0
  317. package/dist/ultragoal/__tests__/steering-fixtures.test.js.map +1 -0
  318. package/dist/ultragoal/artifacts.d.ts +97 -2
  319. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  320. package/dist/ultragoal/artifacts.js +811 -256
  321. package/dist/ultragoal/artifacts.js.map +1 -1
  322. package/dist/utils/__tests__/sleep-resource.test.d.ts +2 -0
  323. package/dist/utils/__tests__/sleep-resource.test.d.ts.map +1 -0
  324. package/dist/utils/__tests__/sleep-resource.test.js +39 -0
  325. package/dist/utils/__tests__/sleep-resource.test.js.map +1 -0
  326. package/dist/utils/sleep.d.ts.map +1 -1
  327. package/dist/utils/sleep.js +17 -6
  328. package/dist/utils/sleep.js.map +1 -1
  329. package/dist/verification/__tests__/ci-rust-gates.test.js +85 -10
  330. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  331. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +1 -0
  332. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
  333. package/package.json +5 -3
  334. package/plugins/oh-my-codex/.codex-plugin/plugin.json +4 -3
  335. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +56 -0
  336. package/plugins/oh-my-codex/hooks/hooks.json +77 -0
  337. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +77 -47
  338. package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +83 -0
  339. package/plugins/oh-my-codex/skills/cancel/SKILL.md +2 -2
  340. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +9 -8
  341. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
  342. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +22 -11
  343. package/plugins/oh-my-codex/skills/plan/SKILL.md +8 -8
  344. package/plugins/oh-my-codex/skills/ralph/SKILL.md +7 -0
  345. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -5
  346. package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
  347. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +38 -4
  348. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +1 -1
  349. package/prompts/planner.md +1 -1
  350. package/prompts/researcher.md +15 -10
  351. package/skills/autopilot/SKILL.md +77 -47
  352. package/skills/best-practice-research/SKILL.md +83 -0
  353. package/skills/cancel/SKILL.md +2 -2
  354. package/skills/deep-interview/SKILL.md +9 -8
  355. package/skills/omx-setup/SKILL.md +1 -1
  356. package/skills/pipeline/SKILL.md +22 -11
  357. package/skills/plan/SKILL.md +8 -8
  358. package/skills/ralph/SKILL.md +7 -0
  359. package/skills/ralplan/SKILL.md +5 -5
  360. package/skills/team/SKILL.md +1 -1
  361. package/skills/ultragoal/SKILL.md +38 -4
  362. package/skills/ultrawork/SKILL.md +1 -1
  363. package/src/scripts/__tests__/codex-native-hook.test.ts +1758 -166
  364. package/src/scripts/__tests__/notify-dispatcher.test.ts +223 -1
  365. package/src/scripts/__tests__/smoke-packed-install.test.ts +39 -2
  366. package/src/scripts/__tests__/verify-native-agents.test.ts +21 -1
  367. package/src/scripts/build-api.ts +48 -0
  368. package/src/scripts/cleanup-explore-harness.ts +1 -0
  369. package/src/scripts/codex-native-hook.ts +416 -18
  370. package/src/scripts/codex-native-pre-post.ts +119 -25
  371. package/src/scripts/notify-dispatcher.ts +97 -0
  372. package/src/scripts/notify-hook/process-runner.ts +40 -16
  373. package/src/scripts/notify-hook/team-dispatch.ts +36 -13
  374. package/src/scripts/notify-hook/team-leader-nudge.ts +25 -11
  375. package/src/scripts/notify-hook/team-tmux-guard.ts +49 -0
  376. package/src/scripts/notify-hook/team-worker-stop.ts +24 -13
  377. package/src/scripts/run-provider-advisor.ts +11 -3
  378. package/src/scripts/smoke-packed-install.ts +107 -0
  379. package/src/scripts/sync-plugin-mirror.ts +3 -3
  380. package/src/scripts/verify-native-agents.ts +2 -2
  381. package/templates/catalog-manifest.json +7 -0
@@ -1,6 +1,6 @@
1
1
  import { execFileSync } from "child_process";
2
2
  import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
3
- import { appendFile, mkdir, readFile, readdir, writeFile } from "fs/promises";
3
+ import { appendFile, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
4
4
  import { extname, join, relative, resolve } from "path";
5
5
  import { pathToFileURL } from "url";
6
6
  import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
@@ -20,12 +20,14 @@ import { maybeNudgeLeaderForAllowedWorkerStop } from "./notify-hook/team-worker-
20
20
  import { resolveCodexExecutionSurface, } from "./codex-execution-surface.js";
21
21
  import { buildNativeHookEvent, } from "../hooks/extensibility/events.js";
22
22
  import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
23
+ import { getNotificationConfig, getVerbosity } from "../notifications/config.js";
23
24
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
24
25
  import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
25
26
  import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
26
27
  import { readRunState } from "../runtime/run-state.js";
27
28
  import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
28
29
  import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
30
+ import { parseUltragoalSteeringDirective, steerUltragoal, } from "../ultragoal/artifacts.js";
29
31
  import { triagePrompt } from "../hooks/triage-heuristic.js";
30
32
  import { readTriageConfig } from "../hooks/triage-config.js";
31
33
  import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignature, } from "../hooks/triage-state.js";
@@ -38,6 +40,7 @@ const TEAM_STOP_BLOCKING_TASK_STATUSES = new Set(["pending", "in_progress", "blo
38
40
  const TEAM_WORKER_TERMINAL_RUN_STATES = new Set(["done", "complete", "completed", "failed", "stopped", "cancelled"]);
39
41
  const NATIVE_STOP_STATE_FILE = "native-stop-state.json";
40
42
  const ORDINARY_STOP_NO_PROGRESS_DEFAULT_MAX_REPEATS = 8;
43
+ const RALPH_ORPHANED_STARTING_STALE_MS = 15 * 60_000;
41
44
  const ORDINARY_STOP_NO_PROGRESS_DEFAULT_IDLE_MS = 10 * 60_000;
42
45
  const ORDINARY_STOP_NO_PROGRESS_MAX_MESSAGE_LENGTH = 240;
43
46
  const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
@@ -185,6 +188,13 @@ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, th
185
188
  return false;
186
189
  return candidateIds.some((id) => summary.allSubagentThreadIds.includes(id));
187
190
  }
191
+ function shouldSuppressSubagentLifecycleHookDispatch() {
192
+ const config = getNotificationConfig();
193
+ if (config?.includeChildAgents === true)
194
+ return false;
195
+ const verbosity = getVerbosity(config);
196
+ return verbosity !== "agent" && verbosity !== "verbose";
197
+ }
188
198
  async function recordIgnoredNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
189
199
  await appendToLog(cwd, {
190
200
  event: "subagent_session_start_ignored",
@@ -285,6 +295,110 @@ function readPromptText(payload) {
285
295
  }
286
296
  return "";
287
297
  }
298
+ function extractBalancedJsonObject(text, startIndex) {
299
+ let depth = 0;
300
+ let inString = false;
301
+ let escaped = false;
302
+ for (let index = startIndex; index < text.length; index++) {
303
+ const char = text[index];
304
+ if (inString) {
305
+ if (escaped)
306
+ escaped = false;
307
+ else if (char === "\\")
308
+ escaped = true;
309
+ else if (char === '"')
310
+ inString = false;
311
+ continue;
312
+ }
313
+ if (char === '"') {
314
+ inString = true;
315
+ continue;
316
+ }
317
+ if (char === "{")
318
+ depth += 1;
319
+ else if (char === "}") {
320
+ depth -= 1;
321
+ if (depth === 0)
322
+ return text.slice(startIndex, index + 1);
323
+ }
324
+ }
325
+ return null;
326
+ }
327
+ function normalizePromptSteeringProposal(raw, prompt) {
328
+ const candidate = safeObject(raw);
329
+ const nested = candidate.omx_ultragoal_steer ?? candidate.ultragoal_steer ?? candidate.steering ?? candidate;
330
+ const proposal = parseUltragoalSteeringDirective(JSON.stringify(nested));
331
+ if (!proposal)
332
+ return null;
333
+ if (proposal.source !== "user_prompt_submit")
334
+ return null;
335
+ const normalized = prompt.trim().toLowerCase();
336
+ return {
337
+ ...proposal,
338
+ directiveText: proposal.directiveText ?? safeContextSnippet(prompt, 600),
339
+ promptSignature: proposal.promptSignature ?? promptSignature(normalized),
340
+ idempotencyKey: proposal.idempotencyKey ?? `user_prompt_submit:${promptSignature(normalized)}`,
341
+ };
342
+ }
343
+ function parseUserPromptUltragoalSteeringDirective(prompt) {
344
+ const trimmed = prompt.trim();
345
+ if (!trimmed)
346
+ return null;
347
+ const fenced = trimmed.match(/```(?:omx-ultragoal-steer|ultragoal-steer)\s*([\s\S]*?)```/i);
348
+ if (fenced?.[1]) {
349
+ try {
350
+ return normalizePromptSteeringProposal(JSON.parse(fenced[1]), prompt);
351
+ }
352
+ catch {
353
+ return null;
354
+ }
355
+ }
356
+ const label = trimmed.match(/(?:^|\n)\s*(?:OMX_ULTRAGOAL_STEER|omx\.ultragoal\.steer|omx ultragoal steer)\s*:\s*{/i);
357
+ if (label?.index !== undefined) {
358
+ const brace = trimmed.indexOf("{", label.index);
359
+ const json = brace >= 0 ? extractBalancedJsonObject(trimmed, brace) : null;
360
+ if (json) {
361
+ try {
362
+ return normalizePromptSteeringProposal(JSON.parse(json), prompt);
363
+ }
364
+ catch {
365
+ return null;
366
+ }
367
+ }
368
+ }
369
+ if (trimmed.startsWith("{")) {
370
+ try {
371
+ const parsed = JSON.parse(trimmed);
372
+ const object = safeObject(parsed);
373
+ if ("omx_ultragoal_steer" in object || "ultragoal_steer" in object) {
374
+ return normalizePromptSteeringProposal(parsed, prompt);
375
+ }
376
+ }
377
+ catch {
378
+ return null;
379
+ }
380
+ }
381
+ return null;
382
+ }
383
+ async function applyUserPromptUltragoalSteering(cwd, prompt) {
384
+ const proposal = parseUserPromptUltragoalSteeringDirective(prompt);
385
+ if (!proposal)
386
+ return null;
387
+ try {
388
+ const result = await steerUltragoal(cwd, proposal);
389
+ const status = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
390
+ const reasons = result.rejectedReasons.length > 0 ? ` rejectedReasons=${result.rejectedReasons.join("; ")}` : "";
391
+ return [
392
+ `OMX native UserPromptSubmit applied bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${status}.`,
393
+ `mutation=${result.audit.kind}; source=${result.audit.source}; targets=${result.audit.targetGoalIds.join(",") || "none"}; idempotencyKey=${result.audit.idempotencyKey ?? "none"}.${reasons}`,
394
+ "Only explicit structured steering directives are parsed; normal prose is ignored and cannot mutate .omx/ultragoal.",
395
+ ].join(" ");
396
+ }
397
+ catch (error) {
398
+ const message = error instanceof Error ? error.message : String(error);
399
+ return `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${message}`;
400
+ }
401
+ }
288
402
  function sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId = "") {
289
403
  const sanitized = { ...payload };
290
404
  if (hookEventName === "UserPromptSubmit") {
@@ -344,6 +458,47 @@ async function readActiveAutoresearchState(cwd, sessionId) {
344
458
  function isRalphStartingPhase(state) {
345
459
  return safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase() === "starting";
346
460
  }
461
+ function parseTimestampMs(value) {
462
+ const text = safeString(value).trim();
463
+ if (!text)
464
+ return null;
465
+ const ms = Date.parse(text);
466
+ return Number.isFinite(ms) ? ms : null;
467
+ }
468
+ function numericValue(value) {
469
+ if (typeof value === "number" && Number.isFinite(value))
470
+ return value;
471
+ if (typeof value === "string" && value.trim()) {
472
+ const parsed = Number(value);
473
+ return Number.isFinite(parsed) ? parsed : null;
474
+ }
475
+ return null;
476
+ }
477
+ function hasRalphOwnerHint(state) {
478
+ return [
479
+ state.owner_omx_session_id,
480
+ state.owner_codex_session_id,
481
+ state.owner_codex_thread_id,
482
+ state.thread_id,
483
+ state.tmux_pane_id,
484
+ state.task_slug,
485
+ ].some((value) => safeString(value).trim() !== "");
486
+ }
487
+ async function isStaleOrphanedRalphStartingState(state, path, nowMs = Date.now()) {
488
+ if (!isRalphStartingPhase(state))
489
+ return false;
490
+ if (numericValue(state.iteration) !== 0)
491
+ return false;
492
+ if (hasRalphOwnerHint(state))
493
+ return false;
494
+ const timestampMs = parseTimestampMs(state.updated_at)
495
+ ?? parseTimestampMs(state.started_at)
496
+ ?? parseTimestampMs(state.created_at)
497
+ ?? await stat(path).then((info) => info.mtimeMs, () => null);
498
+ if (timestampMs === null)
499
+ return false;
500
+ return nowMs - timestampMs > RALPH_ORPHANED_STARTING_STALE_MS;
501
+ }
347
502
  function hasValue(values, value) {
348
503
  return value !== "" && values.some((candidate) => candidate === value);
349
504
  }
@@ -410,6 +565,89 @@ async function hasConsistentRalphSkillActivation(stateDir, sessionId) {
410
565
  return false;
411
566
  return true;
412
567
  }
568
+ function isShadowableRalphStartingSeed(state) {
569
+ if (state.active !== true)
570
+ return false;
571
+ if (!isRalphStartingPhase(state))
572
+ return false;
573
+ if (state.completion_audit || state.completionAudit)
574
+ return false;
575
+ const iteration = numericValue(state.iteration);
576
+ return iteration === null || iteration <= 0;
577
+ }
578
+ function hasPassingCompletedRalphAudit(state, cwd) {
579
+ if (!state)
580
+ return false;
581
+ if (state.mode && safeString(state.mode) !== "ralph")
582
+ return false;
583
+ if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase))
584
+ return false;
585
+ if (state.active === true)
586
+ return false;
587
+ return evaluateRalphCompletionAuditEvidence(state, cwd).complete === true;
588
+ }
589
+ function shouldRetireShadowedRalphStartingSeed(seedState, completedState, cwd, ownerContext) {
590
+ if (!isShadowableRalphStartingSeed(seedState))
591
+ return false;
592
+ if (!hasPassingCompletedRalphAudit(completedState, cwd))
593
+ return false;
594
+ if (!completedState)
595
+ return false;
596
+ const completedSessionId = safeString(ownerContext?.completedSessionId ?? completedState.session_id).trim();
597
+ if (completedSessionId
598
+ && !activeRalphStateMatchesStopOwner(completedState, {
599
+ sessionId: completedSessionId,
600
+ payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
601
+ threadId: safeString(ownerContext?.threadId).trim(),
602
+ currentNativeSessionId: safeString(ownerContext?.currentNativeSessionId).trim(),
603
+ tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
604
+ })) {
605
+ return false;
606
+ }
607
+ const seedThreadId = safeString(seedState.owner_codex_thread_id ?? seedState.thread_id).trim();
608
+ const completedThreadId = safeString(completedState?.owner_codex_thread_id ?? completedState?.thread_id).trim();
609
+ const stopThreadId = safeString(ownerContext?.threadId).trim();
610
+ if (seedThreadId && completedThreadId && seedThreadId !== completedThreadId)
611
+ return false;
612
+ if (seedThreadId && stopThreadId && seedThreadId !== stopThreadId)
613
+ return false;
614
+ if (completedThreadId && stopThreadId && completedThreadId !== stopThreadId)
615
+ return false;
616
+ const seedPaneId = safeString(seedState.tmux_pane_id).trim();
617
+ const completedPaneId = safeString(completedState?.tmux_pane_id).trim();
618
+ const stopPaneId = safeString(ownerContext?.tmuxPaneId).trim();
619
+ if (seedPaneId && completedPaneId && seedPaneId !== completedPaneId)
620
+ return false;
621
+ if (seedPaneId && stopPaneId && seedPaneId !== stopPaneId)
622
+ return false;
623
+ if (completedPaneId && stopPaneId && completedPaneId !== stopPaneId)
624
+ return false;
625
+ const seedStartedAt = parseTimestampMs(seedState.started_at ?? seedState.startedAt);
626
+ const completedAt = parseTimestampMs(completedState?.completed_at ?? completedState?.completedAt);
627
+ if (completedAt === null)
628
+ return false;
629
+ if (seedStartedAt !== null && seedStartedAt > completedAt)
630
+ return false;
631
+ return true;
632
+ }
633
+ async function retireShadowedRalphStartingSeed(path, seedState, completedSessionId, completedPath, completedState) {
634
+ const nowIso = new Date().toISOString();
635
+ const completedAt = safeString(completedState.completed_at ?? completedState.completedAt).trim() || nowIso;
636
+ const next = {
637
+ ...seedState,
638
+ active: false,
639
+ current_phase: "complete",
640
+ completed_at: completedAt,
641
+ stop_reason: "shadowed_by_completed_canonical_ralph",
642
+ shadowed_by_completed_canonical_ralph: {
643
+ session_id: completedSessionId,
644
+ state_path: completedPath,
645
+ completed_at: completedAt,
646
+ reconciled_at: nowIso,
647
+ },
648
+ };
649
+ await writeFile(path, JSON.stringify(next, null, 2));
650
+ }
413
651
  async function readRalphCompletionAuditBlockState(cwd, stateDir, preferredSessionId, ownerContext) {
414
652
  const [rawSessionInfo, usableSessionInfo] = await Promise.all([
415
653
  readSessionState(cwd),
@@ -457,13 +695,12 @@ async function reopenRalphCompletionAuditBlock(block) {
457
695
  const nowIso = new Date().toISOString();
458
696
  const next = {
459
697
  ...block.state,
460
- active: true,
461
- current_phase: "verifying",
698
+ active: false,
699
+ current_phase: "complete",
462
700
  completion_audit_gate: "blocked",
463
701
  completion_audit_missing_reason: block.reason,
464
702
  completion_audit_blocked_at: nowIso,
465
703
  };
466
- delete next.completed_at;
467
704
  await writeFile(block.path, JSON.stringify(next, null, 2));
468
705
  }
469
706
  async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
@@ -480,6 +717,12 @@ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerCont
480
717
  safeString(preferredSessionId).trim(),
481
718
  currentOmxSessionId,
482
719
  ].filter(Boolean))];
720
+ const completedCanonicalPath = currentOmxSessionId
721
+ ? getStateFilePath("ralph-state.json", cwd, currentOmxSessionId)
722
+ : "";
723
+ const completedCanonicalState = completedCanonicalPath
724
+ ? await readJsonIfExists(completedCanonicalPath)
725
+ : null;
483
726
  // Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
484
727
  // That is intentionally stricter than generic state MCP reads: do not scan sibling
485
728
  // session scopes or fall back to root when a current/explicit session is in play.
@@ -492,10 +735,27 @@ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerCont
492
735
  }
493
736
  const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
494
737
  const sessionScoped = await readJsonIfExists(sessionScopedPath);
495
- if (sessionScoped?.active === true
496
- && isRalphStartingPhase(sessionScoped)
497
- && !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
498
- continue;
738
+ if (sessionScoped?.active === true) {
739
+ if (currentOmxSessionId
740
+ && sessionId !== currentOmxSessionId
741
+ && completedCanonicalState
742
+ && shouldRetireShadowedRalphStartingSeed(sessionScoped, completedCanonicalState, cwd, {
743
+ completedSessionId: currentOmxSessionId,
744
+ payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
745
+ threadId: safeString(ownerContext?.threadId).trim(),
746
+ currentNativeSessionId,
747
+ tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
748
+ })) {
749
+ await retireShadowedRalphStartingSeed(sessionScopedPath, sessionScoped, currentOmxSessionId, completedCanonicalPath, completedCanonicalState);
750
+ continue;
751
+ }
752
+ if (await isStaleOrphanedRalphStartingState(sessionScoped, sessionScopedPath)) {
753
+ continue;
754
+ }
755
+ if (isRalphStartingPhase(sessionScoped)
756
+ && !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
757
+ continue;
758
+ }
499
759
  }
500
760
  if (sessionScoped?.active === true
501
761
  && shouldContinueRun(sessionScoped)
@@ -1129,7 +1389,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1129
1389
  ? "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."
1130
1390
  : null;
1131
1391
  const ultragoalPromptActivationNote = match.skill === "ultragoal"
1132
- ? "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."
1392
+ ? "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. Ultragoal does not call `/goal clear`; for multiple sequential ultragoal runs in one Codex session/thread, manually clear the completed Codex goal in the UI before creating the next aggregate goal."
1133
1393
  : null;
1134
1394
  const combinedTransitionMessage = (() => {
1135
1395
  if (!skillState?.transition_message)
@@ -1341,15 +1601,21 @@ function isStopExempt(payload) {
1341
1601
  || value.includes("limit"));
1342
1602
  }
1343
1603
  async function buildModeBasedStopOutput(mode, cwd, sessionId) {
1604
+ if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, mode)) {
1605
+ return null;
1606
+ }
1344
1607
  const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
1345
1608
  if (!state || !shouldContinueRun(state))
1346
1609
  return null;
1347
1610
  const phase = formatPhase(state.current_phase);
1611
+ const systemMessage = mode === "autopilot" && phase.toLowerCase().replace(/_/g, "-") === "code-review"
1612
+ ? "OMX autopilot is still active (phase: code-review). Run the required $code-review step before completing or clearing Autopilot state."
1613
+ : `OMX ${mode} is still active (phase: ${phase}).`;
1348
1614
  return {
1349
1615
  decision: "block",
1350
1616
  reason: `OMX ${mode} is still active (phase: ${phase}); continue the task and gather fresh verification evidence before stopping.`,
1351
1617
  stopReason: `${mode}_${phase}`,
1352
- systemMessage: `OMX ${mode} is still active (phase: ${phase}).`,
1618
+ systemMessage,
1353
1619
  };
1354
1620
  }
1355
1621
  export function looksLikeGoalCompletionPrompt(text) {
@@ -1359,6 +1625,28 @@ export function looksLikeGoalCompletionPrompt(text) {
1359
1625
  || /\b(?:ultragoal|performance[-\s]goal|autoresearch[-\s]goal)\b.{0,80}\b(?:complete|checkpoint|finish|close|mark)\b/i.test(text)
1360
1626
  || /(?:^|[.!?]\s+)(?:the\s+)?goal\s+(?:is\s+|now\s+|has\s+been\s+)?(?:complete|completed|finished|closed)(?:\s*(?:[.!?]|$)|\s*[:;]\s*\S|\s*[—–-]\s*\S)/i.test(text);
1361
1627
  }
1628
+ function reportsAutoresearchGoalObjectiveMismatch(text) {
1629
+ return /\bautoresearch[-\s]goal\b/i.test(text)
1630
+ && /\b(?:complete|completion|reconciliation)\b/i.test(text)
1631
+ && /objective mismatch/i.test(text);
1632
+ }
1633
+ function reportsBlockedPerformanceGoalObjectiveMismatch(state) {
1634
+ const performanceState = safeObject(state);
1635
+ const lastValidation = safeObject(performanceState.lastValidation);
1636
+ if (safeString(performanceState.workflow) !== "performance-goal")
1637
+ return false;
1638
+ if (safeString(performanceState.status) !== "blocked")
1639
+ return false;
1640
+ if (safeString(lastValidation.status) !== "blocked")
1641
+ return false;
1642
+ const evidence = [
1643
+ safeString(lastValidation.evidence),
1644
+ safeString(lastValidation.message),
1645
+ safeString(performanceState.evidence),
1646
+ safeString(performanceState.message),
1647
+ ].join(" ");
1648
+ return /objective mismatch/i.test(evidence);
1649
+ }
1362
1650
  async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1363
1651
  const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
1364
1652
  const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
@@ -1376,7 +1664,7 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1376
1664
  `If get_goal returns a completed task-scoped objective for the same aggregate ultragoal plan, checkpoint ${goalId} with evidence naming ${goalId} plus .omx/ultragoal/goals.json or ledger.jsonl and pass final quality-gate JSON; OMX will reconcile the completed planned scope without mutating Codex goal state.`,
1377
1665
  `If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
1378
1666
  `Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>'.`,
1379
- "Then continue this ultragoal from a fresh Codex thread in the same repo/worktree and create the intended goal there.",
1667
+ "Then continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the intended goal there.",
1380
1668
  ].join(" "),
1381
1669
  };
1382
1670
  }
@@ -1386,6 +1674,9 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1386
1674
  continue;
1387
1675
  const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
1388
1676
  const status = safeString(state?.status);
1677
+ if (reportsBlockedPerformanceGoalObjectiveMismatch(state)) {
1678
+ continue;
1679
+ }
1389
1680
  if (state?.workflow === "performance-goal" && status && status !== "complete") {
1390
1681
  return {
1391
1682
  workflow: "performance-goal",
@@ -1402,10 +1693,17 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1402
1693
  const completion = await readJsonIfExists(join(autoresearchRoot, entry.name, "completion.json"));
1403
1694
  const completionVerdict = safeString(completion?.verdict);
1404
1695
  const completionPassed = completion?.passed === true || completionVerdict === "pass";
1405
- if (mission?.workflow === "autoresearch-goal" && status && status !== "complete" && completionPassed) {
1696
+ if (mission?.workflow === "autoresearch-goal"
1697
+ && status
1698
+ && status !== "complete"
1699
+ && completionPassed) {
1406
1700
  return {
1407
1701
  workflow: "autoresearch-goal",
1408
1702
  command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
1703
+ remediation: [
1704
+ "If that command fails with a Codex goal objective mismatch after a refreshed get_goal snapshot, do not repeat the same complete command blindly in this thread.",
1705
+ "Either retry with a correct refreshed snapshot or record an explicit blocked verdict for this autoresearch-goal and continue from the explicit blocker path.",
1706
+ ].join(" "),
1409
1707
  };
1410
1708
  }
1411
1709
  }
@@ -1431,6 +1729,9 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
1431
1729
  const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
1432
1730
  if (!requirement)
1433
1731
  return null;
1732
+ if (requirement.workflow === "autoresearch-goal" && reportsAutoresearchGoalObjectiveMismatch(lastAssistantMessage)) {
1733
+ return null;
1734
+ }
1434
1735
  const systemMessage = [
1435
1736
  `OMX ${requirement.workflow} requires get_goal snapshot reconciliation before completion; call get_goal and pass --codex-goal-json to ${requirement.command}.`,
1436
1737
  requirement.remediation,
@@ -1533,7 +1834,7 @@ function readPayloadSessionId(payload) {
1533
1834
  return safeString(payload.session_id ?? payload.sessionId).trim();
1534
1835
  }
1535
1836
  function readPayloadThreadId(payload) {
1536
- return safeString(payload.thread_id ?? payload.threadId).trim();
1837
+ return safeString(payload.owner_codex_thread_id ?? payload.thread_id ?? payload.threadId).trim();
1537
1838
  }
1538
1839
  function readPayloadTurnId(payload) {
1539
1840
  return safeString(payload.turn_id ?? payload.turnId).trim();
@@ -1608,6 +1909,8 @@ async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requ
1608
1909
  const modeSnapshot = getRunContinuationSnapshot(modeState);
1609
1910
  if (modeSnapshot?.terminal === true)
1610
1911
  continue;
1912
+ if (await shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(cwd, stateDir, skill, sessionId, threadId))
1913
+ continue;
1611
1914
  const phase = formatPhase(modeState.current_phase, formatPhase(visibleEntries.find((entry) => entry.skill === skill)?.phase, "planning"));
1612
1915
  if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
1613
1916
  continue;
@@ -1648,6 +1951,38 @@ function isTerminalOrInactiveModeState(state) {
1648
1951
  const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
1649
1952
  return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
1650
1953
  }
1954
+ function rootSkillStateHasNoActiveSkillForStopContext(rootState, skill, sessionId, threadId) {
1955
+ if (!rootState)
1956
+ return false;
1957
+ return !listActiveSkills(rootState).some((entry) => (entry.skill === skill
1958
+ && matchesSkillStopContext(entry, rootState, sessionId, threadId)));
1959
+ }
1960
+ function rootModeStateIsCanonicalForStopContext(state, cwd, sessionId, threadId) {
1961
+ if (!modeStateMatchesSkillStopContext(state, cwd, sessionId))
1962
+ return false;
1963
+ const stateSessionId = safeString(state.owner_omx_session_id
1964
+ ?? state.session_id
1965
+ ?? state.codex_session_id
1966
+ ?? state.owner_codex_session_id).trim();
1967
+ if (sessionId && stateSessionId !== sessionId)
1968
+ return false;
1969
+ const stateThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
1970
+ if (threadId && stateThreadId && stateThreadId !== threadId)
1971
+ return false;
1972
+ return true;
1973
+ }
1974
+ async function shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(cwd, stateDir, skill, sessionId, threadId) {
1975
+ const rootModeState = await readJsonIfExists(join(stateDir, `${skill}-state.json`));
1976
+ if (!rootModeState)
1977
+ return false;
1978
+ if (!rootModeStateIsCanonicalForStopContext(rootModeState, cwd, sessionId, threadId))
1979
+ return false;
1980
+ if (!isTerminalOrInactiveModeState(rootModeState))
1981
+ return false;
1982
+ const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
1983
+ const rootSkillState = await readSkillActiveState(rootPath);
1984
+ return rootSkillStateHasNoActiveSkillForStopContext(rootSkillState, skill, sessionId, threadId);
1985
+ }
1651
1986
  async function readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, sessionIds) {
1652
1987
  for (const sessionId of sessionIds) {
1653
1988
  const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
@@ -2173,7 +2508,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2173
2508
  `OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}).`,
2174
2509
  "Continue verification and do not report complete yet.",
2175
2510
  "Record machine-readable completion evidence before stopping:",
2176
- "- either set state.completion_audit = { passed: true, prompt_to_artifact_checklist: [...], verification_evidence: [...] }",
2511
+ '- either set "completion_audit" on the Ralph state object, for example: omx state write --input \'{"mode":"ralph","active":false,"current_phase":"complete","completion_audit":{"passed":true,"prompt_to_artifact_checklist":["..."],"verification_evidence":["..."]}}\' --json',
2177
2512
  "- or set completion_audit_path / completion_audit_evidence_path to a repo-relative JSON file with those same fields.",
2178
2513
  "Markdown artifacts and flat top-level checklist/evidence fields are not accepted by the Ralph Stop gate.",
2179
2514
  ].join(" ");
@@ -2312,6 +2647,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2312
2647
  let skillState = null;
2313
2648
  let triageAdditionalContext = null;
2314
2649
  let goalWorkflowAdditionalContext = null;
2650
+ let ultragoalSteeringAdditionalContext = null;
2315
2651
  const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
2316
2652
  const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
2317
2653
  const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
@@ -2319,10 +2655,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2319
2655
  let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
2320
2656
  let resolvedNativeSessionId = nativeSessionId;
2321
2657
  let skipCanonicalSessionStartContext = false;
2658
+ let isSubagentSessionStart = false;
2322
2659
  if (hookEventName === "SessionStart" && nativeSessionId) {
2323
2660
  const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
2324
2661
  const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
2325
2662
  if (subagentSessionStart && canonicalSessionId) {
2663
+ isSubagentSessionStart = true;
2326
2664
  const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonicalSessionId, currentSessionState, subagentSessionStart);
2327
2665
  if (belongsToCanonicalSession) {
2328
2666
  resolvedNativeSessionId = nativeSessionId;
@@ -2370,9 +2708,14 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2370
2708
  ].filter(Boolean))]
2371
2709
  .map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)))).some(Boolean)
2372
2710
  : false;
2711
+ const suppressNoisySubagentLifecycleDispatch = (isSubagentSessionStart || isSubagentStop)
2712
+ && shouldSuppressSubagentLifecycleHookDispatch();
2373
2713
  if (hookEventName === "UserPromptSubmit") {
2374
2714
  const prompt = readPromptText(payload);
2375
2715
  goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
2716
+ ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit
2717
+ ? await applyUserPromptUltragoalSteering(cwd, prompt).catch((error) => `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${error instanceof Error ? error.message : String(error)}`)
2718
+ : null;
2376
2719
  if (prompt && !isSubagentPromptSubmit) {
2377
2720
  skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
2378
2721
  stateDir,
@@ -2461,7 +2804,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2461
2804
  const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
2462
2805
  await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
2463
2806
  }
2464
- if (omxEventName && !skipCanonicalSessionStartContext) {
2807
+ if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
2465
2808
  const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
2466
2809
  if (resolvedNativeSessionId) {
2467
2810
  baseContext.native_session_id = resolvedNativeSessionId;
@@ -2498,7 +2841,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2498
2841
  })
2499
2842
  : isSubagentPromptSubmit
2500
2843
  ? null
2501
- : (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload) ?? goalWorkflowAdditionalContext ?? triageAdditionalContext);
2844
+ : [
2845
+ buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload),
2846
+ ultragoalSteeringAdditionalContext,
2847
+ goalWorkflowAdditionalContext,
2848
+ triageAdditionalContext,
2849
+ ].filter((entry) => Boolean(entry)).join("\n\n") || null;
2502
2850
  if (additionalContext) {
2503
2851
  outputJson = {
2504
2852
  hookSpecificOutput: {