phasegate 0.31.0 → 0.39.0
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.
- package/CHANGELOG.md +87 -1
- package/README.ja.md +498 -660
- package/README.md +8 -11
- package/docs/folder_management_rules.md +251 -0
- package/package.json +6 -4
- package/scripts/delegate-sonnet.sh +105 -0
- package/scripts/harness/main.ts +92 -7
- package/scripts/harness/setup/skill-deployer.ts +99 -0
- package/skills/environment-designer/SKILL.md +1 -1
- package/skills/implementation-planner/SKILL.md +1 -1
- package/skills/it-test-designer/SKILL.md +3 -3
- package/skills/it-test-logic-designer/SKILL.md +2 -2
- package/skills/mock-designer/SKILL.md +1 -1
- package/skills/scenario-test-designer/SKILL.md +3 -3
- package/skills/scenario-test-logic-designer/SKILL.md +2 -2
- package/skills/story-mapper/SKILL.md +1 -1
- package/skills/story-writer/SKILL.md +1 -1
- package/skills/unit-designer/SKILL.md +1 -1
- package/skills/unit-test-designer/SKILL.md +3 -3
- package/skills/unit-test-logic-designer/SKILL.md +2 -2
- package/templates/.claude/settings.json +3 -3
- package/templates/.husky/pre-commit +1 -1
- package/templates/phasegate.config.json +0 -30
package/README.md
CHANGED
|
@@ -48,17 +48,11 @@ npm install --save-dev phasegate
|
|
|
48
48
|
npx phasegate init --name my-project
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
This deploys 28 skills
|
|
51
|
+
This deploys 28 skills, design principles docs (`docs/principles/*.md`, `docs/folder_management_rules.md`), and generates `phasegate.config.json`.
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Optional: add `--with-husky` to also install a `.husky/pre-commit` hook that runs L2 validators.
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
cp node_modules/phasegate/docs/folder_management_rules.md docs/
|
|
57
|
-
mkdir -p docs/principles
|
|
58
|
-
cp node_modules/phasegate/docs/principles/*.md docs/principles/
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 4. Start the AIDLC
|
|
55
|
+
### 3. Start the AIDLC
|
|
62
56
|
|
|
63
57
|
Launch your AI agent and run the `/product-architect` skill to begin.
|
|
64
58
|
|
|
@@ -275,6 +269,9 @@ npx phasegate <command> [options]
|
|
|
275
269
|
| `phasegate:status` | Display overall harness health summary |
|
|
276
270
|
| `phasegate:check-phase --unit <id>` | Check current phase for a Unit |
|
|
277
271
|
| `list-errors --layer <L0-L4>` | List error definitions with fix examples |
|
|
272
|
+
| `hook <pre-tool-use\|post-tool-use\|stop>` | Run a Claude Code hook (reads JSON from stdin) |
|
|
273
|
+
| `pre-commit` | Run L2 pre-commit validators on staged files |
|
|
274
|
+
| `delegate-sonnet [...args]` | Delegate task to Sonnet 4.6 (transparent wrapper) |
|
|
278
275
|
|
|
279
276
|
See the [Japanese README](README.ja.md) for the complete CLI reference.
|
|
280
277
|
|
|
@@ -301,7 +298,7 @@ Additional resources:
|
|
|
301
298
|
|
|
302
299
|
## Contributing
|
|
303
300
|
|
|
304
|
-
Contributions are welcome.
|
|
301
|
+
Contributions are welcome. See [DEVELOPMENT.md](DEVELOPMENT.md) for internal architecture, regression tests, and release procedures.
|
|
305
302
|
|
|
306
303
|
---
|
|
307
304
|
|
|
@@ -311,4 +308,4 @@ Contributions are welcome. Please read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
|
311
308
|
|
|
312
309
|
---
|
|
313
310
|
|
|
314
|
-
[Japanese version / 日本語版](README.ja.md)
|
|
311
|
+
[Japanese version / 日本語版](README.ja.md) | [Developer Guide](DEVELOPMENT.md) | [開発者ガイド](DEVELOPMENT.ja.md)
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# docs ディレクトリ管理ガイド
|
|
2
|
+
|
|
3
|
+
本ドキュメントは`docs/`配下のドキュメント管理方針を定義します。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ディレクトリ構造
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
docs/
|
|
11
|
+
├── ADR/ # Architecture Decision Records
|
|
12
|
+
├── basic_input/ # 入力サンプル・テンプレート
|
|
13
|
+
├── principles/ # 開発原則・ルール
|
|
14
|
+
├── inception/ # 計画ドキュメント + 作業単位(US・issue)の設計
|
|
15
|
+
└── product/ # 共有設計ドキュメント(確定版)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 各ディレクトリの役割
|
|
21
|
+
|
|
22
|
+
### ADR/
|
|
23
|
+
アーキテクチャ決定記録。技術選定や設計方針の決定理由を記録する。
|
|
24
|
+
|
|
25
|
+
### basic_input/
|
|
26
|
+
入力データのサンプルやテンプレートを格納する。
|
|
27
|
+
|
|
28
|
+
### principles/
|
|
29
|
+
開発原則、テストルール、アーキテクチャ哲学など、プロジェクト全体で遵守すべきルールを定義する。
|
|
30
|
+
|
|
31
|
+
### inception/
|
|
32
|
+
**計画ドキュメント**と**作業単位(US・issue)の設計**を格納する。inception 配下のドキュメントは一時的な作業用であり、設計成果物は `product/` に反映される。
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
inception/
|
|
36
|
+
├── _shared/ # 横断的な計画(複数Unitにまたがるもの)
|
|
37
|
+
├── _operation/ # 運用・デプロイ関連の計画
|
|
38
|
+
├── issues/ # 横断的なissue(複数Unitにまたがるもの)
|
|
39
|
+
│ └── {ISSUE-XXX}/
|
|
40
|
+
│ ├── issue_description.md # 問題の記述
|
|
41
|
+
│ ├── logical_design.md # 論理設計
|
|
42
|
+
│ └── ...
|
|
43
|
+
├── {Unit名}/ # Unit毎の階層
|
|
44
|
+
│ ├── *_plan.md # Unit全体の計画
|
|
45
|
+
│ ├── {US-XXX}/ # ストーリー単位の計画・設計
|
|
46
|
+
│ │ ├── *_plan.md # 実装計画
|
|
47
|
+
│ │ ├── uiux_design.md # UI/UX設計
|
|
48
|
+
│ │ └── ... # その他ストーリー固有のドキュメント
|
|
49
|
+
│ └── issues/ # Unit固有のissue(バグ・不整合)
|
|
50
|
+
│ └── {ISSUE-XXX}/
|
|
51
|
+
│ ├── issue_description.md # 問題の記述
|
|
52
|
+
│ ├── logical_design.md # 論理設計
|
|
53
|
+
│ └── tdd_implementation_plan.md
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### product/
|
|
57
|
+
**確定した設計ドキュメント**を格納する。作業単位(US-XXX / ISSUE-XXX)のドキュメントは含まない。
|
|
58
|
+
|
|
59
|
+
> **設計思想(product docs ハブモデル)**:
|
|
60
|
+
>
|
|
61
|
+
> `product/` はUnit単位で確定済みの仕様を集約する **ハブ** である。
|
|
62
|
+
>
|
|
63
|
+
> ```
|
|
64
|
+
> inception/{unit}/{作業単位}/ 一時設計(US・issue ごと)
|
|
65
|
+
> ↓ 設計成果物の反映(累積更新)
|
|
66
|
+
> product/construction/{unit}/ 正式設計(常に最新、Unitの真実のソース)
|
|
67
|
+
> ↕ フェーズゲート
|
|
68
|
+
> scripts/harness/{unit}/*.ts 実装ファイル
|
|
69
|
+
> ```
|
|
70
|
+
>
|
|
71
|
+
> - **inception → product**: US・issue の設計成果が確定したら product docs を累積更新する
|
|
72
|
+
> - **product → source**: ソースファイルのフェーズゲートは product docs(Unit単位)の存在で判定する
|
|
73
|
+
> - **ソースファイルと US/issue は直接紐付けない**: PJ のライフサイクルが進むほどにバグ修正や US 追加で一つのソースファイルに紐づくドキュメント数が増大し、依存関係が複雑になるため。product docs が常に最新に保たれることで、inception の一時ドキュメントと実装が間接的に紐づく
|
|
74
|
+
> - **US/issue 単位で正として管理しない**: 整合性維持のコストが非常に大きくなるため、作業単位の設計は inception にアーカイブ的に保持し、確定した仕様のみを product に集約する
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
product/
|
|
78
|
+
├── product_overview.md # プロダクト概要
|
|
79
|
+
├── user_stories.md # ユーザーストーリー一覧
|
|
80
|
+
├── user_story_mapping.md # ストーリーマッピング
|
|
81
|
+
├── construction/ # Unit毎の設計(確定版・累積更新)
|
|
82
|
+
│ └── {Unit名}/
|
|
83
|
+
│ ├── domain_model.md # ドメインモデル
|
|
84
|
+
│ ├── logical_design.md # 論理設計
|
|
85
|
+
│ ├── uiux_design.md # UI/UX設計(Unit全体で1ファイル)
|
|
86
|
+
│ ├── unit_test_design.md # ユニットテストケース設計
|
|
87
|
+
│ ├── it_test_design.md # ITテストケース設計
|
|
88
|
+
│ ├── unit_test_logic.md # ユニットテストロジック設計
|
|
89
|
+
│ ├── it_test_logic.md # ITテストロジック設計
|
|
90
|
+
│ └── coverage_report.md # テストカバレッジレポート
|
|
91
|
+
└── units/ # Unit設計ドキュメント
|
|
92
|
+
├── {unit_name}_unit.md # Unit定義
|
|
93
|
+
└── integration_contract.md # 統合契約
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **`construction/{Unit名}/` のドキュメントは累積更新される「生きたドキュメント」です。**
|
|
97
|
+
> ストーリー実装のたびに、新しい仕様を既存ファイルに追記・更新します。
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 重要なルール
|
|
102
|
+
|
|
103
|
+
### 1. productには作業単位(US・issue)の設計を入れない
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
# NG: product配下にUS-XXX/ISSUE-XXXディレクトリを作成
|
|
107
|
+
product/construction/withholding_tax/US-217/
|
|
108
|
+
product/construction/withholding_tax/issues/ISSUE-001/
|
|
109
|
+
|
|
110
|
+
# OK: inception配下に作成
|
|
111
|
+
inception/withholding_tax/US-217/
|
|
112
|
+
inception/withholding_tax/issues/ISSUE-001/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 2. 仕様変更時は既存のproductドキュメントを更新する
|
|
116
|
+
|
|
117
|
+
US 実装や issue 修正で仕様が確定したら、`product/`配下の既存ドキュメント(domain_model.md等)を累積更新する。新規ファイルを作成するのではなく、既存ファイルに変更を追記する。product docs は常に最新の状態を維持する「生きたドキュメント」である。
|
|
118
|
+
|
|
119
|
+
### 3. ストーリー・issue単位の計画・設計は必ずinception配下に作成する
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
# 新しいストーリーUS-999の計画を作成する場合
|
|
123
|
+
inception/{該当Unit}/US-999/
|
|
124
|
+
├── logical_design_plan.md
|
|
125
|
+
├── scenario_test_plan.md
|
|
126
|
+
├── scenario_test_design.md
|
|
127
|
+
├── scenario_test_logic.md
|
|
128
|
+
├── uiux_design_plan.md
|
|
129
|
+
└── tdd_implementation_plan.md
|
|
130
|
+
|
|
131
|
+
# Unit固有のissue(バグ・不整合)を起票する場合
|
|
132
|
+
inception/{該当Unit}/issues/ISSUE-999/
|
|
133
|
+
├── issue_description.md
|
|
134
|
+
├── logical_design.md
|
|
135
|
+
└── tdd_implementation_plan.md
|
|
136
|
+
|
|
137
|
+
# 横断的なissue(複数Unitにまたがる)を起票する場合
|
|
138
|
+
inception/issues/ISSUE-999/
|
|
139
|
+
├── issue_description.md
|
|
140
|
+
└── logical_design.md
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## ドキュメント作成フロー
|
|
146
|
+
|
|
147
|
+
AIDLCプロセスは **US(新機能)** と **issue(バグ・不整合)** の2つの起点を持つ。いずれも inception で計画を立て、product docs を更新し、実装に反映する流れは共通である。
|
|
148
|
+
|
|
149
|
+
### US と issue の違い
|
|
150
|
+
|
|
151
|
+
| 起点 | フロー | inception 配置先 |
|
|
152
|
+
|------|--------|-----------------|
|
|
153
|
+
| **US(新機能)** | Phase 1 → Phase 2 → Phase 3 の全フローを上位から順に実行 | `inception/{unit}/{US-XXX}/` |
|
|
154
|
+
| **issue(バグ・不整合)** | 原因フェーズを特定し、そのフェーズから下位に向けてドキュメント・実装をアップデート | `inception/{unit}/issues/{ISSUE-XXX}/` |
|
|
155
|
+
|
|
156
|
+
#### issue の処理フロー
|
|
157
|
+
|
|
158
|
+
1. **issue 起票**: `inception/{unit}/issues/{ISSUE-XXX}/issue_description.md` に問題の記述・原因分析を記載
|
|
159
|
+
2. **原因フェーズの特定**: バグや仕様の認識違いがどのフェーズに起因するかを判定
|
|
160
|
+
- ドメイン設計に起因 → domain_model から下位に向けてリファクタ
|
|
161
|
+
- 論理設計に起因 → logical_design から下位に向けてリファクタ
|
|
162
|
+
- テスト設計に起因 → test_design から下位に向けてリファクタ
|
|
163
|
+
- 実装のみに起因 → 実装の修正のみ
|
|
164
|
+
3. **inception で計画**: 特定したフェーズから下位のフェーズに向けて、inception 配下に計画・設計文書を作成
|
|
165
|
+
4. **product docs 更新**: 設計成果物を `product/construction/{unit}/` の該当ドキュメントに累積更新
|
|
166
|
+
5. **TDD 実装**: テスト設計→実装の順序で修正を適用
|
|
167
|
+
|
|
168
|
+
> **issue が既存仕様に存在しない追加機能であった場合**: issue ではなく **US を新規作成** し、unit へのマッピングからドメイン設計→TDD 実装まで、下記の Phase 1〜3 の全フローに沿って実施する。
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### US のドキュメント作成フロー
|
|
173
|
+
|
|
174
|
+
US は3つのフェーズで構成される。各フェーズでドキュメントの配置先が異なる。
|
|
175
|
+
|
|
176
|
+
### Phase 1: プロダクト全体設計(横断的・初回)
|
|
177
|
+
|
|
178
|
+
プロダクトの全体像を定義し、ストーリー・Unitの構造を確立する。
|
|
179
|
+
|
|
180
|
+
| Step | スキル | 計画(inception) | 成果物(product) |
|
|
181
|
+
|------|--------|-------------------|-------------------|
|
|
182
|
+
| Step 0 | product-architect | `_shared/product_overview_plan.md` | `product_overview.md` |
|
|
183
|
+
| Step 1.1 | story-writer | `_shared/story_writer_plan.md` | `user_stories.md` |
|
|
184
|
+
| Step 1.5 | story-mapper | `_shared/story_mapping_plan.md` | `user_story_mapping.md` |
|
|
185
|
+
| Step 2 | unit-designer | `_shared/unit_design_plan.md` | `units/{unit_name}.md` + `units/integration_contract.md` |
|
|
186
|
+
|
|
187
|
+
### Phase 2: Unit横断設計(Unit単位)
|
|
188
|
+
|
|
189
|
+
各Unitの設計を確定させる。成果物は`product/construction/{unit}/`に配置される累積更新ドキュメント。
|
|
190
|
+
|
|
191
|
+
| Step | スキル | 計画(inception/{unit}/) | 成果物(product/construction/{unit}/) |
|
|
192
|
+
|------|--------|--------------------------|----------------------------------------|
|
|
193
|
+
| Step 3 | domain-designer | `domain_model_plan.md` | `domain_model.md` |
|
|
194
|
+
| Step 4 | logical-designer(横断) | `logical_design_plan.md` | `logical_design.md` |
|
|
195
|
+
| Step 5 | scenario-test-designer | → Phase 3で実行 | - |
|
|
196
|
+
| Step 5 | it-test-designer | `it_test_design_plan.md` | `it_test_design.md` |
|
|
197
|
+
| Step 5 | unit-test-designer | `unit_test_design_plan.md` | `unit_test_design.md` |
|
|
198
|
+
| - | test-coverage-checker | `test_coverage_plan.md` | `coverage_report.md` |
|
|
199
|
+
| Step 6 | unit-test-logic-designer | `unit_test_logic_plan.md` | `unit_test_logic.md` |
|
|
200
|
+
| Step 6 | it-test-logic-designer | `it_test_logic_plan.md` | `it_test_logic.md` |
|
|
201
|
+
|
|
202
|
+
### Phase 3: ストーリー実装(US単位)/ issue 修正
|
|
203
|
+
|
|
204
|
+
個別ストーリーの設計・テスト・実装。計画・成果物は`inception/{unit}/{US-XXX}/`に配置。
|
|
205
|
+
issue の場合は `inception/{unit}/issues/{ISSUE-XXX}/` に配置し、原因フェーズから下位に向けて同様のドキュメントを作成する。
|
|
206
|
+
|
|
207
|
+
| Step | スキル | 計画(inception/{unit}/{US-XXX}/) | 成果物配置先 |
|
|
208
|
+
|------|--------|-----------------------------------|-------------|
|
|
209
|
+
| Step 4 | logical-designer(固有) | `logical_design_plan.md` | `logical_design.md`(同ディレクトリ) |
|
|
210
|
+
| Step 5 | scenario-test-designer | `scenario_test_plan.md` | `scenario_test_design.md`(同ディレクトリ) |
|
|
211
|
+
| Step 6 | scenario-test-logic-designer | `scenario_test_logic_plan.md` | `scenario_test_logic.md`(同ディレクトリ) |
|
|
212
|
+
| Step 7 | uiux-designer | `uiux_design_plan.md` | `product/construction/{unit}/uiux_design.md`(※累積更新) |
|
|
213
|
+
| Step 8 | story-implementor | `tdd_implementation_plan.md` | コード(TDD実装) |
|
|
214
|
+
| 実装完了後 | - | - | `product/construction/{unit}/` の各ドキュメントを更新 |
|
|
215
|
+
|
|
216
|
+
> **uiux_design.mdについて**: 計画はストーリー単位(`inception/{unit}/{US-XXX}/`)に作成するが、
|
|
217
|
+
> 成果物は`product/construction/{unit}/uiux_design.md`にUnit全体で1ファイルとして累積更新する。
|
|
218
|
+
> これはUI/UXの全体一貫性を保つためで、他のproduct/construction配下のドキュメントと同じルールに従う。
|
|
219
|
+
|
|
220
|
+
### 横断的な計画
|
|
221
|
+
|
|
222
|
+
複数Unitにまたがる計画は `inception/_shared/` に作成する。
|
|
223
|
+
|
|
224
|
+
### 運用関連
|
|
225
|
+
|
|
226
|
+
デプロイ、IaC、運用手順は `inception/_operation/` に作成する。
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## ファイル命名規則
|
|
231
|
+
|
|
232
|
+
| 種別 | 命名パターン | 例 |
|
|
233
|
+
|-----|------------|---|
|
|
234
|
+
| issue記述 | `issue_description.md` | - |
|
|
235
|
+
| 計画 | `*_plan.md` | `domain_model_plan.md` |
|
|
236
|
+
| ドメインモデル | `domain_model.md` | - |
|
|
237
|
+
| 論理設計 | `logical_design.md` | - |
|
|
238
|
+
| UI/UX設計 | `uiux_design.md` | - |
|
|
239
|
+
| シナリオテスト設計 | `scenario_test_design.md` | - |
|
|
240
|
+
| ITテスト設計 | `it_test_design.md` | - |
|
|
241
|
+
| ユニットテスト設計 | `unit_test_design.md` | - |
|
|
242
|
+
| テストロジック設計 | `*_test_logic.md` | `unit_test_logic.md` |
|
|
243
|
+
| カバレッジレポート | `coverage_report.md` | - |
|
|
244
|
+
| Unit定義 | `{unit_name}_unit.md` | `withholding_tax_unit.md` |
|
|
245
|
+
| 統合契約 | `integration_contract.md` | - |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 関連ドキュメント
|
|
250
|
+
- [アーキテクチャ哲学](./principles/architecture-philosophy.md)
|
|
251
|
+
- [テストルール](./principles/testing-rules.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phasegate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"packageManager": "pnpm@10.30.1",
|
|
5
5
|
"description": "Phasegate — AI-agnostic quality defense toolkit. Enforces structural integrity between design intent and code.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -31,11 +31,13 @@
|
|
|
31
31
|
"!scripts/harness/__tests__/**",
|
|
32
32
|
"scripts/harness/**/*.json",
|
|
33
33
|
"!scripts/harness/__tests__/**/*.json",
|
|
34
|
+
"scripts/delegate-sonnet.sh",
|
|
34
35
|
"skills/**",
|
|
35
36
|
"templates/**",
|
|
36
37
|
"docs/ADR/**",
|
|
37
38
|
"docs/principles/**",
|
|
38
39
|
"docs/guide/**",
|
|
40
|
+
"docs/folder_management_rules.md",
|
|
39
41
|
"LICENSE",
|
|
40
42
|
"CHANGELOG.md"
|
|
41
43
|
],
|
|
@@ -44,11 +46,11 @@
|
|
|
44
46
|
},
|
|
45
47
|
"scripts": {
|
|
46
48
|
"phasegate": "npx tsx scripts/harness/main.ts",
|
|
47
|
-
"phasegate:status": "npx tsx scripts/harness/main.ts
|
|
49
|
+
"phasegate:status": "npx tsx scripts/harness/main.ts phasegate:status",
|
|
48
50
|
"phasegate:enable": "npx tsx scripts/harness/main.ts enable-feature",
|
|
49
51
|
"phasegate:disable": "npx tsx scripts/harness/main.ts disable-feature",
|
|
50
|
-
"phasegate:check-phase": "npx tsx scripts/harness/main.ts
|
|
51
|
-
"phasegate:check-ready": "npx tsx scripts/harness/main.ts
|
|
52
|
+
"phasegate:check-phase": "npx tsx scripts/harness/main.ts phasegate:check-phase",
|
|
53
|
+
"phasegate:check-ready": "npx tsx scripts/harness/main.ts phasegate:check-ready",
|
|
52
54
|
"test": "vitest run --config scripts/harness/__tests__/vitest.config.forks.ts && vitest run --config scripts/harness/__tests__/vitest.config.ts"
|
|
53
55
|
},
|
|
54
56
|
"dependencies": {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# delegate-sonnet.sh — Sonnet 4.6 にタスクを委任するラッパースクリプト
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# bash scripts/delegate-sonnet.sh --prompt "プロンプト" --output "出力パス"
|
|
6
|
+
# bash scripts/delegate-sonnet.sh --prompt-file /tmp/prompt.md --output "出力パス"
|
|
7
|
+
#
|
|
8
|
+
# Options:
|
|
9
|
+
# --prompt 委任プロンプト(直接指定、2000文字以下推奨)
|
|
10
|
+
# --prompt-file 委任プロンプトファイル(長文の場合)
|
|
11
|
+
# --output 出力ファイルパス
|
|
12
|
+
# --max-turns 最大ターン数(デフォルト: 30)
|
|
13
|
+
# --dry-run プロンプトを表示するだけで実行しない
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# --- 引数パース ---
|
|
18
|
+
PROMPT=""
|
|
19
|
+
PROMPT_FILE=""
|
|
20
|
+
OUTPUT_PATH=""
|
|
21
|
+
MAX_TURNS=30
|
|
22
|
+
DRY_RUN=false
|
|
23
|
+
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case $1 in
|
|
26
|
+
--prompt)
|
|
27
|
+
PROMPT="$2"
|
|
28
|
+
shift 2
|
|
29
|
+
;;
|
|
30
|
+
--prompt-file)
|
|
31
|
+
PROMPT_FILE="$2"
|
|
32
|
+
shift 2
|
|
33
|
+
;;
|
|
34
|
+
--output)
|
|
35
|
+
OUTPUT_PATH="$2"
|
|
36
|
+
shift 2
|
|
37
|
+
;;
|
|
38
|
+
--max-turns)
|
|
39
|
+
MAX_TURNS="$2"
|
|
40
|
+
shift 2
|
|
41
|
+
;;
|
|
42
|
+
--dry-run)
|
|
43
|
+
DRY_RUN=true
|
|
44
|
+
shift
|
|
45
|
+
;;
|
|
46
|
+
*)
|
|
47
|
+
echo "Unknown option: $1" >&2
|
|
48
|
+
exit 1
|
|
49
|
+
;;
|
|
50
|
+
esac
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
# --- バリデーション ---
|
|
54
|
+
if [[ -z "$PROMPT" && -z "$PROMPT_FILE" ]]; then
|
|
55
|
+
echo "Error: --prompt or --prompt-file is required" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [[ -z "$OUTPUT_PATH" ]]; then
|
|
60
|
+
echo "Error: --output is required" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [[ -n "$PROMPT_FILE" && ! -f "$PROMPT_FILE" ]]; then
|
|
65
|
+
echo "Error: Prompt file not found: $PROMPT_FILE" >&2
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# --- プロンプト構築 ---
|
|
70
|
+
if [[ -n "$PROMPT_FILE" ]]; then
|
|
71
|
+
FINAL_PROMPT=$(cat "$PROMPT_FILE")
|
|
72
|
+
else
|
|
73
|
+
FINAL_PROMPT="$PROMPT"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# 出力指示を付加
|
|
77
|
+
FINAL_PROMPT="${FINAL_PROMPT}
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
## 出力制約
|
|
81
|
+
- 出力は必ず ${OUTPUT_PATH} に書き出すこと
|
|
82
|
+
- 出力以外のファイルを変更しないこと
|
|
83
|
+
- 判断を含む作業(設計判断、優先順位決定、トレードオフ選択)は行わず、
|
|
84
|
+
展開・列挙・構造化に徹すること"
|
|
85
|
+
|
|
86
|
+
# --- 実行 ---
|
|
87
|
+
if [[ "$DRY_RUN" == "true" ]]; then
|
|
88
|
+
echo "=== DRY RUN ==="
|
|
89
|
+
echo "Model: claude-sonnet-4-6"
|
|
90
|
+
echo "Output: $OUTPUT_PATH"
|
|
91
|
+
echo "Max turns: $MAX_TURNS"
|
|
92
|
+
echo "---"
|
|
93
|
+
echo "$FINAL_PROMPT"
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
echo "[delegate-sonnet] Delegating to Sonnet 4.6..."
|
|
98
|
+
echo "[delegate-sonnet] Output: $OUTPUT_PATH"
|
|
99
|
+
|
|
100
|
+
claude --model claude-sonnet-4-6 \
|
|
101
|
+
-p "$FINAL_PROMPT" \
|
|
102
|
+
--max-turns "$MAX_TURNS" \
|
|
103
|
+
--output-format text
|
|
104
|
+
|
|
105
|
+
echo "[delegate-sonnet] Done. Output written to: $OUTPUT_PATH"
|
package/scripts/harness/main.ts
CHANGED
|
@@ -29,10 +29,11 @@ import { buildCiGovernance } from './ci-governance/composition-root.js';
|
|
|
29
29
|
import { createSkillQualityHandlers } from './skill-quality/composition-root.js';
|
|
30
30
|
import { buildRegressionSuite } from './regression-suite/composition-root.js';
|
|
31
31
|
import { buildPhase2Extensions } from './phase2-extensions/composition-root.js';
|
|
32
|
-
import { deploySkills, deployHookScripts, getDeployedVersion, getHarnessVersion, initHarnessConfig, SKILL_CATEGORIES, getCategoryForSkill } from './setup/skill-deployer.js';
|
|
32
|
+
import { deploySkills, deployHookScripts, getDeployedVersion, getHarnessVersion, initHarnessConfig, deployDesignDocs, deployHuskyHook, SKILL_CATEGORIES, getCategoryForSkill } from './setup/skill-deployer.js';
|
|
33
33
|
import type { SkillSet } from './setup/skill-deployer.js';
|
|
34
34
|
import type { HarnessConfigV2 } from './config-foundation/domain/harness-config.js';
|
|
35
35
|
import { ConfigValidationError } from './config-foundation/domain/errors/config-validation-error.js';
|
|
36
|
+
import { ConfigNotFoundError, ConfigPersistenceError } from './config-foundation/infrastructure/repositories/file-system-config-repository.js';
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* main.ts (scripts/harness/main.ts) から2階層上がパッケージルート。
|
|
@@ -51,8 +52,8 @@ function printUsage(): void {
|
|
|
51
52
|
Usage: phasegate <command> [options]
|
|
52
53
|
|
|
53
54
|
Setup:
|
|
54
|
-
init Initialize project: deploy skills +
|
|
55
|
-
(--name <project-name>, --preset <full|standard|minimal|custom
|
|
55
|
+
init Initialize project: deploy skills + design docs + phasegate.config.json
|
|
56
|
+
(--name <project-name>, --preset <full|standard|minimal|custom>, --with-husky)
|
|
56
57
|
update-skills Re-deploy skills from current harness version
|
|
57
58
|
|
|
58
59
|
Commands:
|
|
@@ -105,6 +106,9 @@ Commands:
|
|
|
105
106
|
p2:check-freshness Check doc freshness (--pattern <glob>, --dry-run, --format text|json)
|
|
106
107
|
p2:validate-pointers Validate doc pointers (--include-urls, --format text|json)
|
|
107
108
|
p2:generate-e2e-template Generate E2E test template (--phase <phase>, --output <path>)
|
|
109
|
+
hook <pre-tool-use|post-tool-use|stop> Run Claude Code hook (reads JSON from stdin)
|
|
110
|
+
pre-commit Run L2 pre-commit validators on staged files
|
|
111
|
+
delegate-sonnet [...args] Delegate task to Sonnet 4.6 (forwards args to scripts/delegate-sonnet.sh)
|
|
108
112
|
|
|
109
113
|
Skills:
|
|
110
114
|
skills list List all available skills
|
|
@@ -265,10 +269,22 @@ async function loadStoryReflectionProvider(
|
|
|
265
269
|
};
|
|
266
270
|
reporting?: { outputDir?: string };
|
|
267
271
|
};
|
|
272
|
+
let content: string;
|
|
273
|
+
try {
|
|
274
|
+
content = await fsReadFile(configPath, 'utf8');
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
280
|
+
process.stderr.write(`Warning: failed to read phasegate.config.json: ${message}\n`);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
268
283
|
try {
|
|
269
|
-
const content = await fsReadFile(configPath, 'utf8');
|
|
270
284
|
raw = JSON.parse(content);
|
|
271
|
-
} catch {
|
|
285
|
+
} catch (error) {
|
|
286
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
287
|
+
process.stderr.write(`Warning: phasegate.config.json is not valid JSON: ${message}\n`);
|
|
272
288
|
return null;
|
|
273
289
|
}
|
|
274
290
|
const section: PhaseDepConfigSection = {
|
|
@@ -325,7 +341,15 @@ async function loadResolvedConfig(): Promise<HarnessConfigV2 | undefined> {
|
|
|
325
341
|
process.stderr.write(`Invalid phasegate.config.json: ${error.message}\n`);
|
|
326
342
|
process.exit(2);
|
|
327
343
|
}
|
|
328
|
-
|
|
344
|
+
if (error instanceof ConfigNotFoundError) {
|
|
345
|
+
return undefined;
|
|
346
|
+
}
|
|
347
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
348
|
+
if (error instanceof ConfigPersistenceError) {
|
|
349
|
+
process.stderr.write(`Warning: phasegate.config.json is not valid JSON: ${message}\n`);
|
|
350
|
+
} else {
|
|
351
|
+
process.stderr.write(`Warning: failed to load phasegate.config.json: ${message}\n`);
|
|
352
|
+
}
|
|
329
353
|
return undefined;
|
|
330
354
|
}
|
|
331
355
|
}
|
|
@@ -379,6 +403,11 @@ async function main(): Promise<void> {
|
|
|
379
403
|
const result = await deploySkills(harnessRoot, rootDir, skillSet);
|
|
380
404
|
const configResult = await initHarnessConfig(rootDir, projectName, phasePreset);
|
|
381
405
|
const hooksResult = await deployHookScripts(harnessRoot, rootDir);
|
|
406
|
+
const designDocsResult = await deployDesignDocs(harnessRoot, rootDir);
|
|
407
|
+
const withHusky = hasFlag(args, '--with-husky');
|
|
408
|
+
const huskyResult = withHusky
|
|
409
|
+
? await deployHuskyHook(harnessRoot, rootDir)
|
|
410
|
+
: null;
|
|
382
411
|
console.log(`✓ Skills deployed to ${result.targetDir} (${result.deployedSkills.length} skills, set: ${skillSet})`);
|
|
383
412
|
if (configResult.created) {
|
|
384
413
|
console.log(`✓ phasegate.config.json created`);
|
|
@@ -393,6 +422,19 @@ async function main(): Promise<void> {
|
|
|
393
422
|
} else if (hooksResult.scriptsDeployed > 0) {
|
|
394
423
|
console.log(` .claude/settings.json already exists, skipped`);
|
|
395
424
|
}
|
|
425
|
+
if (designDocsResult.copiedFiles.length > 0) {
|
|
426
|
+
console.log(`✓ Design docs deployed (${designDocsResult.copiedFiles.length} files)`);
|
|
427
|
+
}
|
|
428
|
+
for (const skipped of designDocsResult.skippedFiles) {
|
|
429
|
+
console.log(` ${skipped} already exists, skipped`);
|
|
430
|
+
}
|
|
431
|
+
if (huskyResult !== null) {
|
|
432
|
+
if (huskyResult.created) {
|
|
433
|
+
console.log(`✓ .husky/pre-commit deployed`);
|
|
434
|
+
} else {
|
|
435
|
+
console.log(` .husky/pre-commit already exists, skipped`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
396
438
|
console.log(`✓ Harness v${result.version} initialized`);
|
|
397
439
|
console.log('');
|
|
398
440
|
console.log('Next steps:');
|
|
@@ -685,7 +727,7 @@ async function main(): Promise<void> {
|
|
|
685
727
|
const flags: Record<string, boolean | string> = {};
|
|
686
728
|
if (json) flags.json = true;
|
|
687
729
|
await mod.handlers.status.handle({}, flags);
|
|
688
|
-
await printStoryReflectionStatusLine(rootDir);
|
|
730
|
+
if (!json) await printStoryReflectionStatusLine(rootDir);
|
|
689
731
|
break;
|
|
690
732
|
}
|
|
691
733
|
|
|
@@ -914,6 +956,49 @@ async function main(): Promise<void> {
|
|
|
914
956
|
break;
|
|
915
957
|
}
|
|
916
958
|
|
|
959
|
+
// ── agent integration / hooks ──
|
|
960
|
+
case 'hook': {
|
|
961
|
+
const subCommand = args[1];
|
|
962
|
+
if (!subCommand) {
|
|
963
|
+
console.error('Usage: phasegate hook <pre-tool-use|post-tool-use|stop>');
|
|
964
|
+
process.exit(2);
|
|
965
|
+
}
|
|
966
|
+
const hookFileName: Record<string, string> = {
|
|
967
|
+
'pre-tool-use': 'pre-tool-use-hook.js',
|
|
968
|
+
'post-tool-use': 'post-tool-use-hook.js',
|
|
969
|
+
'stop': 'stop-hook.js',
|
|
970
|
+
};
|
|
971
|
+
const fileName = hookFileName[subCommand];
|
|
972
|
+
if (!fileName) {
|
|
973
|
+
console.error(`Unknown hook subcommand: ${subCommand}`);
|
|
974
|
+
console.error('Usage: phasegate hook <pre-tool-use|post-tool-use|stop>');
|
|
975
|
+
process.exit(2);
|
|
976
|
+
}
|
|
977
|
+
const hookPath = join(harnessRoot, 'scripts/harness/agent-integration/presentation', fileName);
|
|
978
|
+
await import(hookPath);
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
case 'pre-commit': {
|
|
983
|
+
const preCommitPath = join(harnessRoot, 'scripts/harness/integrations/pre-commit.js');
|
|
984
|
+
await import(preCommitPath);
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
case 'delegate-sonnet': {
|
|
989
|
+
const { spawn } = await import('node:child_process');
|
|
990
|
+
const scriptPath = join(harnessRoot, 'scripts/delegate-sonnet.sh');
|
|
991
|
+
const forwardArgs = args.slice(1);
|
|
992
|
+
const child = spawn('bash', [scriptPath, ...forwardArgs], { stdio: 'inherit' });
|
|
993
|
+
await new Promise<void>((_, reject) => {
|
|
994
|
+
child.on('exit', (code) => {
|
|
995
|
+
process.exit(code ?? 1);
|
|
996
|
+
});
|
|
997
|
+
child.on('error', reject);
|
|
998
|
+
});
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
917
1002
|
// ── skills ──
|
|
918
1003
|
case 'skills': {
|
|
919
1004
|
const subCommand = args[1];
|