@sleighmaster/bmad 1.5.5 → 1.5.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.
@@ -0,0 +1,439 @@
1
+ <workflow>
2
+ <critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
3
+ <critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
4
+ <critical>Communicate all responses in {communication_language}</critical>
5
+
6
+ <step n="1" goal="환경 확인">
7
+ <critical>🔧 PUBLIC RELEASE SETUP - Private → Public 릴리스 자동화 설정</critical>
8
+
9
+ <output>📋 **Public 릴리스 자동화 설정**
10
+
11
+ 이 워크플로우는 Private 저장소에서 태그 push 시 Public 저장소에
12
+ 자동으로 릴리스(바이너리 + 문서)를 배포하는 파이프라인을 설정합니다:
13
+
14
+ - Public 릴리스 저장소 생성
15
+ - GitHub Actions 워크플로우 생성 (release-to-public.yml)
16
+ - Secrets (PAT) 설정 가이드
17
+
18
+ </output>
19
+
20
+ <action>git repository 확인: git rev-parse --git-dir</action>
21
+ <check if="git repository NOT detected">
22
+ <output>⚠️ Git 저장소가 감지되지 않습니다. Git 저장소에서 실행해주세요.</output>
23
+ <action>HALT</action>
24
+ </check>
25
+
26
+ <action>gh CLI 확인: gh --version</action>
27
+ <check if="gh CLI not installed">
28
+ <output>⚠️ GitHub CLI(gh)가 설치되지 않았습니다.
29
+
30
+ 설치 방법:
31
+ - Windows: winget install GitHub.cli
32
+ - macOS: brew install gh
33
+ - Linux: https://github.com/cli/cli#installation
34
+
35
+ 설치 후 `gh auth login`으로 인증해주세요.
36
+ </output>
37
+ <action>HALT</action>
38
+ </check>
39
+
40
+ <action>gh CLI 인증 확인: gh auth status</action>
41
+ <check if="gh auth 실패">
42
+ <output>⚠️ GitHub CLI 인증이 필요합니다.</output>
43
+ <ask>`gh auth login`을 실행하시겠습니까? [y/n]</ask>
44
+ <check if="user confirms">
45
+ <action>gh auth login 안내 제공</action>
46
+ </check>
47
+ <check if="user cancels">
48
+ <action>HALT</action>
49
+ </check>
50
+ </check>
51
+
52
+ <action>.github/workflows 디렉토리 확인 (없으면 생성)</action>
53
+
54
+ <action>현재 저장소 정보 추출: gh repo view --json owner,name -q '.owner.login + "/" + .name'</action>
55
+ <action>{{private_owner}} = owner, {{private_repo}} = name</action>
56
+ <output>✅ 환경 확인 완료
57
+ - Private 저장소: {{private_owner}}/{{private_repo}}
58
+ </output>
59
+ </step>
60
+
61
+ <step n="2" goal="프로젝트 정보 수집">
62
+ <critical>📝 PROJECT INFO - 빌드 및 릴리스 정보 수집</critical>
63
+
64
+ <ask>Public 릴리스 저장소 이름을 입력해주세요 (예: {{private_repo}}-releases):</ask>
65
+ <action>{{public_repo_name}} = 사용자 입력값</action>
66
+
67
+ <ask>프로젝트 설명을 입력해주세요 (Public 저장소 description):</ask>
68
+ <action>{{project_description}} = 사용자 입력값</action>
69
+
70
+ <output>📋 **빌드 런타임 선택**
71
+
72
+ 프로젝트의 빌드 런타임을 선택해주세요:
73
+ 1. Node.js — npm ci / npm run build
74
+ 2. Go — go build
75
+ 3. Rust — cargo build --release
76
+ 4. .NET — dotnet publish
77
+ 5. Python — python -m build
78
+ 6. Java — ./gradlew build
79
+ 7. 커스텀 — 직접 설정
80
+ </output>
81
+
82
+ <ask>빌드 런타임을 선택해주세요: [1-7]</ask>
83
+
84
+ <check if="user chooses 1 (Node.js)">
85
+ <action>{{setup_action}} = "actions/setup-node@v4"</action>
86
+ <action>{{setup_with}} = "node-version: '20'"</action>
87
+ <action>{{install_cmd}} = "npm ci"</action>
88
+ <action>{{build_cmd}} = "npm run build"</action>
89
+ <action>{{artifact_path}} = "dist/"</action>
90
+ <action>{{runtime_label}} = "Node.js"</action>
91
+ </check>
92
+
93
+ <check if="user chooses 2 (Go)">
94
+ <action>{{setup_action}} = "actions/setup-go@v5"</action>
95
+ <action>{{setup_with}} = "go-version: 'stable'"</action>
96
+ <action>{{install_cmd}} = ""</action>
97
+ <action>{{build_cmd}} = "go build -o ./build/ ./..."</action>
98
+ <action>{{artifact_path}} = "build/"</action>
99
+ <action>{{runtime_label}} = "Go"</action>
100
+ </check>
101
+
102
+ <check if="user chooses 3 (Rust)">
103
+ <action>{{setup_action}} = "dtolnay/rust-toolchain@stable"</action>
104
+ <action>{{setup_with}} = ""</action>
105
+ <action>{{install_cmd}} = ""</action>
106
+ <action>{{build_cmd}} = "cargo build --release"</action>
107
+ <action>{{artifact_path}} = "target/release/"</action>
108
+ <action>{{runtime_label}} = "Rust"</action>
109
+ </check>
110
+
111
+ <check if="user chooses 4 (.NET)">
112
+ <action>{{setup_action}} = "actions/setup-dotnet@v4"</action>
113
+ <action>{{setup_with}} = "dotnet-version: '8.0.x'"</action>
114
+ <action>{{install_cmd}} = "dotnet restore"</action>
115
+ <action>{{build_cmd}} = "dotnet publish -c Release -o ./publish"</action>
116
+ <action>{{artifact_path}} = "publish/"</action>
117
+ <action>{{runtime_label}} = ".NET"</action>
118
+ </check>
119
+
120
+ <check if="user chooses 5 (Python)">
121
+ <action>{{setup_action}} = "actions/setup-python@v5"</action>
122
+ <action>{{setup_with}} = "python-version: '3.x'"</action>
123
+ <action>{{install_cmd}} = "pip install -r requirements.txt"</action>
124
+ <action>{{build_cmd}} = "python -m build"</action>
125
+ <action>{{artifact_path}} = "dist/"</action>
126
+ <action>{{runtime_label}} = "Python"</action>
127
+ </check>
128
+
129
+ <check if="user chooses 6 (Java)">
130
+ <action>{{setup_action}} = "actions/setup-java@v4"</action>
131
+ <action>{{setup_with}} = "distribution: 'temurin'\n java-version: '21'"</action>
132
+ <action>{{install_cmd}} = ""</action>
133
+ <action>{{build_cmd}} = "./gradlew build"</action>
134
+ <action>{{artifact_path}} = "build/libs/"</action>
135
+ <action>{{runtime_label}} = "Java"</action>
136
+ </check>
137
+
138
+ <check if="user chooses 7 (커스텀)">
139
+ <ask>런타임 setup action을 입력해주세요 (없으면 빈 값):</ask>
140
+ <action>{{setup_action}} = 사용자 입력값</action>
141
+ <check if="{{setup_action}} is not empty">
142
+ <ask>setup action의 with 매개변수를 입력해주세요 (없으면 빈 값):</ask>
143
+ <action>{{setup_with}} = 사용자 입력값</action>
144
+ </check>
145
+ <ask>의존성 설치 명령어를 입력해주세요 (없으면 빈 값):</ask>
146
+ <action>{{install_cmd}} = 사용자 입력값</action>
147
+ <ask>빌드 명령어를 입력해주세요:</ask>
148
+ <action>{{build_cmd}} = 사용자 입력값</action>
149
+ <ask>빌드 결과물 경로를 입력해주세요:</ask>
150
+ <action>{{artifact_path}} = 사용자 입력값</action>
151
+ <action>{{runtime_label}} = "커스텀"</action>
152
+ </check>
153
+
154
+ <output>ℹ️ 기본값이 설정되었습니다. 다음에서 세부 사항을 조정할 수 있습니다.</output>
155
+
156
+ <ask>빌드 명령어를 수정하시겠습니까? (현재: {{build_cmd}}) [y/n]</ask>
157
+ <check if="user confirms">
158
+ <ask>새 빌드 명령어를 입력해주세요:</ask>
159
+ <action>{{build_cmd}} = 사용자 입력값</action>
160
+ </check>
161
+
162
+ <ask>설치 명령어를 수정하시겠습니까? (현재: {{install_cmd}}) [y/n]</ask>
163
+ <check if="user confirms">
164
+ <ask>새 설치 명령어를 입력해주세요:</ask>
165
+ <action>{{install_cmd}} = 사용자 입력값</action>
166
+ </check>
167
+
168
+ <ask>빌드 결과물 경로를 수정하시겠습니까? (현재: {{artifact_path}}) [y/n]</ask>
169
+ <check if="user confirms">
170
+ <ask>새 결과물 경로를 입력해주세요:</ask>
171
+ <action>{{artifact_path}} = 사용자 입력값</action>
172
+ </check>
173
+
174
+ <ask>릴리스에 첨부할 파일 패턴을 입력해주세요 (예: dist/*.zip, dist/*.tar.gz 등, 여러 줄 가능):</ask>
175
+ <action>{{artifact_patterns}} = 사용자 입력값</action>
176
+
177
+ <ask>라이선스를 선택해주세요:
178
+ 1. MIT
179
+ 2. Apache-2.0
180
+ 3. GPL-3.0
181
+ 4. BSD-3-Clause
182
+ 5. 없음 (건너뛰기)
183
+ </ask>
184
+ <action>{{license_type}} = 사용자 선택값</action>
185
+
186
+ <output>📋 **수집된 정보 요약**
187
+
188
+ - Public 저장소: {{private_owner}}/{{public_repo_name}}
189
+ - 설명: {{project_description}}
190
+ - 런타임: {{runtime_label}}
191
+ - 빌드: {{build_cmd}}
192
+ - 설치: {{install_cmd}}
193
+ - 결과물 경로: {{artifact_path}}
194
+ - 릴리스 패턴: {{artifact_patterns}}
195
+ - 라이선스: {{license_type}}
196
+ </output>
197
+
198
+ <ask>위 정보가 맞습니까? [y/n]</ask>
199
+ <check if="user cancels">
200
+ <output>❌ 설정을 취소합니다. 다시 실행해주세요.</output>
201
+ <action>HALT</action>
202
+ </check>
203
+ </step>
204
+
205
+ <step n="3" goal="Public 저장소 생성">
206
+ <critical>🏗️ CREATE PUBLIC REPO - Public 릴리스 저장소 생성</critical>
207
+
208
+ <action>저장소 존재 확인: gh repo view {{private_owner}}/{{public_repo_name}} 2>/dev/null</action>
209
+
210
+ <check if="저장소 이미 존재">
211
+ <output>⚠️ {{private_owner}}/{{public_repo_name}} 저장소가 이미 존재합니다.</output>
212
+ <ask>기존 저장소를 사용하시겠습니까? [y/n]</ask>
213
+ <check if="user cancels">
214
+ <output>❌ 설정을 취소합니다.</output>
215
+ <action>HALT</action>
216
+ </check>
217
+ <output>ℹ️ 기존 저장소를 사용합니다.</output>
218
+ </check>
219
+
220
+ <check if="저장소 없음">
221
+ <action>gh repo create {{private_owner}}/{{public_repo_name}} --public --description "{{project_description}}"</action>
222
+ <output>✅ Public 저장소 생성됨: {{private_owner}}/{{public_repo_name}}</output>
223
+
224
+ <!-- 초기 파일 생성 및 Push -->
225
+ <action>임시 디렉토리 생성 및 이동</action>
226
+ <action>git clone https://github.com/{{private_owner}}/{{public_repo_name}}.git temp-public-repo</action>
227
+ <action>cd temp-public-repo</action>
228
+
229
+ <!-- README.md -->
230
+ <action>README.md 생성:
231
+ # {{public_repo_name}}
232
+
233
+ {{project_description}}
234
+
235
+ ## 설치
236
+
237
+ [릴리스 페이지](https://github.com/{{private_owner}}/{{public_repo_name}}/releases)에서
238
+ 최신 버전을 다운로드하세요.
239
+
240
+ ## 라이선스
241
+
242
+ {{license_type}} 라이선스에 따라 배포됩니다.
243
+ </action>
244
+
245
+ <!-- CHANGELOG.md -->
246
+ <action>CHANGELOG.md 생성:
247
+ # Changelog
248
+
249
+ 이 프로젝트의 주요 변경사항을 기록합니다.
250
+
251
+ 형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)를 따르며,
252
+ [Semantic Versioning](https://semver.org/lang/ko/)을 준수합니다.
253
+ </action>
254
+
255
+ <!-- LICENSE (선택된 경우) -->
256
+ <check if="{{license_type}} != 없음">
257
+ <action>LICENSE 파일 생성 (선택된 라이선스 유형에 맞는 전문)</action>
258
+ </check>
259
+
260
+ <action>git add -A</action>
261
+ <action>git commit -m "chore: 저장소 초기화
262
+
263
+ Generated by BMAD Method - Public Release Setup"</action>
264
+ <action>git push origin main</action>
265
+ <action>임시 디렉토리 정리 (cd .. && rm -rf temp-public-repo)</action>
266
+
267
+ <output>✅ 초기 파일 Push 완료:
268
+ - README.md
269
+ - CHANGELOG.md
270
+ {{license_file_note}}
271
+ </output>
272
+ </check>
273
+ </step>
274
+
275
+ <step n="4" goal="Actions 워크플로우 생성">
276
+ <critical>⚙️ ACTIONS WORKFLOW - release-to-public.yml 생성</critical>
277
+
278
+ <action>{{release_templates}}/release-to-public.yml 기본 템플릿 로드</action>
279
+
280
+ <action>플레이스홀더 교체:
281
+ - __PUBLIC_REPO__ → {{private_owner}}/{{public_repo_name}}
282
+ - __SETUP_ACTION__ → {{setup_action}} (비어있으면 해당 step 제거)
283
+ - __SETUP_WITH__ → {{setup_with}} (비어있으면 with 블록 제거)
284
+ - __INSTALL_CMD__ → {{install_cmd}} (비어있으면 해당 step 제거)
285
+ - __BUILD_CMD__ → {{build_cmd}}
286
+ - __ARTIFACT_PATH__ → {{artifact_path}}
287
+ - __ARTIFACT_PATTERNS__ → {{artifact_patterns}}
288
+ </action>
289
+
290
+ <check if="{{target_workflows_dir}}/release-to-public.yml 이미 존재">
291
+ <output>⚠️ release-to-public.yml이 이미 존재합니다.</output>
292
+ <ask>덮어쓰시겠습니까? [y/n]</ask>
293
+ <check if="user cancels">
294
+ <output>ℹ️ 기존 파일을 유지합니다.</output>
295
+ </check>
296
+ <check if="user confirms">
297
+ <action>기존 파일 백업: release-to-public.yml.backup</action>
298
+ <action>생성된 워크플로우를 {{target_workflows_dir}}/release-to-public.yml에 저장</action>
299
+ <output>✅ release-to-public.yml 덮어쓰기 완료 (백업 생성됨)</output>
300
+ </check>
301
+ </check>
302
+
303
+ <check if="{{target_workflows_dir}}/release-to-public.yml 없음">
304
+ <action>생성된 워크플로우를 {{target_workflows_dir}}/release-to-public.yml에 저장</action>
305
+ <output>✅ release-to-public.yml 생성 완료</output>
306
+ </check>
307
+
308
+ <output>📄 **생성된 워크플로우 요약**
309
+
310
+ 파일: .github/workflows/release-to-public.yml
311
+ 트리거: v* 태그 push
312
+ 동작:
313
+ 1. 소스 체크아웃
314
+ 2. {{runtime_label}} 런타임 설정
315
+ 3. 의존성 설치 및 빌드
316
+ 4. CHANGELOG에서 릴리스 노트 추출
317
+ 5. Public 저장소에 릴리스 생성 + 아티팩트 첨부
318
+ 6. Public 저장소에 CHANGELOG.md 동기화
319
+ </output>
320
+ </step>
321
+
322
+ <step n="5" goal="Secrets 설정">
323
+ <critical>🔑 SECRETS - GitHub Actions Secrets 설정</critical>
324
+
325
+ <output>📋 **Fine-grained Personal Access Token (PAT) 생성 가이드**
326
+
327
+ Public 저장소에 릴리스를 배포하려면 PAT가 필요합니다.
328
+
329
+ **생성 방법:**
330
+ 1. GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens
331
+ 2. "Generate new token" 클릭
332
+ 3. 설정:
333
+ - Token name: `public-release-{{public_repo_name}}`
334
+ - Expiration: 원하는 기간 (권장: 90일, 이후 갱신)
335
+ - Resource owner: {{private_owner}}
336
+ - Repository access: "Only select repositories" → **{{public_repo_name}}** 선택
337
+ - Permissions:
338
+ - Contents: Read and write
339
+ - Metadata: Read-only (자동 선택됨)
340
+ 4. "Generate token" 클릭 후 토큰 복사
341
+
342
+ ⚠️ 토큰은 한 번만 표시됩니다. 반드시 복사해두세요!
343
+ </output>
344
+
345
+ <ask>PAT를 생성하셨습니까? Secret을 설정할 준비가 되셨습니까? [y/n]</ask>
346
+
347
+ <check if="user confirms">
348
+ <output>ℹ️ 다음 명령어로 Secret을 설정합니다:
349
+ `gh secret set PUBLIC_REPO_TOKEN -R {{private_owner}}/{{private_repo}}`
350
+
351
+ 프롬프트에 복사한 PAT 토큰을 붙여넣어주세요.
352
+ </output>
353
+
354
+ <action>gh secret set PUBLIC_REPO_TOKEN -R {{private_owner}}/{{private_repo}}</action>
355
+
356
+ <check if="secret 설정 성공">
357
+ <output>✅ PUBLIC_REPO_TOKEN Secret 설정 완료</output>
358
+ </check>
359
+
360
+ <check if="secret 설정 실패">
361
+ <output>⚠️ Secret 설정에 실패했습니다.
362
+
363
+ 수동으로 설정하려면:
364
+ 1. GitHub → {{private_owner}}/{{private_repo}} → Settings → Secrets and variables → Actions
365
+ 2. "New repository secret" 클릭
366
+ 3. Name: PUBLIC_REPO_TOKEN
367
+ 4. Secret: 생성한 PAT 토큰
368
+ 5. "Add secret" 클릭
369
+ </output>
370
+ </check>
371
+ </check>
372
+
373
+ <check if="user cancels">
374
+ <output>ℹ️ Secret 설정을 건너뜁니다.
375
+
376
+ 나중에 설정하려면:
377
+ `gh secret set PUBLIC_REPO_TOKEN -R {{private_owner}}/{{private_repo}}`
378
+
379
+ 또는 GitHub 웹에서:
380
+ {{private_owner}}/{{private_repo}} → Settings → Secrets and variables → Actions
381
+ </output>
382
+ </check>
383
+ </step>
384
+
385
+ <step n="6" goal="완료 및 안내">
386
+ <output>🎉 **Public 릴리스 자동화 설정 완료!**
387
+
388
+ **설정된 항목:**
389
+ ✅ Public 저장소: {{private_owner}}/{{public_repo_name}}
390
+ ✅ Actions 워크플로우: .github/workflows/release-to-public.yml
391
+ ✅ Secret: PUBLIC_REPO_TOKEN
392
+
393
+ **릴리스 방법:**
394
+ 1. CHANGELOG.md에 새 버전 섹션 추가
395
+ 2. 태그 생성 및 Push:
396
+ ```
397
+ git tag v1.0.0
398
+ git push origin v1.0.0
399
+ ```
400
+ 3. GitHub Actions가 자동으로:
401
+ - 프로젝트 빌드
402
+ - CHANGELOG에서 릴리스 노트 추출
403
+ - Public 저장소에 릴리스 생성 + 아티팩트 첨부
404
+ - Public 저장소에 CHANGELOG.md 동기화
405
+
406
+ **확인:**
407
+ - Private Actions: https://github.com/{{private_owner}}/{{private_repo}}/actions
408
+ - Public Releases: https://github.com/{{private_owner}}/{{public_repo_name}}/releases
409
+
410
+ **주의사항:**
411
+ - PAT 토큰은 만료 기간이 있으므로 갱신이 필요합니다
412
+ - Private 저장소의 소스 코드는 Public에 노출되지 않습니다
413
+ - 릴리스에 첨부되는 아티팩트만 공개됩니다
414
+ </output>
415
+
416
+ <ask>변경사항(.github/workflows/release-to-public.yml)을 지금 커밋하시겠습니까? [y/n]</ask>
417
+
418
+ <check if="user confirms">
419
+ <action>git add .github/workflows/release-to-public.yml</action>
420
+ <action>git commit -m "ci: Public 릴리스 자동 배포 워크플로우 추가
421
+
422
+ - release-to-public.yml: v* 태그 push 시 Public 저장소에 릴리스 배포
423
+ - 빌드 → 아티팩트 첨부 → CHANGELOG 동기화
424
+
425
+ Generated by BMAD Method"</action>
426
+ <output>✅ 커밋 완료!
427
+
428
+ Push하려면: `git push origin {{current_branch}}`
429
+ </output>
430
+
431
+ <ask>지금 Push하시겠습니까? [y/n]</ask>
432
+ <check if="user confirms">
433
+ <action>git push origin {{current_branch}}</action>
434
+ <output>✅ Push 완료!</output>
435
+ </check>
436
+ </check>
437
+ </step>
438
+
439
+ </workflow>
@@ -0,0 +1,13 @@
1
+ name: public-release-setup
2
+ description: "Private 저장소에서 Public 릴리스 저장소로 자동 배포 설정"
3
+ author: "BMAD"
4
+
5
+ config_source: "{project-root}/_bmad/bmm/config.yaml"
6
+ installed_path: "{project-root}/_bmad/bmm/workflows/public-release-setup"
7
+ instructions: "{installed_path}/instructions.xml"
8
+ template: false
9
+ standalone: true
10
+
11
+ variables:
12
+ release_templates: "{project-root}/_bmad/bmm/data/public-release-templates"
13
+ target_workflows_dir: "{project-root}/.github/workflows"
@@ -58,4 +58,13 @@ if ! echo "$FIRST_LINE" | grep -qE "$PATTERN"; then
58
58
  exit 1
59
59
  fi
60
60
 
61
+ # 한글 권장 (description 부분) - 차단하지 않고 경고만 표시
62
+ DESC=$(echo "$FIRST_LINE" | sed 's/^[a-z]*([^)]*): //' | sed 's/^[a-z]*: //')
63
+ if ! echo "$DESC" | grep -P '[\xEA-\xED][\x80-\xBF][\x80-\xBF]' > /dev/null 2>&1; then
64
+ echo ""
65
+ echo "NOTE: 커밋 메시지 제목을 한글로 작성하는 것을 권장합니다."
66
+ echo " 예: feat(cli): Claude Code 보안 훅 추가"
67
+ echo ""
68
+ fi
69
+
61
70
  exit 0
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: 'public-release-setup'
3
+ description: 'Private 저장소에서 Public 릴리스 저장소로 자동 배포 설정'
4
+ ---
5
+
6
+ <steps CRITICAL="TRUE">
7
+ 1. Always LOAD the FULL @{project-root}/_bmad/core/tasks/workflow.xml
8
+ 2. READ its entire contents
9
+ 3. Pass the yaml path as 'workflow-config' parameter to workflow.xml: {project-root}/_bmad/bmm/workflows/public-release-setup/workflow.yaml
10
+ 4. Follow workflow.xml instructions EXACTLY as written
11
+ 5. Save outputs after EACH section
12
+ </steps>
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # BMad6GitHub - Claude Code PreToolUse Hook
3
+ # Block access to paths outside current working directory
4
+ # Outputs permissionDecision JSON for Claude Code hook system
5
+ INPUT=$(cat)
6
+
7
+ RESULT=$(py -c "
8
+ import json, sys, os, re
9
+
10
+ def normalize(p):
11
+ return os.path.normpath(p).replace(chr(92), '/').lower().rstrip('/')
12
+
13
+ def is_outside_cwd(path_str, cwd):
14
+ if not path_str or not cwd:
15
+ return False
16
+ n = normalize(path_str)
17
+ c = normalize(cwd)
18
+ if n.startswith('..'):
19
+ return True
20
+ if os.path.isabs(path_str):
21
+ return not n.startswith(c)
22
+ return False
23
+
24
+ try:
25
+ data = json.load(sys.stdin)
26
+ tool = data.get('tool_name', '')
27
+ ti = data.get('tool_input', {})
28
+ cwd = data.get('cwd', '')
29
+ if not cwd:
30
+ sys.exit(0)
31
+
32
+ if tool in ('Read', 'Edit', 'Write', 'Glob', 'Grep'):
33
+ for key in ['file_path', 'path']:
34
+ v = ti.get(key, '')
35
+ if v and is_outside_cwd(v, cwd):
36
+ print('BLOCK')
37
+ sys.exit(0)
38
+
39
+ if tool == 'Bash':
40
+ cmd = ti.get('command', '')
41
+ if not cmd:
42
+ sys.exit(0)
43
+ if '..' in cmd:
44
+ print('BLOCK')
45
+ sys.exit(0)
46
+ if '~/' in cmd or '\$HOME' in cmd or '%USERPROFILE%' in cmd:
47
+ print('BLOCK')
48
+ sys.exit(0)
49
+ abs_paths = re.findall(r'(?:/[a-zA-Z][a-zA-Z0-9_/.\-]+|[A-Za-z]:[/\\\\][^\s\"\x27;|&>]+)', cmd)
50
+ for p in abs_paths:
51
+ if is_outside_cwd(p, cwd):
52
+ print('BLOCK')
53
+ sys.exit(0)
54
+ except:
55
+ pass
56
+ " <<< "$INPUT" 2>/dev/null)
57
+
58
+ if [ "$RESULT" = "BLOCK" ]; then
59
+ echo '{"permissionDecision":"ask","reason":"WARNING: 현재 작업 디렉토리 외부 경로가 감지되었습니다"}'
60
+ exit 0
61
+ fi
62
+
63
+ exit 0
package/dist/cli.js CHANGED
@@ -37,7 +37,9 @@ program
37
37
  .option('-f, --force', 'Overwrite existing _bmad folder')
38
38
  .option('--skip-github', 'Skip .github templates installation')
39
39
  .option('--skip-hooks', 'Skip Git hooks installation')
40
+ .option('--skip-claude-hooks', 'Skip Claude Code hooks installation')
40
41
  .option('--skip-repo-setup', 'Skip GitHub repository settings')
42
+ .option('--merge-strategy <strategy>', 'Merge strategy: squash-and-merge, merge-only, squash-only')
41
43
  .option('-y, --yes', 'Accept all defaults (non-interactive mode)')
42
44
  .action(async (options) => {
43
45
  await install(options);
@@ -49,7 +51,9 @@ program
49
51
  .option('--dry-run', 'Show what would be updated without making changes')
50
52
  .option('--skip-github', 'Skip .github templates update')
51
53
  .option('--skip-hooks', 'Skip Git hooks update')
54
+ .option('--skip-claude-hooks', 'Skip Claude Code hooks update')
52
55
  .option('--skip-repo-setup', 'Skip GitHub repository settings')
56
+ .option('--merge-strategy <strategy>', 'Merge strategy: squash-and-merge, merge-only, squash-only')
53
57
  .option('-y, --yes', 'Accept all defaults (non-interactive mode)')
54
58
  .action(async (options) => {
55
59
  await update(options);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,12 @@
1
+ import type { MergeStrategy } from '../services/installer.js';
1
2
  export interface InstallOptions {
2
3
  version?: string;
3
4
  force?: boolean;
4
5
  skipGithub?: boolean;
5
6
  skipHooks?: boolean;
7
+ skipClaudeHooks?: boolean;
6
8
  skipRepoSetup?: boolean;
9
+ mergeStrategy?: MergeStrategy;
7
10
  yes?: boolean;
8
11
  }
9
12
  export declare function install(options: InstallOptions): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAkLpE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAiB9D,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA+MpE"}