claude-code-conductor 2.38.0__tar.gz → 2.40.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.38.0 → claude_code_conductor-2.40.0}/.claude/settings.json +1 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/init-session/SKILL.md +4 -11
- claude_code_conductor-2.40.0/.claude/skills/init-session/scripts/session_guard.py +163 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/setup/SKILL.md +3 -1
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/start/SKILL.md +1 -7
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/CHANGELOG.md +31 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/PKG-INFO +1 -1
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/__init__.py +1 -1
- claude_code_conductor-2.40.0/src/c3/cli_init.py +204 -0
- claude_code_conductor-2.40.0/src/c3/gitutil.py +71 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/_skill_helpers.py +6 -0
- claude_code_conductor-2.40.0/tests/skills/test_session_guard.py +574 -0
- claude_code_conductor-2.40.0/tests/test_cli_init.py +468 -0
- claude_code_conductor-2.40.0/tests/test_gitutil.py +242 -0
- claude_code_conductor-2.38.0/src/c3/cli_init.py +0 -108
- claude_code_conductor-2.38.0/tests/test_cli_init.py +0 -204
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/design-critic.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/agents/wt_tester.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/breaking-changes.txt +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/deletions.txt +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/docs/config-policy.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/docs/platform-adapters.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/_hook_utils.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/permission_handler.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/permission_handler_toast.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/recall_autorebuild.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/permission_rules.json +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/brainstorm/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/codex-review/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/scripts/record_tier_outcome.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.gitignore +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/ARCHITECTURE.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSES/numpy-LICENSE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/README.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/hatch_build.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/pyproject.toml +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/_db_params.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/adapters.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_ask.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/db.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrate.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrations/001_initial.sql +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrations/003_tier_cost.sql +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrations/README.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/migrations/__init__.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/pricing.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/question.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/src/c3/usage_ingester.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/__init__.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/conftest.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/fixtures/usage/README.md +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/fixtures/usage/mainline.jsonl +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_hook_utils.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_permission_handler.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_permission_handler_toast.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_recall_autorebuild.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_record_tier_outcome.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_init_session_no_task_type.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_start_skill_new_flow.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_adapters.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_check_deletions.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_ask.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_doctor.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_update_breaking_changes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_cli_update_deletions.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_db.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_extract_breaking_changes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_migrate.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_pricing.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_usage_ingester.py +0 -0
- {claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/test_worktree_guard.py +0 -0
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"Bash(python .claude/skills/dev-workflow/scripts/review_hint_inject.py*)",
|
|
12
12
|
"Bash(python .claude/skills/dev-workflow/scripts/record_review_decision.py*)",
|
|
13
13
|
"Bash(python .claude/skills/dev-workflow/scripts/record_tier_outcome.py*)",
|
|
14
|
+
"Bash(python .claude/skills/init-session/scripts/session_guard.py*)",
|
|
14
15
|
"Read(**)",
|
|
15
16
|
"Glob(**)",
|
|
16
17
|
"Grep(**)",
|
{claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/.claude/skills/init-session/SKILL.md
RENAMED
|
@@ -20,21 +20,12 @@ description: セッション開始時に前回の作業状態・残タスク・
|
|
|
20
20
|
`/start` からの再帰呼び出しを防ぐため、**最初に**現在のセッション ID を実行マーカーへ記録する:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
|
|
24
|
-
printf '%s' "$CLAUDE_CODE_SESSION_ID" > .claude/state/init_session.flag
|
|
23
|
+
python .claude/skills/init-session/scripts/session_guard.py mark
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
### G-2: setup 未実行なら /setup を自動実行
|
|
28
27
|
|
|
29
|
-
プロジェクトのコーディング規約が未設定なら、`/setup` を先に実行する。
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
if [ -f .claude/rules/coding-standards.md ] || [ -f .claude/state/setup_done.flag ]; then
|
|
33
|
-
echo "SETUP_DONE"
|
|
34
|
-
else
|
|
35
|
-
echo "SETUP_NEEDED"
|
|
36
|
-
fi
|
|
37
|
-
```
|
|
28
|
+
プロジェクトのコーディング規約が未設定なら、`/setup` を先に実行する。G-1 の `mark` が併せて出力する `SETUP_DONE` / `SETUP_NEEDED` で判定:
|
|
38
29
|
|
|
39
30
|
> 順序について: setup ガード(G-2)は Step 1(前回セッション復元)より前に置く。`SETUP_NEEDED` となるのは規約未設定=実質的に初回導入のケースであり、その場合 Step 1 で復元すべき前回セッションは通常存在しない(復元はほぼ no-op)ため、setup を先行させてもコンテキストへの実害はない。
|
|
40
31
|
|
|
@@ -42,6 +33,8 @@ fi
|
|
|
42
33
|
- **`SETUP_NEEDED`** → Skill ツールで `setup` を自動的に呼ぶ。ここでの「自動」は**ユーザーが `/setup` を打つ必要なく連鎖起動される**という意味で、`setup` 自体は言語・規約のヒアリング(AskUserQuestion 群)を行うため**ユーザー応答は必要**(規約設定をスキップ・無人実行する意味ではない)。`setup` 完了後(`coding-standards.md` と `setup_done.flag` が生成される)に Step 1 へ進む。
|
|
43
34
|
- ユーザーが `setup` のヒアリングを中断した場合、`coding-standards.md`・`setup_done.flag` のいずれも未生成なら次回の `/init-session`・`/start` で再度 `setup` が起動される(再試行可能)。
|
|
44
35
|
|
|
36
|
+
> `mark` が exit 0 以外で終了した(stdout が空で SETUP_DONE/SETUP_NEEDED いずれでもない)場合は、ディスクフル・権限エラー等の可能性がある。その場合は `SETUP_NEEDED` と同様に扱い(= `/setup` を起動するかエラーを確認してからセッションを続ける)、安全側に倒す。
|
|
37
|
+
|
|
45
38
|
### G-3: from-start 引数の扱い
|
|
46
39
|
|
|
47
40
|
本スキルが **`from-start` 引数付き**で呼ばれた場合(`/start` のセッション初期化ガード経由)は、本ガード(G-1/G-2)と Step 1〜3(前回状態の復元・サマリ表示)まで実行したら、**以下の対話プロンプトを全てスキップ**して本スキルを終了する(Skill 実行が完了すれば呼び出し元の `/start` が Step 0 以降を続行する):
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Session-start guard helper for /init-session and /start.
|
|
3
|
+
|
|
4
|
+
3 つのセッション開始 Bash ブロック(mkdir+printf / setup 判定 / init 判定)を
|
|
5
|
+
1 つの Python エントリに集約し、settings.json の allow を 1 行プレフィックスで
|
|
6
|
+
登録できるようにする(複合 Bash は allow プレフィックス一致が効かないため)。
|
|
7
|
+
|
|
8
|
+
挙動は旧 Bash と等価に保つ:
|
|
9
|
+
- mark : .claude/state を作り init_session.flag に session id を書き、
|
|
10
|
+
coding-standards.md / setup_done.flag の有無で SETUP_DONE/SETUP_NEEDED を print
|
|
11
|
+
- check : init_session.flag を読み strip して CLAUDE_CODE_SESSION_ID と比較し
|
|
12
|
+
INIT_DONE/INIT_NEEDED を print
|
|
13
|
+
- setup-mark: setup_done.flag を書く(/setup Phase 4 用・判定 print なし)
|
|
14
|
+
|
|
15
|
+
Exit code:
|
|
16
|
+
0: 正常(mark/check の判定結果は stdout で返す。判定自体は exit code で表さない)
|
|
17
|
+
2: 未知 / 欠落サブコマンド(usage を stderr に出す)
|
|
18
|
+
|
|
19
|
+
セキュリティ境界:
|
|
20
|
+
init_session.flag に書く CLAUDE_CODE_SESSION_ID は認証トークンではなくセッション識別子であり、
|
|
21
|
+
ループ回避判定にのみ使用する。.claude/state/ は gitignore+配布除外済みで git/wheel に含まれない
|
|
22
|
+
(信頼境界の確認)。
|
|
23
|
+
|
|
24
|
+
allow のスコープ:
|
|
25
|
+
settings.json の allow エントリは末尾 * のプレフィックス一致。
|
|
26
|
+
追加引数は main() で無視される(多層防御: pre_tool hook も Bash を事前検査)。
|
|
27
|
+
"""
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import os
|
|
31
|
+
import pathlib
|
|
32
|
+
import sys
|
|
33
|
+
|
|
34
|
+
if sys.stdout and hasattr(sys.stdout, "reconfigure"):
|
|
35
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
36
|
+
if sys.stderr and hasattr(sys.stderr, "reconfigure"):
|
|
37
|
+
sys.stderr.reconfigure(encoding="utf-8")
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# パス定数
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
FLAG_REL = (".claude", "state", "init_session.flag")
|
|
44
|
+
STATE_DIR_REL = (".claude", "state")
|
|
45
|
+
# setup_done.flag のパスは cmd_mark の SETUP 判定(SETUP_MARKERS_REL 経由)と
|
|
46
|
+
# cmd_setup_mark の書き込み(SETUP_DONE_FLAG_REL)で共通参照する単一真実源(CR-M-001)。
|
|
47
|
+
SETUP_DONE_FLAG_REL = (".claude", "state", "setup_done.flag")
|
|
48
|
+
SETUP_MARKERS_REL = (
|
|
49
|
+
(".claude", "rules", "coding-standards.md"),
|
|
50
|
+
SETUP_DONE_FLAG_REL, # SETUP_DONE_FLAG_REL を参照して DRY を維持(同一オブジェクト)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
USAGE = "usage: session_guard.py {mark|check|setup-mark}"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------------------
|
|
57
|
+
# パス解決
|
|
58
|
+
# ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
def _project_root() -> str:
|
|
61
|
+
"""CLAUDE_PROJECT_DIR があればそれ、無ければ cwd。resolve() で `..` を展開し絶対パスを保証する(SR M-1・recall_inject.py と整合)。
|
|
62
|
+
|
|
63
|
+
CLAUDE_PROJECT_DIR はハーネス信頼値・パス構成要素はハードコードのため実害は薄いが、
|
|
64
|
+
整合性・防御として resolve() を適用する。
|
|
65
|
+
"""
|
|
66
|
+
root = os.environ.get("CLAUDE_PROJECT_DIR")
|
|
67
|
+
if root:
|
|
68
|
+
return str(pathlib.Path(root).resolve())
|
|
69
|
+
return str(pathlib.Path.cwd().resolve())
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# mark サブコマンド
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
def cmd_mark() -> int:
|
|
77
|
+
root = _project_root()
|
|
78
|
+
# 1. state ディレクトリ作成(存在しても失敗しない)
|
|
79
|
+
state_dir = os.path.join(root, *STATE_DIR_REL)
|
|
80
|
+
os.makedirs(state_dir, exist_ok=True)
|
|
81
|
+
# 2. flag 書き込み(session id が空でもそのまま空文字を書く=旧 printf '%s' 等価)
|
|
82
|
+
sid = os.environ.get("CLAUDE_CODE_SESSION_ID", "")
|
|
83
|
+
flag_path = os.path.join(root, *FLAG_REL)
|
|
84
|
+
with open(flag_path, "w", encoding="utf-8", newline="") as f:
|
|
85
|
+
f.write(sid)
|
|
86
|
+
# 3. SETUP 判定 print
|
|
87
|
+
if any(os.path.isfile(os.path.join(root, *m)) for m in SETUP_MARKERS_REL):
|
|
88
|
+
print("SETUP_DONE")
|
|
89
|
+
else:
|
|
90
|
+
print("SETUP_NEEDED")
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# check サブコマンド
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
def _read_flag(root: str) -> str:
|
|
99
|
+
"""flag を読み、CR/LF と前後空白を除去して返す。読めなければ空文字。"""
|
|
100
|
+
flag_path = os.path.join(root, *FLAG_REL)
|
|
101
|
+
try:
|
|
102
|
+
with open(flag_path, "r", encoding="utf-8") as f:
|
|
103
|
+
raw = f.read()
|
|
104
|
+
except (OSError, ValueError):
|
|
105
|
+
# OSError: ファイル不在・権限エラー
|
|
106
|
+
# ValueError: UnicodeDecodeError(ValueError サブクラス)を含む。flag が UTF-8 非互換でも INIT_NEEDED 安全側に倒す
|
|
107
|
+
return ""
|
|
108
|
+
# 旧 bash: tr -d '\r\n'(全 CR/LF を除去)+ strip
|
|
109
|
+
# replace 順は CRLF/CR/LF を確実に除去する(\r 先行で CRLF の \r を確実に消す)。逆順でも結果は同じだが意図を明示
|
|
110
|
+
return raw.replace("\r", "").replace("\n", "").strip()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def cmd_check() -> int:
|
|
114
|
+
root = _project_root()
|
|
115
|
+
sid = os.environ.get("CLAUDE_CODE_SESSION_ID", "")
|
|
116
|
+
saved = _read_flag(root)
|
|
117
|
+
if sid and saved == sid: # 旧 bash: [ -n "$SID" ] && [ "$saved" = "$SID" ](sid 空なら比較せず INIT_NEEDED に倒す)
|
|
118
|
+
print("INIT_DONE")
|
|
119
|
+
else:
|
|
120
|
+
print("INIT_NEEDED")
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
# setup-mark サブコマンド
|
|
126
|
+
# ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
def cmd_setup_mark() -> int:
|
|
129
|
+
"""/setup Phase 4 用: setup_done.flag を書く(存在自体がマーカー・中身不要)。
|
|
130
|
+
判定 print はしない(mark/check と異なり stdout で分岐させない)。
|
|
131
|
+
書き込み例外は握り潰さず上げる(ADR-4 と整合)。
|
|
132
|
+
"""
|
|
133
|
+
root = _project_root()
|
|
134
|
+
state_dir = os.path.join(root, *STATE_DIR_REL)
|
|
135
|
+
os.makedirs(state_dir, exist_ok=True)
|
|
136
|
+
flag_path = os.path.join(root, *SETUP_DONE_FLAG_REL)
|
|
137
|
+
with open(flag_path, "w", encoding="utf-8") as f:
|
|
138
|
+
pass # 空ファイルで可(存在自体がマーカー)
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# ---------------------------------------------------------------------------
|
|
143
|
+
# ディスパッチ(main)
|
|
144
|
+
# ---------------------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
def main(argv: list[str] | None = None) -> int:
|
|
147
|
+
args = sys.argv[1:] if argv is None else argv
|
|
148
|
+
if not args:
|
|
149
|
+
print(USAGE, file=sys.stderr)
|
|
150
|
+
return 2
|
|
151
|
+
cmd = args[0]
|
|
152
|
+
if cmd == "mark":
|
|
153
|
+
return cmd_mark()
|
|
154
|
+
if cmd == "check":
|
|
155
|
+
return cmd_check()
|
|
156
|
+
if cmd == "setup-mark":
|
|
157
|
+
return cmd_setup_mark()
|
|
158
|
+
print(f"{USAGE}\nunknown subcommand: {cmd!r}", file=sys.stderr)
|
|
159
|
+
return 2
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
sys.exit(main())
|
|
@@ -216,9 +216,11 @@ project-setup エージェントが 2 ファイルを生成したら、Bash で
|
|
|
216
216
|
このフラグは**存在自体がマーカー**であり中身は不要(空ファイルで可):
|
|
217
217
|
|
|
218
218
|
```bash
|
|
219
|
-
|
|
219
|
+
python .claude/skills/init-session/scripts/session_guard.py setup-mark
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
+
書き込みが失敗した場合は session_guard.py が例外で停止する(握り潰さない・ADR-4 整合)。フラグ未書き込みなら次回 `/init-session` 実行時に G-2 が SETUP_NEEDED を返し `/setup` が再起動されるためリカバリ可能。
|
|
223
|
+
|
|
222
224
|
その後、以下を報告する:
|
|
223
225
|
|
|
224
226
|
```
|
|
@@ -21,13 +21,7 @@ description: 開発ワークフローの入口。開始地点(標準ワーク
|
|
|
21
21
|
Bash で判定する:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
|
|
25
|
-
saved="$(tr -d '\r\n' < "$flag" 2>/dev/null)"
|
|
26
|
-
if [ -n "$CLAUDE_CODE_SESSION_ID" ] && [ "$saved" = "$CLAUDE_CODE_SESSION_ID" ]; then
|
|
27
|
-
echo "INIT_DONE"
|
|
28
|
-
else
|
|
29
|
-
echo "INIT_NEEDED"
|
|
30
|
-
fi
|
|
24
|
+
python .claude/skills/init-session/scripts/session_guard.py check
|
|
31
25
|
```
|
|
32
26
|
|
|
33
27
|
- **`INIT_DONE`**(フラグの中身が現在の `CLAUDE_CODE_SESSION_ID` と一致)→ 既に初期化済み。そのまま Step 0 へ進む。
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.40.0] - 2026-06-30
|
|
4
|
+
|
|
5
|
+
### 追加
|
|
6
|
+
|
|
7
|
+
- **`c3 init` が非 git ディレクトリで同意の上 `git init` を実行**: C3 の並列実装(parallel-agents skill)は `isolation: "worktree"` で git worktree を使うため、対象ディレクトリが git リポジトリでないと実装フェーズで worktree 生成時に初めてハードエラーになっていた(失敗が実装まで遅延する UX 欠陥)。`c3 init` の時点で git 不在を検出し、**同意ベースで** `git init` まで済ませることで後の worktree 失敗を未然に防ぐ。C3 の核「`.claude/` に閉じる可逆性」を尊重し、黙って `.git/` を作る驚きは避ける設計。
|
|
8
|
+
- **検出**: `git rev-parse --is-inside-work-tree` で判定。既に git 管理下(親が repo のサブディレクトリを含む)なら何もしない(入れ子 repo を作らない)。
|
|
9
|
+
- **同意モデル**(非 git の場合のみ): `--no-git` → init せず誘導メッセージのみ / `--git` → 確認なしで `git init`(CI・非対話の明示 opt-in)/ どちらも無し → TTY なら `[Y/n]` 確認・非 TTY なら `input()` を呼ばず警告のみ(黙って `.git/` を作らない・ハング回避)。
|
|
10
|
+
- **失敗時**: git コマンド不在・`git init` 失敗・タイムアウトのいずれも警告に倒し、`.claude/` の scaffold は成功扱い(`c3 init` の exit code に影響させない)。
|
|
11
|
+
- 新規 `src/c3/gitutil.py`(`GitStatus` Enum・`detect_git_status()` / `git_init()`、subprocess を `shell=False`・固定引数リスト・`timeout=10`・`encoding="utf-8"` で実行)に git プリミティブを分離し、UI 層(`cli_init.py`)と責務分離。
|
|
12
|
+
|
|
13
|
+
### 後方互換
|
|
14
|
+
|
|
15
|
+
- 既存の `c3 init`(git 管理下・`--target`・`--platform` 等)の挙動は不変。新フラグ `--git`/`--no-git` は opt-in。非 TTY(Claude Code の Bash ツール経由・CI)では従来どおり `.claude/` scaffold のみ行い git には触れない。公開 API・CLI 既存オプション・DB スキーマに変更なし。**破壊的変更なし**。
|
|
16
|
+
|
|
17
|
+
## [2.39.0] - 2026-06-24
|
|
18
|
+
|
|
19
|
+
### 改善
|
|
20
|
+
|
|
21
|
+
- **セッション開始・setup 完了の全 Bash ブロックを `session_guard.py` に集約し、Bash 許可ダイアログを恒久解消**: `/init-session`・`/start`・`/setup` の各スキルで実行していた `mkdir`+`printf` でのフラグ書き込み・`setup` 実行済み判定・`init-session` 実行済み判定を**複合 Bash(`if`/`$()`/リダイレクトを含む 3 ブロック)**として実行しており、セッション開始時・`/setup` 完了時に Bash 許可ダイアログが出ていた。複合 Bash は `settings.json` の allow プレフィックス一致が効かない(`if`/`$()`/リダイレクトは静的解析不可)ため、許可を事前登録できなかった。全ブロックを単一の Python エントリ `.claude/skills/init-session/scripts/session_guard.py {mark|check|setup-mark}` に集約し、`settings.json` に `Bash(python .claude/skills/init-session/scripts/session_guard.py*)` の 1 行 allow を追加することでダイアログを恒久的に解消した。
|
|
22
|
+
|
|
23
|
+
### 仕組み
|
|
24
|
+
|
|
25
|
+
- **`session_guard.py mark`**(`/init-session` が起動直後に実行): `.claude/state/` を作成し `init_session.flag` に `CLAUDE_CODE_SESSION_ID` を書き込み、`coding-standards.md` または `setup_done.flag` の有無で `SETUP_DONE` / `SETUP_NEEDED` を stdout に出力する。
|
|
26
|
+
- **`session_guard.py check`**(`/start` のガードが実行): `init_session.flag` を読み(CR/LF 除去+strip)、`CLAUDE_CODE_SESSION_ID` と一致すれば `INIT_DONE`、不一致・未書き込みなら `INIT_NEEDED` を出力する。
|
|
27
|
+
- **`session_guard.py setup-mark`**(`/setup` の Phase 4 完了時に実行): `setup_done.flag` を `.claude/state/` に書き込む。これにより `/setup` 完了フラグの書き込みも Python スクリプト経由に統一され、`/setup` 初回実行時の Bash 許可ダイアログも解消した。
|
|
28
|
+
- 挙動は旧 Bash と等価(フラグ書き込み・判定結果・出力文字列が一致)。冒頭で stdout/stderr を UTF-8 へ reconfigure(CLAUDE.md §9 準拠)。
|
|
29
|
+
|
|
30
|
+
### 後方互換
|
|
31
|
+
|
|
32
|
+
- スキルの利用方法・フラグの配置(`.claude/state/`・gitignore+配布除外済み)・判定ロジックに変更なし。サブコマンドが `{mark|check}` → `{mark|check|setup-mark}` の 3 種に増えたが、既存呼び出しは影響なし。公開 API・CLI・DB スキーマに変更なし。**破壊的変更なし**。
|
|
33
|
+
|
|
3
34
|
## [2.38.0] - 2026-06-16
|
|
4
35
|
|
|
5
36
|
### 追加
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: claude-code-conductor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.40.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
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""``c3 init`` - scaffold ``.claude/`` into the current project."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from c3 import gitutil
|
|
12
|
+
from c3._excludes import should_skip
|
|
13
|
+
from c3.adapters import print_adapter_actions, scaffold_adapters
|
|
14
|
+
from c3.paths import templates_dir
|
|
15
|
+
from c3.platforms import PLATFORM_CHOICES, expand_platforms
|
|
16
|
+
|
|
17
|
+
# 非 git ディレクトリで git 操作を行わない・行えないときに表示するガイダンス文言。
|
|
18
|
+
# 複数の分岐(--no-git / 非 TTY / ユーザー拒否 / input 例外)で共通。
|
|
19
|
+
_MSG_WORKTREE_HINT = (
|
|
20
|
+
"worktree を使う場合は git init してください(または c3 init --git)。"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
25
|
+
parser = subparsers.add_parser(
|
|
26
|
+
"init",
|
|
27
|
+
help="Scaffold a fresh .claude/ directory into the current project",
|
|
28
|
+
description=(
|
|
29
|
+
"Copy the bundled C3 .claude/ template into the current working "
|
|
30
|
+
"directory. Refuses to overwrite an existing .claude/ unless "
|
|
31
|
+
"--force is given."
|
|
32
|
+
),
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--force",
|
|
36
|
+
action="store_true",
|
|
37
|
+
help="Overwrite an existing .claude/ directory without confirmation",
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--target",
|
|
41
|
+
type=Path,
|
|
42
|
+
default=None,
|
|
43
|
+
help="Destination directory (defaults to the current working directory)",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--platform",
|
|
47
|
+
choices=PLATFORM_CHOICES,
|
|
48
|
+
default="claude",
|
|
49
|
+
help=(
|
|
50
|
+
"Target host adapter to initialize. Defaults to claude. "
|
|
51
|
+
"codex/cursor/all also scaffold .claude/ as the canonical C3 source."
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
git_group = parser.add_mutually_exclusive_group()
|
|
55
|
+
git_group.add_argument(
|
|
56
|
+
"--git",
|
|
57
|
+
action="store_true",
|
|
58
|
+
help="git 管理外のとき確認なしで git init する(CI / 非対話の明示 opt-in)",
|
|
59
|
+
)
|
|
60
|
+
git_group.add_argument(
|
|
61
|
+
"--no-git",
|
|
62
|
+
action="store_true",
|
|
63
|
+
help="git init を行わない(誘導メッセージのみ出力して正常終了)",
|
|
64
|
+
)
|
|
65
|
+
parser.set_defaults(handler=handle)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def handle(args: argparse.Namespace) -> int:
|
|
69
|
+
target_root: Path = (args.target or Path.cwd()).resolve()
|
|
70
|
+
dest = target_root / ".claude"
|
|
71
|
+
platforms = expand_platforms(args.platform)
|
|
72
|
+
adapter_platforms = tuple(p for p in platforms if p != "claude")
|
|
73
|
+
|
|
74
|
+
if dest.exists() and not args.force and platforms == ("claude",):
|
|
75
|
+
print(
|
|
76
|
+
f"refusing to overwrite existing directory: {dest}\n"
|
|
77
|
+
"Pass --force to overwrite or run `c3 update` for a diff-aware merge.",
|
|
78
|
+
file=sys.stderr,
|
|
79
|
+
)
|
|
80
|
+
return 1
|
|
81
|
+
|
|
82
|
+
template = templates_dir()
|
|
83
|
+
if dest.exists() and args.force and "claude" in platforms:
|
|
84
|
+
shutil.rmtree(dest)
|
|
85
|
+
|
|
86
|
+
target_root.mkdir(parents=True, exist_ok=True)
|
|
87
|
+
if not dest.exists():
|
|
88
|
+
copied = _copytree(template, dest)
|
|
89
|
+
print(f"initialized {dest} ({copied} files copied)")
|
|
90
|
+
elif "claude" in platforms:
|
|
91
|
+
print(f"using existing {dest}")
|
|
92
|
+
|
|
93
|
+
if adapter_platforms:
|
|
94
|
+
try:
|
|
95
|
+
actions = scaffold_adapters(target_root, adapter_platforms)
|
|
96
|
+
except (FileNotFoundError, ValueError) as exc:
|
|
97
|
+
print(f"adapter init failed: {exc}", file=sys.stderr)
|
|
98
|
+
return 1
|
|
99
|
+
print_adapter_actions(actions)
|
|
100
|
+
|
|
101
|
+
_maybe_init_git(
|
|
102
|
+
target_root,
|
|
103
|
+
git=getattr(args, "git", False),
|
|
104
|
+
no_git=getattr(args, "no_git", False),
|
|
105
|
+
)
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _maybe_init_git(
|
|
110
|
+
target_root: Path, *, git: bool, no_git: bool, _input_fn: Callable[[str], str] | None = None
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Detect git status and, for non-git dirs, init under the consent model.
|
|
113
|
+
|
|
114
|
+
git の成否は ``c3 init`` の exit code に影響させない(戻り値なし)。
|
|
115
|
+
すべてのメッセージは stdout に出す(scaffold 成功通知と同列)。
|
|
116
|
+
|
|
117
|
+
``_input_fn`` はテスト注入ポイント(デフォルト ``None`` = 呼び出し時に
|
|
118
|
+
``builtins.input`` を解決)。本番コードからは渡さない。
|
|
119
|
+
"""
|
|
120
|
+
status = gitutil.detect_git_status(target_root)
|
|
121
|
+
|
|
122
|
+
if status is gitutil.GitStatus.INSIDE_REPO:
|
|
123
|
+
return # 既に git 管理下。何もしない(入れ子 repo を作らない)
|
|
124
|
+
|
|
125
|
+
if status is gitutil.GitStatus.GIT_MISSING:
|
|
126
|
+
print(
|
|
127
|
+
"git コマンドが見つかりません。worktree 並列実装には git が必要です。"
|
|
128
|
+
"git をインストールしてから手動で git init してください。"
|
|
129
|
+
)
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
# ここから status == NOT_A_REPO
|
|
133
|
+
if no_git:
|
|
134
|
+
print(_MSG_WORKTREE_HINT)
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if git:
|
|
138
|
+
_do_git_init(target_root)
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
# フラグ無し: TTY のみ同意プロンプト
|
|
142
|
+
# sys.stdin が None や isatty() が bool True を返さない場合は非 TTY として扱う。
|
|
143
|
+
# 標準ライブラリの isatty() は常に bool を返すため is True で安全に判定できる。
|
|
144
|
+
if not (sys.stdin and hasattr(sys.stdin, "isatty") and sys.stdin.isatty() is True):
|
|
145
|
+
print(
|
|
146
|
+
"git 管理下にないため worktree 並列実装は利用できません。"
|
|
147
|
+
"c3 init --git で git init するか、手動で git init してください。"
|
|
148
|
+
)
|
|
149
|
+
return
|
|
150
|
+
|
|
151
|
+
# input は呼び出し時に解決する(import 時束縛を避けモンキーパッチと両立)。
|
|
152
|
+
fn = _input_fn if _input_fn is not None else input
|
|
153
|
+
try:
|
|
154
|
+
answer = fn(
|
|
155
|
+
"このディレクトリは git 管理下にありません。"
|
|
156
|
+
"worktree 並列実装のため git init しますか? [Y/n]: "
|
|
157
|
+
).strip().lower()
|
|
158
|
+
except (EOFError, OSError):
|
|
159
|
+
# パイプ等の非対話 stdin で input() が EOF/OS エラーを返した場合は
|
|
160
|
+
# 誘導メッセージにフォールバックする。
|
|
161
|
+
print(_MSG_WORKTREE_HINT)
|
|
162
|
+
return
|
|
163
|
+
if answer in ("", "y", "yes"):
|
|
164
|
+
_do_git_init(target_root)
|
|
165
|
+
else:
|
|
166
|
+
print(_MSG_WORKTREE_HINT)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _do_git_init(target_root: Path) -> None:
|
|
170
|
+
"""Run git_init and print the outcome message."""
|
|
171
|
+
if gitutil.git_init(target_root):
|
|
172
|
+
print(f"worktree 並列実装のため git init を実行しました: {target_root}")
|
|
173
|
+
else:
|
|
174
|
+
print(
|
|
175
|
+
"git init に失敗しました(.claude/ scaffold は完了しています)。"
|
|
176
|
+
"必要なら手動で git init してください。"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _copytree(src: Path, dst: Path, *, root: Path | None = None) -> int:
|
|
181
|
+
"""Copy ``src`` -> ``dst`` recursively, skipping personal/working files.
|
|
182
|
+
|
|
183
|
+
``root`` defaults to ``src`` and represents the ``.claude/`` directory; the
|
|
184
|
+
relative path from ``root`` is what ``should_skip`` matches against.
|
|
185
|
+
Returns the number of regular files written.
|
|
186
|
+
"""
|
|
187
|
+
if root is None:
|
|
188
|
+
root = src
|
|
189
|
+
dst.mkdir(parents=True, exist_ok=True)
|
|
190
|
+
count = 0
|
|
191
|
+
for entry in src.iterdir():
|
|
192
|
+
rel = entry.relative_to(root).as_posix()
|
|
193
|
+
target = dst / entry.name
|
|
194
|
+
if entry.is_dir():
|
|
195
|
+
count += _copytree(entry, target, root=root)
|
|
196
|
+
# Drop directories that ended up empty (everything inside was skipped).
|
|
197
|
+
if not any(target.iterdir()):
|
|
198
|
+
target.rmdir()
|
|
199
|
+
elif entry.is_file():
|
|
200
|
+
if should_skip(rel):
|
|
201
|
+
continue
|
|
202
|
+
shutil.copy2(entry, target)
|
|
203
|
+
count += 1
|
|
204
|
+
return count
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Git detection and init helpers for ``c3 init`` (no UI; subprocess only)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitStatus(Enum):
|
|
11
|
+
INSIDE_REPO = "inside_repo" # git 管理下(親 repo のサブディレクトリ含む)
|
|
12
|
+
NOT_A_REPO = "not_a_repo" # git 管理外(git は存在する)
|
|
13
|
+
GIT_MISSING = "git_missing" # git コマンドが PATH に無い
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def detect_git_status(target_root: Path) -> GitStatus:
|
|
17
|
+
"""Return the git status of *target_root* by running ``git rev-parse``.
|
|
18
|
+
|
|
19
|
+
returncode 分類:
|
|
20
|
+
- exit 0 かつ stdout が "true" -> INSIDE_REPO(git 管理下)
|
|
21
|
+
- returncode == 128(git 管理外の慣例値)-> NOT_A_REPO
|
|
22
|
+
- 128 以外の予期しない非ゼロ(権限/I-O エラー等)-> INSIDE_REPO
|
|
23
|
+
(安全側フォールバック:git init を誘発しない)
|
|
24
|
+
- TimeoutExpired -> INSIDE_REPO(安全側フォールバック:git init を誘発しない)
|
|
25
|
+
- git コマンド不在(FileNotFoundError)-> GIT_MISSING
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
result = subprocess.run(
|
|
29
|
+
["git", "rev-parse", "--is-inside-work-tree"],
|
|
30
|
+
cwd=str(target_root),
|
|
31
|
+
capture_output=True,
|
|
32
|
+
text=True,
|
|
33
|
+
check=False,
|
|
34
|
+
timeout=10,
|
|
35
|
+
encoding="utf-8",
|
|
36
|
+
errors="replace",
|
|
37
|
+
)
|
|
38
|
+
except FileNotFoundError:
|
|
39
|
+
return GitStatus.GIT_MISSING
|
|
40
|
+
except subprocess.TimeoutExpired:
|
|
41
|
+
# タイムアウト時は安全側(git init を誘発しない)に倒す
|
|
42
|
+
return GitStatus.INSIDE_REPO
|
|
43
|
+
if result.returncode == 0 and result.stdout.strip() == "true":
|
|
44
|
+
return GitStatus.INSIDE_REPO
|
|
45
|
+
if result.returncode == 128:
|
|
46
|
+
return GitStatus.NOT_A_REPO
|
|
47
|
+
# 予期しない returncode(権限/I-O エラー等)は安全側に倒し git init を誘発しない
|
|
48
|
+
return GitStatus.INSIDE_REPO
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def git_init(target_root: Path) -> bool:
|
|
52
|
+
"""Run ``git init`` in *target_root*. Return True on success (exit 0).
|
|
53
|
+
|
|
54
|
+
git 不在・非 0 終了・タイムアウトのいずれでも False を返す(例外は送出しない)。
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
result = subprocess.run(
|
|
58
|
+
["git", "init"],
|
|
59
|
+
cwd=str(target_root),
|
|
60
|
+
capture_output=True,
|
|
61
|
+
text=True,
|
|
62
|
+
check=False,
|
|
63
|
+
timeout=10,
|
|
64
|
+
encoding="utf-8",
|
|
65
|
+
errors="replace",
|
|
66
|
+
)
|
|
67
|
+
except FileNotFoundError:
|
|
68
|
+
return False
|
|
69
|
+
except subprocess.TimeoutExpired:
|
|
70
|
+
return False
|
|
71
|
+
return result.returncode == 0
|
{claude_code_conductor-2.38.0 → claude_code_conductor-2.40.0}/tests/skills/_skill_helpers.py
RENAMED
|
@@ -24,6 +24,7 @@ SKILL_PATHS = {
|
|
|
24
24
|
"start": SKILLS_DIR / "start" / "SKILL.md",
|
|
25
25
|
"dev-workflow": SKILLS_DIR / "dev-workflow" / "SKILL.md",
|
|
26
26
|
"init-session": SKILLS_DIR / "init-session" / "SKILL.md",
|
|
27
|
+
"setup": SKILLS_DIR / "setup" / "SKILL.md",
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
# 見出しの「近傍」を判定するときに走査する行数。
|
|
@@ -56,6 +57,11 @@ def read_init_session_skill() -> str:
|
|
|
56
57
|
return read_skill("init-session")
|
|
57
58
|
|
|
58
59
|
|
|
60
|
+
def read_setup_skill() -> str:
|
|
61
|
+
"""`.claude/skills/setup/SKILL.md` の内容を返す。"""
|
|
62
|
+
return read_skill("setup")
|
|
63
|
+
|
|
64
|
+
|
|
59
65
|
def keyword_in_neighborhood(
|
|
60
66
|
content: str,
|
|
61
67
|
anchor: str,
|