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.
- package/Cargo.lock +5 -5
- package/Cargo.toml +1 -1
- package/README.md +36 -5
- package/crates/omx-explore/src/main.rs +222 -12
- package/dist/agents/__tests__/native-config.test.js +40 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +6 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/agents/policy.d.ts +1 -0
- package/dist/agents/policy.d.ts.map +1 -1
- package/dist/agents/policy.js +4 -0
- package/dist/agents/policy.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +37 -13
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js +46 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +225 -111
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +96 -1
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +15 -2
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +292 -3
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +223 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +86 -0
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +23 -0
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +76 -11
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +140 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +310 -4
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +78 -19
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +79 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/sidecar.test.d.ts +2 -0
- package/dist/cli/__tests__/sidecar.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sidecar.test.js +24 -0
- package/dist/cli/__tests__/sidecar.test.js.map +1 -0
- package/dist/cli/__tests__/team.test.js +54 -7
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +12 -4
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/codex-home.d.ts +4 -6
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +9 -41
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +509 -279
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +6 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +284 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/omx.js +3 -1
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +13 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -0
- package/dist/cli/plugin-marketplace.js +77 -0
- package/dist/cli/plugin-marketplace.js.map +1 -0
- package/dist/cli/question.d.ts +1 -1
- package/dist/cli/question.d.ts.map +1 -1
- package/dist/cli/question.js +26 -12
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +20 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -0
- package/dist/cli/setup-preferences.js +71 -0
- package/dist/cli/setup-preferences.js.map +1 -0
- package/dist/cli/setup.d.ts +7 -5
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +271 -152
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +1 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +70 -15
- package/dist/cli/team.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +100 -3
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -5
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts +2 -0
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +1 -0
- package/dist/config/__tests__/generator-status-line-presets.test.js +203 -0
- package/dist/config/__tests__/generator-status-line-presets.test.js.map +1 -0
- package/dist/config/__tests__/models.test.js +23 -1
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +9 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +184 -16
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +5 -1
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +12 -2
- package/dist/config/models.js.map +1 -1
- package/dist/exec/followup.d.ts +44 -0
- package/dist/exec/followup.d.ts.map +1 -0
- package/dist/exec/followup.js +349 -0
- package/dist/exec/followup.js.map +1 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +37 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/codebase-map.test.js +63 -1
- package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +5 -5
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +12 -9
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +25 -18
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +23 -2
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +45 -2
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +17 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +121 -0
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +4 -4
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +103 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +2 -2
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +27 -13
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +35 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +215 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +70 -3
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js +5 -0
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +3 -2
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +9 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js +22 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +1 -0
- package/dist/hooks/codebase-map.d.ts.map +1 -1
- package/dist/hooks/codebase-map.js +83 -6
- package/dist/hooks/codebase-map.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +35 -4
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts +6 -0
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +117 -13
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/session.d.ts +2 -0
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +6 -0
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +4 -4
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +4 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/types.test.js +27 -0
- package/dist/hud/__tests__/types.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +8 -0
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +9 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +3 -0
- package/dist/hud/types.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +23 -5
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +50 -7
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +70 -12
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +10 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +71 -26
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-server.d.ts +5 -11
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +16 -432
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js +1 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +89 -5
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +98 -1
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/index.d.ts +5 -3
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +4 -3
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts +7 -6
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +90 -11
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/review-verdict.d.ts +3 -0
- package/dist/pipeline/review-verdict.d.ts.map +1 -0
- package/dist/pipeline/review-verdict.js +14 -0
- package/dist/pipeline/review-verdict.js.map +1 -0
- package/dist/pipeline/stages/code-review.d.ts +33 -0
- package/dist/pipeline/stages/code-review.d.ts.map +1 -0
- package/dist/pipeline/stages/code-review.js +51 -0
- package/dist/pipeline/stages/code-review.js.map +1 -0
- package/dist/pipeline/stages/ralph-verify.d.ts +12 -2
- package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js +24 -6
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +21 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/types.d.ts +14 -7
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/pipeline/types.js +2 -2
- package/dist/planning/__tests__/artifacts.test.js +152 -1
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/artifacts.d.ts +9 -0
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +60 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/client.test.js +23 -3
- package/dist/question/__tests__/client.test.js.map +1 -1
- package/dist/question/__tests__/renderer.test.js +148 -37
- package/dist/question/__tests__/renderer.test.js.map +1 -1
- package/dist/question/__tests__/types.test.js +21 -0
- package/dist/question/__tests__/types.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +155 -7
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/client.d.ts +14 -4
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/renderer.d.ts +11 -1
- package/dist/question/renderer.d.ts.map +1 -1
- package/dist/question/renderer.js +102 -7
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts +2 -2
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js +26 -17
- package/dist/question/state.js.map +1 -1
- package/dist/question/types.d.ts +25 -1
- package/dist/question/types.d.ts.map +1 -1
- package/dist/question/types.js +48 -13
- package/dist/question/types.js.map +1 -1
- package/dist/question/ui.d.ts +15 -2
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +268 -162
- package/dist/question/ui.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +415 -94
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/generate-release-body.test.js +36 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts +2 -0
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/prompt-inventory.test.js +56 -0
- package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +232 -54
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +12 -9
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-release-body.d.ts.map +1 -1
- package/dist/scripts/generate-release-body.js +12 -3
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +2 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +1 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +153 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +1 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts +4 -2
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +188 -6
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
- package/dist/scripts/notify-hook/process-runner.js +7 -3
- package/dist/scripts/notify-hook/process-runner.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +96 -11
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +3 -3
- package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts +34 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts.map +1 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.js +434 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -0
- package/dist/scripts/notify-hook/team-worker.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +3 -43
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +25 -4
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +36 -5
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/prompt-inventory.d.ts +29 -0
- package/dist/scripts/prompt-inventory.d.ts.map +1 -0
- package/dist/scripts/prompt-inventory.js +178 -0
- package/dist/scripts/prompt-inventory.js.map +1 -0
- package/dist/scripts/run-test-files.js +1 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.d.ts +2 -0
- package/dist/sidecar/__tests__/boundary.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/boundary.test.js +48 -0
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -0
- package/dist/sidecar/__tests__/collector.test.d.ts +2 -0
- package/dist/sidecar/__tests__/collector.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/collector.test.js +162 -0
- package/dist/sidecar/__tests__/collector.test.js.map +1 -0
- package/dist/sidecar/__tests__/render.test.d.ts +2 -0
- package/dist/sidecar/__tests__/render.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/render.test.js +67 -0
- package/dist/sidecar/__tests__/render.test.js.map +1 -0
- package/dist/sidecar/__tests__/tmux.test.d.ts +2 -0
- package/dist/sidecar/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/tmux.test.js +30 -0
- package/dist/sidecar/__tests__/tmux.test.js.map +1 -0
- package/dist/sidecar/__tests__/watch.test.d.ts +2 -0
- package/dist/sidecar/__tests__/watch.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/watch.test.js +42 -0
- package/dist/sidecar/__tests__/watch.test.js.map +1 -0
- package/dist/sidecar/collector.d.ts +4 -0
- package/dist/sidecar/collector.d.ts.map +1 -0
- package/dist/sidecar/collector.js +377 -0
- package/dist/sidecar/collector.js.map +1 -0
- package/dist/sidecar/index.d.ts +25 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +165 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/sidecar/render.d.ts +3 -0
- package/dist/sidecar/render.d.ts.map +1 -0
- package/dist/sidecar/render.js +72 -0
- package/dist/sidecar/render.js.map +1 -0
- package/dist/sidecar/tmux.d.ts +13 -0
- package/dist/sidecar/tmux.d.ts.map +1 -0
- package/dist/sidecar/tmux.js +44 -0
- package/dist/sidecar/tmux.js.map +1 -0
- package/dist/sidecar/types.d.ts +125 -0
- package/dist/sidecar/types.d.ts.map +1 -0
- package/dist/sidecar/types.js +2 -0
- package/dist/sidecar/types.js.map +1 -0
- package/dist/state/__tests__/operations.test.js +50 -22
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +9 -1
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +19 -7
- package/dist/state/operations.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +1 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/commit-hygiene.test.d.ts +2 -0
- package/dist/team/__tests__/commit-hygiene.test.d.ts.map +1 -0
- package/dist/team/__tests__/commit-hygiene.test.js +93 -0
- package/dist/team/__tests__/commit-hygiene.test.js.map +1 -0
- package/dist/team/__tests__/delegation-policy.test.d.ts +2 -0
- package/dist/team/__tests__/delegation-policy.test.d.ts.map +1 -0
- package/dist/team/__tests__/delegation-policy.test.js +69 -0
- package/dist/team/__tests__/delegation-policy.test.js.map +1 -0
- package/dist/team/__tests__/events.test.js +54 -4
- package/dist/team/__tests__/events.test.js.map +1 -1
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +2 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +1 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js +78 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +1 -0
- package/dist/team/__tests__/model-contract.test.js +16 -0
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +2 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +1 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js +95 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -0
- package/dist/team/__tests__/runtime.test.js +623 -14
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +177 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +110 -0
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +399 -2
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +94 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/commit-hygiene.d.ts +22 -3
- package/dist/team/commit-hygiene.d.ts.map +1 -1
- package/dist/team/commit-hygiene.js +134 -2
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +1 -1
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/contracts.js +2 -0
- package/dist/team/contracts.js.map +1 -1
- package/dist/team/dag-schema.d.ts +38 -0
- package/dist/team/dag-schema.d.ts.map +1 -0
- package/dist/team/dag-schema.js +221 -0
- package/dist/team/dag-schema.js.map +1 -0
- package/dist/team/delegation-policy.d.ts +3 -0
- package/dist/team/delegation-policy.d.ts.map +1 -0
- package/dist/team/delegation-policy.js +82 -0
- package/dist/team/delegation-policy.js.map +1 -0
- package/dist/team/model-contract.d.ts +3 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +44 -5
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +60 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -0
- package/dist/team/repo-aware-decomposition.js +229 -0
- package/dist/team/repo-aware-decomposition.js.map +1 -0
- package/dist/team/runtime.d.ts +27 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +172 -52
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +33 -0
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state/types.d.ts +23 -1
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state-root.d.ts +35 -0
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +281 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +27 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +6 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +1 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +105 -6
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +3 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +77 -4
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/utils/agents-md.d.ts +3 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +25 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/package.json +3 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +2 -2
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +134 -205
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +4 -4
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +14 -7
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/help/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +41 -10
- package/plugins/oh-my-codex/skills/plan/SKILL.md +12 -14
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +2 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -9
- package/plugins/oh-my-codex/skills/security-review/SKILL.md +4 -4
- package/plugins/oh-my-codex/skills/team/SKILL.md +2 -5
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +2 -5
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -3
- package/prompts/analyst.md +2 -2
- package/prompts/api-reviewer.md +2 -2
- package/prompts/architect.md +2 -2
- package/prompts/build-fixer.md +2 -2
- package/prompts/code-reviewer.md +15 -5
- package/prompts/code-simplifier.md +1 -1
- package/prompts/critic.md +35 -83
- package/prompts/debugger.md +2 -2
- package/prompts/dependency-expert.md +2 -2
- package/prompts/designer.md +2 -2
- package/prompts/executor.md +40 -114
- package/prompts/explore-harness.md +1 -1
- package/prompts/explore.md +37 -90
- package/prompts/git-master.md +2 -2
- package/prompts/information-architect.md +1 -1
- package/prompts/performance-reviewer.md +2 -2
- package/prompts/planner.md +35 -62
- package/prompts/product-analyst.md +2 -2
- package/prompts/product-manager.md +2 -2
- package/prompts/qa-tester.md +2 -2
- package/prompts/quality-reviewer.md +2 -2
- package/prompts/quality-strategist.md +2 -2
- package/prompts/researcher.md +46 -78
- package/prompts/security-reviewer.md +2 -2
- package/prompts/sisyphus-lite.md +2 -2
- package/prompts/style-reviewer.md +2 -2
- package/prompts/team-executor.md +1 -1
- package/prompts/test-engineer.md +2 -2
- package/prompts/ux-researcher.md +2 -2
- package/prompts/verifier.md +29 -34
- package/prompts/vision.md +2 -2
- package/prompts/writer.md +2 -2
- package/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/skills/analyze/SKILL.md +1 -1
- package/skills/autopilot/SKILL.md +134 -205
- package/skills/build-fix/SKILL.md +4 -4
- package/skills/code-review/SKILL.md +4 -4
- package/skills/deep-interview/SKILL.md +14 -7
- package/skills/doctor/SKILL.md +1 -1
- package/skills/help/SKILL.md +1 -1
- package/skills/omx-setup/SKILL.md +41 -10
- package/skills/plan/SKILL.md +12 -14
- package/skills/ralph/SKILL.md +2 -4
- package/skills/ralplan/SKILL.md +5 -9
- package/skills/security-review/SKILL.md +4 -4
- package/skills/team/SKILL.md +2 -5
- package/skills/ultraqa/SKILL.md +2 -5
- package/skills/ultrawork/SKILL.md +2 -3
- package/src/scripts/__tests__/codex-native-hook.test.ts +502 -94
- package/src/scripts/__tests__/generate-release-body.test.ts +41 -0
- package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
- package/src/scripts/codex-native-hook.ts +293 -61
- package/src/scripts/codex-native-pre-post.ts +10 -8
- package/src/scripts/generate-release-body.ts +13 -2
- package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
- package/src/scripts/notify-hook/managed-tmux.ts +196 -9
- package/src/scripts/notify-hook/process-runner.ts +7 -3
- package/src/scripts/notify-hook/team-dispatch.ts +103 -11
- package/src/scripts/notify-hook/team-tmux-guard.ts +3 -3
- package/src/scripts/notify-hook/team-worker-posttooluse.ts +536 -0
- package/src/scripts/notify-hook/team-worker.ts +4 -48
- package/src/scripts/notify-hook/tmux-injection.ts +24 -6
- package/src/scripts/notify-hook.ts +36 -5
- package/src/scripts/prompt-inventory.ts +218 -0
- package/src/scripts/run-test-files.ts +1 -0
- package/templates/AGENTS.md +34 -95
package/dist/cli/doctor.js
CHANGED
|
@@ -1,57 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* omx doctor - Validate oh-my-codex installation
|
|
3
3
|
*/
|
|
4
|
-
import { existsSync } from
|
|
5
|
-
import { readdir, readFile } from
|
|
6
|
-
import { join } from
|
|
7
|
-
import { codexHome, codexConfigPath, codexPromptsDir, userSkillsDir, projectSkillsDir, omxStateDir, detectLegacySkillRootOverlap, } from
|
|
8
|
-
import { classifySpawnError, spawnPlatformCommandSync } from
|
|
9
|
-
import { getCatalogExpectations } from
|
|
10
|
-
import { parse as parseToml } from
|
|
11
|
-
import { getBuiltinExploreHarnessUnsupportedReason, resolvePackagedExploreHarnessCommand, EXPLORE_BIN_ENV, } from
|
|
12
|
-
import { getPackageRoot } from
|
|
13
|
-
import { hasLegacyOmxTeamRunTable } from
|
|
14
|
-
import { getMissingManagedCodexHookEvents } from
|
|
15
|
-
import { OMX_FIRST_PARTY_MCP_SERVER_NAMES } from
|
|
16
|
-
import { getDefaultBridge, isBridgeEnabled } from
|
|
17
|
-
import { OMX_EXPLORE_CMD_ENV, isExploreCommandRoutingEnabled } from
|
|
18
|
-
import { isLeaderRuntimeStale } from
|
|
19
|
-
import { triagePrompt } from
|
|
20
|
-
import { readTriageConfig } from
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
26
|
-
if (
|
|
27
|
-
return {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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:
|
|
32
|
+
return { scope: "user", source: "default" };
|
|
46
33
|
}
|
|
47
34
|
function resolveDoctorPaths(cwd, scope) {
|
|
48
|
-
if (scope ===
|
|
49
|
-
const codexHomeDir = join(cwd,
|
|
35
|
+
if (scope === "project") {
|
|
36
|
+
const codexHomeDir = join(cwd, ".codex");
|
|
50
37
|
return {
|
|
51
38
|
codexHomeDir,
|
|
52
|
-
configPath: join(codexHomeDir,
|
|
53
|
-
hooksPath: join(codexHomeDir,
|
|
54
|
-
promptsDir: join(codexHomeDir,
|
|
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(),
|
|
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 ===
|
|
77
|
-
?
|
|
78
|
-
:
|
|
79
|
-
console.log(
|
|
80
|
-
console.log(
|
|
81
|
-
console.log(`Resolved setup scope: ${scopeResolution.scope}${scopeSourceMessage}
|
|
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(
|
|
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.
|
|
91
|
+
checks.push(await checkSkills(paths, scopeResolution.installMode));
|
|
101
92
|
// Check 6.5: Legacy/current skill-root overlap
|
|
102
|
-
if (scopeResolution.scope ===
|
|
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(
|
|
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 ===
|
|
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 ===
|
|
115
|
+
if (check.status === "pass")
|
|
121
116
|
passCount++;
|
|
122
|
-
else if (check.status ===
|
|
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(
|
|
130
|
+
console.log("\nAll checks passed! oh-my-codex is ready.");
|
|
136
131
|
}
|
|
137
132
|
}
|
|
138
133
|
async function doctorTeam() {
|
|
139
|
-
console.log(
|
|
140
|
-
console.log(
|
|
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(
|
|
144
|
-
console.log(
|
|
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 ===
|
|
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 ===
|
|
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,
|
|
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:
|
|
170
|
+
code: "resume_blocker",
|
|
176
171
|
message: `runtime not ready: ${reason}`,
|
|
177
|
-
severity:
|
|
172
|
+
severity: "fail",
|
|
178
173
|
});
|
|
179
174
|
}
|
|
180
175
|
}
|
|
181
176
|
if (authority?.stale) {
|
|
182
177
|
issues.push({
|
|
183
|
-
code:
|
|
184
|
-
message: `authority stale (owner: ${authority.owner ??
|
|
185
|
-
severity:
|
|
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,
|
|
203
|
-
const configPath = join(teamDir,
|
|
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,
|
|
204
|
+
const raw = await readFile(manifestPath, "utf-8");
|
|
208
205
|
const parsed = JSON.parse(raw);
|
|
209
|
-
if (typeof parsed.tmux_session ===
|
|
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,
|
|
222
|
+
const raw = await readFile(configPath, "utf-8");
|
|
220
223
|
const parsed = JSON.parse(raw);
|
|
221
|
-
if (typeof parsed.tmux_session ===
|
|
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
|
-
|
|
231
|
-
|
|
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:
|
|
254
|
+
code: "resume_blocker",
|
|
234
255
|
message: `${teamName} references missing tmux session ${tmuxSession}`,
|
|
235
|
-
severity:
|
|
256
|
+
severity: "fail",
|
|
236
257
|
});
|
|
237
258
|
}
|
|
238
259
|
// delayed_status_lag + slow_shutdown checks
|
|
239
|
-
const workersRoot = join(teamDir,
|
|
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,
|
|
248
|
-
const heartbeatPath = join(workerDir,
|
|
249
|
-
const shutdownReqPath = join(workerDir,
|
|
250
|
-
const shutdownAckPath = join(workerDir,
|
|
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,
|
|
255
|
-
readFile(heartbeatPath,
|
|
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
|
|
260
|
-
|
|
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:
|
|
287
|
+
code: "delayed_status_lag",
|
|
263
288
|
message: `${teamName}/${worker.name} working with stale heartbeat`,
|
|
264
|
-
severity:
|
|
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,
|
|
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:
|
|
304
|
+
code: "slow_shutdown",
|
|
280
305
|
message: `${teamName}/${worker.name} has stale shutdown request without ack`,
|
|
281
|
-
severity:
|
|
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,
|
|
293
|
-
const leaderActivityPath = join(stateDir,
|
|
294
|
-
if ((existsSync(hudStatePath) || existsSync(leaderActivityPath)) &&
|
|
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:
|
|
332
|
+
code: "stale_leader",
|
|
307
333
|
message: `${teamName} has active tmux session but leader has no recent activity`,
|
|
308
|
-
severity:
|
|
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:
|
|
348
|
+
code: "orphan_tmux_session",
|
|
323
349
|
message: `${session} exists without matching team state (possibly external project)`,
|
|
324
|
-
severity:
|
|
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(
|
|
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 ||
|
|
389
|
+
const stderr = (res.stderr || "").toLowerCase();
|
|
351
390
|
// tmux installed but no server/session is running.
|
|
352
|
-
if (stderr.includes(
|
|
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(
|
|
397
|
+
const sessions = (res.stdout || "")
|
|
398
|
+
.split("\n")
|
|
359
399
|
.map((s) => s.trim())
|
|
360
|
-
.filter((s) => s.startsWith(
|
|
400
|
+
.filter((s) => s.startsWith("omx-team-"));
|
|
361
401
|
return new Set(sessions);
|
|
362
402
|
}
|
|
363
403
|
function checkCodexCli() {
|
|
364
|
-
const { result } = spawnPlatformCommandSync(
|
|
365
|
-
encoding:
|
|
366
|
-
stdio: [
|
|
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 ===
|
|
372
|
-
return {
|
|
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 ===
|
|
418
|
+
if (kind === "blocked") {
|
|
375
419
|
return {
|
|
376
|
-
name:
|
|
377
|
-
status:
|
|
378
|
-
message: `found but could not be executed in this environment (${code ||
|
|
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:
|
|
383
|
-
status:
|
|
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 ||
|
|
389
|
-
return {
|
|
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 ||
|
|
439
|
+
const stderr = (result.stderr || "").trim();
|
|
392
440
|
return {
|
|
393
|
-
name:
|
|
394
|
-
status:
|
|
395
|
-
message: stderr !==
|
|
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(
|
|
449
|
+
const major = parseInt(process.versions.node.split(".")[0] ?? "0", 10);
|
|
400
450
|
if (isNaN(major)) {
|
|
401
|
-
return {
|
|
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 {
|
|
458
|
+
return {
|
|
459
|
+
name: "Node.js",
|
|
460
|
+
status: "pass",
|
|
461
|
+
message: `v${process.versions.node}`,
|
|
462
|
+
};
|
|
405
463
|
}
|
|
406
|
-
return {
|
|
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,
|
|
472
|
+
const manifestPath = join(packageRoot, "crates", "omx-explore", "Cargo.toml");
|
|
411
473
|
if (!existsSync(manifestPath)) {
|
|
412
474
|
return {
|
|
413
|
-
name:
|
|
414
|
-
status:
|
|
415
|
-
message:
|
|
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:
|
|
424
|
-
status:
|
|
485
|
+
name: "Explore Harness",
|
|
486
|
+
status: "pass",
|
|
425
487
|
message: `${EXPLORE_BIN_ENV} configured (${override})`,
|
|
426
488
|
};
|
|
427
489
|
}
|
|
428
490
|
return {
|
|
429
|
-
name:
|
|
430
|
-
status:
|
|
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:
|
|
438
|
-
status:
|
|
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:
|
|
446
|
-
status:
|
|
507
|
+
name: "Explore Harness",
|
|
508
|
+
status: "pass",
|
|
447
509
|
message: `ready (packaged native binary: ${packaged.command})`,
|
|
448
510
|
};
|
|
449
511
|
}
|
|
450
|
-
const { result } = spawnPlatformCommandSync(
|
|
451
|
-
encoding:
|
|
452
|
-
stdio: [
|
|
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 ===
|
|
518
|
+
if (kind === "missing") {
|
|
457
519
|
return {
|
|
458
|
-
name:
|
|
459
|
-
status:
|
|
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:
|
|
465
|
-
status:
|
|
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 ||
|
|
532
|
+
const version = (result.stdout || "").trim();
|
|
471
533
|
return {
|
|
472
|
-
name:
|
|
473
|
-
status:
|
|
474
|
-
message: `ready (${version ||
|
|
534
|
+
name: "Explore Harness",
|
|
535
|
+
status: "pass",
|
|
536
|
+
message: `ready (${version || "cargo available"})`,
|
|
475
537
|
};
|
|
476
538
|
}
|
|
477
539
|
return {
|
|
478
|
-
name:
|
|
479
|
-
status:
|
|
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:
|
|
547
|
+
return { name, status: "pass", message: path };
|
|
486
548
|
}
|
|
487
|
-
return { name, status:
|
|
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
|
|
560
|
+
return "unknown TOML parse error";
|
|
499
561
|
}
|
|
500
562
|
}
|
|
501
563
|
async function checkConfig(configPath) {
|
|
502
564
|
if (!existsSync(configPath)) {
|
|
503
|
-
return { name:
|
|
565
|
+
return { name: "Config", status: "warn", message: "config.toml not found" };
|
|
504
566
|
}
|
|
505
567
|
try {
|
|
506
|
-
const content = await readFile(configPath,
|
|
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(
|
|
511
|
-
tomlError.includes(
|
|
512
|
-
?
|
|
513
|
-
:
|
|
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:
|
|
516
|
-
status:
|
|
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:
|
|
523
|
-
status:
|
|
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(
|
|
589
|
+
const hasOmx = content.includes("omx_") || content.includes("oh-my-codex");
|
|
528
590
|
if (hasOmx) {
|
|
529
|
-
return {
|
|
591
|
+
return {
|
|
592
|
+
name: "Config",
|
|
593
|
+
status: "pass",
|
|
594
|
+
message: "config.toml has OMX entries",
|
|
595
|
+
};
|
|
530
596
|
}
|
|
531
597
|
return {
|
|
532
|
-
name:
|
|
533
|
-
status:
|
|
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 {
|
|
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 ===
|
|
613
|
+
if (typeof envValue === "string" &&
|
|
614
|
+
!isExploreCommandRoutingEnabled(process.env)) {
|
|
544
615
|
return {
|
|
545
|
-
name:
|
|
546
|
-
status:
|
|
547
|
-
message:
|
|
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:
|
|
553
|
-
status:
|
|
554
|
-
message:
|
|
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,
|
|
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 ===
|
|
632
|
+
if (typeof configuredValue === "string" &&
|
|
562
633
|
!isExploreCommandRoutingEnabled({
|
|
563
634
|
USE_OMX_EXPLORE_CMD: configuredValue,
|
|
564
635
|
})) {
|
|
565
636
|
return {
|
|
566
|
-
name:
|
|
567
|
-
status:
|
|
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:
|
|
573
|
-
status:
|
|
574
|
-
message:
|
|
643
|
+
name: "Explore routing",
|
|
644
|
+
status: "pass",
|
|
645
|
+
message: "enabled by default",
|
|
575
646
|
};
|
|
576
647
|
}
|
|
577
648
|
catch {
|
|
578
649
|
return {
|
|
579
|
-
name:
|
|
580
|
-
status:
|
|
581
|
-
message:
|
|
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,
|
|
590
|
-
const hasOmx = configContent.includes(
|
|
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:
|
|
594
|
-
status:
|
|
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:
|
|
606
|
-
status:
|
|
607
|
-
message:
|
|
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,
|
|
683
|
+
const content = await readFile(hooksPath, "utf-8");
|
|
612
684
|
const missingEvents = getMissingManagedCodexHookEvents(content);
|
|
613
685
|
if (missingEvents === null) {
|
|
614
686
|
return {
|
|
615
|
-
name:
|
|
616
|
-
status:
|
|
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:
|
|
623
|
-
status:
|
|
624
|
-
message: `hooks.json is missing OMX-managed coverage for ${missingEvents.join(
|
|
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:
|
|
629
|
-
status:
|
|
630
|
-
message:
|
|
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:
|
|
636
|
-
status:
|
|
637
|
-
message:
|
|
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 {
|
|
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(
|
|
731
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
649
732
|
if (mdFiles.length >= expectations.promptMin) {
|
|
650
|
-
return {
|
|
733
|
+
return {
|
|
734
|
+
name: "Prompts",
|
|
735
|
+
status: "pass",
|
|
736
|
+
message: `${mdFiles.length} agent prompts installed`,
|
|
737
|
+
};
|
|
651
738
|
}
|
|
652
|
-
return {
|
|
739
|
+
return {
|
|
740
|
+
name: "Prompts",
|
|
741
|
+
status: "warn",
|
|
742
|
+
message: `${mdFiles.length} prompts (expected >= ${expectations.promptMin})`,
|
|
743
|
+
};
|
|
653
744
|
}
|
|
654
745
|
catch {
|
|
655
|
-
return {
|
|
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:
|
|
663
|
-
status:
|
|
664
|
-
message:
|
|
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:
|
|
670
|
-
status:
|
|
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:
|
|
677
|
-
status:
|
|
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:
|
|
686
|
-
status:
|
|
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
|
-
|
|
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(
|
|
693
|
-
return {
|
|
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(
|
|
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 {
|
|
859
|
+
return {
|
|
860
|
+
name: "Skills",
|
|
861
|
+
status: "pass",
|
|
862
|
+
message: `${skillDirs.length} skills installed`,
|
|
863
|
+
};
|
|
700
864
|
}
|
|
701
|
-
return {
|
|
865
|
+
return {
|
|
866
|
+
name: "Skills",
|
|
867
|
+
status: "warn",
|
|
868
|
+
message: `${skillDirs.length} skills (expected >= ${expectations.skillMin})`,
|
|
869
|
+
};
|
|
702
870
|
}
|
|
703
871
|
catch {
|
|
704
|
-
return {
|
|
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 ===
|
|
709
|
-
const userAgentsMd = join(codexHomeDir,
|
|
879
|
+
function checkAgentsMd(scope, codexHomeDir, installMode) {
|
|
880
|
+
if (scope === "user") {
|
|
881
|
+
const userAgentsMd = join(codexHomeDir, "AGENTS.md");
|
|
710
882
|
if (existsSync(userAgentsMd)) {
|
|
711
|
-
return {
|
|
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:
|
|
715
|
-
status:
|
|
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(),
|
|
902
|
+
const projectAgentsMd = join(process.cwd(), "AGENTS.md");
|
|
720
903
|
if (existsSync(projectAgentsMd)) {
|
|
721
|
-
return {
|
|
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:
|
|
725
|
-
status:
|
|
726
|
-
message:
|
|
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 ===
|
|
926
|
+
if (config.status === "disabled") {
|
|
733
927
|
return {
|
|
734
|
-
name:
|
|
735
|
-
status:
|
|
928
|
+
name: "Prompt triage",
|
|
929
|
+
status: "warn",
|
|
736
930
|
message: `disabled via ${config.path}`,
|
|
737
931
|
};
|
|
738
932
|
}
|
|
739
|
-
if (config.status ===
|
|
933
|
+
if (config.status === "invalid") {
|
|
740
934
|
return {
|
|
741
|
-
name:
|
|
742
|
-
status:
|
|
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(
|
|
748
|
-
const validLanes = new Set([
|
|
749
|
-
if (!decision ||
|
|
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:
|
|
752
|
-
status:
|
|
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 ===
|
|
952
|
+
const sourceLabel = config.status === "defaulted" ? "enabled (default)" : "enabled";
|
|
757
953
|
return {
|
|
758
|
-
name:
|
|
759
|
-
status:
|
|
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 {
|
|
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
|
-
|
|
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,
|
|
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 {
|
|
1003
|
+
return {
|
|
1004
|
+
name: "MCP Servers",
|
|
1005
|
+
status: "pass",
|
|
1006
|
+
message: `${mcpCount} servers configured (OMX present)`,
|
|
1007
|
+
};
|
|
786
1008
|
}
|
|
787
1009
|
return {
|
|
788
|
-
name:
|
|
789
|
-
status:
|
|
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 {
|
|
1015
|
+
return {
|
|
1016
|
+
name: "MCP Servers",
|
|
1017
|
+
status: "warn",
|
|
1018
|
+
message: "no MCP servers configured",
|
|
1019
|
+
};
|
|
794
1020
|
}
|
|
795
1021
|
catch {
|
|
796
|
-
return {
|
|
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
|