diff --git a/.agents/skills/git-commit/SKILL.md b/.agents/skills/git-commit/SKILL.md index 3c5d6d3..377dc36 100644 --- a/.agents/skills/git-commit/SKILL.md +++ b/.agents/skills/git-commit/SKILL.md @@ -63,6 +63,8 @@ Commit when the user asks for it. Finishing a piece of work is not itself a requ - Unrelated changes → separate commits 3. For each logical group: - Stage the relevant files **by name**: `git add ...` + - Never stage planning documents — `*.spec.md`, `plan*.md`, `계획*.md`. They are working notes from + the planning skill, not part of the change. If one is already staged, unstage it. - Never `git add -A` or `git add .` — they sweep in whatever else is in the tree, which is how an unrelated file or a secret ends up in someone's commit. Leave the rest unstaged and tell the user what you skipped. diff --git a/.agents/skills/planning/SKILL.md b/.agents/skills/planning/SKILL.md index fcce153..eb40c7d 100644 --- a/.agents/skills/planning/SKILL.md +++ b/.agents/skills/planning/SKILL.md @@ -32,7 +32,8 @@ Cite `file:line` for every claim you rely on. ## Step 3 — Write the Spec -Write it to `.spec.md` and tell me the path. It exists to survive the conversation, so record +Write it to `.spec.md` and tell me the path. The spec is a working document: never stage, +commit, or push it, and keep it out of every PR. It exists to survive the conversation, so record the reasoning and not just the conclusion: - **Goal** — what changes for the user, and what is explicitly out of scope diff --git a/.agents/skills/write-pr/SKILL.md b/.agents/skills/write-pr/SKILL.md index cd961ea..3ea5adb 100644 --- a/.agents/skills/write-pr/SKILL.md +++ b/.agents/skills/write-pr/SKILL.md @@ -27,6 +27,9 @@ git diff "origin/$BASE...HEAD" cat .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null ``` +If the diff adds a planning document (`*.spec.md`, `plan*.md`, `계획*.md`), remove it from the branch with a +`git rm --cached` commit before creating the PR, and keep the local file. Planning documents never go into a PR. + ## Step 3 — Learn This Project's Scope Vocabulary Read `.agents/shared/commit-conventions.md` — it holds the commands for reading the repo's existing @@ -48,7 +51,7 @@ matches, attach none — a wrong label is worse than no label, and an undefined **Title** — Generate 3 options in the format `[scope] description`: -- Scope: from Step 3. Lowercase, in brackets — `[member]`, `[expo]`, `[global]` +- Scope: from Step 3. Lowercase, in brackets — `[member]`, `[expo]`, `[global]`. One scope only; a PR spanning several scopes uses `[global]`, never a comma-separated list - Description: Korean, concise, no emojis, max 50 characters total - Wrap class names, method names, annotations, file names, and technical terms in backticks (e.g., `@Transactional`, `MemberService`, `SKILL.md`) diff --git a/.claude/skills/git-commit/SKILL.md b/.claude/skills/git-commit/SKILL.md index c7ca4e0..bb8af72 100644 --- a/.claude/skills/git-commit/SKILL.md +++ b/.claude/skills/git-commit/SKILL.md @@ -63,6 +63,8 @@ Commit when the user asks for it. Finishing a piece of work is not itself a requ - Unrelated changes → separate commits 3. For each logical group: - Stage the relevant files **by name**: `git add ...` + - Never stage planning documents — `*.spec.md`, `plan*.md`, `계획*.md`. They are working notes from + the planning skill, not part of the change. If one is already staged, unstage it. - Never `git add -A` or `git add .` — they sweep in whatever else is in the tree, which is how an unrelated file or a secret ends up in someone's commit. Leave the rest unstaged and tell the user what you skipped. diff --git a/.claude/skills/planning/SKILL.md b/.claude/skills/planning/SKILL.md index 2824884..40a21c1 100644 --- a/.claude/skills/planning/SKILL.md +++ b/.claude/skills/planning/SKILL.md @@ -36,7 +36,8 @@ isn't available, do the same three passes yourself, one after another. ## Step 3 — Write the Spec -Write it to `.spec.md` and tell me the path. It exists to survive the conversation, so record +Write it to `.spec.md` and tell me the path. The spec is a working document: never stage, +commit, or push it, and keep it out of every PR. It exists to survive the conversation, so record the reasoning and not just the conclusion: - **Goal** — what changes for the user, and what is explicitly out of scope diff --git a/.claude/skills/write-pr/SKILL.md b/.claude/skills/write-pr/SKILL.md index b03c78b..4985537 100644 --- a/.claude/skills/write-pr/SKILL.md +++ b/.claude/skills/write-pr/SKILL.md @@ -27,6 +27,9 @@ git diff "origin/$BASE...HEAD" cat .github/PULL_REQUEST_TEMPLATE.md 2>/dev/null ``` +If the diff adds a planning document (`*.spec.md`, `plan*.md`, `계획*.md`), remove it from the branch with a +`git rm --cached` commit before creating the PR, and keep the local file. Planning documents never go into a PR. + ## Step 3 — Learn This Project's Scope Vocabulary Read `.claude/shared/commit-conventions.md` — it holds the commands for reading the repo's existing @@ -48,7 +51,7 @@ matches, attach none — a wrong label is worse than no label, and an undefined **Title** — Generate 3 options in the format `[scope] description`: -- Scope: from Step 3. Lowercase, in brackets — `[member]`, `[expo]`, `[global]` +- Scope: from Step 3. Lowercase, in brackets — `[member]`, `[expo]`, `[global]`. One scope only; a PR spanning several scopes uses `[global]`, never a comma-separated list - Description: Korean, concise, no emojis, max 50 characters total - Wrap class names, method names, annotations, file names, and technical terms in backticks (e.g., `@Transactional`, `MemberService`, `SKILL.md`) diff --git a/.github/workflows/rush-ci.yml b/.github/workflows/rush-ci.yml index 4009d8f..5d06810 100644 --- a/.github/workflows/rush-ci.yml +++ b/.github/workflows/rush-ci.yml @@ -54,10 +54,13 @@ jobs: return; } - const invalidScopes = scopesPart.split(',').map(s => s.trim()) - .filter(scope => !allowedScopes.includes(scope)); - if (invalidScopes.length > 0) { - core.setFailed(`Invalid scope(s): ${invalidScopes.join(', ')}`); + if (scopesPart.includes(',')) { + core.setFailed('Use a single scope. For changes spanning several scopes, use [global]'); + return; + } + + if (!allowedScopes.includes(scopesPart.trim())) { + core.setFailed(`Invalid scope: ${scopesPart}`); } setup-pr-metadata: diff --git a/.github/workflows/rush-push-notify.yml b/.github/workflows/rush-push-notify.yml new file mode 100644 index 0000000..6c72e15 --- /dev/null +++ b/.github/workflows/rush-push-notify.yml @@ -0,0 +1,24 @@ +name: Push Notification + +# 저장소 웹훅은 force push를 걸러낼 수 없어 push 이벤트를 받지 않습니다. +# 대신 이 워크플로가 일반 push만 같은 Discord 채널로 전달합니다. +on: + push: + +permissions: {} + +jobs: + notify: + name: Forward Push to Discord + if: ${{ !github.event.forced }} + runs-on: ubuntu-latest + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_GITHUB_WEBHOOK }} + steps: + - name: Send Push Event + if: env.DISCORD_WEBHOOK != '' + run: | + curl -fsS -X POST "$DISCORD_WEBHOOK" \ + -H "Content-Type: application/json" \ + -H "X-GitHub-Event: push" \ + --data-binary @"$GITHUB_EVENT_PATH" diff --git a/AGENTS.md b/AGENTS.md index b612178..eb1c2c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,7 +58,7 @@ These are the same commands CI (`.github/workflows/rush-ci.yml`) runs. Make them ## Pull Requests - Every PR except a release PR targets `develop`. -- Titles use the `[scope] title` format. Pick scopes from `global`, `gateway`, `config`, `eureka`, `auth`, `shop`, `minigame`, `stage`, `user`, `sp`, `live`, `chat`, `ci/cd`, separating multiple scopes with commas. Do not use a colon (`:`) in the title. +- Titles use the `[scope] title` format. Pick scopes from `global`, `gateway`, `config`, `eureka`, `auth`, `shop`, `minigame`, `stage`, `user`, `sp`, `live`, `chat`, `ci/cd`. When a PR spans more than one scope, use `[global]` instead of listing them. Do not use a colon (`:`) in the title. - Bodies use the 개요 and 본문 sections of `.github/PULL_REQUEST_TEMPLATE.md` and stay short: - 개요: one sentence on what changes. - 본문: up to five one-line bullets on what changed. Add a merge-order or follow-up note only when one exists.