oh-my-codex 0.16.3 → 0.17.0

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 (339) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -3
  4. package/dist/catalog/__tests__/generator.test.js +2 -0
  5. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  6. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
  7. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  8. package/dist/cli/__tests__/cleanup.test.js +27 -0
  9. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  10. package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
  11. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  12. package/dist/cli/__tests__/doctor-warning-copy.test.js +175 -7
  13. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  14. package/dist/cli/__tests__/index.test.js +147 -12
  15. package/dist/cli/__tests__/index.test.js.map +1 -1
  16. package/dist/cli/__tests__/mcp-serve.test.js +4 -0
  17. package/dist/cli/__tests__/mcp-serve.test.js.map +1 -1
  18. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
  19. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  20. package/dist/cli/__tests__/ralph.test.js +47 -0
  21. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  22. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +10 -5
  23. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  24. package/dist/cli/__tests__/setup-install-mode.test.js +299 -27
  25. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  26. package/dist/cli/__tests__/setup-refresh.test.js +85 -3
  27. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  28. package/dist/cli/__tests__/setup-scope.test.js +1 -1
  29. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  30. package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
  31. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  32. package/dist/cli/__tests__/team.test.js +108 -0
  33. package/dist/cli/__tests__/team.test.js.map +1 -1
  34. package/dist/cli/__tests__/ultragoal.test.js +91 -0
  35. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  36. package/dist/cli/__tests__/uninstall.test.js +54 -8
  37. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  38. package/dist/cli/cleanup.d.ts.map +1 -1
  39. package/dist/cli/cleanup.js +8 -4
  40. package/dist/cli/cleanup.js.map +1 -1
  41. package/dist/cli/codex-feature-probe.d.ts +9 -0
  42. package/dist/cli/codex-feature-probe.d.ts.map +1 -0
  43. package/dist/cli/codex-feature-probe.js +28 -0
  44. package/dist/cli/codex-feature-probe.js.map +1 -0
  45. package/dist/cli/doctor.d.ts +1 -0
  46. package/dist/cli/doctor.d.ts.map +1 -1
  47. package/dist/cli/doctor.js +214 -23
  48. package/dist/cli/doctor.js.map +1 -1
  49. package/dist/cli/index.d.ts +17 -4
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +152 -24
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/mcp-parity.js +8 -8
  54. package/dist/cli/mcp-parity.js.map +1 -1
  55. package/dist/cli/mcp-serve.d.ts.map +1 -1
  56. package/dist/cli/mcp-serve.js +4 -0
  57. package/dist/cli/mcp-serve.js.map +1 -1
  58. package/dist/cli/plugin-marketplace.d.ts +23 -0
  59. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  60. package/dist/cli/plugin-marketplace.js +203 -1
  61. package/dist/cli/plugin-marketplace.js.map +1 -1
  62. package/dist/cli/ralph.d.ts.map +1 -1
  63. package/dist/cli/ralph.js +21 -0
  64. package/dist/cli/ralph.js.map +1 -1
  65. package/dist/cli/setup-preferences.d.ts +4 -0
  66. package/dist/cli/setup-preferences.d.ts.map +1 -1
  67. package/dist/cli/setup-preferences.js +7 -0
  68. package/dist/cli/setup-preferences.js.map +1 -1
  69. package/dist/cli/setup.d.ts +5 -3
  70. package/dist/cli/setup.d.ts.map +1 -1
  71. package/dist/cli/setup.js +140 -51
  72. package/dist/cli/setup.js.map +1 -1
  73. package/dist/cli/ultragoal.d.ts +1 -1
  74. package/dist/cli/ultragoal.d.ts.map +1 -1
  75. package/dist/cli/ultragoal.js +70 -5
  76. package/dist/cli/ultragoal.js.map +1 -1
  77. package/dist/cli/uninstall.d.ts +2 -0
  78. package/dist/cli/uninstall.d.ts.map +1 -1
  79. package/dist/cli/uninstall.js +12 -3
  80. package/dist/cli/uninstall.js.map +1 -1
  81. package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
  82. package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
  83. package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
  84. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
  85. package/dist/config/__tests__/codex-hooks.test.js +143 -9
  86. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  87. package/dist/config/__tests__/generator-idempotent.test.js +85 -9
  88. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  89. package/dist/config/__tests__/generator-notify.test.js +116 -11
  90. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  91. package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
  92. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  93. package/dist/config/codex-feature-flags.d.ts +21 -0
  94. package/dist/config/codex-feature-flags.d.ts.map +1 -0
  95. package/dist/config/codex-feature-flags.js +56 -0
  96. package/dist/config/codex-feature-flags.js.map +1 -0
  97. package/dist/config/codex-hooks.d.ts +14 -13
  98. package/dist/config/codex-hooks.d.ts.map +1 -1
  99. package/dist/config/codex-hooks.js +108 -8
  100. package/dist/config/codex-hooks.js.map +1 -1
  101. package/dist/config/generator.d.ts +15 -3
  102. package/dist/config/generator.d.ts.map +1 -1
  103. package/dist/config/generator.js +233 -129
  104. package/dist/config/generator.js.map +1 -1
  105. package/dist/config/omx-first-party-mcp.d.ts +3 -1
  106. package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
  107. package/dist/config/omx-first-party-mcp.js +9 -2
  108. package/dist/config/omx-first-party-mcp.js.map +1 -1
  109. package/dist/hooks/__tests__/design-skill.test.d.ts +2 -0
  110. package/dist/hooks/__tests__/design-skill.test.d.ts.map +1 -0
  111. package/dist/hooks/__tests__/design-skill.test.js +55 -0
  112. package/dist/hooks/__tests__/design-skill.test.js.map +1 -0
  113. package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
  114. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
  116. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  117. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +265 -0
  118. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  119. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
  120. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
  121. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
  122. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
  123. package/dist/hooks/__tests__/skill-guidance-contract.test.js +41 -0
  124. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
  125. package/dist/hooks/agents-overlay.js +2 -2
  126. package/dist/hooks/agents-overlay.js.map +1 -1
  127. package/dist/hooks/keyword-detector.d.ts +1 -0
  128. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  129. package/dist/hooks/keyword-detector.js +12 -6
  130. package/dist/hooks/keyword-detector.js.map +1 -1
  131. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  132. package/dist/hooks/keyword-registry.js +2 -0
  133. package/dist/hooks/keyword-registry.js.map +1 -1
  134. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  135. package/dist/hooks/prompt-guidance-contract.js +47 -2
  136. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  137. package/dist/hud/__tests__/state.test.js +164 -0
  138. package/dist/hud/__tests__/state.test.js.map +1 -1
  139. package/dist/hud/state.d.ts.map +1 -1
  140. package/dist/hud/state.js +4 -5
  141. package/dist/hud/state.js.map +1 -1
  142. package/dist/mcp/__tests__/bootstrap.test.js +3 -0
  143. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  144. package/dist/mcp/__tests__/hermes-bridge.test.d.ts +2 -0
  145. package/dist/mcp/__tests__/hermes-bridge.test.d.ts.map +1 -0
  146. package/dist/mcp/__tests__/hermes-bridge.test.js +374 -0
  147. package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -0
  148. package/dist/mcp/__tests__/state-paths.test.js +155 -11
  149. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  150. package/dist/mcp/__tests__/state-server.test.js +166 -0
  151. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  152. package/dist/mcp/bootstrap.d.ts +1 -1
  153. package/dist/mcp/bootstrap.d.ts.map +1 -1
  154. package/dist/mcp/bootstrap.js +2 -0
  155. package/dist/mcp/bootstrap.js.map +1 -1
  156. package/dist/mcp/hermes-bridge.d.ts +81 -0
  157. package/dist/mcp/hermes-bridge.d.ts.map +1 -0
  158. package/dist/mcp/hermes-bridge.js +400 -0
  159. package/dist/mcp/hermes-bridge.js.map +1 -0
  160. package/dist/mcp/hermes-server.d.ts +269 -0
  161. package/dist/mcp/hermes-server.d.ts.map +1 -0
  162. package/dist/mcp/hermes-server.js +121 -0
  163. package/dist/mcp/hermes-server.js.map +1 -0
  164. package/dist/mcp/state-paths.d.ts.map +1 -1
  165. package/dist/mcp/state-paths.js +64 -11
  166. package/dist/mcp/state-paths.js.map +1 -1
  167. package/dist/modes/__tests__/base-session-scope.test.js +22 -0
  168. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  169. package/dist/modes/__tests__/base-tmux-pane.test.js +88 -27
  170. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  171. package/dist/modes/base.d.ts.map +1 -1
  172. package/dist/modes/base.js +5 -0
  173. package/dist/modes/base.js.map +1 -1
  174. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
  175. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
  176. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
  177. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
  178. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
  179. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
  180. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
  181. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
  182. package/dist/planning/__tests__/artifacts.test.js +533 -4
  183. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  184. package/dist/planning/__tests__/context-pack-status.test.js +524 -0
  185. package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
  186. package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
  187. package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
  188. package/dist/planning/__tests__/markdown-structure.test.js +459 -0
  189. package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
  190. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
  191. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
  192. package/dist/planning/artifacts.d.ts +1 -1
  193. package/dist/planning/artifacts.d.ts.map +1 -1
  194. package/dist/planning/artifacts.js +227 -28
  195. package/dist/planning/artifacts.js.map +1 -1
  196. package/dist/planning/context-pack-status.d.ts +25 -0
  197. package/dist/planning/context-pack-status.d.ts.map +1 -1
  198. package/dist/planning/context-pack-status.js +272 -31
  199. package/dist/planning/context-pack-status.js.map +1 -1
  200. package/dist/planning/markdown-structure.d.ts +20 -0
  201. package/dist/planning/markdown-structure.d.ts.map +1 -0
  202. package/dist/planning/markdown-structure.js +137 -0
  203. package/dist/planning/markdown-structure.js.map +1 -0
  204. package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
  205. package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
  206. package/dist/ralph/__tests__/completion-audit.test.js +121 -0
  207. package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
  208. package/dist/ralph/completion-audit.d.ts +8 -0
  209. package/dist/ralph/completion-audit.d.ts.map +1 -0
  210. package/dist/ralph/completion-audit.js +99 -0
  211. package/dist/ralph/completion-audit.js.map +1 -0
  212. package/dist/scripts/__tests__/codex-native-hook.test.js +407 -15
  213. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  214. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
  215. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
  216. package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
  217. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
  218. package/dist/scripts/codex-native-hook.d.ts +1 -0
  219. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  220. package/dist/scripts/codex-native-hook.js +177 -71
  221. package/dist/scripts/codex-native-hook.js.map +1 -1
  222. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  223. package/dist/scripts/codex-native-pre-post.js +4 -2
  224. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  225. package/dist/scripts/notify-dispatcher.js +30 -1
  226. package/dist/scripts/notify-dispatcher.js.map +1 -1
  227. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  228. package/dist/scripts/notify-hook/tmux-injection.js +91 -2
  229. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  230. package/dist/scripts/notify-hook.js +3 -1
  231. package/dist/scripts/notify-hook.js.map +1 -1
  232. package/dist/state/__tests__/workflow-transition.test.js +102 -27
  233. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  234. package/dist/state/mode-state-context.d.ts +2 -0
  235. package/dist/state/mode-state-context.d.ts.map +1 -1
  236. package/dist/state/mode-state-context.js +21 -0
  237. package/dist/state/mode-state-context.js.map +1 -1
  238. package/dist/state/operations.d.ts.map +1 -1
  239. package/dist/state/operations.js +9 -3
  240. package/dist/state/operations.js.map +1 -1
  241. package/dist/state/skill-active.d.ts +7 -0
  242. package/dist/state/skill-active.d.ts.map +1 -1
  243. package/dist/state/skill-active.js +25 -8
  244. package/dist/state/skill-active.js.map +1 -1
  245. package/dist/state/workflow-transition-reconcile.d.ts +1 -0
  246. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  247. package/dist/state/workflow-transition-reconcile.js +22 -15
  248. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  249. package/dist/state/workflow-transition.js +3 -3
  250. package/dist/state/workflow-transition.js.map +1 -1
  251. package/dist/team/__tests__/approved-execution.test.js +39 -0
  252. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  253. package/dist/team/__tests__/runtime.test.js +5 -0
  254. package/dist/team/__tests__/runtime.test.js.map +1 -1
  255. package/dist/team/__tests__/scaling.test.js +497 -2
  256. package/dist/team/__tests__/scaling.test.js.map +1 -1
  257. package/dist/team/__tests__/state-root.test.js +1 -1
  258. package/dist/team/__tests__/state-root.test.js.map +1 -1
  259. package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
  260. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  261. package/dist/team/approved-execution.d.ts.map +1 -1
  262. package/dist/team/approved-execution.js +3 -0
  263. package/dist/team/approved-execution.js.map +1 -1
  264. package/dist/team/scaling.d.ts.map +1 -1
  265. package/dist/team/scaling.js +43 -0
  266. package/dist/team/scaling.js.map +1 -1
  267. package/dist/team/state-root.d.ts.map +1 -1
  268. package/dist/team/state-root.js +4 -0
  269. package/dist/team/state-root.js.map +1 -1
  270. package/dist/team/state.d.ts.map +1 -1
  271. package/dist/team/state.js +2 -6
  272. package/dist/team/state.js.map +1 -1
  273. package/dist/ultragoal/__tests__/artifacts.test.js +245 -1
  274. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  275. package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
  276. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  277. package/dist/ultragoal/artifacts.d.ts +52 -2
  278. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  279. package/dist/ultragoal/artifacts.js +301 -15
  280. package/dist/ultragoal/artifacts.js.map +1 -1
  281. package/dist/utils/__tests__/paths.test.js +31 -1
  282. package/dist/utils/__tests__/paths.test.js.map +1 -1
  283. package/dist/utils/paths.d.ts +6 -0
  284. package/dist/utils/paths.d.ts.map +1 -1
  285. package/dist/utils/paths.js +18 -0
  286. package/dist/utils/paths.js.map +1 -1
  287. package/dist/wiki/lifecycle.js +4 -4
  288. package/dist/wiki/lifecycle.js.map +1 -1
  289. package/package.json +1 -1
  290. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  291. package/plugins/oh-my-codex/.mcp.json +13 -5
  292. package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
  293. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
  294. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
  295. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
  296. package/plugins/oh-my-codex/skills/design/SKILL.md +180 -0
  297. package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
  298. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
  299. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
  300. package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
  301. package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
  302. package/plugins/oh-my-codex/skills/skill/SKILL.md +2 -1
  303. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
  304. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +175 -64
  305. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
  306. package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +2 -2
  307. package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
  308. package/skills/analyze/SKILL.md +0 -2
  309. package/skills/ask-claude/SKILL.md +5 -3
  310. package/skills/ask-gemini/SKILL.md +5 -3
  311. package/skills/autopilot/SKILL.md +2 -2
  312. package/skills/code-review/SKILL.md +1 -3
  313. package/skills/deep-interview/SKILL.md +5 -7
  314. package/skills/design/SKILL.md +180 -0
  315. package/skills/doctor/SKILL.md +2 -2
  316. package/skills/ecomode/SKILL.md +105 -1
  317. package/skills/frontend-ui-ux/SKILL.md +6 -24
  318. package/skills/git-master/SKILL.md +2 -4
  319. package/skills/omx-setup/SKILL.md +3 -3
  320. package/skills/pipeline/SKILL.md +3 -3
  321. package/skills/plan/SKILL.md +3 -6
  322. package/skills/ralph/SKILL.md +9 -10
  323. package/skills/skill/SKILL.md +2 -1
  324. package/skills/swarm/SKILL.md +5 -3
  325. package/skills/tdd/SKILL.md +95 -1
  326. package/skills/ultragoal/SKILL.md +36 -3
  327. package/skills/ultraqa/SKILL.md +175 -64
  328. package/skills/ultrawork/SKILL.md +8 -8
  329. package/skills/visual-ralph/SKILL.md +2 -2
  330. package/skills/web-clone/SKILL.md +348 -1
  331. package/skills/wiki/SKILL.md +13 -13
  332. package/src/scripts/__tests__/codex-native-hook.test.ts +437 -14
  333. package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
  334. package/src/scripts/codex-native-hook.ts +205 -61
  335. package/src/scripts/codex-native-pre-post.ts +4 -1
  336. package/src/scripts/notify-dispatcher.ts +40 -1
  337. package/src/scripts/notify-hook/tmux-injection.ts +110 -3
  338. package/src/scripts/notify-hook.ts +3 -1
  339. package/templates/catalog-manifest.json +9 -2
@@ -11,15 +11,19 @@
11
11
  */
12
12
  import { readFile, writeFile } from "fs/promises";
13
13
  import { existsSync } from "fs";
14
- import { isAbsolute, join, resolve } from "path";
14
+ import { join, resolve } from "path";
15
15
  import TOML from "@iarna/toml";
16
16
  import { AGENT_DEFINITIONS } from "../agents/definitions.js";
17
17
  import { DEFAULT_FRONTIER_MODEL } from "./models.js";
18
- import { getOmxFirstPartySetupMcpServers } from "./omx-first-party-mcp.js";
19
- import { buildManagedCodexHookTrustToml } from "./codex-hooks.js";
18
+ import { DEFAULT_CODEX_HOOK_FEATURE_FLAG, CODEX_HOOK_FEATURE_FLAGS, formatCodexHookFeatureFlagLine, normalizeCodexHookFeatureFlag, } from "./codex-feature-flags.js";
19
+ import { OMX_FIRST_PARTY_MCP_SERVER_NAMES, getOmxFirstPartySetupMcpServers, } from "./omx-first-party-mcp.js";
20
+ import { buildManagedCodexHookTrustToml, } from "./codex-hooks.js";
20
21
  function escapeTomlString(value) {
21
22
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
22
23
  }
24
+ function isRecord(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
23
27
  // ---------------------------------------------------------------------------
24
28
  // Top-level OMX keys (must live before any [table] header)
25
29
  // ---------------------------------------------------------------------------
@@ -206,23 +210,37 @@ export function getRootTomlArray(config, key) {
206
210
  return null;
207
211
  }
208
212
  }
213
+ function resolveNotifyEntrypoint(command) {
214
+ if (!/(?:^|[\\/])node(?:\.exe)?$/i.test(command[0] ?? "")) {
215
+ return command[0];
216
+ }
217
+ return command.slice(1).find((arg) => !arg.startsWith("-"));
218
+ }
209
219
  export function isOmxManagedNotifyCommand(command, pkgRoot) {
210
220
  if (!command)
211
221
  return false;
222
+ const entrypoint = resolveNotifyEntrypoint(command);
223
+ if (!entrypoint)
224
+ return false;
225
+ if (!/(?:^|[\\/])notify-(?:hook|dispatcher)\.js$/.test(entrypoint)) {
226
+ return false;
227
+ }
212
228
  const managedScripts = pkgRoot
213
229
  ? new Set([
214
230
  resolve(pkgRoot, "dist", "scripts", "notify-hook.js"),
215
231
  resolve(pkgRoot, "dist", "scripts", "notify-dispatcher.js"),
216
232
  ])
217
233
  : new Set();
218
- return command.some((part) => {
219
- if (!/(?:^|[\\/])notify-(?:hook|dispatcher)\.js$/.test(part))
220
- return false;
221
- if (pkgRoot) {
222
- return isAbsolute(part) && managedScripts.has(resolve(part));
223
- }
224
- return /(?:^|[\\/])oh-my-codex(?:[\\/]|$)/.test(part);
225
- });
234
+ if (pkgRoot && managedScripts.has(resolve(entrypoint)))
235
+ return true;
236
+ return /(?:^|[\\/])oh-my-codex(?:[\\/]|$)/.test(entrypoint);
237
+ }
238
+ export function sanitizePreviousNotifyCommand(command, pkgRoot) {
239
+ if (!command || command.length === 0)
240
+ return null;
241
+ if (isOmxManagedNotifyCommand(command, pkgRoot))
242
+ return null;
243
+ return [...command];
226
244
  }
227
245
  function getOmxTopLevelLines(pkgRoot, existingConfig = "", modelOverride, notifyCommand = getDefaultNotifyCommand(pkgRoot)) {
228
246
  const rootValues = parseRootKeyValues(existingConfig);
@@ -346,16 +364,56 @@ export function stripOmxTopLevelKeys(config) {
346
364
  // ---------------------------------------------------------------------------
347
365
  // [features] upsert
348
366
  // ---------------------------------------------------------------------------
349
- function upsertFeatureFlags(config) {
367
+ function isFeatureFlagLine(line, featureFlag) {
368
+ return new RegExp(`^\\s*${featureFlag}\\s*=`).test(line);
369
+ }
370
+ function isAnyCodexHookFeatureFlagLine(line) {
371
+ return CODEX_HOOK_FEATURE_FLAGS.some((flag) => isFeatureFlagLine(line, flag));
372
+ }
373
+ function upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag) {
374
+ const featureFlag = normalizeCodexHookFeatureFlag(codexHookFeatureFlag);
375
+ let featureFlagIdx = -1;
376
+ let fallbackAliasIdx = -1;
377
+ for (let i = featuresStart + 1; i < sectionEnd; i++) {
378
+ if (isFeatureFlagLine(lines[i], featureFlag)) {
379
+ featureFlagIdx = i;
380
+ }
381
+ else if (isAnyCodexHookFeatureFlagLine(lines[i]) && fallbackAliasIdx < 0) {
382
+ fallbackAliasIdx = i;
383
+ }
384
+ }
385
+ if (featureFlagIdx < 0 && fallbackAliasIdx >= 0) {
386
+ featureFlagIdx = fallbackAliasIdx;
387
+ }
388
+ if (featureFlagIdx >= 0) {
389
+ lines[featureFlagIdx] = formatCodexHookFeatureFlagLine(featureFlag);
390
+ }
391
+ else {
392
+ lines.splice(sectionEnd, 0, formatCodexHookFeatureFlagLine(featureFlag));
393
+ featureFlagIdx = sectionEnd;
394
+ sectionEnd += 1;
395
+ }
396
+ for (let i = sectionEnd - 1; i > featuresStart; i--) {
397
+ if (i !== featureFlagIdx && isAnyCodexHookFeatureFlagLine(lines[i])) {
398
+ lines.splice(i, 1);
399
+ sectionEnd -= 1;
400
+ if (featureFlagIdx > i)
401
+ featureFlagIdx -= 1;
402
+ }
403
+ }
404
+ return { sectionEnd, featureFlagIndex: featureFlagIdx };
405
+ }
406
+ function upsertFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
350
407
  const lines = config.split(/\r?\n/);
351
408
  const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
409
+ const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
352
410
  if (featuresStart < 0) {
353
411
  const base = config.trimEnd();
354
412
  const featureBlock = [
355
413
  "[features]",
356
414
  "multi_agent = true",
357
415
  "child_agents_md = true",
358
- "codex_hooks = true",
416
+ hookFeatureFlagLine,
359
417
  "goals = true",
360
418
  "",
361
419
  ].join("\n");
@@ -381,9 +439,6 @@ function upsertFeatureFlags(config) {
381
439
  }
382
440
  let multiAgentIdx = -1;
383
441
  let childAgentsIdx = -1;
384
- let codexHooksIdx = -1;
385
- let unsupportedHooksIdx = -1;
386
- let goalsIdx = -1;
387
442
  for (let i = featuresStart + 1; i < sectionEnd; i++) {
388
443
  if (/^\s*multi_agent\s*=/.test(lines[i])) {
389
444
  multiAgentIdx = i;
@@ -391,15 +446,6 @@ function upsertFeatureFlags(config) {
391
446
  else if (/^\s*child_agents_md\s*=/.test(lines[i])) {
392
447
  childAgentsIdx = i;
393
448
  }
394
- else if (/^\s*hooks\s*=/.test(lines[i])) {
395
- unsupportedHooksIdx = i;
396
- }
397
- else if (/^\s*codex_hooks\s*=/.test(lines[i])) {
398
- codexHooksIdx = i;
399
- }
400
- else if (/^\s*goals\s*=/.test(lines[i])) {
401
- goalsIdx = i;
402
- }
403
449
  }
404
450
  if (multiAgentIdx >= 0) {
405
451
  lines[multiAgentIdx] = "multi_agent = true";
@@ -415,27 +461,11 @@ function upsertFeatureFlags(config) {
415
461
  lines.splice(sectionEnd, 0, "child_agents_md = true");
416
462
  sectionEnd += 1;
417
463
  }
418
- if (codexHooksIdx >= 0) {
419
- lines[codexHooksIdx] = "codex_hooks = true";
420
- }
421
- else if (unsupportedHooksIdx >= 0) {
422
- lines[unsupportedHooksIdx] = "codex_hooks = true";
423
- codexHooksIdx = unsupportedHooksIdx;
424
- unsupportedHooksIdx = -1;
425
- }
426
- else {
427
- lines.splice(sectionEnd, 0, "codex_hooks = true");
428
- codexHooksIdx = sectionEnd;
429
- sectionEnd += 1;
430
- }
431
- for (let i = sectionEnd - 1; i > featuresStart; i--) {
432
- if (i !== codexHooksIdx && /^\s*hooks\s*=/.test(lines[i])) {
433
- lines.splice(i, 1);
434
- sectionEnd -= 1;
435
- if (codexHooksIdx > i)
436
- codexHooksIdx -= 1;
437
- if (goalsIdx > i)
438
- goalsIdx -= 1;
464
+ ({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
465
+ let goalsIdx = -1;
466
+ for (let i = featuresStart + 1; i < sectionEnd; i++) {
467
+ if (/^\s*goals\s*=/.test(lines[i])) {
468
+ goalsIdx = i;
439
469
  }
440
470
  }
441
471
  if (goalsIdx >= 0) {
@@ -469,29 +499,59 @@ export function stripManagedCodexHookTrustState(config) {
469
499
  }
470
500
  return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
471
501
  }
472
- export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile) {
473
- const stripped = stripManagedCodexHookTrustState(config);
474
- const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
502
+ function managedCodexHookTrustStateHeaders(hookTrustToml) {
503
+ const headers = new Set();
504
+ for (const line of hookTrustToml.split(/\r?\n/)) {
505
+ const trimmed = line.trim();
506
+ if (/^\[hooks\.state\./.test(trimmed)) {
507
+ headers.add(trimmed);
508
+ }
509
+ }
510
+ return headers;
511
+ }
512
+ function stripUnfencedManagedCodexHookTrustState(config, hookTrustToml) {
513
+ const managedHeaders = managedCodexHookTrustStateHeaders(hookTrustToml);
514
+ if (managedHeaders.size === 0)
515
+ return config;
516
+ const lines = config.split(/\r?\n/);
517
+ const kept = [];
518
+ for (let i = 0; i < lines.length;) {
519
+ if (!managedHeaders.has(lines[i].trim())) {
520
+ kept.push(lines[i]);
521
+ i += 1;
522
+ continue;
523
+ }
524
+ i += 1;
525
+ while (i < lines.length && !TOML_TABLE_HEADER_PATTERN.test(lines[i])) {
526
+ i += 1;
527
+ }
528
+ }
529
+ return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
530
+ }
531
+ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile, options = {}) {
532
+ const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot, options);
533
+ const stripped = stripUnfencedManagedCodexHookTrustState(stripManagedCodexHookTrustState(config), hookTrustToml);
475
534
  if (!hookTrustToml)
476
535
  return `${stripped}\n`;
477
536
  return [
478
537
  stripped,
479
538
  "",
480
539
  OMX_HOOK_TRUST_START_MARKER,
481
- "# Trusts only setup-managed codex-native-hook.js wrappers.",
540
+ "# Trusts only setup-managed native hook wrappers.",
482
541
  hookTrustToml,
483
542
  OMX_HOOK_TRUST_END_MARKER,
484
543
  "",
485
544
  ].filter((line, index) => index !== 0 || line.length > 0).join("\n");
486
545
  }
487
- export function upsertPluginModeRuntimeFeatureFlags(config) {
546
+ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
488
547
  const lines = config.split(/\r?\n/);
489
548
  const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
549
+ const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
490
550
  if (featuresStart < 0) {
491
551
  const base = config.trimEnd();
492
552
  const featureBlock = [
493
553
  "[features]",
494
- "codex_hooks = true",
554
+ hookFeatureFlagLine,
495
555
  "goals = true",
496
556
  "",
497
557
  ].join("\n");
@@ -515,43 +575,13 @@ export function upsertPluginModeRuntimeFeatureFlags(config) {
515
575
  sectionEnd -= 1;
516
576
  }
517
577
  }
518
- let codexHooksIdx = -1;
519
- let unsupportedHooksIdx = -1;
578
+ ({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
520
579
  let goalsIdx = -1;
521
580
  for (let i = featuresStart + 1; i < sectionEnd; i++) {
522
- if (/^\s*hooks\s*=/.test(lines[i])) {
523
- unsupportedHooksIdx = i;
524
- }
525
- else if (/^\s*codex_hooks\s*=/.test(lines[i])) {
526
- codexHooksIdx = i;
527
- }
528
- else if (/^\s*goals\s*=/.test(lines[i])) {
581
+ if (/^\s*goals\s*=/.test(lines[i])) {
529
582
  goalsIdx = i;
530
583
  }
531
584
  }
532
- if (codexHooksIdx >= 0) {
533
- lines[codexHooksIdx] = "codex_hooks = true";
534
- }
535
- else if (unsupportedHooksIdx >= 0) {
536
- lines[unsupportedHooksIdx] = "codex_hooks = true";
537
- codexHooksIdx = unsupportedHooksIdx;
538
- unsupportedHooksIdx = -1;
539
- }
540
- else {
541
- lines.splice(sectionEnd, 0, "codex_hooks = true");
542
- codexHooksIdx = sectionEnd;
543
- sectionEnd++;
544
- }
545
- for (let i = sectionEnd - 1; i > featuresStart; i--) {
546
- if (i !== codexHooksIdx && /^\s*hooks\s*=/.test(lines[i])) {
547
- lines.splice(i, 1);
548
- sectionEnd--;
549
- if (codexHooksIdx > i)
550
- codexHooksIdx--;
551
- if (goalsIdx > i)
552
- goalsIdx--;
553
- }
554
- }
555
585
  if (goalsIdx >= 0) {
556
586
  lines[goalsIdx] = "goals = true";
557
587
  }
@@ -767,12 +797,13 @@ export function stripOmxFeatureFlags(config) {
767
797
  * Preserve native Codex hook enablement without re-adding other OMX feature
768
798
  * flags. Used by uninstall when user-owned hooks remain in hooks.json.
769
799
  */
770
- export function upsertCodexHooksFeatureFlag(config) {
800
+ export function upsertCodexHooksFeatureFlag(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
771
801
  const lines = config.split(/\r?\n/);
772
802
  const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
803
+ const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
773
804
  if (featuresStart < 0) {
774
805
  const base = config.trimEnd();
775
- const featureBlock = ["[features]", "codex_hooks = true", ""].join("\n");
806
+ const featureBlock = ["[features]", hookFeatureFlagLine, ""].join("\n");
776
807
  return base.length === 0 ? featureBlock : `${base}\n${featureBlock}`;
777
808
  }
778
809
  let sectionEnd = lines.length;
@@ -782,31 +813,7 @@ export function upsertCodexHooksFeatureFlag(config) {
782
813
  break;
783
814
  }
784
815
  }
785
- let codexHooksIdx = -1;
786
- for (let i = featuresStart + 1; i < sectionEnd; i++) {
787
- if (/^\s*codex_hooks\s*=/.test(lines[i])) {
788
- codexHooksIdx = i;
789
- lines[i] = "codex_hooks = true";
790
- break;
791
- }
792
- if (codexHooksIdx < 0 && /^\s*hooks\s*=/.test(lines[i])) {
793
- codexHooksIdx = i;
794
- lines[i] = "codex_hooks = true";
795
- }
796
- }
797
- if (codexHooksIdx < 0) {
798
- lines.splice(sectionEnd, 0, "codex_hooks = true");
799
- codexHooksIdx = sectionEnd;
800
- sectionEnd += 1;
801
- }
802
- for (let i = sectionEnd - 1; i > featuresStart; i--) {
803
- if (i !== codexHooksIdx && /^\s*hooks\s*=/.test(lines[i])) {
804
- lines.splice(i, 1);
805
- sectionEnd -= 1;
806
- if (codexHooksIdx > i)
807
- codexHooksIdx -= 1;
808
- }
809
- }
816
+ upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag);
810
817
  return lines.join("\n");
811
818
  }
812
819
  export function stripOmxEnvSettings(config) {
@@ -822,6 +829,13 @@ export function stripOmxEnvSettings(config) {
822
829
  * Check whether a TOML table name belongs to a legacy OMX-managed agent entry.
823
830
  * Handles both `agents.name` and `agents."name"` forms.
824
831
  */
832
+ function isOmxFirstPartyMcpSection(tableName) {
833
+ const match = tableName.match(/^mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_-]+))$/);
834
+ const name = match?.[1] ?? match?.[2];
835
+ return Boolean(name &&
836
+ (OMX_FIRST_PARTY_MCP_SERVER_NAMES.includes(name) ||
837
+ name === "omx_team_run"));
838
+ }
825
839
  function isLegacyOmxAgentSection(tableName) {
826
840
  const m = tableName.match(/^agents\.(?:"([^"]+)"|(\w[\w-]*))$/);
827
841
  if (!m)
@@ -834,7 +848,8 @@ function isLegacyOmxAgentSection(tableName) {
834
848
  * This covers legacy configs that were written before markers were added,
835
849
  * or configs where the marker was accidentally removed.
836
850
  *
837
- * Targets: [mcp_servers.omx_*], legacy [agents.<name>] entries, [tui]
851
+ * Targets: exact first-party [mcp_servers.<name>] entries, retired
852
+ * [mcp_servers.omx_team_run], and legacy [agents.<name>] entries.
838
853
  */
839
854
  function stripOrphanedOmxSections(config) {
840
855
  const lines = config.split(/\r?\n/);
@@ -848,7 +863,7 @@ function stripOrphanedOmxSections(config) {
848
863
  // Note: [tui] is NOT stripped here because it could be user-owned.
849
864
  // The marker-based stripExistingOmxBlocks already handles [tui]
850
865
  // when it lives inside the OMX marker block.
851
- const isOmxSection = /^mcp_servers\.omx_/.test(tableName) ||
866
+ const isOmxSection = isOmxFirstPartyMcpSection(tableName) ||
852
867
  isLegacyOmxAgentSection(tableName);
853
868
  if (isOmxSection) {
854
869
  // Remove preceding OMX comment lines and blank lines
@@ -1088,6 +1103,72 @@ export function stripExistingSharedMcpRegistryBlock(config) {
1088
1103
  }
1089
1104
  return { cleaned, removed };
1090
1105
  }
1106
+ function getExistingSharedMcpRegistryBlocks(config) {
1107
+ const blocks = [];
1108
+ let cursor = 0;
1109
+ while (cursor < config.length) {
1110
+ const markerIdx = config.indexOf(SHARED_MCP_REGISTRY_MARKER, cursor);
1111
+ if (markerIdx < 0)
1112
+ break;
1113
+ let blockStart = config.lastIndexOf("\n", markerIdx);
1114
+ blockStart = blockStart >= 0 ? blockStart + 1 : 0;
1115
+ const previousLineEnd = blockStart - 1;
1116
+ if (previousLineEnd >= 0) {
1117
+ const previousLineStart = config.lastIndexOf("\n", previousLineEnd - 1);
1118
+ const previousLine = config.slice(previousLineStart + 1, previousLineEnd);
1119
+ if (/^# =+$/.test(previousLine.trim())) {
1120
+ blockStart = previousLineStart >= 0 ? previousLineStart + 1 : 0;
1121
+ }
1122
+ }
1123
+ let blockEnd = config.length;
1124
+ const endIdx = config.indexOf(SHARED_MCP_REGISTRY_END_MARKER, markerIdx);
1125
+ if (endIdx >= 0) {
1126
+ const endLineBreak = config.indexOf("\n", endIdx);
1127
+ blockEnd = endLineBreak >= 0 ? endLineBreak + 1 : config.length;
1128
+ }
1129
+ blocks.push(config.slice(blockStart, blockEnd));
1130
+ cursor = blockEnd;
1131
+ }
1132
+ return blocks;
1133
+ }
1134
+ export function extractSharedMcpRegistryServersFromConfig(config) {
1135
+ const servers = [];
1136
+ let sourcePath;
1137
+ for (const block of getExistingSharedMcpRegistryBlocks(config)) {
1138
+ sourcePath ??= block.match(/^# Source:\s*(.+?)\s*$/m)?.[1];
1139
+ let parsed;
1140
+ try {
1141
+ parsed = TOML.parse(block);
1142
+ }
1143
+ catch {
1144
+ continue;
1145
+ }
1146
+ if (!isRecord(parsed) || !isRecord(parsed.mcp_servers))
1147
+ continue;
1148
+ for (const [name, value] of Object.entries(parsed.mcp_servers)) {
1149
+ if (!isRecord(value) || typeof value.command !== "string")
1150
+ continue;
1151
+ const args = Array.isArray(value.args)
1152
+ ? value.args.filter((arg) => typeof arg === "string")
1153
+ : [];
1154
+ const enabled = typeof value.enabled === "boolean" ? value.enabled : true;
1155
+ const timeoutCandidate = typeof value.startup_timeout_sec === "number"
1156
+ ? value.startup_timeout_sec
1157
+ : value.startupTimeoutSec;
1158
+ const startupTimeoutSec = typeof timeoutCandidate === "number" && Number.isFinite(timeoutCandidate)
1159
+ ? timeoutCandidate
1160
+ : undefined;
1161
+ servers.push({
1162
+ name,
1163
+ command: value.command,
1164
+ args,
1165
+ enabled,
1166
+ ...(startupTimeoutSec !== undefined ? { startupTimeoutSec } : {}),
1167
+ });
1168
+ }
1169
+ }
1170
+ return { servers, sourcePath };
1171
+ }
1091
1172
  function toMcpServerTableKey(name) {
1092
1173
  if (/^[A-Za-z0-9_-]+$/.test(name)) {
1093
1174
  return `mcp_servers.${name}`;
@@ -1207,11 +1288,25 @@ function getSharedMcpRegistryBlock(servers, sourcePath, existingConfig) {
1207
1288
  lines.push(SHARED_MCP_REGISTRY_END_MARKER);
1208
1289
  return lines.join("\n");
1209
1290
  }
1291
+ export function mergeSharedMcpRegistryBlock(config, servers, sourcePath) {
1292
+ const stripped = stripExistingSharedMcpRegistryBlock(config);
1293
+ const existing = stripped.cleaned;
1294
+ const sharedRegistryBlock = getSharedMcpRegistryBlock(servers, sourcePath, existing);
1295
+ const body = existing.trimEnd();
1296
+ const merged = sharedRegistryBlock
1297
+ ? body
1298
+ ? `${body}\n\n${sharedRegistryBlock}\n`
1299
+ : `${sharedRegistryBlock}\n`
1300
+ : body
1301
+ ? `${body}\n`
1302
+ : "";
1303
+ return addDefaultLauncherMcpStartupTimeouts(merged);
1304
+ }
1210
1305
  /**
1211
1306
  * OMX table-section block (MCP servers, TUI).
1212
1307
  * Contains ONLY [table] sections — no bare keys.
1213
1308
  */
1214
- function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile) {
1309
+ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, hookOptions = {}, includeFirstPartyMcp = false) {
1215
1310
  const lines = [
1216
1311
  "",
1217
1312
  "# ============================================================",
@@ -1219,24 +1314,26 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
1219
1314
  "# Managed by omx setup - manual edits preserved on next setup",
1220
1315
  "# ============================================================",
1221
1316
  ];
1222
- for (const server of getOmxFirstPartySetupMcpServers(pkgRoot)) {
1223
- lines.push("");
1224
- lines.push(server.title);
1225
- lines.push(`[mcp_servers.${server.name}]`);
1226
- lines.push(`command = "${escapeTomlString(server.command)}"`);
1227
- lines.push(`args = [${server.args
1228
- .map((arg) => `"${escapeTomlString(arg)}"`)
1229
- .join(", ")}]`);
1230
- lines.push(`enabled = ${server.enabled ? "true" : "false"}`);
1231
- if (typeof server.startupTimeoutSec === "number") {
1232
- lines.push(`startup_timeout_sec = ${server.startupTimeoutSec}`);
1317
+ if (includeFirstPartyMcp) {
1318
+ for (const server of getOmxFirstPartySetupMcpServers(pkgRoot)) {
1319
+ lines.push("");
1320
+ lines.push(server.title);
1321
+ lines.push(`[mcp_servers.${server.name}]`);
1322
+ lines.push(`command = "${escapeTomlString(server.command)}"`);
1323
+ lines.push(`args = [${server.args
1324
+ .map((arg) => `"${escapeTomlString(arg)}"`)
1325
+ .join(", ")}]`);
1326
+ lines.push(`enabled = ${server.enabled ? "true" : "false"}`);
1327
+ if (typeof server.startupTimeoutSec === "number") {
1328
+ lines.push(`startup_timeout_sec = ${server.startupTimeoutSec}`);
1329
+ }
1233
1330
  }
1234
1331
  }
1235
- const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
1332
+ const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot, hookOptions);
1236
1333
  if (hookTrustToml) {
1237
1334
  lines.push("");
1238
1335
  lines.push("# OMX-owned Codex hook trust state");
1239
- lines.push("# Trusts only setup-managed codex-native-hook.js wrappers.");
1336
+ lines.push("# Trusts only setup-managed native hook wrappers.");
1240
1337
  lines.push(hookTrustToml);
1241
1338
  lines.push("# End OMX-owned Codex hook trust state");
1242
1339
  }
@@ -1295,11 +1392,15 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1295
1392
  }
1296
1393
  existing = stripOrphanedManagedNotify(existing, pkgRoot);
1297
1394
  existing = stripManagedCodexHookTrustState(existing);
1395
+ existing = stripUnfencedManagedCodexHookTrustState(existing, buildManagedCodexHookTrustToml(options.codexHooksFile, pkgRoot, {
1396
+ codexHomeDir: options.codexHomeDir,
1397
+ platform: options.hookCommandPlatform,
1398
+ }));
1298
1399
  if (options.modelOverride) {
1299
1400
  existing = stripRootLevelKeys(existing, ["model"]);
1300
1401
  }
1301
1402
  existing = stripOrphanedOmxSections(existing);
1302
- existing = upsertFeatureFlags(existing);
1403
+ existing = upsertFeatureFlags(existing, options.codexHookFeatureFlag);
1303
1404
  existing = upsertEnvSettings(existing);
1304
1405
  existing = upsertAgentsSettings(existing);
1305
1406
  const tuiUpsert = includeTui
@@ -1311,7 +1412,10 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1311
1412
  const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
1312
1413
  ? getDefaultNotifyCommand(pkgRoot)
1313
1414
  : options.notifyCommand);
1314
- const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile);
1415
+ const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, {
1416
+ codexHomeDir: options.codexHomeDir,
1417
+ platform: options.hookCommandPlatform,
1418
+ }, options.includeFirstPartyMcp === true);
1315
1419
  const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
1316
1420
  let body = existing.trimEnd();
1317
1421
  if (sharedRegistryBlock) {