@choblue/claude-code-toolkit 1.1.0 → 1.1.1

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.
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "~/.claude/hooks/quality-gate.sh"
9
+ "command": ".claude/hooks/quality-gate.sh"
10
10
  }
11
11
  ]
12
12
  }
package/install.sh CHANGED
@@ -1,17 +1,18 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  # install.sh - my-claude-code-toolkit을 .claude/에 설치한다
3
- # Usage: ./install.sh [--global] [--fe] [--be]
3
+ # Usage: ./install.sh [--global] [--fe] [--be] [--force]
4
4
  # 기본값: 현재 디렉토리의 .claude/에 전체 설치 (프로젝트 로컬)
5
5
  # --global: ~/.claude/에 설치 (글로벌)
6
6
  # --fe: 공통 + 프론트엔드 스킬만 설치
7
7
  # --be: 공통 + 백엔드 스킬만 설치
8
8
  # --fe --be: 전체 설치 (= 기본값)
9
+ # --force: 사용자 수정 파일도 강제 덮어쓰기
9
10
 
10
11
  set -e
11
12
 
12
13
  # 도움말 출력
13
14
  usage() {
14
- echo "Usage: $0 [--global] [--fe] [--be]"
15
+ echo "Usage: $0 [--global] [--fe] [--be] [--force]"
15
16
  echo ""
16
17
  echo "스택 선택:"
17
18
  echo " (기본값) 전체 설치 (공통 + FE + BE)"
@@ -23,11 +24,15 @@ usage() {
23
24
  echo " (기본값) 현재 디렉토리의 .claude/에 설치 (프로젝트 로컬)"
24
25
  echo " --global ~/.claude/에 설치 (글로벌)"
25
26
  echo ""
27
+ echo "옵션:"
28
+ echo " --force 사용자 수정 파일도 강제 덮어쓰기"
29
+ echo ""
26
30
  echo "예시:"
27
31
  echo " $0 # 전체 설치 (로컬)"
28
32
  echo " $0 --fe # 공통 + FE만 (로컬)"
29
33
  echo " $0 --be # 공통 + BE만 (로컬)"
30
34
  echo " $0 --global --fe # 공통 + FE만 (글로벌)"
35
+ echo " $0 --force # 수정된 파일도 강제 덮어쓰기"
31
36
  exit 0
32
37
  }
33
38
 
@@ -35,6 +40,7 @@ usage() {
35
40
  INSTALL_MODE="local"
36
41
  INSTALL_FE=false
37
42
  INSTALL_BE=false
43
+ FORCE_OVERWRITE=false
38
44
 
39
45
  for arg in "$@"; do
40
46
  case "$arg" in
@@ -47,6 +53,9 @@ for arg in "$@"; do
47
53
  --be)
48
54
  INSTALL_BE=true
49
55
  ;;
56
+ --force)
57
+ FORCE_OVERWRITE=true
58
+ ;;
50
59
  --help|-h)
51
60
  usage
52
61
  ;;
@@ -81,11 +90,9 @@ fi
81
90
 
82
91
  if [ "$INSTALL_MODE" = "global" ]; then
83
92
  TARGET_DIR="$HOME/.claude"
84
- BACKUP_DIR="$HOME/.claude-backup-$(date +%Y%m%d_%H%M%S)"
85
93
  MODE_LABEL="글로벌 설치 (~/.claude/)"
86
94
  else
87
95
  TARGET_DIR="$(pwd)/.claude"
88
- BACKUP_DIR="$(pwd)/.claude-backup-$(date +%Y%m%d_%H%M%S)"
89
96
  MODE_LABEL="로컬 설치 ($(pwd)/.claude/)"
90
97
  fi
91
98
 
@@ -103,52 +110,112 @@ if [ ! -d "$SOURCE_DIR" ]; then
103
110
  exit 1
104
111
  fi
105
112
 
106
- # 기존 파일 백업
107
- if [ -d "$TARGET_DIR" ]; then
108
- # 백업할 파일이 있는지 확인 (agents, skills, hooks, CLAUDE.md, settings.json)
109
- HAS_EXISTING=false
110
- for item in CLAUDE.md settings.json agents skills hooks; do
111
- if [ -e "$TARGET_DIR/$item" ]; then
112
- HAS_EXISTING=true
113
- break
114
- fi
115
- done
113
+ # TARGET_DIR 생성
114
+ mkdir -p "$TARGET_DIR"
115
+
116
+ # === 해시 함수 ===
117
+ file_hash() {
118
+ if command -v shasum &>/dev/null; then
119
+ shasum -a 256 "$1" | cut -d' ' -f1
120
+ elif command -v sha256sum &>/dev/null; then
121
+ sha256sum "$1" | cut -d' ' -f1
122
+ else
123
+ # fallback: md5
124
+ md5 -q "$1" 2>/dev/null || md5sum "$1" | cut -d' ' -f1
125
+ fi
126
+ }
116
127
 
117
- if [ "$HAS_EXISTING" = true ]; then
118
- echo "기존 설정 파일이 발견되었습니다. 백업합니다..."
119
- mkdir -p "$BACKUP_DIR"
120
- for item in CLAUDE.md settings.json agents skills hooks; do
121
- if [ -e "$TARGET_DIR/$item" ]; then
122
- cp -r "$TARGET_DIR/$item" "$BACKUP_DIR/"
123
- echo " 백업: $item → $BACKUP_DIR/$item"
124
- fi
125
- done
126
- echo ""
127
- echo "백업 완료: $BACKUP_DIR"
128
+ # === 매니페스트 관리 ===
129
+ MANIFEST_FILE="$TARGET_DIR/.toolkit-manifest"
130
+ NEW_MANIFEST=""
131
+
132
+ # 이전 매니페스트 로드 (grep 기반으로 bash 3.x 호환)
133
+ # OLD_MANIFEST_CONTENT: 한 줄에 "<sha256hash> <relative_path>" 형식
134
+ OLD_MANIFEST_CONTENT=""
135
+ if [ -f "$MANIFEST_FILE" ]; then
136
+ OLD_MANIFEST_CONTENT="$(cat "$MANIFEST_FILE")"
137
+ fi
138
+
139
+ # 이전 매니페스트에서 특정 파일의 해시를 조회
140
+ old_manifest_hash() {
141
+ local path="$1"
142
+ if [ -z "$OLD_MANIFEST_CONTENT" ]; then
128
143
  echo ""
144
+ return
129
145
  fi
130
- else
131
- mkdir -p "$TARGET_DIR"
132
- fi
146
+ echo "$OLD_MANIFEST_CONTENT" | grep " ${path}$" | head -1 | cut -d' ' -f1
147
+ }
133
148
 
134
149
  # === 헬퍼 함수 ===
135
150
 
136
- # 개별 파일 복사 (상대경로 기준)
151
+ # 개별 파일 복사 (상대경로 기준, 매니페스트 체크섬 비교)
137
152
  copy_file() {
138
153
  local rel_path="$1"
139
154
  local dir
140
155
  dir="$(dirname "$rel_path")"
141
156
  mkdir -p "$TARGET_DIR/$dir"
142
- cp "$SOURCE_DIR/$rel_path" "$TARGET_DIR/$rel_path"
143
- echo " 복사: $rel_path"
157
+
158
+ local target_file="$TARGET_DIR/$rel_path"
159
+ local source_file="$SOURCE_DIR/$rel_path"
160
+
161
+ if [ -f "$target_file" ]; then
162
+ local old_hash
163
+ old_hash="$(old_manifest_hash "$rel_path")"
164
+
165
+ if [ -n "$old_hash" ]; then
166
+ # 매니페스트에 기록이 있음 → 사용자 수정 여부 확인
167
+ local current_hash
168
+ current_hash="$(file_hash "$target_file")"
169
+
170
+ if [ "$current_hash" = "$old_hash" ]; then
171
+ # 사용자가 수정하지 않음 → 새 버전으로 덮어씀
172
+ cp "$source_file" "$target_file"
173
+ echo " 복사: $rel_path"
174
+ else
175
+ # 사용자가 수정함
176
+ if [ "$FORCE_OVERWRITE" = true ]; then
177
+ cp "$target_file" "$target_file.bak"
178
+ cp "$source_file" "$target_file"
179
+ echo " ⚠️ $rel_path - 사용자 수정 감지, 강제 덮어씀"
180
+ else
181
+ echo " ⚠️ $rel_path - 사용자 수정 감지, 건너뜀 (강제: --force)"
182
+ # 건너뛴 파일도 매니페스트에는 현재 해시로 기록 (추적 유지)
183
+ NEW_MANIFEST="${NEW_MANIFEST}${current_hash} ${rel_path}"$'\n'
184
+ return
185
+ fi
186
+ fi
187
+ else
188
+ # 매니페스트에 기록 없음 (첫 설치 or 매니페스트 없음) → 그냥 복사
189
+ cp "$source_file" "$target_file"
190
+ echo " 복사: $rel_path"
191
+ fi
192
+ else
193
+ # 대상 파일이 존재하지 않음 → 그냥 복사
194
+ cp "$source_file" "$target_file"
195
+ echo " 복사: $rel_path"
196
+ fi
197
+
198
+ # 복사 성공한 파일의 해시를 새 매니페스트에 추가
199
+ local new_hash
200
+ new_hash="$(file_hash "$target_file")"
201
+ NEW_MANIFEST="${NEW_MANIFEST}${new_hash} ${rel_path}"$'\n'
144
202
  }
145
203
 
146
- # 디렉토리 전체 복사 (상대경로 기준)
204
+ # 디렉토리 전체 복사 (개별 파일 단위로 처리하여 매니페스트에 기록)
147
205
  copy_dir() {
148
206
  local rel_path="$1"
149
- mkdir -p "$TARGET_DIR/$rel_path"
150
- cp -r "$SOURCE_DIR/$rel_path/"* "$TARGET_DIR/$rel_path/"
151
- echo " 복사: $rel_path/"
207
+ local file
208
+ for file in "$SOURCE_DIR/$rel_path/"*; do
209
+ if [ -f "$file" ]; then
210
+ local filename
211
+ filename="$(basename "$file")"
212
+ copy_file "$rel_path/$filename"
213
+ elif [ -d "$file" ]; then
214
+ local dirname
215
+ dirname="$(basename "$file")"
216
+ copy_dir "$rel_path/$dirname"
217
+ fi
218
+ done
152
219
  }
153
220
 
154
221
  # === 복사 함수 ===
@@ -234,6 +301,25 @@ if [ "$INSTALL_BE" = true ]; then
234
301
  echo ""
235
302
  fi
236
303
 
304
+ # === 오래된 파일 정리 ===
305
+ # 이전 매니페스트에는 있지만 새 매니페스트에는 없는 파일 삭제
306
+ if [ -n "$OLD_MANIFEST_CONTENT" ]; then
307
+ while IFS=' ' read -r old_hash old_path; do
308
+ [ -z "$old_path" ] && continue
309
+ # 새 매니페스트에 해당 경로가 없으면 삭제
310
+ if ! echo "$NEW_MANIFEST" | grep -q " ${old_path}$"; then
311
+ if [ -f "$TARGET_DIR/$old_path" ]; then
312
+ rm "$TARGET_DIR/$old_path"
313
+ echo " 🗑️ $old_path - 더 이상 사용하지 않는 파일 삭제"
314
+ fi
315
+ fi
316
+ done <<< "$OLD_MANIFEST_CONTENT"
317
+ echo ""
318
+ fi
319
+
320
+ # === 새 매니페스트 작성 ===
321
+ printf '%s' "$NEW_MANIFEST" > "$MANIFEST_FILE"
322
+
237
323
  echo "=== 설치 완료 ($MODE_LABEL) ==="
238
324
  echo ""
239
325
  echo "스택: $STACK_LABEL"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choblue/claude-code-toolkit",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Claude Code 서브에이전트 위임 툴킷 - npx로 바로 설치",
5
5
  "bin": {
6
6
  "claude-code-toolkit": "bin/cli.js"