claude-code-conductor 2.11.0__tar.gz → 2.12.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.
Files changed (162) hide show
  1. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/settings.json +3 -0
  2. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/dev-workflow/SKILL.md +10 -10
  3. claude_code_conductor-2.12.0/.claude/skills/dev-workflow/scripts/record_review_decision.py +138 -0
  4. {claude_code_conductor-2.11.0/.claude/hooks → claude_code_conductor-2.12.0/.claude/skills/dev-workflow/scripts}/record_tier_outcome.py +34 -7
  5. {claude_code_conductor-2.11.0/.claude/hooks → claude_code_conductor-2.12.0/.claude/skills/dev-workflow/scripts}/review_hint_inject.py +67 -9
  6. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/mcp-config/SKILL.md +5 -0
  7. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/CHANGELOG.md +58 -0
  8. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/PKG-INFO +1 -1
  9. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/__init__.py +1 -1
  10. claude_code_conductor-2.12.0/tests/hooks/test_record_review_decision.py +239 -0
  11. claude_code_conductor-2.12.0/tests/hooks/test_record_tier_outcome.py +505 -0
  12. claude_code_conductor-2.12.0/tests/hooks/test_review_hint_inject.py +625 -0
  13. claude_code_conductor-2.11.0/.claude/hooks/record_review_decision.py +0 -73
  14. claude_code_conductor-2.11.0/.claude/hooks/subagent_log.py +0 -227
  15. claude_code_conductor-2.11.0/tests/hooks/test_record_tier_outcome.py +0 -291
  16. claude_code_conductor-2.11.0/tests/hooks/test_review_hint_inject.py +0 -356
  17. claude_code_conductor-2.11.0/tests/hooks/test_subagent_log.py +0 -1030
  18. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/CLAUDE.md +0 -0
  19. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/architect.md +0 -0
  20. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/code-reviewer.md +0 -0
  21. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/developer.md +0 -0
  22. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/doc-writer.md +0 -0
  23. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/interviewer.md +0 -0
  24. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/planner.md +0 -0
  25. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/project-setup.md +0 -0
  26. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/security-reviewer.md +0 -0
  27. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/systematic-debugger.md +0 -0
  28. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/tester.md +0 -0
  29. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/wt_developer.md +0 -0
  30. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/wt_systematic-debugger.md +0 -0
  31. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/agents/wt_tester.md +0 -0
  32. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/docs/platform-adapters.md +0 -0
  33. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/docs/settings.json.md +0 -0
  34. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/consolidate_memory.py +0 -0
  35. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/permission_handler.py +0 -0
  36. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/permission_handler_toast.py +0 -0
  37. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/post_tool.py +0 -0
  38. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/pre_compact.py +0 -0
  39. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/pre_tool.py +0 -0
  40. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/recall_inject.py +0 -0
  41. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/restore_session.py +0 -0
  42. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/schema.sql +0 -0
  43. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/select_tier.py +0 -0
  44. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/session_start.py +0 -0
  45. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/session_stop.py +0 -0
  46. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/session_utils.py +0 -0
  47. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/statusline.py +0 -0
  48. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/stop.py +0 -0
  49. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/hooks/worktree_guard.py +0 -0
  50. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/memory/.gitkeep +0 -0
  51. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/permission_rules.json +0 -0
  52. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/rules/code-review-checklist.md +0 -0
  53. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/rules/promoted/index.md +0 -0
  54. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/rules/security-review-checklist.md +0 -0
  55. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/code-review/SKILL.md +0 -0
  56. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/codex-review/SKILL.md +0 -0
  57. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/develop/SKILL.md +0 -0
  58. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/doc/SKILL.md +0 -0
  59. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/extract-lib/SKILL.md +0 -0
  60. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/init-session/SKILL.md +0 -0
  61. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/parallel-agents/SKILL.md +0 -0
  62. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/pattern-status/SKILL.md +0 -0
  63. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
  64. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/recall/SKILL.md +0 -0
  65. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
  66. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
  67. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/setup/SKILL.md +0 -0
  68. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/skills/start/SKILL.md +0 -0
  69. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.claude/state/.gitkeep +0 -0
  70. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/.gitignore +0 -0
  71. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSE +0 -0
  72. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/chroma-hnswlib-LICENSE +0 -0
  73. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/chroma-hnswlib-NOTICE +0 -0
  74. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/fastembed-LICENSE +0 -0
  75. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/fastembed-NOTICE +0 -0
  76. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/onnxruntime-LICENSE +0 -0
  77. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/LICENSES/paraphrase-multilingual-MiniLM-L12-v2-LICENSE +0 -0
  78. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/README.md +0 -0
  79. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/hatch_build.py +0 -0
  80. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/pyproject.toml +0 -0
  81. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/__main__.py +0 -0
  82. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/_excludes.py +0 -0
  83. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/_terminal.py +0 -0
  84. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/adapters.py +0 -0
  85. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli.py +0 -0
  86. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_ask.py +0 -0
  87. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_doctor.py +0 -0
  88. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_init.py +0 -0
  89. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_list.py +0 -0
  90. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_plan.py +0 -0
  91. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_recall.py +0 -0
  92. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_tier.py +0 -0
  93. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/cli_update.py +0 -0
  94. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/db.py +0 -0
  95. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/embedding.py +0 -0
  96. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/mcp_server.py +0 -0
  97. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/paths.py +0 -0
  98. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/plan_validator.py +0 -0
  99. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/platforms.py +0 -0
  100. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/question.py +0 -0
  101. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/recall_chunker.py +0 -0
  102. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/src/c3/recall_index.py +0 -0
  103. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/__init__.py +0 -0
  104. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/conftest.py +0 -0
  105. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/__init__.py +0 -0
  106. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_consolidate_memory.py +0 -0
  107. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_permission_handler.py +0 -0
  108. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_permission_handler_toast.py +0 -0
  109. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_pip_reinstall_reminder.py +0 -0
  110. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_planner_check.py +0 -0
  111. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_post_tool.py +0 -0
  112. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_pre_tool.py +0 -0
  113. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_recall_inject.py +0 -0
  114. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_restore_session.py +0 -0
  115. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_select_tier.py +0 -0
  116. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_select_tier_escalation.py +0 -0
  117. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_session_start.py +0 -0
  118. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_session_stop.py +0 -0
  119. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_session_utils.py +0 -0
  120. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_settings_local_absolute_paths.py +0 -0
  121. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_similarity_boost.py +0 -0
  122. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_statusline.py +0 -0
  123. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_statusline_template_sync.py +0 -0
  124. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_sync_check.py +0 -0
  125. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/hooks/test_template_guard.py +0 -0
  126. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/__init__.py +0 -0
  127. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/_skill_helpers.py +0 -0
  128. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_dev_workflow_no_task_type.py +0 -0
  129. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_init_session_no_task_type.py +0 -0
  130. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_recall_skill.py +0 -0
  131. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_session_backlog_reconciliation.py +0 -0
  132. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_start_skill_bugfix_flow.py +0 -0
  133. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_start_skill_new_flow.py +0 -0
  134. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/skills/test_start_skill_security_audit_phase.py +0 -0
  135. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_adapters.py +0 -0
  136. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_ask.py +0 -0
  137. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_entry.py +0 -0
  138. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_init.py +0 -0
  139. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_list.py +0 -0
  140. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_plan.py +0 -0
  141. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_recall.py +0 -0
  142. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_cli_tier.py +0 -0
  143. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_docstring_consistency.py +0 -0
  144. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_embedding.py +0 -0
  145. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_excludes.py +0 -0
  146. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_mcp_server_elicit.py +0 -0
  147. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_paths.py +0 -0
  148. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_plan_validator.py +0 -0
  149. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_pre_compact.py +0 -0
  150. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_pre_tool_hook.py +0 -0
  151. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_precompact_additional.py +0 -0
  152. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_precompact_toctou_fixes.py +0 -0
  153. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_recall_chunker.py +0 -0
  154. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_recall_index.py +0 -0
  155. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_session_utils_additional.py +0 -0
  156. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_statusline.py +0 -0
  157. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_stop_additional.py +0 -0
  158. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_stop_hook.py +0 -0
  159. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_stop_precompact_fixes.py +0 -0
  160. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_sync_template_stop.py +0 -0
  161. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_template_pre_tool_hook.py +0 -0
  162. {claude_code_conductor-2.11.0 → claude_code_conductor-2.12.0}/tests/test_worktree_guard.py +0 -0
@@ -7,6 +7,9 @@
7
7
  "Bash(python .claude/hooks/restore_session.py*)",
8
8
  "Bash(python .claude/hooks/permission_handler.py*)",
9
9
  "Bash(python .claude/hooks/statusline.py*)",
10
+ "Bash(python .claude/skills/dev-workflow/scripts/review_hint_inject.py*)",
11
+ "Bash(python .claude/skills/dev-workflow/scripts/record_review_decision.py*)",
12
+ "Bash(python .claude/skills/dev-workflow/scripts/record_tier_outcome.py*)",
10
13
  "Read(**)",
11
14
  "Glob(**)",
12
15
  "Grep(**)",
@@ -406,10 +406,10 @@ AskUserQuestion で確認する:
406
406
  Agent ツールで `code-reviewer` エージェントを起動する。
407
407
 
408
408
  **review-hint 過去判断ヒント注入(レポート生成後):**
409
- code-reviewer がレポートを Write し終えたら、Bash で `.claude/hooks/review_hint_inject.py` を呼んで過去判断ヒントをレポート末尾に追記する:
409
+ code-reviewer がレポートを Write し終えたら、Bash で `.claude/skills/dev-workflow/scripts/review_hint_inject.py` を呼んで過去判断ヒントをレポート末尾に追記する:
410
410
 
411
411
  ```bash
412
- python .claude/hooks/review_hint_inject.py .claude/reports/code-review-report-{timestamp}.md
412
+ python .claude/skills/dev-workflow/scripts/review_hint_inject.py .claude/reports/code-review-report-{timestamp}.md
413
413
  ```
414
414
 
415
415
  ヒントは独立セクションとして追加されるだけで、code-reviewer の指摘本文は変更されない。
@@ -465,7 +465,7 @@ AskUserQuestion で確認する:
465
465
  2. 許容する指摘の直下に `> **[許容]** {理由}` を Edit で追記する(検出記録は削除しない)
466
466
  3. **review-hint 判断記録**: 各指摘について Bash で c3.db に記録する(`[CR-XX-NNN]` を含むもののみ。`[CR-NEW]` は記録対象外、チェックリスト追加候補として別途扱う):
467
467
  ```bash
468
- python .claude/hooks/record_review_decision.py \
468
+ python .claude/skills/dev-workflow/scripts/record_review_decision.py \
469
469
  --checklist-id CR-Q-001 \
470
470
  --finding "{指摘本文を 1 行で}" \
471
471
  --decision {fixed|accepted} \
@@ -500,10 +500,10 @@ AskUserQuestion で許容理由を確認する:
500
500
  Agent ツールで `security-reviewer` エージェントを起動する。
501
501
 
502
502
  **review-hint 過去判断ヒント注入(レポート生成後):**
503
- security-reviewer がレポートを Write し終えたら、Bash で `.claude/hooks/review_hint_inject.py` に **両レポートのパス** を渡して呼ぶ。両方渡すことで重複指摘フラグ(同じ checklist_id を CR と SR が指摘)が判定される:
503
+ security-reviewer がレポートを Write し終えたら、Bash で `.claude/skills/dev-workflow/scripts/review_hint_inject.py` に **両レポートのパス** を渡して呼ぶ。両方渡すことで重複指摘フラグ(同じ checklist_id を CR と SR が指摘)が判定される:
504
504
 
505
505
  ```bash
506
- python .claude/hooks/review_hint_inject.py \
506
+ python .claude/skills/dev-workflow/scripts/review_hint_inject.py \
507
507
  .claude/reports/code-review-report-{ts1}.md \
508
508
  .claude/reports/security-review-report-{ts2}.md
509
509
  ```
@@ -530,7 +530,7 @@ AskUserQuestion で確認する:
530
530
  承認後 → セッションファイルの `- [ ] security-review` を `- [x]` に Edit する。続けて **「引き継ぎバックログの照合」**(後述の共通ステップ)を実行してからコミットを提案する。
531
531
  **tier-routing 結果記録**: フェーズ E の最終承認時のみ Bash で記録する(多重カウント防止のため E-1 では記録しない):
532
532
  ```bash
533
- python .claude/hooks/record_tier_outcome.py --outcome success
533
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome success
534
534
  ```
535
535
 
536
536
  **指摘がある場合:**
@@ -565,7 +565,7 @@ python .claude/hooks/record_tier_outcome.py --outcome success
565
565
  2. 許容する指摘の直下に `> **[許容]** {理由}` を Edit で追記する(検出記録は削除しない)
566
566
  3. **review-hint 判断記録**: 各指摘について Bash で c3.db に記録する(`[SR-XX-NNN]` を含むもののみ。`[SR-NEW]` は記録対象外、チェックリスト追加候補として別途扱う):
567
567
  ```bash
568
- python .claude/hooks/record_review_decision.py \
568
+ python .claude/skills/dev-workflow/scripts/record_review_decision.py \
569
569
  --checklist-id SR-K-002 \
570
570
  --finding "{指摘本文を 1 行で}" \
571
571
  --decision {fixed|accepted} \
@@ -590,7 +590,7 @@ AskUserQuestion で許容理由を確認する:
590
590
  4. セッションファイルの `- [ ] security-review` を `- [x]` に Edit する。続けて **「引き継ぎバックログの照合」**(後述の共通ステップ)を実行してからコミットを提案する。
591
591
  5. **tier-routing 結果記録**: 全許容で完了するのも「成功」としてカウント:
592
592
  ```bash
593
- python .claude/hooks/record_tier_outcome.py --outcome success
593
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome success
594
594
  ```
595
595
 
596
596
  **「否認・再診断を依頼する」の場合:**
@@ -598,13 +598,13 @@ AskUserQuestion で許容理由を確認する:
598
598
  セッションファイルの `## 試みたが失敗したアプローチ` に教訓をルール形式で追記し `patterns` に追加する。
599
599
  **tier-routing 結果記録**: 否認は「失敗」としてカウント:
600
600
  ```bash
601
- python .claude/hooks/record_tier_outcome.py --outcome failure
601
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome failure
602
602
  ```
603
603
 
604
604
  **「全て対応する」「対応する指摘を選ぶ」の場合(フェーズ C へ戻る):**
605
605
  これらも tier の選択がコスト最適でなかったとみなし、**tier-routing 結果記録**で失敗をカウントしてからフェーズ C へ:
606
606
  ```bash
607
- python .claude/hooks/record_tier_outcome.py --outcome failure
607
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome failure
608
608
  ```
609
609
 
610
610
  ---
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env python3
2
+ """CLI: record a review decision in c3.db.review_decisions.
3
+
4
+ review-hint: dev-workflow フェーズ E でユーザーが「対応 / 許容 / 保留」を選んだ
5
+ 判断を SQLite に記録するための薄い CLI ラッパー。実装本体は
6
+ ``c3.db.insert_review_decision``。
7
+
8
+ Usage:
9
+ python .claude/skills/dev-workflow/scripts/record_review_decision.py \
10
+ --checklist-id CR-Q-001 \
11
+ --finding "関数が長い" \
12
+ --decision accepted \
13
+ --reason "既存スタイルを尊重するため" \
14
+ --reviewer code-reviewer
15
+
16
+ Exit code:
17
+ 0: 記録成功 / DB が無く何もしなかった(呼び出し元を止めない方針)
18
+ 2: 引数不正(argparse のエラー時)
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import re
25
+ import sys
26
+
27
+
28
+ # checklist_id 形式検証用の正規表現([CR-XX-NNN] / [SR-XX-NNN]、連番 3 桁以上)[SR-V-001]。
29
+ # review_hint_inject.py の CHECKLIST_ID_RE と整合([ ] なし)。
30
+ CHECKLIST_ID_PATTERN = re.compile(r"^(CR|SR)-[A-Z]+-\d{3,}$")
31
+
32
+
33
+ # DB 肥大化防止のためのフィールド長上限 [SR-V-001]。
34
+ # 文字数 / バイト数の両方を上限として切り詰める(呼び出し元を止めない方針)。
35
+ # サロゲートペア・絵文字等で UTF-8 バイト長が文字長を大きく超えるケースを防ぐ。
36
+ MAX_FINDING_LEN = 2000 # 文字数上限
37
+ MAX_REASON_LEN = 2000
38
+ MAX_CONTEXT_LEN = 1000
39
+ MAX_FIELD_BYTES = 8 * 1024 # 全フィールド共通バイト数上限(8 KB)
40
+
41
+
42
+ def _truncate(value: str | None, limit: int, name: str) -> str | None:
43
+ """value が文字数 limit 超または UTF-8 バイト数 MAX_FIELD_BYTES 超なら切り詰めて警告を出す。
44
+
45
+ None / 空文字列はそのまま返す。文字数で切ったあともバイト数を再確認し、
46
+ 両条件で安全になるまで切り詰める(BMP 外文字対応)。
47
+
48
+ NOTE: 現在の定数(MAX_FINDING_LEN=2000・MAX_FIELD_BYTES=8192)では、
49
+ BMP 外の 4 バイト UTF-8 文字 2000 個でも 8000 バイトしか消費しないため、
50
+ 文字数で切った後の while ループは実質的に発火しない(防御的残置)。
51
+ 将来 MAX_*_LEN を引き上げる場合に備えて while を残してある。
52
+ 定数を変更する際は両条件の整合(MAX_LEN * 4 > MAX_FIELD_BYTES)を必ず確認すること。
53
+
54
+ パフォーマンス: while ループ最悪計算量は O(N^2)(N=文字数)であり、入力長が
55
+ 数十 MB のオーダーで遅くなる。ローカル CLI 前提・上記の通り通常入力では
56
+ そもそも while に入らないため許容。本来高速化するなら bytes 単位で 2 分探索する。
57
+ """
58
+ if not value:
59
+ return value
60
+ truncated = False
61
+ if len(value) > limit:
62
+ value = value[:limit]
63
+ truncated = True
64
+ byte_len = len(value.encode("utf-8"))
65
+ while byte_len > MAX_FIELD_BYTES:
66
+ value = value[: max(1, len(value) - 1)]
67
+ byte_len = len(value.encode("utf-8"))
68
+ truncated = True
69
+ if truncated:
70
+ print(
71
+ f"[record_review_decision] --{name} truncated to {len(value)} chars / "
72
+ f"{byte_len} bytes",
73
+ file=sys.stderr,
74
+ )
75
+ return value
76
+
77
+
78
+ def main(argv: list[str] | None = None) -> int:
79
+ parser = argparse.ArgumentParser(description="Record a review decision in c3.db")
80
+ parser.add_argument("--checklist-id", required=True,
81
+ help="例: CR-Q-001 / SR-K-002")
82
+ parser.add_argument("--finding", required=True,
83
+ help=f"指摘本文(後の参照用、最大 {MAX_FINDING_LEN} 文字で切り詰め)")
84
+ parser.add_argument("--decision", required=True,
85
+ choices=["fixed", "accepted", "deferred"],
86
+ help="判断")
87
+ parser.add_argument("--reason", default=None,
88
+ help=f"許容/保留時の理由(最大 {MAX_REASON_LEN} 文字で切り詰め)")
89
+ parser.add_argument("--context", default=None,
90
+ help=f"ファイル名・コミット等の補助情報(最大 {MAX_CONTEXT_LEN} 文字で切り詰め)")
91
+ parser.add_argument("--reviewer", required=True,
92
+ choices=["code-reviewer", "security-reviewer"],
93
+ help="どちらの reviewer の指摘か")
94
+
95
+ args = parser.parse_args(argv)
96
+
97
+ # checklist-id 形式検証(不正な値は DB に蓄積させず skip。CR-NEW / SR-NEW は対象外として除外)
98
+ # [SR-V-001] 不正な ID が DB に入ると review-hint 照合が空振りするため insert を中止する
99
+ if args.checklist_id not in ("CR-NEW", "SR-NEW") and not CHECKLIST_ID_PATTERN.match(args.checklist_id):
100
+ print(
101
+ f"[record_review_decision] --checklist-id format invalid (skipped): {args.checklist_id!r} "
102
+ f"(expected pattern: CR-XX-NNN or SR-XX-NNN)",
103
+ file=sys.stderr,
104
+ )
105
+ return 0
106
+
107
+ # 長さ上限を適用(DB 肥大化防止)
108
+ args.finding = _truncate(args.finding, MAX_FINDING_LEN, "finding")
109
+ args.reason = _truncate(args.reason, MAX_REASON_LEN, "reason")
110
+ args.context = _truncate(args.context, MAX_CONTEXT_LEN, "context")
111
+
112
+ try:
113
+ from c3.db import insert_review_decision
114
+ except ImportError as exc:
115
+ print(f"[record_review_decision] c3.db import failed: {exc}",
116
+ file=sys.stderr)
117
+ return 0 # 呼び出し元を止めない
118
+
119
+ ok = insert_review_decision(
120
+ checklist_id=args.checklist_id,
121
+ finding_text=args.finding,
122
+ decision=args.decision,
123
+ reason=args.reason,
124
+ context_summary=args.context,
125
+ reviewer=args.reviewer,
126
+ )
127
+ if not ok:
128
+ # 失敗は警告のみ(DB 不在等で C3 利用先で頻繁に起きうる)
129
+ print(
130
+ f"[record_review_decision] not recorded "
131
+ f"(DB unavailable?): {args.checklist_id}",
132
+ file=sys.stderr,
133
+ )
134
+ return 0
135
+
136
+
137
+ if __name__ == "__main__":
138
+ sys.exit(main())
@@ -7,8 +7,8 @@ tier-routing MVP: dev-workflow フェーズ E の承認/否認シグナルを受
7
7
  更新する。
8
8
 
9
9
  Usage:
10
- python .claude/hooks/record_tier_outcome.py --outcome success
11
- python .claude/hooks/record_tier_outcome.py --outcome failure
10
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome success
11
+ python .claude/skills/dev-workflow/scripts/record_tier_outcome.py --outcome failure
12
12
 
13
13
  設計のポイント:
14
14
  - 1 引数のみ(``--outcome``)にして dev-workflow から呼びやすくする。
@@ -20,6 +20,7 @@ Usage:
20
20
  from __future__ import annotations
21
21
 
22
22
  import argparse
23
+ import collections
23
24
  import json
24
25
  import os
25
26
  import sys
@@ -33,8 +34,23 @@ try:
33
34
  except AttributeError:
34
35
  pass
35
36
 
36
- _HOOKS_DIR = os.path.dirname(os.path.abspath(__file__))
37
- _CLAUDE_DIR = os.path.dirname(_HOOKS_DIR)
37
+ # このファイルは .claude/skills/dev-workflow/scripts/ に置かれている前提。
38
+ # 上位 3 階層を遡って .claude/ ディレクトリを得る:
39
+ # scripts/ → dev-workflow/ → skills/ → .claude/
40
+ _SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
41
+ _CLAUDE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(_SCRIPT_DIR)))
42
+ # 3 階層遡りで `.claude` に到達することを実行時に検証。
43
+ # 将来スクリプトが別階層に移動された場合のサイレント破綻を防ぐ。
44
+ #
45
+ # 注: これはセキュリティ防御ではなく、スクリプトの誤配置(ディレクトリ階層変更・
46
+ # 移動忘れ等)を実行時に検出するための開発時チェック。外部攻撃者がディレクトリ
47
+ # 構造を制御できる脅威モデルは前提としていない([SR-NEW])。
48
+ # `assert` は `python -O` で無効化されるため、RuntimeError で明示的に投げる。
49
+ if not (_CLAUDE_DIR.endswith(os.sep + ".claude") or _CLAUDE_DIR.endswith("/.claude")):
50
+ raise RuntimeError(
51
+ f"_CLAUDE_DIR resolution broke: expected to end with '.claude' but got {_CLAUDE_DIR!r}. "
52
+ "Check that this file is at .claude/skills/dev-workflow/scripts/."
53
+ )
38
54
  TIER_SELECTION_PATH = os.path.join(_CLAUDE_DIR, "state", "tier_selection.json")
39
55
  # Phase 2-C: prompt 履歴ファイル(select_tier.py が読む類似度推定の母数)。
40
56
  PROMPT_HISTORY_PATH = os.path.join(_CLAUDE_DIR, "logs", "prompt-history.jsonl")
@@ -107,9 +123,8 @@ def _rotate_prompt_history_if_needed() -> None:
107
123
  return
108
124
  try:
109
125
  # 末尾 N 行のみ deque で保持して上書きする(ファイル全体は走査するが I/O のみ)
110
- import collections as _c
111
126
  with open(PROMPT_HISTORY_PATH, "r", encoding="utf-8") as f:
112
- tail = list(_c.deque(f, maxlen=_PROMPT_HISTORY_TRUNCATE_LINES))
127
+ tail = list(collections.deque(f, maxlen=_PROMPT_HISTORY_TRUNCATE_LINES))
113
128
  tmp_path = PROMPT_HISTORY_PATH + ".tmp"
114
129
  with open(tmp_path, "w", encoding="utf-8") as f:
115
130
  f.writelines(tail)
@@ -143,8 +158,20 @@ def _append_prompt_history(selection: dict, success: bool) -> None:
143
158
  try:
144
159
  os.makedirs(os.path.dirname(PROMPT_HISTORY_PATH), exist_ok=True)
145
160
  _rotate_prompt_history_if_needed()
161
+ line = json.dumps(record, ensure_ascii=False)
162
+ # JSONL 互換性: U+2028 (LINE SEPARATOR) / U+2029 (PARAGRAPH SEPARATOR) を
163
+ # ECMAScript パーサが行区切りと解釈するため事前にエスケープする [SR-V-001]。
164
+ # NOTE: ソースコード上は escape 表記で識谞し、実体文字を埋め込まない
165
+ # (Cycle 3 M-01 / Cycle 4 H-01 の回帰防止。)
166
+ _LS = chr(0x2028) # LINE SEPARATOR
167
+ _PS = chr(0x2029) # PARAGRAPH SEPARATOR
168
+ # The second arg must be the 6-char ASCII string '\u2028' (literal backslash + 'u2028'),
169
+ # NOT the actual U+2028 char. In Python a normal string "\u2028" evaluates to the
170
+ # 1-char separator, but raw string r"\u2028" keeps the backslash literal, giving the
171
+ # 6-char escape sequence that JSON consumers need. Do NOT remove the r-prefix.
172
+ line = line.replace(_LS, r"\u2028").replace(_PS, r"\u2029")
146
173
  with open(PROMPT_HISTORY_PATH, "a", encoding="utf-8") as f:
147
- f.write(json.dumps(record, ensure_ascii=False) + "\n")
174
+ f.write(line + "\n")
148
175
  except OSError as exc:
149
176
  print(
150
177
  f"[record_tier_outcome] prompt-history append skipped: {exc}",
@@ -18,6 +18,14 @@ review-hint: レビュー判断ヒント機能。code-reviewer / security-review
18
18
  出力:
19
19
  - 指定された各レポートの末尾に「## 過去判断ヒント」セクションを追記
20
20
  - exit code: 0 (失敗してもセッションを止めない方針)
21
+
22
+ セキュリティ注記:
23
+ - 引数はファイルシステム上の実在するパスのみ受け付ける(`p.is_file()` チェック済み)。
24
+ 存在しないパス・ディレクトリは警告を出してスキップする。
25
+ - URL エンコードは解除しない。`%2e%2e` 等のリテラル文字列はディレクトリ名として
26
+ そのまま扱われる(パスは `Path.resolve()` → `relative_to(ALLOWED_REPORT_DIR)` で
27
+ 正規化後に .claude/reports/ 配下のみ許可するため、エンコード解除は不要かつ不可)。
28
+ - 攻撃者が引数を直接制御できる脅威モデルは想定外(ローカル CLI 前提)。
21
29
  """
22
30
 
23
31
  from __future__ import annotations
@@ -47,14 +55,24 @@ DEFAULT_REEVAL_DAYS = 30 * 6
47
55
  # 短すぎる連番([CR-Q-1] 等)は誤抽出を防ぐため対象外とする。
48
56
  CHECKLIST_ID_RE = re.compile(r"\[((?:CR|SR)-[A-Z]+-\d{3,})\]")
49
57
 
50
-
51
- def _ensure_c3_db_path_in_sys_path() -> None:
52
- """c3.db import 可能にする。
53
-
54
- c3 パッケージは pip install 済みのため sys.path 操作は不要。
55
- 関数自体は後方互換のため残置(呼び出し側のテストが参照する場合がある)。
56
- """
57
- return
58
+ # パスガード: main() の引数は .claude/reports/ 配下に限定する [SR-V-002]。
59
+ # parents[3] .claude/ に到達(scripts/ → dev-workflow/ → skills/ → .claude/)。
60
+ # テストでは monkeypatch で差し替え可能。
61
+ ALLOWED_REPORT_DIR = (Path(__file__).resolve().parents[3] / "reports").resolve()
62
+ # 誤配置検出: ALLOWED_REPORT_DIR の親が `.claude` であることを実行時に検証 [SR-NEW]。
63
+ # パストラバーサル防御ではなく、スクリプトが別階層に移動された場合の
64
+ # サイレント破綻を防ぐ。`assert` は `python -O` で無効化されるため
65
+ # RuntimeError で明示的に投げる。
66
+ # record_tier_outcome.py の _CLAUDE_DIR 検証と対称な endswith パターンを使用。
67
+ # `os.sep + ".claude"` は Windows (`\\.claude`)・`"/.claude"` は POSIX 用の固定リテラル。
68
+ # 両方チェックすることで OS 依存しないパス末尾検証になる。
69
+ _parent_str = str(ALLOWED_REPORT_DIR.parent)
70
+ if not (_parent_str.endswith(os.sep + ".claude") or _parent_str.endswith("/.claude")):
71
+ raise RuntimeError(
72
+ f"ALLOWED_REPORT_DIR resolution broke: expected parent to end with '.claude' "
73
+ f"but got {_parent_str!r}. "
74
+ "Check that this file is at .claude/skills/dev-workflow/scripts/."
75
+ )
58
76
 
59
77
 
60
78
  def extract_checklist_ids(report_text: str) -> list[str]:
@@ -80,6 +98,29 @@ def _is_old(decided_at_iso: str, days: int = DEFAULT_REEVAL_DAYS) -> bool:
80
98
  return (now - decided) > timedelta(days=days)
81
99
 
82
100
 
101
+ def _sanitize_md(s: str) -> str:
102
+ """マークダウン構造を崩しうる文字(改行・# / ``` )を空白に置換する。
103
+
104
+ 対象文字:
105
+ - ``\\r`` / ``\\n``: 行区切り
106
+ - ``#``: 見出し記号
107
+ - `` ` ``: コードブロック・インラインコード境界
108
+ - ``\\u2028`` (LINE SEPARATOR) / ``\\u2029`` (PARAGRAPH SEPARATOR):
109
+ Python の ``str.splitlines()`` および ECMAScript JSON.parse が行区切りとして扱う Unicode 文字。
110
+ Markdown レンダラー上の実害は軽微だが、record_tier_outcome.py の
111
+ U+2028/U+2029 エスケープとの一貫性のため対象に含める。
112
+ - ``\\x85`` (NEXT LINE / NEL):
113
+ Python の ``str.splitlines()`` が行区切りとして扱う Unicode 文字。
114
+ splitlines() 互換性のため対象に含める。
115
+
116
+ DB 由来フィールドをレポート Markdown に埋め込む際の防御。[SR-NEW] / [CR-Q-001]
117
+ """
118
+ # NOTE: ソースコード上は escape 表記で記述し、実体文字を埋め込まない。
119
+ # raw string を使わず通常文字列にすることで \u2028 / \u2029 / \x85 を Python が Unicode に解決する。
120
+ # コードポイント昇順: \r(0D) < \n(0A) < \x85(85) < # < ` < \u2028 < \u2029
121
+ return re.sub("[\r\n\x85#`\u2028\u2029]", " ", str(s))
122
+
123
+
83
124
  def build_hint_section(
84
125
  decisions_by_id: dict[str, list[dict]],
85
126
  *,
@@ -129,8 +170,12 @@ def build_hint_section(
129
170
  flag = " [要再評価]" if _is_old(latest_decided, reeval_days) else ""
130
171
  latest_decision = latest.get("decision", "?")
131
172
  latest_reason = latest.get("reason") or "(理由未記載)"
173
+ latest_decided_safe = _sanitize_md(latest_decided)
174
+ latest_decision_safe = _sanitize_md(latest_decision)
175
+ latest_reason_safe = _sanitize_md(latest_reason)
132
176
  lines.append(
133
- f"- 直近: {latest_decided}({latest_decision}、理由: {latest_reason}){flag}"
177
+ f"- 直近: {latest_decided_safe}({latest_decision_safe}"
178
+ f"理由: {latest_reason_safe}){flag}"
134
179
  )
135
180
  lines.append("")
136
181
 
@@ -208,7 +253,20 @@ def main(argv: list[str] | None = None) -> int:
208
253
  report_paths: list[Path] = []
209
254
  for a in argv:
210
255
  p = Path(a)
256
+ # .claude/reports/ 配下のみを許可する [SR-V-002]。
257
+ # NOTE: Path.resolve() は URL エンコード(%2e%2e 等)を解除しないため、
258
+ # ALLOWED_REPORT_DIR 配下にリテラルディレクトリ名として `%2e%2e` を含む
259
+ # パスを渡すと relative_to() を通過する。実体ファイルが存在しない限り
260
+ # 直後の is_file() が二段目防御として弾くため実害なし(脅威モデル: ローカル CLI)。
261
+ try:
262
+ resolved = p.resolve()
263
+ resolved.relative_to(ALLOWED_REPORT_DIR)
264
+ except (OSError, ValueError):
265
+ print(f"[review_hint_inject] path outside reports/ (skipped): {p}", file=sys.stderr)
266
+ continue
211
267
  if not p.is_file():
268
+ # 二段目防御: %2e%2e 等のリテラルが ALLOWED 配下に解決された場合も
269
+ # 実ファイルが存在しなければここで弾かれる
212
270
  print(f"[review_hint_inject] not a file (skipped): {p}", file=sys.stderr)
213
271
  continue
214
272
  report_paths.append(p)
@@ -8,6 +8,11 @@ disable-model-invocation: true
8
8
  MCP サーバーの追加・一覧・削除を対話形式で行う。
9
9
  全ての設定は `.claude/settings.json` のプロジェクトスコープに書き込む。
10
10
 
11
+ > **注意:** Claude Code にはネイティブの `/mcp` コマンドが別途存在するが、それとは別物。
12
+ > ネイティブ `/mcp add` は `settings.json` 以外のファイル(`~/.claude/mcp.json` 等)に書き込む可能性があるが、
13
+ > 正確な書き込み先は Claude Code のバージョン依存であり未確認(要確認)。
14
+ > C3 プロジェクトでは必ずこの `/mcp-config` スキルを使うこと(設定の分散を防ぐため)。
15
+
11
16
  ---
12
17
 
13
18
  ## Step 1: 操作を選択する
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.12.0] - 2026-05-21
4
+
5
+ ### タクソノミー棚卸(hooks/ 整理)
6
+
7
+ - **skill-callable CLI ヘルパーの再配置**: `review_hint_inject.py` / `record_review_decision.py` / `record_tier_outcome.py` を `.claude/hooks/` から `.claude/skills/dev-workflow/scripts/` に移動。`hooks/` は Claude Code のイベントフックとそのヘルパーモジュール専用とする
8
+ - **`subagent_log.py` を削除**: PO(Parallel Orchestra、v2.0.0 廃止)時代の残骸。SubagentStart/Stop イベントの開発用ロギングフック
9
+ - **`taxonomy.md` / `decisions.md` 更新**: skills の「オーケストレーション skill」「ユーティリティ skill」2 種類分類を追記、D-010 / D-011 を追加(フック拡張・promoted スキルパス変更)
10
+ - **`record_review_decision.py` に文字数 / バイト数上限を導入**: `MAX_FINDING_LEN=2000` / `MAX_REASON_LEN=2000` / `MAX_FIELD_BYTES=8192` で DB 肥大化を防止
11
+ - **`review_hint_inject.py` に `ALLOWED_REPORT_DIR` パスガード**: `.claude/reports/` 配下のみ許可(パストラバーサル防御)
12
+
13
+ #### Migration(既存利用先環境向け cleanup 手順)
14
+
15
+ `c3 update` は配布物の削除を検出しないため、`pip install -U claude-code-conductor` 後に以下を手動実行してください。
16
+
17
+ **1. 旧 hooks/ 配下の skill-callable スクリプトを削除**
18
+
19
+ POSIX(Linux/macOS):
20
+ ```bash
21
+ rm -f .claude/hooks/review_hint_inject.py
22
+ rm -f .claude/hooks/record_review_decision.py
23
+ rm -f .claude/hooks/record_tier_outcome.py
24
+ rm -f .claude/hooks/subagent_log.py
25
+ ```
26
+
27
+ PowerShell(Windows):
28
+ ```powershell
29
+ Remove-Item -Force .claude\hooks\review_hint_inject.py
30
+ Remove-Item -Force .claude\hooks\record_review_decision.py
31
+ Remove-Item -Force .claude\hooks\record_tier_outcome.py
32
+ Remove-Item -Force .claude\hooks\subagent_log.py
33
+ ```
34
+
35
+ **2. `.claude/settings.local.json` から `subagent_log.py` 関連を削除**(個人ファイル)
36
+
37
+ - `permissions.allow` の `"Bash(python .claude/hooks/subagent_log.py*)"` エントリ
38
+ - `hooks.SubagentStart` ブロック全体(subagent_log.py を呼ぶもの)
39
+ - `hooks.SubagentStop` ブロック全体(同上)
40
+
41
+ **3. `.claude/settings.json` の `permissions.allow` を新パスに置換**
42
+
43
+ ```diff
44
+ - "Bash(python .claude/hooks/review_hint_inject.py*)",
45
+ - "Bash(python .claude/hooks/record_review_decision.py*)",
46
+ - "Bash(python .claude/hooks/record_tier_outcome.py*)",
47
+ + "Bash(python .claude/skills/dev-workflow/scripts/review_hint_inject.py*)",
48
+ + "Bash(python .claude/skills/dev-workflow/scripts/record_review_decision.py*)",
49
+ + "Bash(python .claude/skills/dev-workflow/scripts/record_tier_outcome.py*)",
50
+ ```
51
+
52
+ **4. 確認**
53
+
54
+ ```bash
55
+ # 旧パス参照が残っていないか確認
56
+ grep -r "\.claude/hooks/review_hint_inject\|\.claude/hooks/record_review_decision\|\.claude/hooks/record_tier_outcome\|\.claude/hooks/subagent_log" .claude/ || echo "OK: 旧パス参照なし"
57
+ ```
58
+
59
+ ---
60
+
3
61
  ## [2.11.0] - 2026-05-21
4
62
 
5
63
  ### 破壊的変更: summarize-memory 機能の廃止
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-code-conductor
3
- Version: 2.11.0
3
+ Version: 2.12.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
@@ -1,3 +1,3 @@
1
1
  """Claude Code Conductor (C3) - multi-agent orchestration framework for Claude Code."""
2
2
 
3
- __version__ = "2.11.0"
3
+ __version__ = "2.12.0"