oh-my-codex 0.15.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +36 -5
  4. package/crates/omx-explore/src/main.rs +222 -12
  5. package/dist/agents/__tests__/native-config.test.js +40 -0
  6. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  7. package/dist/agents/native-config.d.ts +1 -0
  8. package/dist/agents/native-config.d.ts.map +1 -1
  9. package/dist/agents/native-config.js +6 -1
  10. package/dist/agents/native-config.js.map +1 -1
  11. package/dist/agents/policy.d.ts +1 -0
  12. package/dist/agents/policy.d.ts.map +1 -1
  13. package/dist/agents/policy.js +4 -0
  14. package/dist/agents/policy.js.map +1 -1
  15. package/dist/cli/__tests__/autoresearch-guided.test.js +37 -13
  16. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  17. package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -1
  18. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  19. package/dist/cli/__tests__/doctor-team.test.js +46 -1
  20. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  21. package/dist/cli/__tests__/doctor-warning-copy.test.js +225 -111
  22. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  23. package/dist/cli/__tests__/exec.test.js +96 -1
  24. package/dist/cli/__tests__/exec.test.js.map +1 -1
  25. package/dist/cli/__tests__/explore.test.js +15 -2
  26. package/dist/cli/__tests__/explore.test.js.map +1 -1
  27. package/dist/cli/__tests__/index.test.js +292 -3
  28. package/dist/cli/__tests__/index.test.js.map +1 -1
  29. package/dist/cli/__tests__/launch-fallback.test.js +223 -0
  30. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  31. package/dist/cli/__tests__/mcp-parity.test.js +86 -0
  32. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  33. package/dist/cli/__tests__/package-bin-contract.test.js +23 -0
  34. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  35. package/dist/cli/__tests__/question.test.js +76 -11
  36. package/dist/cli/__tests__/question.test.js.map +1 -1
  37. package/dist/cli/__tests__/setup-agents-overwrite.test.js +140 -1
  38. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  39. package/dist/cli/__tests__/setup-install-mode.test.js +310 -4
  40. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  41. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +78 -19
  42. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
  43. package/dist/cli/__tests__/setup-refresh.test.js +79 -2
  44. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  45. package/dist/cli/__tests__/sidecar.test.d.ts +2 -0
  46. package/dist/cli/__tests__/sidecar.test.d.ts.map +1 -0
  47. package/dist/cli/__tests__/sidecar.test.js +24 -0
  48. package/dist/cli/__tests__/sidecar.test.js.map +1 -0
  49. package/dist/cli/__tests__/team.test.js +54 -7
  50. package/dist/cli/__tests__/team.test.js.map +1 -1
  51. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  52. package/dist/cli/autoresearch-guided.js +12 -4
  53. package/dist/cli/autoresearch-guided.js.map +1 -1
  54. package/dist/cli/codex-home.d.ts +4 -6
  55. package/dist/cli/codex-home.d.ts.map +1 -1
  56. package/dist/cli/codex-home.js +9 -41
  57. package/dist/cli/codex-home.js.map +1 -1
  58. package/dist/cli/doctor.d.ts +1 -1
  59. package/dist/cli/doctor.d.ts.map +1 -1
  60. package/dist/cli/doctor.js +509 -279
  61. package/dist/cli/doctor.js.map +1 -1
  62. package/dist/cli/index.d.ts +6 -4
  63. package/dist/cli/index.d.ts.map +1 -1
  64. package/dist/cli/index.js +284 -25
  65. package/dist/cli/index.js.map +1 -1
  66. package/dist/cli/omx.js +3 -1
  67. package/dist/cli/omx.js.map +1 -1
  68. package/dist/cli/plugin-marketplace.d.ts +13 -0
  69. package/dist/cli/plugin-marketplace.d.ts.map +1 -0
  70. package/dist/cli/plugin-marketplace.js +77 -0
  71. package/dist/cli/plugin-marketplace.js.map +1 -0
  72. package/dist/cli/question.d.ts +1 -1
  73. package/dist/cli/question.d.ts.map +1 -1
  74. package/dist/cli/question.js +26 -12
  75. package/dist/cli/question.js.map +1 -1
  76. package/dist/cli/setup-preferences.d.ts +20 -0
  77. package/dist/cli/setup-preferences.d.ts.map +1 -0
  78. package/dist/cli/setup-preferences.js +71 -0
  79. package/dist/cli/setup-preferences.js.map +1 -0
  80. package/dist/cli/setup.d.ts +7 -5
  81. package/dist/cli/setup.d.ts.map +1 -1
  82. package/dist/cli/setup.js +271 -152
  83. package/dist/cli/setup.js.map +1 -1
  84. package/dist/cli/team.d.ts +1 -0
  85. package/dist/cli/team.d.ts.map +1 -1
  86. package/dist/cli/team.js +70 -15
  87. package/dist/cli/team.js.map +1 -1
  88. package/dist/config/__tests__/generator-idempotent.test.js +100 -3
  89. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  90. package/dist/config/__tests__/generator-notify.test.js +6 -5
  91. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  92. package/dist/config/__tests__/generator-status-line-presets.test.d.ts +2 -0
  93. package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +1 -0
  94. package/dist/config/__tests__/generator-status-line-presets.test.js +203 -0
  95. package/dist/config/__tests__/generator-status-line-presets.test.js.map +1 -0
  96. package/dist/config/__tests__/models.test.js +23 -1
  97. package/dist/config/__tests__/models.test.js.map +1 -1
  98. package/dist/config/generator.d.ts +9 -1
  99. package/dist/config/generator.d.ts.map +1 -1
  100. package/dist/config/generator.js +184 -16
  101. package/dist/config/generator.js.map +1 -1
  102. package/dist/config/models.d.ts +5 -1
  103. package/dist/config/models.d.ts.map +1 -1
  104. package/dist/config/models.js +12 -2
  105. package/dist/config/models.js.map +1 -1
  106. package/dist/exec/followup.d.ts +44 -0
  107. package/dist/exec/followup.d.ts.map +1 -0
  108. package/dist/exec/followup.js +349 -0
  109. package/dist/exec/followup.js.map +1 -0
  110. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +2 -0
  111. package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +1 -0
  112. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +37 -0
  113. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -0
  114. package/dist/hooks/__tests__/codebase-map.test.js +63 -1
  115. package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
  116. package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
  117. package/dist/hooks/__tests__/consensus-execution-handoff.test.js +5 -5
  118. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  119. package/dist/hooks/__tests__/deep-interview-contract.test.js +12 -9
  120. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  121. package/dist/hooks/__tests__/keyword-detector.test.js +25 -18
  122. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  123. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +23 -2
  124. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  125. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +45 -2
  126. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  127. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +17 -0
  128. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  129. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +121 -0
  130. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  131. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +4 -4
  132. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  133. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +103 -0
  134. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  135. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +2 -2
  136. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  137. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +27 -13
  138. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  139. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +2 -0
  140. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +1 -0
  141. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +35 -0
  142. package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -0
  143. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +215 -0
  144. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  145. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +70 -3
  146. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  147. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +5 -0
  148. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  149. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +3 -2
  150. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
  151. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +9 -0
  152. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  153. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +2 -0
  154. package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +1 -0
  155. package/dist/hooks/__tests__/prompt-refactor-contract.test.js +22 -0
  156. package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +1 -0
  157. package/dist/hooks/codebase-map.d.ts.map +1 -1
  158. package/dist/hooks/codebase-map.js +83 -6
  159. package/dist/hooks/codebase-map.js.map +1 -1
  160. package/dist/hooks/keyword-detector.d.ts +1 -1
  161. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  162. package/dist/hooks/keyword-detector.js +35 -4
  163. package/dist/hooks/keyword-detector.js.map +1 -1
  164. package/dist/hooks/prompt-guidance-contract.d.ts +6 -0
  165. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  166. package/dist/hooks/prompt-guidance-contract.js +117 -13
  167. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  168. package/dist/hooks/session.d.ts +2 -0
  169. package/dist/hooks/session.d.ts.map +1 -1
  170. package/dist/hooks/session.js +6 -0
  171. package/dist/hooks/session.js.map +1 -1
  172. package/dist/hud/__tests__/index.test.js +4 -4
  173. package/dist/hud/__tests__/index.test.js.map +1 -1
  174. package/dist/hud/__tests__/state.test.js +4 -0
  175. package/dist/hud/__tests__/state.test.js.map +1 -1
  176. package/dist/hud/__tests__/types.test.js +27 -0
  177. package/dist/hud/__tests__/types.test.js.map +1 -1
  178. package/dist/hud/state.d.ts.map +1 -1
  179. package/dist/hud/state.js +8 -0
  180. package/dist/hud/state.js.map +1 -1
  181. package/dist/hud/types.d.ts +9 -0
  182. package/dist/hud/types.d.ts.map +1 -1
  183. package/dist/hud/types.js +3 -0
  184. package/dist/hud/types.js.map +1 -1
  185. package/dist/mcp/__tests__/bootstrap.test.js +23 -5
  186. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  187. package/dist/mcp/__tests__/server-lifecycle.test.js +50 -7
  188. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  189. package/dist/mcp/__tests__/state-server.test.js +70 -12
  190. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  191. package/dist/mcp/bootstrap.d.ts +10 -1
  192. package/dist/mcp/bootstrap.d.ts.map +1 -1
  193. package/dist/mcp/bootstrap.js +71 -26
  194. package/dist/mcp/bootstrap.js.map +1 -1
  195. package/dist/mcp/state-server.d.ts +5 -11
  196. package/dist/mcp/state-server.d.ts.map +1 -1
  197. package/dist/mcp/state-server.js +16 -432
  198. package/dist/mcp/state-server.js.map +1 -1
  199. package/dist/modes/__tests__/base-autoresearch-contract.test.js +1 -1
  200. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
  201. package/dist/pipeline/__tests__/orchestrator.test.js +89 -5
  202. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  203. package/dist/pipeline/__tests__/stages.test.js +98 -1
  204. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  205. package/dist/pipeline/index.d.ts +5 -3
  206. package/dist/pipeline/index.d.ts.map +1 -1
  207. package/dist/pipeline/index.js +4 -3
  208. package/dist/pipeline/index.js.map +1 -1
  209. package/dist/pipeline/orchestrator.d.ts +7 -6
  210. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  211. package/dist/pipeline/orchestrator.js +90 -11
  212. package/dist/pipeline/orchestrator.js.map +1 -1
  213. package/dist/pipeline/review-verdict.d.ts +3 -0
  214. package/dist/pipeline/review-verdict.d.ts.map +1 -0
  215. package/dist/pipeline/review-verdict.js +14 -0
  216. package/dist/pipeline/review-verdict.js.map +1 -0
  217. package/dist/pipeline/stages/code-review.d.ts +33 -0
  218. package/dist/pipeline/stages/code-review.d.ts.map +1 -0
  219. package/dist/pipeline/stages/code-review.js +51 -0
  220. package/dist/pipeline/stages/code-review.js.map +1 -0
  221. package/dist/pipeline/stages/ralph-verify.d.ts +12 -2
  222. package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
  223. package/dist/pipeline/stages/ralph-verify.js +24 -6
  224. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  225. package/dist/pipeline/stages/ralplan.d.ts +1 -1
  226. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  227. package/dist/pipeline/stages/ralplan.js +21 -1
  228. package/dist/pipeline/stages/ralplan.js.map +1 -1
  229. package/dist/pipeline/types.d.ts +14 -7
  230. package/dist/pipeline/types.d.ts.map +1 -1
  231. package/dist/pipeline/types.js +2 -2
  232. package/dist/planning/__tests__/artifacts.test.js +152 -1
  233. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  234. package/dist/planning/artifacts.d.ts +9 -0
  235. package/dist/planning/artifacts.d.ts.map +1 -1
  236. package/dist/planning/artifacts.js +60 -1
  237. package/dist/planning/artifacts.js.map +1 -1
  238. package/dist/question/__tests__/client.test.js +23 -3
  239. package/dist/question/__tests__/client.test.js.map +1 -1
  240. package/dist/question/__tests__/renderer.test.js +148 -37
  241. package/dist/question/__tests__/renderer.test.js.map +1 -1
  242. package/dist/question/__tests__/types.test.js +21 -0
  243. package/dist/question/__tests__/types.test.js.map +1 -1
  244. package/dist/question/__tests__/ui.test.js +155 -7
  245. package/dist/question/__tests__/ui.test.js.map +1 -1
  246. package/dist/question/client.d.ts +14 -4
  247. package/dist/question/client.d.ts.map +1 -1
  248. package/dist/question/client.js.map +1 -1
  249. package/dist/question/renderer.d.ts +11 -1
  250. package/dist/question/renderer.d.ts.map +1 -1
  251. package/dist/question/renderer.js +102 -7
  252. package/dist/question/renderer.js.map +1 -1
  253. package/dist/question/state.d.ts +2 -2
  254. package/dist/question/state.d.ts.map +1 -1
  255. package/dist/question/state.js +26 -17
  256. package/dist/question/state.js.map +1 -1
  257. package/dist/question/types.d.ts +25 -1
  258. package/dist/question/types.d.ts.map +1 -1
  259. package/dist/question/types.js +48 -13
  260. package/dist/question/types.js.map +1 -1
  261. package/dist/question/ui.d.ts +15 -2
  262. package/dist/question/ui.d.ts.map +1 -1
  263. package/dist/question/ui.js +268 -162
  264. package/dist/question/ui.js.map +1 -1
  265. package/dist/scripts/__tests__/codex-native-hook.test.js +415 -94
  266. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  267. package/dist/scripts/__tests__/generate-release-body.test.js +36 -0
  268. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
  269. package/dist/scripts/__tests__/prompt-inventory.test.d.ts +2 -0
  270. package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +1 -0
  271. package/dist/scripts/__tests__/prompt-inventory.test.js +56 -0
  272. package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -0
  273. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  274. package/dist/scripts/codex-native-hook.js +232 -54
  275. package/dist/scripts/codex-native-hook.js.map +1 -1
  276. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  277. package/dist/scripts/codex-native-pre-post.js +12 -9
  278. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  279. package/dist/scripts/generate-release-body.d.ts.map +1 -1
  280. package/dist/scripts/generate-release-body.js +12 -3
  281. package/dist/scripts/generate-release-body.js.map +1 -1
  282. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +2 -0
  283. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +1 -0
  284. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +153 -0
  285. package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +1 -0
  286. package/dist/scripts/notify-hook/managed-tmux.d.ts +4 -2
  287. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  288. package/dist/scripts/notify-hook/managed-tmux.js +188 -6
  289. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  290. package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
  291. package/dist/scripts/notify-hook/process-runner.js +7 -3
  292. package/dist/scripts/notify-hook/process-runner.js.map +1 -1
  293. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  294. package/dist/scripts/notify-hook/team-dispatch.js +96 -11
  295. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  296. package/dist/scripts/notify-hook/team-tmux-guard.js +3 -3
  297. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts +34 -0
  298. package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts.map +1 -0
  299. package/dist/scripts/notify-hook/team-worker-posttooluse.js +434 -0
  300. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -0
  301. package/dist/scripts/notify-hook/team-worker.d.ts +1 -1
  302. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  303. package/dist/scripts/notify-hook/team-worker.js +3 -43
  304. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  305. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  306. package/dist/scripts/notify-hook/tmux-injection.js +25 -4
  307. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  308. package/dist/scripts/notify-hook.js +36 -5
  309. package/dist/scripts/notify-hook.js.map +1 -1
  310. package/dist/scripts/prompt-inventory.d.ts +29 -0
  311. package/dist/scripts/prompt-inventory.d.ts.map +1 -0
  312. package/dist/scripts/prompt-inventory.js +178 -0
  313. package/dist/scripts/prompt-inventory.js.map +1 -0
  314. package/dist/scripts/run-test-files.js +1 -0
  315. package/dist/scripts/run-test-files.js.map +1 -1
  316. package/dist/sidecar/__tests__/boundary.test.d.ts +2 -0
  317. package/dist/sidecar/__tests__/boundary.test.d.ts.map +1 -0
  318. package/dist/sidecar/__tests__/boundary.test.js +48 -0
  319. package/dist/sidecar/__tests__/boundary.test.js.map +1 -0
  320. package/dist/sidecar/__tests__/collector.test.d.ts +2 -0
  321. package/dist/sidecar/__tests__/collector.test.d.ts.map +1 -0
  322. package/dist/sidecar/__tests__/collector.test.js +162 -0
  323. package/dist/sidecar/__tests__/collector.test.js.map +1 -0
  324. package/dist/sidecar/__tests__/render.test.d.ts +2 -0
  325. package/dist/sidecar/__tests__/render.test.d.ts.map +1 -0
  326. package/dist/sidecar/__tests__/render.test.js +67 -0
  327. package/dist/sidecar/__tests__/render.test.js.map +1 -0
  328. package/dist/sidecar/__tests__/tmux.test.d.ts +2 -0
  329. package/dist/sidecar/__tests__/tmux.test.d.ts.map +1 -0
  330. package/dist/sidecar/__tests__/tmux.test.js +30 -0
  331. package/dist/sidecar/__tests__/tmux.test.js.map +1 -0
  332. package/dist/sidecar/__tests__/watch.test.d.ts +2 -0
  333. package/dist/sidecar/__tests__/watch.test.d.ts.map +1 -0
  334. package/dist/sidecar/__tests__/watch.test.js +42 -0
  335. package/dist/sidecar/__tests__/watch.test.js.map +1 -0
  336. package/dist/sidecar/collector.d.ts +4 -0
  337. package/dist/sidecar/collector.d.ts.map +1 -0
  338. package/dist/sidecar/collector.js +377 -0
  339. package/dist/sidecar/collector.js.map +1 -0
  340. package/dist/sidecar/index.d.ts +25 -0
  341. package/dist/sidecar/index.d.ts.map +1 -0
  342. package/dist/sidecar/index.js +165 -0
  343. package/dist/sidecar/index.js.map +1 -0
  344. package/dist/sidecar/render.d.ts +3 -0
  345. package/dist/sidecar/render.d.ts.map +1 -0
  346. package/dist/sidecar/render.js +72 -0
  347. package/dist/sidecar/render.js.map +1 -0
  348. package/dist/sidecar/tmux.d.ts +13 -0
  349. package/dist/sidecar/tmux.d.ts.map +1 -0
  350. package/dist/sidecar/tmux.js +44 -0
  351. package/dist/sidecar/tmux.js.map +1 -0
  352. package/dist/sidecar/types.d.ts +125 -0
  353. package/dist/sidecar/types.d.ts.map +1 -0
  354. package/dist/sidecar/types.js +2 -0
  355. package/dist/sidecar/types.js.map +1 -0
  356. package/dist/state/__tests__/operations.test.js +50 -22
  357. package/dist/state/__tests__/operations.test.js.map +1 -1
  358. package/dist/state/__tests__/workflow-transition.test.js +9 -1
  359. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  360. package/dist/state/operations.d.ts +1 -1
  361. package/dist/state/operations.d.ts.map +1 -1
  362. package/dist/state/operations.js +19 -7
  363. package/dist/state/operations.js.map +1 -1
  364. package/dist/state/workflow-transition.d.ts.map +1 -1
  365. package/dist/state/workflow-transition.js +1 -0
  366. package/dist/state/workflow-transition.js.map +1 -1
  367. package/dist/team/__tests__/commit-hygiene.test.d.ts +2 -0
  368. package/dist/team/__tests__/commit-hygiene.test.d.ts.map +1 -0
  369. package/dist/team/__tests__/commit-hygiene.test.js +93 -0
  370. package/dist/team/__tests__/commit-hygiene.test.js.map +1 -0
  371. package/dist/team/__tests__/delegation-policy.test.d.ts +2 -0
  372. package/dist/team/__tests__/delegation-policy.test.d.ts.map +1 -0
  373. package/dist/team/__tests__/delegation-policy.test.js +69 -0
  374. package/dist/team/__tests__/delegation-policy.test.js.map +1 -0
  375. package/dist/team/__tests__/events.test.js +54 -4
  376. package/dist/team/__tests__/events.test.js.map +1 -1
  377. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +2 -0
  378. package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +1 -0
  379. package/dist/team/__tests__/hook-primary-e2e-contract.test.js +78 -0
  380. package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +1 -0
  381. package/dist/team/__tests__/model-contract.test.js +16 -0
  382. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  383. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +2 -0
  384. package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +1 -0
  385. package/dist/team/__tests__/repo-aware-decomposition.test.js +95 -0
  386. package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -0
  387. package/dist/team/__tests__/runtime.test.js +623 -14
  388. package/dist/team/__tests__/runtime.test.js.map +1 -1
  389. package/dist/team/__tests__/state-root.test.js +177 -1
  390. package/dist/team/__tests__/state-root.test.js.map +1 -1
  391. package/dist/team/__tests__/state.test.js +110 -0
  392. package/dist/team/__tests__/state.test.js.map +1 -1
  393. package/dist/team/__tests__/tmux-session.test.js +399 -2
  394. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  395. package/dist/team/__tests__/worker-bootstrap.test.js +94 -0
  396. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  397. package/dist/team/commit-hygiene.d.ts +22 -3
  398. package/dist/team/commit-hygiene.d.ts.map +1 -1
  399. package/dist/team/commit-hygiene.js +134 -2
  400. package/dist/team/commit-hygiene.js.map +1 -1
  401. package/dist/team/contracts.d.ts +1 -1
  402. package/dist/team/contracts.d.ts.map +1 -1
  403. package/dist/team/contracts.js +2 -0
  404. package/dist/team/contracts.js.map +1 -1
  405. package/dist/team/dag-schema.d.ts +38 -0
  406. package/dist/team/dag-schema.d.ts.map +1 -0
  407. package/dist/team/dag-schema.js +221 -0
  408. package/dist/team/dag-schema.js.map +1 -0
  409. package/dist/team/delegation-policy.d.ts +3 -0
  410. package/dist/team/delegation-policy.d.ts.map +1 -0
  411. package/dist/team/delegation-policy.js +82 -0
  412. package/dist/team/delegation-policy.js.map +1 -0
  413. package/dist/team/model-contract.d.ts +3 -1
  414. package/dist/team/model-contract.d.ts.map +1 -1
  415. package/dist/team/model-contract.js +44 -5
  416. package/dist/team/model-contract.js.map +1 -1
  417. package/dist/team/repo-aware-decomposition.d.ts +60 -0
  418. package/dist/team/repo-aware-decomposition.d.ts.map +1 -0
  419. package/dist/team/repo-aware-decomposition.js +229 -0
  420. package/dist/team/repo-aware-decomposition.js.map +1 -0
  421. package/dist/team/runtime.d.ts +27 -0
  422. package/dist/team/runtime.d.ts.map +1 -1
  423. package/dist/team/runtime.js +172 -52
  424. package/dist/team/runtime.js.map +1 -1
  425. package/dist/team/state/tasks.d.ts.map +1 -1
  426. package/dist/team/state/tasks.js +33 -0
  427. package/dist/team/state/tasks.js.map +1 -1
  428. package/dist/team/state/types.d.ts +23 -1
  429. package/dist/team/state/types.d.ts.map +1 -1
  430. package/dist/team/state/types.js.map +1 -1
  431. package/dist/team/state-root.d.ts +35 -0
  432. package/dist/team/state-root.d.ts.map +1 -1
  433. package/dist/team/state-root.js +281 -1
  434. package/dist/team/state-root.js.map +1 -1
  435. package/dist/team/state.d.ts +27 -1
  436. package/dist/team/state.d.ts.map +1 -1
  437. package/dist/team/state.js +6 -0
  438. package/dist/team/state.js.map +1 -1
  439. package/dist/team/tmux-session.d.ts +1 -0
  440. package/dist/team/tmux-session.d.ts.map +1 -1
  441. package/dist/team/tmux-session.js +105 -6
  442. package/dist/team/tmux-session.js.map +1 -1
  443. package/dist/team/worker-bootstrap.d.ts +3 -0
  444. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  445. package/dist/team/worker-bootstrap.js +77 -4
  446. package/dist/team/worker-bootstrap.js.map +1 -1
  447. package/dist/utils/agents-md.d.ts +3 -0
  448. package/dist/utils/agents-md.d.ts.map +1 -1
  449. package/dist/utils/agents-md.js +25 -0
  450. package/dist/utils/agents-md.js.map +1 -1
  451. package/package.json +3 -2
  452. package/plugins/oh-my-codex/.codex-plugin/plugin.json +2 -2
  453. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
  454. package/plugins/oh-my-codex/skills/analyze/SKILL.md +1 -1
  455. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +134 -205
  456. package/plugins/oh-my-codex/skills/code-review/SKILL.md +4 -4
  457. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +14 -7
  458. package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
  459. package/plugins/oh-my-codex/skills/help/SKILL.md +1 -1
  460. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +41 -10
  461. package/plugins/oh-my-codex/skills/plan/SKILL.md +12 -14
  462. package/plugins/oh-my-codex/skills/ralph/SKILL.md +2 -4
  463. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -9
  464. package/plugins/oh-my-codex/skills/security-review/SKILL.md +4 -4
  465. package/plugins/oh-my-codex/skills/team/SKILL.md +2 -5
  466. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +2 -5
  467. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -3
  468. package/prompts/analyst.md +2 -2
  469. package/prompts/api-reviewer.md +2 -2
  470. package/prompts/architect.md +2 -2
  471. package/prompts/build-fixer.md +2 -2
  472. package/prompts/code-reviewer.md +15 -5
  473. package/prompts/code-simplifier.md +1 -1
  474. package/prompts/critic.md +35 -83
  475. package/prompts/debugger.md +2 -2
  476. package/prompts/dependency-expert.md +2 -2
  477. package/prompts/designer.md +2 -2
  478. package/prompts/executor.md +40 -114
  479. package/prompts/explore-harness.md +1 -1
  480. package/prompts/explore.md +37 -90
  481. package/prompts/git-master.md +2 -2
  482. package/prompts/information-architect.md +1 -1
  483. package/prompts/performance-reviewer.md +2 -2
  484. package/prompts/planner.md +35 -62
  485. package/prompts/product-analyst.md +2 -2
  486. package/prompts/product-manager.md +2 -2
  487. package/prompts/qa-tester.md +2 -2
  488. package/prompts/quality-reviewer.md +2 -2
  489. package/prompts/quality-strategist.md +2 -2
  490. package/prompts/researcher.md +46 -78
  491. package/prompts/security-reviewer.md +2 -2
  492. package/prompts/sisyphus-lite.md +2 -2
  493. package/prompts/style-reviewer.md +2 -2
  494. package/prompts/team-executor.md +1 -1
  495. package/prompts/test-engineer.md +2 -2
  496. package/prompts/ux-researcher.md +2 -2
  497. package/prompts/verifier.md +29 -34
  498. package/prompts/vision.md +2 -2
  499. package/prompts/writer.md +2 -2
  500. package/skills/ai-slop-cleaner/SKILL.md +1 -1
  501. package/skills/analyze/SKILL.md +1 -1
  502. package/skills/autopilot/SKILL.md +134 -205
  503. package/skills/build-fix/SKILL.md +4 -4
  504. package/skills/code-review/SKILL.md +4 -4
  505. package/skills/deep-interview/SKILL.md +14 -7
  506. package/skills/doctor/SKILL.md +1 -1
  507. package/skills/help/SKILL.md +1 -1
  508. package/skills/omx-setup/SKILL.md +41 -10
  509. package/skills/plan/SKILL.md +12 -14
  510. package/skills/ralph/SKILL.md +2 -4
  511. package/skills/ralplan/SKILL.md +5 -9
  512. package/skills/security-review/SKILL.md +4 -4
  513. package/skills/team/SKILL.md +2 -5
  514. package/skills/ultraqa/SKILL.md +2 -5
  515. package/skills/ultrawork/SKILL.md +2 -3
  516. package/src/scripts/__tests__/codex-native-hook.test.ts +502 -94
  517. package/src/scripts/__tests__/generate-release-body.test.ts +41 -0
  518. package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
  519. package/src/scripts/codex-native-hook.ts +293 -61
  520. package/src/scripts/codex-native-pre-post.ts +10 -8
  521. package/src/scripts/generate-release-body.ts +13 -2
  522. package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
  523. package/src/scripts/notify-hook/managed-tmux.ts +196 -9
  524. package/src/scripts/notify-hook/process-runner.ts +7 -3
  525. package/src/scripts/notify-hook/team-dispatch.ts +103 -11
  526. package/src/scripts/notify-hook/team-tmux-guard.ts +3 -3
  527. package/src/scripts/notify-hook/team-worker-posttooluse.ts +536 -0
  528. package/src/scripts/notify-hook/team-worker.ts +4 -48
  529. package/src/scripts/notify-hook/tmux-injection.ts +24 -6
  530. package/src/scripts/notify-hook.ts +36 -5
  531. package/src/scripts/prompt-inventory.ts +218 -0
  532. package/src/scripts/run-test-files.ts +1 -0
  533. package/templates/AGENTS.md +34 -95
@@ -1,57 +1,44 @@
1
1
  /**
2
2
  * omx doctor - Validate oh-my-codex installation
3
3
  */
4
- import { existsSync } from 'fs';
5
- import { readdir, readFile } from 'fs/promises';
6
- import { join } from 'path';
7
- import { codexHome, codexConfigPath, codexPromptsDir, userSkillsDir, projectSkillsDir, omxStateDir, detectLegacySkillRootOverlap, } from '../utils/paths.js';
8
- import { classifySpawnError, spawnPlatformCommandSync } from '../utils/platform-command.js';
9
- import { getCatalogExpectations } from './catalog-contract.js';
10
- import { parse as parseToml } from '@iarna/toml';
11
- import { getBuiltinExploreHarnessUnsupportedReason, resolvePackagedExploreHarnessCommand, EXPLORE_BIN_ENV, } from './explore.js';
12
- import { getPackageRoot } from '../utils/package.js';
13
- import { hasLegacyOmxTeamRunTable } from '../config/generator.js';
14
- import { getMissingManagedCodexHookEvents } from '../config/codex-hooks.js';
15
- import { OMX_FIRST_PARTY_MCP_SERVER_NAMES } from '../config/omx-first-party-mcp.js';
16
- import { getDefaultBridge, isBridgeEnabled } from '../runtime/bridge.js';
17
- import { OMX_EXPLORE_CMD_ENV, isExploreCommandRoutingEnabled } from '../hooks/explore-routing.js';
18
- import { isLeaderRuntimeStale } from '../team/leader-activity.js';
19
- import { triagePrompt } from '../hooks/triage-heuristic.js';
20
- import { readTriageConfig } from '../hooks/triage-config.js';
21
- const LEGACY_SCOPE_MIGRATION = {
22
- 'project-local': 'project',
23
- };
4
+ import { existsSync } from "fs";
5
+ import { readdir, readFile } from "fs/promises";
6
+ import { join } from "path";
7
+ import { codexHome, codexConfigPath, codexPromptsDir, userSkillsDir, projectSkillsDir, omxStateDir, detectLegacySkillRootOverlap, } from "../utils/paths.js";
8
+ import { classifySpawnError, spawnPlatformCommandSync, } from "../utils/platform-command.js";
9
+ import { getCatalogExpectations } from "./catalog-contract.js";
10
+ import { parse as parseToml } from "@iarna/toml";
11
+ import { getBuiltinExploreHarnessUnsupportedReason, resolvePackagedExploreHarnessCommand, EXPLORE_BIN_ENV, } from "./explore.js";
12
+ import { getPackageRoot } from "../utils/package.js";
13
+ import { hasLegacyOmxTeamRunTable } from "../config/generator.js";
14
+ import { getMissingManagedCodexHookEvents } from "../config/codex-hooks.js";
15
+ import { OMX_FIRST_PARTY_MCP_SERVER_NAMES } from "../config/omx-first-party-mcp.js";
16
+ import { getDefaultBridge, isBridgeEnabled } from "../runtime/bridge.js";
17
+ import { OMX_EXPLORE_CMD_ENV, isExploreCommandRoutingEnabled, } from "../hooks/explore-routing.js";
18
+ import { isLeaderRuntimeStale } from "../team/leader-activity.js";
19
+ import { triagePrompt } from "../hooks/triage-heuristic.js";
20
+ import { readTriageConfig } from "../hooks/triage-config.js";
21
+ import { readPersistedSetupPreferences, } from "./setup-preferences.js";
22
+ import { OMX_LOCAL_MARKETPLACE_NAME, resolvePackagedOmxMarketplace, } from "./plugin-marketplace.js";
24
23
  async function resolveDoctorScope(cwd) {
25
- const scopePath = join(cwd, '.omx', 'setup-scope.json');
26
- if (!existsSync(scopePath)) {
27
- return { scope: 'user', source: 'default' };
28
- }
29
- try {
30
- const raw = await readFile(scopePath, 'utf-8');
31
- const parsed = JSON.parse(raw);
32
- if (typeof parsed.scope === 'string') {
33
- if (parsed.scope === 'user' || parsed.scope === 'project') {
34
- return { scope: parsed.scope, source: 'persisted' };
35
- }
36
- const migrated = LEGACY_SCOPE_MIGRATION[parsed.scope];
37
- if (migrated) {
38
- return { scope: migrated, source: 'persisted' };
39
- }
40
- }
41
- }
42
- catch {
43
- // ignore invalid persisted scope and fall back to default
24
+ const persisted = await readPersistedSetupPreferences(cwd);
25
+ if (persisted?.scope) {
26
+ return {
27
+ scope: persisted.scope,
28
+ source: "persisted",
29
+ installMode: persisted.installMode,
30
+ };
44
31
  }
45
- return { scope: 'user', source: 'default' };
32
+ return { scope: "user", source: "default" };
46
33
  }
47
34
  function resolveDoctorPaths(cwd, scope) {
48
- if (scope === 'project') {
49
- const codexHomeDir = join(cwd, '.codex');
35
+ if (scope === "project") {
36
+ const codexHomeDir = join(cwd, ".codex");
50
37
  return {
51
38
  codexHomeDir,
52
- configPath: join(codexHomeDir, 'config.toml'),
53
- hooksPath: join(codexHomeDir, 'hooks.json'),
54
- promptsDir: join(codexHomeDir, 'prompts'),
39
+ configPath: join(codexHomeDir, "config.toml"),
40
+ hooksPath: join(codexHomeDir, "hooks.json"),
41
+ promptsDir: join(codexHomeDir, "prompts"),
55
42
  skillsDir: projectSkillsDir(cwd),
56
43
  stateDir: omxStateDir(cwd),
57
44
  };
@@ -59,7 +46,7 @@ function resolveDoctorPaths(cwd, scope) {
59
46
  return {
60
47
  codexHomeDir: codexHome(),
61
48
  configPath: codexConfigPath(),
62
- hooksPath: join(codexHome(), 'hooks.json'),
49
+ hooksPath: join(codexHome(), "hooks.json"),
63
50
  promptsDir: codexPromptsDir(),
64
51
  skillsDir: userSkillsDir(),
65
52
  stateDir: omxStateDir(cwd),
@@ -73,12 +60,16 @@ export async function doctor(options = {}) {
73
60
  const cwd = process.cwd();
74
61
  const scopeResolution = await resolveDoctorScope(cwd);
75
62
  const paths = resolveDoctorPaths(cwd, scopeResolution.scope);
76
- const scopeSourceMessage = scopeResolution.source === 'persisted'
77
- ? ' (from .omx/setup-scope.json)'
78
- : '';
79
- console.log('oh-my-codex doctor');
80
- console.log('==================\n');
81
- console.log(`Resolved setup scope: ${scopeResolution.scope}${scopeSourceMessage}\n`);
63
+ const scopeSourceMessage = scopeResolution.source === "persisted"
64
+ ? " (from .omx/setup-scope.json)"
65
+ : "";
66
+ console.log("oh-my-codex doctor");
67
+ console.log("==================\n");
68
+ console.log(`Resolved setup scope: ${scopeResolution.scope}${scopeSourceMessage}`);
69
+ if (scopeResolution.installMode) {
70
+ console.log(`Resolved setup install mode: ${scopeResolution.installMode}${scopeSourceMessage}`);
71
+ }
72
+ console.log();
82
73
  const checks = [];
83
74
  // Check 1: Codex CLI installed
84
75
  checks.push(checkCodexCli());
@@ -87,7 +78,7 @@ export async function doctor(options = {}) {
87
78
  // Check 2.5: Explore harness readiness
88
79
  checks.push(checkExploreHarness());
89
80
  // Check 3: Codex home directory
90
- checks.push(checkDirectory('Codex home', paths.codexHomeDir));
81
+ checks.push(checkDirectory("Codex home", paths.codexHomeDir));
91
82
  // Check 4: Config file
92
83
  checks.push(await checkConfig(paths.configPath));
93
84
  // Check 4.25: Native hooks coverage
@@ -95,19 +86,19 @@ export async function doctor(options = {}) {
95
86
  // Check 4.5: Explore routing default
96
87
  checks.push(await checkExploreRouting(paths.configPath));
97
88
  // Check 5: Prompts installed
98
- checks.push(await checkPrompts(paths.promptsDir));
89
+ checks.push(await checkPrompts(paths.promptsDir, scopeResolution.installMode));
99
90
  // Check 6: Skills installed
100
- checks.push(await checkSkills(paths.skillsDir));
91
+ checks.push(await checkSkills(paths, scopeResolution.installMode));
101
92
  // Check 6.5: Legacy/current skill-root overlap
102
- if (scopeResolution.scope === 'user') {
93
+ if (scopeResolution.scope === "user") {
103
94
  checks.push(await checkLegacySkillRootOverlap());
104
95
  }
105
96
  // Check 7: AGENTS.md in project
106
- checks.push(checkAgentsMd(scopeResolution.scope, paths.codexHomeDir));
97
+ checks.push(checkAgentsMd(scopeResolution.scope, paths.codexHomeDir, scopeResolution.installMode));
107
98
  // Check 8: State directory
108
- checks.push(checkDirectory('State dir', paths.stateDir));
99
+ checks.push(checkDirectory("State dir", paths.stateDir));
109
100
  // Check 9: MCP servers configured
110
- checks.push(await checkMcpServers(paths.configPath));
101
+ checks.push(await checkMcpServers(paths.configPath, scopeResolution.installMode));
111
102
  // Check 10: Prompt triage
112
103
  checks.push(checkPromptTriage());
113
104
  // Print results
@@ -115,11 +106,15 @@ export async function doctor(options = {}) {
115
106
  let warnCount = 0;
116
107
  let failCount = 0;
117
108
  for (const check of checks) {
118
- const icon = check.status === 'pass' ? '[OK]' : check.status === 'warn' ? '[!!]' : '[XX]';
109
+ const icon = check.status === "pass"
110
+ ? "[OK]"
111
+ : check.status === "warn"
112
+ ? "[!!]"
113
+ : "[XX]";
119
114
  console.log(` ${icon} ${check.name}: ${check.message}`);
120
- if (check.status === 'pass')
115
+ if (check.status === "pass")
121
116
  passCount++;
122
- else if (check.status === 'warn')
117
+ else if (check.status === "warn")
123
118
  warnCount++;
124
119
  else
125
120
  failCount++;
@@ -132,22 +127,22 @@ export async function doctor(options = {}) {
132
127
  console.log('\nRun "omx setup --force" to refresh all components.');
133
128
  }
134
129
  else {
135
- console.log('\nAll checks passed! oh-my-codex is ready.');
130
+ console.log("\nAll checks passed! oh-my-codex is ready.");
136
131
  }
137
132
  }
138
133
  async function doctorTeam() {
139
- console.log('oh-my-codex doctor --team');
140
- console.log('=========================\n');
134
+ console.log("oh-my-codex doctor --team");
135
+ console.log("=========================\n");
141
136
  const issues = await collectTeamDoctorIssues(process.cwd());
142
137
  if (issues.length === 0) {
143
- console.log(' [OK] team diagnostics: no issues');
144
- console.log('\nAll team checks passed.');
138
+ console.log(" [OK] team diagnostics: no issues");
139
+ console.log("\nAll team checks passed.");
145
140
  return;
146
141
  }
147
- const failureCount = issues.filter(issue => issue.severity === 'fail').length;
142
+ const failureCount = issues.filter((issue) => issue.severity === "fail").length;
148
143
  const warningCount = issues.length - failureCount;
149
144
  for (const issue of issues) {
150
- const icon = issue.severity === 'warn' ? '[!!]' : '[XX]';
145
+ const icon = issue.severity === "warn" ? "[!!]" : "[XX]";
151
146
  console.log(` ${icon} ${issue.code}: ${issue.message}`);
152
147
  }
153
148
  console.log(`\nResults: ${warningCount} warnings, ${failureCount} failed`);
@@ -158,7 +153,7 @@ async function doctorTeam() {
158
153
  async function collectTeamDoctorIssues(cwd) {
159
154
  const issues = [];
160
155
  const stateDir = omxStateDir(cwd);
161
- const teamsRoot = join(stateDir, 'team');
156
+ const teamsRoot = join(stateDir, "team");
162
157
  const nowMs = Date.now();
163
158
  const lagThresholdMs = 60_000;
164
159
  const shutdownThresholdMs = 30_000;
@@ -172,17 +167,17 @@ async function collectTeamDoctorIssues(cwd) {
172
167
  if (readiness && !readiness.ready) {
173
168
  for (const reason of readiness.reasons) {
174
169
  issues.push({
175
- code: 'resume_blocker',
170
+ code: "resume_blocker",
176
171
  message: `runtime not ready: ${reason}`,
177
- severity: 'fail',
172
+ severity: "fail",
178
173
  });
179
174
  }
180
175
  }
181
176
  if (authority?.stale) {
182
177
  issues.push({
183
- code: 'stale_leader',
184
- message: `authority stale (owner: ${authority.owner ?? 'unknown'}): ${authority.stale_reason ?? 'unknown reason'}`,
185
- severity: 'fail',
178
+ code: "stale_leader",
179
+ message: `authority stale (owner: ${authority.owner ?? "unknown"}): ${authority.stale_reason ?? "unknown reason"}`,
180
+ severity: "fail",
186
181
  });
187
182
  }
188
183
  }
@@ -199,16 +194,24 @@ async function collectTeamDoctorIssues(cwd) {
199
194
  const knownTeamSessions = new Set();
200
195
  for (const teamName of teamDirs) {
201
196
  const teamDir = join(teamsRoot, teamName);
202
- const manifestPath = join(teamDir, 'manifest.v2.json');
203
- const configPath = join(teamDir, 'config.json');
197
+ const manifestPath = join(teamDir, "manifest.v2.json");
198
+ const configPath = join(teamDir, "config.json");
204
199
  let tmuxSession = `omx-team-${teamName}`;
200
+ let workerLaunchMode = "interactive";
201
+ let promptWorkers = [];
205
202
  if (existsSync(manifestPath)) {
206
203
  try {
207
- const raw = await readFile(manifestPath, 'utf-8');
204
+ const raw = await readFile(manifestPath, "utf-8");
208
205
  const parsed = JSON.parse(raw);
209
- if (typeof parsed.tmux_session === 'string' && parsed.tmux_session.trim() !== '') {
206
+ if (typeof parsed.tmux_session === "string" &&
207
+ parsed.tmux_session.trim() !== "") {
210
208
  tmuxSession = parsed.tmux_session;
211
209
  }
210
+ if (parsed.policy?.worker_launch_mode === "prompt") {
211
+ workerLaunchMode = "prompt";
212
+ }
213
+ if (Array.isArray(parsed.workers))
214
+ promptWorkers = parsed.workers;
212
215
  }
213
216
  catch {
214
217
  // ignore malformed manifest
@@ -216,27 +219,45 @@ async function collectTeamDoctorIssues(cwd) {
216
219
  }
217
220
  else if (existsSync(configPath)) {
218
221
  try {
219
- const raw = await readFile(configPath, 'utf-8');
222
+ const raw = await readFile(configPath, "utf-8");
220
223
  const parsed = JSON.parse(raw);
221
- if (typeof parsed.tmux_session === 'string' && parsed.tmux_session.trim() !== '') {
224
+ if (typeof parsed.tmux_session === "string" &&
225
+ parsed.tmux_session.trim() !== "") {
222
226
  tmuxSession = parsed.tmux_session;
223
227
  }
228
+ if (parsed.worker_launch_mode === "prompt") {
229
+ workerLaunchMode = "prompt";
230
+ }
231
+ if (Array.isArray(parsed.workers))
232
+ promptWorkers = parsed.workers;
224
233
  }
225
234
  catch {
226
235
  // ignore malformed config
227
236
  }
228
237
  }
229
238
  knownTeamSessions.add(tmuxSession);
230
- // resume_blocker: only meaningful if tmux is available to query
231
- if (!tmuxUnavailable && !tmuxSessions.has(tmuxSession)) {
239
+ if (workerLaunchMode === "prompt") {
240
+ for (const worker of promptWorkers) {
241
+ const pid = worker.pid ?? 0;
242
+ if (Number.isFinite(pid) && pid > 0 && isPidAlive(pid)) {
243
+ issues.push({
244
+ code: "prompt_resume_unavailable",
245
+ message: `${teamName}/${worker.name ?? "unknown"} pid ${pid} appears to be running, but doctor cannot verify that the PID still belongs to the original prompt-mode worker after CLI restart; if this is the original worker, shut it down or start a new team`,
246
+ severity: "warn",
247
+ });
248
+ }
249
+ }
250
+ }
251
+ else if (!tmuxUnavailable && !tmuxSessions.has(tmuxSession)) {
252
+ // resume_blocker: only meaningful if tmux is available to query for interactive teams.
232
253
  issues.push({
233
- code: 'resume_blocker',
254
+ code: "resume_blocker",
234
255
  message: `${teamName} references missing tmux session ${tmuxSession}`,
235
- severity: 'fail',
256
+ severity: "fail",
236
257
  });
237
258
  }
238
259
  // delayed_status_lag + slow_shutdown checks
239
- const workersRoot = join(teamDir, 'workers');
260
+ const workersRoot = join(teamDir, "workers");
240
261
  if (!existsSync(workersRoot))
241
262
  continue;
242
263
  const workers = await readdir(workersRoot, { withFileTypes: true });
@@ -244,24 +265,28 @@ async function collectTeamDoctorIssues(cwd) {
244
265
  if (!worker.isDirectory())
245
266
  continue;
246
267
  const workerDir = join(workersRoot, worker.name);
247
- const statusPath = join(workerDir, 'status.json');
248
- const heartbeatPath = join(workerDir, 'heartbeat.json');
249
- const shutdownReqPath = join(workerDir, 'shutdown-request.json');
250
- const shutdownAckPath = join(workerDir, 'shutdown-ack.json');
268
+ const statusPath = join(workerDir, "status.json");
269
+ const heartbeatPath = join(workerDir, "heartbeat.json");
270
+ const shutdownReqPath = join(workerDir, "shutdown-request.json");
271
+ const shutdownAckPath = join(workerDir, "shutdown-ack.json");
251
272
  if (existsSync(statusPath) && existsSync(heartbeatPath)) {
252
273
  try {
253
274
  const [statusRaw, hbRaw] = await Promise.all([
254
- readFile(statusPath, 'utf-8'),
255
- readFile(heartbeatPath, 'utf-8'),
275
+ readFile(statusPath, "utf-8"),
276
+ readFile(heartbeatPath, "utf-8"),
256
277
  ]);
257
278
  const status = JSON.parse(statusRaw);
258
279
  const hb = JSON.parse(hbRaw);
259
- const lastTurnMs = hb.last_turn_at ? Date.parse(hb.last_turn_at) : NaN;
260
- if (status.state === 'working' && Number.isFinite(lastTurnMs) && nowMs - lastTurnMs > lagThresholdMs) {
280
+ const lastTurnMs = hb.last_turn_at
281
+ ? Date.parse(hb.last_turn_at)
282
+ : NaN;
283
+ if (status.state === "working" &&
284
+ Number.isFinite(lastTurnMs) &&
285
+ nowMs - lastTurnMs > lagThresholdMs) {
261
286
  issues.push({
262
- code: 'delayed_status_lag',
287
+ code: "delayed_status_lag",
263
288
  message: `${teamName}/${worker.name} working with stale heartbeat`,
264
- severity: 'fail',
289
+ severity: "fail",
265
290
  });
266
291
  }
267
292
  }
@@ -271,14 +296,14 @@ async function collectTeamDoctorIssues(cwd) {
271
296
  }
272
297
  if (existsSync(shutdownReqPath) && !existsSync(shutdownAckPath)) {
273
298
  try {
274
- const reqRaw = await readFile(shutdownReqPath, 'utf-8');
299
+ const reqRaw = await readFile(shutdownReqPath, "utf-8");
275
300
  const req = JSON.parse(reqRaw);
276
301
  const reqMs = req.requested_at ? Date.parse(req.requested_at) : NaN;
277
302
  if (Number.isFinite(reqMs) && nowMs - reqMs > shutdownThresholdMs) {
278
303
  issues.push({
279
- code: 'slow_shutdown',
304
+ code: "slow_shutdown",
280
305
  message: `${teamName}/${worker.name} has stale shutdown request without ack`,
281
- severity: 'fail',
306
+ severity: "fail",
282
307
  });
283
308
  }
284
309
  }
@@ -289,9 +314,10 @@ async function collectTeamDoctorIssues(cwd) {
289
314
  }
290
315
  }
291
316
  // stale_leader: team has active workers but leader has no recent activity
292
- const hudStatePath = join(stateDir, 'hud-state.json');
293
- const leaderActivityPath = join(stateDir, 'leader-runtime-activity.json');
294
- if ((existsSync(hudStatePath) || existsSync(leaderActivityPath)) && teamDirs.length > 0) {
317
+ const hudStatePath = join(stateDir, "hud-state.json");
318
+ const leaderActivityPath = join(stateDir, "leader-runtime-activity.json");
319
+ if ((existsSync(hudStatePath) || existsSync(leaderActivityPath)) &&
320
+ teamDirs.length > 0) {
295
321
  try {
296
322
  const leaderIsStale = await isLeaderRuntimeStale(stateDir, leaderStaleThresholdMs, nowMs);
297
323
  if (leaderIsStale && !tmuxUnavailable) {
@@ -299,13 +325,13 @@ async function collectTeamDoctorIssues(cwd) {
299
325
  for (const teamName of teamDirs) {
300
326
  const session = knownTeamSessions.has(`omx-team-${teamName}`)
301
327
  ? `omx-team-${teamName}`
302
- : [...knownTeamSessions].find(s => s.includes(teamName));
328
+ : [...knownTeamSessions].find((s) => s.includes(teamName));
303
329
  if (!session || !tmuxSessions.has(session))
304
330
  continue;
305
331
  issues.push({
306
- code: 'stale_leader',
332
+ code: "stale_leader",
307
333
  message: `${teamName} has active tmux session but leader has no recent activity`,
308
- severity: 'fail',
334
+ severity: "fail",
309
335
  });
310
336
  }
311
337
  }
@@ -319,15 +345,28 @@ async function collectTeamDoctorIssues(cwd) {
319
345
  for (const session of tmuxSessions) {
320
346
  if (!knownTeamSessions.has(session)) {
321
347
  issues.push({
322
- code: 'orphan_tmux_session',
348
+ code: "orphan_tmux_session",
323
349
  message: `${session} exists without matching team state (possibly external project)`,
324
- severity: 'warn',
350
+ severity: "warn",
325
351
  });
326
352
  }
327
353
  }
328
354
  }
329
355
  return dedupeIssues(issues);
330
356
  }
357
+ function isPidAlive(pid) {
358
+ if (!Number.isFinite(pid) || pid <= 0)
359
+ return false;
360
+ try {
361
+ process.kill(pid, 0);
362
+ return true;
363
+ }
364
+ catch (err) {
365
+ if (err.code === 'ESRCH')
366
+ return false;
367
+ return false;
368
+ }
369
+ }
331
370
  function dedupeIssues(issues) {
332
371
  const seen = new Set();
333
372
  const out = [];
@@ -341,78 +380,101 @@ function dedupeIssues(issues) {
341
380
  return out;
342
381
  }
343
382
  function listTeamTmuxSessions() {
344
- const { result: res } = spawnPlatformCommandSync('tmux', ['list-sessions', '-F', '#{session_name}'], { encoding: 'utf-8' });
383
+ const { result: res } = spawnPlatformCommandSync("tmux", ["list-sessions", "-F", "#{session_name}"], { encoding: "utf-8" });
345
384
  if (res.error) {
346
385
  // tmux binary unavailable or not executable.
347
386
  return null;
348
387
  }
349
388
  if (res.status !== 0) {
350
- const stderr = (res.stderr || '').toLowerCase();
389
+ const stderr = (res.stderr || "").toLowerCase();
351
390
  // tmux installed but no server/session is running.
352
- if (stderr.includes('no server running') || stderr.includes('failed to connect to server')) {
391
+ if (stderr.includes("no server running") ||
392
+ stderr.includes("failed to connect to server")) {
353
393
  return new Set();
354
394
  }
355
395
  return null;
356
396
  }
357
- const sessions = (res.stdout || '')
358
- .split('\n')
397
+ const sessions = (res.stdout || "")
398
+ .split("\n")
359
399
  .map((s) => s.trim())
360
- .filter((s) => s.startsWith('omx-team-'));
400
+ .filter((s) => s.startsWith("omx-team-"));
361
401
  return new Set(sessions);
362
402
  }
363
403
  function checkCodexCli() {
364
- const { result } = spawnPlatformCommandSync('codex', ['--version'], {
365
- encoding: 'utf-8',
366
- stdio: ['pipe', 'pipe', 'pipe'],
404
+ const { result } = spawnPlatformCommandSync("codex", ["--version"], {
405
+ encoding: "utf-8",
406
+ stdio: ["pipe", "pipe", "pipe"],
367
407
  });
368
408
  if (result.error) {
369
409
  const code = result.error.code;
370
410
  const kind = classifySpawnError(result.error);
371
- if (kind === 'missing') {
372
- return { name: 'Codex CLI', status: 'fail', message: 'not found - install from https://github.com/openai/codex' };
411
+ if (kind === "missing") {
412
+ return {
413
+ name: "Codex CLI",
414
+ status: "fail",
415
+ message: "not found - install from https://github.com/openai/codex",
416
+ };
373
417
  }
374
- if (kind === 'blocked') {
418
+ if (kind === "blocked") {
375
419
  return {
376
- name: 'Codex CLI',
377
- status: 'fail',
378
- message: `found but could not be executed in this environment (${code || 'blocked'})`,
420
+ name: "Codex CLI",
421
+ status: "fail",
422
+ message: `found but could not be executed in this environment (${code || "blocked"})`,
379
423
  };
380
424
  }
381
425
  return {
382
- name: 'Codex CLI',
383
- status: 'fail',
426
+ name: "Codex CLI",
427
+ status: "fail",
384
428
  message: `probe failed - ${result.error.message}`,
385
429
  };
386
430
  }
387
431
  if (result.status === 0) {
388
- const version = (result.stdout || '').trim();
389
- return { name: 'Codex CLI', status: 'pass', message: `installed (${version})` };
432
+ const version = (result.stdout || "").trim();
433
+ return {
434
+ name: "Codex CLI",
435
+ status: "pass",
436
+ message: `installed (${version})`,
437
+ };
390
438
  }
391
- const stderr = (result.stderr || '').trim();
439
+ const stderr = (result.stderr || "").trim();
392
440
  return {
393
- name: 'Codex CLI',
394
- status: 'fail',
395
- message: stderr !== '' ? `probe failed - ${stderr}` : `probe failed with exit ${result.status}`,
441
+ name: "Codex CLI",
442
+ status: "fail",
443
+ message: stderr !== ""
444
+ ? `probe failed - ${stderr}`
445
+ : `probe failed with exit ${result.status}`,
396
446
  };
397
447
  }
398
448
  function checkNodeVersion() {
399
- const major = parseInt(process.versions.node.split('.')[0] ?? '0', 10);
449
+ const major = parseInt(process.versions.node.split(".")[0] ?? "0", 10);
400
450
  if (isNaN(major)) {
401
- return { name: 'Node.js', status: 'fail', message: `v${process.versions.node} (unable to parse major version)` };
451
+ return {
452
+ name: "Node.js",
453
+ status: "fail",
454
+ message: `v${process.versions.node} (unable to parse major version)`,
455
+ };
402
456
  }
403
457
  if (major >= 20) {
404
- return { name: 'Node.js', status: 'pass', message: `v${process.versions.node}` };
458
+ return {
459
+ name: "Node.js",
460
+ status: "pass",
461
+ message: `v${process.versions.node}`,
462
+ };
405
463
  }
406
- return { name: 'Node.js', status: 'fail', message: `v${process.versions.node} (need >= 20)` };
464
+ return {
465
+ name: "Node.js",
466
+ status: "fail",
467
+ message: `v${process.versions.node} (need >= 20)`,
468
+ };
407
469
  }
408
470
  export function checkExploreHarness(platform = process.platform, env = process.env) {
409
471
  const packageRoot = getPackageRoot();
410
- const manifestPath = join(packageRoot, 'crates', 'omx-explore', 'Cargo.toml');
472
+ const manifestPath = join(packageRoot, "crates", "omx-explore", "Cargo.toml");
411
473
  if (!existsSync(manifestPath)) {
412
474
  return {
413
- name: 'Explore Harness',
414
- status: 'warn',
415
- message: 'Rust harness sources not found in this install (omx explore unavailable until packaged or OMX_EXPLORE_BIN is set)',
475
+ name: "Explore Harness",
476
+ status: "warn",
477
+ message: "Rust harness sources not found in this install (omx explore unavailable until packaged or OMX_EXPLORE_BIN is set)",
416
478
  };
417
479
  }
418
480
  const override = env[EXPLORE_BIN_ENV]?.trim();
@@ -420,71 +482,71 @@ export function checkExploreHarness(platform = process.platform, env = process.e
420
482
  const resolved = join(packageRoot, override);
421
483
  if (existsSync(override) || existsSync(resolved)) {
422
484
  return {
423
- name: 'Explore Harness',
424
- status: 'pass',
485
+ name: "Explore Harness",
486
+ status: "pass",
425
487
  message: `${EXPLORE_BIN_ENV} configured (${override})`,
426
488
  };
427
489
  }
428
490
  return {
429
- name: 'Explore Harness',
430
- status: 'warn',
491
+ name: "Explore Harness",
492
+ status: "warn",
431
493
  message: `OMX_EXPLORE_BIN is set but path was not found (${override})`,
432
494
  };
433
495
  }
434
496
  const unsupportedReason = getBuiltinExploreHarnessUnsupportedReason(platform, env);
435
497
  if (unsupportedReason) {
436
498
  return {
437
- name: 'Explore Harness',
438
- status: 'warn',
499
+ name: "Explore Harness",
500
+ status: "warn",
439
501
  message: unsupportedReason,
440
502
  };
441
503
  }
442
504
  const packaged = resolvePackagedExploreHarnessCommand(packageRoot);
443
505
  if (packaged) {
444
506
  return {
445
- name: 'Explore Harness',
446
- status: 'pass',
507
+ name: "Explore Harness",
508
+ status: "pass",
447
509
  message: `ready (packaged native binary: ${packaged.command})`,
448
510
  };
449
511
  }
450
- const { result } = spawnPlatformCommandSync('cargo', ['--version'], {
451
- encoding: 'utf-8',
452
- stdio: ['pipe', 'pipe', 'pipe'],
512
+ const { result } = spawnPlatformCommandSync("cargo", ["--version"], {
513
+ encoding: "utf-8",
514
+ stdio: ["pipe", "pipe", "pipe"],
453
515
  });
454
516
  if (result.error) {
455
517
  const kind = classifySpawnError(result.error);
456
- if (kind === 'missing') {
518
+ if (kind === "missing") {
457
519
  return {
458
- name: 'Explore Harness',
459
- status: 'warn',
520
+ name: "Explore Harness",
521
+ status: "warn",
460
522
  message: `Rust harness sources are packaged, but no compatible packaged prebuilt or cargo was found (install Rust or set ${EXPLORE_BIN_ENV} for omx explore)`,
461
523
  };
462
524
  }
463
525
  return {
464
- name: 'Explore Harness',
465
- status: 'warn',
526
+ name: "Explore Harness",
527
+ status: "warn",
466
528
  message: `Rust harness sources are packaged, but cargo probe failed (${result.error.message})`,
467
529
  };
468
530
  }
469
531
  if (result.status === 0) {
470
- const version = (result.stdout || '').trim();
532
+ const version = (result.stdout || "").trim();
471
533
  return {
472
- name: 'Explore Harness',
473
- status: 'pass',
474
- message: `ready (${version || 'cargo available'})`,
534
+ name: "Explore Harness",
535
+ status: "pass",
536
+ message: `ready (${version || "cargo available"})`,
475
537
  };
476
538
  }
477
539
  return {
478
- name: 'Explore Harness',
479
- status: 'warn',
540
+ name: "Explore Harness",
541
+ status: "warn",
480
542
  message: `Rust harness sources are packaged, but cargo probe failed with exit ${result.status} (install Rust or set ${EXPLORE_BIN_ENV})`,
481
543
  };
482
544
  }
483
545
  function checkDirectory(name, path) {
484
546
  if (existsSync(path)) {
485
- return { name, status: 'pass', message: path };
547
+ return { name, status: "pass", message: path };
486
548
  }
487
- return { name, status: 'warn', message: `${path} (not created yet)` };
549
+ return { name, status: "warn", message: `${path} (not created yet)` };
488
550
  }
489
551
  function validateToml(content) {
490
552
  try {
@@ -495,90 +557,99 @@ function validateToml(content) {
495
557
  if (error instanceof Error) {
496
558
  return error.message;
497
559
  }
498
- return 'unknown TOML parse error';
560
+ return "unknown TOML parse error";
499
561
  }
500
562
  }
501
563
  async function checkConfig(configPath) {
502
564
  if (!existsSync(configPath)) {
503
- return { name: 'Config', status: 'warn', message: 'config.toml not found' };
565
+ return { name: "Config", status: "warn", message: "config.toml not found" };
504
566
  }
505
567
  try {
506
- const content = await readFile(configPath, 'utf-8');
568
+ const content = await readFile(configPath, "utf-8");
507
569
  const tomlError = validateToml(content);
508
570
  if (tomlError) {
509
571
  const hint = tomlError.includes("Can't redefine existing key") ||
510
- tomlError.includes('duplicate') ||
511
- tomlError.includes('[tui]')
512
- ? 'possible duplicate TOML table such as [tui]'
513
- : 'invalid TOML syntax';
572
+ tomlError.includes("duplicate") ||
573
+ tomlError.includes("[tui]")
574
+ ? "possible duplicate TOML table such as [tui]"
575
+ : "invalid TOML syntax";
514
576
  return {
515
- name: 'Config',
516
- status: 'fail',
577
+ name: "Config",
578
+ status: "fail",
517
579
  message: `invalid config.toml (${hint})`,
518
580
  };
519
581
  }
520
582
  if (hasLegacyOmxTeamRunTable(content)) {
521
583
  return {
522
- name: 'Config',
523
- status: 'warn',
584
+ name: "Config",
585
+ status: "warn",
524
586
  message: 'retired [mcp_servers.omx_team_run] table still present; run "omx setup --force" to repair the config',
525
587
  };
526
588
  }
527
- const hasOmx = content.includes('omx_') || content.includes('oh-my-codex');
589
+ const hasOmx = content.includes("omx_") || content.includes("oh-my-codex");
528
590
  if (hasOmx) {
529
- return { name: 'Config', status: 'pass', message: 'config.toml has OMX entries' };
591
+ return {
592
+ name: "Config",
593
+ status: "pass",
594
+ message: "config.toml has OMX entries",
595
+ };
530
596
  }
531
597
  return {
532
- name: 'Config',
533
- status: 'warn',
598
+ name: "Config",
599
+ status: "warn",
534
600
  message: 'config.toml exists but no OMX entries yet (expected before first setup; run "omx setup --force" once)',
535
601
  };
536
602
  }
537
603
  catch {
538
- return { name: 'Config', status: 'fail', message: 'cannot read config.toml' };
604
+ return {
605
+ name: "Config",
606
+ status: "fail",
607
+ message: "cannot read config.toml",
608
+ };
539
609
  }
540
610
  }
541
611
  async function checkExploreRouting(configPath) {
542
612
  const envValue = process.env[OMX_EXPLORE_CMD_ENV];
543
- if (typeof envValue === 'string' && !isExploreCommandRoutingEnabled(process.env)) {
613
+ if (typeof envValue === "string" &&
614
+ !isExploreCommandRoutingEnabled(process.env)) {
544
615
  return {
545
- name: 'Explore routing',
546
- status: 'warn',
547
- message: 'disabled by environment override; enable with USE_OMX_EXPLORE_CMD=1 (or remove the explicit opt-out)',
616
+ name: "Explore routing",
617
+ status: "warn",
618
+ message: "disabled by environment override; enable with USE_OMX_EXPLORE_CMD=1 (or remove the explicit opt-out)",
548
619
  };
549
620
  }
550
621
  if (!existsSync(configPath)) {
551
622
  return {
552
- name: 'Explore routing',
553
- status: 'pass',
554
- message: 'enabled by default (config.toml not found yet)',
623
+ name: "Explore routing",
624
+ status: "pass",
625
+ message: "enabled by default (config.toml not found yet)",
555
626
  };
556
627
  }
557
628
  try {
558
- const content = await readFile(configPath, 'utf-8');
629
+ const content = await readFile(configPath, "utf-8");
559
630
  const parsed = parseToml(content);
560
631
  const configuredValue = parsed?.env?.USE_OMX_EXPLORE_CMD;
561
- if (typeof configuredValue === 'string' &&
632
+ if (typeof configuredValue === "string" &&
562
633
  !isExploreCommandRoutingEnabled({
563
634
  USE_OMX_EXPLORE_CMD: configuredValue,
564
635
  })) {
565
636
  return {
566
- name: 'Explore routing',
567
- status: 'warn',
637
+ name: "Explore routing",
638
+ status: "warn",
568
639
  message: 'disabled in config.toml [env]; set USE_OMX_EXPLORE_CMD = "1" to restore default explore-first routing',
569
640
  };
570
641
  }
571
642
  return {
572
- name: 'Explore routing',
573
- status: 'pass',
574
- message: 'enabled by default',
643
+ name: "Explore routing",
644
+ status: "pass",
645
+ message: "enabled by default",
575
646
  };
576
647
  }
577
648
  catch {
578
649
  return {
579
- name: 'Explore routing',
580
- status: 'fail',
581
- message: 'cannot read config.toml for explore routing check',
650
+ name: "Explore routing",
651
+ status: "fail",
652
+ message: "cannot read config.toml for explore routing check",
582
653
  };
583
654
  }
584
655
  }
@@ -586,12 +657,13 @@ async function checkNativeHooks(hooksPath, configPath) {
586
657
  if (!existsSync(hooksPath)) {
587
658
  if (existsSync(configPath)) {
588
659
  try {
589
- const configContent = await readFile(configPath, 'utf-8');
590
- const hasOmx = configContent.includes('omx_') || configContent.includes('oh-my-codex');
660
+ const configContent = await readFile(configPath, "utf-8");
661
+ const hasOmx = configContent.includes("omx_") ||
662
+ configContent.includes("oh-my-codex");
591
663
  if (hasOmx) {
592
664
  return {
593
- name: 'Native hooks',
594
- status: 'warn',
665
+ name: "Native hooks",
666
+ status: "warn",
595
667
  message: 'hooks.json not found even though config.toml has OMX entries; run "omx setup --force" to restore native hook coverage',
596
668
  };
597
669
  }
@@ -602,198 +674,356 @@ async function checkNativeHooks(hooksPath, configPath) {
602
674
  }
603
675
  }
604
676
  return {
605
- name: 'Native hooks',
606
- status: 'pass',
607
- message: 'hooks.json not found yet (expected before first setup)',
677
+ name: "Native hooks",
678
+ status: "pass",
679
+ message: "hooks.json not found yet (expected before first setup)",
608
680
  };
609
681
  }
610
682
  try {
611
- const content = await readFile(hooksPath, 'utf-8');
683
+ const content = await readFile(hooksPath, "utf-8");
612
684
  const missingEvents = getMissingManagedCodexHookEvents(content);
613
685
  if (missingEvents === null) {
614
686
  return {
615
- name: 'Native hooks',
616
- status: 'fail',
687
+ name: "Native hooks",
688
+ status: "fail",
617
689
  message: 'invalid hooks.json; Codex may skip OMX hook coverage until "omx setup --force" repairs it',
618
690
  };
619
691
  }
620
692
  if (missingEvents.length > 0) {
621
693
  return {
622
- name: 'Native hooks',
623
- status: 'warn',
624
- message: `hooks.json is missing OMX-managed coverage for ${missingEvents.join(', ')}; run "omx setup --force" to restore native hooks`,
694
+ name: "Native hooks",
695
+ status: "warn",
696
+ message: `hooks.json is missing OMX-managed coverage for ${missingEvents.join(", ")}; run "omx setup --force" to restore native hooks`,
625
697
  };
626
698
  }
627
699
  return {
628
- name: 'Native hooks',
629
- status: 'pass',
630
- message: 'hooks.json includes OMX-managed coverage for all native hook events',
700
+ name: "Native hooks",
701
+ status: "pass",
702
+ message: "hooks.json includes OMX-managed coverage for all native hook events",
631
703
  };
632
704
  }
633
705
  catch {
634
706
  return {
635
- name: 'Native hooks',
636
- status: 'fail',
637
- message: 'cannot read hooks.json',
707
+ name: "Native hooks",
708
+ status: "fail",
709
+ message: "cannot read hooks.json",
638
710
  };
639
711
  }
640
712
  }
641
- async function checkPrompts(dir) {
713
+ async function checkPrompts(dir, installMode) {
714
+ if (installMode === "plugin") {
715
+ return {
716
+ name: "Prompts",
717
+ status: "pass",
718
+ message: "plugin mode intentionally omits setup-owned prompts; Codex plugin discovery supplies workflow surfaces",
719
+ };
720
+ }
642
721
  const expectations = getCatalogExpectations();
643
722
  if (!existsSync(dir)) {
644
- return { name: 'Prompts', status: 'warn', message: 'prompts directory not found' };
723
+ return {
724
+ name: "Prompts",
725
+ status: "warn",
726
+ message: "prompts directory not found",
727
+ };
645
728
  }
646
729
  try {
647
730
  const files = await readdir(dir);
648
- const mdFiles = files.filter(f => f.endsWith('.md'));
731
+ const mdFiles = files.filter((f) => f.endsWith(".md"));
649
732
  if (mdFiles.length >= expectations.promptMin) {
650
- return { name: 'Prompts', status: 'pass', message: `${mdFiles.length} agent prompts installed` };
733
+ return {
734
+ name: "Prompts",
735
+ status: "pass",
736
+ message: `${mdFiles.length} agent prompts installed`,
737
+ };
651
738
  }
652
- return { name: 'Prompts', status: 'warn', message: `${mdFiles.length} prompts (expected >= ${expectations.promptMin})` };
739
+ return {
740
+ name: "Prompts",
741
+ status: "warn",
742
+ message: `${mdFiles.length} prompts (expected >= ${expectations.promptMin})`,
743
+ };
653
744
  }
654
745
  catch {
655
- return { name: 'Prompts', status: 'fail', message: 'cannot read prompts directory' };
746
+ return {
747
+ name: "Prompts",
748
+ status: "fail",
749
+ message: "cannot read prompts directory",
750
+ };
656
751
  }
657
752
  }
658
753
  async function checkLegacySkillRootOverlap() {
659
754
  const overlap = await detectLegacySkillRootOverlap();
660
755
  if (!overlap.legacyExists) {
661
756
  return {
662
- name: 'Legacy skill roots',
663
- status: 'pass',
664
- message: 'no ~/.agents/skills overlap detected',
757
+ name: "Legacy skill roots",
758
+ status: "pass",
759
+ message: "no ~/.agents/skills overlap detected",
665
760
  };
666
761
  }
667
762
  if (overlap.sameResolvedTarget) {
668
763
  return {
669
- name: 'Legacy skill roots',
670
- status: 'pass',
764
+ name: "Legacy skill roots",
765
+ status: "pass",
671
766
  message: `~/.agents/skills links to canonical ${overlap.canonicalDir}; treating both paths as one shared skill root`,
672
767
  };
673
768
  }
674
769
  if (overlap.overlappingSkillNames.length === 0) {
675
770
  return {
676
- name: 'Legacy skill roots',
677
- status: 'warn',
771
+ name: "Legacy skill roots",
772
+ status: "warn",
678
773
  message: `legacy ~/.agents/skills still exists (${overlap.legacySkillCount} skills) alongside canonical ${overlap.canonicalDir}; remove or archive it if Codex shows duplicate entries`,
679
774
  };
680
775
  }
681
776
  const mismatchMessage = overlap.mismatchedSkillNames.length > 0
682
777
  ? `; ${overlap.mismatchedSkillNames.length} differ in SKILL.md content`
683
- : '';
778
+ : "";
684
779
  return {
685
- name: 'Legacy skill roots',
686
- status: 'warn',
780
+ name: "Legacy skill roots",
781
+ status: "warn",
687
782
  message: `${overlap.overlappingSkillNames.length} overlapping skill names between ${overlap.canonicalDir} and ${overlap.legacyDir}${mismatchMessage}; Codex Enable/Disable Skills may show duplicates until ~/.agents/skills is cleaned up`,
688
783
  };
689
784
  }
690
- async function checkSkills(dir) {
785
+ function getParsedMarketplaceRegistration(content) {
786
+ const parsed = parseToml(content);
787
+ return parsed.marketplaces?.[OMX_LOCAL_MARKETPLACE_NAME] ?? null;
788
+ }
789
+ async function checkPluginMarketplaceRegistration(configPath) {
790
+ const packagedMarketplace = await resolvePackagedOmxMarketplace(getPackageRoot());
791
+ if (!packagedMarketplace) {
792
+ return {
793
+ name: "Skills",
794
+ status: "warn",
795
+ message: `plugin mode selected, but packaged ${OMX_LOCAL_MARKETPLACE_NAME} metadata was not found; reinstall oh-my-codex or run from a package that includes plugins/`,
796
+ };
797
+ }
798
+ if (!existsSync(configPath)) {
799
+ return {
800
+ name: "Skills",
801
+ status: "warn",
802
+ message: `plugin mode selected, but ${OMX_LOCAL_MARKETPLACE_NAME} is not registered because config.toml is missing; run "omx setup --plugin --force"`,
803
+ };
804
+ }
805
+ try {
806
+ const content = await readFile(configPath, "utf-8");
807
+ const registration = getParsedMarketplaceRegistration(content);
808
+ if (!registration) {
809
+ return {
810
+ name: "Skills",
811
+ status: "warn",
812
+ message: `plugin mode selected, but Codex marketplace ${OMX_LOCAL_MARKETPLACE_NAME} is not registered; run "omx setup --plugin --force"`,
813
+ };
814
+ }
815
+ if (registration.source_type !== "local") {
816
+ return {
817
+ name: "Skills",
818
+ status: "warn",
819
+ message: `Codex marketplace ${OMX_LOCAL_MARKETPLACE_NAME} has source_type=${String(registration.source_type)} (expected local); run "omx setup --plugin --force"`,
820
+ };
821
+ }
822
+ if (registration.source !== getPackageRoot()) {
823
+ return {
824
+ name: "Skills",
825
+ status: "warn",
826
+ message: `Codex marketplace ${OMX_LOCAL_MARKETPLACE_NAME} points to ${String(registration.source)} (expected ${getPackageRoot()}); run "omx setup --plugin --force"`,
827
+ };
828
+ }
829
+ return {
830
+ name: "Skills",
831
+ status: "pass",
832
+ message: `plugin marketplace ${OMX_LOCAL_MARKETPLACE_NAME} registered; OMX skills are supplied by ${packagedMarketplace.pluginRoot}`,
833
+ };
834
+ }
835
+ catch {
836
+ return {
837
+ name: "Skills",
838
+ status: "fail",
839
+ message: "cannot read or parse config.toml for plugin marketplace registration",
840
+ };
841
+ }
842
+ }
843
+ async function checkSkills(paths, installMode) {
844
+ if (installMode === "plugin") {
845
+ return checkPluginMarketplaceRegistration(paths.configPath);
846
+ }
691
847
  const expectations = getCatalogExpectations();
692
- if (!existsSync(dir)) {
693
- return { name: 'Skills', status: 'warn', message: 'skills directory not found' };
848
+ if (!existsSync(paths.skillsDir)) {
849
+ return {
850
+ name: "Skills",
851
+ status: "warn",
852
+ message: "skills directory not found",
853
+ };
694
854
  }
695
855
  try {
696
- const entries = await readdir(dir, { withFileTypes: true });
697
- const skillDirs = entries.filter(e => e.isDirectory());
856
+ const entries = await readdir(paths.skillsDir, { withFileTypes: true });
857
+ const skillDirs = entries.filter((e) => e.isDirectory());
698
858
  if (skillDirs.length >= expectations.skillMin) {
699
- return { name: 'Skills', status: 'pass', message: `${skillDirs.length} skills installed` };
859
+ return {
860
+ name: "Skills",
861
+ status: "pass",
862
+ message: `${skillDirs.length} skills installed`,
863
+ };
700
864
  }
701
- return { name: 'Skills', status: 'warn', message: `${skillDirs.length} skills (expected >= ${expectations.skillMin})` };
865
+ return {
866
+ name: "Skills",
867
+ status: "warn",
868
+ message: `${skillDirs.length} skills (expected >= ${expectations.skillMin})`,
869
+ };
702
870
  }
703
871
  catch {
704
- return { name: 'Skills', status: 'fail', message: 'cannot read skills directory' };
872
+ return {
873
+ name: "Skills",
874
+ status: "fail",
875
+ message: "cannot read skills directory",
876
+ };
705
877
  }
706
878
  }
707
- function checkAgentsMd(scope, codexHomeDir) {
708
- if (scope === 'user') {
709
- const userAgentsMd = join(codexHomeDir, 'AGENTS.md');
879
+ function checkAgentsMd(scope, codexHomeDir, installMode) {
880
+ if (scope === "user") {
881
+ const userAgentsMd = join(codexHomeDir, "AGENTS.md");
710
882
  if (existsSync(userAgentsMd)) {
711
- return { name: 'AGENTS.md', status: 'pass', message: `found in ${userAgentsMd}` };
883
+ return {
884
+ name: "AGENTS.md",
885
+ status: "pass",
886
+ message: `found in ${userAgentsMd}`,
887
+ };
888
+ }
889
+ if (installMode === "plugin") {
890
+ return {
891
+ name: "AGENTS.md",
892
+ status: "pass",
893
+ message: `optional plugin-mode AGENTS.md defaults not installed in ${userAgentsMd}`,
894
+ };
712
895
  }
713
896
  return {
714
- name: 'AGENTS.md',
715
- status: 'warn',
897
+ name: "AGENTS.md",
898
+ status: "warn",
716
899
  message: `not found in ${userAgentsMd} (run omx setup --scope user)`,
717
900
  };
718
901
  }
719
- const projectAgentsMd = join(process.cwd(), 'AGENTS.md');
902
+ const projectAgentsMd = join(process.cwd(), "AGENTS.md");
720
903
  if (existsSync(projectAgentsMd)) {
721
- return { name: 'AGENTS.md', status: 'pass', message: 'found in project root' };
904
+ return {
905
+ name: "AGENTS.md",
906
+ status: "pass",
907
+ message: "found in project root",
908
+ };
909
+ }
910
+ if (installMode === "plugin") {
911
+ return {
912
+ name: "AGENTS.md",
913
+ status: "pass",
914
+ message: "optional plugin-mode AGENTS.md defaults not installed in project root",
915
+ };
722
916
  }
723
917
  return {
724
- name: 'AGENTS.md',
725
- status: 'warn',
726
- message: 'not found in project root (run omx agents-init . or omx setup --scope project)',
918
+ name: "AGENTS.md",
919
+ status: "warn",
920
+ message: "not found in project root (run omx agents-init . or omx setup --scope project)",
727
921
  };
728
922
  }
729
923
  function checkPromptTriage() {
730
924
  try {
731
925
  const config = readTriageConfig();
732
- if (config.status === 'disabled') {
926
+ if (config.status === "disabled") {
733
927
  return {
734
- name: 'Prompt triage',
735
- status: 'warn',
928
+ name: "Prompt triage",
929
+ status: "warn",
736
930
  message: `disabled via ${config.path}`,
737
931
  };
738
932
  }
739
- if (config.status === 'invalid') {
933
+ if (config.status === "invalid") {
740
934
  return {
741
- name: 'Prompt triage',
742
- status: 'warn',
935
+ name: "Prompt triage",
936
+ status: "warn",
743
937
  message: `config file malformed at ${config.path} — fails closed to disabled`,
744
938
  };
745
939
  }
746
940
  // Smoke test: verify the classifier is callable and returns the expected shape.
747
- const decision = triagePrompt('hello');
748
- const validLanes = new Set(['HEAVY', 'LIGHT', 'PASS']);
749
- if (!decision || typeof decision !== 'object' || !validLanes.has(decision.lane)) {
941
+ const decision = triagePrompt("hello");
942
+ const validLanes = new Set(["HEAVY", "LIGHT", "PASS"]);
943
+ if (!decision ||
944
+ typeof decision !== "object" ||
945
+ !validLanes.has(decision.lane)) {
750
946
  return {
751
- name: 'Prompt triage',
752
- status: 'fail',
947
+ name: "Prompt triage",
948
+ status: "fail",
753
949
  message: `classifier returned unexpected shape (lane: ${String(decision?.lane)})`,
754
950
  };
755
951
  }
756
- const sourceLabel = config.status === 'defaulted' ? 'enabled (default)' : 'enabled';
952
+ const sourceLabel = config.status === "defaulted" ? "enabled (default)" : "enabled";
757
953
  return {
758
- name: 'Prompt triage',
759
- status: 'pass',
954
+ name: "Prompt triage",
955
+ status: "pass",
760
956
  message: `config: ${sourceLabel}`,
761
957
  };
762
958
  }
763
959
  catch (err) {
764
960
  const msg = err instanceof Error ? err.message : String(err);
765
- return { name: 'Prompt triage', status: 'fail', message: `module load error — ${msg}` };
961
+ return {
962
+ name: "Prompt triage",
963
+ status: "fail",
964
+ message: `module load error — ${msg}`,
965
+ };
766
966
  }
767
967
  }
768
- async function checkMcpServers(configPath) {
968
+ async function checkMcpServers(configPath, installMode) {
769
969
  if (!existsSync(configPath)) {
770
- return { name: 'MCP Servers', status: 'warn', message: 'config.toml not found' };
970
+ if (installMode === "plugin") {
971
+ return {
972
+ name: "MCP Servers",
973
+ status: "warn",
974
+ message: 'plugin mode selected, but config.toml is missing; run "omx setup --plugin --force" to register plugin discovery',
975
+ };
976
+ }
977
+ return {
978
+ name: "MCP Servers",
979
+ status: "warn",
980
+ message: "config.toml not found",
981
+ };
771
982
  }
772
983
  try {
773
- const content = await readFile(configPath, 'utf-8');
984
+ const content = await readFile(configPath, "utf-8");
774
985
  const mcpCount = (content.match(/\[mcp_servers\./g) || []).length;
986
+ if (hasLegacyOmxTeamRunTable(content)) {
987
+ return {
988
+ name: "MCP Servers",
989
+ status: "warn",
990
+ message: `${mcpCount} servers configured, but retired [mcp_servers.omx_team_run] is not supported; run "omx setup --force" to repair the config`,
991
+ };
992
+ }
993
+ if (installMode === "plugin") {
994
+ return {
995
+ name: "MCP Servers",
996
+ status: "pass",
997
+ message: "plugin mode uses plugin-scoped MCP metadata; setup-owned OMX MCP tables are intentionally omitted",
998
+ };
999
+ }
775
1000
  if (mcpCount > 0) {
776
- if (hasLegacyOmxTeamRunTable(content)) {
777
- return {
778
- name: 'MCP Servers',
779
- status: 'warn',
780
- message: `${mcpCount} servers configured, but retired [mcp_servers.omx_team_run] is not supported; run "omx setup --force" to repair the config`,
781
- };
782
- }
783
1001
  const hasOmx = OMX_FIRST_PARTY_MCP_SERVER_NAMES.some((name) => content.includes(name));
784
1002
  if (hasOmx) {
785
- return { name: 'MCP Servers', status: 'pass', message: `${mcpCount} servers configured (OMX present)` };
1003
+ return {
1004
+ name: "MCP Servers",
1005
+ status: "pass",
1006
+ message: `${mcpCount} servers configured (OMX present)`,
1007
+ };
786
1008
  }
787
1009
  return {
788
- name: 'MCP Servers',
789
- status: 'warn',
1010
+ name: "MCP Servers",
1011
+ status: "warn",
790
1012
  message: `${mcpCount} servers but no OMX servers yet (expected before first setup; run "omx setup --force" once)`,
791
1013
  };
792
1014
  }
793
- return { name: 'MCP Servers', status: 'warn', message: 'no MCP servers configured' };
1015
+ return {
1016
+ name: "MCP Servers",
1017
+ status: "warn",
1018
+ message: "no MCP servers configured",
1019
+ };
794
1020
  }
795
1021
  catch {
796
- return { name: 'MCP Servers', status: 'fail', message: 'cannot read config.toml' };
1022
+ return {
1023
+ name: "MCP Servers",
1024
+ status: "fail",
1025
+ message: "cannot read config.toml",
1026
+ };
797
1027
  }
798
1028
  }
799
1029
  //# sourceMappingURL=doctor.js.map