claude-code-conductor 2.49.0__tar.gz → 2.50.0__tar.gz
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.
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/platform-adapters.md +12 -1
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/CHANGELOG.md +18 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/PKG-INFO +1 -1
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/__init__.py +1 -1
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/adapters.py +2 -2
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_doctor.py +77 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_adapters.py +44 -1
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_doctor.py +168 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/design-critic.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/wt_tester.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/breaking-changes.txt +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/deletions.txt +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/config-policy.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/_hook_utils.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/permission_handler.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/permission_handler_toast.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/recall_autorebuild.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/tier_autoapply.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/tier_gap_check.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/permission_rules.json +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/settings.json +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/brainstorm/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/codex-review/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/init-session/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/init-session/scripts/session_guard.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/start/SKILL.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.gitignore +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/ARCHITECTURE.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSES/numpy-LICENSE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/README.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/hatch_build.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/pyproject.toml +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/_db_params.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_ask.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_metrics.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/db.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/gitutil.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrate.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/001_initial.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/003_tier_cost.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/004_agent_outcomes.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/006_review_decisions_severity.sql +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/README.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/migrations/__init__.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/pricing.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/question.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/src/c3/usage_ingester.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/__init__.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/_pre_compact_helpers.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/conftest.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/fixtures/usage/README.md +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/fixtures/usage/mainline.jsonl +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_hook_utils.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_permission_handler.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_permission_handler_toast.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_recall_autorebuild.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_record_agent_outcome.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_settings_tier_autoapply_registration.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_tier_autoapply.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_tier_gap_check.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/hooks/test_tier_security_fixes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/_skill_helpers.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_init_session_no_task_type.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_parallel_agents_skill_tier.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_session_guard.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_start_skill_new_flow.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_check_deletions.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_ask.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_metrics.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_update_breaking_changes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_cli_update_deletions.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_db.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_extract_breaking_changes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_gitutil.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_migrate.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_pricing.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_usage_ingester.py +0 -0
- {claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/tests/test_worktree_guard.py +0 -0
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/platform-adapters.md
RENAMED
|
@@ -11,7 +11,7 @@ C3 は **Claude Code** を canonical platform として設計されているが
|
|
|
11
11
|
- 動作差分のまとめ
|
|
12
12
|
|
|
13
13
|
を一箇所にまとめたリファレンス。実装は `src/c3/adapters.py` / `src/c3/mcp_server.py` /
|
|
14
|
-
`src/c3/cli_ask.py` / `src/c3/platforms.py` を参照。
|
|
14
|
+
`src/c3/cli_ask.py` / `src/c3/platforms.py` / `src/c3/cli_doctor.py` を参照。
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -92,6 +92,9 @@ python -m c3.mcp_server
|
|
|
92
92
|
`C3_PROJECT_ROOT` 環境変数でプロジェクトルートを指定可能(adapter 生成時に自動設定)。
|
|
93
93
|
ソースインストール時は `PYTHONPATH` も adapter が `<repo>/src` に設定する。
|
|
94
94
|
|
|
95
|
+
生成される `.codex/config.toml` / `.cursor/mcp.json` の `command` は `python` ではなく、
|
|
96
|
+
adapter 生成時点の `sys.executable`(絶対パス)を書き込む。理由は「7. 既知の制限」を参照。
|
|
97
|
+
|
|
95
98
|
---
|
|
96
99
|
|
|
97
100
|
## 4. `c3 ask` CLI fallback
|
|
@@ -178,3 +181,11 @@ Claude Code / Codex / Cursor / OpenCode が同じプロジェクトを行き来
|
|
|
178
181
|
- **OpenCode の `AskUserQuestion`**: OpenCode adapter は MCP 設定を生成しないため、`c3_ask_user_question` ツールは使わず `AGENTS.md` の指示に従ってユーザーへ直接確認する。`multiSelect: true` は「複数選択の質問」として維持するよう指示済み
|
|
179
182
|
- **OpenCode の `tools` 制限**: 生成される agent には一律で `bash/read/edit/write/websearch` を付与する。Claude 側 frontmatter の細かな `tools` 制限は反映されない(C3 の `code-reviewer` / `security-reviewer` は Claude 側でもレポート出力のため `write` を持つ)
|
|
180
183
|
- **改行コード**: adapter 生成ファイルは LF 改行で書き出す(`newline="\n"`)。`.gitattributes` で `eol=lf` を固定済み
|
|
184
|
+
- **Codex の trust 要件**: プロジェクトが Codex に trust されていない場合、`.codex/config.toml` は**エラーなしで無視**される(Codex 公式仕様)。MCP サーバーが読み込まれず `AskUserQuestion` が動かない場合は、まず対象プロジェクトを Codex 側で trust 済みか確認する(Codex CLI: 初回起動時のプロンプトで trust するか、設定で許可済みディレクトリに追加する)
|
|
185
|
+
- **MCP `command` の絶対パス化**: adapter が書き込む `command` は `python` ではなく `sys.executable`(adapter 生成時の絶対パス)を使う。理由:
|
|
186
|
+
- macOS 12.3 以降、無印 `python` は標準に存在しない(`python3` のみ。Homebrew も同様)。`command: "python"` のままだと Codex が MCP spawn 時に program not found となり、「起動時にエラーで読み込まれない」症状になる
|
|
187
|
+
- `python` が PATH 上にあっても、pipx / venv などの隔離環境では `No module named c3` で起動失敗することがある
|
|
188
|
+
- GUI 起動の Codex(Desktop / IDE 拡張)はシェルの PATH を継承しないことがある(最小 PATH)
|
|
189
|
+
- 代案の「POSIX では `python3` にする」は不採用: 無印 python 不在の問題しか救えず、pipx 隔離や GUI PATH 最小の問題には無力なため
|
|
190
|
+
- `c3 doctor --platform codex|cursor` は生成済み config から `command` を読み取り、実行可能か・`<command> -c "import c3"` が成功するかを自己診断する
|
|
191
|
+
- **adapter 生成物はマシン固有**: `command` に埋め込む `sys.executable` は生成したマシン・環境(venv / pipx / システム Python)に依存する絶対パスであるため、adapter 生成物(`.codex/config.toml` / `.cursor/mcp.json` など)はチームで共有せず、各マシンで `c3 init --platform <p>` または `c3 update --platform <p>` を実行して再生成する運用とする
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.50.0] - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### 修正
|
|
6
|
+
|
|
7
|
+
- **MCP 設定の `command` を `sys.executable` 絶対パス化(Codex / Cursor adapter)**: 生成される `.codex/config.toml` / `.cursor/mcp.json` の `command` が `"python"` ハードコードだったため、無印 `python` が存在しない環境(macOS 12.3 以降の標準 / Homebrew)・pipx / venv 隔離(`No module named c3`)・GUI 起動の Codex(シェル PATH 非継承)で MCP サーバーが起動時エラーになり `c3_ask_user_question` が使えなかった問題を修正。`c3 init` / `c3 update --platform` を実行した Python の絶対パスを埋め込む(TOML は既存 `_toml_escape` でエスケープ)。X 上の実利用報告「Claude Code だと動くが Codex だと起動時にエラーで読み込まれない」が起点
|
|
8
|
+
|
|
9
|
+
### 追加
|
|
10
|
+
|
|
11
|
+
- **`c3 doctor` の MCP 起動自己診断**: 生成済み config(`.codex/config.toml` / `.cursor/mcp.json`)から `command` を読み取り、(a) 実行可能性 (b) `<command> -c "import c3"` の成否を検証する。失敗時は WARN と `c3 update --platform <p>` での再生成を案内。この種の環境起因の起動失敗を利用者が一発で自己診断できるようにした
|
|
12
|
+
|
|
13
|
+
### 変更
|
|
14
|
+
|
|
15
|
+
- `.claude/docs/platform-adapters.md` の「既知の制限」に、Codex の trust 要件(未 trust プロジェクトの `.codex/config.toml` は**エラーなしで無視**される・trust 手順)・`command` 絶対パス化の理由・adapter 生成物のマシン固有性(チームで共有せず各マシンで `c3 init/update --platform` 再生成する運用)を追記
|
|
16
|
+
|
|
17
|
+
### 後方互換
|
|
18
|
+
|
|
19
|
+
- 既存の生成済み config は次回 `c3 update --platform` 実行まで従来のまま。再生成すると `command` が実行環境の絶対パスに変わる(マシン固有・意図された挙動。チーム共有リポジトリでは各メンバーが自マシンで再生成する)。**破壊的変更なし**
|
|
20
|
+
|
|
3
21
|
## [2.49.0] - 2026-07-17
|
|
4
22
|
|
|
5
23
|
### 追加
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-conductor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.50.0
|
|
4
4
|
Summary: Multi-agent orchestration framework for Claude Code with Codex/Cursor adapters (C3)
|
|
5
5
|
Project-URL: Homepage, https://github.com/satoh-y-0323/claude-code-conductor
|
|
6
6
|
Project-URL: Repository, https://github.com/satoh-y-0323/claude-code-conductor
|
|
@@ -223,7 +223,7 @@ def _write_cursor_mcp(target_root: Path, *, dry_run: bool) -> list[AdapterAction
|
|
|
223
223
|
if pythonpath is not None:
|
|
224
224
|
env["PYTHONPATH"] = str(pythonpath)
|
|
225
225
|
servers["c3"] = {
|
|
226
|
-
"command":
|
|
226
|
+
"command": sys.executable,
|
|
227
227
|
"args": ["-m", "c3.mcp_server"],
|
|
228
228
|
"env": env,
|
|
229
229
|
}
|
|
@@ -331,7 +331,7 @@ tool, read the matching generated Codex skill from `.agents/skills/<name>/SKILL.
|
|
|
331
331
|
def _codex_config_section() -> str:
|
|
332
332
|
lines = [
|
|
333
333
|
"[mcp_servers.c3]",
|
|
334
|
-
'command = "
|
|
334
|
+
f'command = "{_toml_escape(sys.executable)}"',
|
|
335
335
|
'args = ["-m", "c3.mcp_server"]',
|
|
336
336
|
"startup_timeout_sec = 10",
|
|
337
337
|
"tool_timeout_sec = 600",
|
|
@@ -4,7 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
6
|
import json
|
|
7
|
+
import re
|
|
7
8
|
import shutil
|
|
9
|
+
import subprocess
|
|
8
10
|
from pathlib import Path
|
|
9
11
|
|
|
10
12
|
from c3._terminal import supports_color as _supports_color
|
|
@@ -15,6 +17,8 @@ _OK = "OK"
|
|
|
15
17
|
_WARN = "WARN"
|
|
16
18
|
_ERR = "ERR"
|
|
17
19
|
|
|
20
|
+
_MCP_STARTUP_TIMEOUT_SEC = 10
|
|
21
|
+
|
|
18
22
|
|
|
19
23
|
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
20
24
|
parser = subparsers.add_parser(
|
|
@@ -111,6 +115,9 @@ def _check_codex_adapter() -> list[tuple[str, str, str]]:
|
|
|
111
115
|
findings.append(_dir_or_warn(".agents/skills", skills, "run `c3 init --platform codex`"))
|
|
112
116
|
findings.append(_file_or_warn(".codex/config.toml", config, "run `c3 init --platform codex`"))
|
|
113
117
|
findings.append(_dir_or_warn(".codex/agents", custom_agents, "run `c3 init --platform codex`"))
|
|
118
|
+
if config.is_file():
|
|
119
|
+
command = _extract_codex_mcp_command(config.read_text(encoding="utf-8"))
|
|
120
|
+
findings.append(_check_mcp_command_startup("codex MCP startup", command, "codex"))
|
|
114
121
|
codex = shutil.which("codex")
|
|
115
122
|
if codex is None:
|
|
116
123
|
findings.append((_WARN, "codex binary", "not on PATH; install Codex CLI to use the adapter"))
|
|
@@ -147,6 +154,9 @@ def _check_cursor_adapter() -> list[tuple[str, str, str]]:
|
|
|
147
154
|
mcp = root / ".cursor" / "mcp.json"
|
|
148
155
|
findings.append(_file_or_warn(".cursor/rules/c3-core.mdc", rule, "run `c3 init --platform cursor`"))
|
|
149
156
|
findings.append(_file_or_warn(".cursor/mcp.json", mcp, "run `c3 init --platform cursor`"))
|
|
157
|
+
if mcp.is_file():
|
|
158
|
+
command = _extract_cursor_mcp_command(mcp.read_text(encoding="utf-8"))
|
|
159
|
+
findings.append(_check_mcp_command_startup("cursor MCP startup", command, "cursor"))
|
|
150
160
|
cursor = shutil.which("cursor-agent") or shutil.which("cursor")
|
|
151
161
|
if cursor is None:
|
|
152
162
|
findings.append((_WARN, "cursor binary", "not on PATH; install Cursor CLI/editor to use the adapter"))
|
|
@@ -155,6 +165,73 @@ def _check_cursor_adapter() -> list[tuple[str, str, str]]:
|
|
|
155
165
|
return findings
|
|
156
166
|
|
|
157
167
|
|
|
168
|
+
def _extract_codex_mcp_command(config_text: str) -> str | None:
|
|
169
|
+
"""Read the ``command`` value from the ``[mcp_servers.c3]`` table.
|
|
170
|
+
|
|
171
|
+
Uses a targeted regex rather than a full TOML parser: ``tomllib`` is only
|
|
172
|
+
available from Python 3.11 while C3 supports 3.10+, and the generated
|
|
173
|
+
config is always a single-line ``key = "value"`` pair under the section.
|
|
174
|
+
"""
|
|
175
|
+
match = re.search(
|
|
176
|
+
r'(?ms)^\[mcp_servers\.c3\]\s*$.*?^command\s*=\s*"((?:[^"\\]|\\.)*)"',
|
|
177
|
+
config_text,
|
|
178
|
+
)
|
|
179
|
+
if match is None:
|
|
180
|
+
return None
|
|
181
|
+
return match.group(1).replace('\\"', '"').replace("\\\\", "\\")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _extract_cursor_mcp_command(mcp_json_text: str) -> str | None:
|
|
185
|
+
try:
|
|
186
|
+
payload = json.loads(mcp_json_text)
|
|
187
|
+
except json.JSONDecodeError:
|
|
188
|
+
return None
|
|
189
|
+
if not isinstance(payload, dict):
|
|
190
|
+
return None
|
|
191
|
+
servers = payload.get("mcpServers")
|
|
192
|
+
if not isinstance(servers, dict):
|
|
193
|
+
return None
|
|
194
|
+
c3 = servers.get("c3")
|
|
195
|
+
if not isinstance(c3, dict):
|
|
196
|
+
return None
|
|
197
|
+
command = c3.get("command")
|
|
198
|
+
return command if isinstance(command, str) else None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _check_mcp_command_startup(
|
|
202
|
+
label: str, command: str | None, platform: str
|
|
203
|
+
) -> tuple[str, str, str]:
|
|
204
|
+
"""Verify that the generated MCP ``command`` can actually launch and import c3."""
|
|
205
|
+
hint = f"run `c3 update --platform {platform}` to regenerate"
|
|
206
|
+
if not command:
|
|
207
|
+
return _WARN, label, f"command not found in generated config; {hint}"
|
|
208
|
+
|
|
209
|
+
resolvable = (Path(command).is_absolute() and Path(command).is_file()) or (
|
|
210
|
+
shutil.which(command) is not None
|
|
211
|
+
)
|
|
212
|
+
if not resolvable:
|
|
213
|
+
return _WARN, label, f"command not executable: {command}; {hint}"
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
result = subprocess.run(
|
|
217
|
+
[command, "-c", "import c3"],
|
|
218
|
+
capture_output=True,
|
|
219
|
+
text=True,
|
|
220
|
+
timeout=_MCP_STARTUP_TIMEOUT_SEC,
|
|
221
|
+
)
|
|
222
|
+
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
223
|
+
return _WARN, label, f"failed to launch {command}: {exc}; {hint}"
|
|
224
|
+
|
|
225
|
+
if result.returncode != 0:
|
|
226
|
+
detail = next(
|
|
227
|
+
(line for line in reversed(result.stderr.strip().splitlines()) if line.strip()),
|
|
228
|
+
"import c3 failed",
|
|
229
|
+
)
|
|
230
|
+
return _WARN, label, f'`{command} -c "import c3"` failed: {detail}; {hint}'
|
|
231
|
+
|
|
232
|
+
return _OK, label, f"{command} -c \"import c3\" succeeded"
|
|
233
|
+
|
|
234
|
+
|
|
158
235
|
def _file_or_warn(label: str, path: Path, hint: str) -> tuple[str, str, str]:
|
|
159
236
|
if path.is_file():
|
|
160
237
|
return _OK, label, str(path)
|
|
@@ -58,6 +58,48 @@ def test_toml_multiline_escape_keeps_newlines():
|
|
|
58
58
|
assert _toml_multiline_escape(text) == text
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
# ----------------------------------------------------------------------
|
|
62
|
+
# MCP `command` resolution — absolute sys.executable, not bare "python"
|
|
63
|
+
# ----------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_codex_config_section_uses_absolute_sys_executable(monkeypatch):
|
|
67
|
+
monkeypatch.setattr(adapters.sys, "executable", r"C:\Python312\python.exe")
|
|
68
|
+
|
|
69
|
+
section = adapters._codex_config_section()
|
|
70
|
+
|
|
71
|
+
assert 'command = "C:\\\\Python312\\\\python.exe"' in section
|
|
72
|
+
assert 'command = "python"' not in section
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_codex_config_section_escapes_plain_posix_executable(monkeypatch):
|
|
76
|
+
monkeypatch.setattr(adapters.sys, "executable", "/usr/bin/python3")
|
|
77
|
+
|
|
78
|
+
section = adapters._codex_config_section()
|
|
79
|
+
|
|
80
|
+
assert 'command = "/usr/bin/python3"' in section
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_write_codex_config_writes_absolute_windows_command(tmp_path: Path, monkeypatch):
|
|
84
|
+
monkeypatch.setattr(adapters.sys, "executable", r"C:\Users\dev\venv\Scripts\python.exe")
|
|
85
|
+
|
|
86
|
+
adapters._write_codex_config(tmp_path, dry_run=False)
|
|
87
|
+
|
|
88
|
+
config_text = (tmp_path / ".codex" / "config.toml").read_text(encoding="utf-8")
|
|
89
|
+
assert 'command = "C:\\\\Users\\\\dev\\\\venv\\\\Scripts\\\\python.exe"' in config_text
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_write_cursor_mcp_uses_absolute_sys_executable(tmp_path: Path, monkeypatch):
|
|
93
|
+
monkeypatch.setattr(adapters.sys, "executable", r"C:\Python312\python.exe")
|
|
94
|
+
|
|
95
|
+
adapters._write_cursor_mcp(tmp_path, dry_run=False)
|
|
96
|
+
|
|
97
|
+
payload = json.loads((tmp_path / ".cursor" / "mcp.json").read_text(encoding="utf-8"))
|
|
98
|
+
command = payload["mcpServers"]["c3"]["command"]
|
|
99
|
+
assert command == r"C:\Python312\python.exe"
|
|
100
|
+
assert Path(command).is_absolute()
|
|
101
|
+
|
|
102
|
+
|
|
61
103
|
# ----------------------------------------------------------------------
|
|
62
104
|
# _convert_skill
|
|
63
105
|
# ----------------------------------------------------------------------
|
|
@@ -178,7 +220,8 @@ def test_write_cursor_mcp_creates_file_when_missing(tmp_path: Path):
|
|
|
178
220
|
actions = _write_cursor_mcp(target, dry_run=False)
|
|
179
221
|
assert any(a.action == "add" for a in actions)
|
|
180
222
|
payload = json.loads((target / ".cursor" / "mcp.json").read_text(encoding="utf-8"))
|
|
181
|
-
assert payload["mcpServers"]["c3"]["command"] ==
|
|
223
|
+
assert payload["mcpServers"]["c3"]["command"] == sys.executable
|
|
224
|
+
assert Path(payload["mcpServers"]["c3"]["command"]).is_absolute()
|
|
182
225
|
|
|
183
226
|
|
|
184
227
|
def test_write_cursor_mcp_rejects_invalid_json(tmp_path: Path):
|
|
@@ -7,6 +7,8 @@ in handle() for opencode, codex, and cursor platforms.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import argparse
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
10
12
|
from pathlib import Path
|
|
11
13
|
|
|
12
14
|
import c3.cli_doctor as cli_doctor
|
|
@@ -181,3 +183,169 @@ def test_check_opencode_adapter_reports_binary_present(tmp_path: Path, monkeypat
|
|
|
181
183
|
status == _OK and "opencode binary" in label and fake_path in detail
|
|
182
184
|
for status, label, detail in findings
|
|
183
185
|
), f"Expected OK for 'opencode binary' with path, got: {findings}"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
# MCP startup self-diagnostic — _check_mcp_command_startup
|
|
190
|
+
# ---------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_check_mcp_command_startup_ok_when_import_succeeds(monkeypatch):
|
|
194
|
+
"""When the resolved command can `import c3`, the check must return OK."""
|
|
195
|
+
monkeypatch.setattr(
|
|
196
|
+
cli_doctor.subprocess,
|
|
197
|
+
"run",
|
|
198
|
+
lambda *a, **k: subprocess.CompletedProcess(a[0], 0, stdout="", stderr=""),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
status, label, detail = cli_doctor._check_mcp_command_startup(
|
|
202
|
+
"codex MCP startup", sys.executable, "codex"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
assert status == _OK
|
|
206
|
+
assert "codex MCP startup" == label
|
|
207
|
+
assert "import c3" in detail
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_check_mcp_command_startup_warns_when_command_missing():
|
|
211
|
+
"""When the config has no `command` value at all, the check must WARN."""
|
|
212
|
+
status, label, detail = cli_doctor._check_mcp_command_startup(
|
|
213
|
+
"codex MCP startup", None, "codex"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
assert status == _WARN
|
|
217
|
+
assert "not found" in detail
|
|
218
|
+
assert "c3 update --platform codex" in detail
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_check_mcp_command_startup_warns_when_command_not_resolvable(monkeypatch):
|
|
222
|
+
"""When the command path/binary cannot be located at all, the check must WARN
|
|
223
|
+
without attempting to spawn a subprocess."""
|
|
224
|
+
monkeypatch.setattr(cli_doctor.shutil, "which", lambda name: None)
|
|
225
|
+
called = []
|
|
226
|
+
monkeypatch.setattr(
|
|
227
|
+
cli_doctor.subprocess,
|
|
228
|
+
"run",
|
|
229
|
+
lambda *a, **k: called.append(a) or subprocess.CompletedProcess(a[0], 0),
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
status, label, detail = cli_doctor._check_mcp_command_startup(
|
|
233
|
+
"cursor MCP startup", "/nonexistent/path/to/python", "cursor"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
assert status == _WARN
|
|
237
|
+
assert "not executable" in detail
|
|
238
|
+
assert "c3 update --platform cursor" in detail
|
|
239
|
+
assert called == []
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_check_mcp_command_startup_warns_when_import_c3_fails(monkeypatch):
|
|
243
|
+
"""When the resolved command runs but `import c3` fails (e.g. an isolated
|
|
244
|
+
venv/pipx environment without c3 installed), the check must WARN."""
|
|
245
|
+
monkeypatch.setattr(
|
|
246
|
+
cli_doctor.subprocess,
|
|
247
|
+
"run",
|
|
248
|
+
lambda *a, **k: subprocess.CompletedProcess(
|
|
249
|
+
a[0], 1, stdout="", stderr="ModuleNotFoundError: No module named 'c3'"
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
status, label, detail = cli_doctor._check_mcp_command_startup(
|
|
254
|
+
"codex MCP startup", sys.executable, "codex"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
assert status == _WARN
|
|
258
|
+
assert "No module named" in detail
|
|
259
|
+
assert "c3 update --platform codex" in detail
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_check_mcp_command_startup_warns_when_launch_raises(monkeypatch):
|
|
263
|
+
"""When subprocess.run itself raises (e.g. the binary vanished between the
|
|
264
|
+
resolvability check and the launch), the check must WARN, not raise."""
|
|
265
|
+
def _boom(*a, **k):
|
|
266
|
+
raise FileNotFoundError("no such file")
|
|
267
|
+
|
|
268
|
+
monkeypatch.setattr(cli_doctor.subprocess, "run", _boom)
|
|
269
|
+
|
|
270
|
+
status, label, detail = cli_doctor._check_mcp_command_startup(
|
|
271
|
+
"codex MCP startup", sys.executable, "codex"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
assert status == _WARN
|
|
275
|
+
assert "failed to launch" in detail
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# ---------------------------------------------------------------------------
|
|
279
|
+
# command extraction from generated adapter configs
|
|
280
|
+
# ---------------------------------------------------------------------------
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def test_extract_codex_mcp_command_reads_absolute_windows_path():
|
|
284
|
+
config_text = (
|
|
285
|
+
"[mcp_servers.c3]\n"
|
|
286
|
+
'command = "C:\\\\Python312\\\\python.exe"\n'
|
|
287
|
+
'args = ["-m", "c3.mcp_server"]\n'
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
command = cli_doctor._extract_codex_mcp_command(config_text)
|
|
291
|
+
|
|
292
|
+
assert command == r"C:\Python312\python.exe"
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def test_extract_codex_mcp_command_none_when_section_missing():
|
|
296
|
+
assert cli_doctor._extract_codex_mcp_command("[some_other_table]\nfoo = 1\n") is None
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def test_extract_cursor_mcp_command_reads_absolute_path():
|
|
300
|
+
mcp_json = '{"mcpServers": {"c3": {"command": "/usr/bin/python3", "args": []}}}'
|
|
301
|
+
|
|
302
|
+
command = cli_doctor._extract_cursor_mcp_command(mcp_json)
|
|
303
|
+
|
|
304
|
+
assert command == "/usr/bin/python3"
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def test_extract_cursor_mcp_command_none_when_invalid_json():
|
|
308
|
+
assert cli_doctor._extract_cursor_mcp_command("{not valid") is None
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# ---------------------------------------------------------------------------
|
|
312
|
+
# integration — _check_codex_adapter / _check_cursor_adapter wire the
|
|
313
|
+
# self-diagnostic in using the real, currently-running interpreter
|
|
314
|
+
# ---------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def test_check_codex_adapter_includes_ok_mcp_startup_with_real_interpreter(
|
|
318
|
+
tmp_path: Path, monkeypatch
|
|
319
|
+
):
|
|
320
|
+
"""End-to-end: generate a real adapter config pointed at sys.executable
|
|
321
|
+
(which does have c3 importable under the sandbox PYTHONPATH) and confirm
|
|
322
|
+
the doctor wires the self-diagnostic in as OK."""
|
|
323
|
+
(tmp_path / ".claude").mkdir()
|
|
324
|
+
monkeypatch.chdir(tmp_path)
|
|
325
|
+
from c3.adapters import _write_codex_config
|
|
326
|
+
|
|
327
|
+
_write_codex_config(tmp_path, dry_run=False)
|
|
328
|
+
|
|
329
|
+
findings = cli_doctor._check_codex_adapter()
|
|
330
|
+
|
|
331
|
+
assert any(
|
|
332
|
+
status == _OK and label == "codex MCP startup"
|
|
333
|
+
for status, label, _ in findings
|
|
334
|
+
), f"Expected OK codex MCP startup finding, got: {findings}"
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def test_check_cursor_adapter_includes_ok_mcp_startup_with_real_interpreter(
|
|
338
|
+
tmp_path: Path, monkeypatch
|
|
339
|
+
):
|
|
340
|
+
(tmp_path / ".claude").mkdir()
|
|
341
|
+
monkeypatch.chdir(tmp_path)
|
|
342
|
+
from c3.adapters import _write_cursor_mcp
|
|
343
|
+
|
|
344
|
+
_write_cursor_mcp(tmp_path, dry_run=False)
|
|
345
|
+
|
|
346
|
+
findings = cli_doctor._check_cursor_adapter()
|
|
347
|
+
|
|
348
|
+
assert any(
|
|
349
|
+
status == _OK and label == "cursor MCP startup"
|
|
350
|
+
for status, label, _ in findings
|
|
351
|
+
), f"Expected OK cursor MCP startup finding, got: {findings}"
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/code-reviewer.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/design-critic.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/project-setup.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/security-reviewer.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/systematic-debugger.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/agents/wt_developer.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/docs/parallel-agents-setup.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/consolidate_memory.py
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/permission_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/planner_check.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/recall_autorebuild.py
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/recall_inject.py
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/restore_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/session_start.py
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/session_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/tier_autoapply.py
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/tier_gap_check.py
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/hooks/worktree_guard.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/rules/promoted/index.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/brainstorm/SKILL.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/codex-review/SKILL.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/dev-workflow/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/develop/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/extract-lib/SKILL.md
RENAMED
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/init-session/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/mcp-config/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/pattern-status/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/recall/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/review-phase/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{claude_code_conductor-2.49.0 → claude_code_conductor-2.50.0}/.claude/skills/setup/reference.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|