Skip to content

[Chore] AI 에이전트 설정 보완#3

Merged
leemanjae02 merged 11 commits into
mainfrom
chore/init-agent-setup-1
Jun 30, 2026
Merged

[Chore] AI 에이전트 설정 보완#3
leemanjae02 merged 11 commits into
mainfrom
chore/init-agent-setup-1

Conversation

@KyeongJooni

@KyeongJooni KyeongJooni commented Jun 30, 2026

Copy link
Copy Markdown
Member

#️⃣연관된 이슈

🚧 Work in Progress

  • 작업 진행 중

📌 주요 변경사항

  • AI 작업 지침과 실행 표면 정비
  • GitHub 협업 자동화와 CI 검증 흐름 구성
  • 생성 파일 관리와 개발 검증 설정 추가
  • 초기 앱 구조와 문서 정리

📝작업 내용

  • AI 작업 흐름 정리: CLAUDE.md를 Claude의 메인 진입점으로 두고, AGENTS.md는 Codex가 CLAUDE.md.claude/manifest.md를 참조하는 프록시 역할로 정리
  • AI 지침 로딩 기준 추가: .claude/manifest.md에서 기본 rules와 작업별 reference/API/domain 문서를 나눠 읽도록 구성해 불필요한 토큰 사용과 임의 구조 생성을 줄임
  • AI 실행 표면 구성: Claude skill 원본과 Codex proxy skill을 분리해 /create-pr, /scaffold-api, /figma-to-component, /gen-test, /code-review 같은 반복 작업을 프로젝트 규칙에 맞게 실행하도록 구성
  • AI 안전장치 추가: hooks에서 console.log, 명시적 any, npm/yarn, Tailwind v3 설정 생성 같은 프로젝트 금지 패턴을 차단하도록 구성
  • 어드민 API 기준 추가: Swagger 기반 admin API reference와 도메인 reference를 추가해 endpoint, request/response, 구현 위치를 추측하지 않도록 구성
  • GitHub 협업 자동화 구성: 이슈 생성 시 브랜치 자동 생성, PR 메타데이터 동기화, WIP 체크박스 기반 제목 처리, 라벨/assignee 자동화를 추가
  • 생성 파일 관리 체계 추가: SVG 아이콘 컴포넌트 생성과 components/hooks barrel index 생성을 스크립트화하고 CI의 Generated 항목에서 동기화 여부를 확인하도록 구성
  • 개발 검증과 리뷰 자동화 정비: TypeScript, Prettier, ESLint, Test, Build 결과를 CI 댓글로 요약하고 CodeRabbit은 초기 개발 단계에 맞게 낮은 강도로 설정
  • 검증: pnpm format:check, pnpm gen:index:check, pnpm icons:check, pnpm type-check, pnpm lint, git diff --check 통과

📸 스크린샷 (선택)

💬리뷰 요구사항(선택)

  • GitHub Actions는 로컬에서 실행할 수 없어 PR 생성 후 실제 workflow 동작과 PR 댓글 출력 확인 필요

Summary by CodeRabbit

  • New Features
    • 이슈/PR 템플릿과 PR 본문 기반 브랜치·제목·라벨 자동 정규화를 추가했습니다.
    • CI 결과 요약 코멘트 및 생성/동기화 스크립트(아이콘, 컴포넌트/훅 인덱스)를 제공합니다.
    • 코드리뷰·테스트 생성·API 스캐폴딩을 돕는 자동화 규칙/스킬을 확장했습니다.
  • Documentation
    • 프로젝트 개발/아키텍처/코드 품질·스타일/검증·워크플로우 규칙과 관리자 API·도메인 레퍼런스를 정리했습니다.
  • Chores
    • 린트/포맷 체크, ESLint 설정, pre-commit, 생성물/훅 가드 적용을 강화했습니다.

@KyeongJooni KyeongJooni changed the title Chore/init agent setup 1 [Chore] AI 설정 보완 Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Claude/Codex AI 에이전트용 규칙·스킬·훅·API 레퍼런스 체계를 새로 만들고, 이슈 기반 브랜치 자동 생성·PR 정규화·CI 워크플로우를 추가했다. 저장소 툴링으로는 아이콘/인덱스 생성 스크립트, husky pre-commit, tsconfig/vite/ESLint 설정, src 스캐폴딩과 문서 갱신이 포함됐다.

Changes

AI 에이전트 규칙·스킬·훅 체계

Layer / File(s) Summary
에이전트 진입점 및 결정 기록
CLAUDE.md, AGENTS.md, .claude/manifest.md, .claude/decisions/*
CLAUDE.md·AGENTS.md를 프로젝트용 지침으로 재작성하고, .claude/manifest.md에서 로드 규칙·금지 패턴을 정의한다. decision 기록 규칙과 템플릿도 추가된다.
에이전트 코딩 규칙 문서
.claude/rules/*, .claude/references/api/*, .claude/references/domain/*, .claude/references/component-patterns.md
아키텍처·스타일·데이터 패칭·테스팅·검증·워크플로우 규칙과 어드민 API/도메인/컴포넌트 레퍼런스 문서를 추가한다.
에이전트 훅 스크립트 및 설정
.claude/hooks/*.ps1, .claude/settings.json, .codex/hooks.json
입력 가드, ESLint 실행, 스킬 추천 훅을 구현하고 Claude/Codex 훅 설정에 연결한다.
Claude 스킬 정의 및 Codex 프록시
.claude/skills/*/SKILL.md, .codex/skills/*/SKILL.md
scaffold-api·gen-test·code-review·commit-kr·create-pr·figma-to-component·refactor 스킬과 프록시 파일을 추가한다.

GitHub 워크플로우 자동화

Layer / File(s) Summary
이슈·PR 템플릿 재구성
.github/ISSUE_TEMPLATE/*, .github/PULL_REQUEST_TEMPLATE.md
기능 추가 템플릿을 제거하고 YAML 기반 이슈 폼을 추가하며, PR 템플릿을 이슈 연결·WIP·주요 변경사항 중심으로 재구성한다.
이슈 기반 브랜치 자동 생성
.github/workflows/auto-create-branch.yml
이슈 본문에서 브랜치명·타입을 추출해 브랜치를 생성하고, 이슈 제목·라벨 갱신 후 핸드오프 코멘트를 작성한다.
PR 메타데이터 정규화 및 CI
.github/workflows/pr-auto-setup.yml, .github/workflows/ci.yml, .coderabbit.yaml
PR 오픈/수정 시 WIP·제목·assignee·라벨을 자동 처리하고, 체크 결과를 PR 코멘트로 남기는 CI와 리뷰 설정을 추가한다.

프로젝트 툴링 및 스캐폴딩

Layer / File(s) Summary
빌드 도구 설정 갱신
tsconfig.app.json, tsconfig.node.json, tsconfig.json, vite.config.ts, eslint.config.js
TS 경로 별칭을 재구성하고, vite에 @lib 별칭을 추가하며, ESLint 무시 범위와 규칙을 갱신한다.
패키지 스크립트·의존성 및 pre-commit 훅
package.json, .husky/pre-commit, .prettierignore, .gitignore
prepare·type-check·gen:index·icons 스크립트와 SVGR·husky·lint-staged를 추가하고, pre-commit에 pnpm lint-staged를 등록한다.
아이콘 빌드 및 배럴 인덱스 생성 스크립트
scripts/build-icons.ts, scripts/gen-index.ts
SVG를 SVGR로 변환해 @generated 컴포넌트와 index.ts를 생성하고, src/components·src/hooks의 배럴 인덱스를 자동 생성하는 스크립트를 추가한다.
src 디렉터리 스캐폴딩 및 코드 포맷 정리
src/api/.gitkeep, src/components/*, src/hooks/*, src/pages/.gitkeep, src/assets/icons/..., src/App.tsx, src/App.css, src/index.css, src/lib/utils.ts
빈 디렉터리를 추적하고, components/index.ts·hooks/index.ts@generated 빈 모듈로 초기화하며 소스 포맷을 정리한다.
README 및 개발 가이드 갱신
README.md, docs/development.md
Getting Started·Scripts·Project Structure·Path Aliases를 갱신하고, API·컴포넌트·아이콘·생성 파일 관련 개발 가이드를 추가한다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning App.tsx, CSS, utils 같은 스타터 UI/포맷 수정은 AI 설정·워크플로우·문서화 목적과 직접 관련이 약합니다. UI/스타터 정리와 서식 변경은 별도 PR로 분리하거나 이번 이슈와의 필요성을 명시하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 AI 에이전트 설정 보완이라는 변경의 핵심을 정확히 요약합니다.
Linked Issues check ✅ Passed AI 설정, GitHub 워크플로우, README/문서 초안 추가가 이슈의 TO-DO와 일치합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/init-agent-setup-1

Comment @coderabbitai help to get the list of available commands.

@KyeongJooni KyeongJooni changed the title [Chore] AI 설정 보완 [Chore] AI 에이전트 설정 보완 Jun 30, 2026
@github-actions github-actions Bot changed the title [Chore] AI 에이전트 설정 보완 [Chore] init agent setup 1 Jun 30, 2026
@github-actions github-actions Bot added the 🛠️Chore 기타 작업 label Jun 30, 2026
@KyeongJooni KyeongJooni added the 📝Docs 문서 label Jun 30, 2026
@github-actions

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/hooks/guard-rules.ps1:
- Around line 6-23: The guard logic in guard-rules.ps1 is over-matching because
it scans the entire CLAUDE_TOOL_INPUT, so harmless documentation or test edits
that mention banned terms are blocked. Update the checks around the existing
console.log, any, npm/yarn, and tailwind.config rules to evaluate the actual
target file path and the change content separately, and scope the Tailwind rule
in particular to only block creation of a tailwind.config file rather than any
mention of that string.

In @.claude/hooks/skill-suggest.ps1:
- Around line 13-15: The `/create-pr` suggestion trigger in `skill-suggest.ps1`
is too broad because the `-match 'pr|pull request'` pattern also matches common
substrings in unrelated words. Tighten the condition in the prompt-matching
logic so only standalone `pr` or `pull request` phrases are detected, using word
boundaries in the existing `if ($prompt -match ...)` check to keep
`suggestions.Add('/create-pr - create a PR title and body draft')` from firing
on irrelevant prompts.

In @.claude/rules/project-constraints.md:
- Line 33: The UI library priority text is using the wrong package label, so
update the guidance in the project-constraints rule to use the repository’s
standard symbol kusitms.com/ui instead of `@kusitms.com/ui`. Keep the same
priority order in that rule, and make sure the wording around the component
selection hierarchy matches the rest of the project’s conventions.

In @.claude/skills/code-review/SKILL.md:
- Around line 26-33: The review flow in SKILL.md only checks `git diff` and `git
diff --staged`, so untracked new files are skipped and can be missed during
review. Update the review procedure around the staged/unstaged diff steps to
also detect and include newly added files, using the existing diff collection
flow and the relevant shell commands listed there, so that untracked files are
part of the review output.

In @.github/workflows/auto-create-branch.yml:
- Around line 104-113: The Push issue branch step is directly interpolating
issue-derived input into shell commands, which allows command injection through
BRANCH_NAME. Update the workflow in the Push issue branch job to pass
steps.extract.outputs.branch_name via env instead of inline substitution,
validate it with a branch-ref check such as git check-ref-format --branch before
using it, and only then use it in git checkout/git push.

In @.github/workflows/ci.yml:
- Around line 15-18: The workflow permissions are too broad for the main ci job,
exposing write access while running untrusted PR code through pnpm install,
vitest, and build. Update the permissions on the ci workflow so the job that
runs tests and builds only has read-only access, and move pull-requests: write
and issues: write to the separate comment job or any step that actually needs to
post comments. Use the ci job and the comment job identifiers in
.github/workflows/ci.yml to keep the privileges split correctly.

In @.github/workflows/pr-auto-setup.yml:
- Around line 57-78: The branch slug parsing in the PR auto setup workflow can
throw on invalid percent-encoding, which stops the rest of the metadata sync.
Update the branch slug handling in the branchMatch block to safely decode
rawSlug by falling back to the original slug when decodeURIComponent fails, so
titleSource still gets set and the assignee/title/label flow can continue. Keep
the fix localized around the titleSource initialization and related branch
parsing logic.

In `@eslint.config.js`:
- Line 42: The global no-undef override in eslint.config.js is too broad and
hides typos in JavaScript-only files. Update the ESLint config so no-undef stays
enabled by default, and only disable it in the TypeScript-specific override
block if needed; use the existing config structure around the no-undef rule and
the file-pattern overrides to scope the exception correctly.
- Around line 49-55: The current ESLint config applies both browser and Node
globals to `src/**/*.{ts,tsx}` and `scripts/**/*.ts`, which can hide browser
runtime errors in app code. Split this `files` block in `eslint.config.js` into
separate config entries so `src` only gets `globals.browser` and `scripts` only
gets `globals.node`, keeping the relevant globals scoped to each runtime. Use
the existing `languageOptions.globals` setup as the place to separate the two
environments.

In `@scripts/build-icons.ts`:
- Around line 32-45: The component name generation in toComponentName can still
produce an invalid identifier when a SVG file name starts with a number, so
update this helper to guard against numeric leading characters after
toPascalCase. In scripts/build-icons.ts, keep the existing Invalid icon file
name handling, but before returning the final name ensure names like 24Arrow are
prefixed or otherwise normalized so the generated TSX component name is a valid
JavaScript/TypeScript identifier, including the Icon/Logo/Brand/Symbol/Wordmark
suffix path.
- Around line 56-66: readIconSources currently swallows every readdir failure
and returns an empty list, which can hide real filesystem or path regressions;
update this helper to only treat the expected missing-directory case as
recoverable and rethrow any other error. Use the existing readIconSources
function in scripts/build-icons.ts as the fix point, and keep the fallback to []
limited to the ENOENT case so icons:build and icons:check fail loudly on
unexpected directory access problems.
- Around line 47-54: `normalizeToCurrentColor`에서 `style` 속성을 통째로 제거하는 처리가 렌더링을
깨뜨리고 있으니, 색상 관련 값만 currentColor로 정규화하고 `stroke-width`, `opacity`, `fill-rule` 같은
비색상 스타일은 유지하도록 수정하세요. `scripts/build-icons.ts`의 `normalizeToCurrentColor` 로직을
중심으로, `fill`/`stroke` 치환은 유지하되 `style` 전체 삭제 대신 필요한 색상 선언만 선택적으로 변환하거나 보존하도록 바꾸면
됩니다.

In `@scripts/gen-index.ts`:
- Around line 18-39: The FS helpers readEntries, readFileOrEmpty, and
isDirectory are swallowing every error and turning real I/O failures into empty
results, which can produce an empty barrel and hide access/resource issues.
Update these helpers in gen-index so they only treat ENOENT as a benign
missing-path case, while rethrowing other errors from readdir, readFile, and
stat; keep the existing helper names and call sites but make the fallback
behavior error-specific rather than blanket empty values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ffe9ac38-7470-49c5-8260-90bbc2ef728c

📥 Commits

Reviewing files that changed from the base of the PR and between 4d2038f and 43bbd3f.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
  • src/assets/icons/generated/.gitkeep is excluded by !**/generated/**
📒 Files selected for processing (82)
  • .claude/decisions/README.md
  • .claude/decisions/template.md
  • .claude/hooks/guard-rules.ps1
  • .claude/hooks/lint-check.ps1
  • .claude/hooks/skill-suggest.ps1
  • .claude/manifest.md
  • .claude/references/api/admin-auth.md
  • .claude/references/api/admin-blog-reviews.md
  • .claude/references/api/admin-introductions.md
  • .claude/references/api/admin-members.md
  • .claude/references/api/admin-projects.md
  • .claude/references/api/admin-reviews.md
  • .claude/references/api/admin.md
  • .claude/references/component-patterns.md
  • .claude/references/domain/blog-reviews.md
  • .claude/references/domain/introductions.md
  • .claude/references/domain/members.md
  • .claude/references/domain/projects.md
  • .claude/references/domain/reviews.md
  • .claude/rules/architecture.md
  • .claude/rules/code-quality.md
  • .claude/rules/code-style.md
  • .claude/rules/commit-convention.md
  • .claude/rules/component-guide.md
  • .claude/rules/data-fetching.md
  • .claude/rules/generated-workflows.md
  • .claude/rules/project-constraints.md
  • .claude/rules/testing.md
  • .claude/rules/verification.md
  • .claude/rules/workflow.md
  • .claude/settings.json
  • .claude/skills/code-review/SKILL.md
  • .claude/skills/commit-kr/SKILL.md
  • .claude/skills/create-pr/SKILL.md
  • .claude/skills/create-pr/templates/ai-automation-pr.md
  • .claude/skills/figma-to-component/SKILL.md
  • .claude/skills/gen-test/SKILL.md
  • .claude/skills/refactor/SKILL.md
  • .claude/skills/scaffold-api/SKILL.md
  • .coderabbit.yaml
  • .codex/hooks.json
  • .codex/skills/code-review/SKILL.md
  • .codex/skills/commit-kr/SKILL.md
  • .codex/skills/create-pr/SKILL.md
  • .codex/skills/figma-to-component/SKILL.md
  • .codex/skills/gen-test/SKILL.md
  • .codex/skills/refactor/SKILL.md
  • .codex/skills/scaffold-api/SKILL.md
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/feature.md
  • .github/ISSUE_TEMPLATE/issue-template.yml
  • .github/PULL_REQUEST_TEMPLATE.md
  • .github/workflows/auto-create-branch.yml
  • .github/workflows/ci.yml
  • .github/workflows/pr-auto-setup.yml
  • .gitignore
  • .husky/pre-commit
  • .prettierignore
  • AGENTS.md
  • CLAUDE.md
  • README.md
  • docs/development.md
  • eslint.config.js
  • package.json
  • scripts/build-icons.ts
  • scripts/gen-index.ts
  • src/App.css
  • src/App.tsx
  • src/api/.gitkeep
  • src/assets/icons/svg-preserve/.gitkeep
  • src/assets/icons/svg/.gitkeep
  • src/components/.gitkeep
  • src/components/index.ts
  • src/hooks/.gitkeep
  • src/hooks/index.ts
  • src/index.css
  • src/lib/utils.ts
  • src/pages/.gitkeep
  • tsconfig.app.json
  • tsconfig.json
  • tsconfig.node.json
  • vite.config.ts
💤 Files with no reviewable changes (1)
  • .github/ISSUE_TEMPLATE/feature.md

Comment thread .claude/hooks/guard-rules.ps1 Outdated
Comment thread .claude/hooks/skill-suggest.ps1 Outdated
## 의존성

- production dependency 추가 전에는 확인을 받습니다.
- UI 라이브러리는 `@kusitms.com/ui` -> shadcn/ui -> Base UI 순으로 우선합니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

UI 라이브러리 표기를 맞춰 주세요.

@kusitms.com/ui는 이 저장소의 기준 표기와 다릅니다. kusitms.com/ui로 수정해야 에이전트가 같은 우선순위를 따릅니다. Based on learnings: 컴포넌트 선택 우선순위는 kusitms.com/ui -> shadcn/ui -> Base UI 순입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/rules/project-constraints.md at line 33, The UI library priority
text is using the wrong package label, so update the guidance in the
project-constraints rule to use the repository’s standard symbol kusitms.com/ui
instead of `@kusitms.com/ui`. Keep the same priority order in that rule, and make
sure the wording around the component selection hierarchy matches the rest of
the project’s conventions.

Source: Learnings

Comment on lines +26 to +33
인자가 없으면 현재 worktree의 staged + unstaged diff를 리뷰합니다.

```bash
git diff --name-only
git diff --staged --name-only
git diff
git diff --staged
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

새 파일 누락을 막아야 합니다.

현재 절차는 git diff만 읽어서 미추적 파일이 빠집니다. 새로 추가된 파일은 리뷰에서 아예 제외되어 회귀를 놓칠 수 있습니다.

💡 제안
- 인자가 없으면 현재 worktree의 staged + unstaged diff를 리뷰합니다.
+ 인자가 없으면 현재 worktree의 staged + unstaged diff와 미추적 파일까지 리뷰합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/code-review/SKILL.md around lines 26 - 33, The review flow in
SKILL.md only checks `git diff` and `git diff --staged`, so untracked new files
are skipped and can be missed during review. Update the review procedure around
the staged/unstaged diff steps to also detect and include newly added files,
using the existing diff collection flow and the relevant shell commands listed
there, so that untracked files are part of the review output.

Comment on lines +104 to +113
- name: Push issue branch
run: |
BRANCH_NAME="${{ steps.extract.outputs.branch_name }}"

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git fetch origin main
git checkout -b "$BRANCH_NAME" origin/main
git push origin "$BRANCH_NAME"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

이슈 본문에서 온 값을 셸에 직접 주입하고 있습니다.

steps.extract.outputs.branch_name 는 이슈 본문에서 파생된 사용자 입력이라, 현재처럼 Line 106에서 직접 문자열 치환하면 "$()를 섞은 값으로 명령 주입이 가능합니다. env:로 전달하고 git check-ref-format --branch 같은 검증을 넣어야 합니다.

예시 수정
       - name: Push issue branch
+        env:
+          BRANCH_NAME: ${{ steps.extract.outputs.branch_name }}
         run: |
-          BRANCH_NAME="${{ steps.extract.outputs.branch_name }}"
+          git check-ref-format --branch "$BRANCH_NAME"

           git config user.name "github-actions[bot]"
           git config user.email "github-actions[bot]`@users.noreply.github.com`"

           git fetch origin main
           git checkout -b "$BRANCH_NAME" origin/main
           git push origin "$BRANCH_NAME"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Push issue branch
run: |
BRANCH_NAME="${{ steps.extract.outputs.branch_name }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git fetch origin main
git checkout -b "$BRANCH_NAME" origin/main
git push origin "$BRANCH_NAME"
- name: Push issue branch
env:
BRANCH_NAME: ${{ steps.extract.outputs.branch_name }}
run: |
git check-ref-format --branch "$BRANCH_NAME"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]`@users.noreply.github.com`"
git fetch origin main
git checkout -b "$BRANCH_NAME" origin/main
git push origin "$BRANCH_NAME"
🧰 Tools
🪛 zizmor (1.26.1)

[info] 106-106: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/auto-create-branch.yml around lines 104 - 113, The Push
issue branch step is directly interpolating issue-derived input into shell
commands, which allows command injection through BRANCH_NAME. Update the
workflow in the Push issue branch job to pass steps.extract.outputs.branch_name
via env instead of inline substitution, validate it with a branch-ref check such
as git check-ref-format --branch before using it, and only then use it in git
checkout/git push.

Comment thread eslint.config.js
Comment on lines +49 to +55
files: ['src/**/*.{ts,tsx}', 'scripts/**/*.ts'],
extends: [...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked],
languageOptions: {
globals: globals.browser,
globals: {
...globals.browser,
...globals.node,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

srcscripts에 같은 globals를 주면 브라우저 런타임 오류를 숨깁니다.

이 블록은 src/**/*.{ts,tsx}에도 globals.node를 허용합니다. 그 결과 process, Buffer, __dirname 같은 Node 전역을 앱 코드에서 써도 린트가 통과해서, 브라우저에서만 터지는 참조 오류를 놓치게 됩니다. srcscripts를 별도 블록으로 나눠 browser/node globals를 분리하세요.

수정 예시
-  {
-    files: ['src/**/*.{ts,tsx}', 'scripts/**/*.ts'],
+  {
+    files: ['src/**/*.{ts,tsx}'],
     extends: [...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked],
     languageOptions: {
       globals: {
         ...globals.browser,
-        ...globals.node,
       },
       parserOptions: {
         projectService: true,
         tsconfigRootDir: import.meta.dirname,
       },
     },
+    rules: {
+      // ...
+    },
+  },
+  {
+    files: ['scripts/**/*.ts'],
+    extends: [...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked],
+    languageOptions: {
+      globals: {
+        ...globals.node,
+      },
+      parserOptions: {
+        projectService: true,
+        tsconfigRootDir: import.meta.dirname,
+      },
+    },
     rules: {
       '`@typescript-eslint/no-explicit-any`': 'warn',
       '`@typescript-eslint/no-empty-function`': 'off',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@eslint.config.js` around lines 49 - 55, The current ESLint config applies
both browser and Node globals to `src/**/*.{ts,tsx}` and `scripts/**/*.ts`,
which can hide browser runtime errors in app code. Split this `files` block in
`eslint.config.js` into separate config entries so `src` only gets
`globals.browser` and `scripts` only gets `globals.node`, keeping the relevant
globals scoped to each runtime. Use the existing `languageOptions.globals` setup
as the place to separate the two environments.

Comment thread scripts/build-icons.ts
Comment on lines +32 to +45
const toComponentName = (fileName: string) => {
const baseName = basename(fileName, extname(fileName))
const pascalName = toPascalCase(baseName)

if (!pascalName) {
throw new Error(`Invalid icon file name: ${fileName}`)
}

if (/(Icon|Logo|Brand|Symbol|Wordmark)$/.test(pascalName)) {
return pascalName
}

return `${pascalName}Icon`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

숫자로 시작하는 SVG 파일명은 생성된 TSX를 문법 오류로 만듭니다.

24-arrow.svg 같은 이름은 toPascalCase 이후에도 숫자로 시작할 수 있고, 그 값이 그대로 componentName에 들어가면 유효하지 않은 식별자가 생성됩니다. 파일명 입력이 외부 SVG 자산에 의해 결정되는 만큼, 첫 글자가 숫자인 경우 접두사를 강제로 붙여야 합니다.

가능한 수정 예시
 const toComponentName = (fileName: string) => {
   const baseName = basename(fileName, extname(fileName))
   const pascalName = toPascalCase(baseName)

   if (!pascalName) {
     throw new Error(`Invalid icon file name: ${fileName}`)
   }

-  if (/(Icon|Logo|Brand|Symbol|Wordmark)$/.test(pascalName)) {
-    return pascalName
+  const normalizedName = /^[0-9]/.test(pascalName) ? `Icon${pascalName}` : pascalName
+
+  if (/(Icon|Logo|Brand|Symbol|Wordmark)$/.test(normalizedName)) {
+    return normalizedName
   }

-  return `${pascalName}Icon`
+  return `${normalizedName}Icon`
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const toComponentName = (fileName: string) => {
const baseName = basename(fileName, extname(fileName))
const pascalName = toPascalCase(baseName)
if (!pascalName) {
throw new Error(`Invalid icon file name: ${fileName}`)
}
if (/(Icon|Logo|Brand|Symbol|Wordmark)$/.test(pascalName)) {
return pascalName
}
return `${pascalName}Icon`
}
const toComponentName = (fileName: string) => {
const baseName = basename(fileName, extname(fileName))
const pascalName = toPascalCase(baseName)
if (!pascalName) {
throw new Error(`Invalid icon file name: ${fileName}`)
}
const normalizedName = /^[0-9]/.test(pascalName) ? `Icon${pascalName}` : pascalName
if (/(Icon|Logo|Brand|Symbol|Wordmark)$/.test(normalizedName)) {
return normalizedName
}
return `${normalizedName}Icon`
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build-icons.ts` around lines 32 - 45, The component name generation
in toComponentName can still produce an invalid identifier when a SVG file name
starts with a number, so update this helper to guard against numeric leading
characters after toPascalCase. In scripts/build-icons.ts, keep the existing
Invalid icon file name handling, but before returning the final name ensure
names like 24Arrow are prefixed or otherwise normalized so the generated TSX
component name is a valid JavaScript/TypeScript identifier, including the
Icon/Logo/Brand/Symbol/Wordmark suffix path.

Comment thread scripts/build-icons.ts
Comment on lines +47 to +54
const normalizeToCurrentColor = (svg: string) => {
return svg
.replace(
/\s(fill|stroke)=["'](?!none|currentColor|transparent|url\()[^"']+["']/gi,
' $1="currentColor"',
)
.replace(/style=["'][^"']*["']/gi, '')
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

style 전체 제거는 아이콘 렌더링을 깨뜨릴 수 있습니다.

지금 구현은 색상 정규화와 함께 style 속성을 통째로 삭제해서 stroke-width, opacity, fill-rule 같은 비색상 선언도 잃어버립니다. svg 디렉터리의 아이콘도 currentColor 치환만 해야지, 스타일 전체를 지우면 생성된 TSX가 원본 SVG와 다른 모양이 됩니다.

가능한 수정 예시
 const normalizeToCurrentColor = (svg: string) => {
   return svg
     .replace(
       /\s(fill|stroke)=["'](?!none|currentColor|transparent|url\()[^"']+["']/gi,
       ' $1="currentColor"',
     )
-    .replace(/style=["'][^"']*["']/gi, '')
+    .replace(/style=(["'])(.*?)\1/gi, (_match, quote: string, styleValue: string) => {
+      const nextStyle = styleValue
+        .split(';')
+        .map((rule) => rule.trim())
+        .filter(Boolean)
+        .map((rule) =>
+          /^(fill|stroke)\s*:/i.test(rule) &&
+          !/^(fill|stroke)\s*:\s*(none|currentColor|transparent|url\()/i.test(rule)
+            ? rule.replace(/^(fill|stroke)\s*:\s*[^;]+/i, '$1: currentColor')
+            : rule,
+        )
+        .join('; ')
+
+      return nextStyle ? `style=${quote}${nextStyle}${quote}` : ''
+    })
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizeToCurrentColor = (svg: string) => {
return svg
.replace(
/\s(fill|stroke)=["'](?!none|currentColor|transparent|url\()[^"']+["']/gi,
' $1="currentColor"',
)
.replace(/style=["'][^"']*["']/gi, '')
}
const normalizeToCurrentColor = (svg: string) => {
return svg
.replace(
/\s(fill|stroke)=["'](?!none|currentColor|transparent|url\()[^"']+["']/gi,
' $1="currentColor"',
)
.replace(/style=(["'])(.*?)\1/gi, (_match, quote: string, styleValue: string) => {
const nextStyle = styleValue
.split(';')
.map((rule) => rule.trim())
.filter(Boolean)
.map((rule) =>
/^(fill|stroke)\s*:/i.test(rule) &&
!/^(fill|stroke)\s*:\s*(none|currentColor|transparent|url\()/i.test(rule)
? rule.replace(/^(fill|stroke)\s*:\s*[^;]+/i, '$1: currentColor')
: rule,
)
.join('; ')
return nextStyle ? `style=${quote}${nextStyle}${quote}` : ''
})
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build-icons.ts` around lines 47 - 54, `normalizeToCurrentColor`에서
`style` 속성을 통째로 제거하는 처리가 렌더링을 깨뜨리고 있으니, 색상 관련 값만 currentColor로 정규화하고
`stroke-width`, `opacity`, `fill-rule` 같은 비색상 스타일은 유지하도록 수정하세요.
`scripts/build-icons.ts`의 `normalizeToCurrentColor` 로직을 중심으로, `fill`/`stroke`
치환은 유지하되 `style` 전체 삭제 대신 필요한 색상 선언만 선택적으로 변환하거나 보존하도록 바꾸면 됩니다.

Comment thread scripts/build-icons.ts
Comment on lines +56 to +66
const readIconSources = async (
sourceDir: string,
preserveColors: boolean,
): Promise<IconSource[]> => {
let entries

try {
entries = await readdir(sourceDir, { withFileTypes: true })
} catch {
return []
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

소스 디렉터리 읽기 실패를 빈 목록으로 숨기면 잘못된 생성 결과를 정상으로 오인합니다.

이 PR 컨텍스트상 src/assets/icons/svgsrc/assets/icons/svg-preserve는 커밋된 디렉터리입니다. 그런데 여기서 모든 readdir 에러를 []로 바꾸면, 실제 파일시스템 오류나 경로 회귀가 발생해도 icons:build가 누락된 세트로 생성물을 덮어쓰고 icons:check도 통과시킬 수 있습니다. 최소한 ENOENT만 예외 처리하고 나머지는 다시 던져야 합니다.

가능한 수정 예시
   try {
     entries = await readdir(sourceDir, { withFileTypes: true })
-  } catch {
+  } catch (error) {
+    if (
+      error &&
+      typeof error === 'object' &&
+      'code' in error &&
+      error.code === 'ENOENT'
+    ) {
+      return []
+    }
+
+    throw error
+  }
-    return []
-  }
+  
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const readIconSources = async (
sourceDir: string,
preserveColors: boolean,
): Promise<IconSource[]> => {
let entries
try {
entries = await readdir(sourceDir, { withFileTypes: true })
} catch {
return []
}
const readIconSources = async (
sourceDir: string,
preserveColors: boolean,
): Promise<IconSource[]> => {
let entries
try {
entries = await readdir(sourceDir, { withFileTypes: true })
} catch (error) {
if (
error &&
typeof error === 'object' &&
'code' in error &&
error.code === 'ENOENT'
) {
return []
}
throw error
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build-icons.ts` around lines 56 - 66, readIconSources currently
swallows every readdir failure and returns an empty list, which can hide real
filesystem or path regressions; update this helper to only treat the expected
missing-directory case as recoverable and rethrow any other error. Use the
existing readIconSources function in scripts/build-icons.ts as the fix point,
and keep the fallback to [] limited to the ENOENT case so icons:build and
icons:check fail loudly on unexpected directory access problems.

Comment thread scripts/gen-index.ts
Comment on lines +18 to +39
const readEntries = async (dir: string) => {
try {
return await readdir(dir, { withFileTypes: true })
} catch {
return []
}
}

const readFileOrEmpty = async (filePath: string) => {
try {
return await readFile(filePath, 'utf8')
} catch {
return ''
}
}

const isDirectory = async (dir: string) => {
try {
return (await stat(dir)).isDirectory()
} catch {
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

모든 FS 예외를 빈 상태로 삼키면 정상 배럴을 비워 쓸 수 있습니다.

여기서는 readdir/readFile/stat의 모든 실패를 각각 [], '', false로 바꿉니다. 그래서 EACCES, EMFILE 같은 실제 I/O 장애도 “파일이 없음”으로 처리되고, write 모드에서는 비어 있는 index.ts를 생성해 기존 export surface를 깨뜨릴 수 있습니다. ENOENT만 없는 상태로 취급하고 나머지는 바로 실패시키는 편이 안전합니다.

수정 예시
+const isMissing = (error: unknown) => {
+  return (error as NodeJS.ErrnoException).code === 'ENOENT'
+}
+
 const readEntries = async (dir: string) => {
   try {
     return await readdir(dir, { withFileTypes: true })
-  } catch {
+  } catch (error) {
+    if (isMissing(error)) {
+      return []
+    }
+    throw error
+  }
-    return []
-  }
 }
 
 const readFileOrEmpty = async (filePath: string) => {
   try {
     return await readFile(filePath, 'utf8')
-  } catch {
+  } catch (error) {
+    if (isMissing(error)) {
+      return ''
+    }
+    throw error
+  }
-    return ''
-  }
 }
 
 const isDirectory = async (dir: string) => {
   try {
     return (await stat(dir)).isDirectory()
-  } catch {
+  } catch (error) {
+    if (isMissing(error)) {
+      return false
+    }
+    throw error
+  }
-    return false
-  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const readEntries = async (dir: string) => {
try {
return await readdir(dir, { withFileTypes: true })
} catch {
return []
}
}
const readFileOrEmpty = async (filePath: string) => {
try {
return await readFile(filePath, 'utf8')
} catch {
return ''
}
}
const isDirectory = async (dir: string) => {
try {
return (await stat(dir)).isDirectory()
} catch {
return false
}
const isMissing = (error: unknown) => {
return (error as NodeJS.ErrnoException).code === 'ENOENT'
}
const readEntries = async (dir: string) => {
try {
return await readdir(dir, { withFileTypes: true })
} catch (error) {
if (isMissing(error)) {
return []
}
throw error
}
}
const readFileOrEmpty = async (filePath: string) => {
try {
return await readFile(filePath, 'utf8')
} catch (error) {
if (isMissing(error)) {
return ''
}
throw error
}
}
const isDirectory = async (dir: string) => {
try {
return (await stat(dir)).isDirectory()
} catch (error) {
if (isMissing(error)) {
return false
}
throw error
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/gen-index.ts` around lines 18 - 39, The FS helpers readEntries,
readFileOrEmpty, and isDirectory are swallowing every error and turning real I/O
failures into empty results, which can produce an empty barrel and hide
access/resource issues. Update these helpers in gen-index so they only treat
ENOENT as a benign missing-path case, while rethrowing other errors from
readdir, readFile, and stat; keep the existing helper names and call sites but
make the fallback behavior error-specific rather than blanket empty values.

@github-actions

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@kusitms-com kusitms-com deleted a comment from github-actions Bot Jun 30, 2026
@kusitms-com kusitms-com deleted a comment from github-actions Bot Jun 30, 2026
@KyeongJooni KyeongJooni changed the title [Chore] init agent setup 1 [Chore] AI 에이전트 설정 보완 Jun 30, 2026
@github-actions

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/hooks/guard-rules.ps1:
- Around line 1-3: The input env var contract in guard-rules.ps1 is mismatched:
the script only reads CLAUDE_TOOL_INPUT while the rest of the hook setup uses
TOOL_INPUT, so the guard can exit early with no input. Update the guard logic in
the script to read TOOL_INPUT with fallback to CLAUDE_TOOL_INPUT (or vice versa)
before the empty check, and keep the existing exit behavior only when both are
unavailable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f23bbb47-db97-40a5-bb33-ea95516020c6

📥 Commits

Reviewing files that changed from the base of the PR and between 87dbb3d and 40fc8fa.

📒 Files selected for processing (4)
  • .claude/hooks/guard-rules.ps1
  • .claude/hooks/skill-suggest.ps1
  • .github/workflows/auto-create-branch.yml
  • .github/workflows/ci.yml
🚧 Files skipped from review as they are similar to previous changes (3)
  • .claude/hooks/skill-suggest.ps1
  • .github/workflows/ci.yml
  • .github/workflows/auto-create-branch.yml

Comment on lines +1 to +3
$inputText = $env:CLAUDE_TOOL_INPUT
if (-not $inputText) {
exit 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Hook env var usage =="
fd -a '.*\.ps1$' .claude/hooks | xargs -r rg -n '\$env:(TOOL_INPUT|CLAUDE_TOOL_INPUT)'

echo
echo "== Hook registrations =="
sed -n '1,80p' .claude/settings.json
echo
sed -n '1,80p' .codex/hooks.json

Repository: kusitms-com/makers-admin-fe

Length of output: 2461


입력 payload env var 계약이 어긋납니다. guard-rules.ps1CLAUDE_TOOL_INPUT만 읽는데, 같은 훅 계열과 등록 설정은 TOOL_INPUT 기준입니다. 입력이 비면 바로 종료되어 guard가 무력화되므로 둘 다 fallback으로 받게 해주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/hooks/guard-rules.ps1 around lines 1 - 3, The input env var contract
in guard-rules.ps1 is mismatched: the script only reads CLAUDE_TOOL_INPUT while
the rest of the hook setup uses TOOL_INPUT, so the guard can exit early with no
input. Update the guard logic in the script to read TOOL_INPUT with fallback to
CLAUDE_TOOL_INPUT (or vice versa) before the empty check, and keep the existing
exit behavior only when both are unavailable.

@github-actions

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@leemanjae02 leemanjae02 merged commit bd38347 into main Jun 30, 2026
3 checks passed

@leemanjae02 leemanjae02 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!

@coderabbitai coderabbitai Bot mentioned this pull request Jul 5, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️Chore 기타 작업 📝Docs 문서

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Chore] #4 - AI 에이전트 설정 보완

2 participants