oh-my-codex 0.16.3 → 0.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -3
  4. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
  5. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  6. package/dist/cli/__tests__/cleanup.test.js +27 -0
  7. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  8. package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
  9. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  10. package/dist/cli/__tests__/doctor-warning-copy.test.js +101 -6
  11. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  12. package/dist/cli/__tests__/index.test.js +131 -2
  13. package/dist/cli/__tests__/index.test.js.map +1 -1
  14. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
  15. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  16. package/dist/cli/__tests__/ralph.test.js +47 -0
  17. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  18. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +2 -2
  19. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  20. package/dist/cli/__tests__/setup-install-mode.test.js +272 -26
  21. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  22. package/dist/cli/__tests__/setup-refresh.test.js +85 -3
  23. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  24. package/dist/cli/__tests__/setup-scope.test.js +1 -1
  25. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  26. package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
  27. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  28. package/dist/cli/__tests__/team.test.js +108 -0
  29. package/dist/cli/__tests__/team.test.js.map +1 -1
  30. package/dist/cli/__tests__/ultragoal.test.js +69 -0
  31. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  32. package/dist/cli/__tests__/uninstall.test.js +54 -8
  33. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  34. package/dist/cli/cleanup.d.ts.map +1 -1
  35. package/dist/cli/cleanup.js +8 -4
  36. package/dist/cli/cleanup.js.map +1 -1
  37. package/dist/cli/codex-feature-probe.d.ts +9 -0
  38. package/dist/cli/codex-feature-probe.d.ts.map +1 -0
  39. package/dist/cli/codex-feature-probe.js +28 -0
  40. package/dist/cli/codex-feature-probe.js.map +1 -0
  41. package/dist/cli/doctor.d.ts +1 -0
  42. package/dist/cli/doctor.d.ts.map +1 -1
  43. package/dist/cli/doctor.js +152 -17
  44. package/dist/cli/doctor.js.map +1 -1
  45. package/dist/cli/index.d.ts +9 -2
  46. package/dist/cli/index.d.ts.map +1 -1
  47. package/dist/cli/index.js +135 -17
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/mcp-parity.js +8 -8
  50. package/dist/cli/mcp-parity.js.map +1 -1
  51. package/dist/cli/plugin-marketplace.d.ts +3 -0
  52. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  53. package/dist/cli/plugin-marketplace.js +88 -0
  54. package/dist/cli/plugin-marketplace.js.map +1 -1
  55. package/dist/cli/ralph.d.ts.map +1 -1
  56. package/dist/cli/ralph.js +21 -0
  57. package/dist/cli/ralph.js.map +1 -1
  58. package/dist/cli/setup-preferences.d.ts +4 -0
  59. package/dist/cli/setup-preferences.d.ts.map +1 -1
  60. package/dist/cli/setup-preferences.js +7 -0
  61. package/dist/cli/setup-preferences.js.map +1 -1
  62. package/dist/cli/setup.d.ts +5 -3
  63. package/dist/cli/setup.d.ts.map +1 -1
  64. package/dist/cli/setup.js +114 -44
  65. package/dist/cli/setup.js.map +1 -1
  66. package/dist/cli/ultragoal.d.ts +1 -1
  67. package/dist/cli/ultragoal.d.ts.map +1 -1
  68. package/dist/cli/ultragoal.js +64 -5
  69. package/dist/cli/ultragoal.js.map +1 -1
  70. package/dist/cli/uninstall.d.ts +2 -0
  71. package/dist/cli/uninstall.d.ts.map +1 -1
  72. package/dist/cli/uninstall.js +12 -3
  73. package/dist/cli/uninstall.js.map +1 -1
  74. package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
  75. package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
  76. package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
  77. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
  78. package/dist/config/__tests__/codex-hooks.test.js +7 -0
  79. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  80. package/dist/config/__tests__/generator-idempotent.test.js +70 -9
  81. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  82. package/dist/config/__tests__/generator-notify.test.js +116 -11
  83. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  84. package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
  85. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  86. package/dist/config/codex-feature-flags.d.ts +21 -0
  87. package/dist/config/codex-feature-flags.d.ts.map +1 -0
  88. package/dist/config/codex-feature-flags.js +56 -0
  89. package/dist/config/codex-feature-flags.js.map +1 -0
  90. package/dist/config/codex-hooks.d.ts +2 -0
  91. package/dist/config/codex-hooks.d.ts.map +1 -1
  92. package/dist/config/codex-hooks.js +25 -3
  93. package/dist/config/codex-hooks.js.map +1 -1
  94. package/dist/config/generator.d.ts +11 -2
  95. package/dist/config/generator.d.ts.map +1 -1
  96. package/dist/config/generator.js +221 -123
  97. package/dist/config/generator.js.map +1 -1
  98. package/dist/config/omx-first-party-mcp.d.ts +3 -1
  99. package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
  100. package/dist/config/omx-first-party-mcp.js +2 -2
  101. package/dist/config/omx-first-party-mcp.js.map +1 -1
  102. package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
  103. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  104. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
  105. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  106. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
  107. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
  108. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
  109. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
  110. package/dist/hooks/agents-overlay.js +2 -2
  111. package/dist/hooks/agents-overlay.js.map +1 -1
  112. package/dist/hooks/keyword-detector.d.ts +1 -0
  113. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  114. package/dist/hooks/keyword-detector.js +7 -5
  115. package/dist/hooks/keyword-detector.js.map +1 -1
  116. package/dist/hud/__tests__/state.test.js +164 -0
  117. package/dist/hud/__tests__/state.test.js.map +1 -1
  118. package/dist/hud/state.d.ts.map +1 -1
  119. package/dist/hud/state.js +4 -5
  120. package/dist/hud/state.js.map +1 -1
  121. package/dist/mcp/__tests__/state-paths.test.js +61 -0
  122. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  123. package/dist/mcp/__tests__/state-server.test.js +166 -0
  124. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  125. package/dist/mcp/state-paths.d.ts.map +1 -1
  126. package/dist/mcp/state-paths.js +23 -2
  127. package/dist/mcp/state-paths.js.map +1 -1
  128. package/dist/modes/__tests__/base-session-scope.test.js +22 -0
  129. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  130. package/dist/modes/__tests__/base-tmux-pane.test.js +57 -26
  131. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  132. package/dist/modes/base.d.ts.map +1 -1
  133. package/dist/modes/base.js +5 -0
  134. package/dist/modes/base.js.map +1 -1
  135. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
  136. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
  137. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
  138. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
  139. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
  140. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
  141. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
  142. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
  143. package/dist/planning/__tests__/artifacts.test.js +533 -4
  144. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  145. package/dist/planning/__tests__/context-pack-status.test.js +524 -0
  146. package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
  147. package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
  148. package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
  149. package/dist/planning/__tests__/markdown-structure.test.js +459 -0
  150. package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
  151. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
  152. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
  153. package/dist/planning/artifacts.d.ts +1 -1
  154. package/dist/planning/artifacts.d.ts.map +1 -1
  155. package/dist/planning/artifacts.js +227 -28
  156. package/dist/planning/artifacts.js.map +1 -1
  157. package/dist/planning/context-pack-status.d.ts +25 -0
  158. package/dist/planning/context-pack-status.d.ts.map +1 -1
  159. package/dist/planning/context-pack-status.js +272 -31
  160. package/dist/planning/context-pack-status.js.map +1 -1
  161. package/dist/planning/markdown-structure.d.ts +20 -0
  162. package/dist/planning/markdown-structure.d.ts.map +1 -0
  163. package/dist/planning/markdown-structure.js +137 -0
  164. package/dist/planning/markdown-structure.js.map +1 -0
  165. package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
  166. package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
  167. package/dist/ralph/__tests__/completion-audit.test.js +121 -0
  168. package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
  169. package/dist/ralph/completion-audit.d.ts +8 -0
  170. package/dist/ralph/completion-audit.d.ts.map +1 -0
  171. package/dist/ralph/completion-audit.js +99 -0
  172. package/dist/ralph/completion-audit.js.map +1 -0
  173. package/dist/scripts/__tests__/codex-native-hook.test.js +220 -13
  174. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  175. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
  176. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
  177. package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
  178. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
  179. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  180. package/dist/scripts/codex-native-hook.js +133 -54
  181. package/dist/scripts/codex-native-hook.js.map +1 -1
  182. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  183. package/dist/scripts/codex-native-pre-post.js +4 -2
  184. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  185. package/dist/scripts/notify-dispatcher.js +30 -1
  186. package/dist/scripts/notify-dispatcher.js.map +1 -1
  187. package/dist/scripts/notify-hook.js +3 -1
  188. package/dist/scripts/notify-hook.js.map +1 -1
  189. package/dist/state/__tests__/workflow-transition.test.js +102 -27
  190. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  191. package/dist/state/operations.d.ts.map +1 -1
  192. package/dist/state/operations.js +9 -3
  193. package/dist/state/operations.js.map +1 -1
  194. package/dist/state/skill-active.d.ts +7 -0
  195. package/dist/state/skill-active.d.ts.map +1 -1
  196. package/dist/state/skill-active.js +25 -8
  197. package/dist/state/skill-active.js.map +1 -1
  198. package/dist/state/workflow-transition-reconcile.d.ts +1 -0
  199. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  200. package/dist/state/workflow-transition-reconcile.js +22 -15
  201. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  202. package/dist/state/workflow-transition.js +3 -3
  203. package/dist/state/workflow-transition.js.map +1 -1
  204. package/dist/team/__tests__/approved-execution.test.js +39 -0
  205. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  206. package/dist/team/__tests__/runtime.test.js +5 -0
  207. package/dist/team/__tests__/runtime.test.js.map +1 -1
  208. package/dist/team/__tests__/scaling.test.js +497 -2
  209. package/dist/team/__tests__/scaling.test.js.map +1 -1
  210. package/dist/team/__tests__/state-root.test.js +1 -1
  211. package/dist/team/__tests__/state-root.test.js.map +1 -1
  212. package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
  213. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  214. package/dist/team/approved-execution.d.ts.map +1 -1
  215. package/dist/team/approved-execution.js +3 -0
  216. package/dist/team/approved-execution.js.map +1 -1
  217. package/dist/team/scaling.d.ts.map +1 -1
  218. package/dist/team/scaling.js +43 -0
  219. package/dist/team/scaling.js.map +1 -1
  220. package/dist/team/state-root.d.ts.map +1 -1
  221. package/dist/team/state-root.js +4 -0
  222. package/dist/team/state-root.js.map +1 -1
  223. package/dist/team/state.d.ts.map +1 -1
  224. package/dist/team/state.js +2 -6
  225. package/dist/team/state.js.map +1 -1
  226. package/dist/ultragoal/__tests__/artifacts.test.js +124 -1
  227. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  228. package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
  229. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  230. package/dist/ultragoal/artifacts.d.ts +44 -2
  231. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  232. package/dist/ultragoal/artifacts.js +197 -13
  233. package/dist/ultragoal/artifacts.js.map +1 -1
  234. package/dist/wiki/lifecycle.js +1 -1
  235. package/dist/wiki/lifecycle.js.map +1 -1
  236. package/package.json +1 -1
  237. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  238. package/plugins/oh-my-codex/.mcp.json +5 -5
  239. package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
  240. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
  241. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
  242. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
  243. package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
  244. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
  245. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
  246. package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
  247. package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
  248. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
  249. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
  250. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
  251. package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
  252. package/skills/analyze/SKILL.md +0 -2
  253. package/skills/ask-claude/SKILL.md +5 -3
  254. package/skills/ask-gemini/SKILL.md +5 -3
  255. package/skills/autopilot/SKILL.md +2 -2
  256. package/skills/code-review/SKILL.md +1 -3
  257. package/skills/deep-interview/SKILL.md +5 -7
  258. package/skills/doctor/SKILL.md +2 -2
  259. package/skills/ecomode/SKILL.md +105 -1
  260. package/skills/frontend-ui-ux/SKILL.md +4 -26
  261. package/skills/git-master/SKILL.md +2 -4
  262. package/skills/omx-setup/SKILL.md +3 -3
  263. package/skills/pipeline/SKILL.md +3 -3
  264. package/skills/plan/SKILL.md +3 -6
  265. package/skills/ralph/SKILL.md +9 -10
  266. package/skills/swarm/SKILL.md +5 -3
  267. package/skills/tdd/SKILL.md +95 -1
  268. package/skills/ultragoal/SKILL.md +36 -3
  269. package/skills/ultraqa/SKILL.md +21 -24
  270. package/skills/ultrawork/SKILL.md +8 -8
  271. package/skills/web-clone/SKILL.md +348 -1
  272. package/skills/wiki/SKILL.md +13 -13
  273. package/src/scripts/__tests__/codex-native-hook.test.ts +231 -13
  274. package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
  275. package/src/scripts/codex-native-hook.ts +160 -43
  276. package/src/scripts/codex-native-pre-post.ts +4 -1
  277. package/src/scripts/notify-dispatcher.ts +40 -1
  278. package/src/scripts/notify-hook.ts +3 -1
@@ -10,10 +10,12 @@
10
10
  * 3. [table] sections (shell_environment_policy.set, mcp_servers, tui)
11
11
  */
12
12
  import type { UnifiedMcpRegistryServer } from "./mcp-registry.js";
13
+ import { type CodexHookFeatureFlag } from "./codex-feature-flags.js";
13
14
  import type { HudPreset } from "../hud/types.js";
14
15
  interface MergeOptions {
15
16
  includeTui?: boolean;
16
17
  codexHooksFile?: string;
18
+ codexHookFeatureFlag?: CodexHookFeatureFlag;
17
19
  modelOverride?: string;
18
20
  sharedMcpServers?: UnifiedMcpRegistryServer[];
19
21
  sharedMcpRegistrySource?: string;
@@ -21,6 +23,7 @@ interface MergeOptions {
21
23
  statusLinePreset?: HudPreset;
22
24
  forceStatusLinePreset?: boolean;
23
25
  notifyCommand?: string[] | false;
26
+ includeFirstPartyMcp?: boolean;
24
27
  }
25
28
  export interface ModelContextRecommendation {
26
29
  model: string;
@@ -43,6 +46,7 @@ export declare function getRootModelName(config: string): string | undefined;
43
46
  export declare function formatTomlStringArray(values: readonly string[]): string;
44
47
  export declare function getRootTomlArray(config: string, key: string): string[] | null;
45
48
  export declare function isOmxManagedNotifyCommand(command: readonly string[] | null | undefined, pkgRoot?: string): boolean;
49
+ export declare function sanitizePreviousNotifyCommand(command: readonly string[] | null | undefined, pkgRoot?: string): string[] | null;
46
50
  export declare function stripOmxSeededBehavioralDefaults(config: string): string;
47
51
  /**
48
52
  * Remove any existing OMX-owned top-level keys so we can re-insert them
@@ -51,7 +55,7 @@ export declare function stripOmxSeededBehavioralDefaults(config: string): string
51
55
  export declare function stripOmxTopLevelKeys(config: string): string;
52
56
  export declare function stripManagedCodexHookTrustState(config: string): string;
53
57
  export declare function upsertManagedCodexHookTrustState(config: string, pkgRoot: string, codexHooksFile: string | undefined): string;
54
- export declare function upsertPluginModeRuntimeFeatureFlags(config: string): string;
58
+ export declare function upsertPluginModeRuntimeFeatureFlags(config: string, codexHookFeatureFlag?: CodexHookFeatureFlag): string;
55
59
  /**
56
60
  * Remove OMX-owned feature flags from the [features] section.
57
61
  * If the section becomes empty after removal, remove the section header too.
@@ -61,7 +65,7 @@ export declare function stripOmxFeatureFlags(config: string): string;
61
65
  * Preserve native Codex hook enablement without re-adding other OMX feature
62
66
  * flags. Used by uninstall when user-owned hooks remain in hooks.json.
63
67
  */
64
- export declare function upsertCodexHooksFeatureFlag(config: string): string;
68
+ export declare function upsertCodexHooksFeatureFlag(config: string, codexHookFeatureFlag?: CodexHookFeatureFlag): string;
65
69
  export declare function stripOmxEnvSettings(config: string): string;
66
70
  export declare function stripExistingOmxBlocks(config: string): {
67
71
  cleaned: string;
@@ -71,6 +75,11 @@ export declare function stripExistingSharedMcpRegistryBlock(config: string): {
71
75
  cleaned: string;
72
76
  removed: number;
73
77
  };
78
+ export declare function extractSharedMcpRegistryServersFromConfig(config: string): {
79
+ servers: UnifiedMcpRegistryServer[];
80
+ sourcePath?: string;
81
+ };
82
+ export declare function mergeSharedMcpRegistryBlock(config: string, servers: UnifiedMcpRegistryServer[], sourcePath?: string): string;
74
83
  /**
75
84
  * Merge OMX config into existing config.toml
76
85
  * Preserves existing user settings, appends OMX block if not present.
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/config/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/config/generator.ts"],"names":[],"mappings":"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"}
@@ -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";
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";
19
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,9 +499,38 @@ export function stripManagedCodexHookTrustState(config) {
469
499
  }
470
500
  return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
471
501
  }
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
+ }
472
531
  export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile) {
473
- const stripped = stripManagedCodexHookTrustState(config);
474
532
  const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
533
+ const stripped = stripUnfencedManagedCodexHookTrustState(stripManagedCodexHookTrustState(config), hookTrustToml);
475
534
  if (!hookTrustToml)
476
535
  return `${stripped}\n`;
477
536
  return [
@@ -484,14 +543,15 @@ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile
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, includeFirstPartyMcp = false) {
1215
1310
  const lines = [
1216
1311
  "",
1217
1312
  "# ============================================================",
@@ -1219,17 +1314,19 @@ 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
1332
  const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
@@ -1295,11 +1392,12 @@ 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));
1298
1396
  if (options.modelOverride) {
1299
1397
  existing = stripRootLevelKeys(existing, ["model"]);
1300
1398
  }
1301
1399
  existing = stripOrphanedOmxSections(existing);
1302
- existing = upsertFeatureFlags(existing);
1400
+ existing = upsertFeatureFlags(existing, options.codexHookFeatureFlag);
1303
1401
  existing = upsertEnvSettings(existing);
1304
1402
  existing = upsertAgentsSettings(existing);
1305
1403
  const tuiUpsert = includeTui
@@ -1311,7 +1409,7 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1311
1409
  const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
1312
1410
  ? getDefaultNotifyCommand(pkgRoot)
1313
1411
  : options.notifyCommand);
1314
- const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile);
1412
+ const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, options.includeFirstPartyMcp === true);
1315
1413
  const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
1316
1414
  let body = existing.trimEnd();
1317
1415
  if (sharedRegistryBlock) {