oh-my-codex 0.18.0 → 0.18.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 (410) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +45 -19
  4. package/crates/omx-api/src/lib.rs +66 -9
  5. package/crates/omx-sparkshell/src/exec.rs +125 -3
  6. package/crates/omx-sparkshell/src/main.rs +126 -36
  7. package/crates/omx-sparkshell/tests/execution.rs +225 -1
  8. package/dist/agents/__tests__/definitions.test.js +14 -0
  9. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  10. package/dist/agents/__tests__/native-config.test.js +19 -0
  11. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  12. package/dist/agents/definitions.d.ts.map +1 -1
  13. package/dist/agents/definitions.js +30 -0
  14. package/dist/agents/definitions.js.map +1 -1
  15. package/dist/agents/native-config.d.ts +1 -0
  16. package/dist/agents/native-config.d.ts.map +1 -1
  17. package/dist/agents/native-config.js +4 -0
  18. package/dist/agents/native-config.js.map +1 -1
  19. package/dist/catalog/__tests__/generator.test.js +4 -0
  20. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  21. package/dist/cli/__tests__/codex-plugin-layout.test.js +15 -7
  22. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  23. package/dist/cli/__tests__/doctor-warning-copy.test.js +137 -8
  24. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  25. package/dist/cli/__tests__/index.test.js +203 -15
  26. package/dist/cli/__tests__/index.test.js.map +1 -1
  27. package/dist/cli/__tests__/install-docs-contract.test.d.ts +2 -0
  28. package/dist/cli/__tests__/install-docs-contract.test.d.ts.map +1 -0
  29. package/dist/cli/__tests__/install-docs-contract.test.js +55 -0
  30. package/dist/cli/__tests__/install-docs-contract.test.js.map +1 -0
  31. package/dist/cli/__tests__/launch-fallback.test.js +163 -0
  32. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  33. package/dist/cli/__tests__/question.test.js +29 -43
  34. package/dist/cli/__tests__/question.test.js.map +1 -1
  35. package/dist/cli/__tests__/setup-install-mode.test.js +94 -35
  36. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  37. package/dist/cli/__tests__/sparkshell-cli.test.js +20 -1
  38. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  39. package/dist/cli/__tests__/sparkshell-packaging.test.js +1 -0
  40. package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -1
  41. package/dist/cli/__tests__/ultragoal.test.js +227 -4
  42. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  43. package/dist/cli/__tests__/update.test.js +72 -1
  44. package/dist/cli/__tests__/update.test.js.map +1 -1
  45. package/dist/cli/codex-feature-probe.d.ts +5 -0
  46. package/dist/cli/codex-feature-probe.d.ts.map +1 -1
  47. package/dist/cli/codex-feature-probe.js +13 -7
  48. package/dist/cli/codex-feature-probe.js.map +1 -1
  49. package/dist/cli/doctor.d.ts +7 -0
  50. package/dist/cli/doctor.d.ts.map +1 -1
  51. package/dist/cli/doctor.js +297 -17
  52. package/dist/cli/doctor.js.map +1 -1
  53. package/dist/cli/index.d.ts +9 -1
  54. package/dist/cli/index.d.ts.map +1 -1
  55. package/dist/cli/index.js +465 -110
  56. package/dist/cli/index.js.map +1 -1
  57. package/dist/cli/plugin-marketplace.d.ts +2 -0
  58. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  59. package/dist/cli/plugin-marketplace.js +15 -1
  60. package/dist/cli/plugin-marketplace.js.map +1 -1
  61. package/dist/cli/setup.d.ts.map +1 -1
  62. package/dist/cli/setup.js +71 -11
  63. package/dist/cli/setup.js.map +1 -1
  64. package/dist/cli/sparkshell.d.ts +7 -1
  65. package/dist/cli/sparkshell.d.ts.map +1 -1
  66. package/dist/cli/sparkshell.js +13 -3
  67. package/dist/cli/sparkshell.js.map +1 -1
  68. package/dist/cli/ultragoal.d.ts +1 -1
  69. package/dist/cli/ultragoal.d.ts.map +1 -1
  70. package/dist/cli/ultragoal.js +184 -10
  71. package/dist/cli/ultragoal.js.map +1 -1
  72. package/dist/cli/update.d.ts +2 -0
  73. package/dist/cli/update.d.ts.map +1 -1
  74. package/dist/cli/update.js +14 -3
  75. package/dist/cli/update.js.map +1 -1
  76. package/dist/compat/__tests__/doctor-contract.test.js +3 -0
  77. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  78. package/dist/config/__tests__/codex-feature-flags.test.js +11 -1
  79. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -1
  80. package/dist/config/__tests__/codex-hooks.test.js +22 -11
  81. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  82. package/dist/config/__tests__/commit-lore-guard.test.d.ts +2 -0
  83. package/dist/config/__tests__/commit-lore-guard.test.d.ts.map +1 -0
  84. package/dist/config/__tests__/commit-lore-guard.test.js +20 -0
  85. package/dist/config/__tests__/commit-lore-guard.test.js.map +1 -0
  86. package/dist/config/codex-feature-flags.d.ts +4 -0
  87. package/dist/config/codex-feature-flags.d.ts.map +1 -1
  88. package/dist/config/codex-feature-flags.js +4 -0
  89. package/dist/config/codex-feature-flags.js.map +1 -1
  90. package/dist/config/codex-hooks.d.ts +1 -0
  91. package/dist/config/codex-hooks.d.ts.map +1 -1
  92. package/dist/config/codex-hooks.js +8 -10
  93. package/dist/config/codex-hooks.js.map +1 -1
  94. package/dist/config/commit-lore-guard.d.ts +1 -0
  95. package/dist/config/commit-lore-guard.d.ts.map +1 -1
  96. package/dist/config/commit-lore-guard.js +29 -3
  97. package/dist/config/commit-lore-guard.js.map +1 -1
  98. package/dist/config/generator.d.ts +17 -1
  99. package/dist/config/generator.d.ts.map +1 -1
  100. package/dist/config/generator.js +124 -11
  101. package/dist/config/generator.js.map +1 -1
  102. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
  103. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
  104. package/dist/goal-workflows/codex-goal-snapshot.d.ts +4 -0
  105. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
  106. package/dist/goal-workflows/codex-goal-snapshot.js +50 -3
  107. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  108. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +27 -6
  109. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  110. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
  111. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +13 -11
  112. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  113. package/dist/hooks/__tests__/deep-interview-contract.test.js +4 -3
  114. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  115. package/dist/hooks/__tests__/keyword-detector.test.js +173 -17
  116. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  117. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +33 -0
  118. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  119. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
  120. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
  121. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
  122. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
  123. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
  124. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  125. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
  126. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
  127. package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
  128. package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
  129. package/dist/hooks/extensibility/__tests__/dispatcher.test.js +26 -3
  130. package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
  131. package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
  132. package/dist/hooks/extensibility/dispatcher.js +29 -14
  133. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  134. package/dist/hooks/keyword-detector.d.ts +1 -1
  135. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  136. package/dist/hooks/keyword-detector.js +36 -9
  137. package/dist/hooks/keyword-detector.js.map +1 -1
  138. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  139. package/dist/hooks/keyword-registry.js +1 -0
  140. package/dist/hooks/keyword-registry.js.map +1 -1
  141. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  142. package/dist/hooks/prompt-guidance-contract.js +14 -2
  143. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  144. package/dist/hud/__tests__/hud-tmux-injection.test.js +36 -8
  145. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  146. package/dist/hud/__tests__/reconcile.test.js +122 -11
  147. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  148. package/dist/hud/__tests__/render.test.js +84 -0
  149. package/dist/hud/__tests__/render.test.js.map +1 -1
  150. package/dist/hud/__tests__/resource-leak-watch.test.d.ts +2 -0
  151. package/dist/hud/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  152. package/dist/hud/__tests__/resource-leak-watch.test.js +28 -0
  153. package/dist/hud/__tests__/resource-leak-watch.test.js.map +1 -0
  154. package/dist/hud/__tests__/state.test.js +51 -1
  155. package/dist/hud/__tests__/state.test.js.map +1 -1
  156. package/dist/hud/__tests__/tmux.test.js +69 -23
  157. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  158. package/dist/hud/index.d.ts +2 -2
  159. package/dist/hud/index.d.ts.map +1 -1
  160. package/dist/hud/index.js +17 -6
  161. package/dist/hud/index.js.map +1 -1
  162. package/dist/hud/reconcile.d.ts.map +1 -1
  163. package/dist/hud/reconcile.js +6 -3
  164. package/dist/hud/reconcile.js.map +1 -1
  165. package/dist/hud/render.d.ts.map +1 -1
  166. package/dist/hud/render.js +26 -0
  167. package/dist/hud/render.js.map +1 -1
  168. package/dist/hud/state.d.ts +2 -1
  169. package/dist/hud/state.d.ts.map +1 -1
  170. package/dist/hud/state.js +62 -1
  171. package/dist/hud/state.js.map +1 -1
  172. package/dist/hud/tmux.d.ts +10 -3
  173. package/dist/hud/tmux.d.ts.map +1 -1
  174. package/dist/hud/tmux.js +60 -11
  175. package/dist/hud/tmux.js.map +1 -1
  176. package/dist/hud/types.d.ts +22 -0
  177. package/dist/hud/types.d.ts.map +1 -1
  178. package/dist/hud/types.js.map +1 -1
  179. package/dist/notifications/__tests__/http-client-resource.test.d.ts +2 -0
  180. package/dist/notifications/__tests__/http-client-resource.test.d.ts.map +1 -0
  181. package/dist/notifications/__tests__/http-client-resource.test.js +41 -0
  182. package/dist/notifications/__tests__/http-client-resource.test.js.map +1 -0
  183. package/dist/notifications/__tests__/verbosity.test.js +20 -0
  184. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  185. package/dist/notifications/config.d.ts.map +1 -1
  186. package/dist/notifications/config.js +6 -3
  187. package/dist/notifications/config.js.map +1 -1
  188. package/dist/notifications/http-client.d.ts.map +1 -1
  189. package/dist/notifications/http-client.js +78 -27
  190. package/dist/notifications/http-client.js.map +1 -1
  191. package/dist/notifications/types.d.ts +2 -0
  192. package/dist/notifications/types.d.ts.map +1 -1
  193. package/dist/openclaw/__tests__/dispatcher.test.js +49 -1
  194. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
  195. package/dist/openclaw/dispatcher.d.ts +7 -4
  196. package/dist/openclaw/dispatcher.d.ts.map +1 -1
  197. package/dist/openclaw/dispatcher.js +32 -69
  198. package/dist/openclaw/dispatcher.js.map +1 -1
  199. package/dist/pipeline/__tests__/orchestrator.test.js +128 -4
  200. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  201. package/dist/pipeline/__tests__/stages.test.js +460 -9
  202. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  203. package/dist/pipeline/index.d.ts +8 -2
  204. package/dist/pipeline/index.d.ts.map +1 -1
  205. package/dist/pipeline/index.js +5 -2
  206. package/dist/pipeline/index.js.map +1 -1
  207. package/dist/pipeline/orchestrator.d.ts +5 -4
  208. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  209. package/dist/pipeline/orchestrator.js +85 -17
  210. package/dist/pipeline/orchestrator.js.map +1 -1
  211. package/dist/pipeline/stages/code-review.d.ts +2 -2
  212. package/dist/pipeline/stages/code-review.d.ts.map +1 -1
  213. package/dist/pipeline/stages/code-review.js +5 -3
  214. package/dist/pipeline/stages/code-review.js.map +1 -1
  215. package/dist/pipeline/stages/deep-interview.d.ts +15 -0
  216. package/dist/pipeline/stages/deep-interview.d.ts.map +1 -0
  217. package/dist/pipeline/stages/deep-interview.js +32 -0
  218. package/dist/pipeline/stages/deep-interview.js.map +1 -0
  219. package/dist/pipeline/stages/ralph-verify.d.ts +5 -5
  220. package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
  221. package/dist/pipeline/stages/ralph-verify.js +2 -2
  222. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  223. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  224. package/dist/pipeline/stages/ralplan.js +41 -6
  225. package/dist/pipeline/stages/ralplan.js.map +1 -1
  226. package/dist/pipeline/stages/ultragoal.d.ts +19 -0
  227. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -0
  228. package/dist/pipeline/stages/ultragoal.js +38 -0
  229. package/dist/pipeline/stages/ultragoal.js.map +1 -0
  230. package/dist/pipeline/stages/ultraqa.d.ts +30 -0
  231. package/dist/pipeline/stages/ultraqa.d.ts.map +1 -0
  232. package/dist/pipeline/stages/ultraqa.js +46 -0
  233. package/dist/pipeline/stages/ultraqa.js.map +1 -0
  234. package/dist/pipeline/types.d.ts +8 -6
  235. package/dist/pipeline/types.d.ts.map +1 -1
  236. package/dist/pipeline/types.js +2 -2
  237. package/dist/question/__tests__/ui.test.js +43 -10
  238. package/dist/question/__tests__/ui.test.js.map +1 -1
  239. package/dist/question/ui.d.ts +12 -0
  240. package/dist/question/ui.d.ts.map +1 -1
  241. package/dist/question/ui.js +83 -46
  242. package/dist/question/ui.js.map +1 -1
  243. package/dist/ralplan/__tests__/runtime.test.js +200 -10
  244. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  245. package/dist/ralplan/consensus-gate.d.ts +23 -0
  246. package/dist/ralplan/consensus-gate.d.ts.map +1 -0
  247. package/dist/ralplan/consensus-gate.js +212 -0
  248. package/dist/ralplan/consensus-gate.js.map +1 -0
  249. package/dist/ralplan/runtime.d.ts +25 -0
  250. package/dist/ralplan/runtime.d.ts.map +1 -1
  251. package/dist/ralplan/runtime.js +144 -8
  252. package/dist/ralplan/runtime.js.map +1 -1
  253. package/dist/scripts/__tests__/codex-native-hook.test.js +1358 -79
  254. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  255. package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
  256. package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
  257. package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
  258. package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
  259. package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
  260. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  261. package/dist/scripts/__tests__/run-test-files.test.js +57 -0
  262. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  263. package/dist/scripts/__tests__/smoke-packed-install.test.js +23 -1
  264. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  265. package/dist/scripts/__tests__/verify-native-agents.test.js +18 -3
  266. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  267. package/dist/scripts/cleanup-explore-harness.js +1 -0
  268. package/dist/scripts/cleanup-explore-harness.js.map +1 -1
  269. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  270. package/dist/scripts/codex-native-hook.js +372 -44
  271. package/dist/scripts/codex-native-hook.js.map +1 -1
  272. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  273. package/dist/scripts/codex-native-pre-post.js +9 -1
  274. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  275. package/dist/scripts/notify-dispatcher.js +188 -4
  276. package/dist/scripts/notify-dispatcher.js.map +1 -1
  277. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
  278. package/dist/scripts/notify-hook/process-runner.js +39 -17
  279. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  280. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  281. package/dist/scripts/notify-hook/team-dispatch.js +9 -5
  282. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  283. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +1 -1
  284. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  285. package/dist/scripts/notify-hook/team-tmux-guard.js +7 -1
  286. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  287. package/dist/scripts/run-test-files.js +13 -0
  288. package/dist/scripts/run-test-files.js.map +1 -1
  289. package/dist/scripts/smoke-packed-install.d.ts +3 -0
  290. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  291. package/dist/scripts/smoke-packed-install.js +99 -1
  292. package/dist/scripts/smoke-packed-install.js.map +1 -1
  293. package/dist/scripts/sync-plugin-mirror.js +2 -2
  294. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  295. package/dist/scripts/verify-native-agents.js +2 -2
  296. package/dist/scripts/verify-native-agents.js.map +1 -1
  297. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts +2 -0
  298. package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts.map +1 -0
  299. package/dist/sidecar/__tests__/resource-leak-watch.test.js +38 -0
  300. package/dist/sidecar/__tests__/resource-leak-watch.test.js.map +1 -0
  301. package/dist/sidecar/index.d.ts +1 -1
  302. package/dist/sidecar/index.d.ts.map +1 -1
  303. package/dist/sidecar/index.js +29 -12
  304. package/dist/sidecar/index.js.map +1 -1
  305. package/dist/state/__tests__/operations-ralph-phase.test.js +88 -1
  306. package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -1
  307. package/dist/state/__tests__/workflow-transition.test.js +6 -0
  308. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  309. package/dist/state/operations.d.ts.map +1 -1
  310. package/dist/state/operations.js +11 -0
  311. package/dist/state/operations.js.map +1 -1
  312. package/dist/state/workflow-transition.d.ts +1 -1
  313. package/dist/state/workflow-transition.d.ts.map +1 -1
  314. package/dist/state/workflow-transition.js +7 -0
  315. package/dist/state/workflow-transition.js.map +1 -1
  316. package/dist/subagents/tracker.d.ts.map +1 -1
  317. package/dist/subagents/tracker.js +4 -3
  318. package/dist/subagents/tracker.js.map +1 -1
  319. package/dist/team/__tests__/runtime.test.js +36 -44
  320. package/dist/team/__tests__/runtime.test.js.map +1 -1
  321. package/dist/team/__tests__/tmux-session.test.js +163 -15
  322. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  323. package/dist/team/runtime.d.ts.map +1 -1
  324. package/dist/team/runtime.js +10 -20
  325. package/dist/team/runtime.js.map +1 -1
  326. package/dist/team/tmux-session.d.ts.map +1 -1
  327. package/dist/team/tmux-session.js +51 -21
  328. package/dist/team/tmux-session.js.map +1 -1
  329. package/dist/ultragoal/__tests__/artifacts.test.js +764 -10
  330. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  331. package/dist/ultragoal/__tests__/docs-contract.test.js +57 -1
  332. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  333. package/dist/ultragoal/__tests__/steering-fixtures.d.ts +68 -0
  334. package/dist/ultragoal/__tests__/steering-fixtures.d.ts.map +1 -0
  335. package/dist/ultragoal/__tests__/steering-fixtures.js +259 -0
  336. package/dist/ultragoal/__tests__/steering-fixtures.js.map +1 -0
  337. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts +2 -0
  338. package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts.map +1 -0
  339. package/dist/ultragoal/__tests__/steering-fixtures.test.js +65 -0
  340. package/dist/ultragoal/__tests__/steering-fixtures.test.js.map +1 -0
  341. package/dist/ultragoal/artifacts.d.ts +97 -2
  342. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  343. package/dist/ultragoal/artifacts.js +837 -256
  344. package/dist/ultragoal/artifacts.js.map +1 -1
  345. package/dist/utils/__tests__/sleep-resource.test.d.ts +2 -0
  346. package/dist/utils/__tests__/sleep-resource.test.d.ts.map +1 -0
  347. package/dist/utils/__tests__/sleep-resource.test.js +39 -0
  348. package/dist/utils/__tests__/sleep-resource.test.js.map +1 -0
  349. package/dist/utils/sleep.d.ts.map +1 -1
  350. package/dist/utils/sleep.js +17 -6
  351. package/dist/utils/sleep.js.map +1 -1
  352. package/package.json +2 -1
  353. package/plugins/oh-my-codex/.codex-plugin/plugin.json +4 -3
  354. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +56 -0
  355. package/plugins/oh-my-codex/hooks/hooks.json +77 -0
  356. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +92 -50
  357. package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
  358. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
  359. package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
  360. package/plugins/oh-my-codex/skills/cancel/SKILL.md +2 -2
  361. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +8 -8
  362. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
  363. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +23 -12
  364. package/plugins/oh-my-codex/skills/plan/SKILL.md +8 -8
  365. package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
  366. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
  367. package/plugins/oh-my-codex/skills/ralph/SKILL.md +7 -0
  368. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +22 -7
  369. package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
  370. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +38 -4
  371. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +1 -1
  372. package/prompts/planner.md +1 -1
  373. package/prompts/prometheus-strict-metis.md +274 -0
  374. package/prompts/prometheus-strict-momus.md +82 -0
  375. package/prompts/prometheus-strict-oracle.md +107 -0
  376. package/prompts/researcher.md +22 -3
  377. package/skills/autopilot/SKILL.md +92 -50
  378. package/skills/autoresearch/SKILL.md +4 -0
  379. package/skills/autoresearch-goal/SKILL.md +1 -1
  380. package/skills/best-practice-research/SKILL.md +1 -1
  381. package/skills/cancel/SKILL.md +2 -2
  382. package/skills/deep-interview/SKILL.md +8 -8
  383. package/skills/omx-setup/SKILL.md +1 -1
  384. package/skills/pipeline/SKILL.md +23 -12
  385. package/skills/plan/SKILL.md +8 -8
  386. package/skills/prometheus-strict/README.md +35 -0
  387. package/skills/prometheus-strict/SKILL.md +219 -0
  388. package/skills/ralph/SKILL.md +7 -0
  389. package/skills/ralplan/SKILL.md +22 -7
  390. package/skills/team/SKILL.md +1 -1
  391. package/skills/ultragoal/SKILL.md +38 -4
  392. package/skills/ultrawork/SKILL.md +1 -1
  393. package/src/scripts/__tests__/codex-native-hook.test.ts +1757 -210
  394. package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
  395. package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
  396. package/src/scripts/__tests__/run-test-files.test.ts +67 -0
  397. package/src/scripts/__tests__/smoke-packed-install.test.ts +31 -0
  398. package/src/scripts/__tests__/verify-native-agents.test.ts +23 -3
  399. package/src/scripts/cleanup-explore-harness.ts +1 -0
  400. package/src/scripts/codex-native-hook.ts +393 -40
  401. package/src/scripts/codex-native-pre-post.ts +16 -1
  402. package/src/scripts/notify-dispatcher.ts +202 -4
  403. package/src/scripts/notify-hook/process-runner.ts +40 -16
  404. package/src/scripts/notify-hook/team-dispatch.ts +9 -5
  405. package/src/scripts/notify-hook/team-tmux-guard.ts +7 -0
  406. package/src/scripts/run-test-files.ts +13 -0
  407. package/src/scripts/smoke-packed-install.ts +105 -0
  408. package/src/scripts/sync-plugin-mirror.ts +3 -3
  409. package/src/scripts/verify-native-agents.ts +2 -2
  410. package/templates/catalog-manifest.json +22 -0
@@ -2,7 +2,11 @@ import {
2
2
  buildDocumentRefreshAdvisoryOutput,
3
3
  evaluateStagedDocumentRefresh,
4
4
  } from "../document-refresh/enforcer.js";
5
- import { isLoreCommitGuardEnabled } from "../config/commit-lore-guard.js";
5
+ import {
6
+ OMX_LORE_COMMIT_GUARD_ENV,
7
+ isLoreCommitGuardEnabled,
8
+ readConfiguredLoreCommitGuardValue,
9
+ } from "../config/commit-lore-guard.js";
6
10
  import { resolveCodexExecutionSurface } from "./codex-execution-surface.js";
7
11
 
8
12
  type CodexHookPayload = Record<string, unknown>;
@@ -747,6 +751,17 @@ function buildEffectiveLoreCommitGuardEnv(parsed: GitCommitCommandParseResult):
747
751
  for (const [name, value] of Object.entries(parsed.inlineEnvironment)) {
748
752
  if (typeof value === "string") effectiveEnvironment[name] = value;
749
753
  }
754
+
755
+ if (
756
+ !parsed.environmentStartsClean
757
+ && !parsed.unsetEnvironmentNames.includes(OMX_LORE_COMMIT_GUARD_ENV)
758
+ && typeof effectiveEnvironment[OMX_LORE_COMMIT_GUARD_ENV] !== "string"
759
+ ) {
760
+ const configuredValue = readConfiguredLoreCommitGuardValue(effectiveEnvironment);
761
+ if (typeof configuredValue === "string") {
762
+ effectiveEnvironment[OMX_LORE_COMMIT_GUARD_ENV] = configuredValue;
763
+ }
764
+ }
750
765
  return effectiveEnvironment;
751
766
  }
752
767
 
@@ -7,6 +7,9 @@
7
7
 
8
8
  import { readFile } from "fs/promises";
9
9
  import { spawnSync } from "child_process";
10
+ import { closeSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, writeFileSync } from "fs";
11
+ import { dirname, join } from "path";
12
+ import { tmpdir } from "os";
10
13
 
11
14
  interface NotifyDispatcherMetadata {
12
15
  managedBy?: string;
@@ -16,6 +19,195 @@ interface NotifyDispatcherMetadata {
16
19
  dispatcherNotify?: string[];
17
20
  }
18
21
 
22
+ const DISPATCH_LOCK_STALE_MS = 45_000;
23
+ // Codex Desktop can replay a backlog of turn-ended callbacks well after the UI
24
+ // window has gone away. Keep the default same-turn coalescing window longer
25
+ // than a heavily loaded notification hook invocation so sequential queued
26
+ // callbacks from one thread do not slip through merely because the first
27
+ // dispatch was slow. Payloads with different thread/session identity retain
28
+ // independent notification cadence.
29
+ const DEFAULT_TURN_DISPATCH_MIN_INTERVAL_MS = 10_000;
30
+ const DEFAULT_STALE_EVENT_AGE_MS = 5 * 60_000;
31
+
32
+ interface DispatchGuard {
33
+ ok: boolean;
34
+ release?: () => void;
35
+ }
36
+
37
+ interface DispatchGuardState {
38
+ lastDispatchAt?: unknown;
39
+ lastDispatchByIdentity?: Record<string, unknown>;
40
+ }
41
+
42
+ function parseNonNegativeEnvMs(name: string, fallback: number): number {
43
+ const raw = process.env[name];
44
+ if (typeof raw !== "string" || raw.trim() === "") return fallback;
45
+ const parsed = Number(raw);
46
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
47
+ }
48
+
49
+ function parsePayloadObject(payloadArg: string): Record<string, unknown> | null {
50
+ try {
51
+ const parsed = JSON.parse(payloadArg) as unknown;
52
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
53
+ ? (parsed as Record<string, unknown>)
54
+ : null;
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ function isTurnEndedPayload(payload: Record<string, unknown> | null): boolean {
61
+ if (!payload) return false;
62
+ const type = String(payload.type ?? payload.event ?? payload.hook_event_name ?? "")
63
+ .trim()
64
+ .toLowerCase();
65
+ return type === ""
66
+ || type === "agent-turn-complete"
67
+ || type === "turn-complete"
68
+ || type === "turn-ended";
69
+ }
70
+
71
+ function readPayloadTimestampMs(payload: Record<string, unknown>): number | null {
72
+ for (const key of ["timestamp", "created_at", "createdAt", "event_time", "eventTime", "time"]) {
73
+ const value = payload[key];
74
+ if (typeof value === "number" && Number.isFinite(value)) {
75
+ return value > 1_000_000_000_000 ? value : value * 1000;
76
+ }
77
+ if (typeof value === "string" && value.trim()) {
78
+ const parsed = Date.parse(value);
79
+ if (Number.isFinite(parsed)) return parsed;
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ function readPayloadIdentity(payload: Record<string, unknown> | null): string {
86
+ if (!payload) return "global";
87
+ for (const key of [
88
+ "thread_id",
89
+ "threadId",
90
+ "conversation_id",
91
+ "conversationId",
92
+ "session_id",
93
+ "sessionId",
94
+ ]) {
95
+ const value = payload[key];
96
+ if (typeof value === "string" && value.trim()) {
97
+ return `${key}:${value.trim()}`;
98
+ }
99
+ }
100
+ return "global";
101
+ }
102
+
103
+ function dispatchGuardDir(metadataPath: string): string {
104
+ if (metadataPath) return dirname(metadataPath);
105
+ return join(tmpdir(), "oh-my-codex-notify-dispatch");
106
+ }
107
+
108
+ function writeDispatchGuardState(
109
+ statePath: string,
110
+ state: DispatchGuardState,
111
+ identity: string,
112
+ minIntervalMs: number,
113
+ staleEventAgeMs: number,
114
+ ): void {
115
+ const previousByIdentity = state.lastDispatchByIdentity && typeof state.lastDispatchByIdentity === "object"
116
+ ? state.lastDispatchByIdentity
117
+ : {};
118
+ const retainedByIdentity: Record<string, number> = {};
119
+ const now = Date.now();
120
+ const retentionMs = Math.max(minIntervalMs, staleEventAgeMs, DEFAULT_TURN_DISPATCH_MIN_INTERVAL_MS);
121
+ for (const [key, value] of Object.entries(previousByIdentity)) {
122
+ if (typeof value === "number" && now - value <= retentionMs) {
123
+ retainedByIdentity[key] = value;
124
+ }
125
+ }
126
+ retainedByIdentity[identity] = now;
127
+ writeFileSync(statePath, JSON.stringify({
128
+ lastDispatchAt: identity === "global" ? now : (typeof state.lastDispatchAt === "number" ? state.lastDispatchAt : undefined),
129
+ lastDispatchByIdentity: retainedByIdentity,
130
+ pid: process.pid,
131
+ }));
132
+ }
133
+
134
+ function acquireTurnDispatchGuard(metadataPath: string, payloadArg: string): DispatchGuard {
135
+ const payload = parsePayloadObject(payloadArg);
136
+ if (!isTurnEndedPayload(payload)) return { ok: true };
137
+
138
+ const now = Date.now();
139
+ const staleEventAgeMs = parseNonNegativeEnvMs("OMX_NOTIFY_DISPATCH_STALE_EVENT_AGE_MS", DEFAULT_STALE_EVENT_AGE_MS);
140
+ const eventTimestampMs = payload ? readPayloadTimestampMs(payload) : null;
141
+ if (eventTimestampMs !== null && staleEventAgeMs > 0 && now - eventTimestampMs > staleEventAgeMs) {
142
+ return { ok: false };
143
+ }
144
+
145
+ const dir = dispatchGuardDir(metadataPath);
146
+ mkdirSync(dir, { recursive: true });
147
+ const lockPath = join(dir, "notify-dispatch.lock");
148
+ const statePath = join(dir, "notify-dispatch.guard.json");
149
+ try {
150
+ const lockStat = statSync(lockPath);
151
+ if (now - lockStat.mtimeMs > DISPATCH_LOCK_STALE_MS) unlinkSync(lockPath);
152
+ } catch {
153
+ // Missing or unreadable lock: try to acquire below.
154
+ }
155
+
156
+ let fd: number;
157
+ try {
158
+ fd = openSync(lockPath, "wx");
159
+ writeFileSync(fd, String(process.pid));
160
+ closeSync(fd);
161
+ } catch {
162
+ return { ok: false };
163
+ }
164
+
165
+ const release = () => {
166
+ try {
167
+ unlinkSync(lockPath);
168
+ } catch {
169
+ // Best effort.
170
+ }
171
+ };
172
+
173
+ try {
174
+ const minIntervalMs = parseNonNegativeEnvMs("OMX_NOTIFY_DISPATCH_MIN_INTERVAL_MS", DEFAULT_TURN_DISPATCH_MIN_INTERVAL_MS);
175
+ const identity = readPayloadIdentity(payload);
176
+ let state: DispatchGuardState = {};
177
+ try {
178
+ state = JSON.parse(readFileSync(statePath, "utf-8")) as typeof state;
179
+ } catch {
180
+ // No prior guard state.
181
+ }
182
+ if (minIntervalMs > 0) {
183
+ const byIdentity = state.lastDispatchByIdentity && typeof state.lastDispatchByIdentity === "object"
184
+ ? state.lastDispatchByIdentity
185
+ : {};
186
+ const identityLastDispatchAt = typeof byIdentity[identity] === "number" ? byIdentity[identity] : 0;
187
+ const legacyLastDispatchAt = identity === "global" && typeof state.lastDispatchAt === "number" ? state.lastDispatchAt : 0;
188
+ const lastDispatchAt = Math.max(identityLastDispatchAt, legacyLastDispatchAt);
189
+ if (lastDispatchAt > 0 && now - lastDispatchAt < minIntervalMs) {
190
+ release();
191
+ return { ok: false };
192
+ }
193
+ }
194
+ return {
195
+ ok: true,
196
+ release: () => {
197
+ try {
198
+ writeDispatchGuardState(statePath, state, identity, minIntervalMs, staleEventAgeMs);
199
+ } catch {
200
+ // Guard state is best effort; the lock still prevents concurrent duplicate dispatch.
201
+ }
202
+ release();
203
+ },
204
+ };
205
+ } catch {
206
+ release();
207
+ return { ok: false };
208
+ }
209
+ }
210
+
19
211
  function parseArgs(): { metadataPath: string; payloadArg: string } {
20
212
  let metadataPath = "";
21
213
  const args = process.argv.slice(2);
@@ -200,11 +392,17 @@ function runNotify(
200
392
  async function main(): Promise<void> {
201
393
  const { metadataPath, payloadArg } = parseArgs();
202
394
  if (!payloadArg || payloadArg.startsWith("-")) return;
203
- const metadata = await readMetadata(metadataPath);
204
- if (!isManagedPreviousNotify(metadata?.previousNotify, metadata)) {
205
- runNotify(metadata?.previousNotify, payloadArg);
395
+ const guard = acquireTurnDispatchGuard(metadataPath, payloadArg);
396
+ if (!guard.ok) return;
397
+ try {
398
+ const metadata = await readMetadata(metadataPath);
399
+ if (!isManagedPreviousNotify(metadata?.previousNotify, metadata)) {
400
+ runNotify(metadata?.previousNotify, payloadArg);
401
+ }
402
+ runNotify(metadata?.omxNotify, payloadArg);
403
+ } finally {
404
+ guard.release?.();
206
405
  }
207
- runNotify(metadata?.omxNotify, payloadArg);
208
406
  }
209
407
 
210
408
  main().catch(() => {});
@@ -17,35 +17,59 @@ export function runProcess(command: string, args: string[], timeoutMs = 3000): P
17
17
  let stdout = '';
18
18
  let stderr = '';
19
19
  let finished = false;
20
+ let sigkillTimer: ReturnType<typeof setTimeout> | undefined;
20
21
 
21
- const timer = setTimeout(() => {
22
- if (finished) return;
23
- finished = true;
24
- child.kill('SIGTERM');
25
- reject(new Error(`timeout after ${effectiveTimeoutMs}ms`));
26
- }, effectiveTimeoutMs);
22
+ const cleanup = (clearPendingSigkill = true) => {
23
+ clearTimeout(timer);
24
+ if (clearPendingSigkill && sigkillTimer) {
25
+ clearTimeout(sigkillTimer);
26
+ sigkillTimer = undefined;
27
+ }
28
+ child.stdout.off('data', onStdout);
29
+ child.stderr.off('data', onStderr);
30
+ child.off('error', onError);
31
+ child.off('close', onClose);
32
+ };
27
33
 
28
- child.stdout.on('data', (chunk: Buffer) => {
34
+ const onStdout = (chunk: Buffer) => {
29
35
  stdout += chunk.toString();
30
- });
31
- child.stderr.on('data', (chunk: Buffer) => {
36
+ };
37
+ const onStderr = (chunk: Buffer) => {
32
38
  stderr += chunk.toString();
33
- });
34
- child.on('error', (err: Error) => {
39
+ };
40
+ const onError = (err: Error) => {
35
41
  if (finished) return;
36
42
  finished = true;
37
- clearTimeout(timer);
43
+ cleanup();
38
44
  reject(err);
39
- });
40
- child.on('close', (code: number | null) => {
45
+ };
46
+ const onClose = (code: number | null) => {
41
47
  if (finished) return;
42
48
  finished = true;
43
- clearTimeout(timer);
49
+ cleanup();
44
50
  if (code === 0) {
45
51
  resolve({ stdout, stderr, code });
46
52
  } else {
47
53
  reject(new Error(stderr.trim() || `${command} exited ${code}`));
48
54
  }
49
- });
55
+ };
56
+
57
+ const timer = setTimeout(() => {
58
+ if (finished) return;
59
+ finished = true;
60
+ child.kill('SIGTERM');
61
+ sigkillTimer = setTimeout(() => {
62
+ sigkillTimer = undefined;
63
+ child.kill('SIGKILL');
64
+ }, 250);
65
+ sigkillTimer.unref?.();
66
+ cleanup(false);
67
+ reject(new Error(`timeout after ${effectiveTimeoutMs}ms`));
68
+ }, effectiveTimeoutMs);
69
+
70
+ child.stdout.on('data', onStdout);
71
+ child.stderr.on('data', onStderr);
72
+ child.on('error', onError);
73
+ child.on('close', onClose);
50
74
  });
51
75
  }
@@ -822,6 +822,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
822
822
  prompt: request.trigger_message,
823
823
  submitKeyPresses,
824
824
  typePrompt: shouldTypePrompt,
825
+ queueFirstSubmit: leaderTargeted,
825
826
  });
826
827
  if (!sendResult.ok) {
827
828
  return {
@@ -876,11 +877,13 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
876
877
  tmux_injection_attempted: true,
877
878
  };
878
879
  }
879
- // Do not declare success while a *worker* pane is still bootstrapping / not
880
- // input-ready. Otherwise a pre-ready send can be marked "confirmed" and later
881
- // appear as a stuck unsent draft once the UI finishes loading.
882
- // Keep leader-fixed behavior unchanged to avoid regressing leader notification flow.
883
- if (request.to_worker !== 'leader-fixed' && !paneLooksReady(wideCap.stdout)) {
880
+ // Do not declare success while a pane is not input-ready. Otherwise a
881
+ // pre-ready send can be marked "confirmed" and later appear as a stuck
882
+ // unsent draft once the UI finishes loading. This includes leader-fixed:
883
+ // its Codex UI can show "tab to queue message" while busy, and marking
884
+ // delivered before queue/consumption confirmation loses the orchestration
885
+ // nudge until a human presses Tab manually.
886
+ if (!paneLooksReady(wideCap.stdout)) {
884
887
  continue;
885
888
  }
886
889
  if (!triggerInNarrow && !triggerNearTail) {
@@ -904,6 +907,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
904
907
  prompt: request.trigger_message,
905
908
  submitKeyPresses,
906
909
  typePrompt: false,
910
+ queueFirstSubmit: leaderTargeted,
907
911
  }).catch(() => {});
908
912
  }
909
913
 
@@ -134,6 +134,7 @@ export async function sendPaneInput({
134
134
  submitKeyPresses = 2,
135
135
  submitDelayMs = 0,
136
136
  typePrompt = true,
137
+ queueFirstSubmit = false,
137
138
  }: any): Promise<any> {
138
139
  const target = safeString(paneTarget).trim();
139
140
  if (!target) {
@@ -163,6 +164,12 @@ export async function sendPaneInput({
163
164
  if (typePrompt) {
164
165
  await runProcess('tmux', argv.typeArgv, 3000);
165
166
  }
167
+ if (queueFirstSubmit && argv.submitArgv.length > 0) {
168
+ await runProcess('tmux', ['send-keys', '-t', target, 'Tab'], 3000);
169
+ if (submitDelayMs > 0) {
170
+ await new Promise((resolve) => setTimeout(resolve, submitDelayMs));
171
+ }
172
+ }
166
173
  for (const submit of argv.submitArgv) {
167
174
  if (submitDelayMs > 0) {
168
175
  await new Promise((resolve) => setTimeout(resolve, submitDelayMs));
@@ -5,6 +5,14 @@ import { join, resolve } from 'node:path';
5
5
  const DEFAULT_TEST_TIMEOUT_MS = 0;
6
6
  const DEFAULT_RUNNER_TIMEOUT_MS = 30 * 60 * 1_000;
7
7
  const DEFAULT_CI_TEST_CONCURRENCY = 1;
8
+ const RUNTIME_STATE_ENV_KEYS = [
9
+ 'OMX_ROOT',
10
+ 'OMX_STATE_ROOT',
11
+ 'OMX_TEAM_STATE_ROOT',
12
+ 'OMX_SESSION_ID',
13
+ 'CODEX_SESSION_ID',
14
+ 'SESSION_ID',
15
+ ] as const;
8
16
 
9
17
  function parseBooleanEnv(value: string | undefined): boolean {
10
18
  if (!value) return false;
@@ -91,6 +99,11 @@ console.error(
91
99
  const childEnv = { ...process.env };
92
100
  delete childEnv.NODE_TEST_CONTEXT;
93
101
  childEnv.OMX_TEST_RELAX_TMUX_TIMEOUT = '1';
102
+ if (!parseBooleanEnv(process.env.OMX_NODE_TEST_PRESERVE_RUNTIME_ENV)) {
103
+ for (const key of RUNTIME_STATE_ENV_KEYS) {
104
+ delete childEnv[key];
105
+ }
106
+ }
94
107
 
95
108
  const result = spawnSync(process.execPath, testArgs, {
96
109
  stdio: 'inherit',
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  mkdtempSync,
3
+ realpathSync,
3
4
  rmSync,
4
5
  } from 'node:fs';
5
6
  import { mkdirSync } from 'node:fs';
@@ -24,6 +25,16 @@ export const PACKED_INSTALL_SMOKE_CORE_COMMANDS = [
24
25
  ['sparkshell', '--help'],
25
26
  ] as const;
26
27
 
28
+ export const PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS = [
29
+ 'SessionStart',
30
+ 'PreToolUse',
31
+ 'PostToolUse',
32
+ 'UserPromptSubmit',
33
+ 'PreCompact',
34
+ 'PostCompact',
35
+ 'Stop',
36
+ ] as const;
37
+
27
38
  function usage(): string {
28
39
  return [
29
40
  'Usage: node scripts/smoke-packed-install.mjs',
@@ -112,6 +123,99 @@ function npmBinName(name: string): string {
112
123
  return process.platform === 'win32' ? `${name}.cmd` : name;
113
124
  }
114
125
 
126
+ function resolveGlobalNodeModules(prefixDir: string): string {
127
+ const result = run('npm', ['root', '-g', '--prefix', prefixDir], { cwd: prefixDir });
128
+ const root = String(result.stdout || '').trim();
129
+ if (!root) throw new Error('npm root -g did not return a node_modules directory');
130
+ return root;
131
+ }
132
+
133
+ export function validateHookStdout(eventName: string, stdout: string): void {
134
+ const trimmed = stdout.trim();
135
+ if (!trimmed) return;
136
+ try {
137
+ JSON.parse(trimmed);
138
+ } catch (error) {
139
+ throw new Error(
140
+ `native hook ${eventName} emitted invalid JSON stdout: ${error instanceof Error ? error.message : String(error)}`,
141
+ );
142
+ }
143
+ }
144
+
145
+ export function buildNativeHookSmokePayload(
146
+ eventName: typeof PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS[number],
147
+ smokeCwd: string,
148
+ ): Record<string, unknown> {
149
+ const base = {
150
+ hook_event_name: eventName,
151
+ session_id: `packed-install-smoke-${eventName}`,
152
+ cwd: smokeCwd,
153
+ };
154
+ switch (eventName) {
155
+ case 'SessionStart':
156
+ return {
157
+ ...base,
158
+ transcript_path: join(smokeCwd, 'nonexistent-transcript.jsonl'),
159
+ };
160
+ case 'PreToolUse':
161
+ return {
162
+ ...base,
163
+ tool_name: 'Bash',
164
+ tool_use_id: 'packed-install-smoke-tool',
165
+ tool_input: { command: 'echo packed install smoke' },
166
+ };
167
+ case 'PostToolUse':
168
+ return {
169
+ ...base,
170
+ tool_name: 'Bash',
171
+ tool_use_id: 'packed-install-smoke-tool',
172
+ tool_input: { command: 'echo packed install smoke' },
173
+ tool_response: {
174
+ exit_code: 0,
175
+ stdout: 'packed install smoke\n',
176
+ stderr: '',
177
+ },
178
+ };
179
+ case 'UserPromptSubmit':
180
+ return {
181
+ ...base,
182
+ transcript_path: join(smokeCwd, 'nonexistent-transcript.jsonl'),
183
+ prompt: 'packed install native hook smoke test',
184
+ };
185
+ case 'PreCompact':
186
+ case 'PostCompact':
187
+ case 'Stop':
188
+ return base;
189
+ }
190
+ }
191
+
192
+ function smokeInstalledNativeHookDist(prefixDir: string): void {
193
+ const globalNodeModules = resolveGlobalNodeModules(prefixDir);
194
+ const packageRoot = join(globalNodeModules, 'oh-my-codex');
195
+ const hookScript = join(packageRoot, 'dist', 'scripts', 'codex-native-hook.js');
196
+ const smokeCwd = mkdtempSync(join(tmpdir(), 'omx-packed-hook-smoke-'));
197
+ try {
198
+ for (const eventName of PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS) {
199
+ const payload = buildNativeHookSmokePayload(eventName, smokeCwd);
200
+ const result = run(process.execPath, [realpathSync(hookScript)], {
201
+ cwd: smokeCwd,
202
+ env: {
203
+ ...process.env,
204
+ OMX_NATIVE_HOOK_DOCTOR_SMOKE: '1',
205
+ OMX_ROOT: join(smokeCwd, '.omx-packed-hook-root'),
206
+ OMX_SESSION_ID: `packed-install-smoke-${eventName}`,
207
+ OMX_SOURCE_CWD: smokeCwd,
208
+ OMX_STARTUP_CWD: smokeCwd,
209
+ },
210
+ input: JSON.stringify(payload),
211
+ });
212
+ validateHookStdout(eventName, result.stdout as string);
213
+ }
214
+ } finally {
215
+ rmSync(smokeCwd, { recursive: true, force: true });
216
+ }
217
+ }
218
+
115
219
  export function parseNpmPackJsonOutput(stdout: string): Array<{ filename: string }> {
116
220
  const start = stdout.lastIndexOf('\n[');
117
221
  const jsonText = (start >= 0 ? stdout.slice(start + 1) : stdout).trim();
@@ -147,6 +251,7 @@ async function main(): Promise<void> {
147
251
  for (const argv of PACKED_INSTALL_SMOKE_CORE_COMMANDS) {
148
252
  run(omxPath, argv, { cwd: repoRoot });
149
253
  }
254
+ smokeInstalledNativeHookDist(prefixDir);
150
255
 
151
256
  console.log('packed install smoke: PASS');
152
257
  } finally {
@@ -55,7 +55,6 @@ const PLUGIN_NAME = "oh-my-codex";
55
55
  const SETUP_OWNED_PLUGIN_MANIFEST_FIELDS = [
56
56
  "agents",
57
57
  "prompts",
58
- "hooks",
59
58
  ] as const;
60
59
 
61
60
  async function readJsonFile<T>(path: string): Promise<T> {
@@ -199,13 +198,14 @@ async function assertPluginManifestPolicy(
199
198
  const pkg = await readJsonFile<PackageJson>(join(root, "package.json"));
200
199
  const expectedFields: Pick<
201
200
  PluginManifest,
202
- "name" | "version" | "skills" | "mcpServers" | "apps"
201
+ "name" | "version" | "skills" | "mcpServers" | "apps" | "hooks"
203
202
  > = {
204
203
  name: PLUGIN_NAME,
205
204
  version: pkg.version,
206
205
  skills: "./skills/",
207
206
  mcpServers: "./.mcp.json",
208
207
  apps: "./.app.json",
208
+ hooks: "./hooks/hooks.json",
209
209
  };
210
210
 
211
211
  for (const [field, expectedValue] of Object.entries(expectedFields)) {
@@ -229,7 +229,7 @@ async function assertPluginManifestPolicy(
229
229
  "plugin_bundle_metadata_out_of_sync",
230
230
  "kind=plugin-manifest",
231
231
  `field=${field}`,
232
- "message=setup-owned agents/prompts/hooks must not be plugin-scoped",
232
+ "message=setup-owned agents/prompts must not be plugin-scoped",
233
233
  ].join("\n"),
234
234
  );
235
235
  }
@@ -199,11 +199,11 @@ export async function verifyNativeAgents(
199
199
  ? await readPluginManifest(root)
200
200
  : options.pluginManifest;
201
201
  if (pluginManifest) {
202
- for (const field of ["agents", "prompts", "hooks"]) {
202
+ for (const field of ["agents", "prompts"]) {
203
203
  if (pluginManifest[field] !== undefined) {
204
204
  throw errorBlock("native_agent_plugin_boundary_violation", {
205
205
  field,
206
- message: "native agents/prompts/hooks are setup-owned, not plugin-scoped",
206
+ message: "native agents/prompts are setup-owned, not plugin-scoped",
207
207
  });
208
208
  }
209
209
  }
@@ -108,6 +108,13 @@
108
108
  "core": false,
109
109
  "internalRequired": false
110
110
  },
111
+ {
112
+ "name": "prometheus-strict",
113
+ "category": "planning",
114
+ "status": "active",
115
+ "core": false,
116
+ "internalRequired": false
117
+ },
111
118
  {
112
119
  "name": "best-practice-research",
113
120
  "category": "planning",
@@ -499,6 +506,21 @@
499
506
  "status": "merged",
500
507
  "canonical": "analyst"
501
508
  },
509
+ {
510
+ "name": "prometheus-strict-metis",
511
+ "category": "coordination",
512
+ "status": "active"
513
+ },
514
+ {
515
+ "name": "prometheus-strict-momus",
516
+ "category": "coordination",
517
+ "status": "active"
518
+ },
519
+ {
520
+ "name": "prometheus-strict-oracle",
521
+ "category": "coordination",
522
+ "status": "active"
523
+ },
502
524
  {
503
525
  "name": "critic",
504
526
  "category": "coordination",