oh-my-codex 0.16.2 → 0.16.4

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 (340) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -3
  4. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
  5. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  6. package/dist/cli/__tests__/cleanup.test.js +27 -0
  7. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  8. package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
  9. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  10. package/dist/cli/__tests__/doctor-warning-copy.test.js +137 -6
  11. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  12. package/dist/cli/__tests__/index.test.js +303 -4
  13. package/dist/cli/__tests__/index.test.js.map +1 -1
  14. package/dist/cli/__tests__/launch-fallback.test.js +58 -0
  15. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  16. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
  17. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  18. package/dist/cli/__tests__/ralph.test.js +48 -0
  19. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  20. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +8 -0
  21. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  22. package/dist/cli/__tests__/setup-install-mode.test.js +350 -27
  23. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  24. package/dist/cli/__tests__/setup-refresh.test.js +85 -3
  25. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  26. package/dist/cli/__tests__/setup-scope.test.js +1 -1
  27. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  28. package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
  29. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  30. package/dist/cli/__tests__/team.test.js +269 -0
  31. package/dist/cli/__tests__/team.test.js.map +1 -1
  32. package/dist/cli/__tests__/ultragoal.test.js +69 -0
  33. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  34. package/dist/cli/__tests__/uninstall.test.js +90 -6
  35. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  36. package/dist/cli/__tests__/update.test.js +109 -19
  37. package/dist/cli/__tests__/update.test.js.map +1 -1
  38. package/dist/cli/cleanup.d.ts.map +1 -1
  39. package/dist/cli/cleanup.js +8 -4
  40. package/dist/cli/cleanup.js.map +1 -1
  41. package/dist/cli/codex-feature-probe.d.ts +9 -0
  42. package/dist/cli/codex-feature-probe.d.ts.map +1 -0
  43. package/dist/cli/codex-feature-probe.js +28 -0
  44. package/dist/cli/codex-feature-probe.js.map +1 -0
  45. package/dist/cli/doctor.d.ts +1 -0
  46. package/dist/cli/doctor.d.ts.map +1 -1
  47. package/dist/cli/doctor.js +168 -16
  48. package/dist/cli/doctor.js.map +1 -1
  49. package/dist/cli/index.d.ts +9 -2
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +168 -20
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/mcp-parity.js +8 -8
  54. package/dist/cli/mcp-parity.js.map +1 -1
  55. package/dist/cli/plugin-marketplace.d.ts +3 -0
  56. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  57. package/dist/cli/plugin-marketplace.js +88 -0
  58. package/dist/cli/plugin-marketplace.js.map +1 -1
  59. package/dist/cli/ralph.d.ts.map +1 -1
  60. package/dist/cli/ralph.js +21 -0
  61. package/dist/cli/ralph.js.map +1 -1
  62. package/dist/cli/setup-preferences.d.ts +4 -0
  63. package/dist/cli/setup-preferences.d.ts.map +1 -1
  64. package/dist/cli/setup-preferences.js +7 -0
  65. package/dist/cli/setup-preferences.js.map +1 -1
  66. package/dist/cli/setup.d.ts +5 -3
  67. package/dist/cli/setup.d.ts.map +1 -1
  68. package/dist/cli/setup.js +177 -43
  69. package/dist/cli/setup.js.map +1 -1
  70. package/dist/cli/team.d.ts.map +1 -1
  71. package/dist/cli/team.js +54 -15
  72. package/dist/cli/team.js.map +1 -1
  73. package/dist/cli/ultragoal.d.ts +1 -1
  74. package/dist/cli/ultragoal.d.ts.map +1 -1
  75. package/dist/cli/ultragoal.js +64 -5
  76. package/dist/cli/ultragoal.js.map +1 -1
  77. package/dist/cli/uninstall.d.ts +2 -0
  78. package/dist/cli/uninstall.d.ts.map +1 -1
  79. package/dist/cli/uninstall.js +76 -5
  80. package/dist/cli/uninstall.js.map +1 -1
  81. package/dist/cli/update.d.ts +10 -2
  82. package/dist/cli/update.d.ts.map +1 -1
  83. package/dist/cli/update.js +99 -5
  84. package/dist/cli/update.js.map +1 -1
  85. package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
  86. package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
  87. package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
  88. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
  89. package/dist/config/__tests__/codex-hooks.test.js +188 -4
  90. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  91. package/dist/config/__tests__/generator-idempotent.test.js +129 -10
  92. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  93. package/dist/config/__tests__/generator-notify.test.js +148 -7
  94. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  95. package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
  96. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  97. package/dist/config/codex-feature-flags.d.ts +21 -0
  98. package/dist/config/codex-feature-flags.d.ts.map +1 -0
  99. package/dist/config/codex-feature-flags.js +56 -0
  100. package/dist/config/codex-feature-flags.js.map +1 -0
  101. package/dist/config/codex-hooks.d.ts +40 -4
  102. package/dist/config/codex-hooks.d.ts.map +1 -1
  103. package/dist/config/codex-hooks.js +204 -18
  104. package/dist/config/codex-hooks.js.map +1 -1
  105. package/dist/config/generator.d.ts +19 -1
  106. package/dist/config/generator.d.ts.map +1 -1
  107. package/dist/config/generator.js +319 -83
  108. package/dist/config/generator.js.map +1 -1
  109. package/dist/config/omx-first-party-mcp.d.ts +3 -1
  110. package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
  111. package/dist/config/omx-first-party-mcp.js +2 -2
  112. package/dist/config/omx-first-party-mcp.js.map +1 -1
  113. package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
  114. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +29 -1
  116. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  117. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -0
  118. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  119. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +1 -0
  120. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  121. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts +2 -0
  122. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts.map +1 -0
  123. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +176 -0
  124. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -0
  125. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +148 -0
  126. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  127. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +3 -0
  128. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  129. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
  130. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
  131. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
  132. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
  133. package/dist/hooks/__tests__/wiki-docs-contract.test.js +1 -2
  134. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -1
  135. package/dist/hooks/agents-overlay.js +2 -2
  136. package/dist/hooks/agents-overlay.js.map +1 -1
  137. package/dist/hooks/keyword-detector.d.ts +1 -0
  138. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  139. package/dist/hooks/keyword-detector.js +7 -5
  140. package/dist/hooks/keyword-detector.js.map +1 -1
  141. package/dist/hud/__tests__/state.test.js +164 -0
  142. package/dist/hud/__tests__/state.test.js.map +1 -1
  143. package/dist/hud/state.d.ts.map +1 -1
  144. package/dist/hud/state.js +4 -5
  145. package/dist/hud/state.js.map +1 -1
  146. package/dist/mcp/__tests__/state-paths.test.js +61 -0
  147. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  148. package/dist/mcp/__tests__/state-server.test.js +166 -0
  149. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  150. package/dist/mcp/state-paths.d.ts.map +1 -1
  151. package/dist/mcp/state-paths.js +23 -2
  152. package/dist/mcp/state-paths.js.map +1 -1
  153. package/dist/modes/__tests__/base-session-scope.test.js +22 -0
  154. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  155. package/dist/modes/__tests__/base-tmux-pane.test.js +57 -26
  156. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  157. package/dist/modes/base.d.ts.map +1 -1
  158. package/dist/modes/base.js +5 -0
  159. package/dist/modes/base.js.map +1 -1
  160. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
  161. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
  162. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
  163. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
  164. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
  165. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
  166. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
  167. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
  168. package/dist/planning/__tests__/artifacts.test.js +597 -4
  169. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  170. package/dist/planning/__tests__/context-pack-status.test.js +524 -0
  171. package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
  172. package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
  173. package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
  174. package/dist/planning/__tests__/markdown-structure.test.js +459 -0
  175. package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
  176. package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts +2 -0
  177. package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts.map +1 -0
  178. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +612 -0
  179. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -0
  180. package/dist/planning/artifacts.d.ts +7 -2
  181. package/dist/planning/artifacts.d.ts.map +1 -1
  182. package/dist/planning/artifacts.js +279 -26
  183. package/dist/planning/artifacts.js.map +1 -1
  184. package/dist/planning/context-pack-status.d.ts +31 -0
  185. package/dist/planning/context-pack-status.d.ts.map +1 -1
  186. package/dist/planning/context-pack-status.js +291 -25
  187. package/dist/planning/context-pack-status.js.map +1 -1
  188. package/dist/planning/markdown-structure.d.ts +20 -0
  189. package/dist/planning/markdown-structure.d.ts.map +1 -0
  190. package/dist/planning/markdown-structure.js +137 -0
  191. package/dist/planning/markdown-structure.js.map +1 -0
  192. package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
  193. package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
  194. package/dist/ralph/__tests__/completion-audit.test.js +121 -0
  195. package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
  196. package/dist/ralph/completion-audit.d.ts +8 -0
  197. package/dist/ralph/completion-audit.d.ts.map +1 -0
  198. package/dist/ralph/completion-audit.js +99 -0
  199. package/dist/ralph/completion-audit.js.map +1 -0
  200. package/dist/ralph/persistence.d.ts +1 -1
  201. package/dist/ralph/persistence.d.ts.map +1 -1
  202. package/dist/ralph/persistence.js +8 -2
  203. package/dist/ralph/persistence.js.map +1 -1
  204. package/dist/scripts/__tests__/codex-native-hook.test.js +359 -24
  205. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  206. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
  207. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
  208. package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
  209. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
  210. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  211. package/dist/scripts/codex-native-hook.js +142 -76
  212. package/dist/scripts/codex-native-hook.js.map +1 -1
  213. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  214. package/dist/scripts/codex-native-pre-post.js +4 -2
  215. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  216. package/dist/scripts/notify-dispatcher.d.ts +7 -0
  217. package/dist/scripts/notify-dispatcher.d.ts.map +1 -0
  218. package/dist/scripts/notify-dispatcher.js +87 -0
  219. package/dist/scripts/notify-dispatcher.js.map +1 -0
  220. package/dist/scripts/notify-fallback-watcher.js +4 -0
  221. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  222. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  223. package/dist/scripts/notify-hook/ralph-session-resume.js +96 -8
  224. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  225. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  226. package/dist/scripts/notify-hook/state-io.js +6 -2
  227. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  228. package/dist/scripts/notify-hook/visual-verdict.js +3 -3
  229. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
  230. package/dist/scripts/notify-hook.js +127 -1
  231. package/dist/scripts/notify-hook.js.map +1 -1
  232. package/dist/state/__tests__/workflow-transition.test.js +102 -27
  233. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  234. package/dist/state/operations.d.ts.map +1 -1
  235. package/dist/state/operations.js +9 -3
  236. package/dist/state/operations.js.map +1 -1
  237. package/dist/state/skill-active.d.ts +7 -0
  238. package/dist/state/skill-active.d.ts.map +1 -1
  239. package/dist/state/skill-active.js +25 -8
  240. package/dist/state/skill-active.js.map +1 -1
  241. package/dist/state/workflow-transition-reconcile.d.ts +1 -0
  242. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  243. package/dist/state/workflow-transition-reconcile.js +22 -15
  244. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  245. package/dist/state/workflow-transition.js +3 -3
  246. package/dist/state/workflow-transition.js.map +1 -1
  247. package/dist/team/__tests__/approved-execution.test.js +84 -1
  248. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  249. package/dist/team/__tests__/runtime.test.js +178 -19
  250. package/dist/team/__tests__/runtime.test.js.map +1 -1
  251. package/dist/team/__tests__/scaling.test.js +497 -2
  252. package/dist/team/__tests__/scaling.test.js.map +1 -1
  253. package/dist/team/__tests__/state-root.test.js +1 -1
  254. package/dist/team/__tests__/state-root.test.js.map +1 -1
  255. package/dist/team/__tests__/worker-bootstrap.test.js +45 -0
  256. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  257. package/dist/team/approved-execution.d.ts +1 -0
  258. package/dist/team/approved-execution.d.ts.map +1 -1
  259. package/dist/team/approved-execution.js +53 -0
  260. package/dist/team/approved-execution.js.map +1 -1
  261. package/dist/team/delivery-log.d.ts.map +1 -1
  262. package/dist/team/delivery-log.js +8 -1
  263. package/dist/team/delivery-log.js.map +1 -1
  264. package/dist/team/runtime.d.ts.map +1 -1
  265. package/dist/team/runtime.js +104 -18
  266. package/dist/team/runtime.js.map +1 -1
  267. package/dist/team/scaling.d.ts.map +1 -1
  268. package/dist/team/scaling.js +43 -0
  269. package/dist/team/scaling.js.map +1 -1
  270. package/dist/team/state/mailbox.d.ts +1 -0
  271. package/dist/team/state/mailbox.d.ts.map +1 -1
  272. package/dist/team/state/mailbox.js +10 -1
  273. package/dist/team/state/mailbox.js.map +1 -1
  274. package/dist/team/state-root.d.ts.map +1 -1
  275. package/dist/team/state-root.js +5 -1
  276. package/dist/team/state-root.js.map +1 -1
  277. package/dist/team/state.d.ts.map +1 -1
  278. package/dist/team/state.js +3 -7
  279. package/dist/team/state.js.map +1 -1
  280. package/dist/team/worker-bootstrap.d.ts +7 -2
  281. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  282. package/dist/team/worker-bootstrap.js +17 -4
  283. package/dist/team/worker-bootstrap.js.map +1 -1
  284. package/dist/ultragoal/__tests__/artifacts.test.js +124 -1
  285. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  286. package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
  287. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  288. package/dist/ultragoal/artifacts.d.ts +44 -2
  289. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  290. package/dist/ultragoal/artifacts.js +197 -13
  291. package/dist/ultragoal/artifacts.js.map +1 -1
  292. package/dist/wiki/lifecycle.js +1 -1
  293. package/dist/wiki/lifecycle.js.map +1 -1
  294. package/package.json +1 -1
  295. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  296. package/plugins/oh-my-codex/.mcp.json +5 -5
  297. package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
  298. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
  299. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
  300. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
  301. package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
  302. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
  303. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
  304. package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
  305. package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
  306. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
  307. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
  308. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
  309. package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
  310. package/skills/analyze/SKILL.md +0 -2
  311. package/skills/ask-claude/SKILL.md +5 -3
  312. package/skills/ask-gemini/SKILL.md +5 -3
  313. package/skills/autopilot/SKILL.md +2 -2
  314. package/skills/code-review/SKILL.md +1 -3
  315. package/skills/deep-interview/SKILL.md +5 -7
  316. package/skills/doctor/SKILL.md +2 -2
  317. package/skills/ecomode/SKILL.md +105 -1
  318. package/skills/frontend-ui-ux/SKILL.md +4 -26
  319. package/skills/git-master/SKILL.md +2 -4
  320. package/skills/omx-setup/SKILL.md +3 -3
  321. package/skills/pipeline/SKILL.md +3 -3
  322. package/skills/plan/SKILL.md +3 -6
  323. package/skills/ralph/SKILL.md +9 -10
  324. package/skills/swarm/SKILL.md +5 -3
  325. package/skills/tdd/SKILL.md +95 -1
  326. package/skills/ultragoal/SKILL.md +36 -3
  327. package/skills/ultraqa/SKILL.md +21 -24
  328. package/skills/ultrawork/SKILL.md +8 -8
  329. package/skills/web-clone/SKILL.md +348 -1
  330. package/skills/wiki/SKILL.md +13 -13
  331. package/src/scripts/__tests__/codex-native-hook.test.ts +389 -24
  332. package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
  333. package/src/scripts/codex-native-hook.ts +168 -64
  334. package/src/scripts/codex-native-pre-post.ts +4 -1
  335. package/src/scripts/notify-dispatcher.ts +113 -0
  336. package/src/scripts/notify-fallback-watcher.ts +6 -2
  337. package/src/scripts/notify-hook/ralph-session-resume.ts +117 -8
  338. package/src/scripts/notify-hook/state-io.ts +4 -2
  339. package/src/scripts/notify-hook/visual-verdict.ts +3 -3
  340. package/src/scripts/notify-hook.ts +119 -1
@@ -6,10 +6,10 @@ import { pathToFileURL } from "url";
6
6
  import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
7
7
  import {
8
8
  extractSessionIdFromInitializedStatePath,
9
- getSkillActiveStatePaths,
9
+ getSkillActiveStatePathsForStateDir,
10
10
  listActiveSkills,
11
11
  readSkillActiveState,
12
- readVisibleSkillActiveState,
12
+ readVisibleSkillActiveStateForStateDir,
13
13
  type SkillActiveStateLike,
14
14
  } from "../state/skill-active.js";
15
15
  import {
@@ -35,7 +35,7 @@ import {
35
35
  } from "../team/state.js";
36
36
  import { omxNotepadPath, omxProjectMemoryPath } from "../utils/paths.js";
37
37
  import { findGitLayout } from "../utils/git-layout.js";
38
- import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
38
+ import { getBaseStateDir, getStateFilePath, getStatePath } from "../mcp/state-paths.js";
39
39
  import {
40
40
  detectKeywords,
41
41
  detectPrimaryKeyword,
@@ -71,12 +71,12 @@ import type { HookEventEnvelope } from "../hooks/extensibility/types.js";
71
71
  import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
72
72
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
73
73
  import {
74
- onPostCompact as buildWikiPostCompactContext,
75
74
  onPreCompact as buildWikiPreCompactContext,
76
75
  onSessionStart as buildWikiSessionStartContext,
77
76
  } from "../wiki/lifecycle.js";
78
77
  import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
79
78
  import { readRunState } from "../runtime/run-state.js";
79
+ import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
80
80
  import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
81
81
  import { triagePrompt } from "../hooks/triage-heuristic.js";
82
82
  import { readTriageConfig } from "../hooks/triage-config.js";
@@ -486,6 +486,12 @@ interface ActiveRalphStopState {
486
486
  path: string;
487
487
  }
488
488
 
489
+ interface RalphCompletionAuditBlockState {
490
+ state: Record<string, unknown>;
491
+ path: string;
492
+ reason: string;
493
+ }
494
+
489
495
  interface RalphStopOwnershipContext {
490
496
  sessionId: string;
491
497
  payloadSessionId: string;
@@ -560,8 +566,8 @@ async function readCanonicalTerminalRunStateForStop(
560
566
  return shouldHonorCanonicalTerminalRunState(runRecord, mode) ? runRecord : null;
561
567
  }
562
568
 
563
- async function isVisibleRalphActiveForSession(cwd: string, sessionId: string): Promise<boolean> {
564
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
569
+ async function isVisibleRalphActiveForSession(stateDir: string, sessionId: string): Promise<boolean> {
570
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
565
571
  if (!canonicalState) return false;
566
572
  return listActiveSkills(canonicalState).some((entry) => (
567
573
  entry.skill === "ralph"
@@ -569,8 +575,8 @@ async function isVisibleRalphActiveForSession(cwd: string, sessionId: string): P
569
575
  ));
570
576
  }
571
577
 
572
- async function hasConsistentRalphSkillActivation(cwd: string, sessionId: string): Promise<boolean> {
573
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
578
+ async function hasConsistentRalphSkillActivation(stateDir: string, sessionId: string): Promise<boolean> {
579
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
574
580
  if (!canonicalState) return true;
575
581
 
576
582
  const initializedMode = safeString(canonicalState.initialized_mode).trim();
@@ -582,7 +588,74 @@ async function hasConsistentRalphSkillActivation(cwd: string, sessionId: string)
582
588
  return true;
583
589
  }
584
590
 
591
+
592
+ async function readRalphCompletionAuditBlockState(
593
+ cwd: string,
594
+ stateDir: string,
595
+ preferredSessionId?: string,
596
+ ownerContext?: {
597
+ payloadSessionId?: string;
598
+ threadId?: string;
599
+ tmuxPaneId?: string;
600
+ },
601
+ ): Promise<RalphCompletionAuditBlockState | null> {
602
+ const [rawSessionInfo, usableSessionInfo] = await Promise.all([
603
+ readSessionState(cwd),
604
+ readUsableSessionState(cwd),
605
+ ]);
606
+ const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
607
+ const currentNativeSessionId = safeString(usableSessionInfo?.native_session_id).trim();
608
+ const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
609
+ ? safeString(rawSessionInfo.session_id).trim()
610
+ : "";
611
+ const sessionCandidates = [...new Set([
612
+ safeString(preferredSessionId).trim(),
613
+ currentOmxSessionId,
614
+ ].filter(Boolean))];
615
+
616
+ const evaluateCandidate = (state: Record<string, unknown> | null, path: string, sessionId: string): RalphCompletionAuditBlockState | null => {
617
+ if (!state || state.mode && safeString(state.mode) !== "ralph") return null;
618
+ if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase)) return null;
619
+ if (activeRalphStateMatchesStopOwner(state, {
620
+ sessionId,
621
+ payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
622
+ threadId: safeString(ownerContext?.threadId).trim(),
623
+ currentNativeSessionId,
624
+ tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
625
+ }) !== true) return null;
626
+ const audit = evaluateRalphCompletionAuditEvidence(state, cwd);
627
+ return audit.complete ? null : { state, path, reason: audit.reason };
628
+ };
629
+
630
+ for (const sessionId of sessionCandidates) {
631
+ if (staleCurrentSessionId && sessionId === staleCurrentSessionId) continue;
632
+ const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
633
+ const result = evaluateCandidate(await readJsonIfExists(sessionScopedPath), sessionScopedPath, sessionId);
634
+ if (result) return result;
635
+ }
636
+
637
+ if (sessionCandidates.length > 0) return null;
638
+
639
+ const directPath = join(stateDir, "ralph-state.json");
640
+ return evaluateCandidate(await readJsonIfExists(directPath), directPath, "");
641
+ }
642
+
643
+ async function reopenRalphCompletionAuditBlock(block: RalphCompletionAuditBlockState): Promise<void> {
644
+ const nowIso = new Date().toISOString();
645
+ const next: Record<string, unknown> = {
646
+ ...block.state,
647
+ active: true,
648
+ current_phase: "verifying",
649
+ completion_audit_gate: "blocked",
650
+ completion_audit_missing_reason: block.reason,
651
+ completion_audit_blocked_at: nowIso,
652
+ };
653
+ delete next.completed_at;
654
+ await writeFile(block.path, JSON.stringify(next, null, 2));
655
+ }
656
+
585
657
  async function readActiveRalphState(
658
+ cwd: string,
586
659
  stateDir: string,
587
660
  preferredSessionId?: string,
588
661
  ownerContext?: {
@@ -591,7 +664,6 @@ async function readActiveRalphState(
591
664
  tmuxPaneId?: string;
592
665
  },
593
666
  ): Promise<ActiveRalphStopState | null> {
594
- const cwd = resolve(stateDir, "..", "..");
595
667
  const [rawSessionInfo, usableSessionInfo] = await Promise.all([
596
668
  readSessionState(cwd),
597
669
  readUsableSessionState(cwd),
@@ -621,7 +693,7 @@ async function readActiveRalphState(
621
693
  if (
622
694
  sessionScoped?.active === true
623
695
  && isRalphStartingPhase(sessionScoped)
624
- && !(await isVisibleRalphActiveForSession(cwd, sessionId))
696
+ && !(await isVisibleRalphActiveForSession(stateDir, sessionId))
625
697
  ) {
626
698
  continue;
627
699
  }
@@ -635,7 +707,7 @@ async function readActiveRalphState(
635
707
  currentNativeSessionId,
636
708
  tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
637
709
  })
638
- && await hasConsistentRalphSkillActivation(cwd, sessionId)
710
+ && await hasConsistentRalphSkillActivation(stateDir, sessionId)
639
711
  ) {
640
712
  return { state: sessionScoped, path: sessionScopedPath };
641
713
  }
@@ -1314,6 +1386,10 @@ function buildNativeOutsideTmuxTeamPromptBlockState(
1314
1386
  };
1315
1387
  }
1316
1388
 
1389
+ function buildSkillStateCliInstruction(mode: string, statePath: string): string {
1390
+ return `skill: ${mode} activated and initial state initialized at ${statePath}; use CLI-first state updates via \`omx state write/read/clear --input '<json>' --json\`; use omx_state MCP only when explicit MCP compatibility is enabled.`;
1391
+ }
1392
+
1317
1393
  function buildAdditionalContextMessage(
1318
1394
  prompt: string,
1319
1395
  skillState?: SkillActiveState | null,
@@ -1375,7 +1451,7 @@ function buildAdditionalContextMessage(
1375
1451
  promptPriorityMessage,
1376
1452
  ultragoalPromptActivationNote,
1377
1453
  skillState.initialized_mode && skillState.initialized_state_path
1378
- ? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
1454
+ ? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
1379
1455
  : null,
1380
1456
  teamDetected
1381
1457
  ? buildTeamRuntimeInstruction(cwd, payload)
@@ -1387,7 +1463,7 @@ function buildAdditionalContextMessage(
1387
1463
 
1388
1464
  if (teamDetected) {
1389
1465
  const initializedStateMessage = skillState?.initialized_mode && skillState.initialized_state_path
1390
- ? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
1466
+ ? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
1391
1467
  : null;
1392
1468
  return [
1393
1469
  detectedKeywordMessage,
@@ -1414,7 +1490,7 @@ function buildAdditionalContextMessage(
1414
1490
  ? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
1415
1491
  : null,
1416
1492
  promptPriorityMessage,
1417
- `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`,
1493
+ buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path),
1418
1494
  deepInterviewPromptActivationNote,
1419
1495
  ultraworkPromptActivationNote,
1420
1496
  ultragoalPromptActivationNote,
@@ -1481,7 +1557,7 @@ async function resolveTeamWorkerStopDecision(
1481
1557
  const blockWorkerStop = (
1482
1558
  reasonCode: string,
1483
1559
  detail: string,
1484
- stateDirForDecision = join(cwd, ".omx", "state"),
1560
+ stateDirForDecision = getBaseStateDir(cwd),
1485
1561
  ): TeamWorkerStopDecision => ({
1486
1562
  kind: "blocked",
1487
1563
  stateDir: stateDirForDecision,
@@ -1654,7 +1730,10 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
1654
1730
  if (!entry.isDirectory()) continue;
1655
1731
  const mission = await readJsonIfExists(join(autoresearchRoot, entry.name, "mission.json"));
1656
1732
  const status = safeString(mission?.status);
1657
- if (mission?.workflow === "autoresearch-goal" && status && status !== "complete") {
1733
+ const completion = await readJsonIfExists(join(autoresearchRoot, entry.name, "completion.json"));
1734
+ const completionVerdict = safeString(completion?.verdict);
1735
+ const completionPassed = completion?.passed === true || completionVerdict === "pass";
1736
+ if (mission?.workflow === "autoresearch-goal" && status && status !== "complete" && completionPassed) {
1658
1737
  return {
1659
1738
  workflow: "autoresearch-goal",
1660
1739
  command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
@@ -1696,6 +1775,7 @@ async function buildGoalWorkflowReconciliationStopOutput(
1696
1775
 
1697
1776
  async function readTeamModeStateForStop(
1698
1777
  cwd: string,
1778
+ stateDir: string,
1699
1779
  sessionId?: string,
1700
1780
  ): Promise<Record<string, unknown> | null> {
1701
1781
  const normalizedSessionId = safeString(sessionId).trim();
@@ -1703,10 +1783,10 @@ async function readTeamModeStateForStop(
1703
1783
  return await readModeState("team", cwd);
1704
1784
  }
1705
1785
 
1706
- const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId);
1786
+ const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
1707
1787
  if (scopedState) return scopedState;
1708
1788
 
1709
- const rootState = await readJsonIfExists(join(cwd, ".omx", "state", "team-state.json"));
1789
+ const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
1710
1790
  if (rootState?.active !== true) return null;
1711
1791
 
1712
1792
  const ownerSessionId = safeString(rootState.session_id).trim();
@@ -1721,7 +1801,7 @@ async function buildTeamStopOutput(cwd: string, sessionId?: string): Promise<Rec
1721
1801
  if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
1722
1802
  return null;
1723
1803
  }
1724
- const teamState = await readTeamModeStateForStop(cwd, sessionId);
1804
+ const teamState = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId);
1725
1805
  if (teamState?.active !== true) return null;
1726
1806
  const teamName = safeString(teamState.team_name).trim();
1727
1807
  if (teamName) {
@@ -1779,12 +1859,13 @@ function hasReleaseReadinessMode(payload: CodexHookPayload): boolean {
1779
1859
 
1780
1860
  async function hasReleaseReadinessStopMarker(
1781
1861
  cwd: string,
1862
+ stateDir: string,
1782
1863
  sessionId: string,
1783
1864
  teamName: string,
1784
1865
  ): Promise<boolean> {
1785
1866
  if (!sessionId) return false;
1786
1867
 
1787
- const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId);
1868
+ const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId, stateDir);
1788
1869
  if (markerState?.active !== true || markerState.stable_final_recommendation_emitted !== true) {
1789
1870
  return false;
1790
1871
  }
@@ -1829,8 +1910,11 @@ async function readStopSessionPinnedState(
1829
1910
  fileName: string,
1830
1911
  cwd: string,
1831
1912
  sessionId: string,
1913
+ stateDir?: string,
1832
1914
  ): Promise<Record<string, unknown> | null> {
1833
- const statePath = getStateFilePath(fileName, cwd, sessionId || undefined);
1915
+ const statePath = stateDir && sessionId
1916
+ ? join(stateDir, "sessions", sessionId, fileName)
1917
+ : getStateFilePath(fileName, cwd, sessionId || undefined);
1834
1918
  return readJsonIfExists(statePath);
1835
1919
  }
1836
1920
 
@@ -1881,11 +1965,12 @@ function modeStateMatchesSkillStopContext(
1881
1965
 
1882
1966
  async function readBlockingSkillForStop(
1883
1967
  cwd: string,
1968
+ stateDir: string,
1884
1969
  sessionId: string,
1885
1970
  threadId: string,
1886
1971
  requiredSkill?: string,
1887
1972
  ): Promise<{ skill: string; phase: string; latestPlanPath?: string; planningComplete?: boolean; runOutcome?: string } | null> {
1888
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
1973
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
1889
1974
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
1890
1975
  const candidateSkills = requiredSkill
1891
1976
  ? [requiredSkill]
@@ -1895,7 +1980,7 @@ async function readBlockingSkillForStop(
1895
1980
  const terminalRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, skill);
1896
1981
  if (terminalRunState) continue;
1897
1982
 
1898
- const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId);
1983
+ const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
1899
1984
  if (!modeState || modeState.active !== true) continue;
1900
1985
  if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId)) continue;
1901
1986
 
@@ -1955,11 +2040,12 @@ function isTerminalOrInactiveModeState(state: Record<string, unknown> | null): b
1955
2040
 
1956
2041
  async function readSessionScopedModeStateForRootSkill(
1957
2042
  cwd: string,
2043
+ stateDir: string,
1958
2044
  skill: string,
1959
2045
  sessionIds: string[],
1960
2046
  ): Promise<Record<string, unknown> | null> {
1961
2047
  for (const sessionId of sessionIds) {
1962
- const state = await readJsonIfExists(getStateFilePath(`${skill}-state.json`, cwd, sessionId));
2048
+ const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
1963
2049
  if (state) return state;
1964
2050
  }
1965
2051
  return null;
@@ -1967,9 +2053,10 @@ async function readSessionScopedModeStateForRootSkill(
1967
2053
 
1968
2054
  async function reconcileStaleRootSkillActiveStateForStop(
1969
2055
  cwd: string,
2056
+ stateDir: string,
1970
2057
  sessionId: string,
1971
2058
  ): Promise<void> {
1972
- const { rootPath } = getSkillActiveStatePaths(cwd);
2059
+ const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
1973
2060
  const rootState = await readSkillActiveState(rootPath);
1974
2061
  if (!rootState?.active) return;
1975
2062
 
@@ -1995,7 +2082,7 @@ async function reconcileStaleRootSkillActiveStateForStop(
1995
2082
  initializedSessionId,
1996
2083
  safeString(rootState.session_id),
1997
2084
  ]);
1998
- const modeState = await readSessionScopedModeStateForRootSkill(cwd, skill, candidateSessionIds);
2085
+ const modeState = await readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, candidateSessionIds);
1999
2086
  if (isTerminalOrInactiveModeState(modeState)) {
2000
2087
  changed = true;
2001
2088
  continue;
@@ -2074,12 +2161,13 @@ function buildRalplanContinuationStatus(
2074
2161
 
2075
2162
  async function readStopAutoNudgePhase(
2076
2163
  cwd: string,
2164
+ stateDir: string,
2077
2165
  sessionId: string,
2078
2166
  threadId: string,
2079
2167
  ): Promise<string> {
2080
2168
  const normalizedSessionId = sessionId.trim();
2081
2169
  if (normalizedSessionId) {
2082
- const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
2170
+ const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
2083
2171
  if (
2084
2172
  scopedModeState?.active === true
2085
2173
  && safeString(scopedModeState.current_phase).trim().toLowerCase() === "intent-first"
@@ -2087,7 +2175,7 @@ async function readStopAutoNudgePhase(
2087
2175
  return "planning";
2088
2176
  }
2089
2177
  } else {
2090
- const rootModeState = await readJsonIfExists(join(cwd, ".omx", "state", "deep-interview-state.json"));
2178
+ const rootModeState = await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
2091
2179
  if (
2092
2180
  rootModeState?.active === true
2093
2181
  && safeString(rootModeState.current_phase).trim().toLowerCase() === "intent-first"
@@ -2098,7 +2186,7 @@ async function readStopAutoNudgePhase(
2098
2186
 
2099
2187
  if (!normalizedSessionId) return "";
2100
2188
 
2101
- const canonicalState = await readVisibleSkillActiveState(cwd, normalizedSessionId);
2189
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, normalizedSessionId);
2102
2190
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
2103
2191
  const deepInterview = visibleEntries.find((entry) => (
2104
2192
  entry.skill === "deep-interview"
@@ -2106,7 +2194,7 @@ async function readStopAutoNudgePhase(
2106
2194
  ));
2107
2195
  if (!deepInterview) return "";
2108
2196
 
2109
- const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
2197
+ const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
2110
2198
  if (!modeState || modeState.active !== true) return "";
2111
2199
 
2112
2200
  const modePhase = safeString(modeState.current_phase).trim().toLowerCase();
@@ -2115,11 +2203,12 @@ async function readStopAutoNudgePhase(
2115
2203
 
2116
2204
  async function buildDeepInterviewQuestionStopOutput(
2117
2205
  cwd: string,
2206
+ stateDir: string,
2118
2207
  sessionId: string,
2119
2208
  threadId: string,
2120
2209
  ): Promise<{ output: Record<string, unknown>; obligationId: string } | null> {
2121
2210
  await reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords(cwd, sessionId);
2122
- const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
2211
+ const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir);
2123
2212
  if (!modeState) return null;
2124
2213
 
2125
2214
  const questionEnforcement = safeObject(modeState.question_enforcement);
@@ -2131,7 +2220,7 @@ async function buildDeepInterviewQuestionStopOutput(
2131
2220
  return null;
2132
2221
  }
2133
2222
 
2134
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
2223
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
2135
2224
  if (canonicalState) {
2136
2225
  const blocker = listActiveSkills(canonicalState).find((entry) => (
2137
2226
  entry.skill === "deep-interview"
@@ -2334,9 +2423,10 @@ async function findCanonicalActiveTeamForSession(
2334
2423
 
2335
2424
  async function resolveActiveTeamNameForStop(
2336
2425
  cwd: string,
2426
+ stateDir: string,
2337
2427
  sessionId: string,
2338
2428
  ): Promise<string> {
2339
- const directState = await readTeamModeStateForStop(cwd, sessionId);
2429
+ const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
2340
2430
  const directTeamName = safeString(directState?.team_name).trim();
2341
2431
  if (directState?.active === true && directTeamName) return directTeamName;
2342
2432
 
@@ -2352,12 +2442,12 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(
2352
2442
  ): Promise<{ matched: boolean; output: Record<string, unknown> | null }> {
2353
2443
  if (!sessionId) return { matched: false, output: null };
2354
2444
 
2355
- const teamName = await resolveActiveTeamNameForStop(cwd, sessionId);
2445
+ const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
2356
2446
  if (!teamName) return { matched: false, output: null };
2357
2447
 
2358
2448
  const explicitReleaseReadinessContext =
2359
2449
  hasReleaseReadinessMode(payload)
2360
- || await hasReleaseReadinessStopMarker(cwd, sessionId, teamName);
2450
+ || await hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName);
2361
2451
  if (!explicitReleaseReadinessContext) {
2362
2452
  return { matched: false, output: null };
2363
2453
  }
@@ -2395,10 +2485,11 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(
2395
2485
 
2396
2486
  async function buildSkillStopOutput(
2397
2487
  cwd: string,
2488
+ stateDir: string,
2398
2489
  sessionId: string,
2399
2490
  threadId: string,
2400
2491
  ): Promise<Record<string, unknown> | null> {
2401
- const blocker = await readBlockingSkillForStop(cwd, sessionId, threadId);
2492
+ const blocker = await readBlockingSkillForStop(cwd, stateDir, sessionId, threadId);
2402
2493
  if (!blocker) return null;
2403
2494
 
2404
2495
  const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
@@ -2545,17 +2636,41 @@ async function buildStopHookOutput(
2545
2636
  const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
2546
2637
  const threadId = readPayloadThreadId(payload);
2547
2638
  if (canonicalSessionId) {
2548
- await reconcileStaleRootSkillActiveStateForStop(cwd, canonicalSessionId);
2639
+ await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
2549
2640
  }
2550
2641
  const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
2551
2642
  if (execFollowupOutput) return execFollowupOutput;
2643
+ const ralphOwnerContext = {
2644
+ payloadSessionId: sessionId,
2645
+ threadId,
2646
+ tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
2647
+ };
2648
+ const ralphCompletionAuditBlock = options.skipRalphStopBlock === true
2649
+ ? null
2650
+ : await readRalphCompletionAuditBlockState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
2651
+ if (ralphCompletionAuditBlock) {
2652
+ await reopenRalphCompletionAuditBlock(ralphCompletionAuditBlock);
2653
+ const blockingPath = formatStopStatePath(cwd, ralphCompletionAuditBlock.path);
2654
+ const systemMessage =
2655
+ `OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}); continue verification, record a prompt-to-artifact checklist plus verification evidence, and do not report complete yet.`;
2656
+ return await returnPersistentStopBlock(
2657
+ payload,
2658
+ stateDir,
2659
+ "ralph-completion-audit-stop",
2660
+ `${blockingPath}|${ralphCompletionAuditBlock.reason}`,
2661
+ {
2662
+ decision: "block",
2663
+ reason: systemMessage,
2664
+ stopReason: `ralph_completion_audit_${ralphCompletionAuditBlock.reason}`,
2665
+ systemMessage,
2666
+ },
2667
+ canonicalSessionId,
2668
+ { allowRepeatDuringStopHook: true },
2669
+ );
2670
+ }
2552
2671
  const ralphState = options.skipRalphStopBlock === true
2553
2672
  ? null
2554
- : await readActiveRalphState(stateDir, canonicalSessionId, {
2555
- payloadSessionId: sessionId,
2556
- threadId,
2557
- tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
2558
- });
2673
+ : await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
2559
2674
  if (!ralphState) {
2560
2675
  const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
2561
2676
  if (autoresearchState) {
@@ -2665,6 +2780,7 @@ async function buildStopHookOutput(
2665
2780
  if (canonicalSessionId) {
2666
2781
  const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(
2667
2782
  cwd,
2783
+ stateDir,
2668
2784
  canonicalSessionId,
2669
2785
  threadId,
2670
2786
  );
@@ -2698,7 +2814,7 @@ async function buildStopHookOutput(
2698
2814
  if (repeatedCanonicalTeamOutput) return repeatedCanonicalTeamOutput;
2699
2815
  }
2700
2816
 
2701
- const skillOutput = await buildSkillStopOutput(cwd, canonicalSessionId, threadId);
2817
+ const skillOutput = await buildSkillStopOutput(cwd, stateDir, canonicalSessionId, threadId);
2702
2818
  if (skillOutput) {
2703
2819
  return await returnPersistentStopBlock(
2704
2820
  payload,
@@ -2728,7 +2844,7 @@ async function buildStopHookOutput(
2728
2844
  );
2729
2845
  }
2730
2846
  const autoNudgeConfig = await loadAutoNudgeConfig();
2731
- const autoNudgePhase = await readStopAutoNudgePhase(cwd, canonicalSessionId, threadId);
2847
+ const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
2732
2848
 
2733
2849
  if (
2734
2850
  autoNudgeConfig.enabled
@@ -2814,7 +2930,9 @@ export async function dispatchCodexNativeHook(
2814
2930
  ): Promise<NativeHookDispatchResult> {
2815
2931
  const hookEventName = readHookEventName(payload);
2816
2932
  const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
2817
- const stateDir = join(cwd, ".omx", "state");
2933
+ // Native hooks must use the same authoritative runtime state root as HUD/MCP
2934
+ // when boxed/team roots are active; do not bypass it with cwd/.omx/state.
2935
+ const stateDir = getBaseStateDir(cwd);
2818
2936
  await mkdir(stateDir, { recursive: true });
2819
2937
 
2820
2938
  const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
@@ -2916,6 +3034,7 @@ export async function dispatchCodexNativeHook(
2916
3034
  turnId || undefined,
2917
3035
  ) ?? await recordSkillActivation({
2918
3036
  stateDir,
3037
+ sourceCwd: cwd,
2919
3038
  text: prompt,
2920
3039
  sessionId: sessionIdForState,
2921
3040
  threadId,
@@ -3023,25 +3142,10 @@ export async function dispatchCodexNativeHook(
3023
3142
  }
3024
3143
 
3025
3144
  if (hookEventName === "PreCompact") {
3026
- const compactContext = buildWikiPreCompactContext({ cwd });
3027
- if (compactContext.additionalContext) {
3028
- outputJson = {
3029
- hookSpecificOutput: {
3030
- hookEventName,
3031
- additionalContext: compactContext.additionalContext,
3032
- },
3033
- };
3034
- }
3035
- } else if (hookEventName === "PostCompact") {
3036
- const compactContext = buildWikiPostCompactContext({ cwd });
3037
- if (compactContext.additionalContext) {
3038
- outputJson = {
3039
- hookSpecificOutput: {
3040
- hookEventName,
3041
- additionalContext: compactContext.additionalContext,
3042
- },
3043
- };
3044
- }
3145
+ // Codex native PreCompact currently accepts only the common continuation fields.
3146
+ // Keep the OMX lifecycle dispatch above, but do not emit `hookSpecificOutput`
3147
+ // unless Codex defines a supported PreCompact output contract.
3148
+ buildWikiPreCompactContext({ cwd });
3045
3149
  } else if ((hookEventName === "SessionStart" && !skipCanonicalSessionStartContext) || hookEventName === "UserPromptSubmit") {
3046
3150
  const additionalContext = hookEventName === "SessionStart"
3047
3151
  ? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId, {
@@ -185,7 +185,10 @@ function resolveOmxParityTarget(toolName: string): { command: OmxParityCommand;
185
185
  if (!match) return null;
186
186
 
187
187
  const [, server, tool] = match;
188
- if (server === "state") return { command: "state", tool };
188
+ if (server === "state") {
189
+ const stateTool = tool.replace(/^state_/, "").replace(/_/g, "-");
190
+ return { command: "state", tool: stateTool };
191
+ }
189
192
  if (server === "trace") return { command: "trace", tool };
190
193
  if (server === "code_intel") return { command: "code-intel", tool };
191
194
  if (server === "memory" && tool.startsWith("notepad_")) {