bmad-setup 1.4.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/README.md +522 -0
- package/bin/cli.js +270 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# BMAD Framework Submodule
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
BMAD-METHOD - 범용 AI 에이전트 프레임워크
|
|
9
|
+
|
|
10
|
+
소프트웨어 개발 전체 라이프사이클을 위한 프롬프트 & 컨텍스트 엔지니어링 프레임워크입니다. 전문화된 에이전트(Analyst, PM, Architect, Dev, Test Architect)와 워크플로우, 지식 베이스를 제공합니다.
|
|
11
|
+
|
|
12
|
+
| 항목 | 버전 |
|
|
13
|
+
| ------------------ | ----------------- |
|
|
14
|
+
| Submodule Version | v1.3.1 |
|
|
15
|
+
| BMAD Framework | 6.0.0-beta.8 |
|
|
16
|
+
|
|
17
|
+
> [Changelog](./CHANGELOG.md) 에서 변경 이력을 확인하세요.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Git Submodule이란?
|
|
22
|
+
|
|
23
|
+
Git을 처음 접하시거나 Submodule이 생소하신 분들을 위한 설명입니다.
|
|
24
|
+
|
|
25
|
+
### 기본 개념
|
|
26
|
+
|
|
27
|
+
**Submodule**은 하나의 Git 저장소 안에 다른 Git 저장소를 포함시키는 기능입니다.
|
|
28
|
+
|
|
29
|
+
일반적인 폴더와 달리:
|
|
30
|
+
|
|
31
|
+
- 실제 파일 전체가 아닌 **참조(포인터)**만 저장됩니다
|
|
32
|
+
- `.gitmodules` 파일에 원격 저장소 URL이 기록됩니다
|
|
33
|
+
- 특정 커밋(SHA)을 가리키므로 버전 고정이 가능합니다
|
|
34
|
+
|
|
35
|
+
### 비유로 이해하기
|
|
36
|
+
|
|
37
|
+
**일반 폴더 복사** = 책 전체를 복사해서 가져옴
|
|
38
|
+
**Submodule** = 도서관 책의 위치(서가 번호)만 메모해둠
|
|
39
|
+
|
|
40
|
+
따라서:
|
|
41
|
+
|
|
42
|
+
- 메인 프로젝트는 가볍게 유지됩니다
|
|
43
|
+
- BMAD 업데이트는 원본 저장소에서 한 번만 하면 됩니다
|
|
44
|
+
- 여러 프로젝트에서 동일한 BMAD를 공유할 수 있습니다
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 왜 Submodule을 사용하나요?
|
|
49
|
+
|
|
50
|
+
### 장점
|
|
51
|
+
|
|
52
|
+
| 구분 | 직접 복사 | Submodule 사용 |
|
|
53
|
+
| ----------- | --------------------------- | --------------------------- |
|
|
54
|
+
| PR 크기 | 300개 이상 파일 변경 | 2개 파일만 변경 |
|
|
55
|
+
| 업데이트 | 각 프로젝트마다 수동 복사 | `git pull` 한 번으로 해결 |
|
|
56
|
+
| 버전 관리 | 어떤 버전인지 추적 어려움 | 커밋 SHA로 정확한 버전 추적 |
|
|
57
|
+
| 디스크 용량 | 프로젝트마다 전체 파일 중복 | 참조만 저장 |
|
|
58
|
+
| 설치 자동화 | 불가능 | `npm install`로 자동 초기화 |
|
|
59
|
+
|
|
60
|
+
### 단점 및 주의사항
|
|
61
|
+
|
|
62
|
+
- 초기 학습 곡선이 있습니다
|
|
63
|
+
- `git clone` 시 `--recurse-submodules` 옵션을 잊으면 빈 폴더가 됩니다
|
|
64
|
+
- Submodule 내부 변경사항은 별도로 커밋/푸시해야 합니다
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 언제 이 프레임워크를 사용하나요?
|
|
69
|
+
|
|
70
|
+
### 적합한 경우
|
|
71
|
+
|
|
72
|
+
- **AI 기반 개발 워크플로우**를 구축하려는 팀
|
|
73
|
+
- **Claude Code** 또는 **Cursor** 등 AI 도구를 활용하는 프로젝트
|
|
74
|
+
- 여러 프로젝트에서 **일관된 AI 프롬프트/에이전트**를 사용하고 싶을 때
|
|
75
|
+
- **소프트웨어 개발 전체 과정**(기획 → 설계 → 개발 → 테스트)에 AI를 적용하려는 경우
|
|
76
|
+
|
|
77
|
+
### 제공하는 모듈
|
|
78
|
+
|
|
79
|
+
| 모듈 | 설명 | 주요 에이전트/워크플로우 |
|
|
80
|
+
| ------ | ------------------------- | ------------------------------------------- |
|
|
81
|
+
| `core` | 핵심 기능 | bmad-master, brainstorming, party-mode |
|
|
82
|
+
| `bmm` | 소프트웨어 개발 | analyst, architect, dev, pm, sm, ux |
|
|
83
|
+
| `bmb` | 모듈 빌더 | agent-builder, workflow-builder |
|
|
84
|
+
| `gds` | 게임 개발 (구 bmgd) | game-designer, game-dev, game-qa |
|
|
85
|
+
| `tea` | 테스트 아키텍처 | test-engineer-architect |
|
|
86
|
+
| `cis` | 크리에이티브 & 혁신 전략 | design-thinking, innovation, storytelling |
|
|
87
|
+
| `dae` | 데이터 분석 (커스텀) | data-analyst, Amplitude 연동 |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 프로젝트 구조
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
bmad-submodule/
|
|
95
|
+
├── .claude/
|
|
96
|
+
│ └── commands/
|
|
97
|
+
│ ├── bmad-agent-*.md # 에이전트 슬래시 커맨드 (플랫 구조)
|
|
98
|
+
│ ├── bmad-bmm-*.md # BMM 워크플로우 커맨드
|
|
99
|
+
│ ├── bmad-bmb-*.md # BMB 빌더 커맨드
|
|
100
|
+
│ ├── bmad-gds-*.md # GDS 게임 개발 커맨드
|
|
101
|
+
│ ├── bmad-tea-*.md # TEA 테스트 커맨드
|
|
102
|
+
│ ├── bmad-cis-*.md # CIS 크리에이티브 커맨드
|
|
103
|
+
│ ├── bmad-dae-*.md # DAE 데이터 분석 커맨드
|
|
104
|
+
│ └── commit.md # 커밋 커맨드
|
|
105
|
+
├── _bmad/ # BMAD 프레임워크 리소스
|
|
106
|
+
│ ├── _config/ # 설정 파일 (manifest, IDE 설정)
|
|
107
|
+
│ ├── _memory/ # 메모리/사이드카 템플릿
|
|
108
|
+
│ ├── core/ # 핵심 모듈
|
|
109
|
+
│ ├── bmm/ # 소프트웨어 개발 모듈
|
|
110
|
+
│ ├── bmb/ # 모듈 빌더
|
|
111
|
+
│ ├── gds/ # 게임 개발 모듈
|
|
112
|
+
│ ├── tea/ # 테스트 아키텍처 모듈
|
|
113
|
+
│ ├── cis/ # 크리에이티브 & 혁신 전략 모듈
|
|
114
|
+
│ └── dae/ # 데이터 분석 모듈
|
|
115
|
+
├── src/modules/ # 모듈 소스 코드
|
|
116
|
+
├── install.sh # 심볼릭 링크 생성 스크립트
|
|
117
|
+
└── uninstall.sh # 심볼릭 링크 제거 스크립트
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 설치 가이드
|
|
123
|
+
|
|
124
|
+
### 빠른 설치 (권장)
|
|
125
|
+
|
|
126
|
+
프로젝트 루트 디렉토리에서 한 줄로 설치:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx bmad-setup
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
이 명령어는 다음을 자동으로 수행합니다:
|
|
133
|
+
|
|
134
|
+
1. `bmad-submodule` Git Submodule 추가 및 초기화
|
|
135
|
+
2. `.gitmodules`에 `ignore = dirty` 설정
|
|
136
|
+
3. `install.sh` 실행 (심볼릭 링크 생성)
|
|
137
|
+
4. `.gitignore`에 BMAD 항목 추가
|
|
138
|
+
5. `package.json`에 postinstall / bmad:install / bmad:uninstall 스크립트 추가
|
|
139
|
+
|
|
140
|
+
> 이미 설치된 항목은 자동으로 스킵됩니다 (멱등성 보장).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 수동 설치
|
|
145
|
+
|
|
146
|
+
아래는 수동으로 단계별 설치하는 방법입니다.
|
|
147
|
+
|
|
148
|
+
#### 1단계: Submodule 추가
|
|
149
|
+
|
|
150
|
+
프로젝트 루트 디렉토리에서 실행:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Submodule 추가
|
|
154
|
+
git submodule add https://github.com/OhSeungWan/bmad-submodule.git bmad-submodule
|
|
155
|
+
|
|
156
|
+
# Submodule 초기화 및 파일 다운로드
|
|
157
|
+
git submodule init
|
|
158
|
+
git submodule update
|
|
159
|
+
|
|
160
|
+
# dirty 상태 무시 설정 (아래 '설정 파일 설명' 참조)
|
|
161
|
+
git config -f .gitmodules submodule.bmad-submodule.ignore dirty
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### 2단계: 심볼릭 링크 생성
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
./bmad-submodule/install.sh
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
이 스크립트는 다음 심볼릭 링크를 생성합니다:
|
|
171
|
+
|
|
172
|
+
- `프로젝트/.claude/commands/bmad-*.md` → `bmad-submodule/.claude/commands/bmad-*.md`
|
|
173
|
+
- `프로젝트/.claude/commands/commit.md` → `bmad-submodule/.claude/commands/commit.md`
|
|
174
|
+
- `프로젝트/_bmad` → `bmad-submodule/_bmad`
|
|
175
|
+
|
|
176
|
+
#### 3단계: package.json 설정 (권장)
|
|
177
|
+
|
|
178
|
+
팀원들의 자동 설치를 위해 추가:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"scripts": {
|
|
183
|
+
"postinstall": "[ -z \"$CI\" ] && git submodule update --init --recursive && git -C bmad-submodule pull origin master && ./bmad-submodule/install.sh || true",
|
|
184
|
+
"bmad:install": "./bmad-submodule/install.sh",
|
|
185
|
+
"bmad:uninstall": "./bmad-submodule/uninstall.sh"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**각 스크립트 설명:**
|
|
191
|
+
|
|
192
|
+
| 스크립트 | 실행 시점 | 동작 |
|
|
193
|
+
| ---------------- | ---------------- | ------------------------------------- |
|
|
194
|
+
| `postinstall` | `npm install` 후 | Submodule 초기화 + 최신화 + 링크 생성 |
|
|
195
|
+
| `bmad:install` | 수동 실행 | 심볼릭 링크만 생성 |
|
|
196
|
+
| `bmad:uninstall` | 수동 실행 | 심볼릭 링크 제거 |
|
|
197
|
+
|
|
198
|
+
**postinstall 명령어 분석:**
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
[ -z "$CI" ] # CI 환경이 아닐 때만 실행
|
|
202
|
+
&& git submodule update --init --recursive # Submodule 초기화 및 업데이트
|
|
203
|
+
&& git -C bmad-submodule pull origin master # 최신 버전으로 업데이트
|
|
204
|
+
&& ./bmad-submodule/install.sh # 심볼릭 링크 생성
|
|
205
|
+
|| true # 실패해도 npm install은 계속 진행
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### 4단계: .gitignore 추가
|
|
209
|
+
|
|
210
|
+
루트 프로젝트의 `.gitignore`에 추가:
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
# BMAD 심볼릭 링크 (실제 파일은 submodule에 있음)
|
|
214
|
+
.claude/commands/bmad
|
|
215
|
+
_bmad
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 설정 파일 상세 설명
|
|
221
|
+
|
|
222
|
+
### .gitmodules
|
|
223
|
+
|
|
224
|
+
Submodule 정보가 저장되는 파일입니다. `git submodule add` 실행 시 자동 생성됩니다.
|
|
225
|
+
|
|
226
|
+
```ini
|
|
227
|
+
[submodule "bmad-submodule"]
|
|
228
|
+
path = bmad-submodule
|
|
229
|
+
url = https://github.com/OhSeungWan/bmad-submodule.git
|
|
230
|
+
ignore = dirty
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
| 항목 | 설명 |
|
|
234
|
+
| -------- | --------------------------------------------- |
|
|
235
|
+
| `path` | Submodule이 위치할 로컬 경로 |
|
|
236
|
+
| `url` | Submodule의 원격 저장소 URL |
|
|
237
|
+
| `ignore` | `dirty` = 내부 변경사항을 git status에서 무시 |
|
|
238
|
+
|
|
239
|
+
### ignore = dirty 설정
|
|
240
|
+
|
|
241
|
+
**왜 필요한가요?**
|
|
242
|
+
|
|
243
|
+
VSCode 등 에디터가 파일을 열면 자동으로:
|
|
244
|
+
|
|
245
|
+
- 줄 끝 공백 제거
|
|
246
|
+
- 파일 끝 빈 줄 추가
|
|
247
|
+
- 탭→스페이스 변환
|
|
248
|
+
|
|
249
|
+
이런 자동 변경으로 인해 `git status`에서 `bmad-submodule (modified content)`가 표시됩니다.
|
|
250
|
+
|
|
251
|
+
**해결 방법:**
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# dirty 상태 무시 설정
|
|
255
|
+
git config -f .gitmodules submodule.bmad-submodule.ignore dirty
|
|
256
|
+
|
|
257
|
+
# 이미 발생한 변경사항 되돌리기
|
|
258
|
+
git submodule foreach --recursive git checkout .
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Submodule과 함께 Clone
|
|
264
|
+
|
|
265
|
+
### 새 팀원이 프로젝트를 받을 때
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# 방법 1: 한 번에 (권장)
|
|
269
|
+
git clone --recurse-submodules <your-repo-url>
|
|
270
|
+
|
|
271
|
+
# 방법 2: clone 후 별도 초기화
|
|
272
|
+
git clone <your-repo-url>
|
|
273
|
+
cd <your-repo>
|
|
274
|
+
git submodule update --init --recursive
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**주의:** `--recurse-submodules` 없이 clone하면 `bmad-submodule` 폴더가 비어있습니다!
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Submodule 업데이트
|
|
282
|
+
|
|
283
|
+
BMAD에 새 기능이 추가되었을 때:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# 1. Submodule 디렉토리로 이동
|
|
287
|
+
cd bmad-submodule
|
|
288
|
+
|
|
289
|
+
# 2. 최신 버전 가져오기
|
|
290
|
+
git pull origin master
|
|
291
|
+
|
|
292
|
+
# 3. 심볼릭 링크 재생성 (새 파일이 추가된 경우)
|
|
293
|
+
./install.sh
|
|
294
|
+
|
|
295
|
+
# 4. 루트로 돌아가서 변경사항 커밋
|
|
296
|
+
cd ..
|
|
297
|
+
git add bmad-submodule
|
|
298
|
+
git commit -m "chore: update bmad-submodule"
|
|
299
|
+
git push
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 스크립트 상세 설명
|
|
305
|
+
|
|
306
|
+
### install.sh
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
./bmad-submodule/install.sh
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**동작:**
|
|
313
|
+
|
|
314
|
+
1. 기존 심볼릭 링크/폴더가 있으면 삭제
|
|
315
|
+
2. 루트 프로젝트에 `.claude/commands` 디렉토리 생성
|
|
316
|
+
3. 심볼릭 링크 생성:
|
|
317
|
+
- `.claude/commands/bmad` → submodule의 `.claude/commands/bmad`
|
|
318
|
+
- `_bmad` → submodule의 `_bmad`
|
|
319
|
+
|
|
320
|
+
**언제 실행하나요?**
|
|
321
|
+
|
|
322
|
+
- 최초 설치 시
|
|
323
|
+
- Submodule 업데이트 후 (새 파일이 추가된 경우)
|
|
324
|
+
- 심볼릭 링크가 깨진 경우
|
|
325
|
+
|
|
326
|
+
### uninstall.sh
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
./bmad-submodule/uninstall.sh
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**동작:**
|
|
333
|
+
|
|
334
|
+
1. 심볼릭 링크인 경우: 바로 삭제
|
|
335
|
+
2. 일반 디렉토리인 경우: 확인 후 삭제
|
|
336
|
+
|
|
337
|
+
**언제 실행하나요?**
|
|
338
|
+
|
|
339
|
+
- BMAD 사용을 중단할 때
|
|
340
|
+
- 심볼릭 링크 대신 직접 파일을 관리하고 싶을 때
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## 동작 확인
|
|
345
|
+
|
|
346
|
+
설치가 완료되면 BMAD 에이전트가 정상적으로 작동하는지 확인합니다.
|
|
347
|
+
|
|
348
|
+
### 1. Claude Code 실행
|
|
349
|
+
|
|
350
|
+
프로젝트 루트 디렉토리에서 Claude Code를 실행합니다:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
claude
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### 2. 슬래시 커맨드 확인
|
|
357
|
+
|
|
358
|
+
Claude Code 내에서 `/bmad-`를 입력하면 사용 가능한 커맨드 목록이 자동완성됩니다.
|
|
359
|
+
|
|
360
|
+
### 3. 에이전트 실행 테스트
|
|
361
|
+
|
|
362
|
+
예시로 Data Analyst 에이전트를 실행해봅니다:
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
/bmad-agent-dae-data-analyst
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**정상 실행 시 출력 예시:**
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
안녕하세요, 렌트리 개발팀님! 📊
|
|
372
|
+
|
|
373
|
+
저는 재만이에요 - 여러분의 데이터 분석 파트너입니다.
|
|
374
|
+
|
|
375
|
+
----
|
|
376
|
+
현재 서비스 컨텍스트
|
|
377
|
+
|
|
378
|
+
아직 서비스 정보가 설정되지 않았어요. [SC] 서비스 컨텍스트 설정을 통해
|
|
379
|
+
렌트리 서비스의 퍼널과 핵심 지표를 학습하면 더 정확한 분석을 도와드릴 수 있어요!
|
|
380
|
+
|
|
381
|
+
----
|
|
382
|
+
메뉴
|
|
383
|
+
|
|
384
|
+
| # | 명령어 | 설명 |
|
|
385
|
+
| --- | ------ | -------------------------------------- |
|
|
386
|
+
| 1 | [MH] | 메뉴 도움말 다시 표시 |
|
|
387
|
+
| 2 | [CH] | 에이전트와 자유롭게 대화하기 |
|
|
388
|
+
| 3 | [QA] | 빠른 데이터 분석 - 질문에 답하기 |
|
|
389
|
+
| 4 | [FA] | 퍼널 분석 - 전환율, 병목, 이탈 분석 |
|
|
390
|
+
| 5 | [ED] | 실험 설계 - A/B 테스트 계획 수립 |
|
|
391
|
+
| 6 | [ER] | 실험 결과 분석 - 테스트 결과 해석 |
|
|
392
|
+
| 7 | [IA] | 영향도 분석 - 기능 변경 영향 예측 |
|
|
393
|
+
| 8 | [RM] | 위험 모니터링 - 이상 징후 감지 |
|
|
394
|
+
| 9 | [SC] | 서비스 컨텍스트 설정 - 퍼널, 지표 학습 |
|
|
395
|
+
| 10 | [GR] | 리포트 생성 - 분석 결과 문서화 |
|
|
396
|
+
| 11 | [DA] | 에이전트 종료 |
|
|
397
|
+
|
|
398
|
+
----
|
|
399
|
+
번호나 명령어를 입력해주세요. 무엇을 도와드릴까요?
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
위와 같이 에이전트 메뉴가 표시되면 설치가 정상적으로 완료된 것입니다.
|
|
403
|
+
|
|
404
|
+
### 4. 다른 에이전트/워크플로우 테스트
|
|
405
|
+
|
|
406
|
+
모듈별로 다양한 에이전트와 워크플로우를 테스트해볼 수 있습니다:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# BMM (소프트웨어 개발)
|
|
410
|
+
/bmad-agent-bmm-dev # 개발자 에이전트
|
|
411
|
+
/bmad-agent-bmm-architect # 아키텍트 에이전트
|
|
412
|
+
|
|
413
|
+
# Core (핵심)
|
|
414
|
+
/bmad-agent-bmad-master # 마스터 에이전트
|
|
415
|
+
/bmad-brainstorming # 브레인스토밍
|
|
416
|
+
|
|
417
|
+
# DAE (데이터 분석)
|
|
418
|
+
/bmad-agent-dae-data-analyst # 데이터 분석가
|
|
419
|
+
/bmad-dae-data-analysis # 데이터 분석 워크플로우
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### 5. 설치 실패 시 체크리스트
|
|
423
|
+
|
|
424
|
+
에이전트가 실행되지 않으면 다음을 확인하세요:
|
|
425
|
+
|
|
426
|
+
| 확인 항목 | 명령어 |
|
|
427
|
+
| --------------------------- | ------------------------------ |
|
|
428
|
+
| Submodule이 초기화되었는가? | `ls bmad-submodule/` |
|
|
429
|
+
| 심볼릭 링크가 생성되었는가? | `ls -la .claude/commands/bmad` |
|
|
430
|
+
| _bmad 링크가 생성되었는가? | `ls -la _bmad` |
|
|
431
|
+
| install.sh를 실행했는가? | `./bmad-submodule/install.sh` |
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## 문제 해결
|
|
436
|
+
|
|
437
|
+
### "bmad-submodule 폴더가 비어있어요"
|
|
438
|
+
|
|
439
|
+
Submodule이 초기화되지 않은 상태입니다.
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
git submodule update --init --recursive
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### "git status에서 bmad-submodule (modified content)가 보여요"
|
|
446
|
+
|
|
447
|
+
에디터 자동 포맷팅 때문입니다.
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
# 설정으로 방지
|
|
451
|
+
git config -f .gitmodules submodule.bmad-submodule.ignore dirty
|
|
452
|
+
|
|
453
|
+
# 현재 변경사항 되돌리기
|
|
454
|
+
git submodule foreach --recursive git checkout .
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### "심볼릭 링크가 작동하지 않아요"
|
|
458
|
+
|
|
459
|
+
Windows에서는 관리자 권한이 필요할 수 있습니다.
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
# 심볼릭 링크 재생성
|
|
463
|
+
./bmad-submodule/install.sh
|
|
464
|
+
|
|
465
|
+
# 링크 확인
|
|
466
|
+
ls -la .claude/commands/bmad
|
|
467
|
+
ls -la _bmad
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Submodule 완전 재설치
|
|
471
|
+
|
|
472
|
+
문제가 지속되면 깨끗하게 다시 시작:
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
# 1. 변경사항 리셋
|
|
476
|
+
git reset HEAD -- .gitmodules bmad-submodule 2>/dev/null || true
|
|
477
|
+
git checkout HEAD -- .gitmodules 2>/dev/null || true
|
|
478
|
+
|
|
479
|
+
# 2. Submodule 완전 제거
|
|
480
|
+
git submodule deinit -f bmad-submodule 2>/dev/null || true
|
|
481
|
+
git rm -f bmad-submodule 2>/dev/null || true
|
|
482
|
+
rm -rf bmad-submodule
|
|
483
|
+
rm -rf .git/modules/bmad-submodule
|
|
484
|
+
|
|
485
|
+
# 3. .gitmodules 정리
|
|
486
|
+
git config -f .gitmodules --remove-section submodule.bmad-submodule 2>/dev/null || true
|
|
487
|
+
git add .gitmodules
|
|
488
|
+
|
|
489
|
+
# 4. 다시 추가
|
|
490
|
+
git submodule add https://github.com/OhSeungWan/bmad-submodule.git bmad-submodule
|
|
491
|
+
git config -f .gitmodules submodule.bmad-submodule.ignore dirty
|
|
492
|
+
|
|
493
|
+
# 5. 확인
|
|
494
|
+
ls -la bmad-submodule/
|
|
495
|
+
git submodule status
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
gitignore 에서 관련 폴더 제거 (특정 클로드 버전에서 gitignore 에 추가된 파일을 클로드가 인식 못할 수도 있음)
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## 자주 묻는 질문
|
|
503
|
+
|
|
504
|
+
### Q: Submodule 내부에서 직접 수정해도 되나요?
|
|
505
|
+
|
|
506
|
+
A: 가능하지만 권장하지 않습니다. 수정사항은 bmad-submodule 저장소에 별도로 커밋/푸시해야 합니다. 팀 프로젝트라면 원본 저장소에 PR을 보내세요.
|
|
507
|
+
|
|
508
|
+
### Q: 특정 버전의 BMAD를 고정하고 싶어요
|
|
509
|
+
|
|
510
|
+
A: Submodule은 특정 커밋을 가리키므로 기본적으로 버전이 고정됩니다. `git pull`을 하지 않으면 해당 버전이 유지됩니다.
|
|
511
|
+
|
|
512
|
+
### Q: CI/CD에서는 어떻게 하나요?
|
|
513
|
+
|
|
514
|
+
A: postinstall 스크립트에 `[ -z "$CI" ]` 조건이 있어 CI 환경에서는 스킵됩니다. CI에서 BMAD가 필요하다면 이 조건을 제거하세요.
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## [Changelog](./CHANGELOG.md)
|
|
519
|
+
|
|
520
|
+
## 라이선스
|
|
521
|
+
|
|
522
|
+
MIT License
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const VERSION = require('../package.json').version;
|
|
10
|
+
const REPO_URL = 'https://github.com/OhSeungWan/bmad-submodule.git';
|
|
11
|
+
const SUBMODULE_DIR = 'bmad-submodule';
|
|
12
|
+
|
|
13
|
+
const log = (icon, msg) => console.log(`${icon} ${msg}`);
|
|
14
|
+
const logStep = (n, msg) => log(`[${n}/6]`, msg);
|
|
15
|
+
|
|
16
|
+
function run(cmd, opts = {}) {
|
|
17
|
+
return execSync(cmd, { stdio: 'inherit', ...opts });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function runCapture(cmd) {
|
|
21
|
+
return execSync(cmd, { encoding: 'utf8' }).trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function runSafe(cmd, stepName) {
|
|
25
|
+
try {
|
|
26
|
+
run(cmd);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
throw new Error(`${stepName} 실패: ${e.message}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// --- --help / --version ---
|
|
33
|
+
function handleFlags() {
|
|
34
|
+
const args = process.argv.slice(2);
|
|
35
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
36
|
+
console.log(VERSION);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
40
|
+
console.log(`
|
|
41
|
+
bmad-setup v${VERSION}
|
|
42
|
+
|
|
43
|
+
BMAD Framework 서브모듈을 한 줄로 설치합니다.
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
npx bmad-setup 전체 설치 실행
|
|
47
|
+
npx bmad-setup --help 도움말 표시
|
|
48
|
+
npx bmad-setup --version 버전 표시
|
|
49
|
+
|
|
50
|
+
Steps:
|
|
51
|
+
1. git submodule add (bmad-submodule)
|
|
52
|
+
2. git submodule init & update
|
|
53
|
+
3. .gitmodules ignore=dirty 설정
|
|
54
|
+
4. install.sh 실행 (심볼릭 링크)
|
|
55
|
+
5. .gitignore 패치
|
|
56
|
+
6. package.json 스크립트 패치
|
|
57
|
+
`);
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- Step 0: Pre-validation ---
|
|
63
|
+
function validateGitRepo() {
|
|
64
|
+
try {
|
|
65
|
+
runCapture('git rev-parse --git-dir');
|
|
66
|
+
} catch (e) {
|
|
67
|
+
log('\u274c', 'Error: 현재 디렉토리는 git 저장소가 아닙니다.');
|
|
68
|
+
log('', '먼저 `git init` 을 실행하거나 git 프로젝트 루트에서 다시 시도하세요.');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Ensure we are at the git repo root
|
|
73
|
+
const toplevel = runCapture('git rev-parse --show-toplevel');
|
|
74
|
+
if (path.resolve(toplevel) !== path.resolve(process.cwd())) {
|
|
75
|
+
log('\u274c', 'Error: git 저장소의 루트 디렉토리에서 실행해주세요.');
|
|
76
|
+
log('', ` 현재 위치: ${process.cwd()}`);
|
|
77
|
+
log('', ` git root: ${toplevel}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- Step 1: Submodule 추가 ---
|
|
83
|
+
function addSubmodule() {
|
|
84
|
+
logStep(1, 'Submodule 추가');
|
|
85
|
+
if (fs.existsSync(SUBMODULE_DIR)) {
|
|
86
|
+
log(' \u2714', `${SUBMODULE_DIR}/ 이미 존재합니다. 스킵합니다.`);
|
|
87
|
+
return 'skipped';
|
|
88
|
+
}
|
|
89
|
+
runSafe(`git submodule add ${REPO_URL} ${SUBMODULE_DIR}`, 'Submodule 추가');
|
|
90
|
+
log(' \u2714', 'Submodule 추가 완료');
|
|
91
|
+
return 'done';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// --- Step 2: Submodule 초기화 ---
|
|
95
|
+
function initSubmodule() {
|
|
96
|
+
logStep(2, 'Submodule 초기화');
|
|
97
|
+
runSafe('git submodule init && git submodule update', 'Submodule 초기화');
|
|
98
|
+
log(' \u2714', '초기화 완료');
|
|
99
|
+
return 'done';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// --- Step 3: dirty ignore 설정 ---
|
|
103
|
+
function configureDirtyIgnore() {
|
|
104
|
+
logStep(3, 'dirty ignore 설정');
|
|
105
|
+
runSafe(
|
|
106
|
+
`git config -f .gitmodules submodule.${SUBMODULE_DIR}.ignore dirty`,
|
|
107
|
+
'dirty ignore 설정',
|
|
108
|
+
);
|
|
109
|
+
log(' \u2714', '.gitmodules ignore=dirty 설정 완료');
|
|
110
|
+
return 'done';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// --- Step 4: install.sh 실행 ---
|
|
114
|
+
function runInstallScript() {
|
|
115
|
+
logStep(4, 'install.sh 실행 (심볼릭 링크 생성)');
|
|
116
|
+
const scriptPath = `./${SUBMODULE_DIR}/install.sh`;
|
|
117
|
+
if (!fs.existsSync(scriptPath)) {
|
|
118
|
+
log(' \u26a0', `${scriptPath} 파일을 찾을 수 없습니다. 스킵합니다.`);
|
|
119
|
+
return 'skipped';
|
|
120
|
+
}
|
|
121
|
+
runSafe(`bash ${scriptPath}`, 'install.sh 실행');
|
|
122
|
+
log(' \u2714', '심볼릭 링크 생성 완료');
|
|
123
|
+
return 'done';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// --- Step 5: .gitignore 패치 ---
|
|
127
|
+
function patchGitignore() {
|
|
128
|
+
logStep(5, '.gitignore 패치');
|
|
129
|
+
|
|
130
|
+
const MARKER_START = '# BMAD symlinks (auto-generated)';
|
|
131
|
+
const MARKER_END = '# End BMAD';
|
|
132
|
+
const entries = ['_bmad', '.claude/commands/bmad-*'];
|
|
133
|
+
const gitignorePath = '.gitignore';
|
|
134
|
+
|
|
135
|
+
let content = '';
|
|
136
|
+
if (fs.existsSync(gitignorePath)) {
|
|
137
|
+
content = fs.readFileSync(gitignorePath, 'utf8');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check if BMAD section already exists
|
|
141
|
+
if (content.includes(MARKER_START)) {
|
|
142
|
+
log(' \u2714', '.gitignore에 BMAD 섹션이 이미 존재합니다. 스킵합니다.');
|
|
143
|
+
return 'skipped';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Check if individual entries already exist
|
|
147
|
+
const missing = entries.filter((e) => !content.split('\n').some((line) => line.trim() === e));
|
|
148
|
+
if (missing.length === 0) {
|
|
149
|
+
log(' \u2714', '.gitignore에 BMAD 항목이 이미 존재합니다. 스킵합니다.');
|
|
150
|
+
return 'skipped';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const section = ['', MARKER_START, ...entries, MARKER_END, ''].join('\n');
|
|
154
|
+
|
|
155
|
+
fs.writeFileSync(gitignorePath, content.trimEnd() + '\n' + section, 'utf8');
|
|
156
|
+
log(' \u2714', `.gitignore에 BMAD 항목 추가 완료`);
|
|
157
|
+
return 'done';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// --- Step 6: package.json 패치 ---
|
|
161
|
+
function patchPackageJson() {
|
|
162
|
+
logStep(6, 'package.json 패치');
|
|
163
|
+
|
|
164
|
+
const pkgPath = 'package.json';
|
|
165
|
+
if (!fs.existsSync(pkgPath)) {
|
|
166
|
+
log(' \u26a0', 'package.json이 없습니다. 이 단계를 스킵합니다.');
|
|
167
|
+
return 'skipped';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const raw = fs.readFileSync(pkgPath, 'utf8');
|
|
171
|
+
|
|
172
|
+
// Detect indent style from original file
|
|
173
|
+
const indentMatch = raw.match(/^(\s+)"/m);
|
|
174
|
+
const indent = indentMatch ? indentMatch[1] : ' ';
|
|
175
|
+
|
|
176
|
+
let pkg;
|
|
177
|
+
try {
|
|
178
|
+
pkg = JSON.parse(raw);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
log(' \u26a0', `package.json 파싱 실패: ${e.message}. 이 단계를 스킵합니다.`);
|
|
181
|
+
return 'skipped';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!pkg.scripts) {
|
|
185
|
+
pkg.scripts = {};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const scriptsToAdd = {
|
|
189
|
+
postinstall:
|
|
190
|
+
'[ -z "$CI" ] && git submodule update --init --recursive && git -C bmad-submodule pull origin master && ./bmad-submodule/install.sh || true',
|
|
191
|
+
'bmad:install': './bmad-submodule/install.sh',
|
|
192
|
+
'bmad:uninstall': './bmad-submodule/uninstall.sh',
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
let added = 0;
|
|
196
|
+
let warned = 0;
|
|
197
|
+
for (const [key, value] of Object.entries(scriptsToAdd)) {
|
|
198
|
+
if (pkg.scripts[key]) {
|
|
199
|
+
log(' \u26a0', `scripts.${key} 이미 존재합니다. 덮어쓰지 않습니다.`);
|
|
200
|
+
warned++;
|
|
201
|
+
} else {
|
|
202
|
+
pkg.scripts[key] = value;
|
|
203
|
+
added++;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (added > 0) {
|
|
208
|
+
const spaces = indent.length;
|
|
209
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, spaces) + '\n', 'utf8');
|
|
210
|
+
log(' \u2714', `package.json에 ${added}개 스크립트 추가 완료`);
|
|
211
|
+
}
|
|
212
|
+
if (warned > 0 && added === 0) {
|
|
213
|
+
log(' \u2714', '모든 스크립트가 이미 존재합니다. 스킵합니다.');
|
|
214
|
+
return 'skipped';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return added > 0 ? 'done' : 'skipped';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// --- Main ---
|
|
221
|
+
function main() {
|
|
222
|
+
handleFlags();
|
|
223
|
+
|
|
224
|
+
console.log('');
|
|
225
|
+
console.log('=== BMAD Submodule Setup ===');
|
|
226
|
+
console.log('');
|
|
227
|
+
|
|
228
|
+
validateGitRepo();
|
|
229
|
+
|
|
230
|
+
const steps = [
|
|
231
|
+
{ key: 'submodule', label: 'Submodule 추가', fn: addSubmodule },
|
|
232
|
+
{ key: 'init', label: 'Submodule 초기화', fn: initSubmodule },
|
|
233
|
+
{ key: 'dirtyIgnore', label: 'dirty ignore 설정', fn: configureDirtyIgnore },
|
|
234
|
+
{ key: 'installSh', label: 'install.sh 실행', fn: runInstallScript },
|
|
235
|
+
{ key: 'gitignore', label: '.gitignore 패치', fn: patchGitignore },
|
|
236
|
+
{ key: 'packageJson', label: 'package.json 패치', fn: patchPackageJson },
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
const results = {};
|
|
240
|
+
for (const step of steps) {
|
|
241
|
+
try {
|
|
242
|
+
results[step.key] = step.fn();
|
|
243
|
+
} catch (e) {
|
|
244
|
+
log(' \u274c', e.message);
|
|
245
|
+
results[step.key] = 'failed';
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log('');
|
|
250
|
+
console.log('=== Setup Summary ===');
|
|
251
|
+
console.log('');
|
|
252
|
+
|
|
253
|
+
for (const step of steps) {
|
|
254
|
+
const status = results[step.key];
|
|
255
|
+
const icon = status === 'done' ? '\u2714' : status === 'skipped' ? '\u2796' : '\u274c';
|
|
256
|
+
console.log(` ${icon} ${step.label}: ${status}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const hasFailed = Object.values(results).some((s) => s === 'failed');
|
|
260
|
+
console.log('');
|
|
261
|
+
if (hasFailed) {
|
|
262
|
+
log('\u26a0', '일부 단계가 실패했습니다. 위 로그를 확인하세요.');
|
|
263
|
+
process.exit(1);
|
|
264
|
+
} else {
|
|
265
|
+
log('\ud83d\ude80', 'BMAD 설치가 완료되었습니다!');
|
|
266
|
+
}
|
|
267
|
+
console.log('');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bmad-setup",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "BMAD Framework submodule installer - one command setup",
|
|
5
|
+
"bin": {
|
|
6
|
+
"bmad-setup": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=14"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"format": "prettier --write \"**/*.{md,yaml,yml}\"",
|
|
18
|
+
"format:check": "prettier --check \"**/*.{md,yaml,yml}\""
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/OhSeungWan/bmad-submodule.git"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"bmad",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"ai-agent",
|
|
28
|
+
"submodule"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"prettier": "^3.8.1"
|
|
33
|
+
}
|
|
34
|
+
}
|