@yeongjaeyou/claude-code-config 0.1.0 → 0.1.2

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.
@@ -19,16 +19,23 @@ PR이 머지된 후 브랜치 정리와 CLAUDE.md 업데이트를 수행합니
19
19
  - `gh pr view <PR번호> --json number,title,baseRefName,headRefName,body,state`로 PR 정보 확인
20
20
  - `state`가 MERGED인지 확인
21
21
 
22
- 2. **베이스 브랜치로 이동**
22
+ 2. **로컬 변경사항 확인**
23
+ - `git status --porcelain`으로 uncommitted 변경사항 확인
24
+ - 변경사항이 있으면 AskUserQuestion으로 처리 방법 질문:
25
+ - **stash 후 진행**: `git stash push -m "post-merge: 임시 저장"` 후 베이스 브랜치 이동, 작업 완료 후 `git stash pop`
26
+ - **변경사항 버리기**: `git checkout -- . && git clean -fd`
27
+ - **작업 중단**: 사용자가 직접 처리하도록 중단
28
+
29
+ 3. **베이스 브랜치로 이동**
23
30
  - `git fetch origin`
24
31
  - `git checkout <baseRefName>`
25
32
  - `git pull origin <baseRefName>`
26
33
 
27
- 3. **이슈 브랜치 정리 (선택)**
34
+ 4. **이슈 브랜치 정리 (선택)**
28
35
  - AskUserQuestion으로 로컬 브랜치 삭제 여부 질문
29
36
  - 삭제 원하면: `git branch -d <headRefName>`
30
37
 
31
- 4. **CLAUDE.md 분석 및 업데이트**
38
+ 5. **CLAUDE.md 분석 및 업데이트**
32
39
  - CLAUDE.md 존재 여부 확인
33
40
  - 없으면: AskUserQuestion으로 생성 여부 또는 스킵 여부 질문
34
41
  - 기존 내용 분석:
@@ -41,7 +48,7 @@ PR이 머지된 후 브랜치 정리와 CLAUDE.md 업데이트를 수행합니
41
48
  - **수정 대상**: 오래되거나 부정확한 정보
42
49
  - AskUserQuestion으로 제안 내용 확인 후 적용
43
50
 
44
- 5. **변경사항 커밋 (선택)**
51
+ 6. **변경사항 커밋 (선택)**
45
52
  - CLAUDE.md가 변경되었으면 AskUserQuestion으로 커밋 여부 질문
46
53
  - 커밋 원하면: Conventional Commits 형식으로 커밋
47
54
 
package/bin/cli.js CHANGED
@@ -8,6 +8,9 @@ const readline = require('readline');
8
8
  const pkg = require('../package.json');
9
9
  const args = process.argv.slice(2);
10
10
 
11
+ // 설치 대상 폴더 (사용자 데이터가 아닌 것들만)
12
+ const INSTALL_FOLDERS = ['commands', 'agents', 'skills'];
13
+
11
14
  // 옵션 파싱
12
15
  const isGlobal = args.includes('--global') || args.includes('-g');
13
16
  const showHelp = args.includes('--help') || args.includes('-h');
@@ -35,6 +38,14 @@ Claude Code Config v${pkg.version}
35
38
  예시:
36
39
  npx @yeongjaeyou/claude-code-config # 현재 프로젝트에 설치
37
40
  npx @yeongjaeyou/claude-code-config --global # 전역 설치
41
+
42
+ 설치되는 폴더:
43
+ - commands/ : 슬래시 커맨드
44
+ - agents/ : 커스텀 에이전트
45
+ - skills/ : 스킬 (재사용 가능한 도구 모음)
46
+
47
+ 참고:
48
+ --global 설치 시 기존 사용자 데이터(settings.json, history.jsonl 등)는 보존됩니다.
38
49
  `);
39
50
  process.exit(0);
40
51
  }
@@ -52,8 +63,8 @@ const dest = isGlobal
52
63
  function askQuestion(question) {
53
64
  // 비대화형 환경 감지 (CI/CD, 파이프라인 등)
54
65
  if (!process.stdin.isTTY) {
55
- console.log('비대화형 환경이 감지되었습니다. 기본값(Y)을 사용합니다.');
56
- return Promise.resolve('');
66
+ console.log('비대화형 환경이 감지되었습니다. 기본값(merge)을 사용합니다.');
67
+ return Promise.resolve('merge');
57
68
  }
58
69
 
59
70
  const rl = readline.createInterface({
@@ -69,6 +80,91 @@ function askQuestion(question) {
69
80
  });
70
81
  }
71
82
 
83
+ /**
84
+ * 기존 설치 폴더 확인
85
+ * @returns {string[]} - 존재하는 폴더 목록
86
+ */
87
+ function checkExistingFolders() {
88
+ const existing = [];
89
+ for (const folder of INSTALL_FOLDERS) {
90
+ const folderPath = path.join(dest, folder);
91
+ if (fs.existsSync(folderPath)) {
92
+ existing.push(folder);
93
+ }
94
+ }
95
+ return existing;
96
+ }
97
+
98
+ /**
99
+ * 폴더 복사 (재귀적)
100
+ * @param {string} src - 소스 경로
101
+ * @param {string} dst - 대상 경로
102
+ * @param {boolean} mergeMode - 병합 모드 여부
103
+ */
104
+ function copyFolder(src, dst, mergeMode = false) {
105
+ if (!fs.existsSync(src)) {
106
+ return;
107
+ }
108
+
109
+ // 대상 폴더 생성
110
+ if (!fs.existsSync(dst)) {
111
+ try {
112
+ fs.mkdirSync(dst, { recursive: true });
113
+ } catch (err) {
114
+ throw new Error(`폴더 생성 실패: ${dst} - ${err.message}`);
115
+ }
116
+ }
117
+
118
+ const entries = fs.readdirSync(src, { withFileTypes: true });
119
+
120
+ for (const entry of entries) {
121
+ const srcPath = path.join(src, entry.name);
122
+ const dstPath = path.join(dst, entry.name);
123
+
124
+ if (entry.isDirectory()) {
125
+ copyFolder(srcPath, dstPath, mergeMode);
126
+ } else {
127
+ // 병합 모드에서는 기존 파일 유지
128
+ if (mergeMode && fs.existsSync(dstPath)) {
129
+ continue;
130
+ }
131
+ try {
132
+ fs.copyFileSync(srcPath, dstPath);
133
+ } catch (err) {
134
+ throw new Error(`파일 복사 실패: ${srcPath} -> ${dstPath} - ${err.message}`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 설치 대상 폴더만 선택적으로 복사
142
+ * @param {string} mode - 'merge' | 'overwrite'
143
+ */
144
+ function installFolders(mode) {
145
+ const mergeMode = mode === 'merge';
146
+
147
+ for (const folder of INSTALL_FOLDERS) {
148
+ const srcFolder = path.join(source, folder);
149
+ const dstFolder = path.join(dest, folder);
150
+
151
+ if (!fs.existsSync(srcFolder)) {
152
+ continue;
153
+ }
154
+
155
+ // 덮어쓰기 모드에서는 기존 폴더 삭제 후 복사
156
+ if (!mergeMode && fs.existsSync(dstFolder)) {
157
+ try {
158
+ fs.rmSync(dstFolder, { recursive: true });
159
+ } catch (err) {
160
+ throw new Error(`폴더 삭제 실패: ${dstFolder} - ${err.message}`);
161
+ }
162
+ }
163
+
164
+ copyFolder(srcFolder, dstFolder, mergeMode);
165
+ }
166
+ }
167
+
72
168
  /**
73
169
  * 메인 함수
74
170
  */
@@ -93,24 +189,58 @@ async function main() {
93
189
  console.log(`설치 경로: ${dest}`);
94
190
  console.log('');
95
191
 
96
- // 대상 폴더가 이미 존재하는 경우
97
- if (fs.existsSync(dest)) {
98
- console.log('기존 .claude/ 폴더가 발견되었습니다.');
192
+ // 대상 폴더 생성 (없으면)
193
+ if (!fs.existsSync(dest)) {
194
+ try {
195
+ fs.mkdirSync(dest, { recursive: true });
196
+ } catch (err) {
197
+ console.error(`오류: 대상 폴더를 생성할 수 없습니다: ${dest}`);
198
+ console.error(`상세: ${err.message}`);
199
+ process.exit(1);
200
+ }
201
+ }
202
+
203
+ // 기존 설치 폴더 확인
204
+ const existingFolders = checkExistingFolders();
205
+ let installMode = 'overwrite';
99
206
 
100
- const answer = await askQuestion('덮어쓰시겠습니까? (Y/n): ');
207
+ if (existingFolders.length > 0) {
208
+ console.log('기존 설치 폴더가 발견되었습니다:');
209
+ existingFolders.forEach(folder => {
210
+ console.log(` - ${folder}/`);
211
+ });
212
+ console.log('');
101
213
 
102
- // 빈 값(Enter)이거나 y/Y면 덮어쓰기
103
- if (answer === '' || answer === 'y') {
104
- fs.rmSync(dest, { recursive: true });
105
- console.log('기존 폴더를 삭제했습니다.');
106
- } else {
214
+ if (isGlobal) {
215
+ console.log('(사용자 데이터는 보존됩니다: settings.json, history.jsonl 등)');
216
+ console.log('');
217
+ }
218
+
219
+ console.log('설치 옵션:');
220
+ console.log(' [m] merge - 새 파일만 추가 (기존 파일 유지)');
221
+ console.log(' [o] overwrite - 위 폴더들만 덮어쓰기');
222
+ console.log(' [c] cancel - 설치 취소');
223
+ console.log('');
224
+
225
+ const answer = await askQuestion('선택하세요 (m/o/c) [기본: m]: ');
226
+
227
+ if (answer === 'c' || answer === 'cancel') {
107
228
  console.log('설치가 취소되었습니다.');
108
229
  process.exit(0);
230
+ } else if (answer === 'o' || answer === 'overwrite') {
231
+ installMode = 'overwrite';
232
+ console.log('');
233
+ console.log('덮어쓰기 모드로 설치합니다...');
234
+ } else {
235
+ // 기본값: merge (빈 값, 'm', 'merge' 등)
236
+ installMode = 'merge';
237
+ console.log('');
238
+ console.log('병합 모드로 설치합니다 (기존 파일 유지)...');
109
239
  }
110
240
  }
111
241
 
112
- // 폴더 복사
113
- fs.cpSync(source, dest, { recursive: true });
242
+ // 폴더 설치
243
+ installFolders(installMode);
114
244
 
115
245
  console.log('');
116
246
  console.log('.claude/ 폴더가 성공적으로 설치되었습니다!');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeongjaeyou/claude-code-config",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Claude Code CLI custom commands, agents, and skills",
5
5
  "bin": {
6
6
  "claude-code-config": "./bin/cli.js"