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
@@ -4,14 +4,14 @@ import { appendFile, mkdir, readFile, readdir, 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";
7
- import { extractSessionIdFromInitializedStatePath, getSkillActiveStatePaths, listActiveSkills, readSkillActiveState, readVisibleSkillActiveState, } from "../state/skill-active.js";
7
+ import { extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
8
8
  import { readSubagentSessionSummary, recordSubagentTurnForSession, } from "../subagents/tracker.js";
9
9
  import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
10
10
  import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
11
11
  import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
12
12
  import { omxNotepadPath, omxProjectMemoryPath } from "../utils/paths.js";
13
13
  import { findGitLayout } from "../utils/git-layout.js";
14
- import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
14
+ import { getBaseStateDir, getStateFilePath, getStatePath } from "../mcp/state-paths.js";
15
15
  import { detectKeywords, detectPrimaryKeyword, recordSkillActivation, } from "../hooks/keyword-detector.js";
16
16
  import { detectNativeStopStallPattern, loadAutoNudgeConfig, normalizeAutoNudgeSignatureText, resolveEffectiveAutoNudgeResponse, } from "./notify-hook/auto-nudge.js";
17
17
  import { SLOPPY_FALLBACK_GROUNDING_PATTERNS, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS, SLOPPY_FALLBACK_PHRASE_PATTERNS, buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTransportFailure, hasAnyPattern, } from "./codex-native-pre-post.js";
@@ -21,9 +21,10 @@ 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
23
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
24
- import { onPostCompact as buildWikiPostCompactContext, onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
24
+ import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
25
25
  import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
26
26
  import { readRunState } from "../runtime/run-state.js";
27
+ import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
27
28
  import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
28
29
  import { triagePrompt } from "../hooks/triage-heuristic.js";
29
30
  import { readTriageConfig } from "../hooks/triage-config.js";
@@ -381,15 +382,15 @@ async function readCanonicalTerminalRunStateForStop(cwd, sessionId, mode) {
381
382
  const runRecord = runState;
382
383
  return shouldHonorCanonicalTerminalRunState(runRecord, mode) ? runRecord : null;
383
384
  }
384
- async function isVisibleRalphActiveForSession(cwd, sessionId) {
385
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
385
+ async function isVisibleRalphActiveForSession(stateDir, sessionId) {
386
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
386
387
  if (!canonicalState)
387
388
  return false;
388
389
  return listActiveSkills(canonicalState).some((entry) => (entry.skill === "ralph"
389
390
  && matchesSkillStopContext(entry, canonicalState, sessionId, "")));
390
391
  }
391
- async function hasConsistentRalphSkillActivation(cwd, sessionId) {
392
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
392
+ async function hasConsistentRalphSkillActivation(stateDir, sessionId) {
393
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
393
394
  if (!canonicalState)
394
395
  return true;
395
396
  const initializedMode = safeString(canonicalState.initialized_mode).trim();
@@ -400,8 +401,63 @@ async function hasConsistentRalphSkillActivation(cwd, sessionId) {
400
401
  return false;
401
402
  return true;
402
403
  }
403
- async function readActiveRalphState(stateDir, preferredSessionId, ownerContext) {
404
- const cwd = resolve(stateDir, "..", "..");
404
+ async function readRalphCompletionAuditBlockState(cwd, stateDir, preferredSessionId, ownerContext) {
405
+ const [rawSessionInfo, usableSessionInfo] = await Promise.all([
406
+ readSessionState(cwd),
407
+ readUsableSessionState(cwd),
408
+ ]);
409
+ const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
410
+ const currentNativeSessionId = safeString(usableSessionInfo?.native_session_id).trim();
411
+ const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
412
+ ? safeString(rawSessionInfo.session_id).trim()
413
+ : "";
414
+ const sessionCandidates = [...new Set([
415
+ safeString(preferredSessionId).trim(),
416
+ currentOmxSessionId,
417
+ ].filter(Boolean))];
418
+ const evaluateCandidate = (state, path, sessionId) => {
419
+ if (!state || state.mode && safeString(state.mode) !== "ralph")
420
+ return null;
421
+ if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase))
422
+ return null;
423
+ if (activeRalphStateMatchesStopOwner(state, {
424
+ sessionId,
425
+ payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
426
+ threadId: safeString(ownerContext?.threadId).trim(),
427
+ currentNativeSessionId,
428
+ tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
429
+ }) !== true)
430
+ return null;
431
+ const audit = evaluateRalphCompletionAuditEvidence(state, cwd);
432
+ return audit.complete ? null : { state, path, reason: audit.reason };
433
+ };
434
+ for (const sessionId of sessionCandidates) {
435
+ if (staleCurrentSessionId && sessionId === staleCurrentSessionId)
436
+ continue;
437
+ const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
438
+ const result = evaluateCandidate(await readJsonIfExists(sessionScopedPath), sessionScopedPath, sessionId);
439
+ if (result)
440
+ return result;
441
+ }
442
+ if (sessionCandidates.length > 0)
443
+ return null;
444
+ const directPath = join(stateDir, "ralph-state.json");
445
+ return evaluateCandidate(await readJsonIfExists(directPath), directPath, "");
446
+ }
447
+ async function reopenRalphCompletionAuditBlock(block) {
448
+ const nowIso = new Date().toISOString();
449
+ const next = {
450
+ ...block.state,
451
+ active: true,
452
+ current_phase: "verifying",
453
+ completion_audit_gate: "blocked",
454
+ completion_audit_missing_reason: block.reason,
455
+ completion_audit_blocked_at: nowIso,
456
+ };
457
+ delete next.completed_at;
458
+ await writeFile(block.path, JSON.stringify(next, null, 2));
459
+ }
460
+ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
405
461
  const [rawSessionInfo, usableSessionInfo] = await Promise.all([
406
462
  readSessionState(cwd),
407
463
  readUsableSessionState(cwd),
@@ -429,7 +485,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
429
485
  const sessionScoped = await readJsonIfExists(sessionScopedPath);
430
486
  if (sessionScoped?.active === true
431
487
  && isRalphStartingPhase(sessionScoped)
432
- && !(await isVisibleRalphActiveForSession(cwd, sessionId))) {
488
+ && !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
433
489
  continue;
434
490
  }
435
491
  if (sessionScoped?.active === true
@@ -441,7 +497,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
441
497
  currentNativeSessionId,
442
498
  tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
443
499
  })
444
- && await hasConsistentRalphSkillActivation(cwd, sessionId)) {
500
+ && await hasConsistentRalphSkillActivation(stateDir, sessionId)) {
445
501
  return { state: sessionScoped, path: sessionScopedPath };
446
502
  }
447
503
  }
@@ -1030,6 +1086,9 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
1030
1086
  transition_error: "Codex App/native outside-tmux sessions cannot activate the tmux-only `team` workflow directly. Launch OMX CLI from an attached tmux shell first, then run `omx team ...` there.",
1031
1087
  };
1032
1088
  }
1089
+ function buildSkillStateCliInstruction(mode, statePath) {
1090
+ 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.`;
1091
+ }
1033
1092
  function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
1034
1093
  if (!prompt)
1035
1094
  return null;
@@ -1089,7 +1148,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1089
1148
  promptPriorityMessage,
1090
1149
  ultragoalPromptActivationNote,
1091
1150
  skillState.initialized_mode && skillState.initialized_state_path
1092
- ? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
1151
+ ? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
1093
1152
  : null,
1094
1153
  teamDetected
1095
1154
  ? buildTeamRuntimeInstruction(cwd, payload)
@@ -1100,7 +1159,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1100
1159
  }
1101
1160
  if (teamDetected) {
1102
1161
  const initializedStateMessage = skillState?.initialized_mode && skillState.initialized_state_path
1103
- ? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
1162
+ ? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
1104
1163
  : null;
1105
1164
  return [
1106
1165
  detectedKeywordMessage,
@@ -1126,7 +1185,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1126
1185
  ? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
1127
1186
  : null,
1128
1187
  promptPriorityMessage,
1129
- `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`,
1188
+ buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path),
1130
1189
  deepInterviewPromptActivationNote,
1131
1190
  ultraworkPromptActivationNote,
1132
1191
  ultragoalPromptActivationNote,
@@ -1164,7 +1223,7 @@ async function resolveTeamWorkerStopDecision(cwd) {
1164
1223
  || parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER));
1165
1224
  if (!workerContext)
1166
1225
  return { kind: "unresolved", reason: "missing_worker_context" };
1167
- const blockWorkerStop = (reasonCode, detail, stateDirForDecision = join(cwd, ".omx", "state")) => ({
1226
+ const blockWorkerStop = (reasonCode, detail, stateDirForDecision = getBaseStateDir(cwd)) => ({
1168
1227
  kind: "blocked",
1169
1228
  stateDir: stateDirForDecision,
1170
1229
  workerContext,
@@ -1315,7 +1374,10 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
1315
1374
  continue;
1316
1375
  const mission = await readJsonIfExists(join(autoresearchRoot, entry.name, "mission.json"));
1317
1376
  const status = safeString(mission?.status);
1318
- if (mission?.workflow === "autoresearch-goal" && status && status !== "complete") {
1377
+ const completion = await readJsonIfExists(join(autoresearchRoot, entry.name, "completion.json"));
1378
+ const completionVerdict = safeString(completion?.verdict);
1379
+ const completionPassed = completion?.passed === true || completionVerdict === "pass";
1380
+ if (mission?.workflow === "autoresearch-goal" && status && status !== "complete" && completionPassed) {
1319
1381
  return {
1320
1382
  workflow: "autoresearch-goal",
1321
1383
  command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
@@ -1351,15 +1413,15 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
1351
1413
  systemMessage,
1352
1414
  };
1353
1415
  }
1354
- async function readTeamModeStateForStop(cwd, sessionId) {
1416
+ async function readTeamModeStateForStop(cwd, stateDir, sessionId) {
1355
1417
  const normalizedSessionId = safeString(sessionId).trim();
1356
1418
  if (!normalizedSessionId) {
1357
1419
  return await readModeState("team", cwd);
1358
1420
  }
1359
- const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId);
1421
+ const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
1360
1422
  if (scopedState)
1361
1423
  return scopedState;
1362
- const rootState = await readJsonIfExists(join(cwd, ".omx", "state", "team-state.json"));
1424
+ const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
1363
1425
  if (rootState?.active !== true)
1364
1426
  return null;
1365
1427
  const ownerSessionId = safeString(rootState.session_id).trim();
@@ -1372,7 +1434,7 @@ async function buildTeamStopOutput(cwd, sessionId) {
1372
1434
  if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
1373
1435
  return null;
1374
1436
  }
1375
- const teamState = await readTeamModeStateForStop(cwd, sessionId);
1437
+ const teamState = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId);
1376
1438
  if (teamState?.active !== true)
1377
1439
  return null;
1378
1440
  const teamName = safeString(teamState.team_name).trim();
@@ -1422,10 +1484,10 @@ function hasReleaseReadinessMode(payload) {
1422
1484
  const mode = safeString(payload.mode).trim().toLowerCase();
1423
1485
  return mode === "release-readiness";
1424
1486
  }
1425
- async function hasReleaseReadinessStopMarker(cwd, sessionId, teamName) {
1487
+ async function hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName) {
1426
1488
  if (!sessionId)
1427
1489
  return false;
1428
- const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId);
1490
+ const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId, stateDir);
1429
1491
  if (markerState?.active !== true || markerState.stable_final_recommendation_emitted !== true) {
1430
1492
  return false;
1431
1493
  }
@@ -1460,8 +1522,10 @@ async function resolveInternalSessionIdForPayload(cwd, payloadSessionId) {
1460
1522
  return canonicalSessionId;
1461
1523
  return payloadSessionId;
1462
1524
  }
1463
- async function readStopSessionPinnedState(fileName, cwd, sessionId) {
1464
- const statePath = getStateFilePath(fileName, cwd, sessionId || undefined);
1525
+ async function readStopSessionPinnedState(fileName, cwd, sessionId, stateDir) {
1526
+ const statePath = stateDir && sessionId
1527
+ ? join(stateDir, "sessions", sessionId, fileName)
1528
+ : getStateFilePath(fileName, cwd, sessionId || undefined);
1465
1529
  return readJsonIfExists(statePath);
1466
1530
  }
1467
1531
  function matchesSkillStopContext(entry, state, sessionId, threadId) {
@@ -1496,8 +1560,8 @@ function modeStateMatchesSkillStopContext(state, cwd, sessionId) {
1496
1560
  }
1497
1561
  return true;
1498
1562
  }
1499
- async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill) {
1500
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
1563
+ async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requiredSkill) {
1564
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
1501
1565
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
1502
1566
  const candidateSkills = requiredSkill
1503
1567
  ? [requiredSkill]
@@ -1506,7 +1570,7 @@ async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill)
1506
1570
  const terminalRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, skill);
1507
1571
  if (terminalRunState)
1508
1572
  continue;
1509
- const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId);
1573
+ const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
1510
1574
  if (!modeState || modeState.active !== true)
1511
1575
  continue;
1512
1576
  if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
@@ -1554,16 +1618,16 @@ function isTerminalOrInactiveModeState(state) {
1554
1618
  const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
1555
1619
  return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
1556
1620
  }
1557
- async function readSessionScopedModeStateForRootSkill(cwd, skill, sessionIds) {
1621
+ async function readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, sessionIds) {
1558
1622
  for (const sessionId of sessionIds) {
1559
- const state = await readJsonIfExists(getStateFilePath(`${skill}-state.json`, cwd, sessionId));
1623
+ const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
1560
1624
  if (state)
1561
1625
  return state;
1562
1626
  }
1563
1627
  return null;
1564
1628
  }
1565
- async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
1566
- const { rootPath } = getSkillActiveStatePaths(cwd);
1629
+ async function reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, sessionId) {
1630
+ const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
1567
1631
  const rootState = await readSkillActiveState(rootPath);
1568
1632
  if (!rootState?.active)
1569
1633
  return;
@@ -1590,7 +1654,7 @@ async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
1590
1654
  initializedSessionId,
1591
1655
  safeString(rootState.session_id),
1592
1656
  ]);
1593
- const modeState = await readSessionScopedModeStateForRootSkill(cwd, skill, candidateSessionIds);
1657
+ const modeState = await readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, candidateSessionIds);
1594
1658
  if (isTerminalOrInactiveModeState(modeState)) {
1595
1659
  changed = true;
1596
1660
  continue;
@@ -1649,17 +1713,17 @@ function buildRalplanContinuationStatus(blocker, activeSubagentCount) {
1649
1713
  systemMessage: `OMX ralplan status: continue_from_artifact at phase ${phase}; continue from the current ralplan artifact and finish by stating whether ralplan is complete, paused for review, waiting for input, or still continuing.`,
1650
1714
  };
1651
1715
  }
1652
- async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
1716
+ async function readStopAutoNudgePhase(cwd, stateDir, sessionId, threadId) {
1653
1717
  const normalizedSessionId = sessionId.trim();
1654
1718
  if (normalizedSessionId) {
1655
- const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
1719
+ const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
1656
1720
  if (scopedModeState?.active === true
1657
1721
  && safeString(scopedModeState.current_phase).trim().toLowerCase() === "intent-first") {
1658
1722
  return "planning";
1659
1723
  }
1660
1724
  }
1661
1725
  else {
1662
- const rootModeState = await readJsonIfExists(join(cwd, ".omx", "state", "deep-interview-state.json"));
1726
+ const rootModeState = await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
1663
1727
  if (rootModeState?.active === true
1664
1728
  && safeString(rootModeState.current_phase).trim().toLowerCase() === "intent-first") {
1665
1729
  return "planning";
@@ -1667,21 +1731,21 @@ async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
1667
1731
  }
1668
1732
  if (!normalizedSessionId)
1669
1733
  return "";
1670
- const canonicalState = await readVisibleSkillActiveState(cwd, normalizedSessionId);
1734
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, normalizedSessionId);
1671
1735
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
1672
1736
  const deepInterview = visibleEntries.find((entry) => (entry.skill === "deep-interview"
1673
1737
  && matchesSkillStopContext(entry, canonicalState ?? {}, normalizedSessionId, threadId)));
1674
1738
  if (!deepInterview)
1675
1739
  return "";
1676
- const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
1740
+ const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
1677
1741
  if (!modeState || modeState.active !== true)
1678
1742
  return "";
1679
1743
  const modePhase = safeString(modeState.current_phase).trim().toLowerCase();
1680
1744
  return modePhase === "intent-first" ? "planning" : "";
1681
1745
  }
1682
- async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
1746
+ async function buildDeepInterviewQuestionStopOutput(cwd, stateDir, sessionId, threadId) {
1683
1747
  await reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords(cwd, sessionId);
1684
- const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
1748
+ const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir);
1685
1749
  if (!modeState)
1686
1750
  return null;
1687
1751
  const questionEnforcement = safeObject(modeState.question_enforcement);
@@ -1692,7 +1756,7 @@ async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
1692
1756
  if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
1693
1757
  return null;
1694
1758
  }
1695
- const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
1759
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
1696
1760
  if (canonicalState) {
1697
1761
  const blocker = listActiveSkills(canonicalState).find((entry) => (entry.skill === "deep-interview"
1698
1762
  && matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
@@ -1833,8 +1897,8 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
1833
1897
  }
1834
1898
  return null;
1835
1899
  }
1836
- async function resolveActiveTeamNameForStop(cwd, sessionId) {
1837
- const directState = await readTeamModeStateForStop(cwd, sessionId);
1900
+ async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId) {
1901
+ const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
1838
1902
  const directTeamName = safeString(directState?.team_name).trim();
1839
1903
  if (directState?.active === true && directTeamName)
1840
1904
  return directTeamName;
@@ -1844,11 +1908,11 @@ async function resolveActiveTeamNameForStop(cwd, sessionId) {
1844
1908
  async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, sessionId) {
1845
1909
  if (!sessionId)
1846
1910
  return { matched: false, output: null };
1847
- const teamName = await resolveActiveTeamNameForStop(cwd, sessionId);
1911
+ const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
1848
1912
  if (!teamName)
1849
1913
  return { matched: false, output: null };
1850
1914
  const explicitReleaseReadinessContext = hasReleaseReadinessMode(payload)
1851
- || await hasReleaseReadinessStopMarker(cwd, sessionId, teamName);
1915
+ || await hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName);
1852
1916
  if (!explicitReleaseReadinessContext) {
1853
1917
  return { matched: false, output: null };
1854
1918
  }
@@ -1870,8 +1934,8 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateD
1870
1934
  }, sessionId);
1871
1935
  return { matched: true, output };
1872
1936
  }
1873
- async function buildSkillStopOutput(cwd, sessionId, threadId) {
1874
- const blocker = await readBlockingSkillForStop(cwd, sessionId, threadId);
1937
+ async function buildSkillStopOutput(cwd, stateDir, sessionId, threadId) {
1938
+ const blocker = await readBlockingSkillForStop(cwd, stateDir, sessionId, threadId);
1875
1939
  if (!blocker)
1876
1940
  return null;
1877
1941
  const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
@@ -1980,18 +2044,33 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
1980
2044
  const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
1981
2045
  const threadId = readPayloadThreadId(payload);
1982
2046
  if (canonicalSessionId) {
1983
- await reconcileStaleRootSkillActiveStateForStop(cwd, canonicalSessionId);
2047
+ await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
1984
2048
  }
1985
2049
  const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
1986
2050
  if (execFollowupOutput)
1987
2051
  return execFollowupOutput;
2052
+ const ralphOwnerContext = {
2053
+ payloadSessionId: sessionId,
2054
+ threadId,
2055
+ tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
2056
+ };
2057
+ const ralphCompletionAuditBlock = options.skipRalphStopBlock === true
2058
+ ? null
2059
+ : await readRalphCompletionAuditBlockState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
2060
+ if (ralphCompletionAuditBlock) {
2061
+ await reopenRalphCompletionAuditBlock(ralphCompletionAuditBlock);
2062
+ const blockingPath = formatStopStatePath(cwd, ralphCompletionAuditBlock.path);
2063
+ const systemMessage = `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.`;
2064
+ return await returnPersistentStopBlock(payload, stateDir, "ralph-completion-audit-stop", `${blockingPath}|${ralphCompletionAuditBlock.reason}`, {
2065
+ decision: "block",
2066
+ reason: systemMessage,
2067
+ stopReason: `ralph_completion_audit_${ralphCompletionAuditBlock.reason}`,
2068
+ systemMessage,
2069
+ }, canonicalSessionId, { allowRepeatDuringStopHook: true });
2070
+ }
1988
2071
  const ralphState = options.skipRalphStopBlock === true
1989
2072
  ? null
1990
- : await readActiveRalphState(stateDir, canonicalSessionId, {
1991
- payloadSessionId: sessionId,
1992
- threadId,
1993
- tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
1994
- });
2073
+ : await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
1995
2074
  if (!ralphState) {
1996
2075
  const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
1997
2076
  if (autoresearchState) {
@@ -2044,7 +2123,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2044
2123
  return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
2045
2124
  }
2046
2125
  if (canonicalSessionId) {
2047
- const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, canonicalSessionId, threadId);
2126
+ const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, stateDir, canonicalSessionId, threadId);
2048
2127
  if (deepInterviewQuestionOutput) {
2049
2128
  return await returnPersistentStopBlock(payload, stateDir, "deep-interview-question-stop", deepInterviewQuestionOutput.obligationId, deepInterviewQuestionOutput.output, canonicalSessionId);
2050
2129
  }
@@ -2057,7 +2136,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2057
2136
  if (repeatedCanonicalTeamOutput)
2058
2137
  return repeatedCanonicalTeamOutput;
2059
2138
  }
2060
- const skillOutput = await buildSkillStopOutput(cwd, canonicalSessionId, threadId);
2139
+ const skillOutput = await buildSkillStopOutput(cwd, stateDir, canonicalSessionId, threadId);
2061
2140
  if (skillOutput) {
2062
2141
  return await returnPersistentStopBlock(payload, stateDir, "skill-stop", safeString(skillOutput.stopReason), skillOutput, canonicalSessionId);
2063
2142
  }
@@ -2068,7 +2147,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2068
2147
  return await returnPersistentStopBlock(payload, stateDir, "goal-workflow-reconciliation-stop", safeString(goalWorkflowStopOutput.stopReason), goalWorkflowStopOutput, canonicalSessionId, { allowRepeatDuringStopHook: true });
2069
2148
  }
2070
2149
  const autoNudgeConfig = await loadAutoNudgeConfig();
2071
- const autoNudgePhase = await readStopAutoNudgePhase(cwd, canonicalSessionId, threadId);
2150
+ const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
2072
2151
  if (autoNudgeConfig.enabled
2073
2152
  && detectNativeStopStallPattern(lastAssistantMessage, autoNudgeConfig.patterns, autoNudgePhase)) {
2074
2153
  const effectiveResponse = resolveEffectiveAutoNudgeResponse(autoNudgeConfig.response);
@@ -2106,7 +2185,9 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2106
2185
  export async function dispatchCodexNativeHook(payload, options = {}) {
2107
2186
  const hookEventName = readHookEventName(payload);
2108
2187
  const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
2109
- const stateDir = join(cwd, ".omx", "state");
2188
+ // Native hooks must use the same authoritative runtime state root as HUD/MCP
2189
+ // when boxed/team roots are active; do not bypass it with cwd/.omx/state.
2190
+ const stateDir = getBaseStateDir(cwd);
2110
2191
  await mkdir(stateDir, { recursive: true });
2111
2192
  const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
2112
2193
  let skillState = null;
@@ -2176,6 +2257,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2176
2257
  if (prompt && !isSubagentPromptSubmit) {
2177
2258
  skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
2178
2259
  stateDir,
2260
+ sourceCwd: cwd,
2179
2261
  text: prompt,
2180
2262
  sessionId: sessionIdForState,
2181
2263
  threadId,
@@ -2282,26 +2364,10 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2282
2364
  });
2283
2365
  }
2284
2366
  if (hookEventName === "PreCompact") {
2285
- const compactContext = buildWikiPreCompactContext({ cwd });
2286
- if (compactContext.additionalContext) {
2287
- outputJson = {
2288
- hookSpecificOutput: {
2289
- hookEventName,
2290
- additionalContext: compactContext.additionalContext,
2291
- },
2292
- };
2293
- }
2294
- }
2295
- else if (hookEventName === "PostCompact") {
2296
- const compactContext = buildWikiPostCompactContext({ cwd });
2297
- if (compactContext.additionalContext) {
2298
- outputJson = {
2299
- hookSpecificOutput: {
2300
- hookEventName,
2301
- additionalContext: compactContext.additionalContext,
2302
- },
2303
- };
2304
- }
2367
+ // Codex native PreCompact currently accepts only the common continuation fields.
2368
+ // Keep the OMX lifecycle dispatch above, but do not emit `hookSpecificOutput`
2369
+ // unless Codex defines a supported PreCompact output contract.
2370
+ buildWikiPreCompactContext({ cwd });
2305
2371
  }
2306
2372
  else if ((hookEventName === "SessionStart" && !skipCanonicalSessionStartContext) || hookEventName === "UserPromptSubmit") {
2307
2373
  const additionalContext = hookEventName === "SessionStart"