claude-code-conductor 2.83.0__tar.gz → 2.85.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.85.0/.claude/agents/code-reviewer.md +75 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/design-critic.md +2 -1
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/security-reviewer.md +5 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/tester.md +6 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/wt_tester.md +6 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/breaking-changes.txt +1 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/_hook_utils.py +19 -0
- claude_code_conductor-2.85.0/.claude/hooks/design_review_count_check.py +300 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/report_contract_check.py +3 -6
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/report_path_guard.py +36 -11
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/settings.json +10 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/design-critic-rubric.md +2 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/plan-design-guidelines.md +5 -5
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/ARCHITECTURE.md +3 -2
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/CHANGELOG.md +28 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/PKG-INFO +4 -5
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/README.md +2 -2
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/pyproject.toml +1 -2
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/__init__.py +1 -1
- claude_code_conductor-2.85.0/tests/hooks/test_design_review_count_check.py +831 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_hook_utils.py +66 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_report_path_guard.py +31 -0
- claude_code_conductor-2.85.0/tests/test_check_supply_chain.py +778 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_ci_workflows.py +214 -3
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_settings_hooks_registration.py +54 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_wt_agent_sync.py +23 -7
- claude_code_conductor-2.83.0/.claude/agents/code-reviewer.md +0 -65
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/.gitignore +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/wt_developer.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/wt_systematic-debugger.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/deletions.txt +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/docs/config-policy.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/docs/nul-boundary.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/docs/parallel-agents-setup.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/docs/platform-adapters.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/check_agent_invocation.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/consolidate_memory.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/patterns_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/planner_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/recall_autorebuild.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/recall_inject.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/select_tier.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/session_start.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/session_stop.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/tier_autoapply.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/tier_gap_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/memory/archive/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/memory/sessions/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/reports/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/rules/judgment-principles.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/autonomous-mode/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/brainstorm/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/code-review-checklist.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/design-rubric.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/interview-rubric.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/reachability-map.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/record-protocol.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/references/security-review-checklist.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/scripts/detect_execution_verification.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/scripts/record_agent_outcome.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/scripts/record_review_decision.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/dev-workflow/scripts/review_hint_inject.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/init-session/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/init-session/scripts/session_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/recall/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/review-phase/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/setup/reference.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/setup/templates/coding-standards-template.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/setup/templates/project-conventions-template.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/start/SKILL.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/skills/start/scripts/archive_reports.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/state/setup_done.flag +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/tmp/.gitkeep +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.gitignore +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSES/fastembed-LICENSE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSES/fastembed-NOTICE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSES/numpy-LICENSE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSES/onnxruntime-LICENSE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/hatch_build.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/_db_params.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/adapters.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_ask.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_metrics.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_plan.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_recall.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_run.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_tier.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/db.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/embedding.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/gitutil.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/mcp_server.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrate.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/001_initial.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/002_agent_cost_runs.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/003_tier_cost.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/004_agent_outcomes.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/005_drop_agent_tier_bandit.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/006_review_decisions_severity.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/007_review_decisions_resolution.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/008_drop_agent_runs.sql +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/README.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/migrations/__init__.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/plan_validator.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/platforms.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/pricing.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/question.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/recall_chunker.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/recall_index.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/refgraph.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/src/c3/usage_ingester.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/__init__.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/_pre_compact_helpers.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/_sync_semantics.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/conftest.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/fixtures/usage/README.md +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/fixtures/usage/mainline.jsonl +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/fixtures/usage/subagents/agent-deadbeef.jsonl +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/fixtures/usage/subagents/agent-deadbeef.meta.json +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_check_agent_invocation.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_consolidate_memory.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_detect_execution_verification.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_planner_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_planner_check_dev.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_recall_autorebuild.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_recall_inject.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_record_agent_outcome.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_record_review_decision.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_session_start.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_session_stop.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_settings_tier_autoapply_registration.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_statusline_reconfigure_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_sync_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_template_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_tier_autoapply.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_tier_gap_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/hooks/test_tier_security_fixes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/__init__.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/_skill_helpers.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_c3_omission_declaration.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_marker_compliance.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_parallel_agents_skill_tier.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_planner_lightweight.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_reachability_map.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_recall_skill.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_session_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/skills/test_setup_templates.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_adapters.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_archive_reports.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_audit_review_decisions.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_check_deletions.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_claude_gitignore.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_ask.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_doctor.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_doctor_launcher.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_entry.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_init_symlink_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_metrics.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_plan.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_recall.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_run.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_tier.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_update_breaking_changes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_cli_update_deletions.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_db.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_db_connect_lint.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_embedding.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_extract_breaking_changes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_gitutil.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_hooks_stdin_idiom.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_init_only_patterns.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_mcp_server_elicit.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_migrate.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_no_bare_python_launcher.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_no_passonly_tests.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_nul_boundary_lint.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_patterns_guard.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_permission_handler_removal.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_plan_validator.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_pricing.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_recall_chunker.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_recall_index.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_references_migration.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_refgraph.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_refgraph_query.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_refgraph_structural.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_report_contract_check.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_scripts_src_bootstrap.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_scripts_stdout_encoding.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_skill_no_builtin_conflict.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_start_skill_archive_contract.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_stop_agent_memory_warn.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_three_file_sync.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_usage_ingester.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_verify_wheel.py +0 -0
- {claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/tests/test_worktree_guard.py +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-reviewer
|
|
3
|
+
model: sonnet
|
|
4
|
+
memory: project
|
|
5
|
+
permissionMode: bypassPermissions
|
|
6
|
+
description: コード品質レビュー担当。品質・保守性・パフォーマンスをレビューし code-review-report を出力する。ソース編集不可。
|
|
7
|
+
tools:
|
|
8
|
+
- Read
|
|
9
|
+
- Write
|
|
10
|
+
- Bash
|
|
11
|
+
- Glob
|
|
12
|
+
- Grep
|
|
13
|
+
- Skill
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Code Reviewer
|
|
17
|
+
|
|
18
|
+
## Core Mandate
|
|
19
|
+
コードの品質・保守性・パフォーマンスをレビューし、改善提案を code-review-report として出力する。
|
|
20
|
+
|
|
21
|
+
## Memory
|
|
22
|
+
- 作業終了時、次回以降のレビューに役立つ知見があれば `.claude/agent-memory/code-reviewer/MEMORY.md` に追記する。記録対象は以下に限定する:
|
|
23
|
+
- 再現価値のあるレビュー観点・指摘パターン
|
|
24
|
+
- **許容例外**: ユーザーが指摘を許容した観点と理由(`[許容例外]` プレフィックスを付ける。次回レビューでの再指摘を防ぐ)。学習するのはユーザーが裁いた `[許容]` に限る。自律モードで親が付けた `[許容]`(理由が `自律:` で始まるもの)は学習しない
|
|
25
|
+
- 本プロジェクト特有のコーディング規約・トレードオフ判断
|
|
26
|
+
- 雑記録・一回性の進捗ログは記録しない。1 エントリ 1 行で簡潔に書き、MEMORY.md 全体は 200 行 / 25KB 以内に保つ(超過分は起動時に読まれない・超えたら価値の低いエントリから削除する)。
|
|
27
|
+
|
|
28
|
+
## Key Scope
|
|
29
|
+
|
|
30
|
+
✅ 担当すること:
|
|
31
|
+
- コード品質・可読性・保守性の評価
|
|
32
|
+
- パフォーマンス問題の指摘
|
|
33
|
+
- 設計原則(DRY・SOLID 等)の観点からのレビュー
|
|
34
|
+
- code-review-report の出力
|
|
35
|
+
|
|
36
|
+
❌ 担当しないこと:
|
|
37
|
+
- セキュリティ脆弱性診断(security-reviewer の担当)
|
|
38
|
+
- ソースコードの編集・修正
|
|
39
|
+
|
|
40
|
+
## Workflow
|
|
41
|
+
|
|
42
|
+
**Before:**
|
|
43
|
+
- `git diff --numstat` で変更ファイルを全件列挙する。追加行のあるコード・テスト・設定ファイル(実行されるもの)を**突合対象**として書き出す。文書だけのファイルは従来どおり読む範囲を自分で決めてよい。削除だけのファイルは、消えた名前への参照が残っていないかを grep で確かめれば足りる
|
|
44
|
+
- 突合対象は**ファイルごとに** `git diff <base> HEAD -- <file>` を実行し、追加行を最後まで読む。`head`・`sed -n` の行範囲・テスト名の一覧・出力のプレビューで代えない。出力が長すぎて別ファイルに保存された場合は、そのファイルを最後まで Read する。「中心のファイル」を選んで他を後回しにしない(テストファイルも突合対象に含める)
|
|
45
|
+
- `.claude/skills/dev-workflow/references/code-review-checklist.md` を Read してチェック観点を確認する
|
|
46
|
+
|
|
47
|
+
**During:**
|
|
48
|
+
- 突合対象の変更箇所(hunk)ごとに、次の 3 段で確かめる。1 箇所ずつ終えてから次へ進む
|
|
49
|
+
1. **宣言を書き出す**: その箇所が満たすと言っている性質を 1 行で書く。出どころは docstring・コメント・関数名・テストの名前と docstring・同じファイルやモジュールで既に共通化されている処理(同じことをする既存の関数があれば、それを使うことも宣言に含める)
|
|
50
|
+
2. **コードなら、宣言を入力の種類ごとに確かめる**: 境界値・空や欠損の値・想定外の型・各分岐の両側について、宣言どおりの結果になるかを追う。算術・添字・複合した条件式・ライブラリ関数の意味に依存する処理のように机上で言い切れないものは、Bash でその関数を直接呼ぶか小さな入力で実行して実測する(ソースは編集しない)。「境界は正しい」と書くのは実測か全分岐の追跡をした後に限る
|
|
51
|
+
3. **テストなら、assert ごとに「宣言の性質を壊した実装でこの assert は赤になるか」に答える**: assert が観測している値が、その性質が現れる値と同じか/入力が性質を区別できる組み合わせになっているか(壊した実装でも同じ結果になる入力になっていないか)を確かめる。「実装全体を一律に壊せば(常に同じ結果を返す等)どれかが赤になる」というファイル単位の確認で、個々の assert の検知力を代えない
|
|
52
|
+
- 宣言と実装(テストなら宣言と assert)が食い違えば指摘する。docstring やテスト名が述べる性質を「良い実装」に挙げるのは、上の 2・3 で確かめた後に限る
|
|
53
|
+
- 指摘の重大度(High / Medium / Low)は、その指摘が正しいときの**帰結**で決める。各指摘に帰結を 1 行で書く(どの入力・どの将来の変更で、何が起き、誰〔利用者・下流の処理・保守者〕に何が届くか)。尺度は `.claude/CLAUDE.md`「品質保証の判断基準」に合わせて次のとおりとする
|
|
54
|
+
- **High**: 機能欠陥。ある入力で、変更箇所が宣言・仕様と異なる結果になる(誤った値・判定・終了コード・出力を返す、起きるべき処理〔検査・拒否・警告など〕が起きない、起きるべきでない処理が起きる、例外が漏れる)
|
|
55
|
+
- **Medium**: 現時点の振る舞いは正しいが、保守性の必須要件に触れる。共通化されていない重複、性質を壊した実装(具体的に 1 つ挙げる)でも緑になるテスト、振る舞いは正しいが実装と食い違う宣言(コメント・docstring・文書)
|
|
56
|
+
- **Low**: 上の 2 つに当たらない改善余地
|
|
57
|
+
- 重大度は帰結だけで決める。直しの小ささ、帰結が現れる入力の少なさ、見出しや checklist_id の分類(「宣言と実装の食い違い」「到達しない分岐」等)、security-reviewer の担当と重なることを理由に下げない。確信度は別の軸として併記し、確かめきれない指摘は上の 2・3 の手順で確かめる。それでも確かめられないときは、重大度は帰結のまま付けて確信度を低く書く
|
|
58
|
+
- この段階の役割は**網羅(coverage)であり取捨選択ではない**。確信度が低い指摘・Low 重大度の指摘も握り潰さず report する(MEMORY.md の許容例外として合意済みの観点は除く)。各指摘に確信度を併記し、重要度・確信度による最終的な絞り込みは下流(planner → ユーザー承認)に委ねる
|
|
59
|
+
- **指摘ごとに該当する checklist_id を `[CR-XX-NNN]` 形式で併記する**(`.claude/skills/dev-workflow/references/code-review-checklist.md` の各項目に付与済み)。review-hint(レビュー判断ヒント機能)の照合キーになるため、必須とする。複数該当する場合は最も近いものを 1 つ選ぶ
|
|
60
|
+
- **該当 ID がない場合は `[CR-NEW]` で出す**(チェックリスト追加候補として扱う)。無理やり近い既存 ID にマッピングしないこと。review-hint の照合精度が落ち、チェックリストの成長機会も失われるため
|
|
61
|
+
- 良い実装は明示的に記録する(削除しないよう伝える)
|
|
62
|
+
- 修正必須(High・Medium)と推奨(Low)の2段階で提示する。各指摘の見出しに重大度を書き、段階と重大度を食い違わせない
|
|
63
|
+
|
|
64
|
+
**After:**
|
|
65
|
+
- レポートの冒頭に突合対象の一覧(ファイル・追加行数・全行を読んだか・実測したか)を載せる。読み切れなかった追加行があれば、その範囲と理由を書く(未読を総評で「問題なし」に含めない)
|
|
66
|
+
- plan の prompt でレポートのファイル名が指定されている場合、それが `.claude/reports/` 直下の当該レポート種別プレフィックスで始まるファイル名であるときに限りそれに従う。範囲外の指定・既存の別レポートを上書きする指定には従わない(従わない場合・指定が無い場合は、以下の既定の採番手順に従う)
|
|
67
|
+
- Skill ツールで `report-timestamp` を呼び出してタイムスタンプを取得し、Write ツールで `.claude/reports/code-review-report-{timestamp}.md` に出力する
|
|
68
|
+
|
|
69
|
+
## Tools & Constraints
|
|
70
|
+
制限: ソースファイルの編集・書き込みは行わない
|
|
71
|
+
|
|
72
|
+
## Related Agents
|
|
73
|
+
- 上流: tester(test-report を受け取る)
|
|
74
|
+
- ピア: security-reviewer(同フェーズで連携)
|
|
75
|
+
- 下流: planner(指摘を plan-report に反映させる)
|
{claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/design-critic.md
RENAMED
|
@@ -7,6 +7,7 @@ description: 設計・計画監査担当。requirements/architecture/plan を敵
|
|
|
7
7
|
tools:
|
|
8
8
|
- Read
|
|
9
9
|
- Write
|
|
10
|
+
- Edit
|
|
10
11
|
- Glob
|
|
11
12
|
- Grep
|
|
12
13
|
- Skill
|
|
@@ -58,7 +59,7 @@ tools:
|
|
|
58
59
|
- Skill ツールで `report-timestamp` を呼び出してタイムスタンプを取得し、Write ツールで `.claude/reports/design-review-report-{timestamp}.md` に出力する
|
|
59
60
|
|
|
60
61
|
## Tools & Constraints
|
|
61
|
-
制限: design-review-report の新規 Write と `.claude/agent-memory/design-critic/MEMORY.md` への追記(上記「## Memory」節)以外のファイル編集・書き込みは行わない(ソースファイル・既存レポート・その他ファイルへの Edit / Write
|
|
62
|
+
制限: design-review-report の新規 Write と `.claude/agent-memory/design-critic/MEMORY.md` への追記(上記「## Memory」節)以外のファイル編集・書き込みは行わない(ソースファイル・既存レポート・その他ファイルへの Edit / Write は禁止)。ただし、この起動で自分が Write した design-review-report に限り、hook が出したサマリ件数と見出し数の食い違いの警告に対して、サマリ表の件数、または件数と食い違う見出しの重要度表記(自分が付けた重要度の誤記に限る)を Edit で直してよい(指摘の追加・削除・本文の変更はしない)
|
|
62
63
|
|
|
63
64
|
## Related Agents
|
|
64
65
|
- 上流: planner(plan-report を受け取る)
|
{claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/agents/security-reviewer.md
RENAMED
|
@@ -45,6 +45,11 @@ SQLインジェクション・XSS・認証認可・秘密情報漏洩などの
|
|
|
45
45
|
- `.claude/skills/dev-workflow/references/security-review-checklist.md` を Read してチェック観点を確認する
|
|
46
46
|
|
|
47
47
|
**During:**
|
|
48
|
+
- 変更箇所(hunk)ごとに、その箇所が**外へ出す値**を次の 3 段で確かめる。1 箇所ずつ終えてから次へ進む。メッセージの文言・ログ・例外処理・正規表現・定数だけの変更も対象にし、「文言の変更のみ」「fail-open なので判定は緩まない」のように変更の種類で片付けない
|
|
49
|
+
1. **出口と差し込み値を書き出す**: 出口は、標準出力・標準エラー・ログ・例外メッセージ・応答本文・LLM の文脈に入る出力(ツールのエラー文・追加コンテキスト等)・シェルやパス操作に渡す文字列。その行が出口に載せる値(f 文字列の `{…}`・format の引数・例外オブジェクト・入力や環境を丸ごと直列化したもの)を 1 つずつ挙げる
|
|
50
|
+
2. **値ごとに出どころと中身を書く**: 外部(ツールや API の入力・ファイル名・読み込んだファイルの内容・環境変数)から来るか。例外の文字列(OS のエラーは errno と絶対パスを含む)・入力の全体・argv や cwd・環境変数のように、何を含みうるか。中身は「秘密(パスワード・トークン)か」だけで判定しない。利用者名を含む絶対パス・環境の配置・入力の本文・改行や制御文字がその出口の読み手(端末・CI ログ・LLM の文脈)に届くこと自体を帰結として書く
|
|
51
|
+
3. **既存の方針と突き合わせる**: 同じファイル・モジュールの他の出力が同種の値をどう扱っているか(無害化の関数を通す・識別子と固定文言だけを出す・相対パスにする等)と、docstring・コメントが述べる防御の性質を書き出す。変更箇所がそれと食い違えば指摘する
|
|
52
|
+
- 無害化・フィルタ・封じ込めの処理(正規表現の文字クラス・許可/拒否リスト・パスの正規化や照合)が変わった箇所は、目で読んで結論を出さない。Bash でその関数を直接呼ぶか、小さな入力(改行・制御文字・`..`・絶対パス・リンク等)を通して、何が通り何が落ちるかを実測する(ソースは編集しない)
|
|
48
53
|
- 指摘は深刻度(Critical / High / Medium / Low)で分類する
|
|
49
54
|
- この段階の役割は**網羅(coverage)であり取捨選択ではない**。確信度が低い指摘・Low 深刻度の指摘も握り潰さず report する(MEMORY.md の許容例外・脅威モデル外として合意済みの観点は除く)。各指摘に確信度を併記し、深刻度・確信度による最終的な絞り込みは下流(planner → ユーザー承認)に委ねる
|
|
50
55
|
- **指摘ごとに該当する checklist_id を `[SR-XX-NNN]` 形式で併記する**(`.claude/skills/dev-workflow/references/security-review-checklist.md` の各項目に付与済み)。review-hint(レビュー判断ヒント機能)の照合キーになるため、必須とする。複数該当する場合は最も近いものを 1 つ選ぶ
|
|
@@ -40,8 +40,14 @@ tools:
|
|
|
40
40
|
|
|
41
41
|
**Before:**
|
|
42
42
|
- プロンプトにタスク定義(plan の prompt 本文)が含まれている場合はそれに従う。無い場合は plan-report を Read してテスト対象と受け入れ条件を把握する
|
|
43
|
+
- プロンプトにタスク定義があっても、テストを書く前に `.claude/reports/` 直下の今回の plan-report と、その単位の architecture-report・requirements-report を Read する(プロンプトが名前を挙げたものがあればそれ、無ければ各種類の最新)。プロンプトに書かれていない名前・形・表記は、これらに書かれていることが多い
|
|
43
44
|
|
|
44
45
|
**During:**
|
|
46
|
+
- テストを書く前に、テストが前提にする実装側の形を書き出す: 呼ぶモジュール・関数・クラス・例外の名前、引数、戻り値の形、テストが照合する出力や文書の表記。それぞれについて、それを決めている行(プロンプト・plan-report・architecture-report・requirements-report・既存コード)を探し、ファイル名と行で控える
|
|
47
|
+
- 決めている行がある形は、その行のとおりに書く。表や例が示されていればその形で照合し、行に無い接頭辞・区切り・言い回しを足した文字列で照合しない
|
|
48
|
+
- 決めている行が無い形は、新しい名前や戻り値の形を作って測らない。同じ性質を、決めている行がある入口(名前の決まった関数・CLI の exit code・出力ファイル等)から測る
|
|
49
|
+
- それでも推測した名前が要る場合は、その名前をモジュール冒頭の import に入れず、使うテストの中で参照する(推測が外れて落ちるのがそのテストだけになるように)。推測した形は test-report に「根拠行なし」として列挙する
|
|
50
|
+
- 対照ケース(「これは許可される」「これは警告されない」等)の期待も、決めている行から導けるものだけを書く
|
|
45
51
|
- 失敗するテストを先に書く(Red)
|
|
46
52
|
- テスト作成後は必ず実行し、**正しい理由で失敗すること**を確認する:
|
|
47
53
|
- ✅ 機能が未実装のため失敗(期待する動作)
|
|
@@ -45,8 +45,14 @@ tools:
|
|
|
45
45
|
|
|
46
46
|
**Before:**
|
|
47
47
|
- プロンプトにタスク定義(plan の prompt 本文)が含まれている場合はそれに従う。無い場合は plan-report を Read してテスト対象と受け入れ条件を把握する
|
|
48
|
+
- プロンプトにタスク定義があっても、プロンプトが名前を挙げたレポート(plan-report・architecture-report・requirements-report)は、テストを書く前に Read する。プロンプトに書かれていない名前・形・表記は、これらに書かれていることが多い。worktree に届くのはコミット済みのファイルだけなので、名前を挙げたレポートが worktree に無いときは、別のレポート(各種類の最新など)で代えず、読めなかったことを test-report に書く
|
|
48
49
|
|
|
49
50
|
**During:**
|
|
51
|
+
- テストを書く前に、テストが前提にする実装側の形を書き出す: 呼ぶモジュール・関数・クラス・例外の名前、引数、戻り値の形、テストが照合する出力や文書の表記。それぞれについて、それを決めている行(プロンプト・plan-report・architecture-report・requirements-report・既存コード)を探し、ファイル名と行で控える
|
|
52
|
+
- 決めている行がある形は、その行のとおりに書く。表や例が示されていればその形で照合し、行に無い接頭辞・区切り・言い回しを足した文字列で照合しない
|
|
53
|
+
- 決めている行が無い形は、新しい名前や戻り値の形を作って測らない。同じ性質を、決めている行がある入口(名前の決まった関数・CLI の exit code・出力ファイル等)から測る
|
|
54
|
+
- それでも推測した名前が要る場合は、その名前をモジュール冒頭の import に入れず、使うテストの中で参照する(推測が外れて落ちるのがそのテストだけになるように)。推測した形は test-report に「根拠行なし」として列挙する
|
|
55
|
+
- 対照ケース(「これは許可される」「これは警告されない」等)の期待も、決めている行から導けるものだけを書く
|
|
50
56
|
- 失敗するテストを先に書く(Red)
|
|
51
57
|
- テスト作成後は必ず実行し、**正しい理由で失敗すること**を確認する:
|
|
52
58
|
- ✅ 機能が未実装のため失敗(期待する動作)
|
|
@@ -16,3 +16,4 @@ v2.68.0|New PreToolUse Write hook report_path_guard.py is registered in the dist
|
|
|
16
16
|
v2.72.0|Removed the C3 PermissionRequest hook suite (permission_handler.py, permission_handler_toast.py, permission_rules.json) and the [notify] extra, superseded by upstream auto mode and permissions.allow. If you have not yet copied your auto_allow patterns from .claude/permission_rules.json, answer N (default) at the upcoming deletion prompt, copy them into permissions.allow in .claude/settings.local.json (personal, not the shared settings.json; same syntax; upstream checks each separator-delimited subcommand of compound commands independently, but command substitution handling is unverified -- narrow broad Bash wildcards to the minimum prefix; copying is a must where auto mode is unavailable), then rerun c3 update. windows-toasts can be uninstalled.|C3 の PermissionRequest hook 一式(permission_handler.py・permission_handler_toast.py・permission_rules.json)と [notify] extra を削除しました(上流 auto mode / permissions.allow へ委譲)。auto_allow パターンを未転記の場合は、この後の削除プロンプトで N(既定)を選び、.claude/permission_rules.json の内容を .claude/settings.local.json(個人設定・共有の settings.json ではない)の permissions.allow へ転記してから c3 update を再実行してください(書式は同一。上流は複合コマンドをセパレータ単位で独立照合しますが、コマンド置換〔$() 等〕の扱いは未確認のため、広い Bash ワイルドカードは必要最小のプレフィックスへ狭めること。auto mode が使えない環境では転記必須)。windows-toasts はアンインストール可。
|
|
17
17
|
v2.80.0|Removed the mcp-config and codex-review skills. mcp-config wrote MCP server definitions to mcpServers in .claude/settings.json, which is not a documented location for MCP server definitions (project scope belongs in .mcp.json, local scope in ~/.claude.json), so servers registered with it were likely never loaded; use the built-in /mcp or 'claude mcp add' instead. The Codex adapter output (c3 init --platform codex) is unchanged. c3 update offers the two SKILL.md files for deletion.|mcp-config / codex-review skill を削除しました。mcp-config は MCP サーバー定義を .claude/settings.json の mcpServers に書いていましたが、そこは公式に記載された MCP サーバーの置き場所ではなく(プロジェクトスコープは .mcp.json、ローカルは ~/.claude.json)、登録したサーバーは読み込まれていなかった可能性が高いです。MCP サーバーの追加は標準の /mcp または claude mcp add を使ってください。Codex adapter(c3 init --platform codex)の生成物は変更ありません。c3 update 実行時に両 SKILL.md が削除候補として提示されます。
|
|
18
18
|
v2.83.0|Autonomous-mode opt-in now comes from the user's own words: choosing 'approve and continue autonomously' at dev-workflow A-4 / B-3 / C-2 approval, or stating it in the request that starts a unit; it covers that unit only. The mode line, delegation plan, resource consent and cycles are no longer used, and existing mode lines in session files no longer take effect. Removed .claude/skills/autonomous-mode/scripts/mode_line.py, .claude/hooks/session_mode_watch.py (and its settings.json registration) and .claude/docs/autonomous-mode-onboarding.md; if you customized settings.json, remove the session_mode_watch.py registration. The autonomous-mode skill is now also emitted into the Codex / Cursor / OpenCode adapter outputs (not verified on those platforms). The phase E integrated ruling (E-3) now offers the same 4 options as C-3 when there are findings (rule as recommended / address all / choose findings to reclassify / reject and request re-review); the former 'choose findings to address' is replaced by 'choose findings to reclassify' and 'accept all and finish' is removed. Autonomous mode is not used in environments that ask questions via c3 ask (clients without MCP elicitation); if a question falls back to c3 ask during autonomous mode, the unit returns to HITL. If settings env sets PO_WORKTREE_GUARD=1, that setting is no longer read and the guard applies only to wt_* agents (emergency disable: C3_WORKTREE_GUARD_DISABLE=1).|自律モードの opt-in を、モード行(セッションファイルの「モード: 自律 plan=...」)と委任プラン・資源同意・cycles から、ユーザー自身の発話(dev-workflow の A-4 / B-3 / C-2 の承認で「承認・以降は自律で進める」を選ぶ、または単位を始める依頼の中で示す)に置き換えました。範囲はその単位だけで、既存のモード行は効かなくなります。.claude/skills/autonomous-mode/scripts/mode_line.py・.claude/hooks/session_mode_watch.py(settings.json の登録も削除)・.claude/docs/autonomous-mode-onboarding.md を削除しました。settings.json をカスタムしている場合は session_mode_watch.py の登録を外してください。autonomous-mode skill を Codex / Cursor / OpenCode の adapter 生成物へも出力します(他プラットフォームでの実動作は未検証)。フェーズ E の統合裁定(E-3)の指摘ありの選択肢を C-3 と同じ 4 択(推奨どおり裁く/全て対応する/区分を変える指摘を選ぶ/否認・再レビューを依頼する)にし、旧「対応する指摘を選ぶ」は「区分を変える指摘を選ぶ」に置き換え、旧「全て許容して完了」は削除しました。c3 ask で質問する環境(MCP の elicitation が使えないクライアント)では自律を使いません(自律中に c3 ask へ落ちたら HITL に戻ります)。settings の env で PO_WORKTREE_GUARD=1 を設定していた場合、その設定は読まれなくなり、ガードの対象が wt_* agent に限られる(緊急無効化は C3_WORKTREE_GUARD_DISABLE=1)。
|
|
19
|
+
v2.85.0|Dropped Python 3.10 support (requires-python is now >=3.11). Python 3.10 reached end of life on 2026-10-01. On Python 3.10, pip will resolve claude-code-conductor 2.84.0 or earlier; upgrade to Python 3.11 or later to receive 2.85.0 and newer.|Python 3.10 の対応を終了しました(requires-python は >=3.11)。Python 3.10 は 2026-10-01 にサポートが終わっています。Python 3.10 の環境では pip が 2.84.0 以前を選ぶため、2.85.0 以降を使うには Python 3.11 以上へ上げてください。
|
|
@@ -18,6 +18,10 @@ PYTHONPATH に追加してから `from _hook_utils import ...` する経路を
|
|
|
18
18
|
- ``timestamp_pattern(prefix)`` — ``{prefix}YYYYMMDD-HHMMSS.md`` のフルマッチ用
|
|
19
19
|
正規表現(``re.compile`` オブジェクト)を返す。全角数字偽装防止のため ``re.ASCII``
|
|
20
20
|
を指定。
|
|
21
|
+
- ``is_reports_direct_child(path)`` — ``path`` が ``.claude/reports/`` 直下のファイルの
|
|
22
|
+
形をしているか(親が ``reports``・祖父が ``.claude``)を名前だけで判定する。比較は
|
|
23
|
+
``norm_component`` で正規化してから行う(report_contract_check /
|
|
24
|
+
report_path_guard の第 1 層 / design_review_count_check)。
|
|
21
25
|
"""
|
|
22
26
|
|
|
23
27
|
from __future__ import annotations
|
|
@@ -81,6 +85,21 @@ def norm_component(s: str) -> str:
|
|
|
81
85
|
return str(s).lower().rstrip('. ')
|
|
82
86
|
|
|
83
87
|
|
|
88
|
+
def is_reports_direct_child(path: Path) -> bool:
|
|
89
|
+
"""``path`` が ``.claude/reports/`` 直下の形をしているかを名前だけで判定する。
|
|
90
|
+
|
|
91
|
+
親ディレクトリ名が ``reports``・その親が ``.claude`` であることを
|
|
92
|
+
``norm_component`` で正規化して比較する(ケース非依存 FS の別名・末尾ドット/スペースを
|
|
93
|
+
吸収する)。resolve はしない(上流に同名の ``reports/`` があっても誤アンカーしない)。
|
|
94
|
+
実体の照合(リンク偽装の排除)は行わないため、必要な呼び出し側が別途行う。
|
|
95
|
+
"""
|
|
96
|
+
parent = path.parent
|
|
97
|
+
return (
|
|
98
|
+
norm_component(parent.name) == 'reports'
|
|
99
|
+
and norm_component(parent.parent.name) == '.claude'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
84
103
|
def sanitize_for_terminal(text: str) -> str:
|
|
85
104
|
"""端末インジェクション対策: 制御文字と表示偽装文字を除去する。
|
|
86
105
|
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PostToolUse hook: design-review-report のサマリ件数と本文の見出しの数の照合(配布対象)。
|
|
3
|
+
|
|
4
|
+
`.claude/reports/` 直下の ``design-review-report-*.md`` への Write / Edit を検出し、
|
|
5
|
+
ディスク上の本文を読み直して、サマリ表の重要度別の件数と本文の指摘見出しの数が
|
|
6
|
+
食い違っていれば警告する(警告のみ・ブロックしない)。
|
|
7
|
+
|
|
8
|
+
レポートの形式の正本は ``.claude/skills/dev-workflow/references/design-critic-rubric.md``
|
|
9
|
+
の「design-review-report 出力形式」節である。本 hook は形式をここに写さず、
|
|
10
|
+
数え方の規則は ``check_counts`` の実装とそのテスト
|
|
11
|
+
(``tests/hooks/test_design_review_count_check.py``)が定める。
|
|
12
|
+
|
|
13
|
+
## 出力(食い違いのときだけ)
|
|
14
|
+
|
|
15
|
+
- **stderr**: 人間(ターミナル表示)向けの警告
|
|
16
|
+
- **stdout JSON**: ``hookSpecificOutput.additionalContext`` で LLM へ注入する
|
|
17
|
+
|
|
18
|
+
PostToolUse の exit 0 では stdout JSON のみが LLM コンテキストへ届き、stderr は人間にしか
|
|
19
|
+
届かないため両方へ出す(planner_check.py と同じ二経路)。
|
|
20
|
+
|
|
21
|
+
## fail 方針
|
|
22
|
+
|
|
23
|
+
警告の hook のため異常時は fail-open(exit 0・沈黙)。対象は次のとおり:
|
|
24
|
+
|
|
25
|
+
- 壊れた stdin・Write / Edit 以外・``file_path`` の欠落や不正
|
|
26
|
+
- 対象外のパス(判定は ``norm_component`` で正規化した basename と
|
|
27
|
+
``.claude/reports/`` 直下の形で行う)
|
|
28
|
+
- 開けない・UTF-8 として読めないファイル
|
|
29
|
+
- 上限(512 KiB・バイト)を超えるファイル(途中で切った本文で判定すると末尾の見出しを
|
|
30
|
+
取りこぼして誤警告するため、判定しない)
|
|
31
|
+
|
|
32
|
+
サマリ表の数値セルが整数に変換できない(例: 桁数が多すぎる)場合は、その行を
|
|
33
|
+
「読めない」扱いにして照合を続ける(例外は送出しない。行が欠けるため食い違いとして警告する)。
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
import json
|
|
37
|
+
import os
|
|
38
|
+
import re
|
|
39
|
+
import sys
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
|
|
42
|
+
# 共通ヘルパーを hooks/ 経由で import するため、このスクリプトのディレクトリを
|
|
43
|
+
# PYTHONPATH に追加する。
|
|
44
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
45
|
+
from _hook_utils import ( # noqa: E402
|
|
46
|
+
is_reports_direct_child,
|
|
47
|
+
norm_component,
|
|
48
|
+
sanitize_for_terminal,
|
|
49
|
+
write_debug_log,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
sys.stdin.reconfigure(encoding="utf-8")
|
|
54
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
55
|
+
sys.stderr.reconfigure(encoding="utf-8")
|
|
56
|
+
except AttributeError:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# プロジェクトルートと debug ログのパスはスクリプトファイルからの絶対パスに固定する
|
|
61
|
+
# (planner_check.py と同じ。cwd 依存だと worktree で意図しない場所に作られる)。
|
|
62
|
+
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
63
|
+
DEBUG_LOG_PATH = PROJECT_ROOT / ".claude" / "tmp" / "design_review_count_check_debug.log"
|
|
64
|
+
|
|
65
|
+
# DoS 防御の読み取り上限(planner_check.py と同値)。
|
|
66
|
+
_STDIN_READ_LIMIT_CHARS = 1 * 1024 * 1024 # 1M chars
|
|
67
|
+
_FILE_READ_LIMIT_BYTES = 512 * 1024 # 512 KiB
|
|
68
|
+
|
|
69
|
+
_REPORT_PREFIX = "design-review-report-"
|
|
70
|
+
_REPORT_SUFFIX = ".md"
|
|
71
|
+
|
|
72
|
+
SEVERITIES = ("High", "Medium", "Low")
|
|
73
|
+
TOTAL = "合計"
|
|
74
|
+
_TABLE_LABELS = SEVERITIES + (TOTAL,)
|
|
75
|
+
|
|
76
|
+
# 行頭(先頭空白可)の ``` か ~~~ でフェンスを開閉する。閉じるのは開いたのと同じ文字の
|
|
77
|
+
# フェンスのみ(Markdown の解釈に合わせる。``` の中の ~~~ では閉じない)。
|
|
78
|
+
# コードフェンスの行(CommonMark のフェンスの規則)。開きは 3 文字以上の ` か ~ で、
|
|
79
|
+
# ` のフェンスの info string には ` を含まない。閉じは開きと同じ文字・開き以上の長さで、
|
|
80
|
+
# 後ろは空白だけ(info string 付きの行や短い行は閉じず、フェンスの中身になる)。
|
|
81
|
+
# 字下げはリストの中のフェンスを拾うため制限しない(4 文字以上の字下げをコードブロックとして
|
|
82
|
+
# 扱う規則は、リストの入れ子を追わない本 hook では採らない)。
|
|
83
|
+
_FENCE_RE = re.compile(r"^\s*(`{3,}(?=[^`]*$)|~{3,})(.*)$")
|
|
84
|
+
|
|
85
|
+
# 見出しレベル 3 の `[DC-<ID>]` 直後の括弧(全角・半角)の先頭の重要度(太字可)。
|
|
86
|
+
_HEADING_RE = re.compile(
|
|
87
|
+
r"^###[ \t]+\[DC-[^\]\s]+\][ \t]*[((][ \t]*(?:\*\*)?(High|Medium|Low)(?![A-Za-z])"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# サマリ表のヘッダ: 1 番目のセルが「重要度」・2 番目のセルが「件数」で始まる。
|
|
91
|
+
_TABLE_HEADER_RE = re.compile(r"^\s*\|\s*重要度\s*\|\s*件数[^|]*\|")
|
|
92
|
+
|
|
93
|
+
_NUMBER_RE = re.compile(r"\d+", re.ASCII)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _unfenced_lines(text: str) -> list[str]:
|
|
97
|
+
"""コードフェンスの外の行だけを返す。閉じていないフェンスは末尾まで続く。"""
|
|
98
|
+
out: list[str] = []
|
|
99
|
+
open_fence: str | None = None
|
|
100
|
+
for line in text.splitlines():
|
|
101
|
+
m = _FENCE_RE.match(line)
|
|
102
|
+
if open_fence is None:
|
|
103
|
+
if m:
|
|
104
|
+
open_fence = m.group(1)
|
|
105
|
+
continue
|
|
106
|
+
out.append(line)
|
|
107
|
+
elif (
|
|
108
|
+
m
|
|
109
|
+
and m.group(1)[0] == open_fence[0]
|
|
110
|
+
and len(m.group(1)) >= len(open_fence)
|
|
111
|
+
and not m.group(2).strip()
|
|
112
|
+
):
|
|
113
|
+
open_fence = None
|
|
114
|
+
return out
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _count_headings(lines: list[str]) -> dict:
|
|
118
|
+
counts = {sev: 0 for sev in SEVERITIES}
|
|
119
|
+
for line in lines:
|
|
120
|
+
m = _HEADING_RE.match(line)
|
|
121
|
+
if m:
|
|
122
|
+
counts[m.group(1)] += 1
|
|
123
|
+
return counts
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _split_cells(line: str) -> list[str]:
|
|
127
|
+
body = line.strip()
|
|
128
|
+
if body.startswith("|"):
|
|
129
|
+
body = body[1:]
|
|
130
|
+
if body.endswith("|"):
|
|
131
|
+
body = body[:-1]
|
|
132
|
+
return [cell.strip() for cell in body.split("|")]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _strip_bold(cell: str) -> str:
|
|
136
|
+
if len(cell) >= 4 and cell.startswith("**") and cell.endswith("**"):
|
|
137
|
+
return cell[2:-2].strip()
|
|
138
|
+
return cell
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _read_table(lines: list[str]) -> dict | None:
|
|
142
|
+
"""最初のサマリ表の High/Medium/Low/合計 行の 2 番目のセルを読む。表が無ければ None。"""
|
|
143
|
+
start = None
|
|
144
|
+
for i, line in enumerate(lines):
|
|
145
|
+
if _TABLE_HEADER_RE.match(line):
|
|
146
|
+
start = i
|
|
147
|
+
break
|
|
148
|
+
if start is None:
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
values: dict = {}
|
|
152
|
+
for line in lines[start + 1:]:
|
|
153
|
+
if not line.strip().startswith("|"):
|
|
154
|
+
break # 表の終わり
|
|
155
|
+
cells = _split_cells(line)
|
|
156
|
+
if len(cells) < 2:
|
|
157
|
+
continue
|
|
158
|
+
label = _strip_bold(cells[0])
|
|
159
|
+
if label not in _TABLE_LABELS or label in values:
|
|
160
|
+
continue
|
|
161
|
+
value = _strip_bold(cells[1])
|
|
162
|
+
if _NUMBER_RE.fullmatch(value):
|
|
163
|
+
try:
|
|
164
|
+
values[label] = int(value)
|
|
165
|
+
except ValueError:
|
|
166
|
+
# 桁数が整数文字列変換の上限(sys.get_int_max_str_digits)を超える等。
|
|
167
|
+
# 読めない行として扱う(例外で hook を落とさない)
|
|
168
|
+
pass
|
|
169
|
+
# 数値でない行は無いものとして扱う
|
|
170
|
+
return values
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def check_counts(text: str) -> tuple[bool, dict, dict | None]:
|
|
174
|
+
"""サマリ表の件数と本文の見出しの数を照合する。
|
|
175
|
+
|
|
176
|
+
戻り値は ``(一致か, 見出しの数, 表の値 | None)``。見出しの数は常に High/Medium/Low の
|
|
177
|
+
3 キーを持つ。表の値は読めた行だけを持つ(欠けた行はキーが無い)。
|
|
178
|
+
"""
|
|
179
|
+
lines = _unfenced_lines(text)
|
|
180
|
+
headings = _count_headings(lines)
|
|
181
|
+
table = _read_table(lines)
|
|
182
|
+
|
|
183
|
+
if table is None:
|
|
184
|
+
return sum(headings.values()) == 0, headings, None
|
|
185
|
+
|
|
186
|
+
if any(label not in table for label in _TABLE_LABELS):
|
|
187
|
+
return False, headings, table
|
|
188
|
+
ok = all(table[sev] == headings[sev] for sev in SEVERITIES) and table[TOTAL] == sum(
|
|
189
|
+
headings.values()
|
|
190
|
+
)
|
|
191
|
+
return ok, headings, table
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _format_table(table: dict | None) -> str:
|
|
195
|
+
if table is None:
|
|
196
|
+
return "サマリ表なし"
|
|
197
|
+
parts = [
|
|
198
|
+
f"{label} {table[label]}" if label in table else f"{label} 読めない"
|
|
199
|
+
for label in _TABLE_LABELS
|
|
200
|
+
]
|
|
201
|
+
return " / ".join(parts) # nul-boundary: allow(LLM・人間へ出す表示用の一行。行集合として再パースしない)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _format_headings(headings: dict) -> str:
|
|
205
|
+
parts = [f"{sev} {headings[sev]}" for sev in SEVERITIES]
|
|
206
|
+
parts.append(f"{TOTAL} {sum(headings.values())}")
|
|
207
|
+
return " / ".join(parts) # nul-boundary: allow(LLM・人間へ出す表示用の一行。行集合として再パースしない)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _is_target(path: Path) -> bool:
|
|
211
|
+
# ケース非依存 FS の別名・末尾ドット/スペースは同じ実体を指すため、
|
|
212
|
+
# report_contract_check と同じく norm_component で正規化した basename で判定する
|
|
213
|
+
name = norm_component(path.name)
|
|
214
|
+
return (
|
|
215
|
+
name.startswith(_REPORT_PREFIX)
|
|
216
|
+
and name.endswith(_REPORT_SUFFIX)
|
|
217
|
+
and is_reports_direct_child(path)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def main() -> None:
|
|
222
|
+
try:
|
|
223
|
+
payload = json.loads(sys.stdin.read(_STDIN_READ_LIMIT_CHARS))
|
|
224
|
+
except (json.JSONDecodeError, ValueError):
|
|
225
|
+
sys.exit(0)
|
|
226
|
+
if not isinstance(payload, dict):
|
|
227
|
+
sys.exit(0)
|
|
228
|
+
|
|
229
|
+
if payload.get("tool_name") not in ("Write", "Edit"):
|
|
230
|
+
sys.exit(0)
|
|
231
|
+
|
|
232
|
+
tool_input = payload.get("tool_input")
|
|
233
|
+
if not isinstance(tool_input, dict):
|
|
234
|
+
sys.exit(0)
|
|
235
|
+
file_path = tool_input.get("file_path")
|
|
236
|
+
if not isinstance(file_path, str) or not file_path or "\x00" in file_path:
|
|
237
|
+
sys.exit(0)
|
|
238
|
+
|
|
239
|
+
path = Path(file_path)
|
|
240
|
+
if not _is_target(path):
|
|
241
|
+
sys.exit(0)
|
|
242
|
+
|
|
243
|
+
# 本文はディスクから読み直す(Edit の payload は差分のみで、Write の content も
|
|
244
|
+
# 書き込み後の実体と一致する保証がないため)。
|
|
245
|
+
# 上限はバイトで測る。上限 + 1 バイトまで読み、超えていれば判定しない。
|
|
246
|
+
try:
|
|
247
|
+
with open(file_path, "rb") as fh:
|
|
248
|
+
data = fh.read(_FILE_READ_LIMIT_BYTES + 1)
|
|
249
|
+
except (OSError, ValueError):
|
|
250
|
+
sys.exit(0)
|
|
251
|
+
if len(data) > _FILE_READ_LIMIT_BYTES:
|
|
252
|
+
sys.exit(0)
|
|
253
|
+
try:
|
|
254
|
+
text = data.decode("utf-8")
|
|
255
|
+
except UnicodeDecodeError:
|
|
256
|
+
sys.exit(0)
|
|
257
|
+
|
|
258
|
+
ok, headings, table = check_counts(text)
|
|
259
|
+
basename = path.name
|
|
260
|
+
if ok:
|
|
261
|
+
write_debug_log(DEBUG_LOG_PATH, f"{basename} PASS")
|
|
262
|
+
sys.exit(0)
|
|
263
|
+
|
|
264
|
+
write_debug_log(DEBUG_LOG_PATH, f"{basename} WARN")
|
|
265
|
+
|
|
266
|
+
safe_name = sanitize_for_terminal(basename)
|
|
267
|
+
table_line = _format_table(table)
|
|
268
|
+
headings_line = _format_headings(headings)
|
|
269
|
+
|
|
270
|
+
print(
|
|
271
|
+
f"[DesignReviewCount WARN] {safe_name}: サマリ表の件数と本文の指摘見出しの数が"
|
|
272
|
+
"食い違っています。\n"
|
|
273
|
+
f" サマリ表: {table_line}\n"
|
|
274
|
+
f" 本文の見出し: {headings_line}",
|
|
275
|
+
file=sys.stderr,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
additional_context = sanitize_for_terminal(
|
|
279
|
+
f"[DesignReviewCount WARN] {safe_name} のサマリ表の件数と本文の指摘見出し"
|
|
280
|
+
"(### [DC-...](重要度…))の数が食い違っています。"
|
|
281
|
+
) + "\n" + (
|
|
282
|
+
f"- サマリ表の値: {table_line}\n"
|
|
283
|
+
f"- 本文の見出しの数: {headings_line}\n"
|
|
284
|
+
"このレポートを書いた本人なら、サマリ表を本文の見出しの数に合わせて Edit で直すこと"
|
|
285
|
+
"(自分が付けた見出しの重要度の方が誤記なら、その重要度表記に限って見出しを直す)。"
|
|
286
|
+
"書いた本人でない(裁定する親など)なら、サマリ表を書き換えず、"
|
|
287
|
+
"件数は本文の見出しから数えて使うこと。"
|
|
288
|
+
)
|
|
289
|
+
output = {
|
|
290
|
+
"hookSpecificOutput": {
|
|
291
|
+
"hookEventName": "PostToolUse",
|
|
292
|
+
"additionalContext": additional_context,
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
print(json.dumps(output, ensure_ascii=False))
|
|
296
|
+
sys.exit(0)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
if __name__ == "__main__":
|
|
300
|
+
main()
|
{claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/report_contract_check.py
RENAMED
|
@@ -56,6 +56,7 @@ from pathlib import Path
|
|
|
56
56
|
# PYTHONPATH に追加する。
|
|
57
57
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
58
58
|
from _hook_utils import ( # noqa: E402
|
|
59
|
+
is_reports_direct_child,
|
|
59
60
|
norm_component,
|
|
60
61
|
sanitize_for_terminal,
|
|
61
62
|
STRICT4_PREFIXES,
|
|
@@ -147,16 +148,12 @@ def main():
|
|
|
147
148
|
# `.claude/reports/` 直下かどうかの判定
|
|
148
149
|
path_obj = Path(file_path)
|
|
149
150
|
basename = path_obj.name
|
|
150
|
-
parent = path_obj.parent
|
|
151
151
|
|
|
152
152
|
# 構造判定: 親が `reports` かつ祖父が `.claude`(= `.claude/reports/` 直下)。
|
|
153
|
-
#
|
|
154
|
-
# ケース非依存 FS(Windows・macOS)では `.CLAUDE` や `REPORTS` は `.claude` / `reports` と
|
|
155
|
-
# 同一実体の別名のため、比較は norm_component() で正規化してから行う。
|
|
156
|
-
# Windows の末尾ドット・スペースも norm_component() が除去する。
|
|
153
|
+
# 判定は _hook_utils.is_reports_direct_child() に集約(norm_component 正規化・resolve なし)。
|
|
157
154
|
# 例: `/foo/.claude/reports/plan-report-20260725-180252.md` → 対象
|
|
158
155
|
# 例: `/foo/.claude/reports/archive/plan-report-final.md` → 対象外(直下でない)
|
|
159
|
-
if
|
|
156
|
+
if not is_reports_direct_child(path_obj):
|
|
160
157
|
sys.exit(0)
|
|
161
158
|
|
|
162
159
|
# basename を正規化(ケース非依存化・末尾ドット/スペース除去)してから prefix 判定。
|
{claude_code_conductor-2.83.0 → claude_code_conductor-2.85.0}/.claude/hooks/report_path_guard.py
RENAMED
|
@@ -44,14 +44,17 @@ report_contract_check.py と統一したポリシー: **prefix 一致判定は
|
|
|
44
44
|
`norm_component()` 正規化後の basename・形式(timestamp フルマッチ)判定は
|
|
45
45
|
元の basename** に対して行う。これにより大文字混じり prefix(`Plan-Report-`)は
|
|
46
46
|
prefix 一致として検出しつつ、`.MD` のような大文字混じり拡張子は timestamp 形式として
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
誤許可しない(strict-4 なら検査 3 で block する)。既存の上書きの判定(検査 2)だけは、
|
|
48
|
+
書き込み先の名前でなく既存の実体の名前で行う(下記)。
|
|
49
49
|
|
|
50
50
|
## 検査 2: 上書き block
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
書き込み先の実体が既存で、その**実体の名前**(親ディレクトリの項目のうち書き込み先と
|
|
53
|
+
`os.path.samefile` で一致するものの名前)が timestamp 形式(prefix +
|
|
54
|
+
`\\d{8}-\\d{6}\\.md` の `re.ASCII` フルマッチ)→ block。ケース非依存 FS の大文字混じり名や、
|
|
55
|
+
末尾のドットを落とす FS の `.md.` のように、書き込み先の名前が timestamp 形式でなくても
|
|
56
|
+
既存の timestamp 形式のレポートと同じ実体に届く別名を、ここで止める。task_id 形式
|
|
57
|
+
(非 timestamp)の既存上書きは許可する(同一 task の再実行で更新する正規経路のため)。
|
|
55
58
|
|
|
56
59
|
## 検査 3: strict-4 形式 block
|
|
57
60
|
|
|
@@ -82,6 +85,7 @@ from pathlib import Path
|
|
|
82
85
|
# PYTHONPATH に追加する。
|
|
83
86
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
84
87
|
from _hook_utils import ( # noqa: E402
|
|
88
|
+
is_reports_direct_child,
|
|
85
89
|
norm_component,
|
|
86
90
|
sanitize_for_terminal,
|
|
87
91
|
STRICT4_PREFIXES,
|
|
@@ -132,6 +136,28 @@ def _is_timestamp_name(basename, prefix):
|
|
|
132
136
|
return timestamp_pattern(prefix).fullmatch(basename) is not None
|
|
133
137
|
|
|
134
138
|
|
|
139
|
+
def _existing_entity_name(target):
|
|
140
|
+
"""書き込み先の実体が既存ならその実体の名前を、無ければ None を返す。
|
|
141
|
+
|
|
142
|
+
書き込み先の名前は別名(ケース非依存 FS の大文字混じり名・末尾ドット等)でありうるので、
|
|
143
|
+
親ディレクトリの項目から書き込み先と同じ実体のものを探す。実体が既存なのに項目が
|
|
144
|
+
見つからないときは書き込み先の名前を返す。
|
|
145
|
+
"""
|
|
146
|
+
path = str(target)
|
|
147
|
+
if not os.path.exists(path):
|
|
148
|
+
return None
|
|
149
|
+
with os.scandir(os.path.dirname(path)) as entries:
|
|
150
|
+
for entry in entries:
|
|
151
|
+
try:
|
|
152
|
+
same = os.path.samefile(entry.path, path)
|
|
153
|
+
except OSError:
|
|
154
|
+
# 壊れたリンク等の無関係な項目で全体を止めない
|
|
155
|
+
continue
|
|
156
|
+
if same:
|
|
157
|
+
return entry.name
|
|
158
|
+
return os.path.basename(path)
|
|
159
|
+
|
|
160
|
+
|
|
135
161
|
def _allowed_roots():
|
|
136
162
|
"""許可 root(root A / root B)の候補パスを返す。
|
|
137
163
|
|
|
@@ -157,10 +183,8 @@ def _is_contained(target):
|
|
|
157
183
|
"""target が許可 root 直下に封じ込められているか(二層 AND)。"""
|
|
158
184
|
# 第 1 層: 名前判定(`.claude/reports/` 直下の形をしているか)。
|
|
159
185
|
# `..` を含む脱出パスは親の名前が `..` になるためここで落ちる。
|
|
160
|
-
|
|
161
|
-
if
|
|
162
|
-
return False
|
|
163
|
-
if norm_component(parent.parent.name) != CLAUDE_DIR_NAME:
|
|
186
|
+
# 判定は _hook_utils.is_reports_direct_child() に集約(norm_component 正規化)。
|
|
187
|
+
if not is_reports_direct_child(target):
|
|
164
188
|
return False
|
|
165
189
|
|
|
166
190
|
# 第 2 層: 実体照合(リンク偽装で名前だけ揃えた経路をここで落とす)。
|
|
@@ -266,8 +290,9 @@ def main():
|
|
|
266
290
|
|
|
267
291
|
is_timestamp = _is_timestamp_name(raw_basename, prefix)
|
|
268
292
|
|
|
269
|
-
# 検査 2: 上書き block
|
|
270
|
-
|
|
293
|
+
# 検査 2: 上書き block(実体の名前が timestamp 形式の既存のみ)
|
|
294
|
+
existing_name = _existing_entity_name(target)
|
|
295
|
+
if existing_name is not None and _is_timestamp_name(existing_name, prefix):
|
|
271
296
|
_block_overwrite(display_name)
|
|
272
297
|
|
|
273
298
|
# 検査 3: strict-4 形式 block
|
|
@@ -150,6 +150,11 @@
|
|
|
150
150
|
"type": "command",
|
|
151
151
|
"command": "c3",
|
|
152
152
|
"args": ["run", "${CLAUDE_PROJECT_DIR}/.claude/hooks/report_contract_check.py"]
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"type": "command",
|
|
156
|
+
"command": "c3",
|
|
157
|
+
"args": ["run", "${CLAUDE_PROJECT_DIR}/.claude/hooks/design_review_count_check.py"]
|
|
153
158
|
}
|
|
154
159
|
]
|
|
155
160
|
},
|
|
@@ -165,6 +170,11 @@
|
|
|
165
170
|
"type": "command",
|
|
166
171
|
"command": "c3",
|
|
167
172
|
"args": ["run", "${CLAUDE_PROJECT_DIR}/.claude/hooks/planner_check.py"]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"type": "command",
|
|
176
|
+
"command": "c3",
|
|
177
|
+
"args": ["run", "${CLAUDE_PROJECT_DIR}/.claude/hooks/design_review_count_check.py"]
|
|
168
178
|
}
|
|
169
179
|
]
|
|
170
180
|
}
|