claude-code-conductor 1.5.2__tar.gz → 1.7.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-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/consolidate_memory.py +178 -20
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/init_c3_db.py +1 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/permission_handler.py +2 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/select_tier.py +2 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/settings.local.json +2 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/dev-workflow/SKILL.md +36 -2
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/init-session/SKILL.md +48 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/start/SKILL.md +103 -2
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/task-routing/SKILL.md +6 -4
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/CHANGELOG.md +50 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/PKG-INFO +1 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/__init__.py +1 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_po.py +10 -10
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_status.py +1 -1
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/runner.py +56 -27
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_consolidate_memory.py +482 -0
- claude_code_conductor-1.7.0/tests/skills/__init__.py +0 -0
- claude_code_conductor-1.7.0/tests/skills/test_session_backlog_reconciliation.py +158 -0
- claude_code_conductor-1.7.0/tests/skills/test_start_skill_bugfix_flow.py +56 -0
- claude_code_conductor-1.7.0/tests/skills/test_start_skill_security_audit_phase.py +419 -0
- claude_code_conductor-1.7.0/tests/skills/test_task_routing_skill.py +77 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/CLAUDE.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/architect.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/code-reviewer.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/developer.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/doc-writer.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/interviewer.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/planner.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/project-setup.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/security-reviewer.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/systematic-debugger.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/tdd-develop.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/agents/tester.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/docs/parallel-orchestra-manifest.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/docs/po-worktree-writes.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/docs/settings.json.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/clear_file_history.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/enable_sandbox.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/po_heartbeat.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/post_tool.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/pre_compact.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/pre_tool.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/record_review_decision.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/record_tier_outcome.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/restore_session.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/review_hint_inject.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/schema.sql +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/session_utils.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/statusline.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/stop.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/subagent_log.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/validate_skill_change.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/worktree_guard.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/memory/.gitkeep +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/permission_rules.json +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/rules/code-review-checklist.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/rules/promoted/index.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/rules/security-review-checklist.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/settings.json +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/code-review/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/develop/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/doc/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/extract-lib/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/mcp-config/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/pattern-status/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/po-status/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/promote-pattern/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/report-timestamp/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/report-timestamp/scripts/get_timestamp.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/setup/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/wave-execution/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/worktree-tdd-workflow/SKILL.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/state/.gitkeep +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.gitignore +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/LICENSE +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/README.md +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/hatch_build.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/pyproject.toml +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/__main__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/_excludes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/_terminal.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_doctor.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_init.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_list.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/cli_update.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/paths.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/po/__init__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/po/manifest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/c3/po/run.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/__init__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/_exceptions.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/c3_db.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/cli.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/manifest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/src/parallel_orchestra/report.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/__init__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/conftest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/__init__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_clear_file_history.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_enable_sandbox.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_init_c3_db.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_permission_handler.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_post_tool.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_pre_tool.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_record_tier_outcome.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_restore_session.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_review_hint_inject.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_select_tier.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_select_tier_escalation.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_session_utils.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_similarity_boost.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_statusline.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_statusline_template_sync.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/hooks/test_subagent_log.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/__init__.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/conftest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_cli.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_manifest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_po_results_recording.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_po_status_visibility.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_po_worktree_writes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_report.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_retry_backoff.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_review_fixes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_review_fixes2.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_review_fixes3.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_review_fixes4.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_review_fixes5.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_runner_model_override.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_runner_t7.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_runner_v04_fix.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_runner_v04_m1.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_runner_v04_m2.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/parallel_orchestra/test_summary_loop.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_clear_file_history.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_cli_init.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_cli_list.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_cli_po.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_cli_po_tempfile.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_cli_status.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_docstring_consistency.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_enable_sandbox.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_excludes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_manifest_fixes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_manifest_yaml_escape.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_paths.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_po_manifest.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_po_run.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_po_waves.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_pre_compact.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_pre_tool_hook.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_precompact_additional.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_precompact_toctou_fixes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_session_utils_additional.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_statusline.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_stop_additional.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_stop_hook.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_stop_precompact_fixes.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_sync_template_clear_file_history.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_sync_template_stop.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_sync_validate_skill.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_template_pre_tool_hook.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_validate_skill_change.py +0 -0
- {claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/tests/test_worktree_guard.py +0 -0
{claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/consolidate_memory.py
RENAMED
|
@@ -17,6 +17,10 @@ F-004 MVP: 過去 N 日分の `.claude/memory/sessions/YYYYMMDD.tmp` から
|
|
|
17
17
|
呼び出し:
|
|
18
18
|
- `.claude/settings.json` の `Stop` hook 配列に登録される。
|
|
19
19
|
- stdin から JSON payload を受け取るが、内容は使わない(情報源は session ファイルのみ)。
|
|
20
|
+
|
|
21
|
+
実行モード:
|
|
22
|
+
- 通常モード(`_full_sync_main`): Stop hook から起動される。同期で MVP 集約・promotion ログ・archive を完了させ、LLM 要約は子プロセスとしてデタッチ起動して即終了する。Stop hook ブロック時間を 200〜900ms に抑える。
|
|
23
|
+
- LLM 限定モード(`_llm_only_main`、`--llm-only <today_iso>` で起動): 親の Stop hook がデタッチ起動した子プロセス専用エントリ。`.claude/state/consolidate_llm.lock` で多重起動を防ぎ、`write_summary(enable_llm=True)` を実行して `consolidated_summary.md` を LLM 要約付きで書き直す。
|
|
20
24
|
"""
|
|
21
25
|
|
|
22
26
|
from __future__ import annotations
|
|
@@ -27,6 +31,7 @@ import shutil
|
|
|
27
31
|
import subprocess
|
|
28
32
|
import sys
|
|
29
33
|
import tempfile
|
|
34
|
+
import time
|
|
30
35
|
from datetime import datetime, timedelta, timezone
|
|
31
36
|
from pathlib import Path
|
|
32
37
|
|
|
@@ -83,6 +88,14 @@ PROMOTION_CANDIDATES_PATH = os.path.join(
|
|
|
83
88
|
_CLAUDE_DIR, "memory", PROMOTION_CANDIDATES_FILE_NAME
|
|
84
89
|
)
|
|
85
90
|
|
|
91
|
+
# LLM 子プロセスの多重起動防止ロック。
|
|
92
|
+
# `.claude/state/` は `.gitignore` 既存ルールでカバー済み。
|
|
93
|
+
LOCK_PATH = os.path.join(_CLAUDE_DIR, "state", "consolidate_llm.lock")
|
|
94
|
+
# ロックを「新鮮」とみなす TTL(秒)。LLM タイムアウト(60s)の 2 倍を上限とする。
|
|
95
|
+
LOCK_STALE_SEC = 120
|
|
96
|
+
# `--llm-only` モードのフラグ
|
|
97
|
+
LLM_ONLY_FLAG = "--llm-only"
|
|
98
|
+
|
|
86
99
|
|
|
87
100
|
def _load_session_utils():
|
|
88
101
|
"""session_utils モジュールを動的にロードして返す(同階層)。"""
|
|
@@ -90,7 +103,8 @@ def _load_session_utils():
|
|
|
90
103
|
|
|
91
104
|
util_path = os.path.join(_HOOKS_DIR, "session_utils.py")
|
|
92
105
|
spec = importlib.util.spec_from_file_location("session_utils", util_path)
|
|
93
|
-
|
|
106
|
+
if spec is None or spec.loader is None:
|
|
107
|
+
raise ImportError(f"session_utils が見つかりません: {util_path}")
|
|
94
108
|
module = importlib.util.module_from_spec(spec)
|
|
95
109
|
spec.loader.exec_module(module) # type: ignore[attr-defined]
|
|
96
110
|
return module
|
|
@@ -174,7 +188,7 @@ def build_summary_markdown(
|
|
|
174
188
|
"# 集約サマリ",
|
|
175
189
|
"",
|
|
176
190
|
f"_直近 {window_days} 日({start_str} 〜 {today_str})の session ファイル {len(files)} 件をマージ_",
|
|
177
|
-
f"_最終更新: {
|
|
191
|
+
f"_最終更新: {today.isoformat(timespec='seconds')}_",
|
|
178
192
|
"",
|
|
179
193
|
"本ファイルは `.claude/hooks/consolidate_memory.py` が Stop フックで自動生成する。",
|
|
180
194
|
"重複行・空行を除去した単純マージのため、文脈は元の session ファイルを参照すること。",
|
|
@@ -499,6 +513,11 @@ def _atomic_write(output_path: str, payload: str) -> bool:
|
|
|
499
513
|
# ---------------------------------------------------------------------------
|
|
500
514
|
|
|
501
515
|
|
|
516
|
+
def _escape_for_xml(text: str) -> str:
|
|
517
|
+
"""XML タグ境界突破を防ぐためタグ記号をエンティティに変換する。[SR-AI-001]"""
|
|
518
|
+
return text.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
519
|
+
|
|
520
|
+
|
|
502
521
|
def _build_llm_prompt(
|
|
503
522
|
files: list[str],
|
|
504
523
|
*,
|
|
@@ -513,8 +532,8 @@ def _build_llm_prompt(
|
|
|
513
532
|
success_lines = _collect_section_lines(files, TARGET_SECTIONS[0], extract_fn)
|
|
514
533
|
failure_lines = _collect_section_lines(files, TARGET_SECTIONS[1], extract_fn)
|
|
515
534
|
|
|
516
|
-
success_text = "\n".join(success_lines)
|
|
517
|
-
failure_text = "\n".join(failure_lines)
|
|
535
|
+
success_text = _escape_for_xml("\n".join(success_lines))
|
|
536
|
+
failure_text = _escape_for_xml("\n".join(failure_lines))
|
|
518
537
|
|
|
519
538
|
# 入力サイズ制御: 両セクション合計が _LLM_INPUT_MAX_CHARS を超えたら均等に切り詰める
|
|
520
539
|
half = _LLM_INPUT_MAX_CHARS // 2
|
|
@@ -599,17 +618,27 @@ def build_llm_summary_section(
|
|
|
599
618
|
# 子プロセスへ env を引き継いで深度を 1 加算(再帰防止フラグ)
|
|
600
619
|
env = {**os.environ, _LLM_DEPTH_ENV: str(depth + 1)}
|
|
601
620
|
|
|
621
|
+
# Windows では claude.exe が console application のため、CREATE_NO_WINDOW を
|
|
622
|
+
# 指定しないとウィンドウが可視化される(特に親 python が DETACHED 系で起動された場合)。
|
|
623
|
+
run_kwargs: dict = dict(
|
|
624
|
+
capture_output=True,
|
|
625
|
+
text=True,
|
|
626
|
+
encoding="utf-8",
|
|
627
|
+
errors="replace",
|
|
628
|
+
timeout=timeout,
|
|
629
|
+
env=env,
|
|
630
|
+
cwd=_CLAUDE_DIR,
|
|
631
|
+
check=False,
|
|
632
|
+
)
|
|
633
|
+
if sys.platform == "win32":
|
|
634
|
+
run_kwargs["creationflags"] = getattr(
|
|
635
|
+
subprocess, "CREATE_NO_WINDOW", 0x08000000
|
|
636
|
+
)
|
|
637
|
+
|
|
602
638
|
try:
|
|
603
639
|
result = subprocess.run(
|
|
604
640
|
[claude_exe, "-p", prompt, "--dangerously-skip-permissions"],
|
|
605
|
-
|
|
606
|
-
text=True,
|
|
607
|
-
encoding="utf-8",
|
|
608
|
-
errors="replace",
|
|
609
|
-
timeout=timeout,
|
|
610
|
-
env=env,
|
|
611
|
-
cwd=_CLAUDE_DIR,
|
|
612
|
-
check=False,
|
|
641
|
+
**run_kwargs,
|
|
613
642
|
)
|
|
614
643
|
except subprocess.TimeoutExpired:
|
|
615
644
|
print(
|
|
@@ -783,10 +812,95 @@ def _resolve_archive_dest(archive_dir: str, base_name: str) -> str:
|
|
|
783
812
|
return candidate
|
|
784
813
|
|
|
785
814
|
|
|
786
|
-
def
|
|
787
|
-
"""
|
|
815
|
+
def _acquire_llm_lock(lock_path: str = LOCK_PATH) -> bool:
|
|
816
|
+
"""LLM 子プロセスのロックを取得する。新鮮な既存ロックがあれば False を返す。
|
|
788
817
|
|
|
789
|
-
|
|
818
|
+
ロックファイル: ``.claude/state/consolidate_llm.lock``
|
|
819
|
+
新鮮判定: mtime が現在時刻から ``LOCK_STALE_SEC`` 秒以内
|
|
820
|
+
"""
|
|
821
|
+
try:
|
|
822
|
+
if os.path.exists(lock_path):
|
|
823
|
+
mtime = os.path.getmtime(lock_path)
|
|
824
|
+
if time.time() - mtime < LOCK_STALE_SEC:
|
|
825
|
+
return False
|
|
826
|
+
os.makedirs(os.path.dirname(lock_path), exist_ok=True)
|
|
827
|
+
with open(lock_path, "w", encoding="utf-8") as f:
|
|
828
|
+
f.write(f"{os.getpid()}\n{time.time()}\n")
|
|
829
|
+
return True
|
|
830
|
+
except OSError:
|
|
831
|
+
return False
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def _release_llm_lock(lock_path: str = LOCK_PATH) -> None:
|
|
835
|
+
"""LLM 子プロセスのロックを解放する。失敗時は無視(次回 stale 判定で破棄される)。"""
|
|
836
|
+
try:
|
|
837
|
+
os.unlink(lock_path)
|
|
838
|
+
except OSError:
|
|
839
|
+
pass
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def _spawn_detached_llm(today_iso: str) -> None:
|
|
843
|
+
"""LLM 要約フェーズを ``--llm-only`` モードで子プロセスとしてデタッチ起動する。
|
|
844
|
+
|
|
845
|
+
親(Stop hook 内)は子の完了を待たない。子が失敗・ハングしても親は
|
|
846
|
+
ブロックされず、``consolidated_summary.md`` は LLM セクションなし版が残る。
|
|
847
|
+
|
|
848
|
+
Windows では ``CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP`` を使い、
|
|
849
|
+
Unix 系(macOS / Linux)では ``start_new_session=True`` を使う。
|
|
850
|
+
"""
|
|
851
|
+
args = [sys.executable, os.path.abspath(__file__), LLM_ONLY_FLAG, today_iso]
|
|
852
|
+
popen_kwargs: dict = dict(
|
|
853
|
+
stdin=subprocess.DEVNULL,
|
|
854
|
+
stdout=subprocess.DEVNULL,
|
|
855
|
+
stderr=subprocess.DEVNULL,
|
|
856
|
+
close_fds=True,
|
|
857
|
+
cwd=_CLAUDE_DIR,
|
|
858
|
+
)
|
|
859
|
+
if sys.platform == "win32":
|
|
860
|
+
# CREATE_NO_WINDOW: 子プロセス(および子が呼ぶ console アプリ)の
|
|
861
|
+
# コンソールウィンドウを完全に非表示にする。
|
|
862
|
+
# DETACHED_PROCESS は親コンソールから切り離す効果はあるが、
|
|
863
|
+
# 子が更に呼ぶ console アプリ(claude.exe 等)が新規コンソールを
|
|
864
|
+
# 自動取得してウィンドウが見えてしまうため使わない(両者は排他)。
|
|
865
|
+
# CREATE_NEW_PROCESS_GROUP は親からの Ctrl+C 伝播を防ぐので維持。
|
|
866
|
+
# 値は CREATE_NO_WINDOW=0x08000000, CREATE_NEW_PROCESS_GROUP=0x00000200。
|
|
867
|
+
creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0x08000000) | getattr(
|
|
868
|
+
subprocess, "CREATE_NEW_PROCESS_GROUP", 0x00000200
|
|
869
|
+
)
|
|
870
|
+
popen_kwargs["creationflags"] = creationflags
|
|
871
|
+
else:
|
|
872
|
+
popen_kwargs["start_new_session"] = True
|
|
873
|
+
|
|
874
|
+
try:
|
|
875
|
+
# Popen の戻り値を保持しない: プロセスはデタッチ起動済みなので親が exit しても継続する。
|
|
876
|
+
subprocess.Popen(args, **popen_kwargs)
|
|
877
|
+
except OSError as exc:
|
|
878
|
+
print(f"[consolidate_memory] detach spawn failed: {exc}", file=sys.stderr)
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def _parse_today_arg(argv: list[str]) -> datetime:
|
|
882
|
+
"""``--llm-only <today_iso>`` の today を解釈して返す。失敗時は now を返す。"""
|
|
883
|
+
try:
|
|
884
|
+
idx = argv.index(LLM_ONLY_FLAG)
|
|
885
|
+
if idx + 1 < len(argv):
|
|
886
|
+
parsed = datetime.fromisoformat(argv[idx + 1])
|
|
887
|
+
if parsed.tzinfo is None:
|
|
888
|
+
parsed = parsed.replace(tzinfo=timezone.utc)
|
|
889
|
+
return parsed
|
|
890
|
+
except (ValueError, IndexError):
|
|
891
|
+
pass
|
|
892
|
+
return datetime.now(timezone.utc)
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
def _full_sync_main() -> int:
|
|
896
|
+
"""Stop hook 通常モード: 同期処理のみ完了させ LLM はバックグラウンドへ。
|
|
897
|
+
|
|
898
|
+
同期で実行する処理:
|
|
899
|
+
- MVP セクション集約 + 昇格候補サマリの consolidated_summary.md 書き出し(LLM なし)
|
|
900
|
+
- Phase 2-B: promotion-candidates.md 書き出し
|
|
901
|
+
- Phase 2-A: 古い session.tmp の archive/ 移動
|
|
902
|
+
|
|
903
|
+
完了後、LLM 要約を ``--llm-only`` 子プロセスにデタッチ起動して即 exit 0。
|
|
790
904
|
"""
|
|
791
905
|
# stdin の payload は読むが内容は使わない(呼び出し元の Claude Code から送られる)
|
|
792
906
|
try:
|
|
@@ -797,18 +911,17 @@ def main() -> int:
|
|
|
797
911
|
# main() 全体で同じ "today" を共有する(datetime.now() の二重評価回避 + 決定論性)
|
|
798
912
|
today = datetime.now(timezone.utc)
|
|
799
913
|
|
|
800
|
-
# MVP +
|
|
801
|
-
# (LLM 要約 + 昇格候補サマリを含む)
|
|
914
|
+
# 同期: MVP + 昇格候補サマリを LLM なしで生成
|
|
802
915
|
try:
|
|
803
916
|
write_summary(
|
|
804
917
|
patterns_path=PATTERNS_PATH,
|
|
805
918
|
today=today,
|
|
806
|
-
enable_llm=
|
|
919
|
+
enable_llm=False,
|
|
807
920
|
)
|
|
808
921
|
except Exception as exc: # noqa: BLE001
|
|
809
922
|
print(f"[consolidate_memory] unexpected error: {exc}", file=sys.stderr)
|
|
810
923
|
|
|
811
|
-
# Phase 2-B
|
|
924
|
+
# 同期: Phase 2-B 半自動 promotion 候補ログ
|
|
812
925
|
try:
|
|
813
926
|
_, candidates = build_promotion_candidates_section(
|
|
814
927
|
PATTERNS_PATH, today=today
|
|
@@ -822,7 +935,7 @@ def main() -> int:
|
|
|
822
935
|
file=sys.stderr,
|
|
823
936
|
)
|
|
824
937
|
|
|
825
|
-
# Phase 2-A
|
|
938
|
+
# 同期: Phase 2-A 古い session.tmp を archive/ へ移動
|
|
826
939
|
try:
|
|
827
940
|
ttl = _resolve_archive_ttl()
|
|
828
941
|
archive_old_sessions(ttl_days=ttl)
|
|
@@ -832,8 +945,53 @@ def main() -> int:
|
|
|
832
945
|
file=sys.stderr,
|
|
833
946
|
)
|
|
834
947
|
|
|
948
|
+
# 非同期: LLM 要約を子プロセスとしてデタッチ起動
|
|
949
|
+
_spawn_detached_llm(today.isoformat())
|
|
950
|
+
|
|
951
|
+
return 0
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
def _llm_only_main() -> int:
|
|
955
|
+
"""``--llm-only`` 子プロセスエントリ: LLM 要約のみ実行して summary を更新する。
|
|
956
|
+
|
|
957
|
+
多重起動防止のためロックを取得する。新鮮な既存ロックがあれば即終了する。
|
|
958
|
+
LLM 要約に失敗しても exit 0(既存挙動と同等)。
|
|
959
|
+
"""
|
|
960
|
+
today = _parse_today_arg(sys.argv)
|
|
961
|
+
|
|
962
|
+
# LOCK_PATH をモジュール属性から取得することでテストの monkeypatch に対応
|
|
963
|
+
if not _acquire_llm_lock(LOCK_PATH):
|
|
964
|
+
# 既に他の子が走っている、または直前の子がロック保持中
|
|
965
|
+
return 0
|
|
966
|
+
|
|
967
|
+
try:
|
|
968
|
+
write_summary(
|
|
969
|
+
patterns_path=PATTERNS_PATH,
|
|
970
|
+
today=today,
|
|
971
|
+
enable_llm=True,
|
|
972
|
+
)
|
|
973
|
+
except Exception as exc: # noqa: BLE001
|
|
974
|
+
print(
|
|
975
|
+
f"[consolidate_memory:llm-only] unexpected error: {exc}",
|
|
976
|
+
file=sys.stderr,
|
|
977
|
+
)
|
|
978
|
+
finally:
|
|
979
|
+
_release_llm_lock(LOCK_PATH)
|
|
980
|
+
|
|
835
981
|
return 0
|
|
836
982
|
|
|
837
983
|
|
|
984
|
+
def main() -> int:
|
|
985
|
+
"""Stop フックエントリポイント。失敗してもセッションを止めない(exit 0)。
|
|
986
|
+
|
|
987
|
+
起動引数で 2 つのモードに分岐する:
|
|
988
|
+
- ``--llm-only``: 子プロセスとしての LLM 限定モード
|
|
989
|
+
- それ以外: Stop hook 通常モード(同期処理 + LLM デタッチ)
|
|
990
|
+
"""
|
|
991
|
+
if LLM_ONLY_FLAG in sys.argv:
|
|
992
|
+
return _llm_only_main()
|
|
993
|
+
return _full_sync_main()
|
|
994
|
+
|
|
995
|
+
|
|
838
996
|
if __name__ == "__main__":
|
|
839
997
|
sys.exit(main())
|
|
@@ -71,7 +71,7 @@ def apply_schema(db_path: str = DB_PATH, schema_path: str = SCHEMA_PATH) -> None
|
|
|
71
71
|
with open(schema_path, 'r', encoding='utf-8') as f:
|
|
72
72
|
ddl = f.read()
|
|
73
73
|
|
|
74
|
-
conn = sqlite3.connect(db_path)
|
|
74
|
+
conn = sqlite3.connect(db_path, timeout=30)
|
|
75
75
|
try:
|
|
76
76
|
# WAL モードを有効化(reader が writer をブロックしない)
|
|
77
77
|
conn.execute('PRAGMA journal_mode=WAL')
|
{claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/hooks/permission_handler.py
RENAMED
|
@@ -41,7 +41,8 @@ def notify(message: str) -> None:
|
|
|
41
41
|
capture_output=True, timeout=5
|
|
42
42
|
)
|
|
43
43
|
elif system == 'Windows':
|
|
44
|
-
safe =
|
|
44
|
+
safe = re.sub(r'[`$(){}\r\n]', '', message)
|
|
45
|
+
safe = safe.replace('"', '`"')
|
|
45
46
|
ps = (
|
|
46
47
|
'Add-Type -AssemblyName System.Windows.Forms; '
|
|
47
48
|
'$n = New-Object System.Windows.Forms.NotifyIcon; '
|
|
@@ -258,8 +258,9 @@ def maybe_escalate(
|
|
|
258
258
|
if c3_db is None:
|
|
259
259
|
return chosen_tier, None
|
|
260
260
|
|
|
261
|
-
def
|
|
261
|
+
def _db_failure_rate(complexity: str, tier: str) -> tuple:
|
|
262
262
|
return c3_db.read_tier_failure_rate(complexity, tier)
|
|
263
|
+
failure_rate_fn = _db_failure_rate
|
|
263
264
|
|
|
264
265
|
rate, samples = failure_rate_fn(complexity, chosen_tier)
|
|
265
266
|
if rate is None or rate < ESCALATION_THRESHOLD:
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"Bash(python -m pytest tests/parallel_orchestra/test_po_worktree_writes.py tests/parallel_orchestra/test_po_results_recording.py::TestLocateC3Db -v)",
|
|
44
44
|
"Bash(python -m pytest tests/hooks/test_consolidate_memory.py -v)",
|
|
45
45
|
"Bash(mkdir -p .claude/memory/archive)",
|
|
46
|
-
"Bash(touch .claude/memory/archive/.gitkeep)"
|
|
46
|
+
"Bash(touch .claude/memory/archive/.gitkeep)",
|
|
47
|
+
"Bash(dir *)"
|
|
47
48
|
]
|
|
48
49
|
},
|
|
49
50
|
"hooks": {
|
{claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/dev-workflow/SKILL.md
RENAMED
|
@@ -502,7 +502,7 @@ AskUserQuestion で確認する:
|
|
|
502
502
|
}
|
|
503
503
|
```
|
|
504
504
|
|
|
505
|
-
承認後 → セッションファイルの `- [ ] security-review` を `- [x]` に Edit
|
|
505
|
+
承認後 → セッションファイルの `- [ ] security-review` を `- [x]` に Edit する。続けて **「引き継ぎバックログの照合」**(後述の共通ステップ)を実行してからコミットを提案する。
|
|
506
506
|
**F-005 結果記録**: フェーズ E の最終承認時のみ Bash で記録する(多重カウント防止のため E-1 では記録しない):
|
|
507
507
|
```bash
|
|
508
508
|
python .claude/hooks/record_tier_outcome.py --outcome success
|
|
@@ -562,7 +562,7 @@ AskUserQuestion で許容理由を確認する:
|
|
|
562
562
|
1. 全指摘の直下に `> **[許容]** {理由}` を Edit で追記する(検出記録は削除しない)
|
|
563
563
|
2. **F-001 判断記録**: 全 `[SR-XX-NNN]` 指摘について `record_review_decision.py --decision accepted` で記録する
|
|
564
564
|
3. セッションファイルの `## うまくいったアプローチ` に `[許容例外] {指摘内容} → {許容理由}` の形式で追記し `patterns` に記録する
|
|
565
|
-
4. セッションファイルの `- [ ] security-review` を `- [x]` に Edit
|
|
565
|
+
4. セッションファイルの `- [ ] security-review` を `- [x]` に Edit する。続けて **「引き継ぎバックログの照合」**(後述の共通ステップ)を実行してからコミットを提案する。
|
|
566
566
|
5. **F-005 結果記録**: 全許容で完了するのも「成功」としてカウント:
|
|
567
567
|
```bash
|
|
568
568
|
python .claude/hooks/record_tier_outcome.py --outcome success
|
|
@@ -581,3 +581,37 @@ python .claude/hooks/record_tier_outcome.py --outcome failure
|
|
|
581
581
|
```bash
|
|
582
582
|
python .claude/hooks/record_tier_outcome.py --outcome failure
|
|
583
583
|
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## 引き継ぎバックログの照合(フェーズ E 共通ステップ)
|
|
588
|
+
|
|
589
|
+
フェーズ E の最終承認後、コミット提案の直前に必ず実行する。
|
|
590
|
+
|
|
591
|
+
引き継ぎバックログ(過去セッションから繰り越された `## 残タスク` 内の `- [ ]` 行のうち、ワークフローフェーズではない高レベル項目)が今回の作業で完了する場合、ここで `[x]` 化する。リリース時など節目の取りこぼしを防ぐ。
|
|
592
|
+
|
|
593
|
+
### 手順
|
|
594
|
+
|
|
595
|
+
1. session.tmp の `## 残タスク` セクションから `- [ ]` 行を抽出する
|
|
596
|
+
2. 当セッションの作業内容(DURATION・requirements-report タイトル・plan-report タイトル・関連コミット予定の内容)と、各 `- [ ]` 行を**キーワード照合**する(`F-XXX` / `Phase X` / 機能名 / 「Zenn」「リリース」「ドキュメント」などの名詞)
|
|
597
|
+
3. ワークフローフェーズ項目(`ヒアリング` / `設計` / `計画` / `tester:` / `developer:` / `code-review` / `security-review` で始まる行)は対象外。引き継ぎバックログのみを候補にする
|
|
598
|
+
4. 候補が**ゼロ件**ならこのステップをスキップしてそのままコミット提案へ
|
|
599
|
+
5. 候補が**1 件以上**あれば AskUserQuestion を提示する:
|
|
600
|
+
|
|
601
|
+
```json
|
|
602
|
+
{
|
|
603
|
+
"questions": [{
|
|
604
|
+
"question": "今回の作業で完了する引き継ぎバックログ項目があれば [x] にしますか?",
|
|
605
|
+
"options": [
|
|
606
|
+
{ "label": "全て [x] にする", "description": "候補を全て完了扱いにする" },
|
|
607
|
+
{ "label": "個別に選ぶ", "description": "項目ごとに確認する" },
|
|
608
|
+
{ "label": "更新しない", "description": "後で手動確認する" }
|
|
609
|
+
]
|
|
610
|
+
}]
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
6. 承認された項目は Edit で `- [ ] {元の文}` を `- [x] {元の文} → 完了` に置換する(コミット直前のためハッシュは未確定)
|
|
615
|
+
7. ステップ完了後、通常通りコミット提案へ進む
|
|
616
|
+
|
|
617
|
+
> 補足: バックログの陳腐化(例: 「v1.0.0〜v1.6.0 の Zenn 記事化」のように完了済みバージョンを含む)も検出したらユーザーに記述更新を促す。
|
{claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/init-session/SKILL.md
RENAMED
|
@@ -26,6 +26,24 @@ Glob で `.claude/memory/sessions/*.tmp` を検索し、ファイル名(YYYYMM
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
+
## Step 1.5: 残タスクと git log を照合する(陳腐化チェック)
|
|
30
|
+
|
|
31
|
+
引き継ぎバックログ(過去セッションから繰り越された `- [ ]` 項目)が古くなっていないかを確認する。
|
|
32
|
+
|
|
33
|
+
1. 前回 session.tmp の `## 残タスク` セクションから `- [ ]` で始まる行を抽出する
|
|
34
|
+
2. Bash で前回セッション以降のコミット一覧を取得する:
|
|
35
|
+
```bash
|
|
36
|
+
git log --since='{前回 SESSION の YYYYMMDD を YYYY-MM-DD 形式に変換}' --oneline
|
|
37
|
+
```
|
|
38
|
+
3. 各 `- [ ]` 行に含まれる識別キーワード(`F-XXX` / `Phase X` / 機能名 / 「Zenn」「リリース」などの名詞)が、いずれかのコミットメッセージに含まれているかをキーワード照合する
|
|
39
|
+
4. 該当があれば「**完了している可能性のあるタスク**」として Step 3 のサマリに加える(コミットハッシュも併記する)
|
|
40
|
+
5. **自動で `[x]` 化はしない**。Step 4 のあとで AskUserQuestion を提示し、ユーザー承認した項目のみ Edit で `[x]` 化する
|
|
41
|
+
6. 該当なし、または前回セッションが当日の場合はこの Step をスキップする
|
|
42
|
+
|
|
43
|
+
> 目的: 「F-004 Phase 2 → v1.3.0 完了」のように、リリースで完了したのに `[ ]` のまま残った引き継ぎタスクを次セッション開始時に検出する。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
29
47
|
## Step 2: 昇格候補パターンを確認する
|
|
30
48
|
|
|
31
49
|
`.claude/memory/patterns.json` を Read する(存在する場合)。
|
|
@@ -46,6 +64,9 @@ Glob で `.claude/memory/sessions/*.tmp` を検索し、ファイル名(YYYYMM
|
|
|
46
64
|
**残タスク:**
|
|
47
65
|
{残タスクリスト。完了済み [x] は省略する}
|
|
48
66
|
|
|
67
|
+
**完了している可能性のあるタスク(Step 1.5 で検出):**
|
|
68
|
+
{該当タスク行 + 関連コミットハッシュ。検出ゼロなら省略}
|
|
69
|
+
|
|
49
70
|
**前回うまくいったこと:**
|
|
50
71
|
{成功アプローチの要約}
|
|
51
72
|
|
|
@@ -56,6 +77,23 @@ Glob で `.claude/memory/sessions/*.tmp` を検索し、ファイル名(YYYYMM
|
|
|
56
77
|
{promotion_candidate: true のパターン一覧。なければ「なし」}
|
|
57
78
|
```
|
|
58
79
|
|
|
80
|
+
Step 1.5 で「完了している可能性のあるタスク」が検出された場合は、Step 4 の前に以下の AskUserQuestion を提示する:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"questions": [{
|
|
85
|
+
"question": "以下の残タスクは完了済みかもしれません。 [x] に更新しますか?",
|
|
86
|
+
"options": [
|
|
87
|
+
{ "label": "全て [x] にする", "description": "検出された全項目を完了扱いにする" },
|
|
88
|
+
{ "label": "個別に選ぶ", "description": "項目ごとに確認する" },
|
|
89
|
+
{ "label": "更新しない", "description": "後で手動確認する" }
|
|
90
|
+
]
|
|
91
|
+
}]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
承認された項目は Edit で `- [ ] {元の文}` を `- [x] {元の文} → {コミットハッシュ} 完了` に置換する。
|
|
96
|
+
|
|
59
97
|
---
|
|
60
98
|
|
|
61
99
|
## Step 4: 作業の開始方法を選ぶ
|
|
@@ -97,6 +135,16 @@ Skill ツールで `start` スキルを呼び出す。
|
|
|
97
135
|
|
|
98
136
|
session ファイルはタスク完了のたびに更新する。まとめて最後に書かない。
|
|
99
137
|
|
|
138
|
+
`## 残タスク` には性質の異なる 2 種類の項目が混在することに注意する:
|
|
139
|
+
|
|
140
|
+
- **A. ワークフローフェーズ項目**(例: `- [ ] ヒアリング` / `- [ ] 設計` / `- [ ] tester: Red フェーズ`)
|
|
141
|
+
- 各スキル(dev-workflow など)が承認直後に Edit で `[x]` 化する。タイミングは各 SKILL.md に明記されている
|
|
142
|
+
- **B. 引き継ぎバックログ項目**(例: `- [ ] F-XXX Phase X` / `- [ ] Zenn 記事化`)
|
|
143
|
+
- セッションを跨ぐ高レベルタスク。以下のタイミングで必ず照合・更新する:
|
|
144
|
+
- **セッション開始時**: init-session Step 1.5 で git log と照合
|
|
145
|
+
- **リリース・大きな完了の節目**: dev-workflow フェーズ E の最終承認時にバックログ確認 AskUserQuestion で更新
|
|
146
|
+
- **タスクが解決済みと判明した時**: 即座に `[x]` 化、または陳腐化した記述(例: 「v1.0.0〜v1.6.0」のように完了済みバージョンを含む)は内容を更新
|
|
147
|
+
|
|
100
148
|
| タイミング | 更新内容 |
|
|
101
149
|
|---|---|
|
|
102
150
|
| タスク完了時 | 残タスクの該当行を `[x]` にする |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 開発ワークフローの入口。タスク種別(feature / bug-fix / refactor / security-audit / docs)を確認後、種別に応じた最適なエージェント編成と開始地点を選んで実行する。security-audit は並列レビュー→修正計画→TDD 実装→最終レビューのフル修正サイクルを提供する。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# start
|
|
@@ -240,13 +240,114 @@ new: TASK_TYPE: {task_type}
|
|
|
240
240
|
| feature | 設計 | `.claude/skills/dev-workflow/SKILL.md` を Read してフェーズ B から |
|
|
241
241
|
| feature | 計画 | `.claude/skills/dev-workflow/SKILL.md` を Read してフェーズ C から |
|
|
242
242
|
| feature | 実装 | `.claude/skills/dev-workflow/SKILL.md` を Read してフェーズ D から |
|
|
243
|
-
| bug-fix | systematic-debugger 直起動 | Agent ツールで `systematic-debugger` を起動 → `developer` → `tester`
|
|
243
|
+
| bug-fix | systematic-debugger 直起動 | Agent ツールで `systematic-debugger` を起動 → `developer` → `tester` 完了後、`code-reviewer` と `security-reviewer` を 1 メッセージ内で並列起動 |
|
|
244
244
|
| bug-fix | 計画から | `.claude/skills/dev-workflow/SKILL.md` を Read してフェーズ C から(既存 plan-report を利用) |
|
|
245
|
+
|
|
245
246
|
| refactor | 計画 | Agent ツールで `planner` を起動して `po_plan_version` 付き plan-report を生成 → `.claude/skills/wave-execution/SKILL.md` を Read |
|
|
246
247
|
| refactor | 実装 | `.claude/skills/wave-execution/SKILL.md` を Read して PO 並列実行に直接入る |
|
|
247
248
|
| security-audit | 即実行 | Agent ツールで `code-reviewer` と `security-reviewer` を **1 メッセージ内で並列起動** |
|
|
249
|
+
| security-audit | 承認後 | Step 3(フェーズ F/G/H)へ進む(自動遷移) |
|
|
248
250
|
| docs | 即実行 | Agent ツールで `doc-writer` を単独起動 |
|
|
249
251
|
|
|
250
252
|
**最初に必ず** 遷移先の SKILL.md を Read してから実行する。記憶・推測で進めず、AskUserQuestion・Edit・セッションファイル更新の手順を省略しないこと。
|
|
251
253
|
|
|
252
254
|
各エージェント完了後は通常の Approval Flow に従う。
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Step 3: security-audit 承認後フェーズ
|
|
259
|
+
|
|
260
|
+
security-audit の並列レビュー(Step 2)で両レポートが生成され、ユーザー承認を得た後に
|
|
261
|
+
このフェーズへ進む。フェーズ F → G → H の順に実行する。
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## フェーズ F: 修正計画(planner)
|
|
266
|
+
|
|
267
|
+
Glob で `.claude/reports/code-review-report-*.md` と
|
|
268
|
+
`.claude/reports/security-review-report-*.md` の最新をそれぞれ確認する。
|
|
269
|
+
|
|
270
|
+
Agent ツールで `planner` を起動する。プロンプトには両レポートのファイルパスのみ渡し、Read はエージェント側で行わせる(内容を直接プロンプトに展開しない)[SR-AI-001 対策]。プロンプトには以下を含める:
|
|
271
|
+
- 両レポートのファイルパス(パスのみ渡す)
|
|
272
|
+
- 修正タスクを **High / Medium / Low** の重要度別に整理すること
|
|
273
|
+
- 各タスクに「なぜ直すか(根拠・checklist_id)」を記録すること
|
|
274
|
+
- 許容例外(直さないと判断したもの)を `## 許容・除外した変更` セクションに
|
|
275
|
+
理由付きで明示すること
|
|
276
|
+
- 各タスクに **複雑度ラベル** を付与すること
|
|
277
|
+
(Low=1〜5 行 / Medium=〜20 行 / High=大規模リファクタ)
|
|
278
|
+
- 出力先: `.claude/reports/plan-report-YYYYMMDD-HHMMSS.md`(タイムスタンプは `report-timestamp` スキルで取得)
|
|
279
|
+
|
|
280
|
+
planner 完了後、AskUserQuestion で承認を取る:
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"questions": [{
|
|
285
|
+
"question": "plan-report の内容を確認してください。どうしますか?",
|
|
286
|
+
"header": "フェーズ F 承認",
|
|
287
|
+
"options": [
|
|
288
|
+
{ "label": "承認—フェーズ G へ進む", "description": "plan-report の修正タスクを TDD で実装する" },
|
|
289
|
+
{ "label": "否認・修正を依頼する", "description": "フィードバックを入力して planner を再起動する" },
|
|
290
|
+
{ "label": "否認・自分で修正する", "description": "plan-report を手動編集してから再開する" }
|
|
291
|
+
]
|
|
292
|
+
}]
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## フェーズ G: 実装(TDD)
|
|
299
|
+
|
|
300
|
+
フェーズ F で承認された plan-report の各修正タスクを以下のサイクルで処理する。
|
|
301
|
+
plan-report はファイルパスとして渡し、tester・developer が Read して内容を参照する。
|
|
302
|
+
|
|
303
|
+
各タスクごとに:
|
|
304
|
+
|
|
305
|
+
**G-1: tester(Red フェーズ)**
|
|
306
|
+
Agent ツールで `tester` を起動し、修正タスクに対するテストを先行作成させる。
|
|
307
|
+
テストは実装前なので失敗する(Red)のが正しい状態。
|
|
308
|
+
|
|
309
|
+
**G-2: developer(Green フェーズ)**
|
|
310
|
+
Agent ツールで `developer` を起動し、G-1 のテストが通る最小実装を行わせる。
|
|
311
|
+
|
|
312
|
+
**G-2.5: Stuck チェック**
|
|
313
|
+
`.claude/reports/debug-needed-*.md` が存在する場合は Agent ツールで
|
|
314
|
+
`systematic-debugger` を起動して根本原因を調査する。
|
|
315
|
+
|
|
316
|
+
**G-3: tester(最終検証)**
|
|
317
|
+
Agent ツールで `tester` を起動し、全テストの合否を確認させる。
|
|
318
|
+
|
|
319
|
+
全タスクの TDD サイクル(G-1〜G-3)が完了した後、承認なしでフェーズ H へ進む。
|
|
320
|
+
|
|
321
|
+
**設計判断**: フェーズ F で plan-report が承認済みのため、フェーズ G 内の中間承認は不要(承認済みの計画を自律実行する)。レビューゲートはフェーズ H(code-reviewer + security-reviewer 並列)で担保する。
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## フェーズ H: 最終レビュー
|
|
326
|
+
|
|
327
|
+
Agent ツールで `code-reviewer` と `security-reviewer` を **1 メッセージ内で並列起動** する。
|
|
328
|
+
|
|
329
|
+
- `code-reviewer`: フェーズ G で実装したコードの品質・保守性を確認
|
|
330
|
+
- `security-reviewer`: 修正適用後に新たな脆弱性が生まれていないかを確認
|
|
331
|
+
(修正実装によって別の攻撃経路が開く可能性はゼロではないため必須)
|
|
332
|
+
|
|
333
|
+
いずれかのレビューエージェントが失敗した場合は再起動して両方の結果を得てから統合する。
|
|
334
|
+
|
|
335
|
+
両レビュー完了後、AskUserQuestion で承認を取る。承認時は親 Claude がコミットを提案する(git add / git commit):
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"questions": [{
|
|
340
|
+
"question": "最終レビュー結果を確認してください。どうしますか?",
|
|
341
|
+
"header": "フェーズ H 承認",
|
|
342
|
+
"options": [
|
|
343
|
+
{ "label": "承認—コミットへ進む", "description": "修正をコミットして完了" },
|
|
344
|
+
{ "label": "全て対応する", "description": "全指摘を修正してフェーズ F へ戻る" },
|
|
345
|
+
{ "label": "対応する指摘を選ぶ", "description": "対応指摘を選択してフェーズ F へ戻る" },
|
|
346
|
+
{ "label": "全て許容して進む", "description": "指摘を許容理由付きで記録してコミットへ進む" }
|
|
347
|
+
]
|
|
348
|
+
}]
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
「全て対応する」「対応する指摘を選ぶ」を選んだ場合はフェーズ F へ戻り、
|
|
353
|
+
新たな plan-report を生成して TDD サイクルを再度実施する。
|
{claude_code_conductor-1.5.2 → claude_code_conductor-1.7.0}/.claude/skills/task-routing/SKILL.md
RENAMED
|
@@ -62,10 +62,10 @@ AskUserQuestion ツール:
|
|
|
62
62
|
| 1 | `systematic-debugger` | 不具合の根本原因を特定 |
|
|
63
63
|
| 2 | `developer` | 修正実装 |
|
|
64
64
|
| 3 | `tester` | リグレッション確認 |
|
|
65
|
-
| 4 | `code-reviewer` |
|
|
65
|
+
| 4 | `code-reviewer` + `security-reviewer` | 最終レビュー |
|
|
66
66
|
|
|
67
67
|
意図: 原因不明の不具合は systematic-debugger で先に切り分けてから developer に渡す。
|
|
68
|
-
security-reviewer
|
|
68
|
+
修正後のコードに新たな脆弱性が生まれる可能性があるため、最終レビューは code-reviewer と security-reviewer の並列起動で両面を確認する。
|
|
69
69
|
|
|
70
70
|
### feature(直列・dev-workflow フルパス)
|
|
71
71
|
|
|
@@ -90,6 +90,7 @@ security-reviewer は省略(必要なら後から追加)。
|
|
|
90
90
|
|
|
91
91
|
意図: 動作を変えないため、各リファクタを worktree で並列化できる。
|
|
92
92
|
PO(Parallel Orchestra)の `c3 po run` で時間短縮を狙う。
|
|
93
|
+
最終レビューは `code-reviewer` のみ(リファクタは動作変更を伴わないため新たな攻撃面が生まれにくく、security-reviewer は省略可)。
|
|
93
94
|
|
|
94
95
|
### security-audit(並列・レビュアー 2 体)
|
|
95
96
|
|
|
@@ -99,7 +100,7 @@ PO(Parallel Orchestra)の `c3 po run` で時間短縮を狙う。
|
|
|
99
100
|
| `code-reviewer` | 並列起動 |
|
|
100
101
|
|
|
101
102
|
意図: 既存コードへの監査のため、レビュアー 2 体を同時に当てる。
|
|
102
|
-
|
|
103
|
+
検出指摘の対応は `/start` の security-audit フェーズ F/G/H(修正計画 → TDD 実装 → 最終レビュー)で行う。
|
|
103
104
|
|
|
104
105
|
### docs(直列・軽量)
|
|
105
106
|
|
|
@@ -145,7 +146,8 @@ AskUserQuestion ツール:
|
|
|
145
146
|
- **feature**:
|
|
146
147
|
- `args` に `from_start=true` が含まれているとき: 種別を返却するのみ(制御を /start に返す。再帰呼び出しを避ける)
|
|
147
148
|
- `args` 指定なし/`from_start=false` のとき: `.claude/skills/start/SKILL.md` を Read して `/start` フローに合流する
|
|
148
|
-
- **bug-fix
|
|
149
|
+
- **bug-fix**: `systematic-debugger` → `developer` → `tester` の順に Agent ツールで順次起動し、完了後に `code-reviewer` と `security-reviewer` を 1 メッセージ内で並列起動する
|
|
150
|
+
- **docs**: Agent ツールで `doc-writer` を起動する
|
|
149
151
|
- **refactor**: planner で `po_plan_version` 付き plan-report を生成 → `.claude/skills/wave-execution/SKILL.md` を Read して PO 並列実行に合流する
|
|
150
152
|
- **security-audit**: code-reviewer と security-reviewer を **1 メッセージ内で並列起動**(複数 Agent ツール呼び出し)
|
|
151
153
|
|