oh-my-codex 0.20.1 → 0.20.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 (654) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +10 -1
  4. package/dist/adapt/__tests__/hermes.test.js.map +1 -1
  5. package/dist/adapt/contracts.d.ts.map +1 -1
  6. package/dist/agents/native-config.js.map +1 -1
  7. package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
  8. package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
  9. package/dist/auth/__tests__/hotswap.test.js +183 -0
  10. package/dist/auth/__tests__/hotswap.test.js.map +1 -0
  11. package/dist/auth/hotswap.d.ts.map +1 -1
  12. package/dist/auth/hotswap.js +17 -4
  13. package/dist/auth/hotswap.js.map +1 -1
  14. package/dist/auth/paths.js.map +1 -1
  15. package/dist/auth/storage.js.map +1 -1
  16. package/dist/autopilot/__tests__/ralplan-gate.test.js +4 -4
  17. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  18. package/dist/autopilot/completion-gate.js.map +1 -1
  19. package/dist/autopilot/fsm.d.ts +1 -1
  20. package/dist/autopilot/fsm.d.ts.map +1 -1
  21. package/dist/autoresearch/goal.js.map +1 -1
  22. package/dist/autoresearch/runtime.js.map +1 -1
  23. package/dist/capabilities/lockfile.js.map +1 -1
  24. package/dist/catalog/reader.js.map +1 -1
  25. package/dist/catalog/skill-mirror.js.map +1 -1
  26. package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
  27. package/dist/cli/__tests__/agents-init.test.js.map +1 -1
  28. package/dist/cli/__tests__/agents.test.js.map +1 -1
  29. package/dist/cli/__tests__/api.test.js.map +1 -1
  30. package/dist/cli/__tests__/ask.test.js.map +1 -1
  31. package/dist/cli/__tests__/auth.test.js.map +1 -1
  32. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  33. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  34. package/dist/cli/__tests__/capabilities.test.js.map +1 -1
  35. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  36. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
  37. package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
  38. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
  39. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  40. package/dist/cli/__tests__/doctor-warning-copy.test.js +650 -15
  41. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  42. package/dist/cli/__tests__/exec.test.js.map +1 -1
  43. package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
  44. package/dist/cli/__tests__/index.test.js +216 -11
  45. package/dist/cli/__tests__/index.test.js.map +1 -1
  46. package/dist/cli/__tests__/launch-fallback.test.js +49 -3
  47. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  48. package/dist/cli/__tests__/mcp-parity.test.js +84 -12
  49. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  50. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
  51. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
  52. package/dist/cli/__tests__/native-hook-claim-journal.test.js +128 -0
  53. package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
  54. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  55. package/dist/cli/__tests__/question.test.js.map +1 -1
  56. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
  57. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
  58. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  59. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
  60. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
  61. package/dist/cli/__tests__/ralph.test.js +8 -3
  62. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  63. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
  64. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
  65. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +187 -0
  66. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
  67. package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
  68. package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
  69. package/dist/cli/__tests__/ralplan.test.js +129 -0
  70. package/dist/cli/__tests__/ralplan.test.js.map +1 -0
  71. package/dist/cli/__tests__/resume.test.js +6 -1
  72. package/dist/cli/__tests__/resume.test.js.map +1 -1
  73. package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
  74. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  75. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  76. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  77. package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
  78. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  79. package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
  80. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
  81. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  82. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
  83. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
  84. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
  85. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
  86. package/dist/cli/__tests__/setup-install-mode.test.js +2261 -14
  87. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  88. package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
  89. package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
  90. package/dist/cli/__tests__/setup-preferences.test.js +79 -0
  91. package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
  92. package/dist/cli/__tests__/setup-refresh.test.js +33 -2
  93. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  94. package/dist/cli/__tests__/setup-scope.test.js +46 -3
  95. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  96. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  97. package/dist/cli/__tests__/state.test.js +37 -0
  98. package/dist/cli/__tests__/state.test.js.map +1 -1
  99. package/dist/cli/__tests__/team.test.js.map +1 -1
  100. package/dist/cli/__tests__/ultragoal.test.js +61 -1
  101. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  102. package/dist/cli/__tests__/uninstall.test.js +1771 -24
  103. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  104. package/dist/cli/__tests__/update.test.js +58 -0
  105. package/dist/cli/__tests__/update.test.js.map +1 -1
  106. package/dist/cli/__tests__/url.test.js.map +1 -1
  107. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  108. package/dist/cli/adapt.js.map +1 -1
  109. package/dist/cli/agents-init.js.map +1 -1
  110. package/dist/cli/agents.js.map +1 -1
  111. package/dist/cli/api.js.map +1 -1
  112. package/dist/cli/ask.d.ts +1 -1
  113. package/dist/cli/ask.d.ts.map +1 -1
  114. package/dist/cli/ask.js.map +1 -1
  115. package/dist/cli/auth.js.map +1 -1
  116. package/dist/cli/autoresearch-guided.js.map +1 -1
  117. package/dist/cli/autoresearch-intake.js.map +1 -1
  118. package/dist/cli/capabilities.js.map +1 -1
  119. package/dist/cli/cleanup.js.map +1 -1
  120. package/dist/cli/codex-feature-probe.js.map +1 -1
  121. package/dist/cli/codex-home.js.map +1 -1
  122. package/dist/cli/doctor.d.ts +18 -0
  123. package/dist/cli/doctor.d.ts.map +1 -1
  124. package/dist/cli/doctor.js +594 -130
  125. package/dist/cli/doctor.js.map +1 -1
  126. package/dist/cli/explore.js.map +1 -1
  127. package/dist/cli/index.d.ts +11 -3
  128. package/dist/cli/index.d.ts.map +1 -1
  129. package/dist/cli/index.js +108 -20
  130. package/dist/cli/index.js.map +1 -1
  131. package/dist/cli/mcp-serve.js.map +1 -1
  132. package/dist/cli/mission.js.map +1 -1
  133. package/dist/cli/native-assets.js.map +1 -1
  134. package/dist/cli/native-hook-claim-journal.d.ts +18 -0
  135. package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
  136. package/dist/cli/native-hook-claim-journal.js +239 -0
  137. package/dist/cli/native-hook-claim-journal.js.map +1 -0
  138. package/dist/cli/omx.js.map +1 -1
  139. package/dist/cli/plugin-marketplace.js.map +1 -1
  140. package/dist/cli/project-runtime-codex-homes.js.map +1 -1
  141. package/dist/cli/question.js.map +1 -1
  142. package/dist/cli/ralph.d.ts.map +1 -1
  143. package/dist/cli/ralph.js +3 -2
  144. package/dist/cli/ralph.js.map +1 -1
  145. package/dist/cli/ralplan.d.ts +14 -0
  146. package/dist/cli/ralplan.d.ts.map +1 -0
  147. package/dist/cli/ralplan.js +203 -0
  148. package/dist/cli/ralplan.js.map +1 -0
  149. package/dist/cli/setup-preferences.d.ts +11 -0
  150. package/dist/cli/setup-preferences.d.ts.map +1 -1
  151. package/dist/cli/setup-preferences.js +32 -0
  152. package/dist/cli/setup-preferences.js.map +1 -1
  153. package/dist/cli/setup.d.ts +53 -0
  154. package/dist/cli/setup.d.ts.map +1 -1
  155. package/dist/cli/setup.js +1401 -398
  156. package/dist/cli/setup.js.map +1 -1
  157. package/dist/cli/sparkshell.js.map +1 -1
  158. package/dist/cli/star-prompt.js.map +1 -1
  159. package/dist/cli/state.d.ts.map +1 -1
  160. package/dist/cli/state.js +2 -1
  161. package/dist/cli/state.js.map +1 -1
  162. package/dist/cli/team.js.map +1 -1
  163. package/dist/cli/ultragoal.d.ts +5 -1
  164. package/dist/cli/ultragoal.d.ts.map +1 -1
  165. package/dist/cli/ultragoal.js +34 -2
  166. package/dist/cli/ultragoal.js.map +1 -1
  167. package/dist/cli/uninstall.d.ts +8 -0
  168. package/dist/cli/uninstall.d.ts.map +1 -1
  169. package/dist/cli/uninstall.js +944 -95
  170. package/dist/cli/uninstall.js.map +1 -1
  171. package/dist/cli/update.d.ts.map +1 -1
  172. package/dist/cli/update.js +8 -1
  173. package/dist/cli/update.js.map +1 -1
  174. package/dist/cli/url.js.map +1 -1
  175. package/dist/compat/__tests__/doctor-contract.test.js +5 -1
  176. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  177. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
  178. package/dist/config/__tests__/codex-hooks.test.js +1287 -11
  179. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  180. package/dist/config/__tests__/generator-idempotent.test.js +850 -32
  181. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  182. package/dist/config/__tests__/generator-notify.test.js +6 -1
  183. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  184. package/dist/config/codex-feature-flags.d.ts.map +1 -1
  185. package/dist/config/codex-feature-flags.js.map +1 -1
  186. package/dist/config/codex-hooks.d.ts +124 -1
  187. package/dist/config/codex-hooks.d.ts.map +1 -1
  188. package/dist/config/codex-hooks.js +2142 -265
  189. package/dist/config/codex-hooks.js.map +1 -1
  190. package/dist/config/commit-lore-guard.js.map +1 -1
  191. package/dist/config/generator.d.ts +21 -16
  192. package/dist/config/generator.d.ts.map +1 -1
  193. package/dist/config/generator.js +991 -137
  194. package/dist/config/generator.js.map +1 -1
  195. package/dist/config/mcp-registry.js.map +1 -1
  196. package/dist/config/models.d.ts +2 -2
  197. package/dist/config/models.d.ts.map +1 -1
  198. package/dist/config/models.js.map +1 -1
  199. package/dist/config/omx-first-party-mcp.js.map +1 -1
  200. package/dist/config/team-mode.d.ts.map +1 -1
  201. package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
  202. package/dist/document-refresh/enforcer.js.map +1 -1
  203. package/dist/exec/followup.js.map +1 -1
  204. package/dist/goal-workflows/artifacts.js.map +1 -1
  205. package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
  206. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  207. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
  208. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
  209. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  210. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
  211. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  212. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  213. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  214. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  215. package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
  216. package/dist/hooks/__tests__/keyword-detector.test.js +1372 -2
  217. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  218. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +14 -0
  219. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  220. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  221. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +669 -1
  222. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  223. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
  224. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  225. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
  226. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  227. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  228. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
  229. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  230. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
  231. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  232. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  233. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
  234. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
  235. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
  236. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  237. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  238. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +8 -1
  239. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  240. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  241. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  242. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  243. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
  244. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  245. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
  246. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  247. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  248. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
  249. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
  250. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
  251. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
  252. package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
  253. package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
  254. package/dist/hooks/__tests__/session.test.js +532 -11
  255. package/dist/hooks/__tests__/session.test.js.map +1 -1
  256. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
  257. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
  258. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
  259. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
  260. package/dist/hooks/agents-overlay.js +5 -5
  261. package/dist/hooks/agents-overlay.js.map +1 -1
  262. package/dist/hooks/code-simplifier/index.js.map +1 -1
  263. package/dist/hooks/explore-routing.js.map +1 -1
  264. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  265. package/dist/hooks/extensibility/events.js.map +1 -1
  266. package/dist/hooks/extensibility/loader.js.map +1 -1
  267. package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
  268. package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
  269. package/dist/hooks/keyword-detector.d.ts +33 -7
  270. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  271. package/dist/hooks/keyword-detector.js +2228 -119
  272. package/dist/hooks/keyword-detector.js.map +1 -1
  273. package/dist/hooks/keyword-registry.d.ts +12 -0
  274. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  275. package/dist/hooks/keyword-registry.js +41 -0
  276. package/dist/hooks/keyword-registry.js.map +1 -1
  277. package/dist/hooks/prompt-session-provenance.d.ts +87 -0
  278. package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
  279. package/dist/hooks/prompt-session-provenance.js +180 -0
  280. package/dist/hooks/prompt-session-provenance.js.map +1 -0
  281. package/dist/hooks/session.d.ts +139 -34
  282. package/dist/hooks/session.d.ts.map +1 -1
  283. package/dist/hooks/session.js +1239 -317
  284. package/dist/hooks/session.js.map +1 -1
  285. package/dist/hooks/task-size-detector.js.map +1 -1
  286. package/dist/hud/__tests__/state.test.js.map +1 -1
  287. package/dist/hud/authority.js.map +1 -1
  288. package/dist/hud/constants.js.map +1 -1
  289. package/dist/hud/index.js.map +1 -1
  290. package/dist/hud/reconcile.js.map +1 -1
  291. package/dist/hud/render.js.map +1 -1
  292. package/dist/hud/state.js.map +1 -1
  293. package/dist/hud/tmux.js.map +1 -1
  294. package/dist/leader/__tests__/contract.test.js +103 -1
  295. package/dist/leader/__tests__/contract.test.js.map +1 -1
  296. package/dist/leader/contract.d.ts +26 -5
  297. package/dist/leader/contract.d.ts.map +1 -1
  298. package/dist/leader/contract.js +109 -3
  299. package/dist/leader/contract.js.map +1 -1
  300. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  301. package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
  302. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  303. package/dist/mcp/__tests__/state-paths.test.js +98 -1
  304. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  305. package/dist/mcp/bootstrap.js.map +1 -1
  306. package/dist/mcp/code-intel-server.d.ts +58 -58
  307. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  308. package/dist/mcp/code-intel-server.js.map +1 -1
  309. package/dist/mcp/hermes-bridge.js.map +1 -1
  310. package/dist/mcp/hermes-server.d.ts +70 -70
  311. package/dist/mcp/hermes-server.d.ts.map +1 -1
  312. package/dist/mcp/lifecycle-telemetry.js.map +1 -1
  313. package/dist/mcp/memory-server.d.ts +34 -34
  314. package/dist/mcp/memory-server.d.ts.map +1 -1
  315. package/dist/mcp/memory-server.js.map +1 -1
  316. package/dist/mcp/state-paths.d.ts +14 -0
  317. package/dist/mcp/state-paths.d.ts.map +1 -1
  318. package/dist/mcp/state-paths.js +96 -20
  319. package/dist/mcp/state-paths.js.map +1 -1
  320. package/dist/mcp/state-server.d.ts +47 -47
  321. package/dist/mcp/state-server.d.ts.map +1 -1
  322. package/dist/mcp/trace-server.d.ts +4 -4
  323. package/dist/mcp/trace-server.d.ts.map +1 -1
  324. package/dist/mcp/trace-server.js.map +1 -1
  325. package/dist/mcp/wiki-server.d.ts +23 -23
  326. package/dist/mcp/wiki-server.d.ts.map +1 -1
  327. package/dist/mcp/wiki-server.js.map +1 -1
  328. package/dist/modes/__tests__/base-session-scope.test.js +53 -1
  329. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  330. package/dist/modes/base.d.ts.map +1 -1
  331. package/dist/modes/base.js +5 -5
  332. package/dist/modes/base.js.map +1 -1
  333. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
  334. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  335. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
  336. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
  337. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  338. package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
  339. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  340. package/dist/notifications/http-client.js.map +1 -1
  341. package/dist/notifications/index.d.ts +4 -1
  342. package/dist/notifications/index.d.ts.map +1 -1
  343. package/dist/notifications/index.js +3 -9
  344. package/dist/notifications/index.js.map +1 -1
  345. package/dist/notifications/lifecycle-dedupe.js.map +1 -1
  346. package/dist/notifications/reply-listener.d.ts.map +1 -1
  347. package/dist/notifications/reply-listener.js.map +1 -1
  348. package/dist/notifications/session-registry.js.map +1 -1
  349. package/dist/notifications/session-status.js.map +1 -1
  350. package/dist/notifications/temp-contract.js.map +1 -1
  351. package/dist/notifications/tmux-detector.js.map +1 -1
  352. package/dist/notifications/tmux.js.map +1 -1
  353. package/dist/openclaw/config.js.map +1 -1
  354. package/dist/openclaw/dispatcher.js.map +1 -1
  355. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  356. package/dist/pipeline/__tests__/stages.test.js +8 -5
  357. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  358. package/dist/pipeline/stages/code-review.js.map +1 -1
  359. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  360. package/dist/pipeline/stages/ralplan.js.map +1 -1
  361. package/dist/pipeline/stages/team-exec.js.map +1 -1
  362. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  363. package/dist/pipeline/stages/ultraqa.js.map +1 -1
  364. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
  365. package/dist/planning/artifact-names.js.map +1 -1
  366. package/dist/planning/artifacts.js.map +1 -1
  367. package/dist/question/__tests__/state.test.js.map +1 -1
  368. package/dist/question/__tests__/ui.test.js.map +1 -1
  369. package/dist/question/autopilot-wait.js.map +1 -1
  370. package/dist/question/client.d.ts.map +1 -1
  371. package/dist/question/client.js.map +1 -1
  372. package/dist/question/deep-interview.js.map +1 -1
  373. package/dist/question/events.js.map +1 -1
  374. package/dist/question/renderer.js.map +1 -1
  375. package/dist/question/state.d.ts.map +1 -1
  376. package/dist/question/state.js.map +1 -1
  377. package/dist/question/ui.js.map +1 -1
  378. package/dist/ralph/contract.d.ts +1 -1
  379. package/dist/ralph/contract.d.ts.map +1 -1
  380. package/dist/ralplan/__tests__/consensus-gate.test.js +403 -8
  381. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  382. package/dist/ralplan/__tests__/runtime.test.js +112 -14
  383. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  384. package/dist/ralplan/consensus-gate.d.ts +3 -3
  385. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  386. package/dist/ralplan/consensus-gate.js +155 -60
  387. package/dist/ralplan/consensus-gate.js.map +1 -1
  388. package/dist/ralplan/runtime.d.ts +2 -2
  389. package/dist/ralplan/runtime.d.ts.map +1 -1
  390. package/dist/ralplan/runtime.js +1 -2
  391. package/dist/ralplan/runtime.js.map +1 -1
  392. package/dist/runtime/bridge.d.ts.map +1 -1
  393. package/dist/runtime/bridge.js.map +1 -1
  394. package/dist/runtime/process-tree.js.map +1 -1
  395. package/dist/runtime/run-loop.js.map +1 -1
  396. package/dist/runtime/run-outcome.d.ts +3 -3
  397. package/dist/runtime/run-outcome.d.ts.map +1 -1
  398. package/dist/runtime/run-outcome.js.map +1 -1
  399. package/dist/runtime/run-state.js.map +1 -1
  400. package/dist/scripts/__tests__/codex-native-hook.test.js +4121 -592
  401. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  402. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
  403. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
  404. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
  405. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
  406. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
  407. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
  408. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  409. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
  410. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
  411. package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
  412. package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
  413. package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
  414. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  415. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
  416. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
  417. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +205 -0
  418. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
  419. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
  420. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
  421. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +175 -0
  422. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
  423. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  424. package/dist/scripts/__tests__/smoke-packed-install.test.js +848 -4
  425. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  426. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
  427. package/dist/scripts/build-api.js.map +1 -1
  428. package/dist/scripts/build-explore-harness.js.map +1 -1
  429. package/dist/scripts/build-sparkshell.js.map +1 -1
  430. package/dist/scripts/cleanup-explore-harness.js.map +1 -1
  431. package/dist/scripts/codex-execution-surface.js.map +1 -1
  432. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  433. package/dist/scripts/codex-native-hook.js +689 -156
  434. package/dist/scripts/codex-native-hook.js.map +1 -1
  435. package/dist/scripts/generate-native-release-manifest.js.map +1 -1
  436. package/dist/scripts/generate-release-body.js.map +1 -1
  437. package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
  438. package/dist/scripts/hook-payload-guard.js.map +1 -1
  439. package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
  440. package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
  441. package/dist/scripts/notify-fallback-delivery.js +419 -0
  442. package/dist/scripts/notify-fallback-delivery.js.map +1 -0
  443. package/dist/scripts/notify-fallback-watcher.js +136 -30
  444. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  445. package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
  446. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  447. package/dist/scripts/notify-hook/auto-nudge.js +39 -13
  448. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  449. package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
  450. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  451. package/dist/scripts/notify-hook/managed-tmux.js +122 -12
  452. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  453. package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
  454. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
  455. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
  456. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  457. package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
  458. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  459. package/dist/scripts/notify-hook/state-io.d.ts +17 -0
  460. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  461. package/dist/scripts/notify-hook/state-io.js +73 -11
  462. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  463. package/dist/scripts/notify-hook/team-dispatch.d.ts +1 -1
  464. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  465. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
  466. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -4
  467. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
  468. package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
  469. package/dist/scripts/notify-hook/team-worker.d.ts +2 -2
  470. package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
  471. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  472. package/dist/scripts/notify-hook/tmux-injection.js +25 -16
  473. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  474. package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
  475. package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
  476. package/dist/scripts/notify-hook/visual-verdict.js +15 -13
  477. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
  478. package/dist/scripts/notify-hook.d.ts +24 -1
  479. package/dist/scripts/notify-hook.d.ts.map +1 -1
  480. package/dist/scripts/notify-hook.js +266 -90
  481. package/dist/scripts/notify-hook.js.map +1 -1
  482. package/dist/scripts/postinstall.js.map +1 -1
  483. package/dist/scripts/prompt-inventory.js.map +1 -1
  484. package/dist/scripts/smoke-packed-install.d.ts +879 -2
  485. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  486. package/dist/scripts/smoke-packed-install.js +1528 -7
  487. package/dist/scripts/smoke-packed-install.js.map +1 -1
  488. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  489. package/dist/scripts/test-reply-listener-live.js.map +1 -1
  490. package/dist/scripts/test-sparkshell.js.map +1 -1
  491. package/dist/scripts/verify-native-agents.js.map +1 -1
  492. package/dist/session-history/friction.js.map +1 -1
  493. package/dist/session-history/search.js.map +1 -1
  494. package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
  495. package/dist/sidecar/collector.js.map +1 -1
  496. package/dist/sidecar/index.js.map +1 -1
  497. package/dist/sidecar/render.js.map +1 -1
  498. package/dist/sidecar/tmux.js.map +1 -1
  499. package/dist/state/__tests__/operations.test.js +64 -15
  500. package/dist/state/__tests__/operations.test.js.map +1 -1
  501. package/dist/state/__tests__/skill-active.test.js +19 -1
  502. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  503. package/dist/state/__tests__/workflow-transition.test.js +61 -0
  504. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  505. package/dist/state/mode-state-context.js.map +1 -1
  506. package/dist/state/operations.d.ts +1 -1
  507. package/dist/state/operations.d.ts.map +1 -1
  508. package/dist/state/operations.js +49 -55
  509. package/dist/state/operations.js.map +1 -1
  510. package/dist/state/paths.d.ts +1 -1
  511. package/dist/state/paths.d.ts.map +1 -1
  512. package/dist/state/paths.js +1 -1
  513. package/dist/state/paths.js.map +1 -1
  514. package/dist/state/skill-active.d.ts +13 -1
  515. package/dist/state/skill-active.d.ts.map +1 -1
  516. package/dist/state/skill-active.js +43 -4
  517. package/dist/state/skill-active.js.map +1 -1
  518. package/dist/state/terminal-normalization.js.map +1 -1
  519. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  520. package/dist/state/workflow-transition-reconcile.js +20 -4
  521. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  522. package/dist/state/workflow-transition.d.ts +1 -1
  523. package/dist/state/workflow-transition.d.ts.map +1 -1
  524. package/dist/state/workflow-transition.js.map +1 -1
  525. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +2 -0
  526. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +1 -0
  527. package/dist/subagents/__tests__/adapted-role-binding.test.js +988 -0
  528. package/dist/subagents/__tests__/adapted-role-binding.test.js.map +1 -0
  529. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
  530. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
  531. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +273 -0
  532. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
  533. package/dist/subagents/__tests__/tracker.test.js +1550 -10
  534. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  535. package/dist/subagents/adapted-role-binding.d.ts +17 -0
  536. package/dist/subagents/adapted-role-binding.d.ts.map +1 -0
  537. package/dist/subagents/adapted-role-binding.js +75 -0
  538. package/dist/subagents/adapted-role-binding.js.map +1 -0
  539. package/dist/subagents/role-routing-marker.d.ts +10 -0
  540. package/dist/subagents/role-routing-marker.d.ts.map +1 -0
  541. package/dist/subagents/role-routing-marker.js +136 -0
  542. package/dist/subagents/role-routing-marker.js.map +1 -0
  543. package/dist/subagents/tracker.d.ts +172 -0
  544. package/dist/subagents/tracker.d.ts.map +1 -1
  545. package/dist/subagents/tracker.js +1077 -61
  546. package/dist/subagents/tracker.js.map +1 -1
  547. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  548. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  549. package/dist/team/__tests__/model-contract.test.js +231 -1
  550. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  551. package/dist/team/__tests__/role-router.test.js.map +1 -1
  552. package/dist/team/__tests__/runtime.test.js +401 -1
  553. package/dist/team/__tests__/runtime.test.js.map +1 -1
  554. package/dist/team/__tests__/scaling.test.js +181 -0
  555. package/dist/team/__tests__/scaling.test.js.map +1 -1
  556. package/dist/team/__tests__/state-root.test.js.map +1 -1
  557. package/dist/team/__tests__/tmux-session.test.js +434 -4
  558. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  559. package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
  560. package/dist/team/api-interop.d.ts +2 -2
  561. package/dist/team/api-interop.d.ts.map +1 -1
  562. package/dist/team/api-interop.js.map +1 -1
  563. package/dist/team/commit-hygiene.js.map +1 -1
  564. package/dist/team/contracts.d.ts +5 -5
  565. package/dist/team/contracts.d.ts.map +1 -1
  566. package/dist/team/delivery-log.js.map +1 -1
  567. package/dist/team/followup-planner.js.map +1 -1
  568. package/dist/team/goal-workflow.js.map +1 -1
  569. package/dist/team/idle-nudge.d.ts.map +1 -1
  570. package/dist/team/model-contract.d.ts +20 -1
  571. package/dist/team/model-contract.d.ts.map +1 -1
  572. package/dist/team/model-contract.js +267 -30
  573. package/dist/team/model-contract.js.map +1 -1
  574. package/dist/team/orchestrator.js.map +1 -1
  575. package/dist/team/pane-status.js.map +1 -1
  576. package/dist/team/phase-controller.js.map +1 -1
  577. package/dist/team/reminder-intents.d.ts +1 -1
  578. package/dist/team/reminder-intents.d.ts.map +1 -1
  579. package/dist/team/reminder-intents.js.map +1 -1
  580. package/dist/team/runtime-cli.js.map +1 -1
  581. package/dist/team/runtime.d.ts.map +1 -1
  582. package/dist/team/runtime.js +83 -52
  583. package/dist/team/runtime.js.map +1 -1
  584. package/dist/team/scaling.d.ts +9 -7
  585. package/dist/team/scaling.d.ts.map +1 -1
  586. package/dist/team/scaling.js +69 -28
  587. package/dist/team/scaling.js.map +1 -1
  588. package/dist/team/state/dispatch-lock.js.map +1 -1
  589. package/dist/team/state/dispatch.js.map +1 -1
  590. package/dist/team/state/events.js.map +1 -1
  591. package/dist/team/state/tasks.js.map +1 -1
  592. package/dist/team/state-root.js.map +1 -1
  593. package/dist/team/state.js.map +1 -1
  594. package/dist/team/team-identity.d.ts.map +1 -1
  595. package/dist/team/team-identity.js.map +1 -1
  596. package/dist/team/tmux-session.d.ts +2 -0
  597. package/dist/team/tmux-session.d.ts.map +1 -1
  598. package/dist/team/tmux-session.js +90 -42
  599. package/dist/team/tmux-session.js.map +1 -1
  600. package/dist/team/worker-bootstrap.js.map +1 -1
  601. package/dist/team/worktree.js.map +1 -1
  602. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  603. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  604. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  605. package/dist/ultragoal/artifacts.js +4 -1
  606. package/dist/ultragoal/artifacts.js.map +1 -1
  607. package/dist/url-reader/index.js.map +1 -1
  608. package/dist/utils/agents-model-table.js.map +1 -1
  609. package/dist/utils/package.js.map +1 -1
  610. package/dist/utils/paths.js.map +1 -1
  611. package/dist/utils/platform-command.js.map +1 -1
  612. package/dist/utils/repo-deps.js.map +1 -1
  613. package/dist/utils/version.js.map +1 -1
  614. package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
  615. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  616. package/dist/verification/verifier.js.map +1 -1
  617. package/dist/visual/constants.d.ts +1 -1
  618. package/dist/visual/constants.d.ts.map +1 -1
  619. package/dist/vscode/__tests__/index.test.js.map +1 -1
  620. package/dist/vscode/index.js.map +1 -1
  621. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
  622. package/dist/wiki/__tests__/lint.test.js.map +1 -1
  623. package/dist/wiki/__tests__/query.test.js.map +1 -1
  624. package/dist/wiki/__tests__/storage.test.js.map +1 -1
  625. package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
  626. package/dist/wiki/lint.js.map +1 -1
  627. package/dist/wiki/query.js.map +1 -1
  628. package/dist/wiki/storage.js.map +1 -1
  629. package/package.json +2 -2
  630. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  631. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
  632. package/plugins/oh-my-codex/skills/ralph/SKILL.md +4 -2
  633. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -2
  634. package/skills/omx-setup/SKILL.md +10 -5
  635. package/skills/ralph/SKILL.md +4 -2
  636. package/skills/ralplan/SKILL.md +5 -2
  637. package/src/scripts/__tests__/codex-native-hook.test.ts +17522 -10630
  638. package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
  639. package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
  640. package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
  641. package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +215 -0
  642. package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +193 -0
  643. package/src/scripts/__tests__/smoke-packed-install.test.ts +991 -4
  644. package/src/scripts/codex-native-hook.ts +779 -159
  645. package/src/scripts/notify-fallback-delivery.ts +416 -0
  646. package/src/scripts/notify-fallback-watcher.ts +132 -40
  647. package/src/scripts/notify-hook/auto-nudge.ts +43 -12
  648. package/src/scripts/notify-hook/managed-tmux.ts +149 -12
  649. package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
  650. package/src/scripts/notify-hook/state-io.ts +100 -13
  651. package/src/scripts/notify-hook/tmux-injection.ts +38 -21
  652. package/src/scripts/notify-hook/visual-verdict.ts +22 -12
  653. package/src/scripts/notify-hook.ts +335 -90
  654. package/src/scripts/smoke-packed-install.ts +1829 -6
@@ -16,7 +16,7 @@ import TOML from "@iarna/toml";
16
16
  import { DEFAULT_FRONTIER_MODEL } from "./models.js";
17
17
  import { DEFAULT_CODEX_HOOK_FEATURE_FLAG, CODEX_HOOK_FEATURE_FLAGS, CODEX_PLUGIN_SCOPED_HOOKS_FEATURE_FLAG, formatCodexHookFeatureFlagLine, normalizeCodexHookFeatureFlag, } from "./codex-feature-flags.js";
18
18
  import { OMX_FIRST_PARTY_MCP_SERVER_NAMES, getOmxFirstPartySetupMcpServers, } from "./omx-first-party-mcp.js";
19
- import { buildManagedCodexHookTrustState, escapeTomlBasicString, } from "./codex-hooks.js";
19
+ import { buildManagedCodexHookTrustState, escapeTomlBasicString, ManagedCodexHooksPlanError, scanManagedCodexHookTrustStateFromContent, } from "./codex-hooks.js";
20
20
  function escapeTomlString(value) {
21
21
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
22
22
  }
@@ -37,8 +37,8 @@ const LEGACY_SEEDED_MODEL_CONTEXT_WINDOW = 250000;
37
37
  const LEGACY_SEEDED_MODEL_AUTO_COMPACT_TOKEN_LIMIT = 200000;
38
38
  const OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER = "# oh-my-codex seeded behavioral defaults (uninstall removes unchanged defaults)";
39
39
  const OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER = "# End oh-my-codex seeded behavioral defaults";
40
- export const OMX_DEVELOPER_INSTRUCTIONS = "You have oh-my-codex installed. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing, $name workflow invocation, and role-specialized subagents; when spawning native subagents, set `agent_type` to an installed role and never omit it for OMX work. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail. Native subagents live in .codex/agents and may handle independent parallel subtasks within one Codex session or team pane. Skills load from .codex/skills, not native-agent TOMLs. Treat installed prompts as narrower execution surfaces under AGENTS.md authority.";
41
- export const OMX_PLUGIN_DEVELOPER_INSTRUCTIONS = '<omx version="1">You have oh-my-codex installed through Codex plugin mode. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing and $name workflow invocation. When spawning native subagents, set `agent_type` to an installed role and never omit it for OMX work. Registered Codex plugin marketplace surfaces supply OMX workflows and plugin-scoped companion resources when the plugin is installed; native agent roles are installed as setup-owned Codex agent TOML files in plugin mode so agent_type routing works. User-installed skills may still live under ~/.codex/skills. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail.</omx>';
40
+ export const OMX_DEVELOPER_INSTRUCTIONS = "You have oh-my-codex installed. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing, $name workflow invocation, and role-specialized subagents; when the native surface exposes `agent_type` role routing, set `agent_type` to an installed role and never omit it for OMX work. When it does not (`role_routing_unavailable`, for example a Codex App `spawn_agent` surface exposing only `task_name`, `message`, and `fork_turns`), do not fabricate `agent_type`; follow the OMX adapted role-pass protocol by recording a pre-validated role intent in the OMX subagent ledger, and never fake the role via a prompt label. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail. Native subagents live in .codex/agents and may handle independent parallel subtasks within one Codex session or team pane. Skills load from .codex/skills, not native-agent TOMLs. Treat installed prompts as narrower execution surfaces under AGENTS.md authority.";
41
+ export const OMX_PLUGIN_DEVELOPER_INSTRUCTIONS = '<omx version="1">You have oh-my-codex installed through Codex plugin mode. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing and $name workflow invocation. When the native surface exposes `agent_type` role routing, set `agent_type` to an installed role and never omit it for OMX work. When it does not (`role_routing_unavailable`, for example a Codex App `spawn_agent` surface exposing only `task_name`, `message`, and `fork_turns`), do not fabricate `agent_type`; follow the OMX adapted role-pass protocol by recording a pre-validated role intent in the OMX subagent ledger, and never fake the role via a prompt label. Registered Codex plugin marketplace surfaces supply OMX workflows and plugin-scoped companion resources when the plugin is installed; native agent roles are installed as setup-owned Codex agent TOML files in plugin mode so agent_type routing works. User-installed skills may still live under ~/.codex/skills. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail.</omx>';
42
42
  const SHARED_MCP_REGISTRY_MARKER = "oh-my-codex (OMX) Shared MCP Registry Sync";
43
43
  const SHARED_MCP_REGISTRY_END_MARKER = "# End oh-my-codex shared MCP registry sync";
44
44
  const LEGACY_MULTI_AGENT_KEYS = [
@@ -136,6 +136,7 @@ const LEGACY_OMX_STATUS_LINE = statusLineForPreset(DEFAULT_STATUS_LINE_PRESET);
136
136
  const OMX_PRESET_STATUS_LINE_VALUES = new Set(Object.keys(STATUS_LINE_PRESETS).map((preset) => statusLineForPreset(preset)));
137
137
  const LEGACY_OMX_TEAM_RUN_TABLE_PATTERN = /^\s*\[mcp_servers\.(?:"omx_team_run"|omx_team_run)\]\s*$/m;
138
138
  const OMX_CONFIG_MARKER = "oh-my-codex (OMX) Configuration";
139
+ const OMX_CONFIG_START_MARKER = `# ${OMX_CONFIG_MARKER}`;
139
140
  const OMX_CONFIG_END_MARKER = "# End oh-my-codex";
140
141
  const CODEX_MODEL_AVAILABILITY_NUX_TABLE_PATTERN = /^\s*\[tui\.model_availability_nux\]\s*(?:#.*)?$/;
141
142
  const TOML_TABLE_HEADER_PATTERN = /^\s*\[\[?[^\]]+\]?\]\s*(?:#.*)?$/;
@@ -793,105 +794,845 @@ export function syncProjectScopeTrustStateFromRuntime(projectConfig, runtimeConf
793
794
  return block;
794
795
  return `${stripped}\n\n${block}`;
795
796
  }
796
- function decodeTomlBasicString(raw) {
797
- try {
798
- const parsed = TOML.parse(`value = "${raw}"`);
799
- return typeof parsed.value === "string" ? parsed.value : undefined;
797
+ function isMultilineTomlString(mode) {
798
+ return mode === "multiline-basic" || mode === "multiline-literal";
799
+ }
800
+ /**
801
+ * Tracks only lexical boundaries needed to safely associate source lines with
802
+ * TOML statements. TOML's parser gives us semantics; this prevents source
803
+ * repair from treating table-like text in a multiline value as syntax.
804
+ */
805
+ function analyzeTomlSource(config) {
806
+ const lines = config.split(/\r?\n/);
807
+ const lineStartsOutsideMultiline = [];
808
+ const lineHasTomlComment = [];
809
+ let mode;
810
+ let isUnambiguous = true;
811
+ for (const line of lines) {
812
+ lineStartsOutsideMultiline.push(!isMultilineTomlString(mode));
813
+ let hasComment = false;
814
+ for (let index = 0; index < line.length; index += 1) {
815
+ const character = line[index];
816
+ if (mode === "basic") {
817
+ if (character === "\\") {
818
+ index += 1;
819
+ }
820
+ else if (character === "\"") {
821
+ mode = undefined;
822
+ }
823
+ continue;
824
+ }
825
+ if (mode === "literal") {
826
+ if (character === "'")
827
+ mode = undefined;
828
+ continue;
829
+ }
830
+ if (mode === "multiline-basic" || mode === "multiline-literal") {
831
+ const delimiter = mode === "multiline-basic" ? "\"" : "'";
832
+ if (mode === "multiline-basic" && character === "\\") {
833
+ index += 1;
834
+ continue;
835
+ }
836
+ if (character !== delimiter)
837
+ continue;
838
+ let runEnd = index + 1;
839
+ while (line[runEnd] === delimiter)
840
+ runEnd += 1;
841
+ if (runEnd - index >= 3) {
842
+ // TOML permits one or two delimiter characters immediately before
843
+ // the closing triple delimiter as string content.
844
+ mode = undefined;
845
+ index = runEnd - 1;
846
+ }
847
+ continue;
848
+ }
849
+ if (character === "#") {
850
+ hasComment = true;
851
+ break;
852
+ }
853
+ if (character !== "\"" && character !== "'")
854
+ continue;
855
+ const isMultiline = line[index + 1] === character && line[index + 2] === character;
856
+ if (isMultiline) {
857
+ mode = character === "\"" ? "multiline-basic" : "multiline-literal";
858
+ index += 2;
859
+ }
860
+ else {
861
+ mode = character === "\"" ? "basic" : "literal";
862
+ }
863
+ }
864
+ lineHasTomlComment.push(hasComment);
865
+ if (mode === "basic" || mode === "literal")
866
+ isUnambiguous = false;
800
867
  }
801
- catch {
868
+ if (isMultilineTomlString(mode))
869
+ isUnambiguous = false;
870
+ return { lines, lineStartsOutsideMultiline, lineHasTomlComment, isUnambiguous };
871
+ }
872
+ function skipTomlSourceWhitespace(line, index) {
873
+ let cursor = index;
874
+ while (line[cursor] === " " || line[cursor] === "\t")
875
+ cursor += 1;
876
+ return cursor;
877
+ }
878
+ function parseTomlSourceKeySegment(line, index) {
879
+ const start = skipTomlSourceWhitespace(line, index);
880
+ const first = line[start];
881
+ if (!first)
802
882
  return undefined;
883
+ if (first !== '"' && first !== "'") {
884
+ const match = /^[A-Za-z0-9_-]+/.exec(line.slice(start));
885
+ if (!match)
886
+ return undefined;
887
+ return { key: match[0], end: start + match[0].length, incomplete: false };
888
+ }
889
+ let cursor = start + 1;
890
+ let escaped = false;
891
+ for (; cursor < line.length; cursor += 1) {
892
+ const character = line[cursor];
893
+ if (first === '"' && escaped) {
894
+ escaped = false;
895
+ continue;
896
+ }
897
+ if (first === '"' && character === "\\") {
898
+ escaped = true;
899
+ continue;
900
+ }
901
+ if (character !== first)
902
+ continue;
903
+ const token = line.slice(start, cursor + 1);
904
+ const parsed = safeParseToml(`${token} = true`);
905
+ const keys = parsed ? Object.keys(parsed) : [];
906
+ const hasKey = keys.length === 1;
907
+ return {
908
+ ...(hasKey ? { key: keys[0] } : {}),
909
+ end: cursor + 1,
910
+ incomplete: !hasKey,
911
+ };
803
912
  }
913
+ return { end: line.length, incomplete: true };
804
914
  }
805
- function parseHooksStateHeader(line) {
806
- const match = line.match(/^\s*\[hooks\.state\."((?:\\.|[^"\\])*)"\]\s*(#.*)?$/);
807
- if (!match)
915
+ function isTomlSourceKey(segment, key) {
916
+ return segment.key === key;
917
+ }
918
+ function findTomlSourceAssignmentSeparator(line) {
919
+ let segment = parseTomlSourceKeySegment(line, 0);
920
+ if (!segment || segment.incomplete)
808
921
  return undefined;
809
- const key = decodeTomlBasicString(match[1] ?? "");
810
- if (key === undefined)
922
+ let cursor = skipTomlSourceWhitespace(line, segment.end);
923
+ while (line[cursor] === ".") {
924
+ segment = parseTomlSourceKeySegment(line, cursor + 1);
925
+ if (!segment || segment.incomplete)
926
+ return undefined;
927
+ cursor = skipTomlSourceWhitespace(line, segment.end);
928
+ }
929
+ return line[cursor] === "=" ? cursor : undefined;
930
+ }
931
+ function advancePastInlineTomlValue(line, index) {
932
+ let braces = 0;
933
+ let brackets = 0;
934
+ let quote;
935
+ let escaped = false;
936
+ for (let cursor = index; cursor < line.length; cursor += 1) {
937
+ const character = line[cursor];
938
+ if (quote) {
939
+ if (quote === '"' && escaped) {
940
+ escaped = false;
941
+ }
942
+ else if (quote === '"' && character === "\\") {
943
+ escaped = true;
944
+ }
945
+ else if (character === quote) {
946
+ quote = undefined;
947
+ }
948
+ continue;
949
+ }
950
+ if (character === '"' || character === "'") {
951
+ quote = character;
952
+ continue;
953
+ }
954
+ if (character === "#")
955
+ return line.length;
956
+ if (character === "{") {
957
+ braces += 1;
958
+ continue;
959
+ }
960
+ if (character === "}") {
961
+ if (braces === 0 && brackets === 0)
962
+ return cursor;
963
+ braces = Math.max(0, braces - 1);
964
+ continue;
965
+ }
966
+ if (character === "[") {
967
+ brackets += 1;
968
+ continue;
969
+ }
970
+ if (character === "]") {
971
+ brackets = Math.max(0, brackets - 1);
972
+ continue;
973
+ }
974
+ if (character === "," && braces === 0 && brackets === 0)
975
+ return cursor + 1;
976
+ }
977
+ return line.length;
978
+ }
979
+ function inlineTomlTableMaySpellStateKey(line, index) {
980
+ let cursor = index;
981
+ while (cursor < line.length) {
982
+ cursor = skipTomlSourceWhitespace(line, cursor);
983
+ // A comment cannot close the surrounding inline table.
984
+ if (line[cursor] === "#")
985
+ return true;
986
+ if (line[cursor] === "}")
987
+ return false;
988
+ const segment = parseTomlSourceKeySegment(line, cursor);
989
+ if (!segment)
990
+ return true;
991
+ if (segment.incomplete || isTomlSourceKey(segment, "state"))
992
+ return true;
993
+ cursor = skipTomlSourceWhitespace(line, segment.end);
994
+ if (line[cursor] !== "=")
995
+ return true;
996
+ cursor = advancePastInlineTomlValue(line, cursor + 1);
997
+ if (line[cursor] === "}")
998
+ return false;
999
+ }
1000
+ // The unclosed inline table can acquire a state member on a following
1001
+ // unparsed line, so it is not safe to strip the containing marker block.
1002
+ return true;
1003
+ }
1004
+ function lineMaySpellHooksState(line) {
1005
+ let cursor = skipTomlSourceWhitespace(line, 0);
1006
+ if (line[cursor] === "[") {
1007
+ if (line[cursor + 1] === "[") {
1008
+ cursor = skipTomlSourceWhitespace(line, cursor + 2);
1009
+ }
1010
+ else {
1011
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1012
+ }
1013
+ }
1014
+ const hooks = parseTomlSourceKeySegment(line, cursor);
1015
+ if (!hooks || !isTomlSourceKey(hooks, "hooks"))
1016
+ return false;
1017
+ cursor = skipTomlSourceWhitespace(line, hooks.end);
1018
+ if (line[cursor] === ".") {
1019
+ const state = parseTomlSourceKeySegment(line, cursor + 1);
1020
+ // A dangling dot can be completed by a following unparsed state key.
1021
+ return state === undefined || state.incomplete || isTomlSourceKey(state, "state");
1022
+ }
1023
+ if (line[cursor] !== "=")
1024
+ return false;
1025
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1026
+ // A bare assignment or comment cannot prove that a following unparsed line
1027
+ // does not continue an inline hooks table with a state member.
1028
+ if (cursor >= line.length || line[cursor] === "#")
1029
+ return true;
1030
+ return line[cursor] === "{" && inlineTomlTableMaySpellStateKey(line, cursor + 1);
1031
+ }
1032
+ /**
1033
+ * Detects a potential array-table opener without accepting malformed spacing
1034
+ * or extra opening brackets as TOML syntax. Array tables rooted at `hooks`
1035
+ * have no proof-owned representation, so their first key segment is enough
1036
+ * to retain a managed marker block rather than strip it.
1037
+ */
1038
+ function parseTomlSourceArrayTableOpener(line) {
1039
+ let cursor = skipTomlSourceWhitespace(line, 0);
1040
+ if (line[cursor] !== "[")
811
1041
  return undefined;
812
- return { key, hasInlineComment: match[2] !== undefined };
1042
+ const hasExactAdjacentOpener = line[cursor + 1] === "[";
1043
+ if (hasExactAdjacentOpener) {
1044
+ cursor += 2;
1045
+ }
1046
+ else {
1047
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1048
+ if (line[cursor] !== "[")
1049
+ return undefined;
1050
+ cursor += 1;
1051
+ }
1052
+ cursor = skipTomlSourceWhitespace(line, cursor);
1053
+ while (line[cursor] === "[") {
1054
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1055
+ }
1056
+ const firstKey = parseTomlSourceKeySegment(line, cursor);
1057
+ return {
1058
+ firstKey,
1059
+ openerOnly: firstKey === undefined &&
1060
+ (cursor >= line.length || line[cursor] === "#"),
1061
+ };
813
1062
  }
814
- function isTomlTableHeader(line) {
815
- return /^\s*\[\[?[^\]]+\]?\]\s*(?:#.*)?$/.test(line);
1063
+ function hasIncompleteTomlSourceHooksKeyPrefix(line) {
1064
+ let cursor = skipTomlSourceWhitespace(line, 0);
1065
+ let tableHeader = false;
1066
+ let arrayTableHeader = false;
1067
+ if (line[cursor] === "[") {
1068
+ tableHeader = true;
1069
+ if (line[cursor + 1] === "[") {
1070
+ arrayTableHeader = true;
1071
+ cursor = skipTomlSourceWhitespace(line, cursor + 2);
1072
+ }
1073
+ else {
1074
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1075
+ }
1076
+ }
1077
+ const hooks = parseTomlSourceKeySegment(line, cursor);
1078
+ if (!hooks || !isTomlSourceKey(hooks, "hooks"))
1079
+ return false;
1080
+ cursor = skipTomlSourceWhitespace(line, hooks.end);
1081
+ if (!tableHeader)
1082
+ return cursor >= line.length || line[cursor] === "#";
1083
+ if (line[cursor] !== "]" || (arrayTableHeader && line[cursor + 1] !== "]")) {
1084
+ return true;
1085
+ }
1086
+ const suffix = line.slice(cursor + (arrayTableHeader ? 2 : 1)).trimStart();
1087
+ return suffix.length > 0 && !suffix.startsWith("#");
1088
+ }
1089
+ function isTomlSourceHooksKeyContinuationSeparator(line) {
1090
+ const cursor = skipTomlSourceWhitespace(line, 0);
1091
+ return line[cursor] === "." || line[cursor] === "=" || line[cursor] === "[";
816
1092
  }
817
- function isExactlyManagedHookTrustBody(bodyLines, expectedHash) {
818
- const nonBlank = bodyLines.filter((line) => line.trim().length > 0);
819
- if (nonBlank.length !== 1)
1093
+ function isTomlSourceBlankOrComment(line) {
1094
+ return /^\s*(?:#.*)?$/.test(line);
1095
+ }
1096
+ function isTomlSourceStandaloneOpeningBracket(line) {
1097
+ const cursor = skipTomlSourceWhitespace(line, 0);
1098
+ if (line[cursor] !== "[")
820
1099
  return false;
821
- const expected = expectedHash.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
822
- return new RegExp(`^\\s*trusted_hash\\s*=\\s*"${expected}"\\s*$`).test(nonBlank[0] ?? "");
1100
+ const next = skipTomlSourceWhitespace(line, cursor + 1);
1101
+ return next >= line.length || line[next] === "#";
1102
+ }
1103
+ function firstTomlSourceKeyFollowingOpeningBrackets(line) {
1104
+ let cursor = skipTomlSourceWhitespace(line, 0);
1105
+ while (line[cursor] === "[") {
1106
+ cursor = skipTomlSourceWhitespace(line, cursor + 1);
1107
+ }
1108
+ return parseTomlSourceKeySegment(line, cursor);
1109
+ }
1110
+ function lineMaySpellStateKey(line) {
1111
+ const state = parseTomlSourceKeySegment(line, 0);
1112
+ return state !== undefined && (state.incomplete || isTomlSourceKey(state, "state"));
1113
+ }
1114
+ function isTomlSourceHooksTableHeader(parsed) {
1115
+ const hooks = parsed?.hooks;
1116
+ return parsed !== undefined &&
1117
+ Object.keys(parsed).length === 1 &&
1118
+ isPlainTomlRecord(hooks) &&
1119
+ Object.keys(hooks).length === 0;
1120
+ }
1121
+ function hasUnprovenManagedMarkerHooksStateSyntax(source, managedMarkerRanges, parsedStatementSpans, parsedAssignmentSpans) {
1122
+ const parsedLines = new Set();
1123
+ const parsedStatementStartLines = new Set();
1124
+ for (const span of parsedStatementSpans) {
1125
+ parsedStatementStartLines.add(span.start);
1126
+ for (let index = span.start; index < span.end; index += 1)
1127
+ parsedLines.add(index);
1128
+ }
1129
+ const parsedAssignmentLines = new Set();
1130
+ for (const span of parsedAssignmentSpans) {
1131
+ for (let index = span.start; index < span.end; index += 1) {
1132
+ parsedAssignmentLines.add(index);
1133
+ }
1134
+ }
1135
+ const managedContentLines = new Set();
1136
+ for (const range of managedMarkerRanges) {
1137
+ for (let index = range.start + 1; index < range.end; index += 1) {
1138
+ managedContentLines.add(index);
1139
+ }
1140
+ }
1141
+ let insideHooksTable = false;
1142
+ let hasIncompleteHooksKeyPrefix = false;
1143
+ let hasIncompleteHooksArrayTableOpener = false;
1144
+ for (let index = 0; index < source.lines.length; index += 1) {
1145
+ if (!source.lineStartsOutsideMultiline[index]) {
1146
+ hasIncompleteHooksKeyPrefix = false;
1147
+ hasIncompleteHooksArrayTableOpener = false;
1148
+ continue;
1149
+ }
1150
+ const line = source.lines[index] ?? "";
1151
+ const isParsedAssignmentLine = parsedAssignmentLines.has(index);
1152
+ if (!isParsedAssignmentLine) {
1153
+ const header = parseTomlSourceTableHeader(line);
1154
+ if (header?.parsed) {
1155
+ insideHooksTable = isTomlSourceHooksTableHeader(header.parsed);
1156
+ }
1157
+ }
1158
+ if (!managedContentLines.has(index)) {
1159
+ hasIncompleteHooksKeyPrefix = false;
1160
+ hasIncompleteHooksArrayTableOpener = false;
1161
+ continue;
1162
+ }
1163
+ const isParsedStatementLine = parsedLines.has(index);
1164
+ const isParsedStatementStartLine = parsedStatementStartLines.has(index);
1165
+ if (hasIncompleteHooksKeyPrefix) {
1166
+ if (isTomlSourceBlankOrComment(line))
1167
+ continue;
1168
+ if (isTomlSourceHooksKeyContinuationSeparator(line))
1169
+ return true;
1170
+ hasIncompleteHooksKeyPrefix = false;
1171
+ }
1172
+ // Parsed statements can contain nested arrays whose standalone brackets and
1173
+ // quoted "hooks" values must not contribute to malformed-header tracking.
1174
+ if (hasIncompleteHooksArrayTableOpener && !isParsedStatementLine) {
1175
+ if (isTomlSourceBlankOrComment(line))
1176
+ continue;
1177
+ const firstKey = firstTomlSourceKeyFollowingOpeningBrackets(line);
1178
+ if (firstKey) {
1179
+ if (isTomlSourceKey(firstKey, "hooks"))
1180
+ return true;
1181
+ hasIncompleteHooksArrayTableOpener = false;
1182
+ }
1183
+ }
1184
+ const arrayTableOpener = !isParsedStatementLine || isParsedStatementStartLine
1185
+ ? parseTomlSourceArrayTableOpener(line)
1186
+ : undefined;
1187
+ if (arrayTableOpener?.firstKey && isTomlSourceKey(arrayTableOpener.firstKey, "hooks")) {
1188
+ return true;
1189
+ }
1190
+ if (arrayTableOpener?.openerOnly && !isParsedStatementLine) {
1191
+ hasIncompleteHooksArrayTableOpener = true;
1192
+ }
1193
+ if (!isParsedStatementLine && isTomlSourceStandaloneOpeningBracket(line)) {
1194
+ hasIncompleteHooksArrayTableOpener = true;
1195
+ }
1196
+ if (isParsedStatementLine)
1197
+ continue;
1198
+ if (lineMaySpellHooksState(line) || (insideHooksTable && lineMaySpellStateKey(line))) {
1199
+ return true;
1200
+ }
1201
+ const hasIncompleteHooksPrefix = hasIncompleteTomlSourceHooksKeyPrefix(line);
1202
+ if (hasIncompleteHooksPrefix && /^\s*\[\[?/.test(line))
1203
+ return true;
1204
+ hasIncompleteHooksKeyPrefix = hasIncompleteHooksPrefix;
1205
+ }
1206
+ return false;
823
1207
  }
824
- function stripProofManagedCodexHookTrustStateTables(config, managedTrustState) {
825
- if (Object.keys(managedTrustState).length === 0) {
826
- return { config, preservedConflictKeys: new Set() };
1208
+ function managedHookTrustStateExpectations(...states) {
1209
+ const expectations = new Map();
1210
+ for (const state of states) {
1211
+ if (!state)
1212
+ continue;
1213
+ for (const [key, entry] of Object.entries(state)) {
1214
+ const hashes = expectations.get(key) ?? new Set();
1215
+ hashes.add(entry.trusted_hash);
1216
+ expectations.set(key, hashes);
1217
+ }
827
1218
  }
828
- const lines = config.split(/\r?\n/);
829
- const kept = [];
830
- const preservedConflictKeys = new Set();
831
- for (let i = 0; i < lines.length;) {
832
- const header = parseHooksStateHeader(lines[i] ?? "");
833
- if (!header) {
834
- kept.push(lines[i]);
835
- i += 1;
1219
+ return expectations;
1220
+ }
1221
+ function managedHookTrustCoordinateFamily(key) {
1222
+ const match = /^(.*):([a-z_]+):\d+:\d+$/.exec(key);
1223
+ return match ? `${match[1]}:${match[2]}` : undefined;
1224
+ }
1225
+ function expectedManagedHookTrustHashes(expectations, key, allowCoordinateDrift) {
1226
+ const exact = expectations.get(key);
1227
+ if (exact || !allowCoordinateDrift)
1228
+ return exact;
1229
+ const family = managedHookTrustCoordinateFamily(key);
1230
+ if (!family)
1231
+ return undefined;
1232
+ const hashes = new Set();
1233
+ for (const [expectedKey, expectedHashes] of expectations) {
1234
+ if (managedHookTrustCoordinateFamily(expectedKey) !== family)
1235
+ continue;
1236
+ for (const hash of expectedHashes)
1237
+ hashes.add(hash);
1238
+ }
1239
+ return hashes.size > 0 ? hashes : undefined;
1240
+ }
1241
+ function tomlHooksStateValue(parsed) {
1242
+ if (!parsed)
1243
+ return undefined;
1244
+ const hooks = parsed.hooks;
1245
+ if (!isPlainTomlRecord(hooks) || !Object.hasOwn(hooks, "state")) {
1246
+ return undefined;
1247
+ }
1248
+ return hooks.state;
1249
+ }
1250
+ function tomlHooksStateEntries(parsed) {
1251
+ const state = tomlHooksStateValue(parsed);
1252
+ return isPlainTomlRecord(state) ? state : undefined;
1253
+ }
1254
+ function hasOnlyManagedHookTrustStateField(parsed, key) {
1255
+ if (!parsed || Object.keys(parsed).length !== 1 || !Object.hasOwn(parsed, "hooks")) {
1256
+ return false;
1257
+ }
1258
+ const hooks = parsed.hooks;
1259
+ if (!isPlainTomlRecord(hooks) || Object.keys(hooks).length !== 1 || !Object.hasOwn(hooks, "state")) {
1260
+ return false;
1261
+ }
1262
+ const state = hooks.state;
1263
+ return isPlainTomlRecord(state) &&
1264
+ Object.keys(state).length === 1 &&
1265
+ Object.hasOwn(state, key);
1266
+ }
1267
+ function parseTomlSourceTableHeader(line) {
1268
+ const start = line.search(/\S/);
1269
+ if (start === -1 || line[start] !== "[")
1270
+ return undefined;
1271
+ const array = line[start + 1] === "[";
1272
+ let quote;
1273
+ let escaped = false;
1274
+ for (let index = start + (array ? 2 : 1); index < line.length; index += 1) {
1275
+ const character = line[index];
1276
+ if (quote === "\"") {
1277
+ if (escaped) {
1278
+ escaped = false;
1279
+ }
1280
+ else if (character === "\\") {
1281
+ escaped = true;
1282
+ }
1283
+ else if (character === quote) {
1284
+ quote = undefined;
1285
+ }
836
1286
  continue;
837
1287
  }
838
- let tableEnd = lines.length;
839
- for (let next = i + 1; next < lines.length; next += 1) {
840
- if (isTomlTableHeader(lines[next] ?? "")) {
841
- tableEnd = next;
842
- break;
1288
+ if (quote === "'") {
1289
+ if (character === quote)
1290
+ quote = undefined;
1291
+ continue;
1292
+ }
1293
+ if (character === "\"" || character === "'") {
1294
+ quote = character;
1295
+ continue;
1296
+ }
1297
+ if (character !== "]")
1298
+ continue;
1299
+ const end = array ? index + 2 : index + 1;
1300
+ if (array && line[index + 1] !== "]")
1301
+ return undefined;
1302
+ const suffix = line.slice(end).trimStart();
1303
+ if (suffix.length > 0 && !suffix.startsWith("#"))
1304
+ return undefined;
1305
+ return { parsed: safeParseToml(line.slice(start, end)) };
1306
+ }
1307
+ return undefined;
1308
+ }
1309
+ function sourceRangeHasTomlComment(source, start, end) {
1310
+ for (let index = start; index < end; index += 1) {
1311
+ if (source.lineHasTomlComment[index])
1312
+ return true;
1313
+ }
1314
+ return false;
1315
+ }
1316
+ function collectMarkerRanges(source, startMarker, endMarker, includeUnterminatedRange = false, inertAssignmentSpans = []) {
1317
+ const isInsideInertAssignment = (line) => inertAssignmentSpans.some((span) => span.start <= line && line < span.end);
1318
+ const ranges = [];
1319
+ for (let start = 0; start < source.lines.length; start += 1) {
1320
+ if (!source.lineStartsOutsideMultiline[start] ||
1321
+ isInsideInertAssignment(start) ||
1322
+ source.lines[start]?.trim() !== startMarker)
1323
+ continue;
1324
+ const end = source.lines.findIndex((line, index) => index > start &&
1325
+ source.lineStartsOutsideMultiline[index] &&
1326
+ !isInsideInertAssignment(index) &&
1327
+ line.trim() === endMarker);
1328
+ const nestedStart = source.lines.findIndex((line, index) => index > start &&
1329
+ source.lineStartsOutsideMultiline[index] &&
1330
+ !isInsideInertAssignment(index) &&
1331
+ line.trim() === startMarker);
1332
+ if (end === -1 || (nestedStart !== -1 && nestedStart < end)) {
1333
+ if (includeUnterminatedRange)
1334
+ ranges.push({ start, end: source.lines.length });
1335
+ continue;
1336
+ }
1337
+ ranges.push({ start, end });
1338
+ start = end;
1339
+ }
1340
+ return ranges;
1341
+ }
1342
+ function recordManagedMarkerHooksStateSourceSpan(spans, invalidSpans, start, end, parsed, insideManagedMarkerBlock) {
1343
+ if (!insideManagedMarkerBlock)
1344
+ return;
1345
+ const state = tomlHooksStateValue(parsed);
1346
+ if (state === undefined)
1347
+ return;
1348
+ const span = { start, end };
1349
+ spans.push(span);
1350
+ if (!isPlainTomlRecord(state) || Object.keys(state).length === 0) {
1351
+ invalidSpans.push(span);
1352
+ }
1353
+ }
1354
+ function addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, start, end, parsed, insideManagedMarkerBlock, containingTableScope, fallbackKeys = []) {
1355
+ recordManagedMarkerHooksStateSourceSpan(markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, start, end, parsed, insideManagedMarkerBlock);
1356
+ const state = tomlHooksStateEntries(parsed);
1357
+ const hasComment = sourceRangeHasTomlComment(source, start, end);
1358
+ if (state) {
1359
+ const stateEntryCount = Object.keys(state).length;
1360
+ for (const [key, value] of Object.entries(state)) {
1361
+ const hasExactSemanticScope = hasOnlyManagedHookTrustStateField(parsed, key) &&
1362
+ (!containingTableScope ||
1363
+ (!containingTableScope.hasComment &&
1364
+ hasOnlyManagedHookTrustStateField(containingTableScope.parsed, key)));
1365
+ const entries = representations.get(key) ?? [];
1366
+ entries.push({
1367
+ start,
1368
+ end,
1369
+ stateEntryCount,
1370
+ value,
1371
+ hasComment,
1372
+ hasExactSemanticScope,
1373
+ insideManagedMarkerBlock,
1374
+ });
1375
+ representations.set(key, entries);
1376
+ }
1377
+ return;
1378
+ }
1379
+ for (const key of fallbackKeys) {
1380
+ const entries = representations.get(key) ?? [];
1381
+ entries.push({
1382
+ start,
1383
+ end,
1384
+ stateEntryCount: 0,
1385
+ value: undefined,
1386
+ hasComment,
1387
+ hasExactSemanticScope: false,
1388
+ insideManagedMarkerBlock,
1389
+ });
1390
+ representations.set(key, entries);
1391
+ }
1392
+ }
1393
+ function collectManagedHookTrustStateSourceRepresentations(config) {
1394
+ const source = analyzeTomlSource(config);
1395
+ const { lines } = source;
1396
+ const parsedAssignmentSpans = [];
1397
+ for (let cursor = 0; cursor < lines.length; cursor += 1) {
1398
+ if (!source.lineStartsOutsideMultiline[cursor])
1399
+ continue;
1400
+ const line = lines[cursor] ?? "";
1401
+ if (findTomlSourceAssignmentSeparator(line) === undefined)
1402
+ continue;
1403
+ for (let statementEnd = cursor + 1; statementEnd <= lines.length; statementEnd += 1) {
1404
+ if (!safeParseToml(lines.slice(cursor, statementEnd).join("\n")))
1405
+ continue;
1406
+ parsedAssignmentSpans.push({ start: cursor, end: statementEnd });
1407
+ cursor = statementEnd - 1;
1408
+ break;
1409
+ }
1410
+ }
1411
+ const headers = [];
1412
+ for (const [index, line] of lines.entries()) {
1413
+ if (!source.lineStartsOutsideMultiline[index])
1414
+ continue;
1415
+ const header = parseTomlSourceTableHeader(line);
1416
+ if (parsedAssignmentSpans.some((span) => span.start < index && index < span.end))
1417
+ continue;
1418
+ if (header)
1419
+ headers.push({ index, header });
1420
+ }
1421
+ const boundaries = new Set(headers.map(({ index }) => index));
1422
+ for (const [index, line] of lines.entries()) {
1423
+ if (source.lineStartsOutsideMultiline[index] &&
1424
+ (line.trim() === OMX_HOOK_TRUST_END_MARKER ||
1425
+ line.trim() === OMX_CONFIG_END_MARKER)) {
1426
+ boundaries.add(index);
1427
+ }
1428
+ }
1429
+ const sortedBoundaries = [...boundaries].sort((left, right) => left - right);
1430
+ const representations = new Map();
1431
+ const markerContainedHooksStateSpans = [];
1432
+ const invalidMarkerContainedHooksStateSpans = [];
1433
+ const parsedStatementSpans = [];
1434
+ const managedMarkerRanges = [
1435
+ ...collectMarkerRanges(source, OMX_HOOK_TRUST_START_MARKER, OMX_HOOK_TRUST_END_MARKER, false, parsedAssignmentSpans),
1436
+ ...collectMarkerRanges(source, OMX_CONFIG_START_MARKER, OMX_CONFIG_END_MARKER, true, parsedAssignmentSpans),
1437
+ ];
1438
+ const isInsideManagedMarkerBlock = (start, end) => managedMarkerRanges.some((range) => start > range.start && end <= range.end);
1439
+ const collectAssignments = (start, end, prefix, containingTableScope) => {
1440
+ for (let cursor = start; cursor < end;) {
1441
+ const line = lines[cursor] ?? "";
1442
+ if (!source.lineStartsOutsideMultiline[cursor] ||
1443
+ line.trim().length === 0 ||
1444
+ line.trim() === OMX_HOOK_TRUST_START_MARKER ||
1445
+ line.trim() === OMX_CONFIG_START_MARKER) {
1446
+ cursor += 1;
1447
+ continue;
843
1448
  }
1449
+ let parsed;
1450
+ let statementEnd = cursor + 1;
1451
+ for (; statementEnd <= end; statementEnd += 1) {
1452
+ const statement = lines.slice(cursor, statementEnd).join("\n");
1453
+ parsed = safeParseToml(prefix ? `${prefix}\n${statement}` : statement);
1454
+ if (parsed)
1455
+ break;
1456
+ }
1457
+ if (!parsed) {
1458
+ cursor += 1;
1459
+ continue;
1460
+ }
1461
+ parsedStatementSpans.push({ start: cursor, end: statementEnd });
1462
+ addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, cursor, statementEnd, parsed, isInsideManagedMarkerBlock(cursor, statementEnd), containingTableScope);
1463
+ cursor = statementEnd;
844
1464
  }
845
- const expectedState = managedTrustState[header.key];
846
- const removable = expectedState !== undefined &&
847
- !header.hasInlineComment &&
848
- isExactlyManagedHookTrustBody(lines.slice(i + 1, tableEnd), expectedState.trusted_hash);
849
- if (removable) {
850
- i = tableEnd;
1465
+ };
1466
+ const rootEnd = sortedBoundaries[0] ?? lines.length;
1467
+ collectAssignments(0, rootEnd, undefined);
1468
+ for (const { index, header } of headers) {
1469
+ const boundaryIndex = sortedBoundaries.findIndex((boundary) => boundary === index);
1470
+ const end = boundaryIndex === -1
1471
+ ? lines.length
1472
+ : (sortedBoundaries[boundaryIndex + 1] ?? lines.length);
1473
+ const tableScope = {
1474
+ parsed: safeParseToml(lines.slice(index, end).join("\n")),
1475
+ hasComment: sourceRangeHasTomlComment(source, index, end),
1476
+ };
1477
+ if (tableScope.parsed)
1478
+ parsedStatementSpans.push({ start: index, end });
1479
+ const insideManagedMarkerBlock = isInsideManagedMarkerBlock(index, end);
1480
+ recordManagedMarkerHooksStateSourceSpan(markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, index, end, tableScope.parsed, insideManagedMarkerBlock);
1481
+ const headerState = tomlHooksStateEntries(header.parsed);
1482
+ const directKeys = Object.keys(headerState ?? {});
1483
+ if (directKeys.length > 0) {
1484
+ addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, index, end, tableScope.parsed, insideManagedMarkerBlock, undefined, directKeys);
851
1485
  continue;
852
1486
  }
853
- if (expectedState !== undefined) {
854
- preservedConflictKeys.add(header.key);
1487
+ collectAssignments(index + 1, end, lines[index], tableScope);
1488
+ }
1489
+ return {
1490
+ source,
1491
+ representations,
1492
+ managedMarkerRanges,
1493
+ markerContainedHooksStateSpans,
1494
+ invalidMarkerContainedHooksStateSpans,
1495
+ parsedStatementSpans,
1496
+ parsedAssignmentSpans,
1497
+ };
1498
+ }
1499
+ function isExactlyManagedHookTrustStateValue(value, expectedHashes) {
1500
+ return isPlainTomlRecord(value) &&
1501
+ Object.keys(value).length === 1 &&
1502
+ Object.hasOwn(value, "trusted_hash") &&
1503
+ typeof value.trusted_hash === "string" &&
1504
+ expectedHashes.has(value.trusted_hash);
1505
+ }
1506
+ function managedMarkerTrustStateConflicts(source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, expectations) {
1507
+ const conflicts = new Set();
1508
+ const isInsideManagedMarkerRange = (span) => managedMarkerRanges.some((range) => span.start > range.start && span.end <= range.end);
1509
+ if (invalidMarkerContainedHooksStateSpans.some(isInsideManagedMarkerRange) ||
1510
+ hasUnprovenManagedMarkerHooksStateSyntax(source, managedMarkerRanges, [...markerContainedHooksStateSpans, ...parsedStatementSpans], parsedAssignmentSpans)) {
1511
+ conflicts.add("marker-contained hooks.state");
1512
+ }
1513
+ for (const [key, sourceRepresentations] of representations) {
1514
+ for (const representation of sourceRepresentations) {
1515
+ if (!isInsideManagedMarkerRange(representation))
1516
+ continue;
1517
+ const expectedHashes = expectedManagedHookTrustHashes(expectations, key, true);
1518
+ const isExactOwnedRepresentation = expectedHashes !== undefined &&
1519
+ representation.stateEntryCount === 1 &&
1520
+ !representation.hasComment &&
1521
+ representation.hasExactSemanticScope &&
1522
+ isExactlyManagedHookTrustStateValue(representation.value, expectedHashes);
1523
+ if (!source.isUnambiguous || !isExactOwnedRepresentation)
1524
+ conflicts.add(key);
855
1525
  }
856
- kept.push(...lines.slice(i, tableEnd));
857
- i = tableEnd;
858
1526
  }
859
- return { config: kept.join("\n"), preservedConflictKeys };
1527
+ return conflicts;
860
1528
  }
861
- function stripManagedCodexHookTrustStateWithResult(config, options = {}) {
862
- const lines = config.split(/\r?\n/);
863
- const kept = [];
864
- for (let i = 0; i < lines.length;) {
865
- const trimmed = lines[i].trim();
866
- if (trimmed !== OMX_HOOK_TRUST_START_MARKER) {
867
- kept.push(lines[i]);
868
- i += 1;
1529
+ function removeEmptyManagedHookTrustStateMarkerBlocks(source, removed) {
1530
+ const { lines } = source;
1531
+ for (let start = 0; start < lines.length; start += 1) {
1532
+ if (!source.lineStartsOutsideMultiline[start] ||
1533
+ lines[start]?.trim() !== OMX_HOOK_TRUST_START_MARKER)
1534
+ continue;
1535
+ const end = lines.findIndex((line, index) => index > start &&
1536
+ source.lineStartsOutsideMultiline[index] &&
1537
+ line.trim() === OMX_HOOK_TRUST_END_MARKER);
1538
+ const nestedStart = lines.findIndex((line, index) => index > start &&
1539
+ source.lineStartsOutsideMultiline[index] &&
1540
+ line.trim() === OMX_HOOK_TRUST_START_MARKER);
1541
+ if (end === -1 || (nestedStart !== -1 && nestedStart < end))
869
1542
  continue;
1543
+ let onlyOwnedMarkerContent = true;
1544
+ for (let index = start + 1; index < end; index += 1) {
1545
+ const trimmed = lines[index].trim();
1546
+ if (removed.has(index) ||
1547
+ trimmed.length === 0 ||
1548
+ trimmed === "# Trusts only setup-managed native hook wrappers.")
1549
+ continue;
1550
+ onlyOwnedMarkerContent = false;
1551
+ break;
870
1552
  }
871
- const nextEndIdx = lines.findIndex((line, index) => index > i && line.trim() === OMX_HOOK_TRUST_END_MARKER);
872
- const nextStartIdx = lines.findIndex((line, index) => index > i && line.trim() === OMX_HOOK_TRUST_START_MARKER);
873
- if (nextEndIdx === -1 || (nextStartIdx !== -1 && nextStartIdx < nextEndIdx)) {
874
- kept.push(lines[i]);
875
- i += 1;
1553
+ if (!onlyOwnedMarkerContent)
876
1554
  continue;
1555
+ removed.add(start);
1556
+ removed.add(end);
1557
+ for (let index = start + 1; index < end; index += 1) {
1558
+ if (lines[index]?.trim() === "# Trusts only setup-managed native hook wrappers.") {
1559
+ removed.add(index);
1560
+ }
877
1561
  }
878
- i = nextEndIdx + 1;
1562
+ start = end;
1563
+ }
1564
+ }
1565
+ function stripProofManagedCodexHookTrustStateTables(config, expectations) {
1566
+ const { source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, } = collectManagedHookTrustStateSourceRepresentations(config);
1567
+ const preservedConflictKeys = managedMarkerTrustStateConflicts(source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, expectations);
1568
+ if (!source.isUnambiguous) {
1569
+ return { config, preservedConflictKeys };
879
1570
  }
880
- const withoutFenced = kept.join("\n");
881
- const proofStripped = options.managedTrustState
882
- ? stripProofManagedCodexHookTrustStateTables(withoutFenced, options.managedTrustState)
883
- : { config: withoutFenced, preservedConflictKeys: new Set() };
1571
+ const { lines } = source;
1572
+ const removals = new Map();
1573
+ const parsedConfigState = tomlHooksStateEntries(safeParseToml(config));
1574
+ for (const key of Object.keys(parsedConfigState ?? {})) {
1575
+ if (expectations.has(key) && !representations.has(key)) {
1576
+ preservedConflictKeys.add(key);
1577
+ }
1578
+ }
1579
+ for (const [key, sourceRepresentations] of representations) {
1580
+ const isExactOwnedRepresentation = (representation) => {
1581
+ const expectedHashes = expectedManagedHookTrustHashes(expectations, key, representation.insideManagedMarkerBlock);
1582
+ return expectedHashes !== undefined &&
1583
+ representation.stateEntryCount === 1 &&
1584
+ !representation.hasComment &&
1585
+ representation.hasExactSemanticScope &&
1586
+ isExactlyManagedHookTrustStateValue(representation.value, expectedHashes);
1587
+ };
1588
+ if (!sourceRepresentations.some((representation) => expectedManagedHookTrustHashes(expectations, key, representation.insideManagedMarkerBlock) !== undefined))
1589
+ continue;
1590
+ const mayRemoveAll = sourceRepresentations.length === 1
1591
+ ? isExactOwnedRepresentation(sourceRepresentations[0])
1592
+ : sourceRepresentations.every((representation) => representation.insideManagedMarkerBlock &&
1593
+ isExactOwnedRepresentation(representation));
1594
+ if (!mayRemoveAll) {
1595
+ preservedConflictKeys.add(key);
1596
+ continue;
1597
+ }
1598
+ for (const representation of sourceRepresentations) {
1599
+ removals.set(`${representation.start}:${representation.end}`, {
1600
+ start: representation.start,
1601
+ end: representation.end,
1602
+ });
1603
+ }
1604
+ }
1605
+ if (removals.size === 0) {
1606
+ return { config, preservedConflictKeys };
1607
+ }
1608
+ const removed = new Set();
1609
+ for (const range of removals.values()) {
1610
+ for (let index = range.start; index < range.end; index += 1) {
1611
+ removed.add(index);
1612
+ }
1613
+ }
1614
+ removeEmptyManagedHookTrustStateMarkerBlocks(source, removed);
884
1615
  return {
885
- config: proofStripped.config.replace(/\n{3,}/g, "\n\n").trimEnd(),
886
- preservedConflictKeys: proofStripped.preservedConflictKeys,
1616
+ config: lines.filter((_, index) => !removed.has(index)).join("\n").trimEnd(),
1617
+ preservedConflictKeys,
887
1618
  };
888
1619
  }
1620
+ function stripManagedCodexHookTrustStateForRefresh(config, priorManagedTrustState, finalManagedTrustState) {
1621
+ return stripProofManagedCodexHookTrustStateTables(config, managedHookTrustStateExpectations(priorManagedTrustState, finalManagedTrustState));
1622
+ }
1623
+ function rejectManagedCodexHookTrustStateConflicts(conflicts) {
1624
+ if (conflicts.size === 0)
1625
+ return;
1626
+ const keys = [...conflicts].sort((left, right) => left.localeCompare(right));
1627
+ throw new ManagedCodexHooksPlanError("managed_trust_key_conflict", `Refusing to replace existing Codex hook trust state for ${keys.join(", ")}. Remove or reconcile the conflicting [hooks.state] entry before running setup.`, { keys });
1628
+ }
889
1629
  export function stripManagedCodexHookTrustState(config, options = {}) {
890
- return stripManagedCodexHookTrustStateWithResult(config, options).config;
1630
+ const stripped = stripManagedCodexHookTrustStateForRefresh(config, options.priorManagedHookTrustState, options.managedTrustState ?? {});
1631
+ rejectManagedCodexHookTrustStateConflicts(stripped.preservedConflictKeys);
1632
+ return stripped.config;
891
1633
  }
892
- function renderManagedCodexHookTrustToml(managedTrustState, excludedKeys = new Set()) {
1634
+ function renderManagedCodexHookTrustToml(managedTrustState) {
893
1635
  return Object.entries(managedTrustState)
894
- .filter(([key]) => !excludedKeys.has(key))
895
1636
  .sort(([left], [right]) => left.localeCompare(right))
896
1637
  .flatMap(([key, hookState]) => [
897
1638
  `[hooks.state."${escapeTomlBasicString(key)}"]`,
@@ -901,21 +1642,92 @@ function renderManagedCodexHookTrustToml(managedTrustState, excludedKeys = new S
901
1642
  .join("\n")
902
1643
  .trimEnd();
903
1644
  }
904
- function buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options = {}) {
1645
+ function identicalLegacyHookTrustStateEntry(existing, expected) {
1646
+ if (!isPlainTomlRecord(existing))
1647
+ return false;
1648
+ if (!Object.hasOwn(existing, "trusted_hash") ||
1649
+ typeof existing.trusted_hash !== "string" ||
1650
+ existing.trusted_hash !== expected.trusted_hash ||
1651
+ Object.keys(existing).some((key) => key !== "trusted_hash" && key !== "enabled")) {
1652
+ return false;
1653
+ }
1654
+ return Object.hasOwn(existing, "enabled") === Object.hasOwn(expected, "enabled") &&
1655
+ existing.enabled === expected.enabled;
1656
+ }
1657
+ function legacyHookTrustStateConflict(keys, reason) {
1658
+ throw new ManagedCodexHooksPlanError("managed_trust_key_conflict", `Refusing to migrate legacy Codex hook trust state into conflicting config.toml entries for ${keys.join(", ")}.`, { keys: [...keys], ...(reason ? { reason } : {}) });
1659
+ }
1660
+ function appendLegacyHookTrustState(config, legacyTrustState) {
1661
+ if (!legacyTrustState || Object.keys(legacyTrustState).length === 0) {
1662
+ return config;
1663
+ }
1664
+ const parsed = safeParseToml(config);
1665
+ const keys = Object.keys(legacyTrustState).sort((left, right) => left.localeCompare(right));
1666
+ if (!parsed)
1667
+ legacyHookTrustStateConflict(keys, "config_parse_failure");
1668
+ const hooks = parsed.hooks;
1669
+ if (hooks !== undefined && !isPlainTomlRecord(hooks)) {
1670
+ legacyHookTrustStateConflict(keys, "hooks_table_invalid");
1671
+ }
1672
+ const hookState = isPlainTomlRecord(hooks) ? hooks.state : undefined;
1673
+ if (hookState !== undefined && !isPlainTomlRecord(hookState)) {
1674
+ legacyHookTrustStateConflict(keys, "hooks_state_table_invalid");
1675
+ }
1676
+ const existingTrustState = isPlainTomlRecord(hookState) ? hookState : {};
1677
+ const entriesToAppend = Object.entries(legacyTrustState)
1678
+ .filter(([key]) => !Object.hasOwn(existingTrustState, key));
1679
+ const conflictingKeys = Object.entries(legacyTrustState)
1680
+ .filter(([key, expected]) => Object.hasOwn(existingTrustState, key) &&
1681
+ !identicalLegacyHookTrustStateEntry(existingTrustState[key], expected))
1682
+ .map(([key]) => key)
1683
+ .sort((left, right) => left.localeCompare(right));
1684
+ if (conflictingKeys.length > 0)
1685
+ legacyHookTrustStateConflict(conflictingKeys);
1686
+ const trustToml = entriesToAppend
1687
+ .sort(([left], [right]) => left.localeCompare(right))
1688
+ .flatMap(([key, state]) => [
1689
+ `[hooks.state."${escapeTomlBasicString(key)}"]`,
1690
+ `trusted_hash = "${escapeTomlBasicString(state.trusted_hash)}"`,
1691
+ ...(typeof state.enabled === "boolean" ? [`enabled = ${state.enabled}`] : []),
1692
+ "",
1693
+ ])
1694
+ .join("\n")
1695
+ .trimEnd();
1696
+ if (!trustToml)
1697
+ return config;
1698
+ const base = config.trimEnd();
1699
+ return [
1700
+ base,
1701
+ base ? "" : null,
1702
+ "# Migrated from legacy hooks.json state; kept in Codex config.toml because Codex 0.140 rejects top-level hooks.json state.",
1703
+ trustToml,
1704
+ "",
1705
+ ].filter((line) => line !== null).join("\n");
1706
+ }
1707
+ function managedCodexHookOptionsFromMergeOptions(options) {
1708
+ return {
1709
+ codexHomeDir: options.codexHomeDir,
1710
+ platform: options.hookCommandPlatform,
1711
+ hooksContent: options.codexHooksContent,
1712
+ };
1713
+ }
1714
+ function buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options = {}, precomputedTrustState) {
1715
+ if (precomputedTrustState)
1716
+ return precomputedTrustState;
905
1717
  if (!codexHooksFile)
906
1718
  return {};
907
1719
  return buildManagedCodexHookTrustState(codexHooksFile, pkgRoot, options);
908
1720
  }
909
1721
  export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile, options = {}) {
910
- const managedTrustState = buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options);
911
- const strippedResult = stripManagedCodexHookTrustStateWithResult(config, {
912
- managedTrustState,
913
- });
914
- const stripped = strippedResult.config;
915
- const hookTrustToml = renderManagedCodexHookTrustToml(managedTrustState, strippedResult.preservedConflictKeys);
916
- if (!hookTrustToml)
917
- return `${stripped}\n`;
918
- return [
1722
+ const managedTrustState = buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options, options.managedTrustState);
1723
+ const strippedResult = stripManagedCodexHookTrustStateForRefresh(config, options.priorManagedHookTrustState, managedTrustState);
1724
+ rejectManagedCodexHookTrustStateConflicts(strippedResult.preservedConflictKeys);
1725
+ const stripped = strippedResult.config.trimEnd();
1726
+ const hookTrustToml = renderManagedCodexHookTrustToml(managedTrustState);
1727
+ if (!hookTrustToml) {
1728
+ return appendLegacyHookTrustState(`${stripped}\n`, options.legacyHookTrustState);
1729
+ }
1730
+ return appendLegacyHookTrustState([
919
1731
  stripped,
920
1732
  "",
921
1733
  OMX_HOOK_TRUST_START_MARKER,
@@ -923,7 +1735,7 @@ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile
923
1735
  hookTrustToml,
924
1736
  OMX_HOOK_TRUST_END_MARKER,
925
1737
  "",
926
- ].filter((line, index) => index !== 0 || line.length > 0).join("\n");
1738
+ ].filter((line, index) => index !== 0 || line.length > 0).join("\n"), options.legacyHookTrustState);
927
1739
  }
928
1740
  export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG, options = {}) {
929
1741
  const lines = config.split(/\r?\n/);
@@ -936,6 +1748,9 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
936
1748
  const featureBlock = [
937
1749
  "[features]",
938
1750
  hookFeatureFlagLine,
1751
+ ...(options.pluginScopedHooks && options.preserveNativeHooks
1752
+ ? [formatCodexHookFeatureFlagLine(codexHookFeatureFlag)]
1753
+ : []),
939
1754
  "goals = true",
940
1755
  "",
941
1756
  ].join("\n");
@@ -959,9 +1774,15 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
959
1774
  sectionEnd -= 1;
960
1775
  }
961
1776
  }
962
- ({ sectionEnd } = options.pluginScopedHooks
963
- ? upsertPluginScopedHookFeatureFlagInSection(lines, featuresStart, sectionEnd)
964
- : upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
1777
+ if (options.pluginScopedHooks) {
1778
+ ({ sectionEnd } = upsertPluginScopedHookFeatureFlagInSection(lines, featuresStart, sectionEnd));
1779
+ if (options.preserveNativeHooks) {
1780
+ ({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
1781
+ }
1782
+ }
1783
+ else {
1784
+ ({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
1785
+ }
965
1786
  let goalsIdx = -1;
966
1787
  for (let i = featuresStart + 1; i < sectionEnd; i++) {
967
1788
  if (/^\s*goals\s*=/.test(lines[i])) {
@@ -1425,35 +2246,45 @@ function upsertTuiStatusLine(config, preset = DEFAULT_STATUS_LINE_PRESET, option
1425
2246
  // ---------------------------------------------------------------------------
1426
2247
  // OMX [table] sections block (appended at end of file)
1427
2248
  // ---------------------------------------------------------------------------
1428
- export function stripExistingOmxBlocks(config) {
1429
- let cleaned = config;
1430
- let removed = 0;
1431
- while (true) {
1432
- const markerIdx = cleaned.indexOf(OMX_CONFIG_MARKER);
1433
- if (markerIdx < 0)
1434
- break;
1435
- let blockStart = cleaned.lastIndexOf("\n", markerIdx);
1436
- blockStart = blockStart >= 0 ? blockStart + 1 : 0;
1437
- const previousLineEnd = blockStart - 1;
1438
- if (previousLineEnd >= 0) {
1439
- const previousLineStart = cleaned.lastIndexOf("\n", previousLineEnd - 1);
1440
- const previousLine = cleaned.slice(previousLineStart + 1, previousLineEnd);
1441
- if (/^# =+$/.test(previousLine.trim())) {
1442
- blockStart = previousLineStart >= 0 ? previousLineStart + 1 : 0;
1443
- }
1444
- }
1445
- let blockEnd = cleaned.length;
1446
- const endIdx = cleaned.indexOf(OMX_CONFIG_END_MARKER, markerIdx);
1447
- if (endIdx >= 0) {
1448
- const endLineBreak = cleaned.indexOf("\n", endIdx);
1449
- blockEnd = endLineBreak >= 0 ? endLineBreak + 1 : cleaned.length;
1450
- }
1451
- const before = cleaned.slice(0, blockStart).trimEnd();
1452
- const after = cleaned.slice(blockEnd).trimStart();
1453
- cleaned = [before, after].filter(Boolean).join("\n\n");
1454
- removed += 1;
1455
- }
1456
- return { cleaned, removed };
2249
+ export function stripExistingOmxBlocks(config, options = {}) {
2250
+ const inventory = collectManagedHookTrustStateSourceRepresentations(config);
2251
+ const { source } = inventory;
2252
+ const markerRanges = collectMarkerRanges(source, OMX_CONFIG_START_MARKER, OMX_CONFIG_END_MARKER, false, inventory.parsedAssignmentSpans);
2253
+ if (markerRanges.length === 0)
2254
+ return { cleaned: config, removed: 0 };
2255
+ const conflicts = managedMarkerTrustStateConflicts(source, inventory.representations, markerRanges, inventory.markerContainedHooksStateSpans, inventory.invalidMarkerContainedHooksStateSpans, inventory.parsedStatementSpans, inventory.parsedAssignmentSpans, managedHookTrustStateExpectations(options.priorManagedHookTrustState, options.managedTrustState));
2256
+ rejectManagedCodexHookTrustStateConflicts(conflicts);
2257
+ if (!source.isUnambiguous)
2258
+ return { cleaned: config, removed: 0 };
2259
+ const lines = sourceLines(config);
2260
+ if (markerRanges.some((range) => !lines[range.start] || !lines[range.end])) {
2261
+ return { cleaned: config, removed: 0 };
2262
+ }
2263
+ const removalRanges = markerRanges.map((range) => {
2264
+ const startLine = lines[range.start];
2265
+ const endLine = lines[range.end];
2266
+ const previousLine = lines[range.start - 1];
2267
+ const start = previousLine && /^# =+$/.test(previousLine.content.trim())
2268
+ ? previousLine.start
2269
+ : startLine.start;
2270
+ return { start, end: endLine.end };
2271
+ });
2272
+ const segments = [];
2273
+ let cursor = 0;
2274
+ for (const range of removalRanges) {
2275
+ segments.push(config.slice(cursor, range.start));
2276
+ cursor = range.end;
2277
+ }
2278
+ segments.push(config.slice(cursor));
2279
+ const cleaned = segments
2280
+ .map((segment, index) => index === 0
2281
+ ? segment.trimEnd()
2282
+ : index === segments.length - 1
2283
+ ? segment.trimStart()
2284
+ : segment.trim())
2285
+ .filter(Boolean)
2286
+ .join("\n\n");
2287
+ return { cleaned, removed: markerRanges.length };
1457
2288
  }
1458
2289
  export function stripExistingSharedMcpRegistryBlock(config) {
1459
2290
  let cleaned = config;
@@ -1688,7 +2519,7 @@ export function mergeSharedMcpRegistryBlock(config, servers, sourcePath) {
1688
2519
  * OMX table-section block (MCP servers, TUI).
1689
2520
  * Contains ONLY [table] sections — no bare keys.
1690
2521
  */
1691
- function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, hookOptions = {}, includeFirstPartyMcp = false, excludedHookTrustStateKeys = new Set()) {
2522
+ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, hookOptions = {}, managedHookTrustState, includeFirstPartyMcp = false) {
1692
2523
  const lines = [
1693
2524
  "",
1694
2525
  "# ============================================================",
@@ -1711,7 +2542,7 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
1711
2542
  }
1712
2543
  }
1713
2544
  }
1714
- const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions), excludedHookTrustStateKeys);
2545
+ const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions, managedHookTrustState));
1715
2546
  if (hookTrustToml) {
1716
2547
  lines.push("");
1717
2548
  lines.push("# OMX-owned Codex hook trust state");
@@ -1750,6 +2581,10 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
1750
2581
  */
1751
2582
  export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1752
2583
  let existing = stripOmxSeededBehavioralDefaults(existingConfig);
2584
+ const hookOptions = managedCodexHookOptionsFromMergeOptions(options);
2585
+ const managedTrustState = buildManagedCodexHookTrustStateForConfig(options.codexHooksFile, pkgRoot, hookOptions, options.managedHookTrustState);
2586
+ const preflightHookTrustStrip = stripManagedCodexHookTrustStateForRefresh(existing, options.priorManagedHookTrustState, managedTrustState);
2587
+ rejectManagedCodexHookTrustStateConflicts(preflightHookTrustStrip.preservedConflictKeys);
1753
2588
  const preservedFirstPartyMcpSections = options.preserveExistingFirstPartyMcp === true &&
1754
2589
  options.includeFirstPartyMcp !== true
1755
2590
  ? extractFirstPartyOmxMcpSections(existing)
@@ -1758,7 +2593,10 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1758
2593
  const statusLinePreset = options.statusLinePreset ?? DEFAULT_STATUS_LINE_PRESET;
1759
2594
  const customizedManagedTuiSections = extractCustomizedTuiSectionsFromOmxBlocks(existing);
1760
2595
  if (existing.includes(OMX_CONFIG_MARKER)) {
1761
- const stripped = stripExistingOmxBlocks(existing);
2596
+ const stripped = stripExistingOmxBlocks(existing, {
2597
+ managedTrustState,
2598
+ priorManagedHookTrustState: options.priorManagedHookTrustState,
2599
+ });
1762
2600
  existing = stripped.cleaned;
1763
2601
  if (customizedManagedTuiSections.length > 0) {
1764
2602
  existing = `${existing.trimEnd()}\n\n${customizedManagedTuiSections.join("\n\n")}\n`;
@@ -1777,13 +2615,8 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1777
2615
  existing = `${`notify = ${formatTomlStringArray(userNotifyToPreserve)}`}\n${existing.trimStart()}`;
1778
2616
  }
1779
2617
  existing = stripOrphanedManagedNotify(existing, pkgRoot).trimStart();
1780
- const managedTrustState = buildManagedCodexHookTrustStateForConfig(options.codexHooksFile, pkgRoot, {
1781
- codexHomeDir: options.codexHomeDir,
1782
- platform: options.hookCommandPlatform,
1783
- });
1784
- const hookTrustStrip = stripManagedCodexHookTrustStateWithResult(existing, {
1785
- managedTrustState,
1786
- });
2618
+ const hookTrustStrip = stripManagedCodexHookTrustStateForRefresh(existing, options.priorManagedHookTrustState, managedTrustState);
2619
+ rejectManagedCodexHookTrustStateConflicts(hookTrustStrip.preservedConflictKeys);
1787
2620
  existing = hookTrustStrip.config;
1788
2621
  if (options.modelOverride) {
1789
2622
  existing = stripRootLevelKeys(existing, ["model"]);
@@ -1803,17 +2636,15 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1803
2636
  const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
1804
2637
  ? getDefaultNotifyCommand(pkgRoot)
1805
2638
  : options.notifyCommand);
1806
- const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, {
1807
- codexHomeDir: options.codexHomeDir,
1808
- platform: options.hookCommandPlatform,
1809
- }, options.includeFirstPartyMcp === true, hookTrustStrip.preservedConflictKeys);
2639
+ const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, hookOptions, managedTrustState, options.includeFirstPartyMcp === true);
1810
2640
  const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
1811
2641
  let body = existing.trim();
1812
2642
  if (sharedRegistryBlock) {
1813
2643
  body = body ? `${body}\n\n${sharedRegistryBlock}` : sharedRegistryBlock;
1814
2644
  }
1815
2645
  const bodySeparator = body.length > 0 && !/^\s*\[/.test(body) ? "\n" : "\n\n";
1816
- return addDefaultLauncherMcpStartupTimeouts(topLines.join("\n") + bodySeparator + body + "\n" + tablesBlock);
2646
+ const merged = addDefaultLauncherMcpStartupTimeouts(topLines.join("\n") + bodySeparator + body + "\n" + tablesBlock);
2647
+ return appendLegacyHookTrustState(merged, options.legacyHookTrustState);
1817
2648
  }
1818
2649
  /**
1819
2650
  * Detect and repair upgrade-era managed config incompatibilities in config.toml.
@@ -1826,6 +2657,33 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
1826
2657
  *
1827
2658
  * Returns `true` if a repair was performed.
1828
2659
  */
2660
+ function managedHookTrustProofRequiredForRepair(config) {
2661
+ const inventory = collectManagedHookTrustStateSourceRepresentations(config);
2662
+ return managedMarkerTrustStateConflicts(inventory.source, inventory.representations, inventory.managedMarkerRanges, inventory.markerContainedHooksStateSpans, inventory.invalidMarkerContainedHooksStateSpans, inventory.parsedStatementSpans, inventory.parsedAssignmentSpans, managedHookTrustStateExpectations()).size > 0;
2663
+ }
2664
+ async function launchRepairOptionsWithManagedHookTrustProof(configPath, config, options) {
2665
+ if (!managedHookTrustProofRequiredForRepair(config)) {
2666
+ return options;
2667
+ }
2668
+ const hooksPath = options.codexHooksFile ?? resolve(configPath, "..", "hooks.json");
2669
+ let hooksContent;
2670
+ try {
2671
+ hooksContent = await readFile(hooksPath, "utf-8");
2672
+ }
2673
+ catch (error) {
2674
+ throw new ManagedCodexHooksPlanError("invalid_document", `Cannot safely repair config.toml because the current hooks artifact at ${hooksPath} could not be read.`, { cause: String(error), hooksPath });
2675
+ }
2676
+ const trustScan = scanManagedCodexHookTrustStateFromContent(hooksContent, hooksPath, managedCodexHookOptionsFromMergeOptions(options));
2677
+ if (!trustScan.ok)
2678
+ throw trustScan.error;
2679
+ return {
2680
+ ...options,
2681
+ codexHooksFile: hooksPath,
2682
+ codexHooksContent: hooksContent,
2683
+ managedHookTrustState: trustScan.trustState,
2684
+ priorManagedHookTrustState: trustScan.trustState,
2685
+ };
2686
+ }
1829
2687
  export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
1830
2688
  if (!existsSync(configPath))
1831
2689
  return false;
@@ -1835,8 +2693,10 @@ export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
1835
2693
  const hasLauncherTimeoutGap = findLauncherTimeoutRepairTargets(content).length > 0;
1836
2694
  if (tuiCount <= 1 && !hasLegacyTeamRunTable && !hasLauncherTimeoutGap)
1837
2695
  return false;
1838
- // Managed config compatibility issue detected — run full merge to repair
1839
- const repaired = buildMergedConfig(content, pkgRoot, options);
2696
+ // Managed config compatibility issue detected — derive proof from the current
2697
+ // hooks artifact before any marker stripping can replace managed trust state.
2698
+ const repairOptions = await launchRepairOptionsWithManagedHookTrustProof(configPath, content, options);
2699
+ const repaired = buildMergedConfig(content, pkgRoot, repairOptions);
1840
2700
  if (repaired === content)
1841
2701
  return false;
1842
2702
  await writeFile(configPath, repaired);
@@ -1847,12 +2707,6 @@ export async function mergeConfig(configPath, pkgRoot, options = {}) {
1847
2707
  if (existsSync(configPath)) {
1848
2708
  existing = await readFile(configPath, "utf-8");
1849
2709
  }
1850
- if (existing.includes("oh-my-codex (OMX) Configuration")) {
1851
- const stripped = stripExistingOmxBlocks(existing);
1852
- if (options.verbose && stripped.removed > 0) {
1853
- console.log(" Updating existing OMX config block.");
1854
- }
1855
- }
1856
2710
  const finalConfig = buildMergedConfig(existing, pkgRoot, options);
1857
2711
  await writeFile(configPath, finalConfig);
1858
2712
  if (options.verbose) {