oh-my-codex 0.20.1 → 0.20.3

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 (791) hide show
  1. package/Cargo.lock +7 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +36 -1
  4. package/crates/omx-runtime/Cargo.toml +1 -0
  5. package/crates/omx-runtime/src/main.rs +25 -2
  6. package/crates/omx-runtime/tests/execution.rs +219 -0
  7. package/crates/omx-runtime-core/src/dispatch.rs +96 -10
  8. package/crates/omx-runtime-core/src/engine.rs +839 -29
  9. package/crates/omx-runtime-core/src/lib.rs +8 -0
  10. package/dist/adapt/__tests__/hermes.test.js.map +1 -1
  11. package/dist/adapt/contracts.d.ts.map +1 -1
  12. package/dist/agents/__tests__/definitions.test.js +81 -0
  13. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  14. package/dist/agents/__tests__/native-config.test.js +25 -0
  15. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  16. package/dist/agents/native-config.d.ts +2 -1
  17. package/dist/agents/native-config.d.ts.map +1 -1
  18. package/dist/agents/native-config.js.map +1 -1
  19. package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
  20. package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
  21. package/dist/auth/__tests__/hotswap.test.js +183 -0
  22. package/dist/auth/__tests__/hotswap.test.js.map +1 -0
  23. package/dist/auth/hotswap.d.ts +6 -0
  24. package/dist/auth/hotswap.d.ts.map +1 -1
  25. package/dist/auth/hotswap.js +102 -19
  26. package/dist/auth/hotswap.js.map +1 -1
  27. package/dist/auth/paths.js.map +1 -1
  28. package/dist/auth/storage.js.map +1 -1
  29. package/dist/autopilot/__tests__/ralplan-gate.test.js +5 -5
  30. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  31. package/dist/autopilot/completion-gate.js.map +1 -1
  32. package/dist/autopilot/fsm.d.ts +1 -1
  33. package/dist/autopilot/fsm.d.ts.map +1 -1
  34. package/dist/autoresearch/goal.js.map +1 -1
  35. package/dist/autoresearch/runtime.js.map +1 -1
  36. package/dist/capabilities/lockfile.js.map +1 -1
  37. package/dist/catalog/reader.js.map +1 -1
  38. package/dist/catalog/skill-mirror.js.map +1 -1
  39. package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
  40. package/dist/cli/__tests__/agents-init.test.js.map +1 -1
  41. package/dist/cli/__tests__/agents.test.js.map +1 -1
  42. package/dist/cli/__tests__/api.test.js.map +1 -1
  43. package/dist/cli/__tests__/ask.test.js.map +1 -1
  44. package/dist/cli/__tests__/auth.test.js +60 -6
  45. package/dist/cli/__tests__/auth.test.js.map +1 -1
  46. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  47. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  48. package/dist/cli/__tests__/capabilities.test.js.map +1 -1
  49. package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
  50. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  51. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
  52. package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
  53. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
  54. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  55. package/dist/cli/__tests__/doctor-warning-copy.test.js +752 -15
  56. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  57. package/dist/cli/__tests__/exec.test.js +136 -0
  58. package/dist/cli/__tests__/exec.test.js.map +1 -1
  59. package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
  60. package/dist/cli/__tests__/index.test.js +473 -14
  61. package/dist/cli/__tests__/index.test.js.map +1 -1
  62. package/dist/cli/__tests__/launch-fallback.test.js +336 -4
  63. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  64. package/dist/cli/__tests__/mcp-parity.test.js +87 -12
  65. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  66. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
  67. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
  68. package/dist/cli/__tests__/native-hook-claim-journal.test.js +206 -0
  69. package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
  70. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  71. package/dist/cli/__tests__/question.test.js.map +1 -1
  72. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
  73. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
  74. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  75. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
  76. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
  77. package/dist/cli/__tests__/ralph.test.js +8 -3
  78. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  79. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
  80. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
  81. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +72 -0
  82. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
  83. package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
  84. package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
  85. package/dist/cli/__tests__/ralplan.test.js +55 -0
  86. package/dist/cli/__tests__/ralplan.test.js.map +1 -0
  87. package/dist/cli/__tests__/resume.test.js +17 -11
  88. package/dist/cli/__tests__/resume.test.js.map +1 -1
  89. package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
  90. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  91. package/dist/cli/__tests__/session-search-help.test.js +25 -1
  92. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  93. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  94. package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
  95. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  96. package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
  97. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
  98. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  99. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
  100. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
  101. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
  102. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
  103. package/dist/cli/__tests__/setup-install-mode.test.js +2579 -294
  104. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  105. package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
  106. package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
  107. package/dist/cli/__tests__/setup-preferences.test.js +79 -0
  108. package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
  109. package/dist/cli/__tests__/setup-refresh.test.js +33 -2
  110. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  111. package/dist/cli/__tests__/setup-scope.test.js +46 -3
  112. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  113. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  114. package/dist/cli/__tests__/state.test.js +37 -0
  115. package/dist/cli/__tests__/state.test.js.map +1 -1
  116. package/dist/cli/__tests__/team.test.js +105 -7
  117. package/dist/cli/__tests__/team.test.js.map +1 -1
  118. package/dist/cli/__tests__/ultragoal.test.js +61 -1
  119. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  120. package/dist/cli/__tests__/uninstall.test.js +1817 -24
  121. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  122. package/dist/cli/__tests__/update.test.js +58 -0
  123. package/dist/cli/__tests__/update.test.js.map +1 -1
  124. package/dist/cli/__tests__/url.test.js.map +1 -1
  125. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
  126. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  127. package/dist/cli/adapt.js.map +1 -1
  128. package/dist/cli/agents-init.js.map +1 -1
  129. package/dist/cli/agents.js.map +1 -1
  130. package/dist/cli/api.js.map +1 -1
  131. package/dist/cli/ask.d.ts +1 -1
  132. package/dist/cli/ask.d.ts.map +1 -1
  133. package/dist/cli/ask.js.map +1 -1
  134. package/dist/cli/auth.js.map +1 -1
  135. package/dist/cli/autoresearch-guided.js.map +1 -1
  136. package/dist/cli/autoresearch-intake.js.map +1 -1
  137. package/dist/cli/capabilities.js.map +1 -1
  138. package/dist/cli/cleanup.js.map +1 -1
  139. package/dist/cli/codex-feature-probe.js.map +1 -1
  140. package/dist/cli/codex-home.js.map +1 -1
  141. package/dist/cli/doctor.d.ts +21 -0
  142. package/dist/cli/doctor.d.ts.map +1 -1
  143. package/dist/cli/doctor.js +607 -130
  144. package/dist/cli/doctor.js.map +1 -1
  145. package/dist/cli/explore.js.map +1 -1
  146. package/dist/cli/index.d.ts +14 -3
  147. package/dist/cli/index.d.ts.map +1 -1
  148. package/dist/cli/index.js +245 -57
  149. package/dist/cli/index.js.map +1 -1
  150. package/dist/cli/mcp-parity.js +2 -2
  151. package/dist/cli/mcp-parity.js.map +1 -1
  152. package/dist/cli/mcp-serve.js.map +1 -1
  153. package/dist/cli/mission.js.map +1 -1
  154. package/dist/cli/native-assets.js.map +1 -1
  155. package/dist/cli/native-hook-claim-journal.d.ts +29 -0
  156. package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
  157. package/dist/cli/native-hook-claim-journal.js +252 -0
  158. package/dist/cli/native-hook-claim-journal.js.map +1 -0
  159. package/dist/cli/omx.js.map +1 -1
  160. package/dist/cli/plugin-marketplace.js.map +1 -1
  161. package/dist/cli/project-runtime-codex-homes.js.map +1 -1
  162. package/dist/cli/question.js.map +1 -1
  163. package/dist/cli/ralph.d.ts.map +1 -1
  164. package/dist/cli/ralph.js +3 -2
  165. package/dist/cli/ralph.js.map +1 -1
  166. package/dist/cli/ralplan.d.ts +10 -0
  167. package/dist/cli/ralplan.d.ts.map +1 -0
  168. package/dist/cli/ralplan.js +110 -0
  169. package/dist/cli/ralplan.js.map +1 -0
  170. package/dist/cli/session-search.d.ts +5 -0
  171. package/dist/cli/session-search.d.ts.map +1 -1
  172. package/dist/cli/session-search.js +87 -0
  173. package/dist/cli/session-search.js.map +1 -1
  174. package/dist/cli/setup-preferences.d.ts +11 -0
  175. package/dist/cli/setup-preferences.d.ts.map +1 -1
  176. package/dist/cli/setup-preferences.js +32 -0
  177. package/dist/cli/setup-preferences.js.map +1 -1
  178. package/dist/cli/setup.d.ts +58 -0
  179. package/dist/cli/setup.d.ts.map +1 -1
  180. package/dist/cli/setup.js +1450 -398
  181. package/dist/cli/setup.js.map +1 -1
  182. package/dist/cli/sparkshell.js.map +1 -1
  183. package/dist/cli/star-prompt.js.map +1 -1
  184. package/dist/cli/state.d.ts.map +1 -1
  185. package/dist/cli/state.js +2 -1
  186. package/dist/cli/state.js.map +1 -1
  187. package/dist/cli/team.js.map +1 -1
  188. package/dist/cli/ultragoal.d.ts +5 -1
  189. package/dist/cli/ultragoal.d.ts.map +1 -1
  190. package/dist/cli/ultragoal.js +34 -2
  191. package/dist/cli/ultragoal.js.map +1 -1
  192. package/dist/cli/uninstall.d.ts +17 -0
  193. package/dist/cli/uninstall.d.ts.map +1 -1
  194. package/dist/cli/uninstall.js +986 -95
  195. package/dist/cli/uninstall.js.map +1 -1
  196. package/dist/cli/update.d.ts.map +1 -1
  197. package/dist/cli/update.js +8 -1
  198. package/dist/cli/update.js.map +1 -1
  199. package/dist/cli/url.js.map +1 -1
  200. package/dist/compat/__tests__/doctor-contract.test.js +5 -1
  201. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  202. package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
  203. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
  204. package/dist/config/__tests__/codex-hooks.test.js +1287 -11
  205. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  206. package/dist/config/__tests__/generator-idempotent.test.js +1179 -32
  207. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  208. package/dist/config/__tests__/generator-notify.test.js +6 -1
  209. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  210. package/dist/config/__tests__/models.test.js +67 -3
  211. package/dist/config/__tests__/models.test.js.map +1 -1
  212. package/dist/config/codex-feature-flags.d.ts.map +1 -1
  213. package/dist/config/codex-feature-flags.js.map +1 -1
  214. package/dist/config/codex-hooks.d.ts +124 -1
  215. package/dist/config/codex-hooks.d.ts.map +1 -1
  216. package/dist/config/codex-hooks.js +2142 -265
  217. package/dist/config/codex-hooks.js.map +1 -1
  218. package/dist/config/commit-lore-guard.js.map +1 -1
  219. package/dist/config/generator.d.ts +23 -34
  220. package/dist/config/generator.d.ts.map +1 -1
  221. package/dist/config/generator.js +1480 -246
  222. package/dist/config/generator.js.map +1 -1
  223. package/dist/config/mcp-registry.js.map +1 -1
  224. package/dist/config/models.d.ts +14 -4
  225. package/dist/config/models.d.ts.map +1 -1
  226. package/dist/config/models.js +15 -1
  227. package/dist/config/models.js.map +1 -1
  228. package/dist/config/omx-first-party-mcp.js.map +1 -1
  229. package/dist/config/team-mode.d.ts.map +1 -1
  230. package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
  231. package/dist/document-refresh/enforcer.js.map +1 -1
  232. package/dist/exec/followup.js.map +1 -1
  233. package/dist/goal-workflows/artifacts.js.map +1 -1
  234. package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
  235. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  236. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
  237. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
  238. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  239. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
  240. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  241. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  242. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  243. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  244. package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
  245. package/dist/hooks/__tests__/keyword-detector.test.js +1376 -6
  246. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  247. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +252 -543
  248. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  249. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
  250. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  251. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +765 -10
  252. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  253. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
  254. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  255. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
  256. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  257. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  258. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
  259. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  260. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
  261. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  262. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  263. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
  264. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
  265. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
  266. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  267. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
  268. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  269. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +163 -24
  270. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  271. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
  272. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  273. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
  274. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  275. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
  276. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  277. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
  278. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
  279. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  280. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
  281. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  282. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  283. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
  284. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
  285. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
  286. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
  287. package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
  288. package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
  289. package/dist/hooks/__tests__/session.test.js +878 -11
  290. package/dist/hooks/__tests__/session.test.js.map +1 -1
  291. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
  292. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
  293. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
  294. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
  295. package/dist/hooks/agents-overlay.js +5 -5
  296. package/dist/hooks/agents-overlay.js.map +1 -1
  297. package/dist/hooks/code-simplifier/index.js.map +1 -1
  298. package/dist/hooks/explore-routing.js.map +1 -1
  299. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  300. package/dist/hooks/extensibility/events.js.map +1 -1
  301. package/dist/hooks/extensibility/loader.js.map +1 -1
  302. package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
  303. package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
  304. package/dist/hooks/keyword-detector.d.ts +33 -7
  305. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  306. package/dist/hooks/keyword-detector.js +2228 -119
  307. package/dist/hooks/keyword-detector.js.map +1 -1
  308. package/dist/hooks/keyword-registry.d.ts +12 -0
  309. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  310. package/dist/hooks/keyword-registry.js +41 -0
  311. package/dist/hooks/keyword-registry.js.map +1 -1
  312. package/dist/hooks/prompt-session-provenance.d.ts +87 -0
  313. package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
  314. package/dist/hooks/prompt-session-provenance.js +180 -0
  315. package/dist/hooks/prompt-session-provenance.js.map +1 -0
  316. package/dist/hooks/session.d.ts +163 -34
  317. package/dist/hooks/session.d.ts.map +1 -1
  318. package/dist/hooks/session.js +1395 -317
  319. package/dist/hooks/session.js.map +1 -1
  320. package/dist/hooks/task-size-detector.js.map +1 -1
  321. package/dist/hud/__tests__/state.test.js.map +1 -1
  322. package/dist/hud/authority.js.map +1 -1
  323. package/dist/hud/constants.js.map +1 -1
  324. package/dist/hud/index.js.map +1 -1
  325. package/dist/hud/reconcile.js.map +1 -1
  326. package/dist/hud/render.js.map +1 -1
  327. package/dist/hud/state.js.map +1 -1
  328. package/dist/hud/tmux.js.map +1 -1
  329. package/dist/leader/__tests__/contract.test.js +153 -1
  330. package/dist/leader/__tests__/contract.test.js.map +1 -1
  331. package/dist/leader/contract.d.ts +42 -5
  332. package/dist/leader/contract.d.ts.map +1 -1
  333. package/dist/leader/contract.js +184 -3
  334. package/dist/leader/contract.js.map +1 -1
  335. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  336. package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
  337. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
  338. package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
  339. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  340. package/dist/mcp/__tests__/state-paths.test.js +98 -1
  341. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  342. package/dist/mcp/__tests__/wiki-server.test.js +18 -0
  343. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  344. package/dist/mcp/bootstrap.js.map +1 -1
  345. package/dist/mcp/code-intel-server.d.ts +58 -58
  346. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  347. package/dist/mcp/code-intel-server.js +13 -3
  348. package/dist/mcp/code-intel-server.js.map +1 -1
  349. package/dist/mcp/hermes-bridge.js.map +1 -1
  350. package/dist/mcp/hermes-server.d.ts +70 -70
  351. package/dist/mcp/hermes-server.d.ts.map +1 -1
  352. package/dist/mcp/lifecycle-telemetry.js.map +1 -1
  353. package/dist/mcp/memory-server.d.ts +34 -34
  354. package/dist/mcp/memory-server.d.ts.map +1 -1
  355. package/dist/mcp/memory-server.js.map +1 -1
  356. package/dist/mcp/state-paths.d.ts +14 -0
  357. package/dist/mcp/state-paths.d.ts.map +1 -1
  358. package/dist/mcp/state-paths.js +96 -20
  359. package/dist/mcp/state-paths.js.map +1 -1
  360. package/dist/mcp/state-server.d.ts +47 -47
  361. package/dist/mcp/state-server.d.ts.map +1 -1
  362. package/dist/mcp/trace-server.d.ts +4 -4
  363. package/dist/mcp/trace-server.d.ts.map +1 -1
  364. package/dist/mcp/trace-server.js.map +1 -1
  365. package/dist/mcp/wiki-server.d.ts +34 -23
  366. package/dist/mcp/wiki-server.d.ts.map +1 -1
  367. package/dist/mcp/wiki-server.js +9 -2
  368. package/dist/mcp/wiki-server.js.map +1 -1
  369. package/dist/modes/__tests__/base-session-scope.test.js +53 -1
  370. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  371. package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
  372. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  373. package/dist/modes/base.d.ts.map +1 -1
  374. package/dist/modes/base.js +5 -5
  375. package/dist/modes/base.js.map +1 -1
  376. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
  377. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  378. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
  379. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
  380. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  381. package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
  382. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  383. package/dist/notifications/http-client.js.map +1 -1
  384. package/dist/notifications/index.d.ts +4 -1
  385. package/dist/notifications/index.d.ts.map +1 -1
  386. package/dist/notifications/index.js +3 -9
  387. package/dist/notifications/index.js.map +1 -1
  388. package/dist/notifications/lifecycle-dedupe.js.map +1 -1
  389. package/dist/notifications/reply-listener.d.ts.map +1 -1
  390. package/dist/notifications/reply-listener.js.map +1 -1
  391. package/dist/notifications/session-registry.js.map +1 -1
  392. package/dist/notifications/session-status.js.map +1 -1
  393. package/dist/notifications/temp-contract.d.ts.map +1 -1
  394. package/dist/notifications/temp-contract.js +4 -0
  395. package/dist/notifications/temp-contract.js.map +1 -1
  396. package/dist/notifications/tmux-detector.js.map +1 -1
  397. package/dist/notifications/tmux.js.map +1 -1
  398. package/dist/openclaw/config.js.map +1 -1
  399. package/dist/openclaw/dispatcher.js.map +1 -1
  400. package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
  401. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  402. package/dist/pipeline/__tests__/stages.test.js +16 -13
  403. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  404. package/dist/pipeline/stages/code-review.js.map +1 -1
  405. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  406. package/dist/pipeline/stages/ralplan.js.map +1 -1
  407. package/dist/pipeline/stages/team-exec.js.map +1 -1
  408. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  409. package/dist/pipeline/stages/ultraqa.js.map +1 -1
  410. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
  411. package/dist/planning/artifact-names.js.map +1 -1
  412. package/dist/planning/artifacts.js.map +1 -1
  413. package/dist/question/__tests__/state.test.js.map +1 -1
  414. package/dist/question/__tests__/ui.test.js.map +1 -1
  415. package/dist/question/autopilot-wait.js.map +1 -1
  416. package/dist/question/client.d.ts.map +1 -1
  417. package/dist/question/client.js.map +1 -1
  418. package/dist/question/deep-interview.js.map +1 -1
  419. package/dist/question/events.js.map +1 -1
  420. package/dist/question/renderer.js.map +1 -1
  421. package/dist/question/state.d.ts.map +1 -1
  422. package/dist/question/state.js.map +1 -1
  423. package/dist/question/ui.js.map +1 -1
  424. package/dist/ralph/contract.d.ts +1 -1
  425. package/dist/ralph/contract.d.ts.map +1 -1
  426. package/dist/ralplan/__tests__/consensus-gate.test.js +527 -8
  427. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  428. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
  429. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
  430. package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
  431. package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
  432. package/dist/ralplan/__tests__/runtime.test.js +116 -14
  433. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  434. package/dist/ralplan/consensus-gate.d.ts +3 -3
  435. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  436. package/dist/ralplan/consensus-gate.js +173 -70
  437. package/dist/ralplan/consensus-gate.js.map +1 -1
  438. package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
  439. package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
  440. package/dist/ralplan/documented-leader-preflight.js +58 -0
  441. package/dist/ralplan/documented-leader-preflight.js.map +1 -0
  442. package/dist/ralplan/runtime.d.ts +3 -2
  443. package/dist/ralplan/runtime.d.ts.map +1 -1
  444. package/dist/ralplan/runtime.js +12 -9
  445. package/dist/ralplan/runtime.js.map +1 -1
  446. package/dist/runtime/__tests__/bridge.test.js +42 -1
  447. package/dist/runtime/__tests__/bridge.test.js.map +1 -1
  448. package/dist/runtime/bridge.d.ts +12 -0
  449. package/dist/runtime/bridge.d.ts.map +1 -1
  450. package/dist/runtime/bridge.js +52 -1
  451. package/dist/runtime/bridge.js.map +1 -1
  452. package/dist/runtime/process-tree.js.map +1 -1
  453. package/dist/runtime/run-loop.js.map +1 -1
  454. package/dist/runtime/run-outcome.d.ts +3 -3
  455. package/dist/runtime/run-outcome.d.ts.map +1 -1
  456. package/dist/runtime/run-outcome.js.map +1 -1
  457. package/dist/runtime/run-state.js.map +1 -1
  458. package/dist/scripts/__tests__/codex-native-hook.test.js +6657 -995
  459. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  460. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
  461. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
  462. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
  463. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
  464. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
  465. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
  466. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  467. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
  468. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
  469. package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
  470. package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
  471. package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
  472. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  473. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
  474. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
  475. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
  476. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
  477. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
  478. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
  479. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +78 -0
  480. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
  481. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
  482. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
  483. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +55 -0
  484. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
  485. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  486. package/dist/scripts/__tests__/smoke-packed-install.test.js +1100 -4
  487. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  488. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
  489. package/dist/scripts/build-api.js.map +1 -1
  490. package/dist/scripts/build-explore-harness.js.map +1 -1
  491. package/dist/scripts/build-sparkshell.js.map +1 -1
  492. package/dist/scripts/cleanup-explore-harness.js.map +1 -1
  493. package/dist/scripts/codex-execution-surface.js.map +1 -1
  494. package/dist/scripts/codex-native-hook.d.ts +4 -1
  495. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  496. package/dist/scripts/codex-native-hook.js +11577 -1184
  497. package/dist/scripts/codex-native-hook.js.map +1 -1
  498. package/dist/scripts/generate-native-release-manifest.js.map +1 -1
  499. package/dist/scripts/generate-release-body.js.map +1 -1
  500. package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
  501. package/dist/scripts/hook-payload-guard.js.map +1 -1
  502. package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
  503. package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
  504. package/dist/scripts/notify-fallback-delivery.js +419 -0
  505. package/dist/scripts/notify-fallback-delivery.js.map +1 -0
  506. package/dist/scripts/notify-fallback-watcher.js +218 -138
  507. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  508. package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
  509. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  510. package/dist/scripts/notify-hook/auto-nudge.js +112 -15
  511. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  512. package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
  513. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  514. package/dist/scripts/notify-hook/managed-tmux.js +122 -12
  515. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  516. package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
  517. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
  518. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
  519. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  520. package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
  521. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  522. package/dist/scripts/notify-hook/state-io.d.ts +17 -0
  523. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  524. package/dist/scripts/notify-hook/state-io.js +73 -11
  525. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  526. package/dist/scripts/notify-hook/team-dispatch.d.ts +10 -1
  527. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  528. package/dist/scripts/notify-hook/team-dispatch.js +234 -79
  529. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  530. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
  531. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  532. package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
  533. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  534. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +16 -8
  535. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  536. package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
  537. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  538. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
  539. package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
  540. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  541. package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
  542. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  543. package/dist/scripts/notify-hook/team-worker.d.ts +5 -2
  544. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  545. package/dist/scripts/notify-hook/team-worker.js +37 -28
  546. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  547. package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
  548. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  549. package/dist/scripts/notify-hook/tmux-injection.js +53 -18
  550. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  551. package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
  552. package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
  553. package/dist/scripts/notify-hook/visual-verdict.js +15 -13
  554. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
  555. package/dist/scripts/notify-hook.d.ts +24 -1
  556. package/dist/scripts/notify-hook.d.ts.map +1 -1
  557. package/dist/scripts/notify-hook.js +267 -90
  558. package/dist/scripts/notify-hook.js.map +1 -1
  559. package/dist/scripts/postinstall.js.map +1 -1
  560. package/dist/scripts/prompt-inventory.js.map +1 -1
  561. package/dist/scripts/smoke-packed-install.d.ts +927 -5
  562. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  563. package/dist/scripts/smoke-packed-install.js +4317 -13
  564. package/dist/scripts/smoke-packed-install.js.map +1 -1
  565. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  566. package/dist/scripts/test-reply-listener-live.js.map +1 -1
  567. package/dist/scripts/test-sparkshell.js.map +1 -1
  568. package/dist/scripts/verify-native-agents.js.map +1 -1
  569. package/dist/session-history/friction.js.map +1 -1
  570. package/dist/session-history/search.js.map +1 -1
  571. package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
  572. package/dist/sidecar/collector.js.map +1 -1
  573. package/dist/sidecar/index.js.map +1 -1
  574. package/dist/sidecar/render.js.map +1 -1
  575. package/dist/sidecar/tmux.js.map +1 -1
  576. package/dist/state/__tests__/mode-state-context.test.js +54 -0
  577. package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
  578. package/dist/state/__tests__/operations.test.js +66 -15
  579. package/dist/state/__tests__/operations.test.js.map +1 -1
  580. package/dist/state/__tests__/skill-active.test.js +19 -1
  581. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  582. package/dist/state/__tests__/workflow-transition.test.js +61 -0
  583. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  584. package/dist/state/mode-state-context.d.ts +5 -0
  585. package/dist/state/mode-state-context.d.ts.map +1 -1
  586. package/dist/state/mode-state-context.js +59 -0
  587. package/dist/state/mode-state-context.js.map +1 -1
  588. package/dist/state/operations.d.ts +1 -1
  589. package/dist/state/operations.d.ts.map +1 -1
  590. package/dist/state/operations.js +49 -55
  591. package/dist/state/operations.js.map +1 -1
  592. package/dist/state/paths.d.ts +1 -1
  593. package/dist/state/paths.d.ts.map +1 -1
  594. package/dist/state/paths.js +1 -1
  595. package/dist/state/paths.js.map +1 -1
  596. package/dist/state/skill-active.d.ts +13 -1
  597. package/dist/state/skill-active.d.ts.map +1 -1
  598. package/dist/state/skill-active.js +43 -4
  599. package/dist/state/skill-active.js.map +1 -1
  600. package/dist/state/terminal-normalization.js.map +1 -1
  601. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  602. package/dist/state/workflow-transition-reconcile.js +20 -4
  603. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  604. package/dist/state/workflow-transition.d.ts +1 -1
  605. package/dist/state/workflow-transition.d.ts.map +1 -1
  606. package/dist/state/workflow-transition.js.map +1 -1
  607. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
  608. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
  609. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +52 -0
  610. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
  611. package/dist/subagents/__tests__/tracker.test.js +1550 -10
  612. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  613. package/dist/subagents/role-routing-marker.d.ts +10 -0
  614. package/dist/subagents/role-routing-marker.d.ts.map +1 -0
  615. package/dist/subagents/role-routing-marker.js +136 -0
  616. package/dist/subagents/role-routing-marker.js.map +1 -0
  617. package/dist/subagents/tracker.d.ts +91 -0
  618. package/dist/subagents/tracker.d.ts.map +1 -1
  619. package/dist/subagents/tracker.js +806 -62
  620. package/dist/subagents/tracker.js.map +1 -1
  621. package/dist/team/__tests__/api-interop.test.js +91 -1
  622. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  623. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  624. package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
  625. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  626. package/dist/team/__tests__/idle-nudge.test.js +45 -15
  627. package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
  628. package/dist/team/__tests__/mcp-comm.test.js +93 -27
  629. package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
  630. package/dist/team/__tests__/model-contract.test.js +341 -4
  631. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  632. package/dist/team/__tests__/role-router.test.js.map +1 -1
  633. package/dist/team/__tests__/runtime-cli.test.js +9 -0
  634. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  635. package/dist/team/__tests__/runtime.test.js +3624 -355
  636. package/dist/team/__tests__/runtime.test.js.map +1 -1
  637. package/dist/team/__tests__/scaling.test.js +2516 -118
  638. package/dist/team/__tests__/scaling.test.js.map +1 -1
  639. package/dist/team/__tests__/state-root.test.js.map +1 -1
  640. package/dist/team/__tests__/state.test.js +804 -36
  641. package/dist/team/__tests__/state.test.js.map +1 -1
  642. package/dist/team/__tests__/team-ops-contract.test.js +6 -0
  643. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
  644. package/dist/team/__tests__/tmux-session.test.js +3664 -969
  645. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  646. package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
  647. package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
  648. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  649. package/dist/team/__tests__/worktree.test.js +6 -0
  650. package/dist/team/__tests__/worktree.test.js.map +1 -1
  651. package/dist/team/api-interop.d.ts +2 -2
  652. package/dist/team/api-interop.d.ts.map +1 -1
  653. package/dist/team/api-interop.js +15 -9
  654. package/dist/team/api-interop.js.map +1 -1
  655. package/dist/team/commit-hygiene.js.map +1 -1
  656. package/dist/team/contracts.d.ts +5 -5
  657. package/dist/team/contracts.d.ts.map +1 -1
  658. package/dist/team/delivery-log.js.map +1 -1
  659. package/dist/team/exact-pane.d.ts +23 -0
  660. package/dist/team/exact-pane.d.ts.map +1 -0
  661. package/dist/team/exact-pane.js +133 -0
  662. package/dist/team/exact-pane.js.map +1 -0
  663. package/dist/team/followup-planner.js.map +1 -1
  664. package/dist/team/goal-workflow.js.map +1 -1
  665. package/dist/team/idle-nudge.d.ts +12 -1
  666. package/dist/team/idle-nudge.d.ts.map +1 -1
  667. package/dist/team/idle-nudge.js +41 -14
  668. package/dist/team/idle-nudge.js.map +1 -1
  669. package/dist/team/model-contract.d.ts +18 -2
  670. package/dist/team/model-contract.d.ts.map +1 -1
  671. package/dist/team/model-contract.js +314 -35
  672. package/dist/team/model-contract.js.map +1 -1
  673. package/dist/team/orchestrator.js.map +1 -1
  674. package/dist/team/pane-status.js.map +1 -1
  675. package/dist/team/phase-controller.js.map +1 -1
  676. package/dist/team/reminder-intents.d.ts +1 -1
  677. package/dist/team/reminder-intents.d.ts.map +1 -1
  678. package/dist/team/reminder-intents.js.map +1 -1
  679. package/dist/team/runtime-cli.js.map +1 -1
  680. package/dist/team/runtime.d.ts +1 -0
  681. package/dist/team/runtime.d.ts.map +1 -1
  682. package/dist/team/runtime.js +1326 -231
  683. package/dist/team/runtime.js.map +1 -1
  684. package/dist/team/scaling.d.ts +22 -8
  685. package/dist/team/scaling.d.ts.map +1 -1
  686. package/dist/team/scaling.js +1463 -376
  687. package/dist/team/scaling.js.map +1 -1
  688. package/dist/team/state/dispatch-lock.js.map +1 -1
  689. package/dist/team/state/dispatch.d.ts.map +1 -1
  690. package/dist/team/state/dispatch.js +26 -8
  691. package/dist/team/state/dispatch.js.map +1 -1
  692. package/dist/team/state/events.js.map +1 -1
  693. package/dist/team/state/locks.d.ts.map +1 -1
  694. package/dist/team/state/locks.js +61 -13
  695. package/dist/team/state/locks.js.map +1 -1
  696. package/dist/team/state/tasks.d.ts.map +1 -1
  697. package/dist/team/state/tasks.js +4 -3
  698. package/dist/team/state/tasks.js.map +1 -1
  699. package/dist/team/state-root.js.map +1 -1
  700. package/dist/team/state.d.ts +67 -1
  701. package/dist/team/state.d.ts.map +1 -1
  702. package/dist/team/state.js +636 -129
  703. package/dist/team/state.js.map +1 -1
  704. package/dist/team/team-identity.d.ts.map +1 -1
  705. package/dist/team/team-identity.js.map +1 -1
  706. package/dist/team/team-ops.d.ts +5 -0
  707. package/dist/team/team-ops.d.ts.map +1 -1
  708. package/dist/team/team-ops.js +4 -0
  709. package/dist/team/team-ops.js.map +1 -1
  710. package/dist/team/tmux-session.d.ts +125 -23
  711. package/dist/team/tmux-session.d.ts.map +1 -1
  712. package/dist/team/tmux-session.js +1340 -333
  713. package/dist/team/tmux-session.js.map +1 -1
  714. package/dist/team/worker-bootstrap.js.map +1 -1
  715. package/dist/team/worktree.d.ts.map +1 -1
  716. package/dist/team/worktree.js +4 -0
  717. package/dist/team/worktree.js.map +1 -1
  718. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  719. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  720. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  721. package/dist/ultragoal/artifacts.js +4 -1
  722. package/dist/ultragoal/artifacts.js.map +1 -1
  723. package/dist/url-reader/index.js.map +1 -1
  724. package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
  725. package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
  726. package/dist/utils/__tests__/file-durability.test.js +57 -0
  727. package/dist/utils/__tests__/file-durability.test.js.map +1 -0
  728. package/dist/utils/agents-model-table.js.map +1 -1
  729. package/dist/utils/file-durability.d.ts +15 -0
  730. package/dist/utils/file-durability.d.ts.map +1 -0
  731. package/dist/utils/file-durability.js +37 -0
  732. package/dist/utils/file-durability.js.map +1 -0
  733. package/dist/utils/package.js.map +1 -1
  734. package/dist/utils/paths.js.map +1 -1
  735. package/dist/utils/platform-command.js.map +1 -1
  736. package/dist/utils/repo-deps.js.map +1 -1
  737. package/dist/utils/version.js.map +1 -1
  738. package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
  739. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
  740. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  741. package/dist/verification/verifier.js.map +1 -1
  742. package/dist/visual/constants.d.ts +1 -1
  743. package/dist/visual/constants.d.ts.map +1 -1
  744. package/dist/vscode/__tests__/index.test.js.map +1 -1
  745. package/dist/vscode/index.js.map +1 -1
  746. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
  747. package/dist/wiki/__tests__/lint.test.js.map +1 -1
  748. package/dist/wiki/__tests__/query.test.js.map +1 -1
  749. package/dist/wiki/__tests__/storage.test.js.map +1 -1
  750. package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
  751. package/dist/wiki/lint.d.ts +4 -1
  752. package/dist/wiki/lint.d.ts.map +1 -1
  753. package/dist/wiki/lint.js +3 -2
  754. package/dist/wiki/lint.js.map +1 -1
  755. package/dist/wiki/query.js.map +1 -1
  756. package/dist/wiki/storage.js.map +1 -1
  757. package/package.json +2 -2
  758. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  759. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
  760. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
  761. package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -2
  762. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
  763. package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
  764. package/skills/omx-setup/SKILL.md +10 -5
  765. package/skills/ralph/SKILL.md +6 -2
  766. package/skills/ralplan/SKILL.md +6 -2
  767. package/skills/team/SKILL.md +13 -9
  768. package/src/scripts/__tests__/codex-native-hook.test.ts +20048 -10827
  769. package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
  770. package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
  771. package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
  772. package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
  773. package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +78 -0
  774. package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +60 -0
  775. package/src/scripts/__tests__/smoke-packed-install.test.ts +1309 -4
  776. package/src/scripts/codex-native-hook.ts +11429 -1163
  777. package/src/scripts/notify-fallback-delivery.ts +416 -0
  778. package/src/scripts/notify-fallback-watcher.ts +216 -155
  779. package/src/scripts/notify-hook/auto-nudge.ts +113 -14
  780. package/src/scripts/notify-hook/managed-tmux.ts +149 -12
  781. package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
  782. package/src/scripts/notify-hook/state-io.ts +100 -13
  783. package/src/scripts/notify-hook/team-dispatch.ts +242 -75
  784. package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
  785. package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
  786. package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
  787. package/src/scripts/notify-hook/team-worker.ts +39 -26
  788. package/src/scripts/notify-hook/tmux-injection.ts +66 -23
  789. package/src/scripts/notify-hook/visual-verdict.ts +22 -12
  790. package/src/scripts/notify-hook.ts +336 -90
  791. package/src/scripts/smoke-packed-install.ts +5154 -149
@@ -1,14 +1,16 @@
1
1
  import { describe, it } from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { cp, mkdir, mkdtemp, readFile, rm, symlink, writeFile, } from "node:fs/promises";
4
- import { existsSync } from "node:fs";
3
+ import { cp, link, mkdir, mkdtemp, realpath, readFile, rename, rm, symlink, writeFile, } from "node:fs/promises";
4
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
5
  import { join, dirname } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
  import { spawnSync } from "node:child_process";
8
8
  import { fileURLToPath } from "node:url";
9
9
  import { withPackagedExploreHarnessHidden, withPackagedExploreHarnessLock, } from "./packaged-explore-harness-lock.js";
10
- import { checkExploreHarness, checkExternalCodexProcessGuards, buildPostCompactSmokeSpawnInvocation, checkNativeHookDistSmoke, classifyPostCompactHookStdout, checkLegacyMultiAgentCompatibility, } from "../doctor.js";
11
- import { buildManagedCodexNativeHookCommand } from "../../config/codex-hooks.js";
10
+ import { buildPostCompactSmokeSpawnInvocation, checkExternalCodexProcessGuards, checkExploreHarness, checkLegacyMultiAgentCompatibility, checkNativeHookDistSmoke, checkNativePostCompactHookRuntime, checkNativeHooks, classifyPostCompactHookStdout, doctor, setDoctorClaimJournalDurabilityForTest, } from "../doctor.js";
11
+ import { createNativeHookClaimJournalDurability, persistNativeHookClaimJournal, } from "../native-hook-claim-journal.js";
12
+ import { syncRegularFile } from "../../utils/file-durability.js";
13
+ import { buildManagedCodexNativeHookCommand, buildManagedCodexNativeHookWindowsShimContent, } from "../../config/codex-hooks.js";
12
14
  const MANAGED_HOOK_EVENTS = [
13
15
  "SessionStart",
14
16
  "PreToolUse",
@@ -54,6 +56,13 @@ function currentNativeHookCommand(codexHomeDir) {
54
56
  codexHomeDir,
55
57
  });
56
58
  }
59
+ function buildWindowsShimCommand(shimPath) {
60
+ return `& 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe' -NoProfile -ExecutionPolicy Bypass -File '${shimPath.replace(/'/g, "''")}'`;
61
+ }
62
+ function buildWindowsShimHooksJson(shimPath, codexHomeDir) {
63
+ const command = buildWindowsShimCommand(shimPath);
64
+ return buildHooksJsonWithPostCompactCommand(command, codexHomeDir, command);
65
+ }
57
66
  async function installPluginCacheFixture(codexDir) {
58
67
  const root = repoRoot();
59
68
  const sourcePluginDir = join(root, "plugins", "oh-my-codex");
@@ -77,8 +86,7 @@ async function packagedPluginVersion() {
77
86
  }
78
87
  return manifest.version;
79
88
  }
80
- function buildHooksJsonWithPostCompactCommand(postCompactCommand, codexHomeDir) {
81
- const expectedCommand = currentNativeHookCommand(codexHomeDir);
89
+ function buildHooksJsonWithPostCompactCommand(postCompactCommand, codexHomeDir, expectedCommand = currentNativeHookCommand(codexHomeDir)) {
82
90
  return `${JSON.stringify({
83
91
  hooks: Object.fromEntries(MANAGED_HOOK_EVENTS.map((eventName) => [
84
92
  eventName,
@@ -97,6 +105,40 @@ function buildHooksJsonWithPostCompactCommand(postCompactCommand, codexHomeDir)
97
105
  ])),
98
106
  }, null, 2)}\n`;
99
107
  }
108
+ async function withRecoverableDoctorClaimJournal(run) {
109
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-claim-recovery-"));
110
+ const codexHomeDir = join(wd, ".codex");
111
+ const hooksPath = join(codexHomeDir, "hooks.json");
112
+ const claimPath = join(codexHomeDir, ".hooks.json.omx-claim-test.tmp");
113
+ const previousCwd = process.cwd();
114
+ const previousCodexHome = process.env.CODEX_HOME;
115
+ try {
116
+ await mkdir(codexHomeDir, { recursive: true });
117
+ await writeFile(hooksPath, "{\"hooks\":{}}\n");
118
+ await persistNativeHookClaimJournal(codexHomeDir, {
119
+ canonicalPath: hooksPath,
120
+ claimPath,
121
+ before: Buffer.from("{\"hooks\":{}}\n"),
122
+ after: null,
123
+ }, createNativeHookClaimJournalDurability());
124
+ await rename(hooksPath, claimPath);
125
+ const journalPath = join(codexHomeDir, ".omx", "native-hook-claim-journal.json");
126
+ const journal = JSON.parse(await readFile(journalPath, "utf-8"));
127
+ journal.ownerPid = 2_147_483_647;
128
+ await writeFile(journalPath, `${JSON.stringify(journal, null, 2)}\n`, "utf-8");
129
+ process.env.CODEX_HOME = codexHomeDir;
130
+ process.chdir(wd);
131
+ return await run(codexHomeDir);
132
+ }
133
+ finally {
134
+ process.chdir(previousCwd);
135
+ if (previousCodexHome === undefined)
136
+ delete process.env.CODEX_HOME;
137
+ else
138
+ process.env.CODEX_HOME = previousCodexHome;
139
+ await rm(wd, { recursive: true, force: true });
140
+ }
141
+ }
100
142
  describe("omx doctor onboarding warning copy", () => {
101
143
  it("warns about external LaunchAgents that kill Codex app-server MCP children", async () => {
102
144
  const wd = await mkdtemp(join(tmpdir(), "omx-doctor-external-guard-"));
@@ -891,7 +933,7 @@ OMX_LORE_COMMIT_GUARD = "truee"
891
933
  return;
892
934
  assert.equal(res.status, 0, res.stderr || res.stdout);
893
935
  assert.doesNotMatch(res.stdout, /Resolved setup install mode: plugin \(inferred from Codex plugin config\)/);
894
- assert.match(res.stdout, /Native hooks: expected setup-owned hooks\.json is missing at .*\.codex[\\/]+hooks\.json even though config\.toml has OMX entries; run "omx setup --force" to restore native hook coverage/);
936
+ assert.match(res.stdout, /Native hooks: expected setup-owned hooks\.json is missing at .*\.codex[\\/]+hooks\.json even though config\.toml has OMX entries; run "omx setup" to restore native hook coverage/);
895
937
  assert.match(res.stdout, /Prompts: prompts directory not found/);
896
938
  }
897
939
  finally {
@@ -1144,7 +1186,7 @@ OMX_LORE_COMMIT_GUARD = "truee"
1144
1186
  if (shouldSkipForSpawnPermissions(res.error))
1145
1187
  return;
1146
1188
  assert.equal(res.status, 0, res.stderr || res.stdout);
1147
- assert.match(res.stdout, new RegExp(`\\[!!\\] Native hooks: plugin-scoped hooks are enabled, but cached plugin hook files or pinned hook launcher in ${cacheDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")} do not match the packaged plugin; setup-owned hooks\\.json is intentionally absent at .*\\.codex[\\/]+hooks\\.json; run "omx setup --plugin --force" to refresh the plugin cache`));
1189
+ assert.match(res.stdout, new RegExp(`\\[!!\\] Native hooks: plugin-scoped hooks are enabled, but cached plugin hook files or pinned hook launcher in ${cacheDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")} do not match the packaged plugin; setup-owned hooks\\.json is intentionally absent at .*\\.codex[\\/]+hooks\\.json; run "omx setup --plugin" to refresh the plugin cache`));
1148
1190
  assert.doesNotMatch(res.stdout, /plugin cache native hook coverage smoke passed/);
1149
1191
  }
1150
1192
  finally {
@@ -1194,7 +1236,7 @@ OMX_LORE_COMMIT_GUARD = "truee"
1194
1236
  if (shouldSkipForSpawnPermissions(res.error))
1195
1237
  return;
1196
1238
  assert.equal(res.status, 0, res.stderr || res.stdout);
1197
- assert.match(res.stdout, new RegExp(`\\[OK\\] Native hooks: plugin-scoped hooks are enabled; existing hooks\\.json at .*\\.codex[\\/]+hooks\\.json is treated as user-owned because plugin-scoped hooks are enabled, and plugin cache native hook coverage smoke passed via ${join(cacheDir, "hooks", "hooks.json").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`));
1239
+ assert.match(res.stdout, new RegExp(`\\[OK\\] Native hooks: plugin-scoped hooks are enabled; existing hooks\\.json at .*\\.codex[\\/]+hooks\\.json is retained read-only and validated separately because plugin-scoped hooks are enabled, and plugin cache native hook coverage smoke passed via ${join(cacheDir, "hooks", "hooks.json").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`));
1198
1240
  assert.doesNotMatch(res.stdout, /hooks\.json is missing OMX-managed coverage/);
1199
1241
  assert.doesNotMatch(res.stdout, /run "omx setup --force" to restore native hooks/);
1200
1242
  }
@@ -1229,7 +1271,7 @@ OMX_LORE_COMMIT_GUARD = "truee"
1229
1271
  if (shouldSkipForSpawnPermissions(res.error))
1230
1272
  return;
1231
1273
  assert.equal(res.status, 0, res.stderr || res.stdout);
1232
- assert.match(res.stdout, /Native hooks: hooks\.json is missing OMX-managed coverage for PreToolUse, PostToolUse, UserPromptSubmit, PreCompact, PostCompact, Stop; run "omx setup --force" to restore native hooks/);
1274
+ assert.match(res.stdout, /Native hooks: hooks\.json is missing OMX-managed coverage for PreToolUse, PostToolUse, UserPromptSubmit, PreCompact, PostCompact, Stop; run "omx setup" to restore native hooks/);
1233
1275
  }
1234
1276
  finally {
1235
1277
  await rm(wd, { recursive: true, force: true });
@@ -1289,7 +1331,7 @@ command = "node"
1289
1331
  if (shouldSkipForSpawnPermissions(res.error))
1290
1332
  return;
1291
1333
  assert.equal(res.status, 0, res.stderr || res.stdout);
1292
- assert.match(res.stdout, /Native hooks: expected setup-owned hooks\.json is missing at .*\.codex[\/]+hooks\.json even though config\.toml has OMX entries; run "omx setup --force" to restore native hook coverage/);
1334
+ assert.match(res.stdout, /Native hooks: expected setup-owned hooks\.json is missing at .*\.codex[\/]+hooks\.json even though config\.toml has OMX entries; run "omx setup" to restore native hook coverage/);
1293
1335
  }
1294
1336
  finally {
1295
1337
  await rm(wd, { recursive: true, force: true });
@@ -1309,7 +1351,508 @@ command = "node"
1309
1351
  if (shouldSkipForSpawnPermissions(res.error))
1310
1352
  return;
1311
1353
  assert.equal(res.status, 0, res.stderr || res.stdout);
1312
- assert.match(res.stdout, /\[XX\] Native hooks: invalid hooks\.json; Codex may skip OMX hook coverage until "omx setup --force" repairs it/);
1354
+ assert.match(res.stdout, /\[XX\] Native hooks: hooks\.json failed strict load validation \(invalid_document\): hooks\.json must contain a JSON object; inspect the file manually because doctor will not modify it/);
1355
+ }
1356
+ finally {
1357
+ await rm(wd, { recursive: true, force: true });
1358
+ }
1359
+ });
1360
+ it("reports matcher-aware discovery warnings without touching hooks.json", async () => {
1361
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-hooks-matcher-warning-"));
1362
+ try {
1363
+ const home = join(wd, "home");
1364
+ const codexDir = join(home, ".codex");
1365
+ await mkdir(codexDir, { recursive: true });
1366
+ await writeFile(join(codexDir, "hooks.json"), JSON.stringify({
1367
+ hooks: {
1368
+ SessionStart: [{
1369
+ matcher: "[",
1370
+ hooks: [{ type: "command", command: "echo user-owned" }],
1371
+ }],
1372
+ },
1373
+ }, null, 2) + "\n");
1374
+ const res = runOmx(wd, ["doctor"], { HOME: home, CODEX_HOME: codexDir });
1375
+ if (shouldSkipForSpawnPermissions(res.error))
1376
+ return;
1377
+ assert.equal(res.status, 0, res.stderr || res.stdout);
1378
+ assert.match(res.stdout, /Native hooks: hooks\.json discovery warnings: SessionStart\[0\]: Codex skips groups whose matcher is not a valid regular expression; Codex may ignore the listed entries, and doctor will not modify them/);
1379
+ assert.doesNotMatch(res.stdout, /Native hooks:.*--force/);
1380
+ }
1381
+ finally {
1382
+ await rm(wd, { recursive: true, force: true });
1383
+ }
1384
+ });
1385
+ it("treats UserPromptSubmit and Stop matcher groups as valid foreign survivors", async () => {
1386
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-hooks-foreign-survivors-"));
1387
+ try {
1388
+ const home = join(wd, "home");
1389
+ const codexDir = join(home, ".codex");
1390
+ await mkdir(codexDir, { recursive: true });
1391
+ await writeFile(join(codexDir, "hooks.json"), JSON.stringify({
1392
+ hooks: {
1393
+ UserPromptSubmit: [{ matcher: "[", hooks: [{ type: "command", command: "echo prompt" }] }],
1394
+ Stop: [{ matcher: "[", hooks: [{ type: "command", command: "echo stop" }] }],
1395
+ },
1396
+ }, null, 2) + "\n");
1397
+ const res = runOmx(wd, ["doctor"], { HOME: home, CODEX_HOME: codexDir });
1398
+ if (shouldSkipForSpawnPermissions(res.error))
1399
+ return;
1400
+ assert.equal(res.status, 0, res.stderr || res.stdout);
1401
+ assert.match(res.stdout, /\[OK\] Native hooks: hooks\.json contains valid foreign hook entries and no OMX-managed wrappers; doctor will preserve the user-owned configuration/);
1402
+ assert.doesNotMatch(res.stdout, /hooks\.json discovery warnings/);
1403
+ assert.doesNotMatch(res.stdout, /Native hooks:.*--force/);
1404
+ }
1405
+ finally {
1406
+ await rm(wd, { recursive: true, force: true });
1407
+ }
1408
+ });
1409
+ it("reports unsafe managed removal without recommending destructive repair", async () => {
1410
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-hooks-unsafe-removal-"));
1411
+ try {
1412
+ const home = join(wd, "home");
1413
+ const codexDir = join(home, ".codex");
1414
+ await mkdir(codexDir, { recursive: true });
1415
+ await writeFile(join(codexDir, "hooks.json"), JSON.stringify({
1416
+ hooks: {
1417
+ SessionStart: [{
1418
+ matcher: "startup|resume|clear",
1419
+ hooks: [
1420
+ { type: "command", command: 'node "/repo/dist/scripts/codex-native-hook.js"' },
1421
+ { type: "command", command: "echo user-owned" },
1422
+ ],
1423
+ }],
1424
+ },
1425
+ }, null, 2) + "\n");
1426
+ const res = runOmx(wd, ["doctor"], { HOME: home, CODEX_HOME: codexDir });
1427
+ if (shouldSkipForSpawnPermissions(res.error))
1428
+ return;
1429
+ assert.equal(res.status, 0, res.stderr || res.stdout);
1430
+ assert.match(res.stdout, /\[!!\] Native hooks: hooks\.json has OMX entries that cannot be safely removed \(unsafe_managed_removal\): Removing OMX hooks would shift a foreign coordinate or discard opaque metadata; manual cleanup is required because doctor will not overwrite or remove it/);
1431
+ assert.doesNotMatch(res.stdout, /Native hooks:.*--force/);
1432
+ }
1433
+ finally {
1434
+ await rm(wd, { recursive: true, force: true });
1435
+ }
1436
+ });
1437
+ it("fails closed when a Windows native hook references a missing shim", async () => {
1438
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-windows-shim-missing-"));
1439
+ try {
1440
+ const codexDir = join(wd, ".codex");
1441
+ const hooksPath = join(codexDir, "hooks.json");
1442
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
1443
+ await mkdir(codexDir, { recursive: true });
1444
+ const original = buildWindowsShimHooksJson(shimPath, codexDir);
1445
+ await writeFile(hooksPath, original);
1446
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
1447
+ codexHomeDir: codexDir,
1448
+ platform: "win32",
1449
+ });
1450
+ assert.equal(check.status, "fail");
1451
+ assert.match(check.message, /referenced Windows native hook shim is missing at/);
1452
+ assert.match(check.message, /manually reinstall the matching oh-my-codex version/);
1453
+ assert.doesNotMatch(check.message, /omx setup|--force/);
1454
+ assert.equal(existsSync(shimPath), false);
1455
+ assert.equal(await readFile(hooksPath, "utf-8"), original);
1456
+ }
1457
+ finally {
1458
+ await rm(wd, { recursive: true, force: true });
1459
+ }
1460
+ });
1461
+ it("fails closed when a referenced Windows native hook shim is tampered", async () => {
1462
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-windows-shim-tampered-"));
1463
+ try {
1464
+ const codexDir = join(wd, ".codex");
1465
+ const hooksPath = join(codexDir, "hooks.json");
1466
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
1467
+ await mkdir(dirname(shimPath), { recursive: true });
1468
+ const original = buildWindowsShimHooksJson(shimPath, codexDir);
1469
+ const tamperedShim = `${buildManagedCodexNativeHookWindowsShimContent(repoRoot())}# user change\n`;
1470
+ await writeFile(hooksPath, original);
1471
+ await writeFile(shimPath, tamperedShim, "utf-8");
1472
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
1473
+ codexHomeDir: codexDir,
1474
+ platform: "win32",
1475
+ });
1476
+ assert.equal(check.status, "fail");
1477
+ assert.match(check.message, /not an exact current or complete historical generated shim/);
1478
+ assert.match(check.message, /modified, truncated, have extra content, or use ambiguous encoding/);
1479
+ assert.doesNotMatch(check.message, /omx setup|--force/);
1480
+ assert.equal(await readFile(hooksPath, "utf-8"), original);
1481
+ assert.equal(await readFile(shimPath, "utf-8"), tamperedShim);
1482
+ }
1483
+ finally {
1484
+ await rm(wd, { recursive: true, force: true });
1485
+ }
1486
+ });
1487
+ it("accepts a complete historical Windows native hook shim without modifying it", async () => {
1488
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-windows-shim-historical-"));
1489
+ try {
1490
+ const codexDir = join(wd, ".codex");
1491
+ const hooksPath = join(codexDir, "hooks.json");
1492
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
1493
+ await mkdir(dirname(shimPath), { recursive: true });
1494
+ const original = buildWindowsShimHooksJson(shimPath, codexDir);
1495
+ const historicalShim = buildManagedCodexNativeHookWindowsShimContent("", {
1496
+ nodePath: "C:\\Historical Node\\node.exe",
1497
+ hookScriptPath: "C:\\Historical Install\\oh-my-codex\\dist\\scripts\\codex-native-hook.js",
1498
+ });
1499
+ await writeFile(hooksPath, original);
1500
+ await writeFile(shimPath, historicalShim, "utf-8");
1501
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
1502
+ codexHomeDir: codexDir,
1503
+ platform: "win32",
1504
+ });
1505
+ assert.equal(check.status, "pass");
1506
+ assert.match(check.message, /includes OMX-managed coverage for all native hook events/);
1507
+ assert.equal(await readFile(hooksPath, "utf-8"), original);
1508
+ assert.equal(await readFile(shimPath, "utf-8"), historicalShim);
1509
+ }
1510
+ finally {
1511
+ await rm(wd, { recursive: true, force: true });
1512
+ }
1513
+ });
1514
+ it("reports Windows shim integrity before an unsafe managed/foreign group coordinate warning", async () => {
1515
+ for (const fixture of [
1516
+ {
1517
+ name: "missing",
1518
+ shimContent: null,
1519
+ integrity: /referenced Windows native hook shim is missing at/,
1520
+ },
1521
+ {
1522
+ name: "tampered",
1523
+ shimContent: `${buildManagedCodexNativeHookWindowsShimContent(repoRoot())}# mixed-group sentinel\n`,
1524
+ integrity: /not an exact current or complete historical generated shim/,
1525
+ },
1526
+ ]) {
1527
+ const wd = await mkdtemp(join(tmpdir(), `omx-doctor-windows-shim-${fixture.name}-unsafe-`));
1528
+ try {
1529
+ const codexDir = join(wd, ".codex");
1530
+ const hooksPath = join(codexDir, "hooks.json");
1531
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
1532
+ const parsed = JSON.parse(buildWindowsShimHooksJson(shimPath, codexDir));
1533
+ parsed.hooks.PreToolUse[0].hooks.push({
1534
+ type: "command",
1535
+ command: "echo foreign-handler",
1536
+ });
1537
+ await mkdir(codexDir, { recursive: true });
1538
+ await writeFile(hooksPath, `${JSON.stringify(parsed, null, 2)}\n`);
1539
+ if (fixture.shimContent !== null) {
1540
+ await mkdir(dirname(shimPath), { recursive: true });
1541
+ await writeFile(shimPath, fixture.shimContent, "utf-8");
1542
+ }
1543
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
1544
+ codexHomeDir: codexDir,
1545
+ platform: "win32",
1546
+ });
1547
+ assert.equal(check.status, "fail", fixture.name);
1548
+ assert.match(check.message, fixture.integrity, fixture.name);
1549
+ assert.match(check.message, /unsafe_managed_removal/, fixture.name);
1550
+ assert.ok(check.message.search(fixture.integrity) < check.message.indexOf("unsafe_managed_removal"), `${fixture.name} shim integrity must take precedence over the coordinate warning`);
1551
+ }
1552
+ finally {
1553
+ await rm(wd, { recursive: true, force: true });
1554
+ }
1555
+ }
1556
+ });
1557
+ it("never executes missing, tampered, historical, hard-linked, or symlinked Windows shim sentinels during verbose validation", async () => {
1558
+ for (const fixture of [
1559
+ {
1560
+ name: "missing",
1561
+ shimContent: null,
1562
+ hardLink: false,
1563
+ symlinkTarget: null,
1564
+ expected: /referenced Windows native hook shim is missing at/,
1565
+ },
1566
+ {
1567
+ name: "tampered",
1568
+ shimContent: `${buildManagedCodexNativeHookWindowsShimContent(repoRoot())}# verbose-execution sentinel\n`,
1569
+ hardLink: false,
1570
+ symlinkTarget: null,
1571
+ expected: /not an exact current or complete historical generated shim/,
1572
+ },
1573
+ {
1574
+ name: "historical",
1575
+ shimContent: buildManagedCodexNativeHookWindowsShimContent("", {
1576
+ nodePath: "C:\\Historical Node\\node.exe",
1577
+ hookScriptPath: "C:\\Historical Install\\oh-my-codex\\dist\\scripts\\codex-native-hook.js",
1578
+ }),
1579
+ hardLink: false,
1580
+ symlinkTarget: null,
1581
+ expected: /complete historical generated shim.*run "omx setup" to migrate/,
1582
+ },
1583
+ {
1584
+ name: "hard-linked",
1585
+ shimContent: buildManagedCodexNativeHookWindowsShimContent(repoRoot()),
1586
+ hardLink: true,
1587
+ symlinkTarget: null,
1588
+ expected: /is hard-linked; doctor will not execute or modify it/,
1589
+ },
1590
+ {
1591
+ name: "symlinked",
1592
+ shimContent: null,
1593
+ hardLink: false,
1594
+ symlinkTarget: buildManagedCodexNativeHookWindowsShimContent(repoRoot()),
1595
+ expected: /is not a regular file; doctor will not follow or modify it/,
1596
+ },
1597
+ ]) {
1598
+ const wd = await mkdtemp(join(tmpdir(), `omx-doctor-verbose-windows-shim-${fixture.name}-`));
1599
+ try {
1600
+ const codexDir = join(wd, ".codex");
1601
+ const hooksPath = join(codexDir, "hooks.json");
1602
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
1603
+ const command = buildWindowsShimCommand(shimPath);
1604
+ await mkdir(codexDir, { recursive: true });
1605
+ await writeFile(hooksPath, buildWindowsShimHooksJson(shimPath, codexDir));
1606
+ if (fixture.symlinkTarget !== null) {
1607
+ const symlinkTargetPath = join(wd, "symlink-target.ps1");
1608
+ await mkdir(dirname(shimPath), { recursive: true });
1609
+ await writeFile(symlinkTargetPath, fixture.symlinkTarget, "utf-8");
1610
+ await symlink(symlinkTargetPath, shimPath);
1611
+ }
1612
+ else if (fixture.shimContent !== null) {
1613
+ await mkdir(dirname(shimPath), { recursive: true });
1614
+ await writeFile(shimPath, fixture.shimContent, "utf-8");
1615
+ if (fixture.hardLink) {
1616
+ await link(shimPath, join(wd, "canonical-shim-hardlink.ps1"));
1617
+ }
1618
+ }
1619
+ let spawned = false;
1620
+ const check = await checkNativePostCompactHookRuntime(hooksPath, wd, codexDir, {
1621
+ platform: "win32",
1622
+ expectedCommand: command,
1623
+ runner: (() => {
1624
+ spawned = true;
1625
+ throw new Error("unverified Windows shim execution");
1626
+ }),
1627
+ });
1628
+ assert.equal(spawned, false, `${fixture.name} shim executed`);
1629
+ assert.ok(check, `${fixture.name} shim must produce a safety diagnostic`);
1630
+ assert.notEqual(check.status, "pass", fixture.name);
1631
+ assert.match(check.message, fixture.expected, fixture.name);
1632
+ }
1633
+ finally {
1634
+ await rm(wd, { recursive: true, force: true });
1635
+ }
1636
+ }
1637
+ });
1638
+ it("runs exact current Windows shim bytes in memory after canonical replacement, hard-linking, and ancestor retargeting", async () => {
1639
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-verbose-windows-shim-in-memory-"));
1640
+ try {
1641
+ const codexDir = join(wd, ".codex");
1642
+ const hooksPath = join(codexDir, "hooks.json");
1643
+ const hooksDir = join(codexDir, "hooks");
1644
+ const shimPath = join(hooksDir, "omx-native-hook-windows-shim.ps1");
1645
+ const command = buildWindowsShimCommand(shimPath);
1646
+ const currentShim = buildManagedCodexNativeHookWindowsShimContent(repoRoot());
1647
+ const sentinel = "# foreign canonical shim sentinel\n";
1648
+ const foreignHooksDir = join(codexDir, "foreign-hooks");
1649
+ const foreignShimPath = join(foreignHooksDir, "omx-native-hook-windows-shim.ps1");
1650
+ const foreignHardLinkPath = join(foreignHooksDir, "foreign-shim-hard-link.ps1");
1651
+ await mkdir(hooksDir, { recursive: true });
1652
+ await writeFile(hooksPath, buildWindowsShimHooksJson(shimPath, codexDir));
1653
+ await writeFile(shimPath, currentShim, "utf-8");
1654
+ const check = await checkNativePostCompactHookRuntime(hooksPath, wd, codexDir, {
1655
+ platform: "win32",
1656
+ expectedCommand: command,
1657
+ beforeWindowsShimSmoke: async () => {
1658
+ const parkedHooksDir = join(codexDir, "validated-hooks");
1659
+ await rename(hooksDir, parkedHooksDir);
1660
+ await mkdir(foreignHooksDir, { recursive: true });
1661
+ await writeFile(foreignShimPath, sentinel);
1662
+ await link(foreignShimPath, foreignHardLinkPath);
1663
+ await symlink(foreignHooksDir, hooksDir, "dir");
1664
+ },
1665
+ runner: ((_command, args) => {
1666
+ const encodedCommand = args[args.indexOf("-EncodedCommand") + 1];
1667
+ if (typeof encodedCommand !== "string") {
1668
+ throw new Error("PowerShell smoke must receive an encoded in-memory command");
1669
+ }
1670
+ assert.doesNotMatch(args.join("\u0000"), /(?:^|\u0000)-File(?:\u0000|$)/);
1671
+ const smokeCommand = Buffer.from(encodedCommand, "base64").toString("utf16le");
1672
+ assert.doesNotMatch(smokeCommand, /(?:^|\s)-File(?:\s|$)/);
1673
+ assert.equal(smokeCommand.includes(shimPath), false);
1674
+ assert.match(smokeCommand, /\[ScriptBlock\]::Create\(\$omxShimSource\)/);
1675
+ const encodedShimBytes = /FromBase64String\('([A-Za-z0-9+/=]+)'\)/.exec(smokeCommand)?.[1];
1676
+ if (encodedShimBytes === undefined) {
1677
+ throw new Error("encoded PowerShell smoke command omitted validated shim bytes");
1678
+ }
1679
+ assert.deepEqual(Buffer.from(encodedShimBytes, "base64"), Buffer.from(currentShim, "utf-8"));
1680
+ assert.equal(readFileSync(shimPath, "utf-8"), sentinel);
1681
+ assert.equal(readFileSync(foreignHardLinkPath, "utf-8"), sentinel);
1682
+ return { status: 0, stdout: "", stderr: "" };
1683
+ }),
1684
+ });
1685
+ assert.equal(check?.status, "pass");
1686
+ }
1687
+ finally {
1688
+ await rm(wd, { recursive: true, force: true });
1689
+ }
1690
+ });
1691
+ it("preserves a swapped Windows PostCompact smoke root instead of recursively deleting it", async () => {
1692
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-verbose-windows-smoke-root-"));
1693
+ let foreignSmokeCwd = null;
1694
+ let parkedSmokeCwd = null;
1695
+ try {
1696
+ const codexDir = join(wd, ".codex");
1697
+ const hooksPath = join(codexDir, "hooks.json");
1698
+ const hooksDir = join(codexDir, "hooks");
1699
+ const shimPath = join(hooksDir, "omx-native-hook-windows-shim.ps1");
1700
+ const command = buildWindowsShimCommand(shimPath);
1701
+ await mkdir(hooksDir, { recursive: true });
1702
+ await writeFile(hooksPath, buildWindowsShimHooksJson(shimPath, codexDir));
1703
+ await writeFile(shimPath, buildManagedCodexNativeHookWindowsShimContent(repoRoot()), "utf-8");
1704
+ const check = await checkNativePostCompactHookRuntime(hooksPath, wd, codexDir, {
1705
+ platform: "win32",
1706
+ expectedCommand: command,
1707
+ beforeWindowsShimSmoke: ({ smokeCwd }) => {
1708
+ foreignSmokeCwd = smokeCwd;
1709
+ },
1710
+ runner: (() => {
1711
+ const currentSmokeCwd = foreignSmokeCwd;
1712
+ if (currentSmokeCwd === null) {
1713
+ throw new Error("Windows smoke root was not captured before execution");
1714
+ }
1715
+ parkedSmokeCwd = `${currentSmokeCwd}-parked`;
1716
+ renameSync(currentSmokeCwd, parkedSmokeCwd);
1717
+ mkdirSync(currentSmokeCwd, { mode: 0o700 });
1718
+ writeFileSync(join(currentSmokeCwd, "foreign-sentinel.txt"), "foreign smoke root\n");
1719
+ return { status: 0, stdout: "", stderr: "" };
1720
+ }),
1721
+ });
1722
+ assert.equal(check?.status, "warn");
1723
+ assert.match(check?.message ?? "", /temporary PostCompact smoke directory changed during validation/);
1724
+ if (foreignSmokeCwd === null)
1725
+ assert.fail("Windows smoke root was not captured");
1726
+ assert.equal(readFileSync(join(foreignSmokeCwd, "foreign-sentinel.txt"), "utf-8"), "foreign smoke root\n");
1727
+ }
1728
+ finally {
1729
+ if (foreignSmokeCwd !== null)
1730
+ await rm(foreignSmokeCwd, { recursive: true, force: true });
1731
+ if (parkedSmokeCwd !== null)
1732
+ await rm(parkedSmokeCwd, { recursive: true, force: true });
1733
+ await rm(wd, { recursive: true, force: true });
1734
+ }
1735
+ });
1736
+ it("preserves a failed PostCompact smoke result when cleanup retains the smoke directory", async () => {
1737
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-postcompact-smoke-cleanup-failure-"));
1738
+ let smokeCwd = null;
1739
+ try {
1740
+ const codexDir = join(wd, ".codex");
1741
+ const hooksPath = join(codexDir, "hooks.json");
1742
+ const hooksDir = join(codexDir, "hooks");
1743
+ const shimPath = join(hooksDir, "omx-native-hook-windows-shim.ps1");
1744
+ const command = buildWindowsShimCommand(shimPath);
1745
+ await mkdir(hooksDir, { recursive: true });
1746
+ await writeFile(hooksPath, buildWindowsShimHooksJson(shimPath, codexDir));
1747
+ await writeFile(shimPath, buildManagedCodexNativeHookWindowsShimContent(repoRoot()), "utf-8");
1748
+ const check = await checkNativePostCompactHookRuntime(hooksPath, wd, codexDir, {
1749
+ platform: "win32",
1750
+ expectedCommand: command,
1751
+ beforeWindowsShimSmoke: ({ smokeCwd: currentSmokeCwd }) => {
1752
+ smokeCwd = currentSmokeCwd;
1753
+ },
1754
+ runner: (() => {
1755
+ if (smokeCwd === null) {
1756
+ throw new Error("Windows smoke root was not captured before execution");
1757
+ }
1758
+ writeFileSync(join(smokeCwd, "retained-sentinel.txt"), "retained smoke root\n");
1759
+ return { status: 1, stdout: "", stderr: "hook failure" };
1760
+ }),
1761
+ });
1762
+ assert.equal(check?.status, "fail");
1763
+ assert.match(check?.message ?? "", /PostCompact hook smoke validation exited 1: hook failure/);
1764
+ assert.match(check?.message ?? "", /temporary PostCompact smoke directory could not be removed without recursive deletion/);
1765
+ if (smokeCwd === null)
1766
+ assert.fail("Windows smoke root was not captured");
1767
+ assert.equal(readFileSync(join(smokeCwd, "retained-sentinel.txt"), "utf-8"), "retained smoke root\n");
1768
+ }
1769
+ finally {
1770
+ if (smokeCwd !== null)
1771
+ await rm(smokeCwd, { recursive: true, force: true });
1772
+ await rm(wd, { recursive: true, force: true });
1773
+ }
1774
+ });
1775
+ it("preserves a thrown PostCompact smoke error when cleanup also fails", async () => {
1776
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-postcompact-smoke-thrown-cleanup-"));
1777
+ let smokeCwd = null;
1778
+ try {
1779
+ const codexDir = join(wd, ".codex");
1780
+ const hooksPath = join(codexDir, "hooks.json");
1781
+ const hooksDir = join(codexDir, "hooks");
1782
+ const shimPath = join(hooksDir, "omx-native-hook-windows-shim.ps1");
1783
+ const command = buildWindowsShimCommand(shimPath);
1784
+ await mkdir(hooksDir, { recursive: true });
1785
+ await writeFile(hooksPath, buildWindowsShimHooksJson(shimPath, codexDir));
1786
+ await writeFile(shimPath, buildManagedCodexNativeHookWindowsShimContent(repoRoot()), "utf-8");
1787
+ await assert.rejects(checkNativePostCompactHookRuntime(hooksPath, wd, codexDir, {
1788
+ platform: "win32",
1789
+ expectedCommand: command,
1790
+ beforeWindowsShimSmoke: ({ smokeCwd: currentSmokeCwd }) => {
1791
+ smokeCwd = currentSmokeCwd;
1792
+ },
1793
+ runner: (() => {
1794
+ if (smokeCwd === null)
1795
+ throw new Error("Windows smoke root was not captured before execution");
1796
+ writeFileSync(join(smokeCwd, "retained-sentinel.txt"), "retained smoke root\n");
1797
+ throw new Error("primary spawn failure");
1798
+ }),
1799
+ }), /primary spawn failure; temporary PostCompact smoke directory could not be removed without recursive deletion/);
1800
+ }
1801
+ finally {
1802
+ if (smokeCwd !== null)
1803
+ await rm(smokeCwd, { recursive: true, force: true });
1804
+ await rm(wd, { recursive: true, force: true });
1805
+ }
1806
+ });
1807
+ it("reports exact nested legacy hook trust state as migration-required without modifying hooks.json", async () => {
1808
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-hooks-legacy-trust-"));
1809
+ try {
1810
+ const home = join(wd, "home");
1811
+ const codexDir = join(home, ".codex");
1812
+ await mkdir(codexDir, { recursive: true });
1813
+ const parsed = JSON.parse(buildHooksJsonWithPostCompactCommand(currentNativeHookCommand(codexDir), codexDir));
1814
+ parsed.hooks.state = {
1815
+ "custom:/hooks.json:stop:0:0": {
1816
+ trusted_hash: "sha256:legacy",
1817
+ enabled: false,
1818
+ },
1819
+ };
1820
+ const hooksPath = join(codexDir, "hooks.json");
1821
+ const original = `${JSON.stringify(parsed, null, 2)}\n`;
1822
+ await writeFile(hooksPath, original);
1823
+ const res = runOmx(wd, ["doctor"], { HOME: home, CODEX_HOME: codexDir });
1824
+ if (shouldSkipForSpawnPermissions(res.error))
1825
+ return;
1826
+ assert.equal(res.status, 0, res.stderr || res.stdout);
1827
+ assert.match(res.stdout, /\[!!\] Native hooks: hooks\.json contains 1 exact historical OMX hook trust-state entry that requires migration; run "omx setup" to migrate it after reviewing the configuration/);
1828
+ assert.doesNotMatch(res.stdout, /Native hooks: hooks\.json includes OMX-managed coverage/);
1829
+ assert.doesNotMatch(res.stdout, /Native hooks:.*--force/);
1830
+ assert.equal(await readFile(hooksPath, "utf-8"), original);
1831
+ }
1832
+ finally {
1833
+ await rm(wd, { recursive: true, force: true });
1834
+ }
1835
+ });
1836
+ it("preserves nonmatching nested hooks.state without reporting a migration", async () => {
1837
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-hooks-nonlegacy-state-"));
1838
+ try {
1839
+ const home = join(wd, "home");
1840
+ const codexDir = join(home, ".codex");
1841
+ await mkdir(codexDir, { recursive: true });
1842
+ const parsed = JSON.parse(buildHooksJsonWithPostCompactCommand(currentNativeHookCommand(codexDir), codexDir));
1843
+ parsed.hooks.state = {
1844
+ retained: { custom: true, trusted_hash: "sha256:not-omx" },
1845
+ };
1846
+ const hooksPath = join(codexDir, "hooks.json");
1847
+ const original = `${JSON.stringify(parsed, null, 2)}\n`;
1848
+ await writeFile(hooksPath, original);
1849
+ const res = runOmx(wd, ["doctor"], { HOME: home, CODEX_HOME: codexDir });
1850
+ if (shouldSkipForSpawnPermissions(res.error))
1851
+ return;
1852
+ assert.equal(res.status, 0, res.stderr || res.stdout);
1853
+ assert.match(res.stdout, /\[OK\] Native hooks: hooks\.json includes OMX-managed coverage for all native hook events/);
1854
+ assert.doesNotMatch(res.stdout, /Native hooks:.*legacy OMX hook trust-state/);
1855
+ assert.equal(await readFile(hooksPath, "utf-8"), original);
1313
1856
  }
1314
1857
  finally {
1315
1858
  await rm(wd, { recursive: true, force: true });
@@ -1407,8 +1950,9 @@ command = "node"
1407
1950
  assert.equal(check.name, "Native hook dist smoke");
1408
1951
  assert.equal(check.status, "fail");
1409
1952
  assert.match(check.message, /minimal UserPromptSubmit smoke/);
1410
- assert.match(check.message, /npm install -g oh-my-codex@0\.18\.0 --force --min-release-age=0 --before=/);
1411
- assert.match(check.message, /omx setup --force/);
1953
+ assert.match(check.message, /reinstall the matching oh-my-codex version/);
1954
+ assert.doesNotMatch(check.message, /--force/);
1955
+ assert.match(check.message, /run "omx setup"/);
1412
1956
  }
1413
1957
  finally {
1414
1958
  await rm(wd, { recursive: true, force: true });
@@ -1489,7 +2033,7 @@ command = "node"
1489
2033
  assert.equal(res.status, 0, res.stderr || res.stdout);
1490
2034
  assert.match(res.stdout, /Resolved setup scope: project \(from \.omx\/setup-scope\.json\)/);
1491
2035
  assert.equal(res.stdout.match(/\[!!\] GPT-5\.6 multi-agent compatibility:/g)?.length, 1);
1492
- assert.match(res.stdout, new RegExp(`project scope config at ${configPath}`));
2036
+ assert.match(res.stdout, new RegExp(`project scope config at ${join(await realpath(wd), ".codex", "config.toml")}`));
1493
2037
  assert.match(res.stdout, /features\.multi_agent \(custom; custom-value\)/);
1494
2038
  assert.match(res.stdout, /agents\.max_threads \(custom; custom-value\)/);
1495
2039
  assert.match(res.stdout, /agents\.max_depth \(custom; custom-value\)/);
@@ -1526,5 +2070,198 @@ command = "node"
1526
2070
  await rm(wd, { recursive: true, force: true });
1527
2071
  }
1528
2072
  });
2073
+ it("validates an existing global hooks.json before reporting plugin-cache status", async () => {
2074
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-plugin-global-invalid-"));
2075
+ try {
2076
+ const codexDir = join(wd, ".codex");
2077
+ const configPath = join(codexDir, "config.toml");
2078
+ const hooksPath = join(codexDir, "hooks.json");
2079
+ await mkdir(codexDir, { recursive: true });
2080
+ await writeFile(configPath, "plugin_hooks = true\n");
2081
+ await writeFile(hooksPath, '{"state":{}}\n');
2082
+ const check = await checkNativeHooks(hooksPath, configPath, {
2083
+ codexHomeDir: codexDir,
2084
+ installMode: "plugin",
2085
+ });
2086
+ assert.equal(check.status, "fail");
2087
+ assert.match(check.message, /plugin-scoped hooks are enabled/);
2088
+ assert.match(check.message, /existing global hooks\.json: hooks\.json failed strict load validation/);
2089
+ assert.match(check.message, /unknown root field state/);
2090
+ }
2091
+ finally {
2092
+ await rm(wd, { recursive: true, force: true });
2093
+ }
2094
+ });
2095
+ it("fails plugin mode when an existing global Windows shim is tampered", async () => {
2096
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-plugin-global-shim-"));
2097
+ try {
2098
+ const codexDir = join(wd, ".codex");
2099
+ const configPath = join(codexDir, "config.toml");
2100
+ const hooksPath = join(codexDir, "hooks.json");
2101
+ const shimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
2102
+ await mkdir(dirname(shimPath), { recursive: true });
2103
+ await writeFile(configPath, "plugin_hooks = true\n");
2104
+ await writeFile(hooksPath, `${JSON.stringify({
2105
+ hooks: {
2106
+ PostCompact: [{ hooks: [{ type: "command", command: buildWindowsShimCommand(shimPath) }] }],
2107
+ },
2108
+ })}\n`);
2109
+ await writeFile(shimPath, "# modified\n");
2110
+ const check = await checkNativeHooks(hooksPath, configPath, {
2111
+ codexHomeDir: codexDir,
2112
+ installMode: "plugin",
2113
+ platform: "win32",
2114
+ });
2115
+ assert.equal(check.status, "fail");
2116
+ assert.match(check.message, /not an exact current or complete historical generated shim/);
2117
+ assert.match(check.message, /plugin-scoped hooks are enabled/);
2118
+ }
2119
+ finally {
2120
+ await rm(wd, { recursive: true, force: true });
2121
+ }
2122
+ });
2123
+ it("fails ambiguous managed handler ownership instead of downgrading it to a warning", async () => {
2124
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-ambiguous-managed-handler-"));
2125
+ try {
2126
+ const codexDir = join(wd, ".codex");
2127
+ const hooksPath = join(codexDir, "hooks.json");
2128
+ await mkdir(codexDir, { recursive: true });
2129
+ await writeFile(hooksPath, `${JSON.stringify({
2130
+ hooks: {
2131
+ SessionStart: [{
2132
+ matcher: "startup|resume|clear",
2133
+ hooks: [{ type: "command", command: "node /repo/dist/scripts/codex-native-hook.js --unexpected" }],
2134
+ }],
2135
+ },
2136
+ })}\n`);
2137
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
2138
+ codexHomeDir: codexDir,
2139
+ });
2140
+ assert.equal(check.status, "fail");
2141
+ assert.match(check.message, /ambiguous_managed_handler/);
2142
+ assert.match(check.message, /ambiguous or untrusted OMX ownership/);
2143
+ }
2144
+ finally {
2145
+ await rm(wd, { recursive: true, force: true });
2146
+ }
2147
+ });
2148
+ it("fails closed instead of recognizing a shell-expanding foreign command as an OMX hook", async () => {
2149
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-shell-expanding-handler-"));
2150
+ try {
2151
+ const codexDir = join(wd, ".codex");
2152
+ const hooksPath = join(codexDir, "hooks.json");
2153
+ await mkdir(codexDir, { recursive: true });
2154
+ await writeFile(hooksPath, `${JSON.stringify({
2155
+ hooks: {
2156
+ SessionStart: [{
2157
+ matcher: "startup|resume|clear",
2158
+ hooks: [{ type: "command", command: 'node "$HOME/repo/dist/scripts/codex-native-hook.js"' }],
2159
+ }],
2160
+ },
2161
+ })}\n`);
2162
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
2163
+ codexHomeDir: codexDir,
2164
+ });
2165
+ assert.equal(check.status, "fail");
2166
+ assert.match(check.message, /ambiguous_managed_handler|does not match the managed command grammar/i);
2167
+ }
2168
+ finally {
2169
+ await rm(wd, { recursive: true, force: true });
2170
+ }
2171
+ });
2172
+ it("ignores prompt, agent, and future-event metadata while scanning Windows shim references", async () => {
2173
+ const wd = await mkdtemp(join(tmpdir(), "omx-doctor-inert-shim-metadata-"));
2174
+ try {
2175
+ const codexDir = join(wd, ".codex");
2176
+ const hooksPath = join(codexDir, "hooks.json");
2177
+ const missingShimPath = join(codexDir, "hooks", "omx-native-hook-windows-shim.ps1");
2178
+ await mkdir(codexDir, { recursive: true });
2179
+ await writeFile(hooksPath, `${JSON.stringify({
2180
+ hooks: {
2181
+ PostCompact: [{ hooks: [
2182
+ { type: "prompt", command: buildWindowsShimCommand(missingShimPath) },
2183
+ { type: "agent", commandWindows: buildWindowsShimCommand(missingShimPath) },
2184
+ ] }],
2185
+ FutureSerdeEvent: [{ hooks: [{ type: "command", command: buildWindowsShimCommand(missingShimPath) }] }],
2186
+ },
2187
+ })}\n`);
2188
+ const check = await checkNativeHooks(hooksPath, join(codexDir, "config.toml"), {
2189
+ codexHomeDir: codexDir,
2190
+ platform: "win32",
2191
+ });
2192
+ assert.equal(check.status, "warn");
2193
+ assert.match(check.message, /hooks\.json discovery warnings/);
2194
+ assert.doesNotMatch(check.message, /referenced Windows native hook shim/);
2195
+ }
2196
+ finally {
2197
+ await rm(wd, { recursive: true, force: true });
2198
+ }
2199
+ });
2200
+ it("recovers a claim journal after Windows regular-file EPERM with one degraded-durability warning", async () => {
2201
+ const originalStderrWrite = process.stderr.write;
2202
+ const stderr = [];
2203
+ try {
2204
+ await withRecoverableDoctorClaimJournal(async (codexHomeDir) => {
2205
+ const restoreDurability = setDoctorClaimJournalDurabilityForTest({
2206
+ platform: "win32",
2207
+ syncRegularFile: async () => syncRegularFile({
2208
+ sync: async () => {
2209
+ throw Object.assign(new Error("injected Windows EPERM"), { code: "EPERM" });
2210
+ },
2211
+ }, "win32"),
2212
+ syncDirectory: async () => undefined,
2213
+ });
2214
+ process.stderr.write = ((chunk) => {
2215
+ stderr.push(String(chunk));
2216
+ return true;
2217
+ });
2218
+ try {
2219
+ await doctor();
2220
+ assert.equal(await readFile(join(codexHomeDir, "hooks.json"), "utf-8"), "{\"hooks\":{}}\n");
2221
+ await assert.rejects(readFile(join(codexHomeDir, ".omx", "native-hook-claim-journal.json")), /ENOENT/);
2222
+ }
2223
+ finally {
2224
+ restoreDurability();
2225
+ }
2226
+ });
2227
+ assert.equal(stderr.length, 1);
2228
+ assert.match(stderr[0], /Windows EPERM/);
2229
+ assert.match(stderr[0], /native-hook claim-journal recovery/);
2230
+ assert.match(stderr[0], /degraded durability/);
2231
+ }
2232
+ finally {
2233
+ process.stderr.write = originalStderrWrite;
2234
+ }
2235
+ });
2236
+ it("keeps non-EPERM regular-file and directory claim-journal sync failures fatal", async () => {
2237
+ const regularError = Object.assign(new Error("injected regular-file EIO"), { code: "EIO" });
2238
+ await withRecoverableDoctorClaimJournal(async () => {
2239
+ const restoreDurability = setDoctorClaimJournalDurabilityForTest({
2240
+ platform: "win32",
2241
+ syncRegularFile: async () => { throw regularError; },
2242
+ syncDirectory: async () => undefined,
2243
+ });
2244
+ try {
2245
+ await assert.rejects(doctor(), (error) => error === regularError);
2246
+ }
2247
+ finally {
2248
+ restoreDurability();
2249
+ }
2250
+ });
2251
+ const directoryError = Object.assign(new Error("injected directory EPERM"), { code: "EPERM" });
2252
+ await withRecoverableDoctorClaimJournal(async () => {
2253
+ const restoreDurability = setDoctorClaimJournalDurabilityForTest({
2254
+ platform: "win32",
2255
+ syncRegularFile: async () => "synced",
2256
+ syncDirectory: async () => { throw directoryError; },
2257
+ });
2258
+ try {
2259
+ await assert.rejects(doctor(), (error) => error === directoryError);
2260
+ }
2261
+ finally {
2262
+ restoreDurability();
2263
+ }
2264
+ });
2265
+ });
1529
2266
  });
1530
2267
  //# sourceMappingURL=doctor-warning-copy.test.js.map