claude-dev-kit 2.1.3 → 2.1.6
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.
- package/package.json +4 -2
- package/scripts/lib/merge-settings.js +87 -0
- package/scripts/migrate.sh +444 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-dev-kit",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"description": "Transform Claude Code into a fully autonomous development team — orchestrated sub-agents for planning, implementation, testing, and review.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-dev-kit": "./bin/claude-dev-kit.js"
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
".claude/skills/",
|
|
16
16
|
".claude/templates/",
|
|
17
17
|
"CLAUDE.local.md.example",
|
|
18
|
-
"scripts/install.sh"
|
|
18
|
+
"scripts/install.sh",
|
|
19
|
+
"scripts/migrate.sh",
|
|
20
|
+
"scripts/lib/"
|
|
19
21
|
],
|
|
20
22
|
"keywords": [
|
|
21
23
|
"claude",
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/lib/merge-settings.js
|
|
3
|
+
// Merges CDK's settings.json into a user's existing settings.json.
|
|
4
|
+
//
|
|
5
|
+
// Usage: node merge-settings.js <user-settings-path> <cdk-settings-path>
|
|
6
|
+
// Output: merged JSON on stdout
|
|
7
|
+
//
|
|
8
|
+
// Merge rules:
|
|
9
|
+
// permissions.allow — union (add CDK entries not already present)
|
|
10
|
+
// permissions.deny — union (add CDK entries not already present)
|
|
11
|
+
// hooks — per-event: add CDK hook commands not already present
|
|
12
|
+
// (dedup key: command string, trimmed)
|
|
13
|
+
// All other user settings are preserved unchanged.
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
|
|
19
|
+
const [, , userPath, cdkPath] = process.argv;
|
|
20
|
+
|
|
21
|
+
if (!userPath || !cdkPath) {
|
|
22
|
+
process.stderr.write('Usage: node merge-settings.js <user-settings-path> <cdk-settings-path>\n');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let user, cdk;
|
|
27
|
+
try {
|
|
28
|
+
user = JSON.parse(fs.readFileSync(userPath, 'utf8'));
|
|
29
|
+
} catch (e) {
|
|
30
|
+
process.stderr.write(`Failed to parse user settings at ${userPath}: ${e.message}\n`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
cdk = JSON.parse(fs.readFileSync(cdkPath, 'utf8'));
|
|
35
|
+
} catch (e) {
|
|
36
|
+
process.stderr.write(`Failed to parse CDK settings at ${cdkPath}: ${e.message}\n`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Deep clone user settings as the base
|
|
41
|
+
const result = JSON.parse(JSON.stringify(user));
|
|
42
|
+
|
|
43
|
+
// Strip CDK internal-only comment keys if they leaked in
|
|
44
|
+
delete result._comment;
|
|
45
|
+
delete result._hooks_note;
|
|
46
|
+
|
|
47
|
+
// ── Merge permissions.allow ──────────────────────────────────────────────────
|
|
48
|
+
result.permissions = result.permissions ?? {};
|
|
49
|
+
const userAllow = new Set(result.permissions.allow ?? []);
|
|
50
|
+
for (const entry of (cdk.permissions?.allow ?? [])) {
|
|
51
|
+
userAllow.add(entry);
|
|
52
|
+
}
|
|
53
|
+
result.permissions.allow = [...userAllow];
|
|
54
|
+
|
|
55
|
+
// ── Merge permissions.deny ───────────────────────────────────────────────────
|
|
56
|
+
const userDeny = new Set(result.permissions.deny ?? []);
|
|
57
|
+
for (const entry of (cdk.permissions?.deny ?? [])) {
|
|
58
|
+
userDeny.add(entry);
|
|
59
|
+
}
|
|
60
|
+
result.permissions.deny = [...userDeny];
|
|
61
|
+
|
|
62
|
+
// ── Merge hooks ──────────────────────────────────────────────────────────────
|
|
63
|
+
result.hooks = result.hooks ?? {};
|
|
64
|
+
|
|
65
|
+
for (const [event, cdkGroups] of Object.entries(cdk.hooks ?? {})) {
|
|
66
|
+
result.hooks[event] = result.hooks[event] ?? [];
|
|
67
|
+
|
|
68
|
+
// Collect all command strings already present for this event
|
|
69
|
+
const existingCommands = new Set();
|
|
70
|
+
for (const group of result.hooks[event]) {
|
|
71
|
+
for (const h of (group.hooks ?? [])) {
|
|
72
|
+
if (h.command) existingCommands.add(h.command.trim());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// For each CDK hook group, keep only commands not already present
|
|
77
|
+
for (const cdkGroup of cdkGroups) {
|
|
78
|
+
const newHooks = (cdkGroup.hooks ?? []).filter(
|
|
79
|
+
(h) => h.command && !existingCommands.has(h.command.trim())
|
|
80
|
+
);
|
|
81
|
+
if (newHooks.length > 0) {
|
|
82
|
+
result.hooks[event].push({ ...cdkGroup, hooks: newHooks });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/migrate.sh — Claude Dev Kit Migration Tool
|
|
3
|
+
#
|
|
4
|
+
# Intelligently merges CDK into an existing .claude/ setup without data loss.
|
|
5
|
+
# Detects NEW / UNCHANGED / MODIFIED files, asks about conflicts, and
|
|
6
|
+
# performs smart merges of settings.json and CLAUDE.md.
|
|
7
|
+
#
|
|
8
|
+
# Usage (called by install.sh):
|
|
9
|
+
# bash scripts/migrate.sh <kit-root> <target-dir>
|
|
10
|
+
#
|
|
11
|
+
# Safe to run standalone. Exit codes: 0 = success, 1 = aborted/error.
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# ─── Args ─────────────────────────────────────────────────────────────────────
|
|
16
|
+
KIT_ROOT="${1:-}"
|
|
17
|
+
TARGET="${2:-}"
|
|
18
|
+
|
|
19
|
+
if [[ -z "$KIT_ROOT" || -z "$TARGET" ]]; then
|
|
20
|
+
echo "Usage: bash scripts/migrate.sh <kit-root> <target-dir>" >&2
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
CDK_CLAUDE="$KIT_ROOT/.claude"
|
|
25
|
+
TGT_CLAUDE="$TARGET/.claude"
|
|
26
|
+
MANIFEST="$TGT_CLAUDE/.cdk-manifest"
|
|
27
|
+
|
|
28
|
+
# ─── Colors ───────────────────────────────────────────────────────────────────
|
|
29
|
+
BOLD='\033[1m'
|
|
30
|
+
DIM='\033[2m'
|
|
31
|
+
GREEN='\033[0;32m'
|
|
32
|
+
YELLOW='\033[1;33m'
|
|
33
|
+
CYAN='\033[0;36m'
|
|
34
|
+
RED='\033[0;31m'
|
|
35
|
+
BLUE='\033[0;34m'
|
|
36
|
+
NC='\033[0m'
|
|
37
|
+
|
|
38
|
+
info() { echo -e "${CYAN} →${NC} $*"; }
|
|
39
|
+
success() { echo -e "${GREEN} ✓${NC} $*"; }
|
|
40
|
+
warn() { echo -e "${YELLOW} ⚠${NC} $*"; }
|
|
41
|
+
error() { echo -e "${RED} ✗${NC} $*" >&2; }
|
|
42
|
+
header() { echo -e "\n${BOLD}$*${NC}"; }
|
|
43
|
+
dim() { echo -e "${DIM}$*${NC}"; }
|
|
44
|
+
|
|
45
|
+
CI_MODE="${CI:-false}"
|
|
46
|
+
|
|
47
|
+
# ─── Section 1: Load existing manifest ────────────────────────────────────────
|
|
48
|
+
IS_FIRST_INSTALL=false
|
|
49
|
+
|
|
50
|
+
mkdir -p "$TGT_CLAUDE"
|
|
51
|
+
|
|
52
|
+
if [[ -f "$MANIFEST" ]]; then
|
|
53
|
+
while IFS= read -r line; do
|
|
54
|
+
[[ "$line" =~ ^# ]] && continue
|
|
55
|
+
[[ -z "$line" ]] && continue
|
|
56
|
+
done < "$MANIFEST"
|
|
57
|
+
else
|
|
58
|
+
IS_FIRST_INSTALL=true
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# ─── Section 2: Enumerate CDK files ───────────────────────────────────────────
|
|
62
|
+
declare -a cdk_files=()
|
|
63
|
+
|
|
64
|
+
while IFS= read -r -d '' f; do
|
|
65
|
+
rel="${f#"$CDK_CLAUDE"/}"
|
|
66
|
+
# Skip files that have their own special merge logic or should never be copied
|
|
67
|
+
[[ "$rel" == "settings.json" ]] && continue
|
|
68
|
+
[[ "$rel" == "settings.json.example" ]] && continue
|
|
69
|
+
[[ "$rel" == ".cdk-manifest" ]] && continue
|
|
70
|
+
[[ "$rel" == *"node_modules"* ]] && continue
|
|
71
|
+
[[ "$rel" == *.jsonl ]] && continue
|
|
72
|
+
[[ "$rel" == "learning/"* ]] && continue
|
|
73
|
+
cdk_files+=("$rel")
|
|
74
|
+
done < <(find "$CDK_CLAUDE" -type f -print0 2>/dev/null | sort -z)
|
|
75
|
+
|
|
76
|
+
# ─── Section 3: Categorize files ──────────────────────────────────────────────
|
|
77
|
+
declare -a cat_new=()
|
|
78
|
+
declare -a cat_unchanged=()
|
|
79
|
+
declare -a cat_modified=()
|
|
80
|
+
|
|
81
|
+
for rel in "${cdk_files[@]}"; do
|
|
82
|
+
src="$CDK_CLAUDE/$rel"
|
|
83
|
+
dst="$TGT_CLAUDE/$rel"
|
|
84
|
+
|
|
85
|
+
if [[ ! -f "$dst" ]]; then
|
|
86
|
+
cat_new+=("$rel")
|
|
87
|
+
elif cmp -s "$src" "$dst"; then
|
|
88
|
+
cat_unchanged+=("$rel")
|
|
89
|
+
else
|
|
90
|
+
# File exists in both and content differs — it was modified
|
|
91
|
+
cat_modified+=("$rel")
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# Count user-only files (in target .claude but not in CDK source)
|
|
96
|
+
user_only_count=0
|
|
97
|
+
if [[ -d "$TGT_CLAUDE" ]]; then
|
|
98
|
+
while IFS= read -r -d '' f; do
|
|
99
|
+
rel="${f#"$TGT_CLAUDE"/}"
|
|
100
|
+
[[ "$rel" == ".cdk-manifest" ]] && continue
|
|
101
|
+
# Check if this file is in the CDK source
|
|
102
|
+
if [[ ! -f "$CDK_CLAUDE/$rel" ]]; then
|
|
103
|
+
(( user_only_count++ )) || true
|
|
104
|
+
fi
|
|
105
|
+
done < <(find "$TGT_CLAUDE" -type f -print0 2>/dev/null)
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# ─── Section 4: Print migration report ────────────────────────────────────────
|
|
109
|
+
echo ""
|
|
110
|
+
echo -e "${BOLD}╔═══════════════════════════════════════════╗${NC}"
|
|
111
|
+
echo -e "${BOLD}║ Claude Dev Kit — Migration Tool ║${NC}"
|
|
112
|
+
echo -e "${BOLD}╚═══════════════════════════════════════════╝${NC}"
|
|
113
|
+
echo ""
|
|
114
|
+
echo -e " ${DIM}Source: $KIT_ROOT${NC}"
|
|
115
|
+
echo -e " ${DIM}Target: $TARGET${NC}"
|
|
116
|
+
echo ""
|
|
117
|
+
|
|
118
|
+
if [[ "$IS_FIRST_INSTALL" == "true" ]] && [[ ! -d "$TARGET/.claude" || -z "$(ls -A "$TGT_CLAUDE" 2>/dev/null)" ]]; then
|
|
119
|
+
info "No existing .claude/ found — performing fresh install"
|
|
120
|
+
else
|
|
121
|
+
header "Migration Report"
|
|
122
|
+
echo ""
|
|
123
|
+
|
|
124
|
+
echo -e " ${GREEN}${BOLD}NEW${NC} ${#cat_new[@]} file(s) — will be added"
|
|
125
|
+
if [[ ${#cat_new[@]} -gt 0 && ${#cat_new[@]} -le 10 ]]; then
|
|
126
|
+
for f in "${cat_new[@]}"; do echo -e " ${DIM}$f${NC}"; done
|
|
127
|
+
elif [[ ${#cat_new[@]} -gt 10 ]]; then
|
|
128
|
+
for f in "${cat_new[@]:0:5}"; do echo -e " ${DIM}$f${NC}"; done
|
|
129
|
+
echo -e " ${DIM}... and $((${#cat_new[@]} - 5)) more${NC}"
|
|
130
|
+
fi
|
|
131
|
+
echo ""
|
|
132
|
+
|
|
133
|
+
echo -e " ${CYAN}${BOLD}UNCHANGED${NC} ${#cat_unchanged[@]} file(s) — CDK version matches yours, will refresh"
|
|
134
|
+
echo ""
|
|
135
|
+
|
|
136
|
+
if [[ ${#cat_modified[@]} -gt 0 ]]; then
|
|
137
|
+
echo -e " ${YELLOW}${BOLD}MODIFIED${NC} ${#cat_modified[@]} file(s) — differ from CDK, ${BOLD}requires your input${NC}"
|
|
138
|
+
for f in "${cat_modified[@]}"; do echo -e " ${YELLOW}$f${NC}"; done
|
|
139
|
+
echo ""
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
if [[ $user_only_count -gt 0 ]]; then
|
|
143
|
+
echo -e " ${BLUE}${BOLD}YOURS${NC} $user_only_count file(s) — only in your .claude/, CDK will never touch"
|
|
144
|
+
echo ""
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
echo -e " ${BOLD}SPECIAL MERGES${NC}"
|
|
148
|
+
if [[ -f "$TGT_CLAUDE/settings.json" ]]; then
|
|
149
|
+
echo -e " ${DIM}settings.json${NC} — will merge hooks + permissions (yours preserved)"
|
|
150
|
+
else
|
|
151
|
+
echo -e " ${DIM}settings.json${NC} — will be created from CDK template"
|
|
152
|
+
fi
|
|
153
|
+
if [[ -f "$TARGET/CLAUDE.md" ]]; then
|
|
154
|
+
if grep -qF "CDK:GENERATED:START" "$TARGET/CLAUDE.md" 2>/dev/null; then
|
|
155
|
+
echo -e " ${DIM}CLAUDE.md${NC} — will update CDK block (your custom content preserved)"
|
|
156
|
+
else
|
|
157
|
+
echo -e " ${DIM}CLAUDE.md${NC} — will append CDK block (your existing content preserved)"
|
|
158
|
+
fi
|
|
159
|
+
else
|
|
160
|
+
echo -e " ${DIM}CLAUDE.md${NC} — will be created from template"
|
|
161
|
+
fi
|
|
162
|
+
echo ""
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# ─── Section 5: Confirm before proceeding ─────────────────────────────────────
|
|
166
|
+
if [[ "$CI_MODE" != "true" && ${#cat_modified[@]} -eq 0 ]]; then
|
|
167
|
+
echo -ne " Proceed with migration? ${DIM}[Y/n]${NC}: "
|
|
168
|
+
read -r _confirm </dev/tty
|
|
169
|
+
if [[ "$_confirm" =~ ^[Nn]$ ]]; then
|
|
170
|
+
echo " Aborted."
|
|
171
|
+
exit 1
|
|
172
|
+
fi
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# ─── Section 6: Resolve MODIFIED files interactively ──────────────────────────
|
|
176
|
+
declare -a resolution_files=()
|
|
177
|
+
declare -a resolution_actions=()
|
|
178
|
+
|
|
179
|
+
set_resolution() {
|
|
180
|
+
local file="$1"
|
|
181
|
+
local action="$2"
|
|
182
|
+
local i
|
|
183
|
+
for (( i=0; i<${#resolution_files[@]}; i++ )); do
|
|
184
|
+
if [[ "${resolution_files[$i]}" == "$file" ]]; then
|
|
185
|
+
resolution_actions[$i]="$action"
|
|
186
|
+
return
|
|
187
|
+
fi
|
|
188
|
+
done
|
|
189
|
+
resolution_files+=("$file")
|
|
190
|
+
resolution_actions+=("$action")
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get_resolution() {
|
|
194
|
+
local file="$1"
|
|
195
|
+
local i
|
|
196
|
+
for (( i=0; i<${#resolution_files[@]}; i++ )); do
|
|
197
|
+
if [[ "${resolution_files[$i]}" == "$file" ]]; then
|
|
198
|
+
printf '%s\n' "${resolution_actions[$i]}"
|
|
199
|
+
return
|
|
200
|
+
fi
|
|
201
|
+
done
|
|
202
|
+
printf 'keep\n'
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if [[ ${#cat_modified[@]} -gt 0 ]]; then
|
|
206
|
+
if [[ "$CI_MODE" == "true" ]]; then
|
|
207
|
+
warn "CI mode — all ${#cat_modified[@]} modified file(s) will be preserved (keeping your versions)"
|
|
208
|
+
warn "To update them: run scripts/migrate.sh manually and choose [u] for each"
|
|
209
|
+
for rel in "${cat_modified[@]}"; do
|
|
210
|
+
set_resolution "$rel" "keep"
|
|
211
|
+
done
|
|
212
|
+
else
|
|
213
|
+
header "Resolving modified files"
|
|
214
|
+
echo -e " ${DIM}For each file that differs from CDK, choose what to do.${NC}"
|
|
215
|
+
echo ""
|
|
216
|
+
|
|
217
|
+
for rel in "${cat_modified[@]}"; do
|
|
218
|
+
src="$CDK_CLAUDE/$rel"
|
|
219
|
+
dst="$TGT_CLAUDE/$rel"
|
|
220
|
+
|
|
221
|
+
echo -e " ${YELLOW}${BOLD}MODIFIED:${NC} $rel"
|
|
222
|
+
|
|
223
|
+
while true; do
|
|
224
|
+
echo -ne " [k]eep mine [u]se CDK version [d]iff [s]kip: "
|
|
225
|
+
read -r -n1 choice </dev/tty
|
|
226
|
+
echo ""
|
|
227
|
+
|
|
228
|
+
case "$choice" in
|
|
229
|
+
k|K)
|
|
230
|
+
set_resolution "$rel" "keep"
|
|
231
|
+
info "Keeping your version"
|
|
232
|
+
break
|
|
233
|
+
;;
|
|
234
|
+
u|U)
|
|
235
|
+
set_resolution "$rel" "cdk"
|
|
236
|
+
info "Will use CDK version"
|
|
237
|
+
break
|
|
238
|
+
;;
|
|
239
|
+
d|D)
|
|
240
|
+
echo ""
|
|
241
|
+
if command -v diff &>/dev/null; then
|
|
242
|
+
diff --color=always -u "$dst" "$src" 2>/dev/null | head -80 || true
|
|
243
|
+
else
|
|
244
|
+
warn "diff not available — cannot show comparison"
|
|
245
|
+
fi
|
|
246
|
+
echo ""
|
|
247
|
+
;;
|
|
248
|
+
s|S)
|
|
249
|
+
resolutions["$rel"]="keep"
|
|
250
|
+
info "Skipped (keeping yours)"
|
|
251
|
+
break
|
|
252
|
+
;;
|
|
253
|
+
*)
|
|
254
|
+
echo -ne " Invalid choice. "
|
|
255
|
+
;;
|
|
256
|
+
esac
|
|
257
|
+
done
|
|
258
|
+
echo ""
|
|
259
|
+
done
|
|
260
|
+
fi
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
# ─── Section 7: Apply regular file changes ────────────────────────────────────
|
|
264
|
+
header "Applying changes"
|
|
265
|
+
echo ""
|
|
266
|
+
|
|
267
|
+
new_count=0
|
|
268
|
+
unchanged_count=0
|
|
269
|
+
modified_applied=0
|
|
270
|
+
modified_kept=0
|
|
271
|
+
|
|
272
|
+
# Apply NEW files
|
|
273
|
+
for rel in "${cat_new[@]}"; do
|
|
274
|
+
src="$CDK_CLAUDE/$rel"
|
|
275
|
+
dst="$TGT_CLAUDE/$rel"
|
|
276
|
+
mkdir -p "$(dirname "$dst")"
|
|
277
|
+
cp "$src" "$dst"
|
|
278
|
+
(( new_count++ )) || true
|
|
279
|
+
done
|
|
280
|
+
|
|
281
|
+
# Apply UNCHANGED files (refresh to latest CDK version — they're identical so this is safe)
|
|
282
|
+
for rel in "${cat_unchanged[@]}"; do
|
|
283
|
+
src="$CDK_CLAUDE/$rel"
|
|
284
|
+
dst="$TGT_CLAUDE/$rel"
|
|
285
|
+
mkdir -p "$(dirname "$dst")"
|
|
286
|
+
cp "$src" "$dst"
|
|
287
|
+
(( unchanged_count++ )) || true
|
|
288
|
+
done
|
|
289
|
+
|
|
290
|
+
# Apply MODIFIED based on user decisions
|
|
291
|
+
for rel in "${cat_modified[@]}"; do
|
|
292
|
+
case "$(get_resolution "$rel")" in
|
|
293
|
+
cdk)
|
|
294
|
+
mkdir -p "$(dirname "$TGT_CLAUDE/$rel")"
|
|
295
|
+
cp "$CDK_CLAUDE/$rel" "$TGT_CLAUDE/$rel"
|
|
296
|
+
(( modified_applied++ )) || true
|
|
297
|
+
;;
|
|
298
|
+
keep)
|
|
299
|
+
(( modified_kept++ )) || true
|
|
300
|
+
;;
|
|
301
|
+
esac
|
|
302
|
+
done
|
|
303
|
+
|
|
304
|
+
[[ $new_count -gt 0 ]] && success "$new_count new file(s) added"
|
|
305
|
+
[[ $unchanged_count -gt 0 ]] && success "$unchanged_count unchanged file(s) refreshed"
|
|
306
|
+
[[ $modified_applied -gt 0 ]] && success "$modified_applied modified file(s) updated to CDK version"
|
|
307
|
+
[[ $modified_kept -gt 0 ]] && info "$modified_kept modified file(s) kept as your version"
|
|
308
|
+
|
|
309
|
+
# ─── Section 8: Merge settings.json ───────────────────────────────────────────
|
|
310
|
+
merge_settings() {
|
|
311
|
+
local tgt_settings="$TGT_CLAUDE/settings.json"
|
|
312
|
+
local cdk_settings="$CDK_CLAUDE/settings.json"
|
|
313
|
+
local merge_script="$KIT_ROOT/scripts/lib/merge-settings.js"
|
|
314
|
+
|
|
315
|
+
if [[ ! -f "$cdk_settings" ]]; then
|
|
316
|
+
warn "settings.json: CDK source not found — skipping"
|
|
317
|
+
return
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
if [[ ! -f "$tgt_settings" ]]; then
|
|
321
|
+
# No existing settings — install CDK's (strip internal comment keys)
|
|
322
|
+
node -e "
|
|
323
|
+
const s = JSON.parse(require('fs').readFileSync('$cdk_settings', 'utf8'));
|
|
324
|
+
delete s._comment; delete s._hooks_note;
|
|
325
|
+
process.stdout.write(JSON.stringify(s, null, 2) + '\n');
|
|
326
|
+
" > "$tgt_settings"
|
|
327
|
+
success "settings.json: created from CDK template"
|
|
328
|
+
return
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
local tmp
|
|
332
|
+
tmp=$(mktemp /tmp/cdk-settings-XXXXXX.json)
|
|
333
|
+
# shellcheck disable=SC2064
|
|
334
|
+
trap "rm -f '$tmp'" RETURN
|
|
335
|
+
|
|
336
|
+
if node "$merge_script" "$tgt_settings" "$cdk_settings" > "$tmp" 2>&1; then
|
|
337
|
+
# Validate output is parseable JSON before overwriting
|
|
338
|
+
if node -e "JSON.parse(require('fs').readFileSync('$tmp', 'utf8'))" 2>/dev/null; then
|
|
339
|
+
cp "$tmp" "$tgt_settings"
|
|
340
|
+
success "settings.json: merged (permissions + hooks updated)"
|
|
341
|
+
else
|
|
342
|
+
warn "settings.json: merge produced invalid JSON — your original preserved"
|
|
343
|
+
warn "Manual merge reference: $CDK_CLAUDE/settings.json.example"
|
|
344
|
+
fi
|
|
345
|
+
else
|
|
346
|
+
warn "settings.json: merge failed — your original preserved"
|
|
347
|
+
warn "Manual merge reference: $CDK_CLAUDE/settings.json.example"
|
|
348
|
+
fi
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
merge_settings
|
|
352
|
+
|
|
353
|
+
# ─── Section 9: Merge CLAUDE.md ───────────────────────────────────────────────
|
|
354
|
+
merge_claude_md() {
|
|
355
|
+
local tgt_md="$TARGET/CLAUDE.md"
|
|
356
|
+
local cdk_template="$CDK_CLAUDE/templates/claude-md-template.md"
|
|
357
|
+
local START_MARKER="CDK:GENERATED:START"
|
|
358
|
+
local END_MARKER="CDK:GENERATED:END"
|
|
359
|
+
|
|
360
|
+
if [[ ! -f "$cdk_template" ]]; then
|
|
361
|
+
warn "CLAUDE.md: template not found at $cdk_template — skipping"
|
|
362
|
+
return
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
if [[ ! -f "$tgt_md" ]]; then
|
|
366
|
+
cp "$cdk_template" "$tgt_md"
|
|
367
|
+
success "CLAUDE.md: created from template"
|
|
368
|
+
return
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
if grep -qF "$START_MARKER" "$tgt_md" 2>/dev/null; then
|
|
372
|
+
# Has CDK markers — replace only the block between markers (inclusive)
|
|
373
|
+
local tmp
|
|
374
|
+
tmp=$(mktemp /tmp/cdk-claude-md-XXXXXX.md)
|
|
375
|
+
# shellcheck disable=SC2064
|
|
376
|
+
trap "rm -f '$tmp'" RETURN
|
|
377
|
+
|
|
378
|
+
# Extract CDK block from template
|
|
379
|
+
local cdk_block
|
|
380
|
+
cdk_block=$(awk "/<!-- ${START_MARKER}/,/<!-- ${END_MARKER} -->/" "$cdk_template")
|
|
381
|
+
|
|
382
|
+
# Build merged file: content before START + cdk block + content after END
|
|
383
|
+
awk -v block="$cdk_block" \
|
|
384
|
+
-v start="$START_MARKER" \
|
|
385
|
+
-v end="$END_MARKER" \
|
|
386
|
+
'BEGIN { in_block=0; printed=0 }
|
|
387
|
+
index($0, start) > 0 {
|
|
388
|
+
if (!printed) { print block; printed=1 }
|
|
389
|
+
in_block=1; next
|
|
390
|
+
}
|
|
391
|
+
in_block && index($0, end) > 0 { in_block=0; next }
|
|
392
|
+
!in_block { print }
|
|
393
|
+
' "$tgt_md" > "$tmp"
|
|
394
|
+
|
|
395
|
+
cp "$tmp" "$tgt_md"
|
|
396
|
+
success "CLAUDE.md: CDK block updated (your custom content preserved)"
|
|
397
|
+
else
|
|
398
|
+
# No CDK markers — append the CDK block at the end
|
|
399
|
+
local cdk_block
|
|
400
|
+
cdk_block=$(awk "/<!-- ${START_MARKER}/,/<!-- ${END_MARKER} -->/" "$cdk_template")
|
|
401
|
+
{
|
|
402
|
+
echo ""
|
|
403
|
+
echo "---"
|
|
404
|
+
echo ""
|
|
405
|
+
printf '%s\n' "$cdk_block"
|
|
406
|
+
} >> "$tgt_md"
|
|
407
|
+
success "CLAUDE.md: CDK block appended (your existing content preserved)"
|
|
408
|
+
info "Tip: you can move the appended block anywhere in the file — the markers let future migrations update it in place"
|
|
409
|
+
fi
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
merge_claude_md
|
|
413
|
+
|
|
414
|
+
# ─── Section 10: Write manifest ───────────────────────────────────────────────
|
|
415
|
+
write_manifest() {
|
|
416
|
+
{
|
|
417
|
+
echo "# CDK Manifest — generated by scripts/migrate.sh"
|
|
418
|
+
echo "# Lists all files installed by claude-dev-kit."
|
|
419
|
+
echo "# Do not edit manually. Used to distinguish CDK-owned from user-created files."
|
|
420
|
+
echo "#"
|
|
421
|
+
for rel in "${cdk_files[@]}"; do
|
|
422
|
+
echo "$rel"
|
|
423
|
+
done
|
|
424
|
+
} > "$MANIFEST"
|
|
425
|
+
success "Manifest written (.claude/.cdk-manifest — tracks CDK-owned files for future migrations)"
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
write_manifest
|
|
429
|
+
|
|
430
|
+
# ─── Done ─────────────────────────────────────────────────────────────────────
|
|
431
|
+
echo ""
|
|
432
|
+
success "Migration complete"
|
|
433
|
+
echo ""
|
|
434
|
+
echo -e " ${DIM}Next steps:${NC}"
|
|
435
|
+
if [[ ! -f "$TARGET/CLAUDE.md" ]] || ! grep -qF "CDK:GENERATED" "$TARGET/CLAUDE.md" 2>/dev/null; then
|
|
436
|
+
echo -e " ${DIM} 1. Run \`/init\` inside Claude Code to configure CLAUDE.md for your stack${NC}"
|
|
437
|
+
echo -e " ${DIM} 2. Copy CLAUDE.local.md.example → CLAUDE.local.md for personal preferences${NC}"
|
|
438
|
+
echo -e " ${DIM} 3. Run \`/primer\` to verify Claude understands the project${NC}"
|
|
439
|
+
else
|
|
440
|
+
echo -e " ${DIM} 1. Copy CLAUDE.local.md.example → CLAUDE.local.md for personal preferences${NC}"
|
|
441
|
+
echo -e " ${DIM} 2. Review any modified files you chose to keep — ensure they're still compatible${NC}"
|
|
442
|
+
echo -e " ${DIM} 3. Run \`/primer\` to verify Claude understands the project${NC}"
|
|
443
|
+
fi
|
|
444
|
+
echo ""
|