dw-kit 1.0.0 → 1.0.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.
- package/.claude/hooks/post-write.sh +1 -3
- package/.claude/skills/dw-upgrade/SKILL.md +20 -30
- package/.dw/adapters/claude-cli/extensions/README.md +2 -2
- package/.dw/adapters/claude-cli/generated/README.md +3 -3
- package/.dw/adapters/claude-cli/overrides/README.md +4 -2
- package/README.md +68 -127
- package/package.json +4 -5
- package/scripts/e2e-local-check.sh +1 -2
- package/src/cli.mjs +0 -9
- package/src/smoke-test.mjs +1 -11
- package/scripts/migrate-v03-to-v1.sh +0 -243
- package/scripts/upgrade.sh +0 -246
- package/setup.sh +0 -382
- package/src/commands/migrate.mjs +0 -215
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# scripts/migrate-v03-to-v1.sh
|
|
3
|
-
# ⚠ DEPRECATED: Prefer `dw migrate` from npm CLI.
|
|
4
|
-
# Migrate project từ dw-kit v0.3 sang v1
|
|
5
|
-
# Usage: bash scripts/migrate-v03-to-v1.sh [--dry-run]
|
|
6
|
-
|
|
7
|
-
set -euo pipefail
|
|
8
|
-
|
|
9
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
11
|
-
|
|
12
|
-
DRY_RUN=false
|
|
13
|
-
[ "${1:-}" = "--dry-run" ] && DRY_RUN=true
|
|
14
|
-
|
|
15
|
-
log() { echo " $*"; }
|
|
16
|
-
info() { echo ""; echo "▶ $*"; }
|
|
17
|
-
warn() { echo " ⚠ $*"; }
|
|
18
|
-
ok() { echo " ✓ $*"; }
|
|
19
|
-
dry() { [ "$DRY_RUN" = true ] && echo " [dry] $*" || true; }
|
|
20
|
-
do_action() {
|
|
21
|
-
if [ "$DRY_RUN" = true ]; then echo " [dry] $*"; else eval "$*"; fi
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
OLD_CONFIG="$PROJECT_ROOT/.dw/config/dw.config.yml"
|
|
25
|
-
NEW_CONFIG_DIR="$PROJECT_ROOT/config"
|
|
26
|
-
NEW_CONFIG="$NEW_CONFIG_DIR/dw.config.yml"
|
|
27
|
-
|
|
28
|
-
echo ""
|
|
29
|
-
echo "══════════════════════════════════════════"
|
|
30
|
-
echo " dw-kit v0.3 → v1 Migration"
|
|
31
|
-
[ "$DRY_RUN" = true ] && echo " Mode: DRY RUN"
|
|
32
|
-
echo "══════════════════════════════════════════"
|
|
33
|
-
|
|
34
|
-
# ── Step 1: Validate v0.3 present ────────────────────────────────────────────
|
|
35
|
-
info "Step 1: Validate source config"
|
|
36
|
-
|
|
37
|
-
if [ ! -f "$OLD_CONFIG" ]; then
|
|
38
|
-
echo " No config/dw.config.yml found. Already on v1 or fresh install."
|
|
39
|
-
exit 0
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
if [ -L "$OLD_CONFIG" ]; then
|
|
43
|
-
warn "config/dw.config.yml is already a symlink → migration may have already run."
|
|
44
|
-
read -r -p " Continue anyway? [y/N] " confirm
|
|
45
|
-
[[ "$confirm" =~ ^[Yy]$ ]] || exit 0
|
|
46
|
-
fi
|
|
47
|
-
|
|
48
|
-
ok "Found config/dw.config.yml"
|
|
49
|
-
|
|
50
|
-
# ── Step 2: Detect customized skills ─────────────────────────────────────────
|
|
51
|
-
info "Step 2: Detect customized skills"
|
|
52
|
-
|
|
53
|
-
OVERRIDES_DIR="$PROJECT_ROOT/.dw/adapters/claude-cli/overrides/skills"
|
|
54
|
-
SKILLS_DIR="$PROJECT_ROOT/.claude/skills"
|
|
55
|
-
customized_count=0
|
|
56
|
-
|
|
57
|
-
# Heuristic: compare với toolkit's own copy nếu có, hoặc check git
|
|
58
|
-
if command -v git &>/dev/null && git -C "$PROJECT_ROOT" rev-parse --git-dir &>/dev/null; then
|
|
59
|
-
for skill_dir in "$SKILLS_DIR"/*/; do
|
|
60
|
-
[ -d "$skill_dir" ] || continue
|
|
61
|
-
skill_name=$(basename "$skill_dir")
|
|
62
|
-
skill_file="$skill_dir/SKILL.md"
|
|
63
|
-
[ -f "$skill_file" ] || continue
|
|
64
|
-
|
|
65
|
-
# Check if file was modified from its committed version
|
|
66
|
-
if ! git -C "$PROJECT_ROOT" diff --quiet HEAD -- ".claude/skills/$skill_name/SKILL.md" 2>/dev/null; then
|
|
67
|
-
warn "Skill '$skill_name' has uncommitted changes → preserving to overrides/"
|
|
68
|
-
do_action "mkdir -p '$OVERRIDES_DIR/$skill_name'"
|
|
69
|
-
do_action "cp '$skill_file' '$OVERRIDES_DIR/$skill_name/SKILL.md'"
|
|
70
|
-
customized_count=$((customized_count + 1))
|
|
71
|
-
fi
|
|
72
|
-
done
|
|
73
|
-
else
|
|
74
|
-
warn "Not a git repo or git not available. Cannot auto-detect customizations."
|
|
75
|
-
warn "Manually copy customized skills to adapters/claude-cli/overrides/skills/ before upgrading."
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
if [ $customized_count -gt 0 ]; then
|
|
79
|
-
ok "$customized_count customized skill(s) preserved to overrides/"
|
|
80
|
-
else
|
|
81
|
-
ok "No customized skills detected"
|
|
82
|
-
fi
|
|
83
|
-
|
|
84
|
-
# ── Step 3: Migrate config ────────────────────────────────────────────────────
|
|
85
|
-
info "Step 3: Migrate config (config/dw.config.yml → config/dw.config.yml)"
|
|
86
|
-
|
|
87
|
-
if [ -f "$NEW_CONFIG" ]; then
|
|
88
|
-
warn "config/dw.config.yml already exists. Skipping config migration."
|
|
89
|
-
warn "Review manually: $NEW_CONFIG"
|
|
90
|
-
else
|
|
91
|
-
if ! command -v python3 &>/dev/null; then
|
|
92
|
-
warn "python3 not found. Manual config migration needed."
|
|
93
|
-
warn "Map: level: 1 → default_depth: quick"
|
|
94
|
-
warn " level: 2 → default_depth: standard"
|
|
95
|
-
warn " level: 3 → default_depth: thorough"
|
|
96
|
-
else
|
|
97
|
-
if [ "$DRY_RUN" = false ]; then
|
|
98
|
-
mkdir -p "$NEW_CONFIG_DIR"
|
|
99
|
-
python3 - "$OLD_CONFIG" "$NEW_CONFIG" <<'PYEOF'
|
|
100
|
-
import sys, re
|
|
101
|
-
|
|
102
|
-
old_path = sys.argv[1]
|
|
103
|
-
new_path = sys.argv[2]
|
|
104
|
-
|
|
105
|
-
with open(old_path) as f:
|
|
106
|
-
old_content = f.read()
|
|
107
|
-
|
|
108
|
-
# Extract values from old config
|
|
109
|
-
def get_val(key, content, default=""):
|
|
110
|
-
m = re.search(rf'^\s*{re.escape(key)}:\s*([^\n#]+)', content, re.MULTILINE)
|
|
111
|
-
if m:
|
|
112
|
-
return m.group(1).strip().strip('"').strip("'")
|
|
113
|
-
return default
|
|
114
|
-
|
|
115
|
-
project_name = get_val("name", old_content, "my-project")
|
|
116
|
-
project_lang = get_val("language", old_content, "vi")
|
|
117
|
-
level_str = get_val("level", old_content, "2")
|
|
118
|
-
|
|
119
|
-
depth_map = {"1": "quick", "2": "standard", "3": "thorough"}
|
|
120
|
-
depth = depth_map.get(level_str, "standard")
|
|
121
|
-
|
|
122
|
-
# Extract roles
|
|
123
|
-
roles_match = re.findall(r'^\s+-\s+(dev|techlead|ba|qc|pm)\b', old_content, re.MULTILINE)
|
|
124
|
-
roles = roles_match if roles_match else ["dev"]
|
|
125
|
-
|
|
126
|
-
# Extract quality commands
|
|
127
|
-
test_cmd = get_val("test_command", old_content, "")
|
|
128
|
-
lint_cmd = get_val("lint_command", old_content, "")
|
|
129
|
-
|
|
130
|
-
# Extract paths
|
|
131
|
-
tasks_path = get_val("tasks", old_content, ".dw/tasks")
|
|
132
|
-
docs_path = get_val("docs", old_content, ".dw/docs")
|
|
133
|
-
|
|
134
|
-
# Build new config
|
|
135
|
-
roles_yaml = "\n".join(f" - {r}" for r in roles)
|
|
136
|
-
|
|
137
|
-
new_config = f"""# dw-kit Configuration
|
|
138
|
-
# Generated by migrate-v03-to-v1.sh
|
|
139
|
-
# Review and adjust as needed.
|
|
140
|
-
|
|
141
|
-
project:
|
|
142
|
-
name: "{project_name}"
|
|
143
|
-
language: "{project_lang}"
|
|
144
|
-
|
|
145
|
-
workflow:
|
|
146
|
-
default_depth: "{depth}" # quick | standard | thorough
|
|
147
|
-
# AI assesses per-task and may recommend different depth
|
|
148
|
-
|
|
149
|
-
team:
|
|
150
|
-
roles:
|
|
151
|
-
{roles_yaml}
|
|
152
|
-
|
|
153
|
-
quality:
|
|
154
|
-
test_command: "{test_cmd}" # empty = skip
|
|
155
|
-
lint_command: "{lint_cmd}" # empty = skip
|
|
156
|
-
block_on_fail: false
|
|
157
|
-
|
|
158
|
-
tracking:
|
|
159
|
-
estimation: false
|
|
160
|
-
log_work: false
|
|
161
|
-
estimation_unit: "hours"
|
|
162
|
-
|
|
163
|
-
paths:
|
|
164
|
-
tasks: "{tasks_path}"
|
|
165
|
-
docs: "{docs_path}"
|
|
166
|
-
|
|
167
|
-
# Claude-specific capabilities (Layer 2)
|
|
168
|
-
claude:
|
|
169
|
-
models:
|
|
170
|
-
plan: "" # empty = inherit from Claude Code settings
|
|
171
|
-
execute: ""
|
|
172
|
-
review: ""
|
|
173
|
-
structured_output: true
|
|
174
|
-
worktree_execution: false
|
|
175
|
-
mcp: []
|
|
176
|
-
|
|
177
|
-
# Toolkit version tracking (do not edit manually)
|
|
178
|
-
_toolkit:
|
|
179
|
-
core_version: "1.0"
|
|
180
|
-
platform_version: "1.0"
|
|
181
|
-
capability_version: "1.0"
|
|
182
|
-
migrated_from: "v0.3"
|
|
183
|
-
last_upgrade: "{__import__('datetime').date.today().isoformat()}"
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
with open(new_path, 'w') as f:
|
|
187
|
-
f.write(new_config)
|
|
188
|
-
PYEOF
|
|
189
|
-
ok "config/dw.config.yml created (migrated from level: $level_str → depth: $(grep default_depth "$NEW_CONFIG" | head -1))"
|
|
190
|
-
else
|
|
191
|
-
dry "Would create config/dw.config.yml from config/dw.config.yml"
|
|
192
|
-
fi
|
|
193
|
-
fi
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
|
-
# ── Step 4: Create backward-compat symlink ────────────────────────────────────
|
|
197
|
-
info "Step 4: Create backward-compat symlink"
|
|
198
|
-
|
|
199
|
-
if [ -f "$NEW_CONFIG" ] && [ ! -L "$OLD_CONFIG" ]; then
|
|
200
|
-
if [ "$DRY_RUN" = false ]; then
|
|
201
|
-
# Backup original
|
|
202
|
-
cp "$OLD_CONFIG" "${OLD_CONFIG}.bak"
|
|
203
|
-
ok "Backed up original to config/dw.config.yml.bak"
|
|
204
|
-
# Create symlink
|
|
205
|
-
rm "$OLD_CONFIG"
|
|
206
|
-
ln -s ".dw/.dw/config/dw.config.yml" "$OLD_CONFIG"
|
|
207
|
-
ok "Created symlink: config/dw.config.yml → config/dw.config.yml"
|
|
208
|
-
else
|
|
209
|
-
dry "Would create symlink: config/dw.config.yml → config/dw.config.yml"
|
|
210
|
-
fi
|
|
211
|
-
fi
|
|
212
|
-
|
|
213
|
-
# ── Step 5: Check CI/CD references ───────────────────────────────────────────
|
|
214
|
-
info "Step 5: Check CI/CD references"
|
|
215
|
-
|
|
216
|
-
found_refs=false
|
|
217
|
-
for ci_file in ".github/workflows/"*.yml ".gitlab-ci.yml" "Makefile" ".circleci/config.yml" "package.json"; do
|
|
218
|
-
full_path="$PROJECT_ROOT/$ci_file"
|
|
219
|
-
if [ -f "$full_path" ]; then
|
|
220
|
-
if grep -qE "dv-workflow\.config\.yml|dv-workflow-kit" "$full_path" 2>/dev/null; then
|
|
221
|
-
warn "Found reference in: $ci_file — update to config/dw.config.yml"
|
|
222
|
-
found_refs=true
|
|
223
|
-
fi
|
|
224
|
-
fi
|
|
225
|
-
done
|
|
226
|
-
[ "$found_refs" = false ] && ok "No CI/CD references found"
|
|
227
|
-
|
|
228
|
-
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
229
|
-
echo ""
|
|
230
|
-
echo "══════════════════════════════════════════"
|
|
231
|
-
if [ "$DRY_RUN" = true ]; then
|
|
232
|
-
echo " DRY RUN complete. Review above, then run without --dry-run."
|
|
233
|
-
else
|
|
234
|
-
echo " Migration complete!"
|
|
235
|
-
echo ""
|
|
236
|
-
echo " Next steps:"
|
|
237
|
-
echo " 1. Review config/dw.config.yml — adjust team.roles, quality commands"
|
|
238
|
-
echo " 2. Run: bash setup.sh to regenerate .claude/ from new config"
|
|
239
|
-
echo " 3. Check adapters/claude-cli/overrides/ for preserved customizations"
|
|
240
|
-
[ "$found_refs" = true ] && echo " 4. ⚠ Update CI/CD files (see warnings above)"
|
|
241
|
-
fi
|
|
242
|
-
echo "══════════════════════════════════════════"
|
|
243
|
-
echo ""
|
package/scripts/upgrade.sh
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# scripts/upgrade.sh
|
|
3
|
-
# ⚠ DEPRECATED: Prefer `dw upgrade` from npm CLI.
|
|
4
|
-
# Upgrade dw-kit: update generated/ files, preserve overrides/ và extensions/
|
|
5
|
-
# Usage: bash scripts/upgrade.sh [--dry-run] [--layer core|platform|all]
|
|
6
|
-
|
|
7
|
-
set -euo pipefail
|
|
8
|
-
|
|
9
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
11
|
-
|
|
12
|
-
# ── Options ──────────────────────────────────────────────────────────────────
|
|
13
|
-
DRY_RUN=false
|
|
14
|
-
LAYER="all"
|
|
15
|
-
|
|
16
|
-
for arg in "$@"; do
|
|
17
|
-
case "$arg" in
|
|
18
|
-
--dry-run) DRY_RUN=true ;;
|
|
19
|
-
--layer) shift; LAYER="${1:-all}" ;;
|
|
20
|
-
--layer=*) LAYER="${arg#*=}" ;;
|
|
21
|
-
esac
|
|
22
|
-
done
|
|
23
|
-
|
|
24
|
-
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
25
|
-
log() { echo " $*"; }
|
|
26
|
-
info() { echo ""; echo "▶ $*"; }
|
|
27
|
-
warn() { echo " ⚠ $*"; }
|
|
28
|
-
ok() { echo " ✓ $*"; }
|
|
29
|
-
dry() { echo " [dry-run] $*"; }
|
|
30
|
-
|
|
31
|
-
do_copy() {
|
|
32
|
-
local src="$1" dst="$2"
|
|
33
|
-
if [ "$DRY_RUN" = true ]; then
|
|
34
|
-
dry "cp $src → $dst"
|
|
35
|
-
else
|
|
36
|
-
mkdir -p "$(dirname "$dst")"
|
|
37
|
-
cp "$src" "$dst"
|
|
38
|
-
fi
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
do_mkdir() {
|
|
42
|
-
if [ "$DRY_RUN" = true ]; then
|
|
43
|
-
dry "mkdir -p $1"
|
|
44
|
-
else
|
|
45
|
-
mkdir -p "$1"
|
|
46
|
-
fi
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# ── Read current versions ─────────────────────────────────────────────────────
|
|
50
|
-
CONFIG_FILE="$PROJECT_ROOT/.dw/config/dw.config.yml"
|
|
51
|
-
CURRENT_CORE="unknown"
|
|
52
|
-
CURRENT_PLATFORM="unknown"
|
|
53
|
-
|
|
54
|
-
if [ -f "$CONFIG_FILE" ]; then
|
|
55
|
-
CURRENT_CORE=$(grep -m1 "core_version:" "$CONFIG_FILE" 2>/dev/null \
|
|
56
|
-
| sed 's/.*:[[:space:]]*//' | tr -d '"' | tr -d "'" | tr -d '[:space:]' || echo "unknown")
|
|
57
|
-
CURRENT_PLATFORM=$(grep -m1 "platform_version:" "$CONFIG_FILE" 2>/dev/null \
|
|
58
|
-
| sed 's/.*:[[:space:]]*//' | tr -d '"' | tr -d "'" | tr -d '[:space:]' || echo "unknown")
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
TOOLKIT_CORE=$(grep -m1 "core-version:" "$PROJECT_ROOT/core/WORKFLOW.md" 2>/dev/null \
|
|
62
|
-
| sed 's/.*core-version:[[:space:]]*//' | tr -d ' -->' | head -1 || echo "1.0")
|
|
63
|
-
|
|
64
|
-
echo ""
|
|
65
|
-
echo "══════════════════════════════════════════"
|
|
66
|
-
echo " dw-kit Upgrade"
|
|
67
|
-
echo " Current: core=$CURRENT_CORE platform=$CURRENT_PLATFORM"
|
|
68
|
-
echo " Toolkit: core=$TOOLKIT_CORE"
|
|
69
|
-
if [ "$DRY_RUN" = true ]; then
|
|
70
|
-
echo " Mode: DRY RUN (no changes)"
|
|
71
|
-
fi
|
|
72
|
-
echo "══════════════════════════════════════════"
|
|
73
|
-
|
|
74
|
-
# ── Phase 1: Update generated/ ───────────────────────────────────────────────
|
|
75
|
-
info "Phase 1: Update generated files"
|
|
76
|
-
|
|
77
|
-
GENERATED="$PROJECT_ROOT/.dw/adapters/claude-cli/generated"
|
|
78
|
-
CLAUDE_DIR="$PROJECT_ROOT/.claude"
|
|
79
|
-
|
|
80
|
-
if [ "$LAYER" = "all" ] || [ "$LAYER" = "platform" ]; then
|
|
81
|
-
# Copy generated skills → .claude/skills (skip if override exists)
|
|
82
|
-
if [ -d "$GENERATED/skills" ]; then
|
|
83
|
-
for skill_dir in "$GENERATED/skills"/*/; do
|
|
84
|
-
skill_name=$(basename "$skill_dir")
|
|
85
|
-
override="$PROJECT_ROOT/.dw/adapters/claude-cli/overrides/skills/$skill_name"
|
|
86
|
-
|
|
87
|
-
if [ -d "$override" ]; then
|
|
88
|
-
warn "Skill '$skill_name': override exists → keeping override"
|
|
89
|
-
# Copy override instead of generated
|
|
90
|
-
for f in "$override"/*; do
|
|
91
|
-
[ -f "$f" ] && do_copy "$f" "$CLAUDE_DIR/skills/$skill_name/$(basename "$f")"
|
|
92
|
-
done
|
|
93
|
-
else
|
|
94
|
-
for f in "$skill_dir"*; do
|
|
95
|
-
[ -f "$f" ] && do_copy "$f" "$CLAUDE_DIR/skills/$skill_name/$(basename "$f")"
|
|
96
|
-
done
|
|
97
|
-
ok "Skill '$skill_name': updated"
|
|
98
|
-
fi
|
|
99
|
-
done
|
|
100
|
-
fi
|
|
101
|
-
|
|
102
|
-
# Copy generated agents → .claude/agents (skip if override exists)
|
|
103
|
-
if [ -d "$GENERATED/agents" ]; then
|
|
104
|
-
for agent_file in "$GENERATED/agents"/*.md; do
|
|
105
|
-
[ -f "$agent_file" ] || continue
|
|
106
|
-
agent_name=$(basename "$agent_file")
|
|
107
|
-
override="$PROJECT_ROOT/.dw/adapters/claude-cli/overrides/agents/$agent_name"
|
|
108
|
-
|
|
109
|
-
if [ -f "$override" ]; then
|
|
110
|
-
warn "Agent '$agent_name': override exists → keeping override"
|
|
111
|
-
do_copy "$override" "$CLAUDE_DIR/agents/$agent_name"
|
|
112
|
-
else
|
|
113
|
-
do_copy "$agent_file" "$CLAUDE_DIR/agents/$agent_name"
|
|
114
|
-
ok "Agent '$agent_name': updated"
|
|
115
|
-
fi
|
|
116
|
-
done
|
|
117
|
-
fi
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
# ── Phase 2: Copy extensions/ ────────────────────────────────────────────────
|
|
121
|
-
info "Phase 2: Copy extensions (team-specific skills)"
|
|
122
|
-
|
|
123
|
-
EXTENSIONS="$PROJECT_ROOT/.dw/adapters/claude-cli/extensions"
|
|
124
|
-
if [ -d "$EXTENSIONS" ]; then
|
|
125
|
-
ext_count=0
|
|
126
|
-
for ext_dir in "$EXTENSIONS"/*/; do
|
|
127
|
-
[ -d "$ext_dir" ] || continue
|
|
128
|
-
ext_name=$(basename "$ext_dir")
|
|
129
|
-
[ "$ext_name" = ".gitkeep" ] && continue
|
|
130
|
-
|
|
131
|
-
do_mkdir "$CLAUDE_DIR/skills/$ext_name"
|
|
132
|
-
for f in "$ext_dir"*; do
|
|
133
|
-
[ -f "$f" ] && do_copy "$f" "$CLAUDE_DIR/skills/$ext_name/$(basename "$f")"
|
|
134
|
-
done
|
|
135
|
-
ok "Extension '$ext_name': installed"
|
|
136
|
-
ext_count=$((ext_count + 1))
|
|
137
|
-
done
|
|
138
|
-
[ $ext_count -eq 0 ] && log "No extensions found"
|
|
139
|
-
fi
|
|
140
|
-
|
|
141
|
-
# ── Phase 3: Merge settings.json ─────────────────────────────────────────────
|
|
142
|
-
info "Phase 3: Merge settings.json"
|
|
143
|
-
|
|
144
|
-
SETTINGS_TEMPLATE="$GENERATED/settings.json"
|
|
145
|
-
SETTINGS_TARGET="$CLAUDE_DIR/settings.json"
|
|
146
|
-
|
|
147
|
-
if [ -f "$SETTINGS_TEMPLATE" ] && [ -f "$SETTINGS_TARGET" ]; then
|
|
148
|
-
if command -v python3 &>/dev/null; then
|
|
149
|
-
if [ "$DRY_RUN" = true ]; then
|
|
150
|
-
dry "Merge settings.json (python3)"
|
|
151
|
-
else
|
|
152
|
-
python3 - "$SETTINGS_TEMPLATE" "$SETTINGS_TARGET" <<'PYEOF'
|
|
153
|
-
import json, sys
|
|
154
|
-
|
|
155
|
-
template_path = sys.argv[1]
|
|
156
|
-
target_path = sys.argv[2]
|
|
157
|
-
|
|
158
|
-
with open(template_path) as f:
|
|
159
|
-
template = json.load(f)
|
|
160
|
-
with open(target_path) as f:
|
|
161
|
-
target = json.load(f)
|
|
162
|
-
|
|
163
|
-
def deep_merge(base, override):
|
|
164
|
-
"""Override values from base with override, but preserve keys not in template."""
|
|
165
|
-
result = dict(base)
|
|
166
|
-
for k, v in override.items():
|
|
167
|
-
if k in result and isinstance(result[k], dict) and isinstance(v, dict):
|
|
168
|
-
result[k] = deep_merge(result[k], v)
|
|
169
|
-
else:
|
|
170
|
-
result[k] = v
|
|
171
|
-
return result
|
|
172
|
-
|
|
173
|
-
merged = deep_merge(template, target)
|
|
174
|
-
|
|
175
|
-
with open(target_path, 'w') as f:
|
|
176
|
-
json.dump(merged, f, indent=2, ensure_ascii=False)
|
|
177
|
-
f.write('\n')
|
|
178
|
-
PYEOF
|
|
179
|
-
ok "settings.json: merged"
|
|
180
|
-
fi
|
|
181
|
-
else
|
|
182
|
-
warn "python3 not found — skipping settings.json merge. Manual merge may be needed."
|
|
183
|
-
fi
|
|
184
|
-
elif [ -f "$SETTINGS_TEMPLATE" ] && [ ! -f "$SETTINGS_TARGET" ]; then
|
|
185
|
-
do_copy "$SETTINGS_TEMPLATE" "$SETTINGS_TARGET"
|
|
186
|
-
ok "settings.json: created from template"
|
|
187
|
-
fi
|
|
188
|
-
|
|
189
|
-
# ── Phase 4: Update version in config ────────────────────────────────────────
|
|
190
|
-
info "Phase 4: Update version tracking"
|
|
191
|
-
|
|
192
|
-
if [ "$DRY_RUN" = false ] && [ -f "$CONFIG_FILE" ]; then
|
|
193
|
-
TODAY=$(date +%Y-%m-%d)
|
|
194
|
-
if command -v python3 &>/dev/null; then
|
|
195
|
-
python3 - "$CONFIG_FILE" "$TOOLKIT_CORE" "$TODAY" <<'PYEOF'
|
|
196
|
-
import sys, re
|
|
197
|
-
|
|
198
|
-
config_path = sys.argv[1]
|
|
199
|
-
new_core = sys.argv[2]
|
|
200
|
-
today = sys.argv[3]
|
|
201
|
-
|
|
202
|
-
with open(config_path) as f:
|
|
203
|
-
content = f.read()
|
|
204
|
-
|
|
205
|
-
content = re.sub(r'(core_version:\s*)["\']?[\d.]+["\']?', f'\\g<1>"{new_core}"', content)
|
|
206
|
-
content = re.sub(r'(last_upgrade:\s*)["\']?[\d-]+["\']?', f'\\g<1>"{today}"', content)
|
|
207
|
-
|
|
208
|
-
with open(config_path, 'w') as f:
|
|
209
|
-
f.write(content)
|
|
210
|
-
PYEOF
|
|
211
|
-
ok "Config version updated: core=$TOOLKIT_CORE, last_upgrade=$TODAY"
|
|
212
|
-
fi
|
|
213
|
-
fi
|
|
214
|
-
|
|
215
|
-
# ── Phase 5: Check for CI/CD references needing manual update ────────────────
|
|
216
|
-
info "Phase 5: Check backward compatibility"
|
|
217
|
-
|
|
218
|
-
OLD_CONFIG="$PROJECT_ROOT/.dw/config/dw.config.yml"
|
|
219
|
-
if [ -f "$OLD_CONFIG" ]; then
|
|
220
|
-
if [ -L "$OLD_CONFIG" ]; then
|
|
221
|
-
ok "config/dw.config.yml: symlink intact (backward compat)"
|
|
222
|
-
else
|
|
223
|
-
warn "config/dw.config.yml exists as real file. Run scripts/migrate-v03-to-v1.sh first."
|
|
224
|
-
fi
|
|
225
|
-
fi
|
|
226
|
-
|
|
227
|
-
# Check for CI references
|
|
228
|
-
for ci_file in ".github/workflows/"*.yml ".gitlab-ci.yml" "Makefile" ".circleci/config.yml"; do
|
|
229
|
-
full_path="$PROJECT_ROOT/$ci_file"
|
|
230
|
-
if [ -f "$full_path" ] && grep -q ".dw/.dw/config/dw.config.yml" "$full_path" 2>/dev/null; then
|
|
231
|
-
warn "CI file '$ci_file' references config/dw.config.yml — update manually"
|
|
232
|
-
fi
|
|
233
|
-
done
|
|
234
|
-
|
|
235
|
-
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
236
|
-
echo ""
|
|
237
|
-
echo "══════════════════════════════════════════"
|
|
238
|
-
if [ "$DRY_RUN" = true ]; then
|
|
239
|
-
echo " DRY RUN complete. No changes made."
|
|
240
|
-
echo " Run without --dry-run to apply."
|
|
241
|
-
else
|
|
242
|
-
echo " Upgrade complete!"
|
|
243
|
-
echo " Core version: $TOOLKIT_CORE"
|
|
244
|
-
fi
|
|
245
|
-
echo "══════════════════════════════════════════"
|
|
246
|
-
echo ""
|