oh-my-codex 0.21.0 → 0.21.2

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 (346) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +4 -2
  3. package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.d.ts +2 -0
  4. package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.d.ts.map +1 -0
  5. package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.js +592 -0
  6. package/dist/cli/__tests__/detached-launch-diagnostics-3578.test.js.map +1 -0
  7. package/dist/cli/__tests__/detached-leader-teardown.test.js +270 -33
  8. package/dist/cli/__tests__/detached-leader-teardown.test.js.map +1 -1
  9. package/dist/cli/__tests__/doctor-warning-copy.test.js +133 -5
  10. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  11. package/dist/cli/__tests__/index.test.js +543 -2
  12. package/dist/cli/__tests__/index.test.js.map +1 -1
  13. package/dist/cli/__tests__/issue-windows-cancel-identity.test.d.ts +2 -0
  14. package/dist/cli/__tests__/issue-windows-cancel-identity.test.d.ts.map +1 -0
  15. package/dist/cli/__tests__/issue-windows-cancel-identity.test.js +17 -0
  16. package/dist/cli/__tests__/issue-windows-cancel-identity.test.js.map +1 -0
  17. package/dist/cli/__tests__/launch-fallback.test.js +15 -3
  18. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  19. package/dist/cli/__tests__/package-bin-contract.test.js +20 -0
  20. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  21. package/dist/cli/__tests__/plugin-cache-stale-lock.test.d.ts +2 -0
  22. package/dist/cli/__tests__/plugin-cache-stale-lock.test.d.ts.map +1 -0
  23. package/dist/cli/__tests__/plugin-cache-stale-lock.test.js +76 -0
  24. package/dist/cli/__tests__/plugin-cache-stale-lock.test.js.map +1 -0
  25. package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.d.ts +2 -0
  26. package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.d.ts.map +1 -0
  27. package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.js +1662 -0
  28. package/dist/cli/__tests__/plugin-cache-symlink-provenance-3552.test.js.map +1 -0
  29. package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.d.ts +2 -0
  30. package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.d.ts.map +1 -0
  31. package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.js +522 -0
  32. package/dist/cli/__tests__/plugin-launcher-provenance-3558.test.js.map +1 -0
  33. package/dist/cli/__tests__/ralplan-advisory.test.d.ts +2 -0
  34. package/dist/cli/__tests__/ralplan-advisory.test.d.ts.map +1 -0
  35. package/dist/cli/__tests__/ralplan-advisory.test.js +301 -0
  36. package/dist/cli/__tests__/ralplan-advisory.test.js.map +1 -0
  37. package/dist/cli/__tests__/ralplan.test.js +39 -0
  38. package/dist/cli/__tests__/ralplan.test.js.map +1 -1
  39. package/dist/cli/__tests__/resume.test.js +81 -6
  40. package/dist/cli/__tests__/resume.test.js.map +1 -1
  41. package/dist/cli/__tests__/session-scoped-runtime.test.js +423 -4
  42. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  43. package/dist/cli/__tests__/setup-install-mode.test.js +60 -3
  44. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  45. package/dist/cli/__tests__/setup-refresh.test.js +9 -0
  46. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  47. package/dist/cli/__tests__/sparkshell-cli.test.js +4 -0
  48. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  49. package/dist/cli/__tests__/ultragoal.test.js +71 -0
  50. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  51. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +30 -4
  52. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  53. package/dist/cli/doctor.d.ts.map +1 -1
  54. package/dist/cli/doctor.js +57 -8
  55. package/dist/cli/doctor.js.map +1 -1
  56. package/dist/cli/index.d.ts +113 -7
  57. package/dist/cli/index.d.ts.map +1 -1
  58. package/dist/cli/index.js +1850 -185
  59. package/dist/cli/index.js.map +1 -1
  60. package/dist/cli/native-assets.d.ts +2 -1
  61. package/dist/cli/native-assets.d.ts.map +1 -1
  62. package/dist/cli/native-assets.js +7 -7
  63. package/dist/cli/native-assets.js.map +1 -1
  64. package/dist/cli/plugin-marketplace.d.ts +89 -4
  65. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  66. package/dist/cli/plugin-marketplace.js +2135 -118
  67. package/dist/cli/plugin-marketplace.js.map +1 -1
  68. package/dist/cli/ralplan.d.ts +2 -1
  69. package/dist/cli/ralplan.d.ts.map +1 -1
  70. package/dist/cli/ralplan.js +149 -9
  71. package/dist/cli/ralplan.js.map +1 -1
  72. package/dist/cli/setup.d.ts.map +1 -1
  73. package/dist/cli/setup.js +7 -1
  74. package/dist/cli/setup.js.map +1 -1
  75. package/dist/cli/sparkshell.d.ts.map +1 -1
  76. package/dist/cli/sparkshell.js +9 -10
  77. package/dist/cli/sparkshell.js.map +1 -1
  78. package/dist/cli/update-worker.js +9 -0
  79. package/dist/cli/update-worker.js.map +1 -1
  80. package/dist/cli/update.d.ts +1 -0
  81. package/dist/cli/update.d.ts.map +1 -1
  82. package/dist/cli/update.js +9 -0
  83. package/dist/cli/update.js.map +1 -1
  84. package/dist/config/__tests__/generator-idempotent.test.js +118 -0
  85. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  86. package/dist/config/generator.d.ts.map +1 -1
  87. package/dist/config/generator.js +74 -4
  88. package/dist/config/generator.js.map +1 -1
  89. package/dist/hooks/__tests__/keyword-detector.test.js +74 -0
  90. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  91. package/dist/hooks/__tests__/ralplan-advisory-keyword.test.d.ts +2 -0
  92. package/dist/hooks/__tests__/ralplan-advisory-keyword.test.d.ts.map +1 -0
  93. package/dist/hooks/__tests__/ralplan-advisory-keyword.test.js +250 -0
  94. package/dist/hooks/__tests__/ralplan-advisory-keyword.test.js.map +1 -0
  95. package/dist/hooks/__tests__/session.test.js +10 -1
  96. package/dist/hooks/__tests__/session.test.js.map +1 -1
  97. package/dist/hooks/keyword-detector.d.ts +8 -1
  98. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  99. package/dist/hooks/keyword-detector.js +130 -9
  100. package/dist/hooks/keyword-detector.js.map +1 -1
  101. package/dist/hooks/session.d.ts +5 -0
  102. package/dist/hooks/session.d.ts.map +1 -1
  103. package/dist/hooks/session.js +17 -3
  104. package/dist/hooks/session.js.map +1 -1
  105. package/dist/hud/__tests__/index.test.js +16 -1
  106. package/dist/hud/__tests__/index.test.js.map +1 -1
  107. package/dist/hud/__tests__/reconcile.test.js +134 -7
  108. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  109. package/dist/hud/__tests__/render.test.js +57 -0
  110. package/dist/hud/__tests__/render.test.js.map +1 -1
  111. package/dist/hud/__tests__/session-attached.test.d.ts +2 -0
  112. package/dist/hud/__tests__/session-attached.test.d.ts.map +1 -0
  113. package/dist/hud/__tests__/session-attached.test.js +82 -0
  114. package/dist/hud/__tests__/session-attached.test.js.map +1 -0
  115. package/dist/hud/__tests__/state.test.js +94 -2
  116. package/dist/hud/__tests__/state.test.js.map +1 -1
  117. package/dist/hud/__tests__/tmux-split-realtmux.test.js +169 -2
  118. package/dist/hud/__tests__/tmux-split-realtmux.test.js.map +1 -1
  119. package/dist/hud/__tests__/tmux.test.js +104 -22
  120. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  121. package/dist/hud/__tests__/types.test.js +9 -0
  122. package/dist/hud/__tests__/types.test.js.map +1 -1
  123. package/dist/hud/__tests__/watch-detached.test.d.ts +2 -0
  124. package/dist/hud/__tests__/watch-detached.test.d.ts.map +1 -0
  125. package/dist/hud/__tests__/watch-detached.test.js +383 -0
  126. package/dist/hud/__tests__/watch-detached.test.js.map +1 -0
  127. package/dist/hud/__tests__/watch-realtmux.test.d.ts +2 -0
  128. package/dist/hud/__tests__/watch-realtmux.test.d.ts.map +1 -0
  129. package/dist/hud/__tests__/watch-realtmux.test.js +322 -0
  130. package/dist/hud/__tests__/watch-realtmux.test.js.map +1 -0
  131. package/dist/hud/index.d.ts +3 -0
  132. package/dist/hud/index.d.ts.map +1 -1
  133. package/dist/hud/index.js +98 -20
  134. package/dist/hud/index.js.map +1 -1
  135. package/dist/hud/reconcile.d.ts.map +1 -1
  136. package/dist/hud/reconcile.js +68 -24
  137. package/dist/hud/reconcile.js.map +1 -1
  138. package/dist/hud/render.d.ts.map +1 -1
  139. package/dist/hud/render.js +20 -0
  140. package/dist/hud/render.js.map +1 -1
  141. package/dist/hud/session-attached.d.ts +15 -0
  142. package/dist/hud/session-attached.d.ts.map +1 -0
  143. package/dist/hud/session-attached.js +47 -0
  144. package/dist/hud/session-attached.js.map +1 -0
  145. package/dist/hud/state.d.ts +9 -1
  146. package/dist/hud/state.d.ts.map +1 -1
  147. package/dist/hud/state.js +140 -3
  148. package/dist/hud/state.js.map +1 -1
  149. package/dist/hud/tmux.d.ts +4 -0
  150. package/dist/hud/tmux.d.ts.map +1 -1
  151. package/dist/hud/tmux.js +86 -23
  152. package/dist/hud/tmux.js.map +1 -1
  153. package/dist/hud/types.d.ts +20 -0
  154. package/dist/hud/types.d.ts.map +1 -1
  155. package/dist/hud/types.js +3 -0
  156. package/dist/hud/types.js.map +1 -1
  157. package/dist/modes/base.d.ts +15 -2
  158. package/dist/modes/base.d.ts.map +1 -1
  159. package/dist/modes/base.js +105 -16
  160. package/dist/modes/base.js.map +1 -1
  161. package/dist/question/autopilot-wait.js +2 -2
  162. package/dist/question/autopilot-wait.js.map +1 -1
  163. package/dist/question/deep-interview.js +2 -2
  164. package/dist/question/deep-interview.js.map +1 -1
  165. package/dist/ralplan/__tests__/advisory-activation.test.d.ts +2 -0
  166. package/dist/ralplan/__tests__/advisory-activation.test.d.ts.map +1 -0
  167. package/dist/ralplan/__tests__/advisory-activation.test.js +700 -0
  168. package/dist/ralplan/__tests__/advisory-activation.test.js.map +1 -0
  169. package/dist/ralplan/__tests__/advisory-detached-transition.test.d.ts +2 -0
  170. package/dist/ralplan/__tests__/advisory-detached-transition.test.d.ts.map +1 -0
  171. package/dist/ralplan/__tests__/advisory-detached-transition.test.js +88 -0
  172. package/dist/ralplan/__tests__/advisory-detached-transition.test.js.map +1 -0
  173. package/dist/ralplan/__tests__/advisory.test.d.ts +2 -0
  174. package/dist/ralplan/__tests__/advisory.test.d.ts.map +1 -0
  175. package/dist/ralplan/__tests__/advisory.test.js +1087 -0
  176. package/dist/ralplan/__tests__/advisory.test.js.map +1 -0
  177. package/dist/ralplan/__tests__/runtime.test.js +416 -7
  178. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  179. package/dist/ralplan/advisory-activation-verifier.d.ts +19 -0
  180. package/dist/ralplan/advisory-activation-verifier.d.ts.map +1 -0
  181. package/dist/ralplan/advisory-activation-verifier.js +77 -0
  182. package/dist/ralplan/advisory-activation-verifier.js.map +1 -0
  183. package/dist/ralplan/advisory-activation.d.ts +34 -0
  184. package/dist/ralplan/advisory-activation.d.ts.map +1 -0
  185. package/dist/ralplan/advisory-activation.js +205 -0
  186. package/dist/ralplan/advisory-activation.js.map +1 -0
  187. package/dist/ralplan/advisory-contract.d.ts +103 -0
  188. package/dist/ralplan/advisory-contract.d.ts.map +1 -0
  189. package/dist/ralplan/advisory-contract.js +83 -0
  190. package/dist/ralplan/advisory-contract.js.map +1 -0
  191. package/dist/ralplan/advisory-detached-transition.d.ts +11 -0
  192. package/dist/ralplan/advisory-detached-transition.d.ts.map +1 -0
  193. package/dist/ralplan/advisory-detached-transition.js +21 -0
  194. package/dist/ralplan/advisory-detached-transition.js.map +1 -0
  195. package/dist/ralplan/advisory-evidence.d.ts +91 -0
  196. package/dist/ralplan/advisory-evidence.d.ts.map +1 -0
  197. package/dist/ralplan/advisory-evidence.js +393 -0
  198. package/dist/ralplan/advisory-evidence.js.map +1 -0
  199. package/dist/ralplan/advisory-lifecycle-validation.d.ts +11 -0
  200. package/dist/ralplan/advisory-lifecycle-validation.d.ts.map +1 -0
  201. package/dist/ralplan/advisory-lifecycle-validation.js +72 -0
  202. package/dist/ralplan/advisory-lifecycle-validation.js.map +1 -0
  203. package/dist/ralplan/advisory-postconditions.d.ts +3 -0
  204. package/dist/ralplan/advisory-postconditions.d.ts.map +1 -0
  205. package/dist/ralplan/advisory-postconditions.js +33 -0
  206. package/dist/ralplan/advisory-postconditions.js.map +1 -0
  207. package/dist/ralplan/advisory-recovery-journal.d.ts +56 -0
  208. package/dist/ralplan/advisory-recovery-journal.d.ts.map +1 -0
  209. package/dist/ralplan/advisory-recovery-journal.js +136 -0
  210. package/dist/ralplan/advisory-recovery-journal.js.map +1 -0
  211. package/dist/ralplan/advisory-storage.d.ts +24 -0
  212. package/dist/ralplan/advisory-storage.d.ts.map +1 -0
  213. package/dist/ralplan/advisory-storage.js +106 -0
  214. package/dist/ralplan/advisory-storage.js.map +1 -0
  215. package/dist/ralplan/advisory.d.ts +99 -0
  216. package/dist/ralplan/advisory.d.ts.map +1 -0
  217. package/dist/ralplan/advisory.js +914 -0
  218. package/dist/ralplan/advisory.js.map +1 -0
  219. package/dist/ralplan/documented-leader-preflight.d.ts +8 -0
  220. package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -1
  221. package/dist/ralplan/documented-leader-preflight.js +60 -2
  222. package/dist/ralplan/documented-leader-preflight.js.map +1 -1
  223. package/dist/ralplan/runtime-advisory-lifecycle.d.ts +74 -0
  224. package/dist/ralplan/runtime-advisory-lifecycle.d.ts.map +1 -0
  225. package/dist/ralplan/runtime-advisory-lifecycle.js +352 -0
  226. package/dist/ralplan/runtime-advisory-lifecycle.js.map +1 -0
  227. package/dist/ralplan/runtime-contract.d.ts +126 -0
  228. package/dist/ralplan/runtime-contract.d.ts.map +1 -0
  229. package/dist/ralplan/runtime-contract.js +2 -0
  230. package/dist/ralplan/runtime-contract.js.map +1 -0
  231. package/dist/ralplan/runtime.d.ts +6 -109
  232. package/dist/ralplan/runtime.d.ts.map +1 -1
  233. package/dist/ralplan/runtime.js +174 -56
  234. package/dist/ralplan/runtime.js.map +1 -1
  235. package/dist/scripts/__tests__/postinstall.test.js +26 -0
  236. package/dist/scripts/__tests__/postinstall.test.js.map +1 -1
  237. package/dist/scripts/__tests__/ralplan-advisory-hook.test.d.ts +2 -0
  238. package/dist/scripts/__tests__/ralplan-advisory-hook.test.d.ts.map +1 -0
  239. package/dist/scripts/__tests__/ralplan-advisory-hook.test.js +299 -0
  240. package/dist/scripts/__tests__/ralplan-advisory-hook.test.js.map +1 -0
  241. package/dist/scripts/__tests__/smoke-packed-install.test.js +102 -8
  242. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  243. package/dist/scripts/codex-native-hook.d.ts +20 -0
  244. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  245. package/dist/scripts/codex-native-hook.js +226 -15
  246. package/dist/scripts/codex-native-hook.js.map +1 -1
  247. package/dist/scripts/postinstall.d.ts +7 -0
  248. package/dist/scripts/postinstall.d.ts.map +1 -1
  249. package/dist/scripts/postinstall.js +40 -0
  250. package/dist/scripts/postinstall.js.map +1 -1
  251. package/dist/scripts/smoke-packed-install.d.ts +21 -5
  252. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  253. package/dist/scripts/smoke-packed-install.js +157 -57
  254. package/dist/scripts/smoke-packed-install.js.map +1 -1
  255. package/dist/state/__tests__/mode-binding-lease.test.d.ts +2 -0
  256. package/dist/state/__tests__/mode-binding-lease.test.d.ts.map +1 -0
  257. package/dist/state/__tests__/mode-binding-lease.test.js +498 -0
  258. package/dist/state/__tests__/mode-binding-lease.test.js.map +1 -0
  259. package/dist/state/__tests__/operations.test.js +1 -0
  260. package/dist/state/__tests__/operations.test.js.map +1 -1
  261. package/dist/state/__tests__/pinned-atomic-file.test.d.ts +2 -0
  262. package/dist/state/__tests__/pinned-atomic-file.test.d.ts.map +1 -0
  263. package/dist/state/__tests__/pinned-atomic-file.test.js +438 -0
  264. package/dist/state/__tests__/pinned-atomic-file.test.js.map +1 -0
  265. package/dist/state/__tests__/skill-active-exact-session-transaction.test.d.ts +2 -0
  266. package/dist/state/__tests__/skill-active-exact-session-transaction.test.d.ts.map +1 -0
  267. package/dist/state/__tests__/skill-active-exact-session-transaction.test.js +179 -0
  268. package/dist/state/__tests__/skill-active-exact-session-transaction.test.js.map +1 -0
  269. package/dist/state/__tests__/skill-active.test.js +29 -1
  270. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  271. package/dist/state/mode-binding-lease-helper.d.ts +2 -0
  272. package/dist/state/mode-binding-lease-helper.d.ts.map +1 -0
  273. package/dist/state/mode-binding-lease-helper.js +623 -0
  274. package/dist/state/mode-binding-lease-helper.js.map +1 -0
  275. package/dist/state/mode-binding-lease.d.ts +25 -0
  276. package/dist/state/mode-binding-lease.d.ts.map +1 -0
  277. package/dist/state/mode-binding-lease.js +380 -0
  278. package/dist/state/mode-binding-lease.js.map +1 -0
  279. package/dist/state/operations.d.ts +29 -1
  280. package/dist/state/operations.d.ts.map +1 -1
  281. package/dist/state/operations.js +203 -122
  282. package/dist/state/operations.js.map +1 -1
  283. package/dist/state/pinned-atomic-file-darwin-client.d.ts +34 -0
  284. package/dist/state/pinned-atomic-file-darwin-client.d.ts.map +1 -0
  285. package/dist/state/pinned-atomic-file-darwin-client.js +174 -0
  286. package/dist/state/pinned-atomic-file-darwin-client.js.map +1 -0
  287. package/dist/state/pinned-atomic-file-darwin-helper.d.ts +2 -0
  288. package/dist/state/pinned-atomic-file-darwin-helper.d.ts.map +1 -0
  289. package/dist/state/pinned-atomic-file-darwin-helper.js +275 -0
  290. package/dist/state/pinned-atomic-file-darwin-helper.js.map +1 -0
  291. package/dist/state/pinned-atomic-file-darwin-janitor.d.ts +2 -0
  292. package/dist/state/pinned-atomic-file-darwin-janitor.d.ts.map +1 -0
  293. package/dist/state/pinned-atomic-file-darwin-janitor.js +272 -0
  294. package/dist/state/pinned-atomic-file-darwin-janitor.js.map +1 -0
  295. package/dist/state/pinned-atomic-file.d.ts +29 -0
  296. package/dist/state/pinned-atomic-file.d.ts.map +1 -0
  297. package/dist/state/pinned-atomic-file.js +536 -0
  298. package/dist/state/pinned-atomic-file.js.map +1 -0
  299. package/dist/state/process-identity.d.ts +30 -0
  300. package/dist/state/process-identity.d.ts.map +1 -0
  301. package/dist/state/process-identity.js +99 -0
  302. package/dist/state/process-identity.js.map +1 -0
  303. package/dist/state/skill-active.d.ts +18 -1
  304. package/dist/state/skill-active.d.ts.map +1 -1
  305. package/dist/state/skill-active.js +82 -5
  306. package/dist/state/skill-active.js.map +1 -1
  307. package/dist/state/workflow-transition-reconcile.js +1 -1
  308. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  309. package/dist/team/__tests__/tmux-session.test.js +109 -0
  310. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  311. package/dist/team/tmux-session.d.ts.map +1 -1
  312. package/dist/team/tmux-session.js +10 -1
  313. package/dist/team/tmux-session.js.map +1 -1
  314. package/dist/utils/__tests__/file-durability.test.js +20 -0
  315. package/dist/utils/__tests__/file-durability.test.js.map +1 -1
  316. package/dist/utils/file-durability.d.ts +1 -1
  317. package/dist/utils/file-durability.d.ts.map +1 -1
  318. package/dist/utils/file-durability.js.map +1 -1
  319. package/dist/verification/__tests__/ci-rust-gates.test.js +12 -4
  320. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  321. package/dist/verification/__tests__/ci-trusted-publish.test.d.ts +2 -0
  322. package/dist/verification/__tests__/ci-trusted-publish.test.d.ts.map +1 -0
  323. package/dist/verification/__tests__/ci-trusted-publish.test.js +205 -0
  324. package/dist/verification/__tests__/ci-trusted-publish.test.js.map +1 -0
  325. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +10 -5
  326. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
  327. package/dist/verification/__tests__/publish-npm-manual-retired.test.d.ts +2 -0
  328. package/dist/verification/__tests__/publish-npm-manual-retired.test.d.ts.map +1 -0
  329. package/dist/verification/__tests__/publish-npm-manual-retired.test.js +22 -0
  330. package/dist/verification/__tests__/publish-npm-manual-retired.test.js.map +1 -0
  331. package/package.json +1 -1
  332. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  333. package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
  334. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
  335. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +10 -1
  336. package/plugins/oh-my-codex/skills/team/SKILL.md +2 -0
  337. package/skills/doctor/SKILL.md +1 -1
  338. package/skills/omx-setup/SKILL.md +1 -1
  339. package/skills/ralplan/SKILL.md +10 -1
  340. package/skills/team/SKILL.md +2 -0
  341. package/src/scripts/__tests__/postinstall.test.ts +28 -0
  342. package/src/scripts/__tests__/ralplan-advisory-hook.test.ts +320 -0
  343. package/src/scripts/__tests__/smoke-packed-install.test.ts +120 -7
  344. package/src/scripts/codex-native-hook.ts +220 -10
  345. package/src/scripts/postinstall.ts +46 -0
  346. package/src/scripts/smoke-packed-install.ts +175 -70
@@ -48,7 +48,7 @@ omx doctor
48
48
 
49
49
  Expect doctor evidence for prompts and skills in the selected scope, project-root AGENTS.md, `.omx/state`, and CLI-first config in the scope target `config.toml`. First-party MCP and shared registry sync are omitted unless setup used `--mcp compat` (if supported by the installed CLI).
50
50
 
51
- If using local source, run `npm run build` before `node bin/omx.js setup --force --verbose` and `node bin/omx.js doctor`. If AGENTS was not overwritten or merged, stop the active OMX session and rerun with `--force` or `--merge-agents`; do not edit lifecycle state manually.
51
+ If using local source, run `npm run build` before `node dist/cli/omx.js setup --force --verbose` and `node dist/cli/omx.js doctor`. If AGENTS was not overwritten or merged, stop the active OMX session and rerun with `--force` or `--merge-agents`; do not edit lifecycle state manually.
52
52
 
53
53
  ## Discovery troubleshooting
54
54
 
@@ -13,10 +13,19 @@ Ralplan is the canonical consensus-planning stage used by Autopilot between `$de
13
13
  $ralplan "task description"
14
14
  ```
15
15
 
16
+ Standalone advisory planning is explicitly opt-in:
17
+
18
+ ```text
19
+ $ralplan --advisory "task description"
20
+ ```
21
+
22
+ Advisory runs the same sequential Planner → Architect → Critic review lifecycle, binds the plan and both review artifacts to exact bytes and one tracker-backed iteration, then returns to the caller with `active:false`. It is a cooperative workflow pause, not a security fence or permission system. It never emits a `PreToolUse` allow/block decision, never completes the host consensus gate, never authorizes execution, and never suppresses unrelated host behavior. Terminal state must carry explicit `false` values for the consensus gate, host verification, and execution handoff rather than omitting them. A later concrete affirmative execution request may produce non-authoritative routing context, but it does not persist a permission, rewrite terminal evidence, or create an automatic handoff; quotations, code, examples, documentation, questions, modal requests, negations, and vague approval remain classifier negatives. `approved+proven` requires complete lifecycle digests plus post-write revalidation. Administrative abandonment is append-only, idempotent for prepared or committed journals, and records a separate byte-bound admin event without rewriting the original closeout journal. Real enforcement requires an explicit host-issued, host-verified receipt or capability on a non-user-mintable surface; local Advisory files, prompts, session/thread fields, tracker records, and HERDR observability cannot substitute for it. On Darwin, each Advisory evidence artifact is limited to 128 KiB by the pinned-directory reader; other supported platforms allow up to 8 MiB.
23
+
16
24
  ## Flags
17
25
 
18
26
  - `--interactive`: Enables user prompts at key decision points (draft review in step 2 and final approval in step 6). Without this flag the workflow runs fully automated — Planner → Architect → Critic loop — and outputs the final plan without asking for confirmation.
19
27
  - `--deliberate`: Forces deliberate mode for high-risk work. Adds pre-mortem (3 scenarios) and expanded test planning (unit/integration/e2e/observability). Without this flag, deliberate mode can still auto-enable when the request explicitly signals high risk (auth/security, migrations, destructive changes, production incidents, compliance/PII, public API breakage).
28
+ - `--advisory`: Standalone only. It cannot be combined with Autopilot, Pipeline, Team, Ralph, Ultragoal, execution flags, or unknown flags. Activation requires canonical session, root thread, and turn identity.
20
29
 
21
30
  ## Ontology-heavy review
22
31
 
@@ -194,7 +203,7 @@ The gate auto-passes when it detects **any** concrete signal. You do not need al
194
203
  | Gate fires on a well-specified prompt | Add a file reference, function name, or issue number to anchor the request |
195
204
  | Want to bypass the gate | Prefix with `force:` or `!` (e.g., `force: ralph fix it`) |
196
205
  | Gate does not fire on a vague prompt | The gate only catches prompts with <=15 effective words and no concrete anchors; add more detail or use `$ralplan` explicitly |
197
- | Redirected to ralplan but want to skip planning | In the ralplan workflow, say "just do it" or "skip planning" to transition directly to execution |
206
+ | Redirected to ralplan but want to stop planning | Cancel or abandon through the workflow's administrative path. Advisory is cooperative and does not enforce host permissions; a real security gate would require an explicit host-issued, host-verified receipt. |
198
207
 
199
208
  ## Scenario Examples
200
209
 
@@ -15,6 +15,8 @@ Use only for an explicit `$team` request or `omx team ...` launch that benefits
15
15
  - Require `tmux -V`, a leader session with `$TMUX`, and the intended `omx` executable. In Codex App/plain non-tmux sessions, explain the runtime boundary instead of pretending Team is available.
16
16
  - Before launch, ground the task in a recent `.omx/context/{slug}-*.md`; create a concise snapshot when none exists. Include target, evidence, constraints, unknowns, and likely touchpoints.
17
17
  - Do not launch nested Team runs. Pick worker roles deliberately; use `OMX_TEAM_WORKER_CLI=codex|claude|auto` or `OMX_TEAM_WORKER_CLI_MAP=...` only when needed.
18
+ - Per-agent reasoning is set by `agentReasoning`; accepted values are `low`, `medium`, `high`, `xhigh`, and `max`. `max` is passed unchanged and remains capability-dependent. `ultra` is unsupported and is not an alias for `max`.
19
+ - Invalid configured values use the built-in role-default fallback. An explicit raw `-c model_reasoning_effort=...` is opaque and wins. When both sources are present, explicit raw reasoning wins over inherited Team reasoning and environment reasoning. Do not downgrade or retry `max` as `xhigh`; built-in role defaults remain unchanged.
18
20
 
19
21
  ## Operational steps
20
22
 
@@ -17,7 +17,7 @@ omx doctor --force # repair eligible repo artifact ownership issues
17
17
  omx doctor --dry-run --force # preview eligible ownership repairs
18
18
  ```
19
19
 
20
- For a local source checkout, build first and invoke `node bin/omx.js doctor`. Keep command output and exact paths for the report.
20
+ For a local source checkout, build first and invoke `node dist/cli/omx.js doctor`. Keep command output and exact paths for the report.
21
21
 
22
22
  ### Plugin cache and version
23
23
 
@@ -48,7 +48,7 @@ omx doctor
48
48
 
49
49
  Expect doctor evidence for prompts and skills in the selected scope, project-root AGENTS.md, `.omx/state`, and CLI-first config in the scope target `config.toml`. First-party MCP and shared registry sync are omitted unless setup used `--mcp compat` (if supported by the installed CLI).
50
50
 
51
- If using local source, run `npm run build` before `node bin/omx.js setup --force --verbose` and `node bin/omx.js doctor`. If AGENTS was not overwritten or merged, stop the active OMX session and rerun with `--force` or `--merge-agents`; do not edit lifecycle state manually.
51
+ If using local source, run `npm run build` before `node dist/cli/omx.js setup --force --verbose` and `node dist/cli/omx.js doctor`. If AGENTS was not overwritten or merged, stop the active OMX session and rerun with `--force` or `--merge-agents`; do not edit lifecycle state manually.
52
52
 
53
53
  ## Discovery troubleshooting
54
54
 
@@ -13,10 +13,19 @@ Ralplan is the canonical consensus-planning stage used by Autopilot between `$de
13
13
  $ralplan "task description"
14
14
  ```
15
15
 
16
+ Standalone advisory planning is explicitly opt-in:
17
+
18
+ ```text
19
+ $ralplan --advisory "task description"
20
+ ```
21
+
22
+ Advisory runs the same sequential Planner → Architect → Critic review lifecycle, binds the plan and both review artifacts to exact bytes and one tracker-backed iteration, then returns to the caller with `active:false`. It is a cooperative workflow pause, not a security fence or permission system. It never emits a `PreToolUse` allow/block decision, never completes the host consensus gate, never authorizes execution, and never suppresses unrelated host behavior. Terminal state must carry explicit `false` values for the consensus gate, host verification, and execution handoff rather than omitting them. A later concrete affirmative execution request may produce non-authoritative routing context, but it does not persist a permission, rewrite terminal evidence, or create an automatic handoff; quotations, code, examples, documentation, questions, modal requests, negations, and vague approval remain classifier negatives. `approved+proven` requires complete lifecycle digests plus post-write revalidation. Administrative abandonment is append-only, idempotent for prepared or committed journals, and records a separate byte-bound admin event without rewriting the original closeout journal. Real enforcement requires an explicit host-issued, host-verified receipt or capability on a non-user-mintable surface; local Advisory files, prompts, session/thread fields, tracker records, and HERDR observability cannot substitute for it. On Darwin, each Advisory evidence artifact is limited to 128 KiB by the pinned-directory reader; other supported platforms allow up to 8 MiB.
23
+
16
24
  ## Flags
17
25
 
18
26
  - `--interactive`: Enables user prompts at key decision points (draft review in step 2 and final approval in step 6). Without this flag the workflow runs fully automated — Planner → Architect → Critic loop — and outputs the final plan without asking for confirmation.
19
27
  - `--deliberate`: Forces deliberate mode for high-risk work. Adds pre-mortem (3 scenarios) and expanded test planning (unit/integration/e2e/observability). Without this flag, deliberate mode can still auto-enable when the request explicitly signals high risk (auth/security, migrations, destructive changes, production incidents, compliance/PII, public API breakage).
28
+ - `--advisory`: Standalone only. It cannot be combined with Autopilot, Pipeline, Team, Ralph, Ultragoal, execution flags, or unknown flags. Activation requires canonical session, root thread, and turn identity.
20
29
 
21
30
  ## Ontology-heavy review
22
31
 
@@ -194,7 +203,7 @@ The gate auto-passes when it detects **any** concrete signal. You do not need al
194
203
  | Gate fires on a well-specified prompt | Add a file reference, function name, or issue number to anchor the request |
195
204
  | Want to bypass the gate | Prefix with `force:` or `!` (e.g., `force: ralph fix it`) |
196
205
  | Gate does not fire on a vague prompt | The gate only catches prompts with <=15 effective words and no concrete anchors; add more detail or use `$ralplan` explicitly |
197
- | Redirected to ralplan but want to skip planning | In the ralplan workflow, say "just do it" or "skip planning" to transition directly to execution |
206
+ | Redirected to ralplan but want to stop planning | Cancel or abandon through the workflow's administrative path. Advisory is cooperative and does not enforce host permissions; a real security gate would require an explicit host-issued, host-verified receipt. |
198
207
 
199
208
  ## Scenario Examples
200
209
 
@@ -15,6 +15,8 @@ Use only for an explicit `$team` request or `omx team ...` launch that benefits
15
15
  - Require `tmux -V`, a leader session with `$TMUX`, and the intended `omx` executable. In Codex App/plain non-tmux sessions, explain the runtime boundary instead of pretending Team is available.
16
16
  - Before launch, ground the task in a recent `.omx/context/{slug}-*.md`; create a concise snapshot when none exists. Include target, evidence, constraints, unknowns, and likely touchpoints.
17
17
  - Do not launch nested Team runs. Pick worker roles deliberately; use `OMX_TEAM_WORKER_CLI=codex|claude|auto` or `OMX_TEAM_WORKER_CLI_MAP=...` only when needed.
18
+ - Per-agent reasoning is set by `agentReasoning`; accepted values are `low`, `medium`, `high`, `xhigh`, and `max`. `max` is passed unchanged and remains capability-dependent. `ultra` is unsupported and is not an alias for `max`.
19
+ - Invalid configured values use the built-in role-default fallback. An explicit raw `-c model_reasoning_effort=...` is opaque and wins. When both sources are present, explicit raw reasoning wins over inherited Team reasoning and environment reasoning. Do not downgrade or retry `max` as `xhigh`; built-in role defaults remain unchanged.
18
20
 
19
21
  ## Operational steps
20
22
 
@@ -33,6 +33,7 @@ describe("runPostinstall", () => {
33
33
  const result = await runPostinstall({
34
34
  env: { npm_config_global: "true" },
35
35
  getCurrentVersion: async () => "0.14.1",
36
+ hydrateRuntime: async () => "/cache/omx-runtime",
36
37
  log: (message) => logs.push(message),
37
38
  readStamp: async () => ({
38
39
  installed_version: "0.14.0",
@@ -44,6 +45,7 @@ describe("runPostinstall", () => {
44
45
  });
45
46
 
46
47
  assert.equal(result.status, "hinted");
48
+ assert.match(logs.join("\n"), /Hydrated omx-runtime/);
47
49
  assert.match(logs.join("\n"), /OMX setup is explicit opt-in; run `omx setup` or `omx update` when you're ready/);
48
50
 
49
51
  const stamp = JSON.parse(await readFile(stampPath, "utf-8")) as {
@@ -68,6 +70,7 @@ describe("runPostinstall", () => {
68
70
  const result = await runPostinstall({
69
71
  env: { npm_config_global: "true" },
70
72
  getCurrentVersion: async () => "0.14.1",
73
+ hydrateRuntime: async () => "/cache/omx-runtime",
71
74
  log: (message) => logs.push(message),
72
75
  readStamp: async () => ({
73
76
  installed_version: "0.14.0",
@@ -100,6 +103,7 @@ describe("runPostinstall", () => {
100
103
  npm_config_user_agent: "bun/1.2.0 npm/? node/v22.0.0 linux x64",
101
104
  },
102
105
  getCurrentVersion: async () => "0.14.1",
106
+ hydrateRuntime: async () => "/cache/omx-runtime",
103
107
  readStamp: async () => null,
104
108
  writeStamp: async (stamp) => {
105
109
  writtenStamp = stamp;
@@ -114,15 +118,21 @@ describe("runPostinstall", () => {
114
118
  const result = await runPostinstall({
115
119
  env: { npm_config_global: "false" },
116
120
  getCurrentVersion: async () => "0.14.1",
121
+ hydrateRuntime: async () => "/cache/omx-runtime",
117
122
  });
118
123
 
119
124
  assert.equal(result.status, "noop-local");
120
125
  });
121
126
 
122
127
  it("does not rerun setup when the installed version matches the saved stamp", async () => {
128
+ let hydrated = false;
123
129
  const result = await runPostinstall({
124
130
  env: { npm_config_global: "true" },
125
131
  getCurrentVersion: async () => "0.14.1",
132
+ hydrateRuntime: async () => {
133
+ hydrated = true;
134
+ return "/cache/omx-runtime";
135
+ },
126
136
  readStamp: async () => ({
127
137
  installed_version: "0.14.1",
128
138
  setup_completed_version: "0.14.1",
@@ -131,5 +141,23 @@ describe("runPostinstall", () => {
131
141
  });
132
142
 
133
143
  assert.equal(result.status, "noop-same-version");
144
+ assert.equal(hydrated, true, "same-version reinstalls must repair a missing native runtime cache");
145
+ });
146
+
147
+ it("keeps global installation non-fatal when runtime hydration fails", async () => {
148
+ const logs: string[] = [];
149
+ const result = await runPostinstall({
150
+ env: { npm_config_global: "true" },
151
+ getCurrentVersion: async () => "0.14.1",
152
+ hydrateRuntime: async () => {
153
+ throw new Error("offline");
154
+ },
155
+ log: (message) => logs.push(message),
156
+ readStamp: async () => null,
157
+ writeStamp: async () => {},
158
+ });
159
+
160
+ assert.equal(result.status, "hinted");
161
+ assert.match(logs.join("\n"), /hydration failed non-fatally: offline/);
134
162
  });
135
163
  });
@@ -0,0 +1,320 @@
1
+ import { afterEach, describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { spawnSync } from 'node:child_process';
7
+ import {
8
+ readCurrentRalplanAdvisory,
9
+ reconcileRalplanAdvisory,
10
+ observeRalplanAdvisoryPrompt,
11
+ terminalizeRalplanAdvisory,
12
+ } from '../../ralplan/advisory.js';
13
+ import { activateOrResumeRalplanAdvisory } from '../../ralplan/advisory-activation.js';
14
+ import {
15
+ buildRalplanAdvisoryRoutingObservation,
16
+ dispatchCodexNativeHook,
17
+ } from '../codex-native-hook.js';
18
+
19
+ const roots: string[] = [];
20
+ afterEach(async () => Promise.all(roots.splice(0).map((path) => rm(path, { recursive: true, force: true }))));
21
+
22
+ async function terminalFixture(prefix: string) {
23
+ const cwd = await mkdtemp(join(tmpdir(), prefix));
24
+ roots.push(cwd);
25
+ const sessionId = 'session-a';
26
+ const stateDir = join(cwd, '.omx', 'state');
27
+ const sessionDir = join(stateDir, 'sessions', sessionId);
28
+ await mkdir(sessionDir, { recursive: true });
29
+ await writeFile(join(stateDir, 'session.json'), JSON.stringify({
30
+ session_id: sessionId, native_session_id: sessionId, owner_codex_session_id: sessionId,
31
+ leader_thread_id: 'root-a', started_at: '2026-08-28T00:00:00.000Z', cwd, state_root: stateDir,
32
+ }));
33
+ await writeFile(join(stateDir, 'subagent-tracking.json'), JSON.stringify({
34
+ schemaVersion: 1,
35
+ sessions: {
36
+ [sessionId]: {
37
+ session_id: sessionId, leader_thread_id: 'root-a',
38
+ threads: { 'root-a': { thread_id: 'root-a', kind: 'leader' } },
39
+ },
40
+ },
41
+ }));
42
+ const { activation } = await activateOrResumeRalplanAdvisory({
43
+ cwd, sessionId, rootThreadId: 'root-a', activationTurnId: 'turn-a', generationId: 'generation-a',
44
+ prompt: '$ralplan --advisory hook fixture', producer: 'native', threadKind: 'root-or-drift',
45
+ });
46
+ const activeMode = {
47
+ active: true, mode: 'ralplan', current_phase: 'draft', iteration: 1,
48
+ session_id: sessionId, thread_id: 'root-a', turn_id: 'turn-a',
49
+ workflow_variant: 'advisory', advisory_generation_id: activation.generation_id,
50
+ execution_handoff_authorized: false, host_verified: false, planning_complete: false,
51
+ };
52
+ await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify(activeMode));
53
+ await terminalizeRalplanAdvisory({
54
+ cwd, sessionId, generationId: activation.generation_id, closingTurnId: 'turn-close', iteration: 1,
55
+ outcome: 'cancelled', integrityStatus: 'proven',
56
+ });
57
+ const inactiveMode = {
58
+ ...activeMode, active: false, current_phase: 'complete', planning_complete: true,
59
+ execution_handoff_authorized: false, host_verified: false,
60
+ ralplan_consensus_gate: { complete: false },
61
+ };
62
+ await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify(inactiveMode));
63
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify(inactiveMode));
64
+ return { cwd, sessionId, stateDir, sessionDir, activation };
65
+ }
66
+
67
+ async function conflictingReplayFixture(prefix: string, standardPhase = 'architect-review') {
68
+ const fixture = await terminalFixture(prefix);
69
+ // Replace the committed cancellation fixture with a fresh generation whose
70
+ // journal is deliberately left prepared before any mirror replay.
71
+ await rm(join(fixture.sessionDir, 'ralplan-advisory'), { recursive: true, force: true });
72
+ const { activation } = await activateOrResumeRalplanAdvisory({
73
+ cwd: fixture.cwd, sessionId: fixture.sessionId, rootThreadId: 'root-a', activationTurnId: 'turn-replay', generationId: 'generation-replay',
74
+ prompt: '$ralplan --advisory replay fixture', producer: 'native', threadKind: 'root-or-drift',
75
+ });
76
+ const advisoryMode = {
77
+ active: true, mode: 'ralplan', current_phase: 'draft', session_id: fixture.sessionId, thread_id: 'root-a', turn_id: 'turn-replay',
78
+ workflow_variant: 'advisory', advisory_generation_id: activation.generation_id,
79
+ };
80
+ await writeFile(join(fixture.sessionDir, 'ralplan-state.json'), JSON.stringify(advisoryMode));
81
+ await assert.rejects(terminalizeRalplanAdvisory({
82
+ cwd: fixture.cwd, sessionId: fixture.sessionId, generationId: activation.generation_id,
83
+ closingTurnId: 'turn-close-replay', iteration: 1, outcome: 'cancelled', integrityStatus: 'proven',
84
+ terminalModeUpdates: {
85
+ ...advisoryMode, active: false, current_phase: 'cancelled', execution_handoff_authorized: false, host_verified: false,
86
+ },
87
+ failpoint: (name) => { if (name === 'journal-prepare') throw new Error('prepared-replay'); },
88
+ }), /prepared-replay/);
89
+ const standardMode = {
90
+ active: true, mode: 'ralplan', workflow_variant: 'standard', current_phase: standardPhase,
91
+ session_id: fixture.sessionId, thread_id: 'root-standard', turn_id: 'turn-standard',
92
+ };
93
+ const modePath = join(fixture.sessionDir, 'ralplan-state.json');
94
+ await writeFile(modePath, JSON.stringify(standardMode));
95
+ return { ...fixture, activation, generationDir: join(fixture.sessionDir, 'ralplan-advisory', activation.generation_id), modePath, standardMode };
96
+ }
97
+
98
+ async function snapshotDirectoryBytes(root: string): Promise<Array<[string, string]>> {
99
+ const values: Array<[string, string]> = [];
100
+ const walk = async (directory: string, prefix = ''): Promise<void> => {
101
+ for (const entry of (await readdir(directory, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
102
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
103
+ const path = join(directory, entry.name);
104
+ if (entry.isDirectory()) await walk(path, relative);
105
+ else values.push([relative, (await readFile(path)).toString('base64')]);
106
+ }
107
+ };
108
+ await walk(root);
109
+ return values;
110
+ }
111
+
112
+ describe('ralplan advisory non-authoritative native hooks', () => {
113
+ it('the packed hook never emits a PreToolUse block for Advisory, including mutation and unknown MCP transports', async () => {
114
+ const { cwd, sessionId } = await terminalFixture('omx-advisory-nonauthoritative-pretool-');
115
+ for (const toolName of ['Write', 'Bash', 'mcp__omx_goal__create_goal', 'mcp__thirdparty__commit', 'mcp__unknown__anything']) {
116
+ const packed = await dispatchCodexNativeHook({
117
+ hook_event_name: 'PreToolUse', cwd, session_id: sessionId, thread_id: 'root-a',
118
+ tool_name: toolName, tool_input: { file_path: join(cwd, 'src', 'x.ts'), content: 'x' },
119
+ } as never, { cwd });
120
+ assert.notEqual(packed.outputJson?.decision, 'block', toolName);
121
+ }
122
+ const cli = spawnSync(process.execPath, [join(process.cwd(), 'dist', 'scripts', 'codex-native-hook.js')], {
123
+ cwd,
124
+ input: JSON.stringify({
125
+ hook_event_name: 'PreToolUse', cwd, session_id: sessionId, thread_id: 'root-a',
126
+ tool_name: 'Write', tool_input: { file_path: join(cwd, 'src', 'packed.ts'), content: 'x' },
127
+ }),
128
+ encoding: 'utf8',
129
+ });
130
+ assert.equal(cli.status, 0, cli.stderr);
131
+ assert.notEqual((JSON.parse(cli.stdout || '{}') as Record<string, unknown>).decision, 'block');
132
+ });
133
+
134
+ it('observes an explicit later execution request without automatic handoff or persistent elevation', async () => {
135
+ const { cwd, sessionId, sessionDir, activation } = await terminalFixture('omx-advisory-routing-observation-');
136
+ const before = await readCurrentRalplanAdvisory(cwd, sessionId);
137
+ const observed = await observeRalplanAdvisoryPrompt({
138
+ cwd, sessionId, turnId: 'turn-execute', threadId: 'root-a', prompt: 'implementá el plan .omx/plans/plan.md',
139
+ producer: 'native', threadKind: 'root-or-drift', isSubagentPromptSubmit: false,
140
+ });
141
+ const mode = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf8'));
142
+ const context = buildRalplanAdvisoryRoutingObservation(observed.intent, observed.projection, mode) ?? '';
143
+ assert.match(context, /ended as cancelled/i);
144
+ assert.doesNotMatch(context, /planning is complete/i);
145
+ const after = await readCurrentRalplanAdvisory(cwd, sessionId);
146
+ assert.deepEqual(after?.fence, before?.fence);
147
+ assert.equal(mode.active, false);
148
+ assert.equal(mode.planning_complete, true);
149
+ assert.equal(mode.host_verified, false);
150
+ assert.equal(mode.execution_handoff_authorized, false);
151
+ await assert.rejects(readFile(join(sessionDir, 'ralplan-advisory', activation.generation_id, 'release-authority.json')), /ENOENT/);
152
+ });
153
+
154
+ it('keeps classifier negatives inert and supplies context only for a primary affirmative request', async () => {
155
+ for (const [index, prompt] of ['¿podés implementarlo?', 'no quiero implementar', 'considerá implementar', 'copiá la frase implementá el plan'].entries()) {
156
+ const { cwd, sessionId } = await terminalFixture(`omx-advisory-routing-negative-${index}-`);
157
+ const observed = await observeRalplanAdvisoryPrompt({
158
+ cwd, sessionId, turnId: `turn-${index}`, threadId: 'root-a', prompt,
159
+ producer: 'native', threadKind: 'root-or-drift', isSubagentPromptSubmit: false,
160
+ });
161
+ const context = buildRalplanAdvisoryRoutingObservation(observed.intent, observed.projection, null) ?? '';
162
+ assert.doesNotMatch(context, /non-authoritative routing observation/i, prompt);
163
+ }
164
+ });
165
+
166
+ it('reports positive routing context only for a complete approved proven lifecycle without a conflicting workflow', async () => {
167
+ const { cwd, sessionId } = await terminalFixture('omx-advisory-routing-matrix-');
168
+ const base = (await readCurrentRalplanAdvisory(cwd, sessionId))!;
169
+ const digest = 'a'.repeat(64);
170
+ const approved = {
171
+ ...base,
172
+ fence: {
173
+ ...base.fence!, state: 'closed', outcome: 'approved', integrity_status: 'proven', evidence_bundle_sha256: digest,
174
+ iteration_id: 'iteration-a', plan_manifest_sha256: 'b'.repeat(64), architect_review_sha256: 'c'.repeat(64),
175
+ critic_review_sha256: 'd'.repeat(64),
176
+ },
177
+ journal: {
178
+ ...base.journal!, phase: 'committed', outcome: 'approved', integrity_status: 'proven', evidence_bundle_sha256: digest,
179
+ terminal_mode_updates: { ralplan_review_lifecycle: {
180
+ complete: true, sequence_valid: true, iteration: base.fence!.iteration, iteration_id: 'iteration-a',
181
+ plan_manifest_sha256: 'b'.repeat(64), architect_review_sha256: 'c'.repeat(64),
182
+ critic_review_sha256: 'd'.repeat(64), evidence_bundle_sha256: digest,
183
+ evidence_scope: 'local_runtime', host_observable: false, host_verified: false,
184
+ } },
185
+ },
186
+ } as typeof base;
187
+ const advisoryBinding = {
188
+ active: false, workflow_variant: 'advisory', advisory_generation_id: base.activation.generation_id,
189
+ execution_handoff_authorized: false, host_verified: false, ralplan_consensus_gate: { complete: false },
190
+ };
191
+ const positive = buildRalplanAdvisoryRoutingObservation('execute', approved, advisoryBinding) ?? '';
192
+ assert.match(positive, /planning is complete/i);
193
+ assert.match(buildRalplanAdvisoryRoutingObservation('execute', approved, null) ?? '', /planning is complete/i);
194
+ assert.equal(buildRalplanAdvisoryRoutingObservation('execute', approved, { workflow_variant: 'standard', active: true }), null);
195
+
196
+ for (const [state, outcome, expected] of [
197
+ ['pending_closeout', undefined, /still pending/i],
198
+ ['recovery_required', 'failed', /requires lifecycle recovery/i],
199
+ ['abandoned', 'abandoned', /ended as abandoned/i],
200
+ ['abandoned', 'cancelled', /ended as cancelled/i],
201
+ ] as const) {
202
+ const projection = { ...base, fence: { ...base.fence!, state, outcome } } as typeof base;
203
+ assert.match(buildRalplanAdvisoryRoutingObservation('execute', projection, advisoryBinding) ?? '', expected);
204
+ }
205
+ const incomplete = { ...approved, journal: { ...approved.journal!, terminal_mode_updates: {} } } as typeof base;
206
+ assert.match(buildRalplanAdvisoryRoutingObservation('execute', incomplete, advisoryBinding) ?? '', /does not contain a complete/i);
207
+ });
208
+
209
+ it('retains terminal evidence across restart-shaped reads without creating authorization', async () => {
210
+ const { cwd, sessionId, sessionDir } = await terminalFixture('omx-advisory-restart-evidence-');
211
+ const first = await readCurrentRalplanAdvisory(cwd, sessionId);
212
+ const second = await readCurrentRalplanAdvisory(cwd, sessionId);
213
+ assert.deepEqual(second?.fence, first?.fence);
214
+ assert.equal(second?.corruption, null);
215
+ const mode = JSON.parse(await readFile(join(sessionDir, 'ralplan-state.json'), 'utf8'));
216
+ assert.equal(mode.host_verified, false);
217
+ assert.equal(mode.execution_handoff_authorized, false);
218
+ });
219
+
220
+ it('surfaces reconciliation failures non-authoritatively while SessionStart and Stop continue normally', async () => {
221
+ const { cwd, sessionId } = await terminalFixture('omx-advisory-reconcile-diagnostic-');
222
+ const reconcileFailure = async (): Promise<never> => { throw new Error('test-reconcile-visible'); };
223
+ const start = await dispatchCodexNativeHook({
224
+ hook_event_name: 'SessionStart', cwd, session_id: sessionId, thread_id: 'root-a', source: 'startup',
225
+ }, { cwd, reconcileRalplanAdvisoryFn: reconcileFailure });
226
+ const startContext = ((start.outputJson?.hookSpecificOutput as Record<string, unknown> | undefined)?.additionalContext ?? '') as string;
227
+ assert.match(startContext, /test-reconcile-visible/);
228
+ assert.match(startContext, /non-authoritative diagnostic/);
229
+ assert.match(startContext, /Execution environment/i, 'normal SessionStart context should still be produced');
230
+
231
+ const stopFixture = await terminalFixture('omx-advisory-stop-reconcile-diagnostic-');
232
+ const stop = await dispatchCodexNativeHook({
233
+ hook_event_name: 'Stop', cwd: stopFixture.cwd, source: 'codex-app', session_id: stopFixture.sessionId,
234
+ thread_id: 'root-a', turn_id: 'turn-stop-diagnostic',
235
+ }, { cwd: stopFixture.cwd, reconcileRalplanAdvisoryFn: reconcileFailure });
236
+ assert.notEqual(stop.outputJson?.decision, 'block');
237
+ const baselineFixture = await terminalFixture('omx-advisory-stop-reconcile-baseline-');
238
+ const baselineStop = await dispatchCodexNativeHook({
239
+ hook_event_name: 'Stop', cwd: baselineFixture.cwd, source: 'codex-app', session_id: baselineFixture.sessionId,
240
+ thread_id: 'root-a', turn_id: 'turn-stop-baseline',
241
+ }, { cwd: baselineFixture.cwd });
242
+ assert.deepEqual(stop.outputJson, baselineStop.outputJson, 'diagnostic must not change the Stop decision/output contract');
243
+ const logDir = join(stopFixture.cwd, '.omx', 'logs');
244
+ const logBytes = (await Promise.all((await (await import('node:fs/promises')).readdir(logDir))
245
+ .map((name) => readFile(join(logDir, name), 'utf8')))).join('\n');
246
+ assert.match(logBytes, /ralplan_advisory_reconciliation_diagnostic/);
247
+ assert.match(logBytes, /test-reconcile-visible/);
248
+ });
249
+
250
+ it('does not replay a terminal Advisory journal over a live standard workflow on SessionStart or Stop', async () => {
251
+ const snapshotRelevant = async (fixture: Awaited<ReturnType<typeof conflictingReplayFixture>>) => ({
252
+ mode: await readFile(fixture.modePath, 'utf8'),
253
+ generation: await snapshotDirectoryBytes(fixture.generationDir),
254
+ sessionSkill: await readFile(join(fixture.sessionDir, 'skill-active-state.json'), 'utf8').catch(() => null),
255
+ rootSkill: await readFile(join(fixture.stateDir, 'skill-active-state.json'), 'utf8').catch(() => null),
256
+ });
257
+
258
+ const startFixture = await conflictingReplayFixture('omx-advisory-standard-start-conflict-');
259
+ const startBefore = await snapshotRelevant(startFixture);
260
+ const start = await dispatchCodexNativeHook({
261
+ hook_event_name: 'SessionStart', cwd: startFixture.cwd, session_id: startFixture.sessionId,
262
+ thread_id: 'root-standard', source: 'startup',
263
+ }, { cwd: startFixture.cwd });
264
+ const startContext = ((start.outputJson?.hookSpecificOutput as Record<string, unknown> | undefined)?.additionalContext ?? '') as string;
265
+ assert.match(startContext, /live_session_binding_conflict/);
266
+ assert.deepEqual(await snapshotRelevant(startFixture), startBefore);
267
+ const routed = await observeRalplanAdvisoryPrompt({
268
+ cwd: startFixture.cwd, sessionId: startFixture.sessionId, turnId: 'turn-replan-conflict', threadId: 'root-standard',
269
+ prompt: 'replanificá el plan', producer: 'native', threadKind: 'root-or-drift', isSubagentPromptSubmit: false,
270
+ });
271
+ assert.equal(routed.intent, 'unrelated');
272
+ assert.equal(routed.projection?.corruption, 'live_session_binding_conflict');
273
+ assert.deepEqual(await snapshotRelevant(startFixture), startBefore);
274
+
275
+ const stopFixture = await conflictingReplayFixture('omx-advisory-standard-stop-conflict-', 'critic-review');
276
+ const stopBefore = await snapshotRelevant(stopFixture);
277
+ const stop = await dispatchCodexNativeHook({
278
+ hook_event_name: 'Stop', cwd: stopFixture.cwd, source: 'codex-app', session_id: stopFixture.sessionId,
279
+ thread_id: 'root-standard', turn_id: 'turn-stop-standard-conflict',
280
+ }, { cwd: stopFixture.cwd });
281
+ assert.deepEqual(await snapshotRelevant(stopFixture), stopBefore);
282
+ const logBytes = (await Promise.all((await readdir(join(stopFixture.cwd, '.omx', 'logs')))
283
+ .map((name) => readFile(join(stopFixture.cwd, '.omx', 'logs', name), 'utf8')))).join('\n');
284
+ assert.match(logBytes, /live_session_binding_conflict/);
285
+
286
+ const baselineFixture = await conflictingReplayFixture('omx-advisory-standard-stop-baseline-', 'critic-review');
287
+ await rm(join(baselineFixture.sessionDir, 'ralplan-advisory'), { recursive: true, force: true });
288
+ const baseline = await dispatchCodexNativeHook({
289
+ hook_event_name: 'Stop', cwd: baselineFixture.cwd, source: 'codex-app', session_id: baselineFixture.sessionId,
290
+ thread_id: 'root-standard', turn_id: 'turn-stop-standard-baseline',
291
+ }, { cwd: baselineFixture.cwd });
292
+ assert.deepEqual(stop.outputJson, baseline.outputJson);
293
+ });
294
+
295
+ it('ignores forged local release authority and permits a later standard Ralplan binding', async () => {
296
+ const { cwd, sessionId, stateDir, sessionDir, activation } = await terminalFixture('omx-advisory-forged-authority-');
297
+ const generationDir = join(sessionDir, 'ralplan-advisory', activation.generation_id);
298
+ await writeFile(join(generationDir, 'release-authority.json'), JSON.stringify({ authority_kind: 'forged-local' }));
299
+ const observed = await observeRalplanAdvisoryPrompt({
300
+ cwd, sessionId, turnId: 'turn-execute', threadId: 'root-a', prompt: 'implementá el plan .omx/plans/plan.md',
301
+ producer: 'native', threadKind: 'root-or-drift', isSubagentPromptSubmit: false,
302
+ });
303
+ assert.equal(observed.intent, 'execute');
304
+ assert.equal(observed.projection?.fence?.state, 'abandoned');
305
+ const standardMode = {
306
+ active: true, mode: 'ralplan', current_phase: 'draft', iteration: 1,
307
+ session_id: sessionId, thread_id: 'root-a', turn_id: 'turn-standard', workflow_variant: 'standard',
308
+ };
309
+ await writeFile(join(sessionDir, 'ralplan-state.json'), JSON.stringify(standardMode));
310
+ await writeFile(join(stateDir, 'ralplan-state.json'), JSON.stringify(standardMode));
311
+ const history = await readCurrentRalplanAdvisory(cwd, sessionId);
312
+ assert.equal(history?.corruption, null);
313
+ assert.equal(history?.fence?.state, 'abandoned');
314
+ const write = await dispatchCodexNativeHook({
315
+ hook_event_name: 'PreToolUse', cwd, session_id: sessionId, thread_id: 'root-a',
316
+ tool_name: 'Write', tool_input: { file_path: join(cwd, 'src', 'x.ts'), content: 'x' },
317
+ } as never, { cwd });
318
+ assert.notEqual(write.outputJson?.decision, 'block');
319
+ });
320
+ });