oh-my-codex 0.18.6 → 0.18.7

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 (278) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +56 -7
  4. package/dist/agents/__tests__/definitions.test.js +11 -0
  5. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  6. package/dist/agents/__tests__/native-config.test.js +14 -5
  7. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  8. package/dist/agents/definitions.d.ts +2 -0
  9. package/dist/agents/definitions.d.ts.map +1 -1
  10. package/dist/agents/definitions.js +4 -1
  11. package/dist/agents/definitions.js.map +1 -1
  12. package/dist/agents/native-config.js +2 -2
  13. package/dist/agents/native-config.js.map +1 -1
  14. package/dist/autopilot/__tests__/fsm.test.d.ts +2 -0
  15. package/dist/autopilot/__tests__/fsm.test.d.ts.map +1 -0
  16. package/dist/autopilot/__tests__/fsm.test.js +75 -0
  17. package/dist/autopilot/__tests__/fsm.test.js.map +1 -0
  18. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts +2 -0
  19. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts.map +1 -0
  20. package/dist/autopilot/__tests__/ralplan-gate.test.js +79 -0
  21. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -0
  22. package/dist/autopilot/deep-interview-gate.d.ts +18 -0
  23. package/dist/autopilot/deep-interview-gate.d.ts.map +1 -0
  24. package/dist/autopilot/deep-interview-gate.js +256 -0
  25. package/dist/autopilot/deep-interview-gate.js.map +1 -0
  26. package/dist/autopilot/fsm.d.ts +13 -0
  27. package/dist/autopilot/fsm.d.ts.map +1 -0
  28. package/dist/autopilot/fsm.js +70 -0
  29. package/dist/autopilot/fsm.js.map +1 -0
  30. package/dist/autopilot/ralplan-gate.d.ts +17 -0
  31. package/dist/autopilot/ralplan-gate.d.ts.map +1 -0
  32. package/dist/autopilot/ralplan-gate.js +61 -0
  33. package/dist/autopilot/ralplan-gate.js.map +1 -0
  34. package/dist/cli/__tests__/index.test.js +24 -4
  35. package/dist/cli/__tests__/index.test.js.map +1 -1
  36. package/dist/cli/__tests__/launch-fallback.test.js +175 -6
  37. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  38. package/dist/cli/__tests__/question.test.js +100 -0
  39. package/dist/cli/__tests__/question.test.js.map +1 -1
  40. package/dist/cli/__tests__/setup-refresh.test.js +18 -0
  41. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  42. package/dist/cli/__tests__/team.test.js +2 -2
  43. package/dist/cli/__tests__/team.test.js.map +1 -1
  44. package/dist/cli/index.d.ts +3 -1
  45. package/dist/cli/index.d.ts.map +1 -1
  46. package/dist/cli/index.js +191 -36
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/cli/question.d.ts.map +1 -1
  49. package/dist/cli/question.js +36 -5
  50. package/dist/cli/question.js.map +1 -1
  51. package/dist/config/__tests__/deep-interview.test.js +7 -6
  52. package/dist/config/__tests__/deep-interview.test.js.map +1 -1
  53. package/dist/config/deep-interview.d.ts.map +1 -1
  54. package/dist/config/deep-interview.js +14 -4
  55. package/dist/config/deep-interview.js.map +1 -1
  56. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +8 -0
  57. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  58. package/dist/hooks/__tests__/deep-interview-contract.test.js +10 -0
  59. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  60. package/dist/hooks/__tests__/keyword-detector.test.js +649 -11
  61. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  62. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +63 -0
  63. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  64. package/dist/hooks/__tests__/session.test.js +25 -0
  65. package/dist/hooks/__tests__/session.test.js.map +1 -1
  66. package/dist/hooks/deep-interview-config-instruction.js +1 -1
  67. package/dist/hooks/deep-interview-config-instruction.js.map +1 -1
  68. package/dist/hooks/keyword-detector.d.ts +1 -0
  69. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  70. package/dist/hooks/keyword-detector.js +171 -21
  71. package/dist/hooks/keyword-detector.js.map +1 -1
  72. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  73. package/dist/hooks/keyword-registry.js +1 -0
  74. package/dist/hooks/keyword-registry.js.map +1 -1
  75. package/dist/hooks/session.d.ts +2 -0
  76. package/dist/hooks/session.d.ts.map +1 -1
  77. package/dist/hooks/session.js +13 -5
  78. package/dist/hooks/session.js.map +1 -1
  79. package/dist/hud/__tests__/authority.test.js +35 -0
  80. package/dist/hud/__tests__/authority.test.js.map +1 -1
  81. package/dist/hud/__tests__/index.test.js +168 -2
  82. package/dist/hud/__tests__/index.test.js.map +1 -1
  83. package/dist/hud/__tests__/reconcile.test.js +67 -13
  84. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  85. package/dist/hud/__tests__/state.test.js +80 -0
  86. package/dist/hud/__tests__/state.test.js.map +1 -1
  87. package/dist/hud/__tests__/tmux.test.js +134 -1
  88. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  89. package/dist/hud/authority.d.ts.map +1 -1
  90. package/dist/hud/authority.js +13 -2
  91. package/dist/hud/authority.js.map +1 -1
  92. package/dist/hud/index.d.ts +17 -0
  93. package/dist/hud/index.d.ts.map +1 -1
  94. package/dist/hud/index.js +64 -10
  95. package/dist/hud/index.js.map +1 -1
  96. package/dist/hud/reconcile.js +1 -1
  97. package/dist/hud/reconcile.js.map +1 -1
  98. package/dist/hud/state.d.ts.map +1 -1
  99. package/dist/hud/state.js +16 -1
  100. package/dist/hud/state.js.map +1 -1
  101. package/dist/hud/tmux.d.ts +2 -0
  102. package/dist/hud/tmux.d.ts.map +1 -1
  103. package/dist/hud/tmux.js +39 -2
  104. package/dist/hud/tmux.js.map +1 -1
  105. package/dist/mcp/__tests__/hermes-bridge.test.js +203 -7
  106. package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -1
  107. package/dist/mcp/__tests__/state-server.test.js +13 -1
  108. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  109. package/dist/mcp/hermes-bridge.d.ts +12 -2
  110. package/dist/mcp/hermes-bridge.d.ts.map +1 -1
  111. package/dist/mcp/hermes-bridge.js +83 -9
  112. package/dist/mcp/hermes-bridge.js.map +1 -1
  113. package/dist/modes/__tests__/base-autoresearch-contract.test.js +7 -1
  114. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
  115. package/dist/pipeline/__tests__/stages.test.js +130 -0
  116. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  117. package/dist/pipeline/orchestrator.js +1 -1
  118. package/dist/pipeline/orchestrator.js.map +1 -1
  119. package/dist/pipeline/stages/ralplan.d.ts +1 -0
  120. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  121. package/dist/pipeline/stages/ralplan.js +14 -5
  122. package/dist/pipeline/stages/ralplan.js.map +1 -1
  123. package/dist/question/__tests__/deep-interview.test.js +160 -2
  124. package/dist/question/__tests__/deep-interview.test.js.map +1 -1
  125. package/dist/question/__tests__/policy.test.js +63 -3
  126. package/dist/question/__tests__/policy.test.js.map +1 -1
  127. package/dist/question/__tests__/renderer.test.js +191 -2
  128. package/dist/question/__tests__/renderer.test.js.map +1 -1
  129. package/dist/question/__tests__/state.test.js +94 -3
  130. package/dist/question/__tests__/state.test.js.map +1 -1
  131. package/dist/question/__tests__/ui.test.js +4 -0
  132. package/dist/question/__tests__/ui.test.js.map +1 -1
  133. package/dist/question/autopilot-wait.d.ts +12 -2
  134. package/dist/question/autopilot-wait.d.ts.map +1 -1
  135. package/dist/question/autopilot-wait.js +158 -47
  136. package/dist/question/autopilot-wait.js.map +1 -1
  137. package/dist/question/deep-interview.d.ts.map +1 -1
  138. package/dist/question/deep-interview.js +22 -6
  139. package/dist/question/deep-interview.js.map +1 -1
  140. package/dist/question/policy.d.ts.map +1 -1
  141. package/dist/question/policy.js +2 -5
  142. package/dist/question/policy.js.map +1 -1
  143. package/dist/question/renderer.d.ts +12 -0
  144. package/dist/question/renderer.d.ts.map +1 -1
  145. package/dist/question/renderer.js +87 -3
  146. package/dist/question/renderer.js.map +1 -1
  147. package/dist/question/state.d.ts +8 -1
  148. package/dist/question/state.d.ts.map +1 -1
  149. package/dist/question/state.js +54 -14
  150. package/dist/question/state.js.map +1 -1
  151. package/dist/question/types.d.ts +1 -1
  152. package/dist/question/types.d.ts.map +1 -1
  153. package/dist/question/ui.d.ts +1 -0
  154. package/dist/question/ui.d.ts.map +1 -1
  155. package/dist/question/ui.js +1 -0
  156. package/dist/question/ui.js.map +1 -1
  157. package/dist/ralplan/__tests__/runtime.test.js +191 -0
  158. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  159. package/dist/ralplan/consensus-gate.d.ts +9 -1
  160. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  161. package/dist/ralplan/consensus-gate.js +84 -2
  162. package/dist/ralplan/consensus-gate.js.map +1 -1
  163. package/dist/ralplan/runtime.d.ts +9 -0
  164. package/dist/ralplan/runtime.d.ts.map +1 -1
  165. package/dist/ralplan/runtime.js +32 -11
  166. package/dist/ralplan/runtime.js.map +1 -1
  167. package/dist/scripts/__tests__/codex-native-hook.test.js +1487 -34
  168. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  169. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  170. package/dist/scripts/codex-native-hook.js +356 -38
  171. package/dist/scripts/codex-native-hook.js.map +1 -1
  172. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  173. package/dist/scripts/codex-native-pre-post.js +79 -1
  174. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  175. package/dist/scripts/hook-payload-guard.d.ts +9 -0
  176. package/dist/scripts/hook-payload-guard.d.ts.map +1 -0
  177. package/dist/scripts/hook-payload-guard.js +111 -0
  178. package/dist/scripts/hook-payload-guard.js.map +1 -0
  179. package/dist/scripts/notify-fallback-watcher.js +8 -1
  180. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  181. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts +2 -0
  182. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts.map +1 -0
  183. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js +39 -0
  184. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js.map +1 -0
  185. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  186. package/dist/scripts/notify-hook/team-worker-stop.js +234 -86
  187. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  188. package/dist/scripts/notify-hook.js +11 -2
  189. package/dist/scripts/notify-hook.js.map +1 -1
  190. package/dist/state/__tests__/operations.test.js +1012 -1
  191. package/dist/state/__tests__/operations.test.js.map +1 -1
  192. package/dist/state/__tests__/skill-active.test.js +59 -1
  193. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  194. package/dist/state/__tests__/workflow-transition.test.js +73 -7
  195. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  196. package/dist/state/operations.d.ts.map +1 -1
  197. package/dist/state/operations.js +102 -0
  198. package/dist/state/operations.js.map +1 -1
  199. package/dist/state/skill-active.d.ts.map +1 -1
  200. package/dist/state/skill-active.js +33 -3
  201. package/dist/state/skill-active.js.map +1 -1
  202. package/dist/state/workflow-transition-reconcile.d.ts +6 -0
  203. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  204. package/dist/state/workflow-transition-reconcile.js +28 -1
  205. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  206. package/dist/state/workflow-transition.d.ts.map +1 -1
  207. package/dist/state/workflow-transition.js +10 -3
  208. package/dist/state/workflow-transition.js.map +1 -1
  209. package/dist/subagents/__tests__/tracker.test.js +139 -0
  210. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  211. package/dist/subagents/tracker.d.ts +3 -0
  212. package/dist/subagents/tracker.d.ts.map +1 -1
  213. package/dist/subagents/tracker.js +41 -4
  214. package/dist/subagents/tracker.js.map +1 -1
  215. package/dist/team/__tests__/coordination-protocol.test.d.ts +2 -0
  216. package/dist/team/__tests__/coordination-protocol.test.d.ts.map +1 -0
  217. package/dist/team/__tests__/coordination-protocol.test.js +173 -0
  218. package/dist/team/__tests__/coordination-protocol.test.js.map +1 -0
  219. package/dist/team/__tests__/runtime.test.js +51 -2
  220. package/dist/team/__tests__/runtime.test.js.map +1 -1
  221. package/dist/team/__tests__/state.test.js +83 -0
  222. package/dist/team/__tests__/state.test.js.map +1 -1
  223. package/dist/team/__tests__/tmux-session.test.js +45 -0
  224. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  225. package/dist/team/__tests__/worker-bootstrap.test.js +84 -0
  226. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  227. package/dist/team/coordination-protocol.d.ts +14 -0
  228. package/dist/team/coordination-protocol.d.ts.map +1 -0
  229. package/dist/team/coordination-protocol.js +244 -0
  230. package/dist/team/coordination-protocol.js.map +1 -0
  231. package/dist/team/runtime.d.ts +1 -0
  232. package/dist/team/runtime.d.ts.map +1 -1
  233. package/dist/team/runtime.js +19 -3
  234. package/dist/team/runtime.js.map +1 -1
  235. package/dist/team/state/tasks.d.ts.map +1 -1
  236. package/dist/team/state/tasks.js +24 -0
  237. package/dist/team/state/tasks.js.map +1 -1
  238. package/dist/team/state/types.d.ts +21 -1
  239. package/dist/team/state/types.d.ts.map +1 -1
  240. package/dist/team/state/types.js.map +1 -1
  241. package/dist/team/state.d.ts +17 -1
  242. package/dist/team/state.d.ts.map +1 -1
  243. package/dist/team/state.js +12 -5
  244. package/dist/team/state.js.map +1 -1
  245. package/dist/team/team-ops.d.ts +1 -1
  246. package/dist/team/team-ops.d.ts.map +1 -1
  247. package/dist/team/team-ops.js.map +1 -1
  248. package/dist/team/tmux-session.d.ts.map +1 -1
  249. package/dist/team/tmux-session.js +19 -1
  250. package/dist/team/tmux-session.js.map +1 -1
  251. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  252. package/dist/team/worker-bootstrap.js +63 -0
  253. package/dist/team/worker-bootstrap.js.map +1 -1
  254. package/dist/utils/__tests__/agents-model-table.test.js +4 -2
  255. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  256. package/dist/utils/agents-model-table.d.ts.map +1 -1
  257. package/dist/utils/agents-model-table.js +3 -0
  258. package/dist/utils/agents-model-table.js.map +1 -1
  259. package/package.json +1 -1
  260. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  261. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +10 -5
  262. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +9 -4
  263. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +12 -0
  264. package/plugins/oh-my-codex/skills/team/SKILL.md +16 -0
  265. package/plugins/oh-my-codex/skills/worker/SKILL.md +14 -0
  266. package/skills/autopilot/SKILL.md +10 -5
  267. package/skills/deep-interview/SKILL.md +9 -4
  268. package/skills/ralplan/SKILL.md +12 -0
  269. package/skills/team/SKILL.md +16 -0
  270. package/skills/worker/SKILL.md +14 -0
  271. package/src/scripts/__tests__/codex-native-hook.test.ts +2202 -523
  272. package/src/scripts/codex-native-hook.ts +444 -36
  273. package/src/scripts/codex-native-pre-post.ts +80 -0
  274. package/src/scripts/hook-payload-guard.ts +113 -0
  275. package/src/scripts/notify-fallback-watcher.ts +8 -1
  276. package/src/scripts/notify-hook/__tests__/payload-guard.test.ts +41 -0
  277. package/src/scripts/notify-hook/team-worker-stop.ts +193 -52
  278. package/src/scripts/notify-hook.ts +14 -2
@@ -1 +1 @@
1
- {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AAyCA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AA8BtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAmClE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AA4RD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAwoBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AAg8BD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AA+mDD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAqRnC;AAOD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AA2ED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAuC3D"}
1
+ {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA2CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AA8BtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAuClE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAmVD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAwoBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AAk+BD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AA2vDD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAiTnC;AA6BD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AAoMD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyC3D"}
@@ -4,8 +4,9 @@ import { appendFile, mkdir, readFile, readdir, stat, writeFile } from "fs/promis
4
4
  import { extname, join, relative, resolve } from "path";
5
5
  import { pathToFileURL } from "url";
6
6
  import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
7
+ import { redactAuthSecrets } from "../auth/redact.js";
7
8
  import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
8
- import { readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
9
+ import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
9
10
  import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
10
11
  import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
11
12
  import { appendTeamEvent, readTeamLeaderAttention, readTeamConfig, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
@@ -36,6 +37,7 @@ import { isPendingDeepInterviewQuestionEnforcement, reconcileDeepInterviewQuesti
36
37
  import { readAutopilotDeepInterviewQuestionWaitState } from "../question/autopilot-wait.js";
37
38
  import { buildDocumentRefreshAdvisoryOutput, evaluateFinalHandoffDocumentRefresh, isFinalHandoffDocumentRefreshCandidate, } from "../document-refresh/enforcer.js";
38
39
  import { buildExecFollowupStopOutput } from "../exec/followup.js";
40
+ import { MAX_NATIVE_STDIN_JSON_BYTES, extractRawCodexHookEventName, } from "./hook-payload-guard.js";
39
41
  const TERMINAL_MODE_PHASES = new Set(["complete", "completed", "failed", "cancelled"]);
40
42
  const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
41
43
  const TEAM_STOP_BLOCKING_TASK_STATUSES = new Set(["pending", "in_progress", "blocked"]);
@@ -45,6 +47,7 @@ const ORDINARY_STOP_NO_PROGRESS_DEFAULT_MAX_REPEATS = 8;
45
47
  const RALPH_ORPHANED_STARTING_STALE_MS = 15 * 60_000;
46
48
  const ORDINARY_STOP_NO_PROGRESS_DEFAULT_IDLE_MS = 10 * 60_000;
47
49
  const ORDINARY_STOP_NO_PROGRESS_MAX_MESSAGE_LENGTH = 240;
50
+ const OMX_OWNER_SESSION_ID_PATTERN = /^omx-[A-Za-z0-9_-]{1,60}$/;
48
51
  const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
49
52
  /^\s*(?:launch|release|ship)-?ready\s*:\s*(?:yes|no)\b[^\n\r]*/im,
50
53
  /^\s*ready to release\s*:\s*(?:yes|no)\b[^\n\r]*/im,
@@ -71,6 +74,12 @@ function safeString(value) {
71
74
  function safeObject(value) {
72
75
  return value && typeof value === "object" ? value : {};
73
76
  }
77
+ function resolveHudReconcileSessionId(currentSessionState, canonicalSessionId, sessionIdForState) {
78
+ const ownerOmxSessionId = safeString(currentSessionState?.owner_omx_session_id).trim();
79
+ if (OMX_OWNER_SESSION_ID_PATTERN.test(ownerOmxSessionId))
80
+ return ownerOmxSessionId;
81
+ return canonicalSessionId || sessionIdForState || undefined;
82
+ }
74
83
  function safeContextSnippet(value, maxLength = 300) {
75
84
  const text = safeString(value).replace(/\s+/g, " ").trim();
76
85
  if (text.length <= maxLength)
@@ -134,18 +143,25 @@ function readNativeSubagentSessionStartMetadata(transcriptPath) {
134
143
  }
135
144
  }
136
145
  async function recordNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
146
+ const parentThreadId = metadata.parentThreadId.trim();
147
+ const childThreadId = childSessionId.trim();
137
148
  const trackingSessionIds = [...new Set([
138
149
  canonicalSessionId.trim(),
139
- metadata.parentThreadId.trim(),
150
+ parentThreadId,
140
151
  ].filter(Boolean))];
141
152
  for (const sessionId of trackingSessionIds) {
153
+ if (parentThreadId && parentThreadId !== childThreadId) {
154
+ await recordSubagentTurnForSession(cwd, {
155
+ sessionId,
156
+ threadId: parentThreadId,
157
+ kind: 'leader',
158
+ }).catch(() => { });
159
+ }
142
160
  await recordSubagentTurnForSession(cwd, {
143
161
  sessionId,
144
- threadId: metadata.parentThreadId,
145
- }).catch(() => { });
146
- await recordSubagentTurnForSession(cwd, {
147
- sessionId,
148
- threadId: childSessionId,
162
+ threadId: childThreadId,
163
+ kind: 'subagent',
164
+ ...(parentThreadId && parentThreadId !== childThreadId ? { leaderThreadId: parentThreadId } : {}),
149
165
  mode: metadata.agentRole,
150
166
  }).catch(() => { });
151
167
  }
@@ -176,17 +192,42 @@ async function nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonica
176
192
  return true;
177
193
  return summary.allThreadIds.includes(parentThreadId);
178
194
  }
179
- async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId) {
180
- const candidateIds = [nativeSessionId, threadId]
195
+ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId, canonicalLeaderNativeSessionId = "") {
196
+ const nativeId = nativeSessionId.trim();
197
+ const promptThreadId = threadId.trim();
198
+ const candidateIds = [nativeId, promptThreadId]
181
199
  .map((value) => value.trim())
182
200
  .filter(Boolean);
183
201
  if (candidateIds.length === 0)
184
202
  return false;
185
203
  const sessionId = canonicalSessionId.trim();
186
- if (sessionId) {
187
- const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
188
- if (summary && candidateIds.some((id) => summary.allSubagentThreadIds.includes(id))) {
189
- return true;
204
+ const currentLeaderNativeSessionId = canonicalLeaderNativeSessionId.trim();
205
+ const summary = sessionId
206
+ ? await readSubagentSessionSummary(cwd, sessionId).catch(() => null)
207
+ : null;
208
+ const currentLeaderIds = new Set([
209
+ currentLeaderNativeSessionId,
210
+ summary?.leaderThreadId?.trim(),
211
+ ].filter(Boolean));
212
+ if (summary
213
+ && candidateIds.some((id) => !currentLeaderIds.has(id) && summary.allSubagentThreadIds.includes(id))) {
214
+ return true;
215
+ }
216
+ // Native UserPromptSubmit can carry a per-turn thread_id that differs from
217
+ // the long-lived native session id. Treat the current canonical native
218
+ // session as the leader before consulting stale/global tracker state.
219
+ if (sessionId
220
+ && currentLeaderNativeSessionId
221
+ && (nativeId === currentLeaderNativeSessionId
222
+ || (!nativeId && promptThreadId === currentLeaderNativeSessionId))) {
223
+ return false;
224
+ }
225
+ if (summary) {
226
+ const leaderThreadId = summary.leaderThreadId?.trim();
227
+ if (leaderThreadId
228
+ && (nativeId === leaderThreadId
229
+ || (!nativeId && promptThreadId === leaderThreadId))) {
230
+ return false;
190
231
  }
191
232
  }
192
233
  // Native Codex resume can report the child native session as the canonical
@@ -199,7 +240,7 @@ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, th
199
240
  const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
200
241
  if (!trackingState)
201
242
  return false;
202
- return Object.values(trackingState.sessions).some((session) => (candidateIds.some((id) => session.threads[id]?.kind === "subagent")));
243
+ return Object.values(trackingState.sessions).some((session) => (candidateIds.some((id) => isTrustedSubagentThread(session, id))));
203
244
  }
204
245
  function shouldSuppressSubagentLifecycleHookDispatch() {
205
246
  const config = getNotificationConfig();
@@ -1374,16 +1415,21 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
1374
1415
  function buildSkillStateCliInstruction(mode, statePath) {
1375
1416
  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.`;
1376
1417
  }
1377
- function buildAutopilotPromptActivationNote(skillState) {
1418
+ function buildAutopilotPromptActivationNote(skillState, options = {}) {
1378
1419
  if (skillState?.initialized_mode !== "autopilot")
1379
1420
  return null;
1380
1421
  return [
1381
1422
  "Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal (+ $team if needed) -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).",
1382
1423
  "Start/resume at current_phase=deep-interview unless the task is clear and bounded; if deep-interview is intentionally skipped, persist and state an explicit deep_interview_gate.skip_reason before moving to ralplan.",
1424
+ "Deep-interview is a structured question chain, not a one-question gate: after an omx question answer, re-score ambiguity against the active threshold, treat max_rounds as a cap, and crystallize once ambiguity is at or below threshold and readiness gates pass.",
1425
+ options.markedQuestionAnswer
1426
+ ? "This turn is a marked omx question answer. Treat ordinary selected option/freeform answer text as interview input, then re-score. Do not close merely because the first question was answered; if ambiguity is at or below threshold and readiness gates pass, write interview_complete evidence and hand off. Ask another deep-interview follow-up only when a readiness gate remains unresolved and the answer would materially change execution."
1427
+ : null,
1428
+ "Do not advance from deep-interview to ralplan merely because the first question was answered; persist explicit interview_complete evidence before setting current_phase=ralplan, and do advance when threshold plus readiness gates are satisfied.",
1383
1429
  "The ralplan phase is not complete until Planner output has been reviewed sequentially by Architect and then Critic; do not hand off to Ultragoal or implementation until the ralplan state/artifact records both ralplan_architect_review and ralplan_critic_review with approval or an explicit blocker.",
1384
1430
  "Do not silently fall back to ordinary $plan/ralplan-only handling; keep autopilot-state.json, skill-active-state.json, HUD/statusline, and Codex goal-mode handoff guidance visible while the workflow is active.",
1385
1431
  "When Codex goal tools are available, call get_goal/create_goal only from the active thread handoff and treat the active goal as the completion contract until code-review and ultraqa are clean.",
1386
- ].join(" ");
1432
+ ].filter(Boolean).join(" ");
1387
1433
  }
1388
1434
  function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
1389
1435
  if (!prompt)
@@ -1399,6 +1445,8 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1399
1445
  ? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
1400
1446
  : null;
1401
1447
  const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
1448
+ const markedQuestionAnswer = /^\s*\[omx question answered\]/i.test(prompt);
1449
+ const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer });
1402
1450
  return [
1403
1451
  `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
1404
1452
  promptPriorityMessage,
@@ -1407,12 +1455,34 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1407
1455
  : null,
1408
1456
  deepInterviewPromptActivationNote,
1409
1457
  deepInterviewConfigPromptActivationNote,
1458
+ autopilotPromptActivationNote,
1410
1459
  "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
1411
1460
  ].filter(Boolean).join(" ");
1412
1461
  }
1413
1462
  const detectedKeywordMessage = matches.length > 1
1414
1463
  ? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
1415
1464
  : `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
1465
+ const continuedSkill = safeString(skillState?.skill).trim();
1466
+ if (continuedSkill
1467
+ && continuedSkill !== match.skill
1468
+ && /^\s*\[omx question answered\]/i.test(prompt)) {
1469
+ const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
1470
+ ? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
1471
+ : null;
1472
+ const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
1473
+ const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true });
1474
+ return [
1475
+ `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}"; workflow-like tokens inside the marked omx question answer are treated as answer text, not a new workflow activation.`,
1476
+ promptPriorityMessage,
1477
+ skillState?.initialized_mode && skillState.initialized_state_path
1478
+ ? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
1479
+ : null,
1480
+ deepInterviewPromptActivationNote,
1481
+ deepInterviewConfigPromptActivationNote,
1482
+ autopilotPromptActivationNote,
1483
+ "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
1484
+ ].filter(Boolean).join(" ");
1485
+ }
1416
1486
  const activeSkills = Array.isArray(skillState?.active_skills)
1417
1487
  ? skillState.active_skills.map((entry) => entry.skill)
1418
1488
  : [];
@@ -1968,13 +2038,30 @@ const DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES = [
1968
2038
  ".omx/specs",
1969
2039
  ".omx/state",
1970
2040
  ];
1971
- const DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES = new Set([
2041
+ const RALPLAN_ALLOWED_WRITE_PREFIXES = [
2042
+ ".omx/context",
2043
+ ".omx/plans",
2044
+ ".omx/specs",
2045
+ ".omx/state",
2046
+ ];
2047
+ const PLANNING_MODE_IMPLEMENTATION_TOOL_NAMES = new Set([
1972
2048
  "Write",
1973
2049
  "Edit",
1974
2050
  "MultiEdit",
2051
+ "NotebookEdit",
1975
2052
  "apply_patch",
1976
2053
  "ApplyPatch",
1977
2054
  ]);
2055
+ const DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES = PLANNING_MODE_IMPLEMENTATION_TOOL_NAMES;
2056
+ const RALPLAN_EXECUTION_HANDOFF_SKILLS = new Set([
2057
+ "autopilot",
2058
+ "autoresearch",
2059
+ "ralph",
2060
+ "team",
2061
+ "ultragoal",
2062
+ "ultrawork",
2063
+ "ultraqa",
2064
+ ]);
1978
2065
  function isActiveDeepInterviewPhase(state) {
1979
2066
  if (!state || state.active !== true)
1980
2067
  return false;
@@ -1986,7 +2073,31 @@ function isActiveDeepInterviewPhase(state) {
1986
2073
  return false;
1987
2074
  return true;
1988
2075
  }
1989
- function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
2076
+ function isActiveRalplanPhase(state) {
2077
+ if (!state || state.active !== true)
2078
+ return false;
2079
+ const mode = safeString(state.mode).trim();
2080
+ if (mode && mode !== "ralplan")
2081
+ return false;
2082
+ const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
2083
+ if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing"))
2084
+ return false;
2085
+ return true;
2086
+ }
2087
+ function isActiveAutopilotRalplanPhase(state) {
2088
+ if (!state || state.active !== true)
2089
+ return false;
2090
+ const mode = safeString(state.mode).trim();
2091
+ if (mode && mode !== "autopilot")
2092
+ return false;
2093
+ const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
2094
+ return phase === "ralplan";
2095
+ }
2096
+ function hasExplicitExecutionHandoffSkill(state, sessionId, threadId) {
2097
+ return listActiveSkills(state ?? {}).some((entry) => (RALPLAN_EXECUTION_HANDOFF_SKILLS.has(entry.skill)
2098
+ && matchesSkillStopContext(entry, state ?? {}, sessionId, threadId)));
2099
+ }
2100
+ function isAllowedPlanningArtifactPath(cwd, rawPath, allowedPrefixes) {
1990
2101
  const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
1991
2102
  if (!trimmed || trimmed.includes("\0"))
1992
2103
  return false;
@@ -2000,7 +2111,13 @@ function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
2000
2111
  }
2001
2112
  if (!relativePath || relativePath.startsWith("..") || relativePath.startsWith("/"))
2002
2113
  return false;
2003
- return DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES.some((prefix) => (relativePath === prefix || relativePath.startsWith(`${prefix}/`)));
2114
+ return allowedPrefixes.some((prefix) => (relativePath === prefix || relativePath.startsWith(`${prefix}/`)));
2115
+ }
2116
+ function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
2117
+ return isAllowedPlanningArtifactPath(cwd, rawPath, DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES);
2118
+ }
2119
+ function isAllowedRalplanArtifactPath(cwd, rawPath) {
2120
+ return isAllowedPlanningArtifactPath(cwd, rawPath, RALPLAN_ALLOWED_WRITE_PREFIXES);
2004
2121
  }
2005
2122
  function readPreToolUseCommand(payload) {
2006
2123
  const toolInput = safeObject(payload.tool_input);
@@ -2064,6 +2181,76 @@ async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionI
2064
2181
  && matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
2065
2182
  return hasActiveDeepInterviewSkill ? modeState : null;
2066
2183
  }
2184
+ async function readActiveRalplanStateForPreToolUse(cwd, stateDir, sessionId, threadId) {
2185
+ const modeState = sessionId
2186
+ ? await readStopSessionPinnedState("ralplan-state.json", cwd, sessionId, stateDir)
2187
+ : await readJsonIfExists(join(stateDir, "ralplan-state.json"));
2188
+ const canonicalState = sessionId
2189
+ ? await readVisibleSkillActiveStateForStateDir(stateDir, sessionId)
2190
+ : await readSkillActiveState(join(stateDir, SKILL_ACTIVE_STATE_FILE));
2191
+ if (isActiveRalplanPhase(modeState) && modeState && modeStateMatchesSkillStopContext(modeState, cwd, sessionId)) {
2192
+ if (hasExplicitExecutionHandoffSkill(canonicalState, sessionId, threadId))
2193
+ return null;
2194
+ if (!canonicalState)
2195
+ return modeState;
2196
+ const hasActiveRalplanSkill = listActiveSkills(canonicalState).some((entry) => (entry.skill === "ralplan"
2197
+ && matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
2198
+ if (hasActiveRalplanSkill)
2199
+ return modeState;
2200
+ }
2201
+ const autopilotState = sessionId
2202
+ ? await readStopSessionPinnedState("autopilot-state.json", cwd, sessionId, stateDir)
2203
+ : await readJsonIfExists(join(stateDir, "autopilot-state.json"));
2204
+ if (!isActiveAutopilotRalplanPhase(autopilotState) || !autopilotState)
2205
+ return null;
2206
+ if (!modeStateMatchesSkillStopContext(autopilotState, cwd, sessionId))
2207
+ return null;
2208
+ const terminalAutopilotRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, "autopilot");
2209
+ if (terminalAutopilotRunState)
2210
+ return null;
2211
+ if (!canonicalState)
2212
+ return autopilotState;
2213
+ const hasActiveAutopilotSkill = listActiveSkills(canonicalState).some((entry) => (entry.skill === "autopilot"
2214
+ && matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
2215
+ return hasActiveAutopilotSkill ? autopilotState : null;
2216
+ }
2217
+ function isAllowedRalplanBashWrite(cwd, command) {
2218
+ if (!commandHasDeepInterviewWriteIntent(command))
2219
+ return true;
2220
+ if (/\bomx\s+(?:state\s+(?:write|read|clear)|question)\b/.test(command))
2221
+ return true;
2222
+ const targets = extractDeepInterviewCommandWriteTargets(command);
2223
+ return targets.length > 0 && targets.every((target) => isAllowedRalplanArtifactPath(cwd, target));
2224
+ }
2225
+ async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir) {
2226
+ const sessionId = readPayloadSessionId(payload);
2227
+ const threadId = readPayloadThreadId(payload);
2228
+ const activeState = await readActiveRalplanStateForPreToolUse(cwd, stateDir, sessionId, threadId);
2229
+ if (!activeState)
2230
+ return null;
2231
+ const toolName = safeString(payload.tool_name).trim();
2232
+ const command = readPreToolUseCommand(payload);
2233
+ const pathCandidates = readPreToolUsePathCandidates(payload);
2234
+ let blocked = false;
2235
+ if (toolName === "Bash") {
2236
+ blocked = !isAllowedRalplanBashWrite(cwd, command);
2237
+ }
2238
+ else if (PLANNING_MODE_IMPLEMENTATION_TOOL_NAMES.has(toolName)) {
2239
+ blocked = pathCandidates.length === 0
2240
+ || !pathCandidates.every((candidate) => isAllowedRalplanArtifactPath(cwd, candidate));
2241
+ }
2242
+ if (!blocked)
2243
+ return null;
2244
+ const phase = formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning");
2245
+ return {
2246
+ decision: "block",
2247
+ reason: `Ralplan is active (phase: ${phase}); implementation/write tools are blocked until an explicit execution handoff workflow is activated.`,
2248
+ hookSpecificOutput: {
2249
+ hookEventName: "PreToolUse",
2250
+ additionalContext: "Ralplan is consensus-planning mode. Write only planning artifacts under `.omx/context/`, `.omx/plans/`, `.omx/specs/`, or required `.omx/state/` files. Do not edit implementation files or run implementation-focused writes from ralplan. To execute, first process an explicit handoff such as `$ultragoal`, `$team`, or `$ralph`, which must emit terminal ralplan state before implementation begins.",
2251
+ },
2252
+ };
2253
+ }
2067
2254
  async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir) {
2068
2255
  const sessionId = readPayloadSessionId(payload);
2069
2256
  const threadId = readPayloadThreadId(payload);
@@ -2304,12 +2491,12 @@ function buildRalplanContinuationStatus(blocker, activeSubagentCount) {
2304
2491
  };
2305
2492
  }
2306
2493
  const completeHint = blocker.planningComplete
2307
- ? " The planning artifacts are present; if consensus is approved, emit the final complete/approved handoff instead of stopping here."
2494
+ ? " The planning artifacts are present; if consensus is approved, emit terminal ralplan complete/approved handoff state and stop planning. Implementation must wait for an explicit $ultragoal, $team, or $ralph handoff."
2308
2495
  : "";
2309
2496
  return {
2310
- reason: `Status: continue_from_artifact — ralplan is still active (phase: ${phase}) and has not emitted a terminal complete/paused/waiting status. Continue from the current ralplan artifact, resolve any review ambiguity conservatively or ask the user if needed, and proceed to the next planning/review step before stopping.${artifact}${completeHint}`,
2497
+ reason: `Status: continue_from_artifact — ralplan is still active (phase: ${phase}) and has not emitted a terminal complete/paused/waiting status. Continue from the current ralplan artifact, resolve any review ambiguity conservatively or ask the user if needed, and proceed to the next planning/review step before stopping; do not begin implementation from ralplan.${artifact}${completeHint}`,
2311
2498
  stopReasonSuffix: "continue_artifact",
2312
- 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.`,
2499
+ 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; do not begin implementation from ralplan.`,
2313
2500
  };
2314
2501
  }
2315
2502
  async function readStopAutoNudgePhase(cwd, stateDir, sessionId, threadId) {
@@ -2878,6 +3065,14 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
2878
3065
  export async function dispatchCodexNativeHook(payload, options = {}) {
2879
3066
  const hookEventName = readHookEventName(payload);
2880
3067
  const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
3068
+ if (hookEventName === "Stop" && !hasNativeStopRuntimeSurface(cwd)) {
3069
+ return {
3070
+ hookEventName,
3071
+ omxEventName: mapCodexHookEventToOmxEvent(hookEventName),
3072
+ skillState: null,
3073
+ outputJson: null,
3074
+ };
3075
+ }
2881
3076
  // Native hooks must use the same authoritative runtime state root as HUD/MCP
2882
3077
  // when boxed/team roots are active; do not bypass it with cwd/.omx/state.
2883
3078
  const stateDir = getBaseStateDir(cwd);
@@ -2938,14 +3133,16 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
2938
3133
  const sessionIdForState = canonicalSessionId || nativeSessionId;
2939
3134
  let outputJson = null;
2940
3135
  const isSubagentPromptSubmit = hookEventName === "UserPromptSubmit"
2941
- ? await isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId)
3136
+ ? await isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId, safeString(currentSessionState?.native_session_id).trim())
2942
3137
  : false;
2943
3138
  const isSubagentStop = hookEventName === "Stop"
2944
3139
  ? (await Promise.all([...new Set([
2945
3140
  canonicalSessionId,
2946
3141
  safeString(currentSessionState?.session_id).trim(),
2947
3142
  ].filter(Boolean))]
2948
- .map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)))).some(Boolean)
3143
+ .map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId, candidateSessionId === safeString(currentSessionState?.session_id).trim()
3144
+ ? safeString(currentSessionState?.native_session_id).trim()
3145
+ : "")))).some(Boolean)
2949
3146
  : false;
2950
3147
  const suppressNoisySubagentLifecycleDispatch = (isSubagentSessionStart || isSubagentStop)
2951
3148
  && shouldSuppressSubagentLifecycleHookDispatch();
@@ -3044,7 +3241,8 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
3044
3241
  && await isConfirmedTeamWorkerPromptSubmitPane(cwd).catch(() => false);
3045
3242
  if (!skipHudReconcileForTeamWorkerPane) {
3046
3243
  const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
3047
- await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
3244
+ const hudSessionId = resolveHudReconcileSessionId(currentSessionState, canonicalSessionId, sessionIdForState);
3245
+ await reconcileHudForPromptSubmitFn(cwd, { sessionId: hudSessionId }).catch(() => { });
3048
3246
  }
3049
3247
  }
3050
3248
  if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
@@ -3101,6 +3299,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
3101
3299
  }
3102
3300
  else if (hookEventName === "PreToolUse") {
3103
3301
  outputJson = await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir)
3302
+ ?? await buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir)
3104
3303
  ?? buildNativePreToolUseOutput(payload);
3105
3304
  }
3106
3305
  else if (hookEventName === "PostToolUse") {
@@ -3122,6 +3321,28 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
3122
3321
  outputJson,
3123
3322
  };
3124
3323
  }
3324
+ function hasNativeStopRuntimeSurface(cwd) {
3325
+ if (existsSync(join(cwd, ".omx")))
3326
+ return true;
3327
+ if (findGitLayout(cwd))
3328
+ return true;
3329
+ const omxRoot = safeString(process.env.OMX_ROOT).trim();
3330
+ if (omxRoot && existsSync(join(omxRoot, ".omx")))
3331
+ return true;
3332
+ const stateRoot = safeString(process.env.OMX_STATE_ROOT).trim();
3333
+ if (stateRoot && existsSync(stateRoot))
3334
+ return true;
3335
+ return [
3336
+ process.env.OMX_SESSION_ID,
3337
+ process.env.OMX_TEAM_INTERNAL_WORKER,
3338
+ process.env.OMX_TEAM_WORKER,
3339
+ process.env.OMX_TEAM_STATE_ROOT,
3340
+ process.env.OMX_TEAM_LEADER_CWD,
3341
+ process.env.OMX_NOTIFY_HOOK_TRUSTED_MANAGED_CWD,
3342
+ process.env.OMX_TMUX_HUD_OWNER,
3343
+ process.env.OMX_TMUX_HUD_LEADER_PANE,
3344
+ ].some((value) => safeString(value).trim() !== "");
3345
+ }
3125
3346
  export function isCodexNativeHookMainModule(moduleUrl, argv1) {
3126
3347
  if (!argv1)
3127
3348
  return false;
@@ -3129,30 +3350,129 @@ export function isCodexNativeHookMainModule(moduleUrl, argv1) {
3129
3350
  }
3130
3351
  async function readStdinJson() {
3131
3352
  const chunks = [];
3353
+ let totalBytes = 0;
3354
+ let oversized = false;
3132
3355
  for await (const chunk of process.stdin) {
3133
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
3356
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
3357
+ totalBytes += buffer.byteLength;
3358
+ if (totalBytes > MAX_NATIVE_STDIN_JSON_BYTES) {
3359
+ const remaining = Math.max(0, MAX_NATIVE_STDIN_JSON_BYTES - (totalBytes - buffer.byteLength));
3360
+ if (remaining > 0)
3361
+ chunks.push(Buffer.from(buffer.subarray(0, remaining)));
3362
+ oversized = true;
3363
+ process.stdin.destroy();
3364
+ break;
3365
+ }
3366
+ chunks.push(buffer);
3134
3367
  }
3135
3368
  const raw = Buffer.concat(chunks).toString("utf-8").trim();
3369
+ const rawHookEventName = extractRawCodexHookEventName(raw);
3370
+ if (oversized) {
3371
+ return {
3372
+ payload: {},
3373
+ parseError: null,
3374
+ rawInput: raw,
3375
+ oversized: true,
3376
+ rawHookEventName,
3377
+ };
3378
+ }
3136
3379
  if (!raw) {
3137
- return { payload: {}, parseError: null };
3380
+ return { payload: {}, parseError: null, rawInput: raw, oversized: false, rawHookEventName };
3138
3381
  }
3139
3382
  try {
3140
3383
  return {
3141
3384
  payload: safeObject(JSON.parse(raw)),
3142
3385
  parseError: null,
3386
+ rawInput: raw,
3387
+ oversized: false,
3388
+ rawHookEventName,
3143
3389
  };
3144
3390
  }
3145
3391
  catch (error) {
3146
3392
  return {
3147
3393
  payload: {},
3148
3394
  parseError: error instanceof Error ? error : new Error(String(error)),
3395
+ rawInput: raw,
3396
+ oversized: false,
3397
+ rawHookEventName,
3149
3398
  };
3150
3399
  }
3151
3400
  }
3401
+ function inferHookEventNameFromMalformedInput(raw) {
3402
+ const match = raw.match(/(?:\"|['"])?hook[_-]?event[_-]?name(?:\"|['"])?\s*:\s*(?:\"|['"])?(SessionStart|PreToolUse|PostToolUse|UserPromptSubmit|PreCompact|PostCompact|Stop)\b/i);
3403
+ const value = match?.[1];
3404
+ if (!value)
3405
+ return null;
3406
+ return readHookEventName({ hook_event_name: value });
3407
+ }
3408
+ function buildMalformedStdinHookOutput(parseError, rawInput) {
3409
+ const reason = "OMX native hook received malformed JSON input. Preserve runtime state, inspect the emitting hook payload yourself, and retry with valid JSON.";
3410
+ const systemMessage = `${reason} stdin JSON parsing failed inside codex-native-hook: ${parseError.message}.`;
3411
+ if (inferHookEventNameFromMalformedInput(rawInput) === "Stop") {
3412
+ return {
3413
+ decision: "block",
3414
+ reason,
3415
+ stopReason: "native_hook_stdin_parse_error",
3416
+ systemMessage,
3417
+ };
3418
+ }
3419
+ return {
3420
+ continue: false,
3421
+ stopReason: "native_hook_stdin_parse_error",
3422
+ systemMessage,
3423
+ };
3424
+ }
3425
+ async function buildOversizedStopActiveWorkflowOutput(cwd) {
3426
+ const currentSession = await readUsableSessionState(cwd);
3427
+ const currentSessionId = safeString(currentSession?.session_id).trim()
3428
+ || safeString(process.env.OMX_SESSION_ID || process.env.CODEX_SESSION_ID).trim();
3429
+ if (!currentSessionId)
3430
+ return null;
3431
+ if (await readCanonicalTerminalRunStateForStop(cwd, currentSessionId, "autopilot"))
3432
+ return null;
3433
+ const autopilotState = await readModeStateForActiveDecision("autopilot", currentSessionId, cwd);
3434
+ if (!autopilotState || !shouldContinueRun(autopilotState))
3435
+ return null;
3436
+ const phase = formatPhase(autopilotState.current_phase);
3437
+ const reason = `OMX native Stop received oversized stdin before parsing while the current session has active OMX autopilot state (phase: ${phase}); continue once with a compact response or reduce hook payload size so normal Stop gates can run.`;
3438
+ return {
3439
+ decision: "block",
3440
+ reason,
3441
+ stopReason: "native_stop_stdin_oversized_active_workflow",
3442
+ systemMessage: "OMX native Stop rejected oversized stdin before parsing; active current-session workflow state is present, so Stop is blocked instead of silently allowing termination.",
3443
+ };
3444
+ }
3445
+ async function buildOversizedStdinHookOutput(rawHookEventName, cwd) {
3446
+ if (rawHookEventName === "Stop") {
3447
+ return await buildOversizedStopActiveWorkflowOutput(cwd) ?? {};
3448
+ }
3449
+ const systemMessage = `OMX native hook rejected oversized stdin JSON before parsing; maxBytes=${MAX_NATIVE_STDIN_JSON_BYTES}.`;
3450
+ return {
3451
+ continue: false,
3452
+ stopReason: "native_hook_stdin_oversized",
3453
+ systemMessage,
3454
+ };
3455
+ }
3152
3456
  function writeNativeHookJsonStdout(output) {
3153
3457
  process.stdout.write(`${JSON.stringify(output)}\n`);
3154
3458
  }
3155
- async function logNativeHookCliError(cwd, type, error, payload = {}) {
3459
+ function redactMalformedHookPreview(rawInput) {
3460
+ const withoutControls = rawInput.replace(/[\u0000-\u001f\u007f-\u009f]/g, "");
3461
+ const withoutAuthSecrets = redactAuthSecrets(withoutControls);
3462
+ return withoutAuthSecrets
3463
+ .replace(/(["']?(?:prompt|user_prompt|input|text)["']?\s*:\s*)(["'])(?:\\.|(?!\2)[^\\])*\2/gi, "$1$2[REDACTED]$2")
3464
+ .replace(/(["']?(?:prompt|user_prompt|input|text)["']?\s*:\s*)(["'])(?:\\.|[^\\])*$/gi, "$1$2[REDACTED]$2")
3465
+ .replace(/(["']?(?:prompt|user_prompt|input|text)["']?\s*:\s*)(?!["'])[^,}]*/gi, "$1[REDACTED]");
3466
+ }
3467
+ function buildRawInputLogFields(rawInput) {
3468
+ if (!rawInput)
3469
+ return {};
3470
+ return {
3471
+ raw_input_length: Buffer.byteLength(rawInput, "utf-8"),
3472
+ raw_input_prefix: redactMalformedHookPreview(rawInput).slice(0, 240),
3473
+ };
3474
+ }
3475
+ async function logNativeHookCliError(cwd, type, error, payload = {}, details = {}) {
3156
3476
  const logsDir = join(cwd || process.cwd(), ".omx", "logs");
3157
3477
  await mkdir(logsDir, { recursive: true }).catch(() => { });
3158
3478
  const logPath = join(logsDir, `native-hook-${new Date().toISOString().split("T")[0]}.jsonl`);
@@ -3164,6 +3484,7 @@ async function logNativeHookCliError(cwd, type, error, payload = {}) {
3164
3484
  thread_id: readPayloadThreadId(payload) || undefined,
3165
3485
  turn_id: readPayloadTurnId(payload) || undefined,
3166
3486
  error: error instanceof Error ? error.message : String(error),
3487
+ ...details,
3167
3488
  }) + "\n").catch(() => { });
3168
3489
  }
3169
3490
  function isStopDispatchFailureTestTrigger(payload) {
@@ -3186,17 +3507,14 @@ function buildStopDispatchFailureOutput(error) {
3186
3507
  };
3187
3508
  }
3188
3509
  export async function runCodexNativeHookCli() {
3189
- const { payload, parseError } = await readStdinJson();
3510
+ const { payload, parseError, rawInput, oversized, rawHookEventName } = await readStdinJson();
3511
+ if (oversized) {
3512
+ writeNativeHookJsonStdout(await buildOversizedStdinHookOutput(rawHookEventName, process.cwd()));
3513
+ return;
3514
+ }
3190
3515
  if (parseError) {
3191
- await logNativeHookCliError(process.cwd(), "native_hook_stdin_parse_error", parseError);
3192
- writeNativeHookJsonStdout({
3193
- decision: "block",
3194
- reason: "OMX native hook received malformed JSON input. Preserve runtime state, inspect the emitting hook payload yourself, and retry with valid JSON.",
3195
- hookSpecificOutput: {
3196
- hookEventName: "Unknown",
3197
- additionalContext: `stdin JSON parsing failed inside codex-native-hook: ${parseError.message}. Emit valid JSON from the native hook caller before retrying.`,
3198
- },
3199
- });
3516
+ await logNativeHookCliError(process.cwd(), "native_hook_stdin_parse_error", parseError, {}, buildRawInputLogFields(rawInput));
3517
+ writeNativeHookJsonStdout(buildMalformedStdinHookOutput(parseError, rawInput));
3200
3518
  return;
3201
3519
  }
3202
3520
  try {