@sleighmaster/bmad 1.5.6 → 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,99 @@
1
+ # Release to Public Repository
2
+ # Private 저장소에서 v* 태그 push 시 Public 저장소에 릴리스 생성
3
+ #
4
+ # 필요 Secrets:
5
+ # PUBLIC_REPO_TOKEN - Public 저장소에 대한 Fine-grained PAT
6
+ # (Contents: Read and write)
7
+ #
8
+ # Generated by BMAD Method - Public Release Setup
9
+
10
+ name: Release to Public
11
+
12
+ on:
13
+ push:
14
+ tags:
15
+ - 'v*'
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ release-to-public:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Checkout source
25
+ uses: actions/checkout@v4
26
+ with:
27
+ fetch-depth: 0
28
+
29
+ - name: Setup runtime
30
+ uses: __SETUP_ACTION__
31
+ with:
32
+ __SETUP_WITH__
33
+
34
+ - name: Install dependencies
35
+ run: __INSTALL_CMD__
36
+
37
+ - name: Build
38
+ run: __BUILD_CMD__
39
+
40
+ - name: Extract version from tag
41
+ id: version
42
+ run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
43
+
44
+ - name: Extract changelog for current version
45
+ id: changelog
46
+ run: |
47
+ # CHANGELOG.md에서 현재 버전 섹션 추출
48
+ VERSION="${{ steps.version.outputs.version }}"
49
+ NOTES=$(awk -v ver="$VERSION" '
50
+ /^## \[/ {
51
+ if (found) exit
52
+ if (index($0, ver)) found=1
53
+ next
54
+ }
55
+ found { print }
56
+ ' CHANGELOG.md)
57
+
58
+ if [ -z "$NOTES" ]; then
59
+ NOTES="Release ${GITHUB_REF_NAME}"
60
+ fi
61
+
62
+ # multiline output
63
+ {
64
+ echo "notes<<EOF"
65
+ echo "$NOTES"
66
+ echo "EOF"
67
+ } >> "$GITHUB_OUTPUT"
68
+
69
+ - name: Create release on public repo
70
+ uses: softprops/action-gh-release@v2
71
+ with:
72
+ repository: __PUBLIC_REPO__
73
+ token: ${{ secrets.PUBLIC_REPO_TOKEN }}
74
+ tag_name: ${{ github.ref_name }}
75
+ name: ${{ github.ref_name }}
76
+ body: ${{ steps.changelog.outputs.notes }}
77
+ files: |
78
+ __ARTIFACT_PATTERNS__
79
+
80
+ - name: Sync CHANGELOG to public repo
81
+ env:
82
+ GH_TOKEN: ${{ secrets.PUBLIC_REPO_TOKEN }}
83
+ run: |
84
+ git clone "https://x-access-token:${GH_TOKEN}@github.com/__PUBLIC_REPO__.git" _public_repo
85
+ cp CHANGELOG.md _public_repo/CHANGELOG.md
86
+ cd _public_repo
87
+
88
+ git config user.name "github-actions[bot]"
89
+ git config user.email "github-actions[bot]@users.noreply.github.com"
90
+
91
+ # 변경사항이 있을 때만 커밋
92
+ if git diff --quiet CHANGELOG.md; then
93
+ echo "CHANGELOG.md is already up to date"
94
+ else
95
+ git add CHANGELOG.md
96
+ git commit -m "docs: CHANGELOG.md 동기화 (${{ github.ref_name }})"
97
+ git push origin main
98
+ echo "CHANGELOG.md synced successfully"
99
+ fi
@@ -167,6 +167,8 @@
167
167
 
168
168
  <check if="user chooses 1 (squash-and-merge)">
169
169
  <action>gh repo edit --enable-squash-merge --enable-merge-commit --enable-rebase-merge=false --delete-branch-on-merge</action>
170
+ <action>config.yaml에 merge_strategy 저장: _bmad/bmm/config.yaml의 merge_strategy 필드를 squash-and-merge로 업데이트</action>
171
+ <action>CLAUDE.md 머지 명령 업데이트: CLAUDE.md에서 `gh pr merge` 명령을 찾아 `--squash` 플래그로 교체, 단계명 "Squash Merge"</action>
170
172
  <output>✅ 저장소 머지 규칙 설정 완료:
171
173
  - Squash Merge: 허용
172
174
  - Merge Commit: 허용
@@ -176,6 +178,8 @@
176
178
 
177
179
  <check if="user chooses 2 (merge-only)">
178
180
  <action>gh repo edit --enable-merge-commit --enable-squash-merge=false --enable-rebase-merge=false --delete-branch-on-merge</action>
181
+ <action>config.yaml에 merge_strategy 저장: _bmad/bmm/config.yaml의 merge_strategy 필드를 merge-only로 업데이트</action>
182
+ <action>CLAUDE.md 머지 명령 업데이트: CLAUDE.md에서 `gh pr merge` 명령을 찾아 `--merge` 플래그로 교체, 단계명 "Merge"</action>
179
183
  <output>✅ 저장소 머지 규칙 설정 완료:
180
184
  - Merge Commit: 허용
181
185
  - Squash Merge: 비활성화
@@ -185,6 +189,8 @@
185
189
 
186
190
  <check if="user chooses 3 (squash-only)">
187
191
  <action>gh repo edit --enable-squash-merge --enable-merge-commit=false --enable-rebase-merge=false --delete-branch-on-merge</action>
192
+ <action>config.yaml에 merge_strategy 저장: _bmad/bmm/config.yaml의 merge_strategy 필드를 squash-only로 업데이트</action>
193
+ <action>CLAUDE.md 머지 명령 업데이트: CLAUDE.md에서 `gh pr merge` 명령을 찾아 `--squash` 플래그로 교체, 단계명 "Squash Merge"</action>
188
194
  <output>✅ 저장소 머지 규칙 설정 완료:
189
195
  - Squash Merge: 허용
190
196
  - Merge Commit: 비활성화
@@ -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