CommitGen — NPM 배포 & 회고
이전 글 요약
1편에서 설계, 2편에서 핵심 구현을 다뤘다. 이번 편에서는 NPM 패키지 배포 과정과 프로젝트 전체 회고를 정리한다.
NPM 패키지 설정
package.json 핵심 필드
{
"name": "@lukaplayground/commitgen",
"version": "1.0.0",
"type": "module",
"main": "src/index.js",
"bin": {
"commitgen": "bin/commitgen.js"
},
"files": [
"bin/",
"src/",
"README.md",
"LICENSE"
],
"engines": {
"node": ">=18.0.0"
}
}
각 필드의 역할:
| 필드 | 값 | 설명 |
|---|---|---|
| name | @lukaplayground/commitgen | scoped 패키지 (조직명 네임스페이스) |
| type | module | ESM 모듈 시스템 사용 |
| bin | commitgen → bin/commitgen.js | npx commitgen 또는 글로벌 설치 시 명령어 등록 |
| files | bin/, src/, README, LICENSE | 배포 시 포함할 파일 (node_modules 제외) |
| engines | >=18.0.0 | ESM + top-level await 최소 요구사항 |
bin 필드의 동작 원리
"bin": {
"commitgen": "bin/commitgen.js"
}
이 설정이 하는 일:
npm install -g @lukaplayground/commitgen→ 시스템 PATH에commitgen명령어 등록npx @lukaplayground/commitgen→ 임시 설치 후bin/commitgen.js실행bin/commitgen.js파일 상단의#!/usr/bin/env node→ Node.js로 실행
files 필드로 배포 크기 최적화
files 배열을 명시하지 않으면 .gitignore에 없는 모든 파일이 배포된다. 테스트 파일, 설정 파일, 문서 등이 불필요하게 포함될 수 있다.
files 미지정: ~2MB (node_modules 제외해도 잡다한 파일 포함)
files 지정: ~25KB (필요한 소스만)배포 전 체크리스트
NPM에 배포하기 전에 확인한 항목:
| 항목 | 확인 |
|---|---|
node bin/commitgen.js --version 정상 출력 |
1.0.0 |
node bin/commitgen.js --help 명령어 목록 표시 |
generate, config |
.gitignore에 node_modules/, .env 포함 |
확인 |
files 필드로 배포 범위 제한 |
bin/, src/ |
engines로 Node.js 최소 버전 명시 |
>=18.0.0 |
| README.md에 설치/사용법 작성 | 확인 |
| LICENSE 파일 포함 | MIT |
npm pack으로 사전 확인
실제 배포 전에 npm pack으로 패키지에 어떤 파일이 포함되는지 확인할 수 있다.
$ npm pack --dry-run
npm notice Tarball Contents
npm notice 1.1kB LICENSE
npm notice 2.3kB README.md
npm notice 1.2kB bin/commitgen.js
npm notice 1.7kB package.json
npm notice 4.2kB src/index.js
npm notice 3.1kB src/commands/configure.js
npm notice 1.8kB src/utils/ai.js
npm notice 2.1kB src/utils/config.js
npm notice 3.2kB src/utils/gitDiff.js
npm notice 1.4kB src/utils/prompt.js
의도한 파일만 포함되는지, 민감한 파일(.env, API 키)이 빠졌는지 확인한다.
사용법
설치
# 글로벌 설치 (추천)
npm install -g @lukaplayground/commitgen
# 또는 npx로 바로 실행
npx @lukaplayground/commitgen
초기 설정
$ commitgen config
⚙️ CommitGen Configuration
? Default AI provider: OpenAI (GPT-4o-mini)
? Default commit message language: English
? Include emoji in commit messages? Yes
? Set up API keys now? Yes
? OpenAI API key (not set): ********
? Claude (Anthropic) API key (not set):
? Gemini (Google) API key (not set):
✅ Configuration saved to ~/.commitgen/config.json
일상 사용
# 기본 사용
git add .
commitgen
# 한국어 커밋 메시지
commitgen -l ko
# Claude로 생성
commitgen -p claude
# 메시지만 확인 (커밋 안 함)
commitgen --dry-run
# 이모지 없이
commitgen --no-emoji
CI/CD 환경
CI에서는 설정 파일 대신 환경 변수를 사용한다.
# GitHub Actions 예시
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
steps:
- run: npx @lukaplayground/commitgen --dry-run
실제 생성 결과 비교
같은 diff로 3개 프로바이더의 결과를 비교했다.
테스트 diff
+export function isExpired(entry, ttl = 3600000) {
+ return Date.now() - entry.timestamp > ttl;
+}
+
+export function cleanExpired(cache, ttl) {
+ return Object.fromEntries(
+ Object.entries(cache).filter(([_, v]) => !isExpired(v, ttl))
+ );
+}
프로바이더별 결과
| 프로바이더 | 생성된 메시지 |
|---|---|
| OpenAI (gpt-4o-mini) | ✨ feat(cache): add TTL-based expiration and cleanup utilities |
| Claude (sonnet 3.5) | ✨ feat(cache): add cache entry expiration with TTL support |
| Gemini (1.5 flash) | ✨ feat: add cache expiration logic with TTL |
세 프로바이더 모두 feat 타입을 정확히 잡았다. Claude가 가장 구체적인 scope를 넣었고, Gemini는 scope를 생략했다. OpenAI는 두 함수의 역할을 모두 커버하는 메시지를 생성했다.
프로젝트 회고
잘된 점
1. AIKit이 진짜 편했다
AI 호출 코드가 ai.js 파일 하나, 57줄이다. OpenAI SDK를 직접 썼으면 이것만으로도 150줄은 넘었을 것이다. 프로바이더 전환도 설정 한 줄이면 끝이라 테스트가 쉬웠다.
2. 모듈 분리가 효과적
gitDiff.js → git 관련만
prompt.js → 프롬프트 빌드만
ai.js → AI 호출만
config.js → 설정 관리만
index.js → 조합만각 모듈이 단일 책임을 갖고 있어서 수정 시 영향 범위가 명확했다. 프롬프트를 바꿀 때 prompt.js만 건드리면 되고, AI 프로바이더를 추가할 때는 AIKit 쪽만 업데이트하면 된다.
3. 559줄로 완성
전체 소스가 559줄이다. 의존성 관리를 AIKit과 잘 알려진 CLI 라이브러리들에 맡긴 덕분이다.
아쉬운 점
1. 오프라인에서 사용 불가
AI API에 의존하므로 네트워크 없으면 동작하지 않는다. 로컬 모델(Ollama 등)을 지원하면 해결되지만, 현재 AIKit이 로컬 모델을 지원하지 않아서 보류했다.
2. 대규모 diff의 품질
8000자 truncate 후 AI에 넘기면, 잘린 부분의 변경사항이 커밋 메시지에 반영되지 않는다. 파일 목록과 stats를 같이 넘기는 것으로 어느 정도 보완되지만, 완벽하지는 않다.
3. 모노레포 대응
여러 패키지가 있는 모노레포에서는 하나의 커밋 메시지로 묶기 어려운 경우가 있다. scope를 패키지별로 분리하거나, 여러 커밋으로 나누는 기능이 필요할 수 있다.
향후 계획
| 기능 | 우선순위 | 설명 |
|---|---|---|
| git hook 연동 | 높음 | prepare-commit-msg 훅으로 자동 실행 |
| 커밋 히스토리 학습 | 중간 | 기존 커밋 스타일에 맞춰 생성 |
| Ollama 지원 | 중간 | 로컬 AI 모델로 오프라인 사용 |
| 템플릿 커스터마이징 | 낮음 | 팀별 커밋 메시지 규칙 반영 |
전체 시리즈 정리
| 편 | 주제 | 핵심 |
|---|---|---|
| #1 | 왜 만들었나 + 설계 | git diff 파싱, CLI 아키텍처, AIKit 연동 설계 |
| #2 | 핵심 구현 | Commander.js, 프롬프트 엔지니어링, Before/After |
| #3 | NPM 배포 & 회고 (이 글) | 패키지 퍼블리싱, 사용법, 삽질 기록 |
마무리
"내가 만든 라이브러리로 내가 쓸 도구를 만든다"는 목표를 달성했다. AIKit → CommitGen으로 이어지는 흐름이 자연스러웠고, 실전에서 AIKit의 장단점도 체감할 수 있었다.
559줄, 의존성 5개, 프로바이더 3개 지원. 작은 도구지만, 매일 쓰는 git commit을 개선하는 도구라 체감 효과가 크다.
기술 스택: Node.js, AIKit, Commander.js, Inquirer.js, Chalk, Ora
소스 코드: GitHub
NPM: npm install -g @lukaplayground/commitgen
'프로젝트 > CLI 도구' 카테고리의 다른 글
| CommitGen #2 - 핵심 구현 (0) | 2026.02.13 |
|---|---|
| CommitGen #1 - 왜 커밋 메시지 생성기를 만들었나 (0) | 2026.02.12 |