🔧 chore: 설치 스크립트에서 .gitignore 관련 코드 제거 및 주석 수정

This commit is contained in:
“hyeonggkim”
2026-04-20 19:37:50 +09:00
parent fb31c8d7e5
commit 64c383ce32
5 changed files with 427 additions and 53 deletions

View File

@@ -56,18 +56,13 @@ git submodule update --init --recursive
bash .claude/common/scripts/install.sh https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
```
> `install.sh`는 `.gitignore`에 `.claude/common/`를 자동으로 추가합니다.
> `.gitignore`가 없으면 새로 생성합니다.
설치 후 프로젝트 구조는 다음과 같이 됩니다.
```
your-project/
├── .claude/
│ ├── common/ ← submodule (gameservice-fe-agent)
── project/ ← 프로젝트 고유 지침
│ └── skills/ ← 공통 skill 심볼릭 링크
├── .gitignore ← .claude/common/ 자동 추가됨
── project/ ← 프로젝트 고유 지침
├── CLAUDE.md ← 공통 + 프로젝트 지침을 @import
└── ...
```
@@ -114,7 +109,6 @@ bash .claude/common/scripts/update.sh
```bash
bash .claude/common/scripts/install.sh https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
# → .claude/common 에 submodule 설치
# → .gitignore 에 .claude/common/ 추가
# → templates/project/*.md 를 .claude/project/ 로 복사
# → templates/CLAUDE.md.tpl 을 루트 CLAUDE.md 로 복사
```

View File

@@ -43,22 +43,7 @@ else
echo "✅ submodule 추가 완료: $TARGET_PATH"
fi
# 2) .gitignore 에 .claude/common 추가
GITIGNORE=".gitignore"
IGNORE_ENTRY=".claude/common/"
if [[ -f "$GITIGNORE" ]]; then
if grep -qF "$IGNORE_ENTRY" "$GITIGNORE" || grep -qF ".claude/common" "$GITIGNORE"; then
echo " .gitignore 에 '$IGNORE_ENTRY' 가 이미 있습니다. 건너뜁니다."
else
printf "\n# gameservice-fe-agent submodule\n%s\n" "$IGNORE_ENTRY" >> "$GITIGNORE"
echo "✅ .gitignore 에 '$IGNORE_ENTRY' 를 추가했습니다."
fi
else
printf "# gameservice-fe-agent submodule\n%s\n" "$IGNORE_ENTRY" > "$GITIGNORE"
echo "✅ .gitignore 를 생성하고 '$IGNORE_ENTRY' 를 추가했습니다."
fi
# 4) 프로젝트 지침 양식 복사 (templates/project/ → .claude/project/)
# 2) 프로젝트 지침 양식 복사 (templates/project/ → .claude/project/)
mkdir -p "$PROJECT_PATH"
TEMPLATE_DIR="$TARGET_PATH/templates/project"
@@ -79,7 +64,7 @@ else
echo "⚠️ $TEMPLATE_DIR 를 찾지 못했습니다. 공통 저장소의 templates 가 오래됐을 수 있습니다."
fi
# 5) 루트 CLAUDE.md 템플릿 복사
# 3) 루트 CLAUDE.md 템플릿 복사
if [[ ! -f "CLAUDE.md" ]]; then
TPL_FILE="$TARGET_PATH/templates/CLAUDE.md.tpl"
if [[ -f "$TPL_FILE" ]]; then
@@ -112,7 +97,7 @@ else
echo ""
fi
# 6) 공통 skill 심볼릭 링크 (.claude/common/skills/* → .claude/skills/*)
# 4) 공통 skill 심볼릭 링크 (.claude/common/skills/* → .claude/skills/*)
SKILLS_SRC="$TARGET_PATH/skills"
SKILLS_DEST=".claude/skills"
@@ -136,33 +121,6 @@ if [[ -d "$SKILLS_SRC" ]]; then
done
fi
# 7) pre-commit 훅: .claude/common 변경 커밋 방지
HOOK_DIR="$(git rev-parse --git-dir)/hooks"
HOOK_FILE="$HOOK_DIR/pre-commit"
HOOK_MARKER="# gameservice-fe-agent: block .claude/common commit"
mkdir -p "$HOOK_DIR"
if [[ -f "$HOOK_FILE" ]] && grep -qF "$HOOK_MARKER" "$HOOK_FILE"; then
echo " pre-commit 훅에 .claude/common 보호 규칙이 이미 있습니다. 건너뜁니다."
else
# 훅이 없으면 새로 생성, 있으면 기존 훅 뒤에 추가
if [[ ! -f "$HOOK_FILE" ]]; then
echo "#!/usr/bin/env bash" > "$HOOK_FILE"
fi
cat >> "$HOOK_FILE" <<'HOOK'
# gameservice-fe-agent: block .claude/common commit
if git diff --cached --name-only | grep -q "^\.claude/common"; then
echo "❌ .claude/common (gameservice-fe-agent submodule) 변경은 커밋할 수 없습니다."
echo " 공통 지침 수정은 gameservice-fe-agent 저장소에서 PR을 통해 진행해 주세요."
exit 1
fi
HOOK
chmod +x "$HOOK_FILE"
echo "✅ pre-commit 훅을 설치했습니다. (.claude/common 변경 커밋 방지)"
fi
echo ""
echo "🎉 설치가 완료되었습니다."
echo " - 공통 지침: $TARGET_PATH/CLAUDE.md"
@@ -173,5 +131,5 @@ echo ""
echo "다음 작업을 진행해 주세요:"
echo " 1) $PROJECT_PATH/*.md 내용을 프로젝트에 맞게 채우기"
echo " 2) 변경 사항을 커밋하기"
echo " git add .gitmodules .gitignore .claude CLAUDE.md"
echo " git add .gitmodules .claude CLAUDE.md"
echo " git commit -m 'chore: add gameservice-fe-agent submodule'"

View File

@@ -0,0 +1,165 @@
---
name: project-init
description: >
현재 프로젝트를 분석하여 .claude/project/ 하위 문서(overview.md, conventions.md, architecture.md)를
실제 내용으로 채웁니다. 사용자가 "/init", "프로젝트 초기화", "프로젝트 문서 작성해줘" 등을
요청할 때 트리거됩니다.
---
# Project Init — 프로젝트 문서 자동 작성
이 skill 은 현재 Git 저장소를 탐색하여 `.claude/project/` 하위 세 파일을
실제 프로젝트 정보로 채웁니다.
## 언제 사용하는가
- `/init` 실행 시
- `.claude/project/*.md` 가 템플릿 상태(placeholder 가 남아 있음)일 때
- 새로운 프로젝트에 gameservice-fe-agent 를 처음 적용할 때
## 작업 순서
### 1. 환경 파악 (읽기 전용)
아래 파일들을 순서대로 읽어 프로젝트 정보를 수집한다.
파일이 없으면 건너뛴다.
| 파일 / 명령 | 수집 정보 |
|---|---|
| `package.json` | 프로젝트 이름, 의존성, 스크립트, 패키지 매니저 |
| `pnpm-lock.yaml` / `yarn.lock` / `package-lock.json` | 패키지 매니저 확정 |
| `nuxt.config.ts` / `next.config.*` / `vite.config.*` | 프레임워크, 모듈, 빌드 설정 |
| `tsconfig.json` | TypeScript strict 여부 |
| `tailwind.config.*` | CSS 프레임워크 |
| `.eslintrc.*` / `eslint.config.*` | 린터 설정 |
| `README.md` | 서비스 설명, 팀 정보 |
| `app/` / `src/` / `pages/` 디렉토리 구조 | 레이어, 주요 기능 |
| `server/api/` 또는 `src/api/` | 외부 의존성, API 패턴 |
| `stores/` / `composables/` | 상태 관리 패턴 |
### 2. 기존 문서 상태 확인
`.claude/project/overview.md`, `conventions.md`, `architecture.md` 를 읽어
이미 작성된 내용이 있으면 덮어쓰지 않고 **비어 있는 섹션만 채운다**.
- placeholder(`<...>`) 가 남아 있는 줄 → 채움 대상
- 실제 내용이 작성된 줄 → 유지
### 3. 사용자 확인 후 작성
탐색이 끝나면 아래 요약을 사용자에게 먼저 보여준다.
```
📋 감지된 프로젝트 정보
이름: <name>
프레임워크: <framework>
패키지 매니저: <pm>
언어: TypeScript (strict: <yes/no>)
CSS: <css>
상태관리: <state>
테스트: <test>
✍️ 아래 파일을 업데이트하려고 합니다:
- CLAUDE.md (제목 · 주요 명령어 · 주의사항)
- .claude/project/overview.md
- .claude/project/conventions.md
- .claude/project/architecture.md
진행할까요? (y/n)
```
사용자가 **y** 또는 별도 지시 없이 진행을 허락할 때만 파일을 수정한다.
### 4. 각 파일 작성 규칙
#### CLAUDE.md
루트 `CLAUDE.md` 는 Claude 가 대화 시작 시 **항상** 읽는 파일이므로, 매번 하위 파일까지 탐색하지 않아도 되는 핵심 정보만 간결하게 기재한다.
- **제목** (`# <프로젝트 이름>`): `package.json``name` 필드로 교체
예) `# epic7-esports``# Epic7 Esports E7WC`
`name` 이 slug 형태면 사람이 읽기 좋은 표기로 변환한다.
- **`## 주요 명령어`** 섹션 (필수 추가):
`package.json``scripts` 에서 아래 유형을 추출하여 그룹별로 정리한다.
주석은 스크립트 이름만으로 의도를 알기 어려울 때만 달고, 뻔한 것은 생략한다.
```markdown
## 주요 명령어
# 개발 서버
<dev 계열 스크립트>
# 빌드
<build 계열 스크립트>
# 린트 / 포맷
<lint 계열 스크립트>
```
- `dev`, `start`, `local` 등 → **개발 서버** 그룹
- `build`, `build:*` → **빌드** 그룹
- `lint`, `lint:*`, `format`, `prettier` → **린트 / 포맷** 그룹
- `test`, `test:*` → **테스트** 그룹 (존재할 때만)
- 나머지 잡다한 스크립트는 포함하지 않는다.
- **`## 주의사항`** 섹션 (선택 추가):
프로젝트 고유의 "함정"이 될 수 있는 항목을 2-4개 이내로 요약한다.
소스는 `conventions.md` 의 **금지 사항** 섹션 + CSS/API 탐색 결과.
없으면 이 섹션은 추가하지 않는다.
```markdown
## 주의사항
- CSS: <탐색 결과에 따라 기재. 예: Tailwind 아님, SCSS 사용 — Tailwind 클래스 금지>
- API: <API 호출 패턴 금지/허용 규칙>
- 환경: <.env 파일 분기 규칙>
```
- 이미 제목이 실제 이름으로 바뀌어 있거나 섹션이 존재하면 덮어쓰지 않고 유지한다.
#### overview.md
- **서비스 > 이름**: `package.json` 의 `name` 필드 사용
- **서비스 > 설명**: `README.md` 첫 단락 또는 `package.json` 의 `description`
- **기술 스택**: 탐색에서 수집한 실제 값으로 채움. 모르면 `<확인 필요>` 유지
- **주요 기능**: `pages/` 또는 `app/pages/` 디렉토리 목록을 기반으로 유추
- **참고 문서**: `README.md` 에 링크가 있으면 옮기고, 없으면 `<확인 필요>` 유지
#### conventions.md
- **디렉토리 규칙**: 실제 디렉토리 구조에서 확인된 폴더만 설명, 없는 항목은 삭제
- **API 호출 창구**: `composables/` 또는 `api/` 디렉토리 패턴에서 유추
- **테스트 러너 / 위치**: `package.json` devDependencies + `vitest.config.*` 참고
- 공통 지침과 다른 점이 없다면 "공통 지침을 따른다" 로 간단히 기재
#### architecture.md
- **레이어 구조**: 실제 디렉토리 목록으로 ASCII 다이어그램을 업데이트
- **상태 관리 가이드**: 탐색에서 확인한 라이브러리로 표의 권장 위치를 채움
- **외부 의존성**: `server/api/` 파일명 또는 `useFetch` 호출에서 유추. 불확실하면 `<확인 필요>`
### 5. 완료 안내
```
✅ 문서 업데이트 완료
변경된 파일:
- CLAUDE.md
- .claude/project/overview.md
- .claude/project/conventions.md
- .claude/project/architecture.md
다음 단계:
1) 각 파일에서 <확인 필요> 항목을 직접 채워주세요.
2) 변경 사항을 커밋해 주세요:
git add CLAUDE.md .claude/project/
git commit -m "docs: 프로젝트 초기 문서 작성"
```
## 주의사항
- **파일 삭제 금지**: 기존 `.claude/project/*.md` 는 내용을 수정할 뿐 절대 삭제하지 않는다.
- **추측 표시**: 확실하지 않은 정보는 `(추정)` 을 붙이고, 사용자가 쉽게 찾아 수정할 수 있게 한다.
- **최소 변경**: 이미 올바르게 작성된 섹션은 건드리지 않는다.
- **커밋 금지**: 파일 수정 후 git commit 은 사용자 명시 요청이 없으면 실행하지 않는다.

View File

@@ -0,0 +1,115 @@
---
name: translation-keys
description: 번역 요청 엑셀 파일의 EN 셀을 기반으로 '번역코드' 컬럼에 함축적인 코드를 자동 생성합니다. 사용자가 "번역코드 만들어줘", "translation key 생성", "번역 키 추출" 등을 요청하면 트리거됩니다.
---
# 번역 코드 생성 (Translation Key Generator)
이 skill 은 번역 요청 엑셀 파일의 **EN 컬럼** 텍스트를 분석하여
`번역코드` 컬럼에 함축적이고 일관된 코드를 자동으로 작성합니다.
## 코드 생성 규칙
| 규칙 | 설명 | 예시 |
|------|------|------|
| **단어 수** | 3단어 이하 | `NAV-main` ✅ / `NAV-main-section-title` ❌ |
| **구분자** | 단어 사이 `-` (하이픈) | `EVENT-title` |
| **첫 단어** | 카테고리를 나타내는 **대문자** | `HERO`, `NAV`, `TOAST` |
| **함축성** | 텍스트의 핵심 의미를 최대한 압축 | `HERO-czn-title` (CHAOS ZERO NIGHTMARE → czn) |
## 카테고리 가이드
| 카테고리 | 사용 상황 | 예시 |
|----------|----------|------|
| `BRAND` | 브랜드명, 서비스 이름 | `BRAND-smilegate-ax` |
| `NAV` | 내비게이션, 메뉴 항목 | `NAV-main`, `NAV-location` |
| `EVENT` | 이벤트 정보 (제목/날짜/장소) | `EVENT-title`, `EVENT-date`, `EVENT-venue` |
| `HERO` | 히어로 배너 텍스트 | `HERO-miresi-title` |
| `SECTION` | 섹션 헤더/소제목 | `SECTION-intro` |
| `BTN` | 버튼 레이블 | `BTN-register`, `BTN-more` |
| `TOAST` | 토스트/알림 메시지 | `TOAST-link-copied`, `TOAST-paste-hint` |
| `LABEL` | 폼 레이블, 태그 | `LABEL-date`, `LABEL-venue` |
| `MSG` | 일반 안내 메시지 | `MSG-loading`, `MSG-empty` |
| `MODAL` | 모달/팝업 내 텍스트 | `MODAL-confirm-title` |
## 작업 순서
1. **파일 확인**
- 사용자가 엑셀 파일 경로를 제공했는지 확인
- 미제공 시: 파일 경로를 먼저 요청
2. **데이터 파악**
```python
import openpyxl
wb = openpyxl.load_workbook('파일경로.xlsx')
ws = wb.active
# 헤더 행에서 '번역코드', 'EN' 컬럼 인덱스 찾기
```
- 1행(헤더)에서 `번역코드` 컬럼과 `EN` 컬럼 위치를 동적으로 탐지
- 데이터가 있는 행(EN 값이 None이 아닌 행)만 처리
3. **코드 생성**
- EN 텍스트를 분석해 카테고리와 핵심 키워드 추출
- 이미 `번역코드` 값이 있는 행은 **덮어쓰지 않음** (사용자 확인 후 진행)
- 생성한 코드 목록을 사용자에게 미리 보여주고 승인 요청
4. **중복 코드 검사** ← 저장 전 반드시 수행
- 기존에 이미 작성된 코드 + 이번에 새로 생성한 코드를 **전체 합산**하여 중복 여부 검사
- 중복이 발견되면 **저장을 중단**하고 사용자에게 아래 형식으로 보고:
```
⚠️ 중복 코드 발견
- HERO-title: 3행, 12행 (2건)
- EVENT-date: 8행, 15행 (2건)
```
- 중복 해소 방법을 제안하고 사용자 승인 후 재생성
- 중복이 없으면 "중복 없음 확인" 메시지 출력 후 저장 진행
5. **엑셀 저장**
- 사용자 승인 후 `번역코드` 컬럼에 값 기입 및 저장
- 저장 완료 메시지와 변경 내역 요약 출력
## 코드 작성 예시 (실제 케이스)
| EN 텍스트 | 생성 코드 | 근거 |
|-----------|----------|------|
| `Smilegate x AX` | `BRAND-smilegate-ax` | 브랜드명 전체 |
| `Main` | `NAV-main` | 내비 메인 항목 |
| `Program & Events` | `NAV-program-events` | 내비 항목, 특수문자 제거 |
| `Smilegate x Anime Expo` | `EVENT-title` | 이벤트 대표 제목 |
| `07/02/2026 (THU)~ 07/05/2026 (SUN)` | `EVENT-date` | 날짜 데이터 |
| `Los Angeles Convention Center` | `EVENT-venue` | 행사 장소 |
| `The link has been copied.` | `TOAST-link-copied` | 토스트 알림, 링크 복사 완료 |
| `You may now paste it elsewhere.` | `TOAST-paste-hint` | 토스트 알림, 붙여넣기 안내 |
| `MIRESI ARRIVES AT <br> ANIME EXPO!` | `HERO-miresi-title` | 히어로 배너, 캐릭터명 |
| `CHAOS ZERO NIGHTMARE ARRIVES AT <br> ANIME EXPO!` | `HERO-czn-title` | 히어로 배너, 약어 처리 |
## 처리 스크립트
스크립트 파일: `scripts/generate_translation_keys.py`
```bash
python scripts/generate_translation_keys.py <엑셀파일경로>
```
스크립트 주요 함수:
| 함수 | 역할 |
|------|------|
| `load_existing_codes(ws, code_col)` | 기존 번역 코드를 `{행번호: 코드}` 로 수집 |
| `check_duplicates(existing, new)` | 기존+신규 코드 합산 중복 검사, 결과 반환 |
| `run(filepath, new_codes)` | 중복 검사 → 저장 실행 (중복 시 중단) |
> `new_codes` 딕셔너리는 Claude AI가 EN 텍스트를 분석하여 직접 채웁니다.
> 스크립트는 중복 검사와 저장만 담당합니다.
## 주의사항
- **행 순서 고정**: 엑셀의 기존 행 순서를 절대 변경하지 않는다. 코드는 원래 행 위치에 그대로 기입한다.
- **이미지 셀 보존**: 셀에 이미지가 삽입된 경우 해당 셀 및 시트의 이미지를 덮어쓰거나 삭제하지 않는다. `openpyxl.load_workbook(path, keep_vba=True)` 옵션을 사용하고, 이미지 객체(`ws._images`)를 건드리지 않는다.
- **기존 코드 보존**: 이미 `번역코드` 값이 있는 셀은 덮어쓰지 않는다.
- **중복 코드 방지**: 동일한 코드가 두 행에 생기지 않도록 확인한다.
- **HTML 태그 무시**: `<br>`, `<b>` 등 마크업 태그는 의미 분석에서 제외한다.
- **날짜/숫자 데이터**: 날짜 형식 셀은 `EVENT-date`, `LABEL-date` 등 의미 기반으로 처리한다.
- **약어 처리**: 3단어 초과 시 캐릭터명·고유명사를 약어(초성/이니셜)로 압축한다.
- 예) `CHAOS ZERO NIGHTMARE` → `czn`
- 사용자가 코드를 직접 수정 요청하면 수정 후 재저장한다.

View File

@@ -0,0 +1,142 @@
"""
번역 코드 자동 생성 스크립트
사용법: python generate_translation_keys.py <엑셀파일경로>
주의:
- 행 순서를 변경하지 않는다 (원래 행 위치에만 값 기입)
- 셀에 삽입된 이미지를 보존한다 (ws._images 미수정)
"""
import sys
import openpyxl
def generate_translation_key(en_text: str) -> str:
"""
EN 텍스트를 분석하여 번역 코드를 생성합니다.
규칙:
- 3단어 이하 (CATEGORY-word1-word2)
- 단어 사이 '-' 구분
- 첫 단어는 카테고리 대문자
- 함축적인 의미로 생성
NOTE: 이 함수는 템플릿입니다.
실제 코드 생성은 Claude AI가 EN 텍스트의 의미를 분석하여 수행합니다.
"""
raise NotImplementedError("AI가 EN 텍스트를 분석하여 코드를 직접 생성합니다.")
def load_existing_codes(ws, code_col: int) -> dict[int, str]:
"""기존에 입력된 번역 코드를 {행번호: 코드} 형태로 반환합니다."""
return {
row: ws.cell(row=row, column=code_col).value
for row in range(2, ws.max_row + 1)
if ws.cell(row=row, column=code_col).value
}
def check_duplicates(existing: dict[int, str], new: dict[int, str]) -> dict[str, list[int]]:
"""
기존 코드 + 신규 코드 전체를 합산하여 중복 검사합니다.
반환: {중복코드: [행번호, ...]}
"""
seen: dict[str, int] = {}
duplicates: dict[str, list[int]] = {}
for row_num, code in {**existing, **new}.items():
if code in seen:
duplicates.setdefault(code, [seen[code]]).append(row_num)
else:
seen[code] = row_num
return duplicates
def run(filepath: str, new_codes: dict[int, str]) -> None:
"""
신규 코드를 중복 검사 후 엑셀에 저장합니다.
Args:
filepath: 엑셀 파일 경로
new_codes: {행번호: 생성된코드} 딕셔너리
"""
# keep_vba=True: 이미지·VBA 등 파일 내 임베딩 요소를 보존
wb = openpyxl.load_workbook(filepath, keep_vba=True)
ws = wb.active
# 이미지가 있는 셀 좌표를 미리 수집 (덮어쓰기 방지)
image_cells: set[tuple[int, int]] = set()
for img in getattr(ws, '_images', []):
anchor = img.anchor
if hasattr(anchor, '_from'):
image_cells.add((anchor._from.row + 1, anchor._from.col + 1)) # 1-based
# 헤더에서 컬럼 인덱스 탐지
headers = [cell.value for cell in ws[1]]
if '번역코드' not in headers or 'EN' not in headers:
print("❌ 헤더에 '번역코드' 또는 'EN' 컬럼이 없습니다.")
sys.exit(1)
code_col = headers.index('번역코드') + 1 # 1-based
en_col = headers.index('EN') + 1 # 1-based
# 기존 코드 수집
existing_codes = load_existing_codes(ws, code_col)
# 빈 행 / 이미 코드 있는 행 필터링
rows_to_fill: list[tuple[int, str]] = []
for row in ws.iter_rows(min_row=2):
row_num = row[0].row
en_val = row[en_col - 1].value
code_val = row[code_col - 1].value
if not en_val:
continue # 빈 행 스킵
if code_val:
continue # 기존 코드 보존
if (row_num, code_col) in image_cells:
print(f" ⚠️ Row {row_num}: 이미지 셀 — 스킵 (보존)")
continue # 이미지 있는 셀 보존
if row_num in new_codes:
rows_to_fill.append((row_num, new_codes[row_num]))
if not rows_to_fill:
print(" 입력할 신규 코드가 없습니다.")
return
# 중복 검사
new_codes_filtered = dict(rows_to_fill)
duplicates = check_duplicates(existing_codes, new_codes_filtered)
if duplicates:
print("⚠️ 중복 코드 발견 — 저장 중단")
for code, rows in duplicates.items():
print(f" - {code}: {', '.join(map(str, rows))}행 ({len(rows)}건)")
print("\n중복을 해소한 뒤 다시 실행해 주세요.")
sys.exit(1)
# 중복 없음 → 저장
print("✅ 중복 없음 확인")
for row_num, code in rows_to_fill:
ws.cell(row=row_num, column=code_col, value=code)
en_text = ws.cell(row=row_num, column=en_col).value
print(f" Row {row_num}: {code:<30}\"{en_text}\"")
wb.save(filepath)
print(f"\n저장 완료: {filepath}")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("사용법: python generate_translation_keys.py <엑셀파일경로>")
sys.exit(1)
# new_codes는 Claude AI가 EN 텍스트를 분석하여 채워줍니다.
# 예시:
# new_codes = {
# 2: 'BRAND-smilegate-ax',
# 3: 'NAV-main',
# }
new_codes: dict[int, str] = {}
run(sys.argv[1], new_codes)