claude-code-conductor 0.2.0__py3-none-any.whl

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 (57) hide show
  1. c3/__init__.py +3 -0
  2. c3/__main__.py +4 -0
  3. c3/_template/.claude/CLAUDE.md +182 -0
  4. c3/_template/.claude/agents/architect.md +50 -0
  5. c3/_template/.claude/agents/code-reviewer.md +50 -0
  6. c3/_template/.claude/agents/developer.md +55 -0
  7. c3/_template/.claude/agents/doc-writer.md +62 -0
  8. c3/_template/.claude/agents/interviewer.md +46 -0
  9. c3/_template/.claude/agents/planner.md +59 -0
  10. c3/_template/.claude/agents/project-setup.md +106 -0
  11. c3/_template/.claude/agents/security-reviewer.md +51 -0
  12. c3/_template/.claude/agents/tdd-develop.md +117 -0
  13. c3/_template/.claude/agents/tester.md +48 -0
  14. c3/_template/.claude/commands/develop.md +10 -0
  15. c3/_template/.claude/commands/doc.md +174 -0
  16. c3/_template/.claude/commands/extract-lib.md +292 -0
  17. c3/_template/.claude/commands/init-session.md +110 -0
  18. c3/_template/.claude/commands/mcp.md +322 -0
  19. c3/_template/.claude/commands/promote-pattern.md +135 -0
  20. c3/_template/.claude/commands/review.md +9 -0
  21. c3/_template/.claude/commands/setup.md +206 -0
  22. c3/_template/.claude/commands/start.md +88 -0
  23. c3/_template/.claude/docs/parallel-orchestra-manifest.md +108 -0
  24. c3/_template/.claude/hooks/clear_file_history.py +39 -0
  25. c3/_template/.claude/hooks/enable_sandbox.py +61 -0
  26. c3/_template/.claude/hooks/pre_compact.py +82 -0
  27. c3/_template/.claude/hooks/pre_tool.py +64 -0
  28. c3/_template/.claude/hooks/statusline.py +170 -0
  29. c3/_template/.claude/hooks/stop.py +202 -0
  30. c3/_template/.claude/hooks/validate_skill_change.py +33 -0
  31. c3/_template/.claude/hooks/worktree_guard.py +53 -0
  32. c3/_template/.claude/memory/.gitkeep +0 -0
  33. c3/_template/.claude/rules/code-review-checklist.md +91 -0
  34. c3/_template/.claude/rules/promoted/index.md +5 -0
  35. c3/_template/.claude/rules/security-review-checklist.md +84 -0
  36. c3/_template/.claude/settings.json +136 -0
  37. c3/_template/.claude/settings.local.json +126 -0
  38. c3/_template/.claude/skills/dev-workflow.md +484 -0
  39. c3/_template/.claude/skills/parallel-execution.md +121 -0
  40. c3/_template/.claude/skills/promoted/index.md +5 -0
  41. c3/_template/.claude/skills/worktree-tdd-workflow.md +71 -0
  42. c3/cli.py +63 -0
  43. c3/cli_doctor.py +135 -0
  44. c3/cli_init.py +70 -0
  45. c3/cli_list.py +69 -0
  46. c3/cli_po.py +102 -0
  47. c3/cli_update.py +117 -0
  48. c3/paths.py +64 -0
  49. c3/po/__init__.py +11 -0
  50. c3/po/detect.py +44 -0
  51. c3/po/manifest.py +336 -0
  52. c3/po/run.py +105 -0
  53. claude_code_conductor-0.2.0.dist-info/METADATA +362 -0
  54. claude_code_conductor-0.2.0.dist-info/RECORD +57 -0
  55. claude_code_conductor-0.2.0.dist-info/WHEEL +4 -0
  56. claude_code_conductor-0.2.0.dist-info/entry_points.txt +2 -0
  57. claude_code_conductor-0.2.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,206 @@
1
+ # /setup コマンド
2
+
3
+ プロジェクトのコーディング規約を設定する。
4
+ ヒアリングは親 Claude が担当し、収集後に project-setup エージェントを起動する。
5
+
6
+ ---
7
+
8
+ ## Phase 1: 技術スタックのヒアリング(親 Claude が実施)
9
+
10
+ ### Q1: 言語・バージョン
11
+
12
+ AskUserQuestion ツール:
13
+ ```json
14
+ {
15
+ "questions": [{
16
+ "question": "使用する言語とバージョンを教えてください",
17
+ "options": [
18
+ { "label": "Python", "description": "バージョンを後で確認します" },
19
+ { "label": "TypeScript / JavaScript", "description": "バージョンを後で確認します" },
20
+ { "label": "Go", "description": "バージョンを後で確認します" },
21
+ { "label": "Java / Kotlin", "description": "バージョンを後で確認します" },
22
+ { "label": "C# / .NET", "description": "バージョンを後で確認します" },
23
+ { "label": "その他・自由入力" }
24
+ ]
25
+ }]
26
+ }
27
+ ```
28
+
29
+ 選択後にバージョンを確認する。
30
+
31
+ ### Q2: フレームワーク
32
+
33
+ AskUserQuestion ツール:
34
+ ```json
35
+ {
36
+ "questions": [{
37
+ "question": "使用するフレームワーク・主要ライブラリを教えてください",
38
+ "options": [
39
+ { "label": "使用するものがある", "description": "具体的に入力してください" },
40
+ { "label": "まだ決めていない" },
41
+ { "label": "使用しない" }
42
+ ]
43
+ }]
44
+ }
45
+ ```
46
+
47
+ ### Q3: 実行環境
48
+
49
+ AskUserQuestion ツール:
50
+ ```json
51
+ {
52
+ "questions": [{
53
+ "question": "実行環境はどれですか?",
54
+ "options": [
55
+ { "label": "サーバーサイド(API・バックエンド)" },
56
+ { "label": "ブラウザ(フロントエンド)" },
57
+ { "label": "両方(フルスタック)" },
58
+ { "label": "CLI ツール" },
59
+ { "label": "その他・自由入力" }
60
+ ]
61
+ }]
62
+ }
63
+ ```
64
+
65
+ ### Q4: データベース
66
+
67
+ AskUserQuestion ツール:
68
+ ```json
69
+ {
70
+ "questions": [{
71
+ "question": "データベースは使いますか?",
72
+ "options": [
73
+ { "label": "PostgreSQL" },
74
+ { "label": "MySQL / MariaDB" },
75
+ { "label": "SQLite" },
76
+ { "label": "MongoDB" },
77
+ { "label": "その他・自由入力" },
78
+ { "label": "使わない" }
79
+ ]
80
+ }]
81
+ }
82
+ ```
83
+
84
+ ### Q5: テストフレームワーク
85
+
86
+ AskUserQuestion ツール:
87
+ ```json
88
+ {
89
+ "questions": [{
90
+ "question": "テストフレームワークは決まっていますか?",
91
+ "options": [
92
+ { "label": "決まっている", "description": "具体的に入力してください" },
93
+ { "label": "まだ決めていない" }
94
+ ]
95
+ }]
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Phase 2: 独自規約のヒアリング(親 Claude が実施)
102
+
103
+ ### Q6: 参考スタイルガイド
104
+
105
+ AskUserQuestion ツール:
106
+ ```json
107
+ {
108
+ "questions": [{
109
+ "question": "参考にするスタイルガイドはありますか?",
110
+ "options": [
111
+ { "label": "公式スタイルガイドに従う", "description": "PEP8・Google・StandardJS 等" },
112
+ { "label": "Airbnb スタイル" },
113
+ { "label": "独自ルールがある", "description": "後で詳しく教えてください" },
114
+ { "label": "特になし・おすすめに任せる" }
115
+ ]
116
+ }]
117
+ }
118
+ ```
119
+
120
+ ### Q7: コメント方針
121
+
122
+ AskUserQuestion ツール:
123
+ ```json
124
+ {
125
+ "questions": [{
126
+ "question": "コードコメントの方針を教えてください",
127
+ "options": [
128
+ { "label": "最小限にする", "description": "コード自体を読みやすく書く" },
129
+ { "label": "積極的に書く" },
130
+ { "label": "英語で統一" },
131
+ { "label": "日本語で統一" },
132
+ { "label": "特になし" }
133
+ ],
134
+ "multiSelect": true
135
+ }]
136
+ }
137
+ ```
138
+
139
+ ### Q8: テストカバレッジ
140
+
141
+ AskUserQuestion ツール:
142
+ ```json
143
+ {
144
+ "questions": [{
145
+ "question": "テストカバレッジの目標はありますか?",
146
+ "options": [
147
+ { "label": "80% 以上" },
148
+ { "label": "クリティカルパスのみ" },
149
+ { "label": "数値目標なし" },
150
+ { "label": "その他・自由入力" }
151
+ ]
152
+ }]
153
+ }
154
+ ```
155
+
156
+ ### Q9: その他の規約
157
+
158
+ AskUserQuestion ツール:
159
+ ```json
160
+ {
161
+ "questions": [{
162
+ "question": "他に規約として残しておきたいことはありますか?",
163
+ "options": [
164
+ { "label": "ある", "description": "自由に入力してください" },
165
+ { "label": "特になし" }
166
+ ]
167
+ }]
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Phase 3: project-setup エージェントの起動
174
+
175
+ 全ヒアリング結果を整理して Agent ツールで `project-setup` エージェントを起動する。
176
+
177
+ プロンプト形式:
178
+ ```
179
+ 以下の情報をもとに rules/ ファイルを生成してください。
180
+
181
+ ## 技術スタック
182
+ - 言語・バージョン: {回答}
183
+ - フレームワーク: {回答}
184
+ - 実行環境: {回答}
185
+ - データベース: {回答}
186
+ - テストフレームワーク: {回答}
187
+
188
+ ## チーム規約
189
+ - 参考スタイルガイド: {回答}
190
+ - コメント方針: {回答}
191
+ - テストカバレッジ目標: {回答}
192
+ - その他: {回答}
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Phase 4: 完了報告
198
+
199
+ ```
200
+ セットアップ完了:
201
+ .claude/rules/coding-standards.md — 標準コーディング規約
202
+ .claude/rules/project-conventions.md — プロジェクト固有の規約
203
+
204
+ 次回から architect・developer・tester・code-reviewer・security-reviewer
205
+ がこれらのルールを参照して作業します。
206
+ ```
@@ -0,0 +1,88 @@
1
+ # /start コマンド
2
+
3
+ 開発ワークフローの入口。
4
+
5
+ ---
6
+
7
+ ## Step 0: レポートの整理
8
+
9
+ Glob で `.claude/reports/*.md` を検索する(`archive/` 配下は含まない)。
10
+ レポートが存在しない場合はこの Step をスキップして Step 1 へ進む。
11
+
12
+ レポートが存在する場合はファイル名の一覧をテキストで提示してから AskUserQuestion で確認する:
13
+
14
+ ```json
15
+ {
16
+ "questions": [{
17
+ "question": "既存のレポートがあります。どうしますか?",
18
+ "options": [
19
+ { "label": "全てアーカイブして新しく始める", "description": "全レポートを reports/archive/ に移動する" },
20
+ { "label": "アーカイブするフェーズを選ぶ", "description": "フェーズ単位で選んで一部だけ移動する" },
21
+ { "label": "そのまま引き継ぐ", "description": "レポートを変更せずに続ける" }
22
+ ]
23
+ }]
24
+ }
25
+ ```
26
+
27
+ **「全てアーカイブして新しく始める」の場合:**
28
+ Bash ツールで実行する:
29
+ ```bash
30
+ mkdir -p .claude/reports/archive && mv .claude/reports/*.md .claude/reports/archive/
31
+ ```
32
+
33
+ **「アーカイブするフェーズを選ぶ」の場合:**
34
+ AskUserQuestion で対象フェーズを確認する:
35
+
36
+ ```json
37
+ {
38
+ "questions": [{
39
+ "question": "アーカイブするフェーズを選んでください(複数選択可)",
40
+ "options": [
41
+ { "label": "要件定義", "description": "requirements-report-*.md" },
42
+ { "label": "設計", "description": "architecture-report-*.md" },
43
+ { "label": "計画", "description": "plan-report-*.md" },
44
+ { "label": "レビュー", "description": "code-review-report-*.md / security-review-report-*.md" }
45
+ ],
46
+ "multiSelect": true
47
+ }]
48
+ }
49
+ ```
50
+
51
+ 選択されたフェーズに対応するファイルを Bash ツールで移動する(ファイルが存在しない場合はスキップ):
52
+ - 要件定義: `mkdir -p .claude/reports/archive && mv .claude/reports/requirements-report-*.md .claude/reports/archive/ 2>/dev/null || true`
53
+ - 設計: `mkdir -p .claude/reports/archive && mv .claude/reports/architecture-report-*.md .claude/reports/archive/ 2>/dev/null || true`
54
+ - 計画: `mkdir -p .claude/reports/archive && mv .claude/reports/plan-report-*.md .claude/reports/archive/ 2>/dev/null || true`
55
+ - レビュー: `mkdir -p .claude/reports/archive && mv .claude/reports/code-review-report-*.md .claude/reports/archive/ 2>/dev/null || true && mv .claude/reports/security-review-report-*.md .claude/reports/archive/ 2>/dev/null || true`
56
+
57
+ ---
58
+
59
+ ## Step 1: 開始地点の選択
60
+
61
+ AskUserQuestion ツールで以下を提示する:
62
+
63
+ ```json
64
+ {
65
+ "questions": [{
66
+ "question": "どこから始めますか?",
67
+ "options": [
68
+ { "label": "ヒアリング", "description": "要件を整理するところから始める(新規・大きな変更)" },
69
+ { "label": "設計", "description": "要件は明確なので設計から始める" },
70
+ { "label": "計画", "description": "設計済みなのでタスク計画から始める" },
71
+ { "label": "実装", "description": "計画済みなので実装から始める" }
72
+ ]
73
+ }]
74
+ }
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Step 2: dev-workflow.md を Read してフェーズを実行する
80
+
81
+ **最初に必ず** `.claude/skills/dev-workflow.md` を Read する。記憶・推測で進めず、dev-workflow.md の AskUserQuestion・Edit・セッションファイル更新の手順を省略しないこと。
82
+
83
+ 選択した開始地点に対応するフェーズから実行する:
84
+
85
+ - **ヒアリング** → フェーズ A から実行
86
+ - **設計** → フェーズ B から実行
87
+ - **計画** → フェーズ C から実行
88
+ - **実装** → フェーズ D から実行
@@ -0,0 +1,108 @@
1
+ # Parallel Orchestra YAML フロントマター仕様
2
+
3
+ Parallel Orchestra が読み込む YAML フロントマターのフォーマット定義。
4
+ C3 では `plan-report` ファイルのフロントマターとして planner が出力する。
5
+
6
+ ---
7
+
8
+ ## フィールド一覧
9
+
10
+ | フィールド | 必須 | 型 | 備考 |
11
+ |---|---|---|---|
12
+ | `po_plan_version` | ✅ | string | フォーマットバージョン(現在: `"0.1"`) |
13
+ | `name` | ✅ | string | プランの表示名 |
14
+ | `cwd` | ✅ | string | YAML フロントマターが書かれたファイルのディレクトリからプロジェクトルートへの相対パス |
15
+ | `tasks` | ✅ | array | タスク定義の配列(1件以上) |
16
+ | `tasks[].id` | ✅ | string | タスクの一意識別子。英数字・ハイフン・アンダースコアのみ |
17
+ | `tasks[].agent` | ✅ | string | 使用するエージェント名 |
18
+ | `tasks[].read_only` | ✅ | boolean | `true`: 読み取り専用(worktree なし)/`false`: 書き込みあり(worktree 作成) |
19
+ | `tasks[].prompt` | ✅ | string | エージェントへの指示内容 |
20
+ | `tasks[].depends_on` | 任意 | string[] | 先行タスクの ID リスト。DAG スケジューリングに使用 |
21
+ | `tasks[].writes` | 任意 | string[] | このタスクが書き込むファイルパス。タスク間の衝突検出ヒントに使用 |
22
+ | `tasks[].max_retries` | 任意 | integer (≥0) | プロセス失敗時の最大リトライ回数。`defaults.max_retries` を上書き |
23
+ | `tasks[].concurrency_group` | 任意 | string | 同時実行数を制限するグループ名。`concurrency_limits` に対応するエントリが必要 |
24
+ | `defaults` | 任意 | object | 全タスク共通のデフォルト値 |
25
+ | `defaults.max_retries` | 任意 | integer (≥0) | タスクレベルの `max_retries` が未指定の場合に使用 |
26
+ | `concurrency_limits` | 任意 | object | グループ名をキー、最大同時実行数を値とするマップ |
27
+ | `on_complete` | 任意 | object | 全タスク成功時の Webhook 設定 |
28
+ | `on_complete.webhook_url` | — | string | HTTP/HTTPS URL |
29
+ | `on_failure` | 任意 | object | 1件以上のタスク失敗時の Webhook 設定 |
30
+ | `on_failure.webhook_url` | — | string | HTTP/HTTPS URL |
31
+
32
+ ---
33
+
34
+ ## Parallel Orchestra が内部で管理するもの(フロントマターに書かない)
35
+
36
+ | 項目 | 理由 |
37
+ |---|---|
38
+ | `timeout_sec` | Parallel Orchestra がデフォルト値を内部保持 |
39
+ | `idle_timeout_sec` | worktree + Agent ツール構成では誤検知になるため不採用 |
40
+ | `retry_delay_sec` / `retry_backoff_factor` | Parallel Orchestra が固定値を内部保持 |
41
+ | タスクの CWD(起動時) | `read_only: false` → worktree ルート、`read_only: true` → プロジェクトルートを PO が自動設定 |
42
+ | `PO_WORKTREE_GUARD=1` | `read_only: false` タスク起動時に PO が自動セット |
43
+
44
+ ---
45
+
46
+ ## フォーマット例
47
+
48
+ ```yaml
49
+ ---
50
+ po_plan_version: "0.1"
51
+ name: "ユーザー認証機能の並列実装"
52
+ cwd: "../.."
53
+
54
+ tasks:
55
+ - id: tdd-auth-login
56
+ agent: tdd-develop
57
+ read_only: false
58
+ prompt: |
59
+ ログイン機能を TDD で実装してください。
60
+ plan-report: .claude/reports/plan-report-20260429-120000.md
61
+ writes:
62
+ - src/auth/login.py
63
+ - tests/test_login.py
64
+
65
+ - id: tdd-auth-logout
66
+ agent: tdd-develop
67
+ read_only: false
68
+ prompt: |
69
+ ログアウト機能を TDD で実装してください。
70
+ plan-report: .claude/reports/plan-report-20260429-120000.md
71
+ writes:
72
+ - src/auth/logout.py
73
+ - tests/test_logout.py
74
+
75
+ - id: review-auth
76
+ agent: code-reviewer
77
+ read_only: true
78
+ prompt: "認証モジュール全体のコードレビューを行ってください。"
79
+ depends_on: [tdd-auth-login, tdd-auth-logout]
80
+ concurrency_group: api-calls
81
+
82
+ defaults:
83
+ max_retries: 1
84
+
85
+ concurrency_limits:
86
+ api-calls: 2
87
+
88
+ on_failure:
89
+ webhook_url: "https://example.com/notify"
90
+ ---
91
+ ```
92
+
93
+ ---
94
+
95
+ ## C3 における配置場所
96
+
97
+ | ファイル | パス |
98
+ |---|---|
99
+ | plan-report(フロントマターを含む) | `.claude/reports/plan-report-YYYYMMDD-HHMMSS.md` |
100
+ | `cwd` の値(C3 標準) | `"../.."` |
101
+
102
+ ---
103
+
104
+ ## 注意事項
105
+
106
+ - `claude -p` の起動 CWD は `cwd` フィールドではなく worktree ルートパスを使用する
107
+ - `cwd` は Parallel Orchestra が git worktree を作成するための**プロジェクトルート特定**に使用する
108
+ - `read_only: false` タスクは必ず git リポジトリ内で実行すること(worktree が git 依存のため)
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env python3
2
+ """Utility: clear ~/.claude/file-history/ directory."""
3
+
4
+ import os
5
+ import shutil
6
+ import sys
7
+
8
+ sys.stdout.reconfigure(encoding='utf-8')
9
+ sys.stderr.reconfigure(encoding='utf-8')
10
+
11
+ FILE_HISTORY_DIR = os.path.join(os.path.expanduser('~'), '.claude', 'file-history')
12
+
13
+
14
+ def main():
15
+ if not os.path.isdir(FILE_HISTORY_DIR):
16
+ print('[clear-file-history] file-history フォルダが存在しません。スキップします。')
17
+ return
18
+
19
+ entries = os.listdir(FILE_HISTORY_DIR)
20
+ deleted = 0
21
+
22
+ for name in entries:
23
+ full_path = os.path.join(FILE_HISTORY_DIR, name)
24
+ try:
25
+ if os.path.isdir(full_path):
26
+ shutil.rmtree(full_path)
27
+ else:
28
+ os.unlink(full_path)
29
+ deleted += 1
30
+ except FileNotFoundError:
31
+ pass
32
+ except Exception as e:
33
+ print(f'[clear-file-history] 削除に失敗: {name} ({e})')
34
+
35
+ print(f'[clear-file-history] {deleted} 件削除しました。')
36
+
37
+
38
+ if __name__ == '__main__':
39
+ main()
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ """Utility: ensure full sandbox config is present in settings.json."""
3
+
4
+ import json
5
+ import os
6
+ import sys
7
+
8
+ sys.stdout.reconfigure(encoding='utf-8')
9
+ sys.stderr.reconfigure(encoding='utf-8')
10
+
11
+ FULL_SANDBOX_CONFIG = {
12
+ "enabled": True,
13
+ "autoAllowBashIfSandboxed": True,
14
+ "allowUnsandboxedCommands": False,
15
+ "excludedCommands": [],
16
+ "network": {
17
+ "allowUnixSockets": [],
18
+ "allowAllUnixSockets": False,
19
+ "allowLocalBinding": False,
20
+ "allowedDomains": []
21
+ },
22
+ "enableWeakerNestedSandbox": True
23
+ }
24
+
25
+
26
+ def main():
27
+ cwd = os.getcwd()
28
+
29
+ # git worktree 内では実行しない(.git がファイルの場合は worktree)
30
+ git_path = os.path.join(cwd, '.git')
31
+ if os.path.exists(git_path) and os.path.isfile(git_path):
32
+ print('[enable-sandbox] git worktree 内での実行のためスキップします。')
33
+ return
34
+
35
+ settings_path = os.path.join(cwd, '.claude', 'settings.json')
36
+ if not os.path.exists(settings_path):
37
+ print(f'[enable-sandbox] settings.json が見つかりません: {settings_path}')
38
+ return
39
+
40
+ with open(settings_path, 'r', encoding='utf-8') as f:
41
+ try:
42
+ settings = json.load(f)
43
+ except json.JSONDecodeError as e:
44
+ print(f'[enable-sandbox] settings.json の JSON 解析に失敗しました: {e}')
45
+ return
46
+
47
+ if settings.get('sandbox', {}).get('enabled') is True:
48
+ print('[enable-sandbox] sandbox はすでに有効です。')
49
+ return
50
+
51
+ settings['sandbox'] = FULL_SANDBOX_CONFIG
52
+
53
+ with open(settings_path, 'w', encoding='utf-8') as f:
54
+ json.dump(settings, f, ensure_ascii=False, indent=2)
55
+ f.write('\n')
56
+
57
+ print('[enable-sandbox] sandbox を有効化しました。Claude Code 再起動後に反映されます。')
58
+
59
+
60
+ if __name__ == '__main__':
61
+ main()
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+ """PreCompact hook: append checkpoint marker to today's session file."""
3
+
4
+ import json
5
+ import os
6
+ import sys
7
+ from datetime import datetime, timezone
8
+
9
+ sys.stdout.reconfigure(encoding='utf-8')
10
+ sys.stderr.reconfigure(encoding='utf-8')
11
+
12
+
13
+ def is_worktree(cwd: str) -> bool:
14
+ git_path = os.path.join(cwd, '.git')
15
+ return os.path.exists(git_path) and os.path.isfile(git_path)
16
+
17
+
18
+ def create_session_template(date_str: str) -> str:
19
+ return (
20
+ f"SESSION: {date_str}\n"
21
+ f"AGENT: \n"
22
+ f"DURATION: \n"
23
+ f"\n"
24
+ f"## うまくいったアプローチ\n"
25
+ f"\n"
26
+ f"## 試みたが失敗したアプローチ\n"
27
+ f"\n"
28
+ f"## 残タスク\n"
29
+ f"\n"
30
+ f"## 事実ログ(自動生成 / stop.py)\n"
31
+ f"- 記録時刻: \n"
32
+ f"\n"
33
+ f"<!-- C3:SESSION:JSON\n"
34
+ f"{{\n"
35
+ f' "session": "{date_str}",\n'
36
+ f' "patterns": [],\n'
37
+ f' "successes": [],\n'
38
+ f' "failures": [],\n'
39
+ f' "todos": []\n'
40
+ f"}}\n"
41
+ f"-->\n"
42
+ )
43
+
44
+
45
+ def main():
46
+ try:
47
+ json.loads(sys.stdin.read())
48
+ except (json.JSONDecodeError, ValueError):
49
+ pass
50
+
51
+ cwd = os.getcwd()
52
+
53
+ if is_worktree(cwd):
54
+ sys.exit(0)
55
+
56
+ session_dir = os.path.join(cwd, '.claude', 'memory', 'sessions')
57
+ os.makedirs(session_dir, exist_ok=True)
58
+
59
+ now = datetime.now(timezone.utc)
60
+ date_str = now.strftime('%Y%m%d')
61
+ session_file = os.path.join(session_dir, f'{date_str}.tmp')
62
+
63
+ if not os.path.exists(session_file):
64
+ with open(session_file, 'w', encoding='utf-8') as f:
65
+ f.write(create_session_template(date_str))
66
+
67
+ ts = now.isoformat()
68
+ checkpoint = (
69
+ f'\n'
70
+ f'## [PreCompact checkpoint: {ts}]\n'
71
+ f'コンテキストウィンドウ圧縮が発生しました。\n'
72
+ f'このポイント以前の詳細な文脈は失われています。\n'
73
+ )
74
+
75
+ with open(session_file, 'a', encoding='utf-8') as f:
76
+ f.write(checkpoint)
77
+
78
+ print(f'[PreCompact] セッション状態を {session_file} に保存しました', file=sys.stderr)
79
+
80
+
81
+ if __name__ == '__main__':
82
+ main()
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env python3
2
+ """PreToolUse hook: guard dangerous Bash commands."""
3
+
4
+ import json
5
+ import re
6
+ import sys
7
+
8
+ sys.stdout.reconfigure(encoding='utf-8')
9
+ sys.stderr.reconfigure(encoding='utf-8')
10
+
11
+
12
+ def main():
13
+ try:
14
+ payload = json.loads(sys.stdin.read())
15
+ except (json.JSONDecodeError, ValueError):
16
+ sys.exit(0)
17
+
18
+ if payload.get('tool_name') != 'Bash':
19
+ sys.exit(0)
20
+
21
+ cmd = payload.get('tool_input', {}).get('command', '')
22
+ if not isinstance(cmd, str):
23
+ sys.exit(0)
24
+
25
+ # git force push: 警告(ブロックしない)
26
+ if re.search(r'git\s+push\s+(--force|--force-with-lease|-f)\b', cmd):
27
+ print('[PreToolUse WARNING] git force push を検出しました。実行前にユーザーに確認を取ってください。',
28
+ file=sys.stderr)
29
+
30
+ # DROP TABLE / DROP DATABASE / TRUNCATE: 警告(ブロックしない)
31
+ if re.search(r'DROP\s+TABLE|DROP\s+DATABASE|TRUNCATE', cmd, re.IGNORECASE):
32
+ print('[PreToolUse WARNING] 破壊的な DB 操作を検出しました。本番環境での実行でないことを確認してください。',
33
+ file=sys.stderr)
34
+
35
+ # cd コマンド: CWD 固定バグを防ぐためブロック
36
+ # Bash ツールで cd を実行すると以降の全コマンドの CWD が変わり、
37
+ # フックが相対パスで .claude/hooks/ を参照できなくなる。
38
+ if re.search(r'(?:^|[;&|])\s*cd(?:\s|$)', cmd):
39
+ print(
40
+ '[PreToolUse BLOCK] cd コマンドをブロックしました。\n'
41
+ 'Bash ツールで cd を実行すると CWD が変わり、以降のフックが失敗します。\n'
42
+ 'cd を使わず、プロジェクトルートからの相対パスで実行してください。\n'
43
+ '例: python -m pytest test1/tests -v (cd test1 && python -m pytest の代わり)',
44
+ file=sys.stderr
45
+ )
46
+ sys.exit(2)
47
+
48
+ # rm -rf 系: ブロック
49
+ # 短フラグ形式(-rf / -fr / -r -f 等)とロングオプション形式(--recursive --force)に対応
50
+ if re.search(r'\brm\b', cmd):
51
+ short_flags = ''.join(re.findall(r'-[a-zA-Z]+', cmd))
52
+ has_r = 'r' in short_flags or bool(re.search(r'\brm\b.*\s-[a-zA-Z]*r[a-zA-Z]*', cmd))
53
+ has_f = 'f' in short_flags or bool(re.search(r'\brm\b.*\s-[a-zA-Z]*f[a-zA-Z]*', cmd))
54
+ has_long_recursive = '--recursive' in cmd
55
+ has_long_force = '--force' in cmd
56
+ if (has_r and has_f) or (has_long_recursive and has_long_force):
57
+ print(f'[PreToolUse BLOCK] 危険なコマンドをブロックしました: {cmd}', file=sys.stderr)
58
+ sys.exit(2)
59
+
60
+ sys.exit(0)
61
+
62
+
63
+ if __name__ == '__main__':
64
+ main()