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.
- c3/__init__.py +3 -0
- c3/__main__.py +4 -0
- c3/_template/.claude/CLAUDE.md +182 -0
- c3/_template/.claude/agents/architect.md +50 -0
- c3/_template/.claude/agents/code-reviewer.md +50 -0
- c3/_template/.claude/agents/developer.md +55 -0
- c3/_template/.claude/agents/doc-writer.md +62 -0
- c3/_template/.claude/agents/interviewer.md +46 -0
- c3/_template/.claude/agents/planner.md +59 -0
- c3/_template/.claude/agents/project-setup.md +106 -0
- c3/_template/.claude/agents/security-reviewer.md +51 -0
- c3/_template/.claude/agents/tdd-develop.md +117 -0
- c3/_template/.claude/agents/tester.md +48 -0
- c3/_template/.claude/commands/develop.md +10 -0
- c3/_template/.claude/commands/doc.md +174 -0
- c3/_template/.claude/commands/extract-lib.md +292 -0
- c3/_template/.claude/commands/init-session.md +110 -0
- c3/_template/.claude/commands/mcp.md +322 -0
- c3/_template/.claude/commands/promote-pattern.md +135 -0
- c3/_template/.claude/commands/review.md +9 -0
- c3/_template/.claude/commands/setup.md +206 -0
- c3/_template/.claude/commands/start.md +88 -0
- c3/_template/.claude/docs/parallel-orchestra-manifest.md +108 -0
- c3/_template/.claude/hooks/clear_file_history.py +39 -0
- c3/_template/.claude/hooks/enable_sandbox.py +61 -0
- c3/_template/.claude/hooks/pre_compact.py +82 -0
- c3/_template/.claude/hooks/pre_tool.py +64 -0
- c3/_template/.claude/hooks/statusline.py +170 -0
- c3/_template/.claude/hooks/stop.py +202 -0
- c3/_template/.claude/hooks/validate_skill_change.py +33 -0
- c3/_template/.claude/hooks/worktree_guard.py +53 -0
- c3/_template/.claude/memory/.gitkeep +0 -0
- c3/_template/.claude/rules/code-review-checklist.md +91 -0
- c3/_template/.claude/rules/promoted/index.md +5 -0
- c3/_template/.claude/rules/security-review-checklist.md +84 -0
- c3/_template/.claude/settings.json +136 -0
- c3/_template/.claude/settings.local.json +126 -0
- c3/_template/.claude/skills/dev-workflow.md +484 -0
- c3/_template/.claude/skills/parallel-execution.md +121 -0
- c3/_template/.claude/skills/promoted/index.md +5 -0
- c3/_template/.claude/skills/worktree-tdd-workflow.md +71 -0
- c3/cli.py +63 -0
- c3/cli_doctor.py +135 -0
- c3/cli_init.py +70 -0
- c3/cli_list.py +69 -0
- c3/cli_po.py +102 -0
- c3/cli_update.py +117 -0
- c3/paths.py +64 -0
- c3/po/__init__.py +11 -0
- c3/po/detect.py +44 -0
- c3/po/manifest.py +336 -0
- c3/po/run.py +105 -0
- claude_code_conductor-0.2.0.dist-info/METADATA +362 -0
- claude_code_conductor-0.2.0.dist-info/RECORD +57 -0
- claude_code_conductor-0.2.0.dist-info/WHEEL +4 -0
- claude_code_conductor-0.2.0.dist-info/entry_points.txt +2 -0
- 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()
|