spec-runner 1.0.6 → 1.0.7

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 (95) hide show
  1. package/README.md +33 -188
  2. package/bin/spec-runner.js +192 -706
  3. package/install.sh +6 -12
  4. package/package.json +3 -2
  5. package/templates/.spec-runner/hooks/pre-commit +33 -0
  6. package/templates/.spec-runner/hooks/pre-push +9 -0
  7. package/templates/.spec-runner/project.json.example +25 -0
  8. package/templates/.spec-runner/scripts/branch/create-uc-branch.sh +105 -0
  9. package/templates/.spec-runner/scripts/branch/uc-next-id.sh +17 -0
  10. package/templates/.spec-runner/scripts/branch/uc-next-start.sh +81 -0
  11. package/templates/.spec-runner/scripts/check/drift.sh +66 -0
  12. package/templates/.spec-runner/scripts/check/health.sh +103 -0
  13. package/templates/.spec-runner/scripts/check/naming.sh +51 -0
  14. package/templates/.spec-runner/scripts/check/schema-drift.sh +74 -0
  15. package/templates/.spec-runner/scripts/check/schema-sync.sh +153 -0
  16. package/templates/.spec-runner/scripts/check.sh +20 -0
  17. package/templates/.spec-runner/scripts/lib/uc-context.sh +75 -0
  18. package/templates/.spec-runner/scripts/openapi/openapi-generate.sh +207 -0
  19. package/templates/.spec-runner/scripts/setup/init-project.sh +152 -0
  20. package/templates/.spec-runner/scripts/spec-runner-core.sh +282 -0
  21. package/templates/.spec-runner/scripts/test/require-tests-green.sh +83 -0
  22. package/templates/.spec-runner/spec-runner.sh +30 -0
  23. package/templates/.spec-runner/steps//343/201/235/343/201/256/344/273/226/344/275/234/346/245/255.md +22 -0
  24. package/templates/.spec-runner/steps//343/202/277/343/202/271/343/202/257/344/270/200/350/246/247.md +132 -0
  25. package/templates/.spec-runner/steps//343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +106 -0
  26. package/templates/.spec-runner/steps//343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +50 -0
  27. package/templates/.spec-runner/steps//343/203/211/343/203/241/343/202/244/343/203/263/350/250/255/350/250/210.md +32 -0
  28. package/templates/.spec-runner/steps//344/273/225/346/247/230/347/255/226/345/256/232.md +219 -0
  29. package/templates/.spec-runner/steps//345/210/206/346/236/220.md +167 -0
  30. package/templates/.spec-runner/steps//345/256/237/350/243/205.md +91 -0
  31. package/templates/.spec-runner/steps//345/256/237/350/243/205/350/250/210/347/224/273.md +96 -0
  32. package/templates/.spec-runner/steps//346/206/262/347/253/240.md +74 -0
  33. package/templates/.spec-runner/steps//346/233/226/346/230/247/343/201/225/350/247/243/346/266/210.md +159 -0
  34. package/templates/.spec-runner/templates/UC-NNN-/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/345/220/215.md +22 -0
  35. package/templates/spec-runner-command.md +42 -0
  36. package/templates/base/.github/PULL_REQUEST_TEMPLATE.md +0 -43
  37. package/templates/base/.github/workflows/phase-gate-check.yml +0 -216
  38. package/templates/base/scripts/spec-runner.sh +0 -1144
  39. package/templates/base/templates/01_/350/246/201/344/273/266/345/256/232/347/276/251//343/201/262/343/201/252/345/275/242.md +0 -40
  40. package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/202/244/343/203/263/343/203/225/343/203/251.md +0 -14
  41. package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/206/343/203/274/343/203/226/343/203/253.md +0 -17
  42. package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/211/343/203/241/343/202/244/343/203/263.md +0 -18
  43. package/templates/base/templates/03_/350/251/263/347/264/260/350/250/255/350/250/210//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +0 -12
  44. package/templates/base/templates/99_/350/250/255/350/250/210/345/210/244/346/226/255/350/250/230/351/214/262//343/201/262/343/201/252/345/275/242.md +0 -46
  45. package/templates/base/templates/README.md +0 -32
  46. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/01_/346/206/262/347/253/240.md +0 -48
  47. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/02_/344/273/225/346/247/230.md +0 -39
  48. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/03_/347/224/250/350/252/236/351/233/206.md +0 -51
  49. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210/99_/350/250/255/350/250/210/345/210/244/346/226/255/350/250/230/351/214/262/.gitkeep +0 -0
  50. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210//343/203/206/343/203/263/343/203/227/343/203/254/343/203/274/343/203/210/344/270/200/350/246/247.md +0 -14
  51. package/templates/base/templates//345/210/235/346/234/237/343/203/211/343/202/255/343/203/245/343/203/241/343/203/263/343/203/210//346/214/257/343/202/212/350/277/224/343/202/212//350/262/240/345/202/265.md +0 -8
  52. package/templates/claude/.claude/commands/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.md +0 -9
  53. package/templates/claude/.claude/commands/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +0 -9
  54. package/templates/claude/.claude/commands/sr-/343/203/254/343/203/223/343/203/245/343/203/274.md +0 -9
  55. package/templates/claude/.claude/commands/sr-/344/273/225/346/247/230.md +0 -9
  56. package/templates/claude/.claude/commands/sr-/344/277/256/346/255/243.md +0 -9
  57. package/templates/claude/.claude/commands/sr-/345/210/235/346/234/237/345/214/226.md +0 -10
  58. package/templates/claude/.claude/commands/sr-/345/256/237/350/243/205.md +0 -9
  59. package/templates/claude/.claude/commands/sr-/346/206/262/347/253/240.md +0 -9
  60. package/templates/claude/.claude/commands/sr-/346/246/202/350/246/201/350/250/255/350/250/210.md +0 -9
  61. package/templates/claude/.claude/commands/sr-/347/212/266/346/205/213.md +0 -9
  62. package/templates/claude/.claude/commands/sr-/347/267/212/346/200/245/344/277/256/346/255/243.md +0 -9
  63. package/templates/claude/.claude/commands/sr-/350/250/255/345/256/232.md +0 -11
  64. package/templates/claude/.claude/commands/sr-/350/251/263/347/264/260/350/250/255/350/250/210.md +0 -9
  65. package/templates/claude/.claude/hooks/pre-tool-use.sh +0 -79
  66. package/templates/claude/.claude/settings.json +0 -29
  67. package/templates/claude/CLAUDE.md +0 -141
  68. package/templates/copilot/.github/copilot-instructions.md +0 -25
  69. package/templates/copilot/.github/prompts/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.prompt.md +0 -14
  70. package/templates/copilot/.github/prompts/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.prompt.md +0 -13
  71. package/templates/copilot/.github/prompts/sr-/343/203/254/343/203/223/343/203/245/343/203/274.prompt.md +0 -14
  72. package/templates/copilot/.github/prompts/sr-/344/273/225/346/247/230.prompt.md +0 -13
  73. package/templates/copilot/.github/prompts/sr-/344/277/256/346/255/243.prompt.md +0 -14
  74. package/templates/copilot/.github/prompts/sr-/345/210/235/346/234/237/345/214/226.prompt.md +0 -15
  75. package/templates/copilot/.github/prompts/sr-/345/256/237/350/243/205.prompt.md +0 -13
  76. package/templates/copilot/.github/prompts/sr-/346/206/262/347/253/240.prompt.md +0 -13
  77. package/templates/copilot/.github/prompts/sr-/346/246/202/350/246/201/350/250/255/350/250/210.prompt.md +0 -13
  78. package/templates/copilot/.github/prompts/sr-/347/212/266/346/205/213.prompt.md +0 -13
  79. package/templates/copilot/.github/prompts/sr-/347/267/212/346/200/245/344/277/256/346/255/243.prompt.md +0 -14
  80. package/templates/copilot/.github/prompts/sr-/350/250/255/345/256/232.prompt.md +0 -13
  81. package/templates/copilot/.github/prompts/sr-/350/251/263/347/264/260/350/250/255/350/250/210.prompt.md +0 -14
  82. package/templates/cursor/.cursor/commands/sr-/343/202/262/343/203/274/343/203/210/350/250/255/345/256/232.md +0 -11
  83. package/templates/cursor/.cursor/commands/sr-/343/203/206/343/202/271/343/203/210/350/250/255/350/250/210.md +0 -9
  84. package/templates/cursor/.cursor/commands/sr-/343/203/254/343/203/223/343/203/245/343/203/274.md +0 -9
  85. package/templates/cursor/.cursor/commands/sr-/344/273/225/346/247/230.md +0 -9
  86. package/templates/cursor/.cursor/commands/sr-/344/277/256/346/255/243.md +0 -9
  87. package/templates/cursor/.cursor/commands/sr-/345/210/235/346/234/237/345/214/226.md +0 -35
  88. package/templates/cursor/.cursor/commands/sr-/345/256/237/350/243/205.md +0 -9
  89. package/templates/cursor/.cursor/commands/sr-/346/206/262/347/253/240.md +0 -9
  90. package/templates/cursor/.cursor/commands/sr-/346/246/202/350/246/201/350/250/255/350/250/210.md +0 -9
  91. package/templates/cursor/.cursor/commands/sr-/347/212/266/346/205/213.md +0 -9
  92. package/templates/cursor/.cursor/commands/sr-/347/267/212/346/200/245/344/277/256/346/255/243.md +0 -9
  93. package/templates/cursor/.cursor/commands/sr-/350/250/255/345/256/232.md +0 -20
  94. package/templates/cursor/.cursor/commands/sr-/350/251/263/347/264/260/350/250/255/350/250/210.md +0 -9
  95. package/templates/cursor/.cursorrules +0 -26
@@ -1,1144 +0,0 @@
1
- #!/usr/bin/env bash
2
- # =============================================================================
3
- # spec-runner.sh — ドメイン駆動AI開発 フェーズゲートシステム
4
- # =============================================================================
5
- # このスクリプトが「本当の強制」を担う。
6
- # Claude CodeはCLAUDE.mdを読んでルールを「知る」が、スキップできる。
7
- # このスクリプトはシェルレベルで実行を拒否するため、AIも人間もスキップできない。
8
- #
9
- # 使い方:
10
- # ./.spec-runner/scripts/spec-runner.sh init … 詳細設定の対話のみ
11
- # ./.spec-runner/scripts/spec-runner.sh init <ユースケース名> [集約名] … 設定後ユースケース作成
12
- # ./.spec-runner/scripts/spec-runner.sh require
13
- # ./.spec-runner/scripts/spec-runner.sh design-high
14
- # ./.spec-runner/scripts/spec-runner.sh design-detail <サブフェーズ: domain|usecase|table|infra>
15
- # ./.spec-runner/scripts/spec-runner.sh test-design
16
- # ./.spec-runner/scripts/spec-runner.sh implement
17
- # ./.spec-runner/scripts/spec-runner.sh status
18
- # ./.spec-runner/scripts/spec-runner.sh fix <修正内容>
19
- # ./.spec-runner/scripts/spec-runner.sh hotfix <内容>
20
- # ./.spec-runner/scripts/spec-runner.sh review-pass <ドキュメントパス>
21
- # =============================================================================
22
-
23
- set -euo pipefail
24
-
25
- # ── 定数 ──────────────────────────────────────────────────────────────────────
26
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
27
- # .spec-runner/scripts/ にいる場合は PROJECT_ROOT は 2 階層上、そうでなければ 1 階層上(旧レイアウト)
28
- if [[ "$SCRIPT_DIR" == */.spec-runner/scripts ]]; then
29
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
30
- SPEC_RUNNER_DIR="$PROJECT_ROOT/.spec-runner"
31
- else
32
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
33
- SPEC_RUNNER_DIR="$PROJECT_ROOT"
34
- fi
35
- STATE_FILE="$PROJECT_ROOT/.spec-runner/state.json"
36
- DEBT_FILE="$PROJECT_ROOT/docs/振り返り/負債.md"
37
- GLOSSARY="$PROJECT_ROOT/docs/03_用語集.md"
38
-
39
- # ── フレームワーク設定を読み込む ───────────────────────────────────────────────
40
- # npx spec-runner によって生成された .spec-runner/config.sh を読み込む
41
- # これによりフレームワーク依存の設定(拡張子・パス等)が外部化される
42
- CONFIG_FILE="$PROJECT_ROOT/.spec-runner/config.sh"
43
- if [[ -f "$CONFIG_FILE" ]]; then
44
- # shellcheck source=.spec-runner/config.sh
45
- source "$CONFIG_FILE"
46
- else
47
- # .spec-runner/config.sh がない場合のデフォルト値
48
- SOURCE_EXTENSIONS="${SOURCE_EXTENSIONS:-ts tsx js jsx php py rb}"
49
- DOMAIN_PATH="${DOMAIN_PATH:-src/domain}"
50
- USECASE_PATH="${USECASE_PATH:-src/useCase}"
51
- INFRA_PATH="${INFRA_PATH:-src/infrastructure}"
52
- fi
53
-
54
- # ── カラー出力 ──────────────────────────────────────────────────────────────
55
- RED='\033[0;31m'
56
- GREEN='\033[0;32m'
57
- YELLOW='\033[1;33m'
58
- BLUE='\033[0;34m'
59
- CYAN='\033[0;36m'
60
- BOLD='\033[1m'
61
- NC='\033[0m'
62
-
63
- ok() { echo -e "${GREEN}✓${NC} $*"; }
64
- fail() { echo -e "${RED}✗${NC} $*"; }
65
- warn() { echo -e "${YELLOW}⚠${NC} $*"; }
66
- info() { echo -e "${CYAN}ℹ${NC} $*"; }
67
- step() { echo -e "${BOLD}${BLUE}▶${NC} $*"; }
68
- die() { echo -e "${RED}${BOLD}ERROR:${NC} $*" >&2; exit 1; }
69
-
70
- # ── 依存チェック ───────────────────────────────────────────────────────────
71
- require_cmd() {
72
- command -v "$1" &>/dev/null || die "$1 がインストールされていません"
73
- }
74
- require_cmd jq
75
- require_cmd git
76
-
77
- # ── ステート操作 ───────────────────────────────────────────────────────────
78
- state_get() { jq -r ".$1 // empty" "$STATE_FILE" 2>/dev/null || echo ""; }
79
- state_set() {
80
- local key="$1" val="$2"
81
- local tmp
82
- tmp="${STATE_FILE}.tmp.$$"
83
- jq ".$key = $val" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
84
- }
85
- state_set_str() { state_set "$1" "\"$2\""; }
86
- state_set_bool() { state_set "$1" "$2"; } # true / false
87
-
88
- state_init() {
89
- local usecase="$1" aggregate="${2:-}"
90
- local branch="feature/uc-$(echo "$usecase" | tr ' ' '-')"
91
- local agg_branch=""
92
- [[ -n "$aggregate" ]] && agg_branch="aggregate/$(echo "$aggregate" | tr ' ' '-')"
93
-
94
- mkdir -p "$(dirname "$STATE_FILE")"
95
- cat > "$STATE_FILE" <<EOF
96
- {
97
- "usecase": "$usecase",
98
- "aggregate": "$aggregate",
99
- "phase": "require",
100
- "branch": "$branch",
101
- "aggregate_branch": "$agg_branch",
102
- "started_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
103
- "gates": {
104
- "require_approved": false,
105
- "glossary_checked": false,
106
- "high_level_reviewed": false,
107
- "domain_model_reviewed": false,
108
- "usecase_design_reviewed": false,
109
- "table_design_reviewed": false,
110
- "infra_design_reviewed": false,
111
- "test_design_reviewed": false,
112
- "test_code_committed": false
113
- },
114
- "history": []
115
- }
116
- EOF
117
- }
118
-
119
- state_push_history() {
120
- local msg="$1"
121
- local tmp
122
- tmp="${STATE_FILE}.tmp.$$"
123
- jq ".history += [\"$(date -u +%Y-%m-%dT%H:%M:%SZ): $msg\"]" "$STATE_FILE" > "$tmp" && mv "$tmp" "$STATE_FILE"
124
- }
125
-
126
- # ── ステートファイル必須チェック ───────────────────────────────────────────
127
- require_state() {
128
- [[ -f "$STATE_FILE" ]] || die "作業中のユースケースがありません。まず: ./.spec-runner/scripts/spec-runner.sh init <ユースケース名>"
129
- local phase
130
- phase=$(state_get "phase")
131
- [[ -n "$phase" ]] || die "ステートファイルが壊れています: $STATE_FILE"
132
- }
133
-
134
- # ── ゲートチェック関数群 ───────────────────────────────────────────────────
135
-
136
- # ドキュメントのfrontmatterからstatusを取得
137
- doc_status() {
138
- local file="$1"
139
- [[ -f "$file" ]] || { echo "missing"; return; }
140
- grep -m1 '^status:' "$file" | sed 's/status: *//' | tr -d '[:space:]' || echo "draft"
141
- }
142
-
143
- # ファイル存在チェック(エラーメッセージ付き)
144
- check_file() {
145
- local file="$1" label="$2"
146
- if [[ -f "$file" ]]; then
147
- ok "$label: $file"
148
- return 0
149
- else
150
- fail "$label が存在しません: $file"
151
- return 1
152
- fi
153
- }
154
-
155
- # ドキュメントステータスチェック
156
- check_status() {
157
- local file="$1" required_status="$2" label="$3"
158
- local status
159
- status=$(doc_status "$file")
160
- if [[ "$status" == "$required_status" ]] || [[ "$status" == "approved" && "$required_status" == "reviewed" ]]; then
161
- ok "$label (status: $status)"
162
- return 0
163
- else
164
- fail "$label のステータスが '$status' です。'$required_status' が必要です"
165
- info " レビュー後: ./.spec-runner/scripts/spec-runner.sh review-pass $file"
166
- return 1
167
- fi
168
- }
169
-
170
- # gateフラグチェック
171
- check_gate() {
172
- local gate="$1" label="$2"
173
- local val
174
- val=$(state_get "gates.$gate")
175
- if [[ "$val" == "true" ]]; then
176
- ok "$label"
177
- return 0
178
- else
179
- fail "$label(未完了)"
180
- return 1
181
- fi
182
- }
183
-
184
- # ── debt.md チェック ───────────────────────────────────────────────────────
185
- check_debt() {
186
- if [[ -f "$DEBT_FILE" ]]; then
187
- local unchecked
188
- unchecked=$(grep -c '^\- \[ \]' "$DEBT_FILE" 2>/dev/null; true)
189
- unchecked="${unchecked:-0}"
190
- if [[ "${unchecked}" -gt 0 ]]; then
191
- echo ""
192
- warn "══════════════════════════════════════════════════════════"
193
- warn " ドキュメント負債が $unchecked 件あります: $DEBT_FILE"
194
- warn " 新規開発の前に消化することを推奨します"
195
- warn "══════════════════════════════════════════════════════════"
196
- echo ""
197
- read -r -p "このまま続けますか? [y/N] " answer
198
- [[ "$answer" =~ ^[Yy]$ ]] || die "ドキュメント負債を先に解消してください"
199
- fi
200
- fi
201
- }
202
-
203
- # ── usecase/aggregate のパス計算 ───────────────────────────────────────────
204
- uc_slug() { echo "$(state_get usecase)" | tr ' ' '-'; }
205
- agg_slug() { echo "$(state_get aggregate)" | tr ' ' '-'; }
206
- uc_req() { echo "$PROJECT_ROOT/docs/01_要件/$(uc_slug).md"; }
207
- uc_high() { echo "$PROJECT_ROOT/docs/02_概要設計/$(uc_slug).md"; }
208
- uc_detail() { echo "$PROJECT_ROOT/docs/03_詳細設計/$(uc_slug)"; }
209
- uc_test() { echo "$PROJECT_ROOT/docs/04_テスト設計/$(uc_slug).md"; }
210
-
211
- # ═══════════════════════════════════════════════════════════════════════════════
212
- # コマンド実装
213
- # ═══════════════════════════════════════════════════════════════════════════════
214
-
215
- # ── init ──────────────────────────────────────────────────────────────────────
216
- cmd_init() {
217
- local usecase="${1:-}" aggregate="${2:-}"
218
-
219
- [[ -f "$CONFIG_FILE" ]] || die ".spec-runner/config.sh がありません。まず npx spec-runner を実行してください。"
220
-
221
- # 詳細設定がまだの場合は対話で設定(npx では開発環境だけ聞き、ここでパス・TDD 等を聞く)
222
- if [[ "${CONFIGURED:-false}" != "true" ]]; then
223
- echo ""
224
- info "詳細設定がまだです。パス・TDD 等を対話で設定します..."
225
- echo ""
226
- npx spec-runner --configure
227
- # 設定を再読み込み
228
- source "$CONFIG_FILE"
229
- echo ""
230
- fi
231
-
232
- # 引数なしの init = 設定対話のみ。ユースケース名を渡すと作成に進む
233
- if [[ -z "$usecase" ]]; then
234
- info "設定が完了しました。最初のユースケースを開始するには:"
235
- echo ""
236
- echo " ./.spec-runner/scripts/spec-runner.sh init \"ユースケース名\" \"集約名\""
237
- echo ""
238
- return 0
239
- fi
240
-
241
- check_debt
242
-
243
- echo ""
244
- step "ユースケース初期化: $usecase"
245
- echo ""
246
-
247
- # 既存のstateがあれば警告(SR_YES=1 のときは AI/CI 用に確認をスキップ)
248
- if [[ -f "$STATE_FILE" ]]; then
249
- local current
250
- current=$(state_get "usecase")
251
- if [[ "${SR_YES:-0}" == "1" ]]; then
252
- warn "作業中のユースケース '$current' を上書きします(SR_YES=1)"
253
- else
254
- warn "作業中のユースケース '$current' があります"
255
- read -r -p "上書きしますか? [y/N] " answer
256
- [[ "$answer" =~ ^[Yy]$ ]] || die "中止しました"
257
- fi
258
- fi
259
-
260
- # ブランチ作成
261
- local slug branch agg_branch
262
- slug=$(echo "$usecase" | tr ' ' '-')
263
- branch="feature/uc-$slug"
264
-
265
- # デフォルトブランチを取得(main / master など)
266
- local default_branch
267
- default_branch=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main")
268
-
269
- if [[ -n "$aggregate" ]]; then
270
- agg_branch="aggregate/$(echo "$aggregate" | tr ' ' '-')"
271
- step "集約ブランチを確認/作成: $agg_branch"
272
- if ! git show-ref --verify --quiet "refs/heads/$agg_branch"; then
273
- git checkout -b "$agg_branch" 2>/dev/null || git checkout -b "$agg_branch" "$default_branch"
274
- ok "集約ブランチ作成: $agg_branch"
275
- else
276
- git checkout "$agg_branch"
277
- ok "集約ブランチに切替: $agg_branch"
278
- fi
279
- fi
280
-
281
- step "ユースケースブランチを作成: $branch"
282
- if git show-ref --verify --quiet "refs/heads/$branch"; then
283
- die "ブランチ $branch は既に存在します"
284
- fi
285
- local base="${aggregate:+aggregate/$(echo "$aggregate" | tr ' ' '-')}"
286
- git checkout -b "$branch" "${base:-$default_branch}" 2>/dev/null || git checkout -b "$branch"
287
- ok "ブランチ作成: $branch"
288
-
289
- # ステート初期化
290
- state_init "$usecase" "$aggregate"
291
-
292
- # 要件定義ファイルをテンプレートから生成(templates/requirement/template.md を必須とする)
293
- local req_file tmpl
294
- req_file=$(uc_req)
295
- tmpl="$SPEC_RUNNER_DIR/templates/01_要件定義/ひな形.md"
296
- [[ -f "$tmpl" ]] || die "要件テンプレートがありません: $tmpl (npx spec-runner でセットアップしてください)"
297
-
298
- mkdir -p "$(dirname "$req_file")"
299
- if [[ ! -f "$req_file" ]]; then
300
- sed "s/{{USECASE}}/$usecase/g; s/{{DATE}}/$(date +%Y-%m-%d)/g" "$tmpl" > "$req_file"
301
- ok "要件定義ファイルを作成: $req_file"
302
- else
303
- warn "要件定義ファイルは既に存在します: $req_file"
304
- fi
305
-
306
- echo ""
307
- info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
308
- info "次のステップ:"
309
- info " 1. $req_file を編集する"
310
- info " 2. チームに確認してもらう"
311
- info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $req_file"
312
- info " 4. ./.spec-runner/scripts/spec-runner.sh design-high"
313
- info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
314
- }
315
-
316
- # ── require ───────────────────────────────────────────────────────────────────
317
- cmd_require() {
318
- require_state
319
- local phase
320
- phase=$(state_get "phase")
321
- [[ "$phase" == "require" ]] || die "現在のフェーズは '$phase' です。要件定義フェーズではありません"
322
-
323
- local req_file
324
- req_file=$(uc_req)
325
- info "要件定義ファイル: $req_file"
326
- info "編集後、チームに確認してもらい:"
327
- info " ./.spec-runner/scripts/spec-runner.sh review-pass $req_file"
328
- }
329
-
330
- # ── design-high ───────────────────────────────────────────────────────────────
331
- cmd_design_high() {
332
- require_state
333
-
334
- echo ""
335
- step "【ゲートチェック】概要設計フェーズに進む条件を確認します"
336
- echo ""
337
-
338
- local errors=0
339
- local req_file
340
- req_file=$(uc_req)
341
-
342
- check_file "$req_file" "要件定義ファイル" || ((errors++))
343
- check_status "$req_file" "approved" "要件定義のステータス" || ((errors++))
344
- check_gate "glossary_checked" "用語集.md の確認済み" || ((errors++))
345
-
346
- if [[ $errors -gt 0 ]]; then
347
- echo ""
348
- die "ゲートを通過できません。${errors}件の条件が未達です ↑"
349
- fi
350
-
351
- echo ""
352
- ok "ゲート通過!概要設計フェーズを開始します"
353
- state_set_str "phase" "design-high"
354
- state_push_history "design-high フェーズ開始"
355
-
356
- # 概要設計ファイルをテンプレートから生成
357
- local high_file usecase
358
- high_file=$(uc_high)
359
- usecase=$(state_get "usecase")
360
- mkdir -p "$(dirname "$high_file")"
361
-
362
- if [[ ! -f "$high_file" ]]; then
363
- cat > "$high_file" <<TMPL
364
- ---
365
- title: $usecase 概要設計
366
- status: draft
367
- requirement: $(uc_req)
368
- created: $(date +%Y-%m-%d)
369
- updated: $(date +%Y-%m-%d)
370
- ---
371
-
372
- # $usecase 概要設計
373
-
374
- ## ユースケース
375
-
376
- ### UC-01: $usecase
377
-
378
- **アクター**:
379
- **前提条件**:
380
- **主要フロー**:
381
- 1.
382
- **事後条件**:
383
- **例外フロー**:
384
-
385
- ## ドメインモデルの洗い出し
386
-
387
- <!-- 用語集.md の日本語名で書く -->
388
-
389
- ### エンティティ候補
390
-
391
- | 名前(日本語) | 説明 | 属する集約 |
392
- |-------------|------|----------|
393
- | | | |
394
-
395
- ### 値オブジェクト候補
396
-
397
- | 名前(日本語) | 説明 |
398
- |-------------|------|
399
- | | |
400
-
401
- ### ドメインイベント候補
402
-
403
- | 名前(日本語) | いつ発生するか |
404
- |-------------|-------------|
405
- | | |
406
-
407
- ## 未決事項
408
-
409
- - [ ]
410
-
411
- ## レビュー記録
412
-
413
- | 日付 | レビュアー | 結果 |
414
- |------|----------|------|
415
- TMPL
416
- ok "概要設計ファイルを作成: $high_file"
417
- fi
418
-
419
- echo ""
420
- info "次のステップ:"
421
- info " 1. $high_file を編集する"
422
- info " 2. チームにレビューしてもらう"
423
- info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $high_file"
424
- info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail domain"
425
- }
426
-
427
- # ── design-detail ─────────────────────────────────────────────────────────────
428
- cmd_design_detail() {
429
- require_state
430
- local sub="${1:-}"
431
- local valid_subs="domain usecase table infra"
432
-
433
- if [[ -z "$sub" ]]; then
434
- # サブフェーズなしで呼んだ場合、現在の進捗を表示
435
- echo ""
436
- step "詳細設計フェーズの進捗"
437
- echo ""
438
- local usecase detail_dir
439
- usecase=$(state_get "usecase")
440
- detail_dir=$(uc_detail)
441
-
442
- local all_ok=true
443
- for s in domain usecase table infra; do
444
- local f="$detail_dir/$s.md"
445
- if [[ -f "$f" ]]; then
446
- local st
447
- st=$(doc_status "$f")
448
- if [[ "$st" == "reviewed" || "$st" == "approved" ]]; then
449
- ok "$s.md (status: $st)"
450
- else
451
- warn "$s.md (status: $st) ← レビュー未完了"
452
- all_ok=false
453
- fi
454
- else
455
- fail "$s.md 未作成"
456
- all_ok=false
457
- fi
458
- done
459
-
460
- echo ""
461
- if $all_ok; then
462
- info "全サブフェーズ完了。次: ./.spec-runner/scripts/spec-runner.sh test-design"
463
- else
464
- info "次のサブフェーズ: ./.spec-runner/scripts/spec-runner.sh design-detail <domain|usecase|table|infra>"
465
- fi
466
- return
467
- fi
468
-
469
- echo "$valid_subs" | grep -qw "$sub" || die "無効なサブフェーズ: $sub(domain / usecase / table / infra)"
470
-
471
- # ゲートチェック
472
- echo ""
473
- step "【ゲートチェック】詳細設計($sub)フェーズに進む条件を確認します"
474
- echo ""
475
-
476
- local errors=0
477
- local high_file
478
- high_file=$(uc_high)
479
-
480
- check_file "$high_file" "概要設計ファイル" || ((errors++))
481
- check_status "$high_file" "reviewed" "概要設計のステータス" || ((errors++))
482
-
483
- # サブフェーズ固有の依存チェック
484
- local detail_dir
485
- detail_dir=$(uc_detail)
486
- case "$sub" in
487
- usecase)
488
- check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
489
- check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
490
- ;;
491
- table)
492
- check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
493
- check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
494
- check_file "$detail_dir/ユースケース.md" "ユースケース設計" || ((errors++))
495
- check_status "$detail_dir/ユースケース.md" "reviewed" "ユースケース設計のレビュー" || ((errors++))
496
- ;;
497
- infra)
498
- check_file "$detail_dir/ドメイン.md" "ドメインモデル設計" || ((errors++))
499
- check_status "$detail_dir/ドメイン.md" "reviewed" "ドメインモデルのレビュー" || ((errors++))
500
- check_file "$detail_dir/ユースケース.md" "ユースケース設計" || ((errors++))
501
- check_status "$detail_dir/ユースケース.md" "reviewed" "ユースケース設計のレビュー" || ((errors++))
502
- check_file "$detail_dir/テーブル.md" "テーブル設計" || ((errors++))
503
- check_status "$detail_dir/テーブル.md" "reviewed" "テーブル設計のレビュー" || ((errors++))
504
- ;;
505
- esac
506
-
507
- if [[ $errors -gt 0 ]]; then
508
- echo ""
509
- die "ゲートを通過できません。${errors}件の条件が未達です ↑"
510
- fi
511
-
512
- echo ""
513
- ok "ゲート通過!詳細設計($sub)フェーズを開始します"
514
- state_set_str "phase" "design-detail-$sub"
515
- state_push_history "design-detail-$sub フェーズ開始"
516
-
517
- # サブ種別→日本語ファイル名(ドメイン駆動の用語をそのまま)
518
- local sub_ja
519
- case "$sub" in
520
- domain) sub_ja="ドメイン" ;;
521
- usecase) sub_ja="ユースケース" ;;
522
- table) sub_ja="テーブル" ;;
523
- infra) sub_ja="インフラ" ;;
524
- *) sub_ja="$sub" ;;
525
- esac
526
-
527
- # ファイルをテンプレートから生成
528
- local dest_file usecase
529
- usecase=$(state_get "usecase")
530
- dest_file="$detail_dir/${sub_ja}.md"
531
- mkdir -p "$detail_dir"
532
-
533
- local tmpl="$SPEC_RUNNER_DIR/templates/03_詳細設計/${sub_ja}.md"
534
- if [[ ! -f "$dest_file" ]]; then
535
- if [[ -f "$tmpl" ]]; then
536
- sed "s/{{USECASE}}/$usecase/g; s/{{DATE}}/$(date +%Y-%m-%d)/g" "$tmpl" > "$dest_file"
537
- else
538
- echo "---
539
- title: $usecase $(case $sub in domain) echo "ドメインモデル設計";; usecase) echo "ユースケース設計";; table) echo "テーブル設計";; infra) echo "インフラ設計";; esac)
540
- status: draft
541
- created: $(date +%Y-%m-%d)
542
- updated: $(date +%Y-%m-%d)
543
- ---
544
-
545
- # $usecase $(case $sub in domain) echo "ドメインモデル設計";; usecase) echo "ユースケース設計";; table) echo "テーブル設計";; infra) echo "インフラ設計";; esac)
546
- " > "$dest_file"
547
- fi
548
- ok "設計ファイルを作成: $dest_file"
549
- fi
550
-
551
- echo ""
552
- info "次のステップ:"
553
- info " 1. $dest_file を編集する"
554
- info " 2. チームにレビューしてもらう"
555
- info " 3. ./.spec-runner/scripts/spec-runner.sh review-pass $dest_file"
556
- case "$sub" in
557
- domain) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail usecase" ;;
558
- usecase) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail table" ;;
559
- table) info " 4. ./.spec-runner/scripts/spec-runner.sh design-detail infra" ;;
560
- infra) info " 4. ./.spec-runner/scripts/spec-runner.sh test-design" ;;
561
- esac
562
- }
563
-
564
- # ── test-design ───────────────────────────────────────────────────────────────
565
- cmd_test_design() {
566
- require_state
567
-
568
- echo ""
569
- step "【ゲートチェック】テスト設計フェーズに進む条件を確認します"
570
- echo ""
571
-
572
- local errors=0
573
- local detail_dir
574
- detail_dir=$(uc_detail)
575
-
576
- for sub_ja in ドメイン ユースケース テーブル インフラ; do
577
- check_file "$detail_dir/$sub_ja.md" "03_詳細設計/$sub_ja.md" || ((errors++))
578
- check_status "$detail_dir/$sub_ja.md" "reviewed" "03_詳細設計/$sub_ja.md のレビュー" || ((errors++))
579
- done
580
-
581
- # 設計判断記録チェック(ADR が 1 件もない場合に促す)
582
- local adr_count
583
- adr_count=$(find "$PROJECT_ROOT/docs/99_設計判断記録" -name "*.md" ! -name "ひな形.md" 2>/dev/null | wc -l | tr -d ' ')
584
- if [[ "$adr_count" -eq 0 ]]; then
585
- warn "docs/99_設計判断記録/ にADRが1件もありません。設計判断があれば作成してください"
586
- fi
587
-
588
- if [[ $errors -gt 0 ]]; then
589
- echo ""
590
- die "ゲートを通過できません。${errors}件の条件が未達です ↑"
591
- fi
592
-
593
- echo ""
594
- ok "ゲート通過!テスト設計フェーズを開始します"
595
- state_set_str "phase" "test-design"
596
- state_push_history "test-design フェーズ開始"
597
-
598
- local test_file usecase
599
- usecase=$(state_get "usecase")
600
- test_file=$(uc_test)
601
- mkdir -p "$(dirname "$test_file")"
602
-
603
- if [[ ! -f "$test_file" ]]; then
604
- cat > "$test_file" <<TMPL
605
- ---
606
- title: $usecase テスト設計
607
- status: draft
608
- created: $(date +%Y-%m-%d)
609
- updated: $(date +%Y-%m-%d)
610
- ---
611
-
612
- # $usecase テスト設計
613
-
614
- ## テスト方針
615
-
616
- | 種別 | 対象 | ツール |
617
- |------|------|-------|
618
- | Unit | ドメインモデルの振る舞い | PHPUnit |
619
- | Unit | 値オブジェクトのバリデーション | PHPUnit |
620
- | Integration | ユースケース | PHPUnit + DB |
621
- | Feature | APIエンドポイント | PHPUnit + HTTP |
622
-
623
- ## ドメインモデル テストケース
624
-
625
- | # | テストケース名(日本語) | 入力 | 期待結果 | 種別 |
626
- |---|----------------------|------|---------|------|
627
- | 1 | の場合、となる | | | 正常 |
628
-
629
- ## ユースケース テストケース
630
-
631
- | # | テストケース名(日本語) | 前提条件 | 入力 | 期待結果 |
632
- |---|----------------------|---------|------|---------|
633
- | 1 | | | | |
634
-
635
- ## テストコードチェックリスト
636
-
637
- - [ ] ドメインモデルのUnitテスト作成済み(Red状態確認)
638
- - [ ] 値オブジェクトのUnitテスト作成済み(Red状態確認)
639
- - [ ] ユースケースのIntegrationテスト作成済み(Red状態確認)
640
- - [ ] APIのFeatureテスト作成済み(Red状態確認)
641
- TMPL
642
- ok "テスト設計ファイルを作成: $test_file"
643
- fi
644
-
645
- echo ""
646
- info "次のステップ:"
647
- info " 1. $test_file を編集する(テスト設計)"
648
- info " 2. テストコードを書く(実装前。Red状態でOK)"
649
- info " 3. git commit でテストコードをコミット"
650
- info " 4. ./.spec-runner/scripts/spec-runner.sh review-pass $test_file"
651
- info " 5. ./.spec-runner/scripts/spec-runner.sh implement"
652
- }
653
-
654
- # ── implement ─────────────────────────────────────────────────────────────────
655
- cmd_implement() {
656
- require_state
657
-
658
- echo ""
659
- step "【ゲートチェック】実装フェーズに進む条件を確認します"
660
- echo ""
661
-
662
- local errors=0
663
- local test_file
664
- test_file=$(uc_test)
665
-
666
- # TDD 有効時のみ: テスト設計+テストコードを必須(.spec-runner/config.sh の TDD_ENABLED=false で無効化可)
667
- if [[ "${TDD_ENABLED:-true}" != "false" ]]; then
668
- check_file "$test_file" "テスト設計ファイル" || ((errors++))
669
- check_status "$test_file" "reviewed" "テスト設計のレビュー" || ((errors++))
670
-
671
- local test_committed
672
- test_committed=$(state_get "gates.test_code_committed")
673
- if [[ "$test_committed" != "true" ]]; then
674
- # テストディレクトリ(.spec-runner/config.sh の TEST_DIR)配下の未コミットを検出
675
- local test_dir_prefix="${TEST_DIR:-tests}"
676
- local uncommitted_under_test
677
- uncommitted_under_test=$(git status --porcelain 2>/dev/null | awk '{print $2}' | grep -E "^${test_dir_prefix}/" | wc -l | tr -d ' ')
678
- if [[ "${uncommitted_under_test:-0}" -gt 0 ]]; then
679
- fail "テストコードが未コミットです(TDD 必須。${test_dir_prefix}/ 配下をコミットするか set-gate test_code_committed)"
680
- ((errors++))
681
- else
682
- warn "テストコードがコミット済みか未確認です"
683
- warn "確認後: ./.spec-runner/scripts/spec-runner.sh set-gate test_code_committed"
684
- fi
685
- else
686
- check_gate "test_code_committed" "テストコードのコミット確認" || ((errors++))
687
- fi
688
- else
689
- # TDD オプション時: テスト設計・テストコードは必須ではない(あれば推奨)
690
- if [[ -f "$test_file" ]]; then
691
- ok "テスト設計ファイル: $test_file(TDD オプションのため未レビューでも可)"
692
- else
693
- warn "テスト設計ファイルがありません(TDD オプションのため実装は進められます)"
694
- fi
695
- fi
696
-
697
- if [[ $errors -gt 0 ]]; then
698
- echo ""
699
- die "ゲートを通過できません。${errors}件の条件が未達です ↑"
700
- fi
701
-
702
- echo ""
703
- ok "ゲート通過!実装フェーズを開始します"
704
- state_set_str "phase" "implement"
705
- state_push_history "implement フェーズ開始"
706
-
707
- echo ""
708
- warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
709
- warn " 実装フェーズのルール"
710
- warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
711
- info " 1. テストを Green にする実装を書く"
712
- info " 2. 設計と乖離した場合は先にドキュメントを更新する"
713
- info " 3. コードとドキュメントを同一コミットに含める"
714
- info " 4. 完了したら: git push → PR 作成。次のユースケースは init <名前> で開始"
715
- warn "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
716
- }
717
-
718
- # ── review-pass ───────────────────────────────────────────────────────────────
719
- cmd_review_pass() {
720
- local file="${1:-}"
721
- [[ -n "$file" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh review-pass <ファイルパス>"
722
- [[ -f "$file" ]] || die "ファイルが存在しません: $file"
723
-
724
- # frontmatterのstatusを更新
725
- local today
726
- today=$(date +%Y-%m-%d)
727
-
728
- if grep -q '^status:' "$file"; then
729
- # 既存のstatusを更新(同一デバイス上に一時ファイルを作成してmv)
730
- local tmp
731
- tmp="${file}.tmp.$$"
732
- sed "s/^status: .*/status: reviewed/" "$file" > "$tmp" && mv "$tmp" "$file"
733
- # updated日付も更新
734
- tmp="${file}.tmp.$$"
735
- sed "s/^updated: .*/updated: $today/" "$file" > "$tmp" && mv "$tmp" "$file"
736
- else
737
- die "ファイルにfrontmatter(status:)がありません: $file"
738
- fi
739
-
740
- ok "レビュー通過: $file (status: reviewed)"
741
-
742
- # どのゲートフラグを立てるか判定
743
- require_state
744
- local uc_slug_val
745
- uc_slug_val=$(uc_slug)
746
-
747
- case "$file" in
748
- *01_要件*)
749
- state_set_bool "gates.require_approved" true
750
- state_set_str "phase" "require-approved"
751
- # statusもapprovedに(同一デバイス上で一時ファイル)
752
- local tmp2
753
- tmp2="${file}.tmp.$$"
754
- sed "s/^status: .*/status: approved/" "$file" > "$tmp2" && mv "$tmp2" "$file"
755
- ok "ゲート更新: require_approved = true"
756
- info "次: docs/03_用語集.md を確認後 ./.spec-runner/scripts/spec-runner.sh set-gate glossary_checked"
757
- info " ./.spec-runner/scripts/spec-runner.sh design-high"
758
- ;;
759
- *02_概要設計*)
760
- state_set_bool "gates.high_level_reviewed" true
761
- ok "ゲート更新: high_level_reviewed = true"
762
- info "次: ./.spec-runner/scripts/spec-runner.sh design-detail domain"
763
- ;;
764
- *ドメイン*)
765
- state_set_bool "gates.domain_model_reviewed" true
766
- ok "ゲート更新: domain_model_reviewed = true"
767
- info "次: ./.spec-runner/scripts/spec-runner.sh design-detail usecase"
768
- ;;
769
- *ユースケース*)
770
- state_set_bool "gates.usecase_design_reviewed" true
771
- ok "ゲート更新: usecase_design_reviewed = true"
772
- info "次: ./.spec-runner/scripts/spec-runner.sh design-detail table"
773
- ;;
774
- *テーブル*)
775
- state_set_bool "gates.table_design_reviewed" true
776
- ok "ゲート更新: table_design_reviewed = true"
777
- info "次: ./.spec-runner/scripts/spec-runner.sh design-detail infra"
778
- ;;
779
- *インフラ*)
780
- state_set_bool "gates.infra_design_reviewed" true
781
- ok "ゲート更新: infra_design_reviewed = true"
782
- info "次: ./.spec-runner/scripts/spec-runner.sh test-design"
783
- ;;
784
- *04_テスト設計*)
785
- state_set_bool "gates.test_design_reviewed" true
786
- ok "ゲート更新: test_design_reviewed = true"
787
- info "テストコードをコミット後: ./.spec-runner/scripts/spec-runner.sh set-gate test_code_committed"
788
- info "その後: ./.spec-runner/scripts/spec-runner.sh implement"
789
- ;;
790
- esac
791
- }
792
-
793
- # 日本語ゲート名 → 内部キー(set-gate で日本語指定時に使用)
794
- gate_ja_to_key() {
795
- case "$1" in
796
- 要件レビュー済み) echo "require_approved" ;;
797
- 用語集確認済み) echo "glossary_checked" ;;
798
- 概要設計レビュー済み) echo "high_level_reviewed" ;;
799
- ドメインモデルレビュー済み) echo "domain_model_reviewed" ;;
800
- ユースケース設計レビュー済み) echo "usecase_design_reviewed" ;;
801
- テーブル設計レビュー済み) echo "table_design_reviewed" ;;
802
- インフラ設計レビュー済み) echo "infra_design_reviewed" ;;
803
- テスト設計レビュー済み) echo "test_design_reviewed" ;;
804
- テストコードコミット済み) echo "test_code_committed" ;;
805
- *) echo "$1" ;;
806
- esac
807
- }
808
-
809
- # ── set-gate ──────────────────────────────────────────────────────────────────
810
- cmd_set_gate() {
811
- require_state
812
- local gate="${1:-}"
813
- [[ -n "$gate" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh set-gate <ゲート名> 例: 用語集確認済み、テストコードコミット済み"
814
- local key
815
- key=$(gate_ja_to_key "$gate")
816
- state_set_bool "gates.$key" true
817
- ok "ゲートフラグ設定: $key = true"
818
- }
819
-
820
- # ── status 表示用:フェーズ・ゲートの日本語ラベル ─────────────────────────────
821
- phase_ja() {
822
- case "$1" in
823
- require) echo "要件定義" ;;
824
- require-approved) echo "要件承認済み" ;;
825
- design-high) echo "概要設計" ;;
826
- design-detail*) echo "詳細設計" ;;
827
- test-design) echo "テスト設計" ;;
828
- implement) echo "実装" ;;
829
- complete) echo "完了" ;;
830
- fix) echo "修正" ;;
831
- *) echo "$1" ;;
832
- esac
833
- }
834
- gate_ja() {
835
- case "$1" in
836
- require_approved) echo "要件レビュー済み" ;;
837
- glossary_checked) echo "用語集確認済み" ;;
838
- high_level_reviewed) echo "概要設計レビュー済み" ;;
839
- domain_model_reviewed) echo "ドメインモデルレビュー済み" ;;
840
- usecase_design_reviewed) echo "ユースケース設計レビュー済み" ;;
841
- table_design_reviewed) echo "テーブル設計レビュー済み" ;;
842
- infra_design_reviewed) echo "インフラ設計レビュー済み" ;;
843
- test_design_reviewed) echo "テスト設計レビュー済み" ;;
844
- test_code_committed) echo "テストコードコミット済み" ;;
845
- *) echo "$1" ;;
846
- esac
847
- }
848
-
849
- # ── status: プロジェクト土台(憲章・仕様)の未記入チェック ─────────────────────
850
- # プレースホルダーが残っている=テンプレートのまま=未記入とみなす
851
- CONSTITUTION_PLACEHOLDER="この節を編集"
852
- SPECIFY_PLACEHOLDER="(1〜2文で。例:"
853
-
854
- is_foundation_written() {
855
- local kind="$1"
856
- case "$kind" in
857
- constitution)
858
- [[ -f "$PROJECT_ROOT/docs/01_憲章.md" ]] && ! grep -q "$CONSTITUTION_PLACEHOLDER" "$PROJECT_ROOT/docs/01_憲章.md" 2>/dev/null
859
- ;;
860
- specify)
861
- [[ -f "$PROJECT_ROOT/docs/02_仕様.md" ]] && ! grep -q "$SPECIFY_PLACEHOLDER" "$PROJECT_ROOT/docs/02_仕様.md" 2>/dev/null
862
- ;;
863
- *) return 1 ;;
864
- esac
865
- }
866
-
867
- # 憲章・仕様の未記入案内を表示。mode: no_state(ユースケースなし) or has_state(開始済み)
868
- status_show_foundation_reminder() {
869
- local mode="${1:-no_state}"
870
- local c_ok s_ok
871
- is_foundation_written constitution && c_ok=1 || c_ok=0
872
- is_foundation_written specify && s_ok=1 || s_ok=0
873
- [[ $c_ok -eq 1 && $s_ok -eq 1 ]] && return
874
-
875
- if [[ "$mode" == "no_state" ]]; then
876
- info "プロジェクトの土台(init の前推奨):"
877
- [[ $c_ok -eq 0 ]] && info " ✗ 憲章がまだ記入されていません → docs/01_憲章.md (/sr-憲章 で編集)"
878
- [[ $s_ok -eq 0 ]] && info " ✗ 仕様がまだ記入されていません → docs/02_仕様.md (/sr-仕様 で編集)"
879
- else
880
- info "💡 プロジェクトの土台:"
881
- [[ $c_ok -eq 0 ]] && info " 憲章がまだ → /sr-憲章"
882
- [[ $s_ok -eq 0 ]] && info " 仕様がまだ → /sr-仕様"
883
- fi
884
- info ""
885
- }
886
-
887
- # ── status ─────────────────────────────────────────────────────────────────────
888
- cmd_status() {
889
- if [[ ! -f "$STATE_FILE" ]]; then
890
- info "作業中のユースケースはありません"
891
- info ""
892
- status_show_foundation_reminder no_state
893
- info "開始するには: チャットで /sr-初期化 <ユースケース名> またはターミナルで下記を実行してください。"
894
- info " 例(チャット): /sr-初期化 会員登録 会員"
895
- info " 例(ターミナル): ./.spec-runner/scripts/spec-runner.sh init 会員登録 会員"
896
- return
897
- fi
898
-
899
- status_show_foundation_reminder has_state
900
-
901
- local usecase phase branch agg_branch
902
- usecase=$(state_get "usecase")
903
- phase=$(state_get "phase")
904
- branch=$(state_get "branch")
905
- agg_branch=$(state_get "aggregate_branch")
906
-
907
- local phase_ja_label
908
- phase_ja_label=$(phase_ja "$phase")
909
-
910
- echo ""
911
- echo -e "${BOLD}════════════════════════════════════════${NC}"
912
- echo -e "${BOLD} 現在の作業状況${NC}"
913
- echo -e "${BOLD}════════════════════════════════════════${NC}"
914
- echo -e " ユースケース : ${CYAN}$usecase${NC}"
915
- echo -e " フェーズ : ${YELLOW}$phase_ja_label${NC}"
916
- echo -e " ブランチ : ${BLUE}$branch${NC}"
917
- [[ -n "$agg_branch" ]] && echo -e " 集約ブランチ: ${BLUE}$agg_branch${NC}"
918
- echo ""
919
- echo -e "${BOLD} ゲート状況${NC}"
920
-
921
- local gates
922
- for gate in require_approved glossary_checked high_level_reviewed \
923
- domain_model_reviewed usecase_design_reviewed \
924
- table_design_reviewed infra_design_reviewed \
925
- test_design_reviewed test_code_committed; do
926
- local val gate_label
927
- val=$(state_get "gates.$gate")
928
- gate_label=$(gate_ja "$gate")
929
- if [[ "$val" == "true" ]]; then
930
- echo -e " ${GREEN}✓${NC} $gate_label"
931
- else
932
- echo -e " ${RED}✗${NC} $gate_label"
933
- fi
934
- done
935
-
936
- echo ""
937
- echo -e "${BOLD} 次にやるべきこと${NC} ${CYAN}(チャットでは /sr-* スラッシュコマンドが使えます)${NC}"
938
- local req_file high_file
939
- req_file=$(uc_req)
940
- high_file=$(uc_high)
941
- case "$phase" in
942
- require)
943
- echo -e " 1. ${CYAN}$req_file${NC} を編集"
944
- echo -e " 2. /sr-レビュー $req_file"
945
- echo -e " 3. /sr-ゲート設定 用語集確認済み"
946
- echo -e " 4. /sr-概要設計"
947
- ;;
948
- design-high)
949
- echo -e " 1. ${CYAN}$high_file${NC} を編集"
950
- echo -e " 2. /sr-レビュー $high_file"
951
- echo -e " 3. /sr-詳細設計 domain"
952
- ;;
953
- design-detail*)
954
- if [[ "$(state_get "gates.domain_model_reviewed")" != "true" ]]; then
955
- echo -e " 1. docs/03_詳細設計/$(uc_slug)/ドメイン.md を編集"
956
- echo -e " 2. /sr-レビュー のあと /sr-詳細設計 usecase"
957
- elif [[ "$(state_get "gates.usecase_design_reviewed")" != "true" ]]; then
958
- echo -e " 1. docs/03_詳細設計/$(uc_slug)/ユースケース.md を編集"
959
- echo -e " 2. /sr-レビュー のあと /sr-詳細設計 table"
960
- elif [[ "$(state_get "gates.table_design_reviewed")" != "true" ]]; then
961
- echo -e " 1. docs/03_詳細設計/$(uc_slug)/テーブル.md を編集"
962
- echo -e " 2. /sr-レビュー のあと /sr-詳細設計 infra"
963
- elif [[ "$(state_get "gates.infra_design_reviewed")" != "true" ]]; then
964
- echo -e " 1. docs/03_詳細設計/$(uc_slug)/インフラ.md を編集"
965
- echo -e " 2. /sr-レビュー のあと /sr-テスト設計"
966
- else
967
- echo -e " /sr-テスト設計"
968
- fi
969
- ;;
970
- test-design)
971
- echo -e " 1. docs/04_テスト設計/$(uc_slug).md を編集し、テストコードを書く(Red)"
972
- echo -e " 2. テストコードをコミット → /sr-ゲート設定 テストコードコミット済み"
973
- echo -e " 3. /sr-レビュー docs/04_テスト設計/$(uc_slug).md"
974
- echo -e " 4. /sr-実装"
975
- ;;
976
- implement)
977
- echo -e " 実装完了したら: git push → PR 作成。次のユースケースは /sr-初期化 <名前> で開始"
978
- ;;
979
- fix)
980
- echo -e " 案内に従って該当ドキュメントを修正し、必要なら /sr-詳細設計 等から再実行。"
981
- ;;
982
- *)
983
- echo -e " ./.spec-runner/scripts/spec-runner.sh help でコマンド一覧を確認"
984
- ;;
985
- esac
986
- echo ""
987
- echo -e "${BOLD} 履歴${NC}"
988
- jq -r '.history[]' "$STATE_FILE" 2>/dev/null | tail -5 | while read -r line; do
989
- echo " $line"
990
- done
991
- echo -e "${BOLD}════════════════════════════════════════${NC}"
992
-
993
- # debt確認
994
- if [[ -f "$DEBT_FILE" ]]; then
995
- local unchecked
996
- unchecked=$(grep -c '^\- \[ \]' "$DEBT_FILE" 2>/dev/null; true)
997
- unchecked="${unchecked:-0}"
998
- if [[ "${unchecked}" -gt 0 ]]; then
999
- warn "ドキュメント負債: ${unchecked} 件"
1000
- fi
1001
- fi
1002
- }
1003
-
1004
- # ── fix ───────────────────────────────────────────────────────────────────────
1005
- cmd_fix() {
1006
- local content="${1:-}"
1007
- [[ -n "$content" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh fix <修正内容>"
1008
-
1009
- echo ""
1010
- step "修正フロー: $content"
1011
- echo ""
1012
- echo "修正レベルを選択してください:"
1013
- echo " 1) ドメインモデルの構造変更 → domain設計から再実行"
1014
- echo " 2) ユースケースのフロー変更 → usecase設計から再実行"
1015
- echo " 3) APIの仕様変更 → infra設計から再実行"
1016
- echo " 4) テーブル構造の変更 → table設計から再実行"
1017
- echo " 5) バグ修正(設計は正しい)→ テスト追加→実装修正"
1018
- echo ""
1019
- read -r -p "番号を選択 [1-5]: " level
1020
-
1021
- local usecase slug branch
1022
- slug=$(echo "$content" | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-30)
1023
- usecase="${2:-$(state_get "usecase" 2>/dev/null || echo "unknown")}"
1024
- branch="fix/$(echo "$usecase" | tr ' ' '-')-$slug"
1025
-
1026
- git checkout -b "$branch" 2>/dev/null || warn "ブランチ作成に失敗しました(手動で作成してください)"
1027
-
1028
- case "$level" in
1029
- 1)
1030
- info "ドメインモデルから再設計します"
1031
- info "修正ファイル:"
1032
- info " docs/03_詳細設計/$(uc_slug)/ドメイン.md → status: draft に戻す"
1033
- info " docs/03_詳細設計/$(uc_slug)/ユースケース.md → 再確認"
1034
- info " docs/04_テスト設計/$(uc_slug).md → 再確認"
1035
- ;;
1036
- 2)
1037
- info "ユースケース設計から修正します"
1038
- info " docs/03_詳細設計/$(uc_slug)/ユースケース.md → status: draft に戻す"
1039
- info " docs/04_テスト設計/$(uc_slug).md → 再確認"
1040
- ;;
1041
- 3)
1042
- info "インフラ設計から修正します"
1043
- info " docs/03_詳細設計/$(uc_slug)/インフラ.md → status: draft に戻す"
1044
- ;;
1045
- 4)
1046
- info "テーブル設計から修正します"
1047
- info " docs/03_詳細設計/$(uc_slug)/テーブル.md → status: draft に戻す"
1048
- ;;
1049
- 5)
1050
- info "テストを追加して実装を修正します"
1051
- info " テストコード追加 → git commit → ./.spec-runner/scripts/spec-runner.sh implement"
1052
- ;;
1053
- *)
1054
- die "無効な選択です"
1055
- ;;
1056
- esac
1057
-
1058
- state_set_str "phase" "fix"
1059
- state_push_history "修正開始: $content (level: $level)"
1060
- }
1061
-
1062
- # ── hotfix ────────────────────────────────────────────────────────────────────
1063
- cmd_hotfix() {
1064
- local content="${1:-}"
1065
- [[ -n "$content" ]] || die "使い方: ./.spec-runner/scripts/spec-runner.sh hotfix <内容>"
1066
-
1067
- local slug branch
1068
- slug=$(echo "$content" | tr ' ' '-' | tr -cd '[:alnum:]-' | cut -c1-30)
1069
- branch="hotfix/$slug"
1070
-
1071
- step "緊急修正ブランチを作成: $branch"
1072
- git checkout -b "$branch" main
1073
-
1074
- ok "ブランチ作成: $branch"
1075
- warn "緊急修正後、ドキュメント負債として記録されます"
1076
-
1077
- # debt.mdに追記
1078
- mkdir -p "$(dirname "$DEBT_FILE")"
1079
- [[ -f "$DEBT_FILE" ]] || echo "# ドキュメント負債" > "$DEBT_FILE"
1080
-
1081
- cat >> "$DEBT_FILE" <<DEBT
1082
-
1083
- ## $(date +%Y-%m-%d): hotfix/$slug
1084
-
1085
- - [ ] 修正内容に対応するテスト設計ドキュメントの更新
1086
- - hotfix内容: $content
1087
- - 対象ユースケース: 要確認
1088
- - 修正したコード: 要確認
1089
- DEBT
1090
-
1091
- ok "負債を記録: $DEBT_FILE"
1092
- info "修正完了後: git push origin $branch → main へPR"
1093
- info "次回の init 時に負債の消化を促されます"
1094
- }
1095
-
1096
- # ── メインルーター ────────────────────────────────────────────────────────────
1097
- main() {
1098
- local cmd="${1:-help}"
1099
- shift || true
1100
-
1101
- case "$cmd" in
1102
- init) cmd_init "$@" ;;
1103
- require) cmd_require "$@" ;;
1104
- design-high) cmd_design_high "$@" ;;
1105
- design-detail) cmd_design_detail "$@" ;;
1106
- test-design) cmd_test_design "$@" ;;
1107
- implement) cmd_implement "$@" ;;
1108
- review-pass) cmd_review_pass "$@" ;;
1109
- set-gate) cmd_set_gate "$@" ;;
1110
- status) cmd_status "$@" ;;
1111
- fix) cmd_fix "$@" ;;
1112
- hotfix) cmd_hotfix "$@" ;;
1113
- help|--help|-h)
1114
- echo ""
1115
- echo -e "${BOLD}使い方:${NC}"
1116
- echo " ./.spec-runner/scripts/spec-runner.sh <コマンド> [引数]"
1117
- echo ""
1118
- echo -e "${BOLD}新規開発フロー:${NC}"
1119
- echo " init [ユースケース名] [集約名] 引数なしで設定対話。名前を渡すとユースケース作成"
1120
- echo " require 要件定義フェーズ(ファイルパスを確認)"
1121
- echo " design-high 概要設計フェーズに移行(ゲートチェック)"
1122
- echo " design-detail <sub> 詳細設計フェーズ(sub: domain|usecase|table|infra)"
1123
- echo " test-design テスト設計フェーズに移行(ゲートチェック)"
1124
- echo " implement 実装フェーズに移行(ゲートチェック)"
1125
- echo ""
1126
- echo -e "${BOLD}レビュー:${NC}"
1127
- echo " review-pass <ファイル> ドキュメントをレビュー通過にする"
1128
- echo " set-gate <ゲート名> 手動でゲートフラグを立てる(日本語可。例: 用語集確認済み)"
1129
- echo ""
1130
- echo -e "${BOLD}確認:${NC}"
1131
- echo " status 現在の状態を表示"
1132
- echo ""
1133
- echo -e "${BOLD}修正フロー:${NC}"
1134
- echo " fix <修正内容> 通常修正フロー(影響範囲分析)"
1135
- echo " hotfix <内容> 緊急修正(負債として記録)"
1136
- echo ""
1137
- ;;
1138
- *)
1139
- die "不明なコマンド: $cmd\n使い方: ./.spec-runner/scripts/spec-runner.sh help"
1140
- ;;
1141
- esac
1142
- }
1143
-
1144
- main "$@"