mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-06-04 10:14:47 +08:00
fix(migrate-v2): bash 3.2 compatibility + reset coverage
migrate-v2.sh
Replace `declare -A STEP_RESULTS` with two parallel indexed arrays
(STEP_NAMES + STEP_STATUSES) plus a `record_step` helper. macOS ships
bash 3.2 which has no associative arrays — `declare -A` errored out
silently and every `STEP_RESULTS["1a-env"]=...` triggered a fatal
bash arithmetic error (interpreting "1a" as a number). Visible
symptom: `steps: {}` in handoff.json. Latent symptom: phase 2c's
install loop sometimes bailed mid-iteration before invoking the
channel install script, leaving channel code uninstalled while
reporting `overall_status: success`.
migrate-v2-reset.sh
Cover the gaps that left install side-effects in place between
iterations:
- Remove untracked adapter files in src/channels/ (mirror the
pattern already used for container/skills/).
- Restore tracked setup helpers that channel installs overwrite
(setup/whatsapp-auth.ts, setup/pair-telegram.ts, setup/index.ts)
and remove untracked ones they create (setup/groups.ts).
- Restore package.json + pnpm-lock.yaml (channel installs add
deps like @whiskeysockets/baileys).
Setup/migrate-v2/* is intentionally not touched — that's where user
WIP lives.
Verified end-to-end: reset → migrate → all 9 steps reported in
handoff.json with status "success", phase 2c install actually runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+37
-8
@@ -6,17 +6,27 @@
|
||||
# bash migrate-v2-reset.sh && bash migrate-v2.sh
|
||||
#
|
||||
# What it removes:
|
||||
# - data/ (v2 DBs, session state)
|
||||
# - logs/ (migration + setup logs)
|
||||
# - .env (merged env keys)
|
||||
# - groups/*/ (non-git group folders copied from v1)
|
||||
# - data/ (v2 DBs, session state)
|
||||
# - logs/ (migration + setup logs)
|
||||
# - .env (merged env keys)
|
||||
# - groups/*/ (non-git group folders copied from v1)
|
||||
# - container/skills/*/ (untracked skill dirs copied from v1)
|
||||
# - src/channels/*.ts (untracked adapters copied from channels branch)
|
||||
# - setup/groups.ts (untracked, copied by channel install scripts)
|
||||
#
|
||||
# What it restores:
|
||||
# - groups/global/CLAUDE.md and groups/main/CLAUDE.md from git
|
||||
# What it restores from git:
|
||||
# - groups/ (CLAUDE.md files etc.)
|
||||
# - container/skills/ (tracked container skills)
|
||||
# - src/channels/ (tracked bridge / registry code)
|
||||
# - setup/whatsapp-auth.ts (channel installs may overwrite)
|
||||
# - setup/pair-telegram.ts (channel installs may overwrite)
|
||||
# - setup/index.ts (channel installs append entries)
|
||||
# - package.json + pnpm-lock.yaml (channel installs add deps)
|
||||
#
|
||||
# What it does NOT touch:
|
||||
# - node_modules/ (expensive to reinstall, keep it)
|
||||
# - The v1 install (read-only, never modified)
|
||||
# - node_modules/ (expensive to reinstall, kept on purpose)
|
||||
# - setup/migrate-v2/* (the migration scripts themselves, plus user WIP)
|
||||
# - The v1 install (read-only, never modified)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -63,7 +73,26 @@ printf '%s Restored %s\n' "$(green '✓')" "container/skills/ from git"
|
||||
|
||||
# Restore channel code (src/channels/) to git state
|
||||
git checkout -- src/channels/ 2>/dev/null || true
|
||||
# Remove any untracked channel adapters copied in by install-*.sh
|
||||
for f in src/channels/*.ts; do
|
||||
[ -f "$f" ] || continue
|
||||
if ! git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
|
||||
rm -f "$f"
|
||||
fi
|
||||
done
|
||||
printf '%s Restored %s\n' "$(green '✓')" "src/channels/ from git"
|
||||
|
||||
# Restore tracked setup helpers that channel installs overwrite, and
|
||||
# remove the untracked ones they create. Don't blanket-clean setup/
|
||||
# because user WIP (setup/migrate-v2/*) lives there too.
|
||||
git checkout -- setup/whatsapp-auth.ts setup/pair-telegram.ts setup/index.ts 2>/dev/null || true
|
||||
rm -f setup/groups.ts
|
||||
printf '%s Restored %s\n' "$(green '✓')" "setup/ install helpers"
|
||||
|
||||
# Restore package.json + lockfile (channel installs add deps like
|
||||
# @whiskeysockets/baileys). node_modules/ is intentionally kept.
|
||||
git checkout -- package.json pnpm-lock.yaml 2>/dev/null || true
|
||||
printf '%s Restored %s\n' "$(green '✓')" "package.json + pnpm-lock.yaml"
|
||||
|
||||
echo
|
||||
printf '%s\n\n' "$(dim 'Clean. Run: bash migrate-v2.sh')"
|
||||
|
||||
+36
-23
@@ -29,14 +29,25 @@ SERVICE_SWITCHED=false
|
||||
SELECTED_CHANNELS=()
|
||||
ABORTED_AT=""
|
||||
|
||||
# Per-step status tracking. Parallel indexed arrays so this works on
|
||||
# bash 3.2 (macOS default) which has no associative arrays.
|
||||
STEP_NAMES=()
|
||||
STEP_STATUSES=()
|
||||
|
||||
record_step() {
|
||||
STEP_NAMES+=("$1")
|
||||
STEP_STATUSES+=("$2")
|
||||
}
|
||||
|
||||
# Write handoff.json on any exit so the skill can always read it
|
||||
write_handoff() {
|
||||
local handoff_dir="$LOGS_DIR/setup-migration"
|
||||
mkdir -p "$handoff_dir"
|
||||
|
||||
local has_failures=false
|
||||
for step_name in "${!STEP_RESULTS[@]}"; do
|
||||
[ "${STEP_RESULTS[$step_name]}" = "failed" ] && has_failures=true
|
||||
local i
|
||||
for ((i=0; i<${#STEP_NAMES[@]}; i++)); do
|
||||
[ "${STEP_STATUSES[$i]}" = "failed" ] && has_failures=true
|
||||
done
|
||||
|
||||
local overall="success"
|
||||
@@ -44,8 +55,10 @@ write_handoff() {
|
||||
[ -n "$ABORTED_AT" ] && overall="failed"
|
||||
|
||||
local steps_json="{"
|
||||
for step_name in "${!STEP_RESULTS[@]}"; do
|
||||
steps_json="${steps_json}\"${step_name}\": {\"status\": \"${STEP_RESULTS[$step_name]}\", \"log\": \"logs/migrate-steps/${step_name}.log\"},"
|
||||
for ((i=0; i<${#STEP_NAMES[@]}; i++)); do
|
||||
local n="${STEP_NAMES[$i]}"
|
||||
local s="${STEP_STATUSES[$i]}"
|
||||
steps_json="${steps_json}\"${n}\": {\"status\": \"${s}\", \"log\": \"logs/migrate-steps/${n}.log\"},"
|
||||
done
|
||||
steps_json="${steps_json%,}}"
|
||||
|
||||
@@ -245,8 +258,8 @@ export NANOCLAW_V2_PATH="$PROJECT_ROOT"
|
||||
# ─── run_step helper ─────────────────────────────────────────────────────
|
||||
# Runs a TypeScript migration step, captures output, reports success/failure.
|
||||
|
||||
# Track step outcomes for handoff.json
|
||||
declare -A STEP_RESULTS
|
||||
# Step outcomes are tracked via record_step() into STEP_NAMES/STEP_STATUSES
|
||||
# (defined above, near write_handoff).
|
||||
|
||||
run_step() {
|
||||
local name=$1 label=$2 script=$3
|
||||
@@ -258,7 +271,7 @@ run_step() {
|
||||
result=$(grep '^OK:' "$raw" | head -1 || true)
|
||||
step_ok "$label $(dim "$result")"
|
||||
log "$name: $result"
|
||||
STEP_RESULTS[$name]="success"
|
||||
record_step "$name" "success"
|
||||
# Surface partial errors (rows skipped due to parse/lookup failures)
|
||||
# even when the step exited successfully — they're easy to miss in the
|
||||
# raw log and have caused silent migrations before.
|
||||
@@ -276,7 +289,7 @@ run_step() {
|
||||
reason=$(grep '^SKIPPED:' "$raw" | head -1 | sed 's/^SKIPPED://')
|
||||
step_skip "$label $(dim "($reason)")"
|
||||
log "$name: skipped ($reason)"
|
||||
STEP_RESULTS[$name]="skipped"
|
||||
record_step "$name" "skipped"
|
||||
else
|
||||
step_fail "$label"
|
||||
echo
|
||||
@@ -285,7 +298,7 @@ run_step() {
|
||||
done
|
||||
echo
|
||||
log "$name: FAILED (see $raw)"
|
||||
STEP_RESULTS[$name]="failed"
|
||||
record_step "$name" "failed"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -359,10 +372,10 @@ else
|
||||
STATUS_LINE=$(grep '^STATUS:' "$STEP_LOG" | head -1 | sed 's/^STATUS: *//')
|
||||
if [ "$STATUS_LINE" = "already-installed" ]; then
|
||||
step_skip "Install $ch $(dim "(already installed)")"
|
||||
STEP_RESULTS[$STEP_NAME]="skipped"
|
||||
record_step "$STEP_NAME" "skipped"
|
||||
else
|
||||
step_ok "Install $ch"
|
||||
STEP_RESULTS[$STEP_NAME]="success"
|
||||
record_step "$STEP_NAME" "success"
|
||||
fi
|
||||
log "install-$ch: $STATUS_LINE"
|
||||
else
|
||||
@@ -371,12 +384,12 @@ else
|
||||
echo " $(dim "$line")"
|
||||
done
|
||||
log "install-$ch: FAILED (see $STEP_LOG)"
|
||||
STEP_RESULTS[$STEP_NAME]="failed"
|
||||
record_step "$STEP_NAME" "failed"
|
||||
fi
|
||||
else
|
||||
step_skip "Install $ch $(dim "(no install script)")"
|
||||
log "install-$ch: no install script"
|
||||
STEP_RESULTS[$STEP_NAME]="failed"
|
||||
record_step "$STEP_NAME" "failed"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -401,11 +414,11 @@ else
|
||||
if bash setup/install-docker.sh > "$DOCKER_LOG" 2>&1; then
|
||||
hash -r 2>/dev/null || true
|
||||
step_ok "Docker installed"
|
||||
STEP_RESULTS["3a-docker"]="success"
|
||||
record_step "3a-docker" "success"
|
||||
log "Docker: installed"
|
||||
else
|
||||
step_fail "Docker install failed $(dim "(see $DOCKER_LOG)")"
|
||||
STEP_RESULTS["3a-docker"]="failed"
|
||||
record_step "3a-docker" "failed"
|
||||
log "Docker: FAILED"
|
||||
fi
|
||||
fi
|
||||
@@ -426,16 +439,16 @@ elif command -v docker >/dev/null 2>&1; then
|
||||
if pnpm exec tsx setup/index.ts --step onecli > "$ONECLI_LOG" 2>"$ONECLI_ERR"; then
|
||||
step_ok "OneCLI ready"
|
||||
ONECLI_OK=true
|
||||
STEP_RESULTS["3b-onecli"]="success"
|
||||
record_step "3b-onecli" "success"
|
||||
log "OneCLI: installed/configured"
|
||||
else
|
||||
step_fail "OneCLI setup failed $(dim "(see $ONECLI_LOG)")"
|
||||
STEP_RESULTS["3b-onecli"]="failed"
|
||||
record_step "3b-onecli" "failed"
|
||||
log "OneCLI: FAILED"
|
||||
fi
|
||||
else
|
||||
step_fail "OneCLI needs Docker $(dim "(install Docker first)")"
|
||||
STEP_RESULTS["3b-onecli"]="failed"
|
||||
record_step "3b-onecli" "failed"
|
||||
log "OneCLI: skipped (no Docker)"
|
||||
fi
|
||||
|
||||
@@ -449,11 +462,11 @@ elif [ "$ONECLI_OK" = "true" ]; then
|
||||
AUTH_ERR="$STEPS_DIR/3c-auth.err"
|
||||
if pnpm exec tsx setup/index.ts --step auth > "$AUTH_LOG" 2>"$AUTH_ERR"; then
|
||||
step_ok "Anthropic credential registered"
|
||||
STEP_RESULTS["3c-auth"]="success"
|
||||
record_step "3c-auth" "success"
|
||||
log "Anthropic credential: registered via auth step"
|
||||
else
|
||||
step_fail "Auth setup failed $(dim "(see $AUTH_LOG)")"
|
||||
STEP_RESULTS["3c-auth"]="failed"
|
||||
record_step "3c-auth" "failed"
|
||||
log "Anthropic credential: FAILED"
|
||||
fi
|
||||
else
|
||||
@@ -494,11 +507,11 @@ if command -v docker >/dev/null 2>&1; then
|
||||
BUILD_LOG="$STEPS_DIR/3e-container-build.log"
|
||||
if bash container/build.sh > "$BUILD_LOG" 2>&1; then
|
||||
step_ok "Container image built"
|
||||
STEP_RESULTS["3e-build"]="success"
|
||||
record_step "3e-build" "success"
|
||||
log "Container build: success"
|
||||
else
|
||||
step_fail "Container build failed"
|
||||
STEP_RESULTS["3e-build"]="failed"
|
||||
record_step "3e-build" "failed"
|
||||
tail -10 "$BUILD_LOG" 2>/dev/null | while IFS= read -r line; do
|
||||
echo " $(dim "$line")"
|
||||
done
|
||||
@@ -506,7 +519,7 @@ if command -v docker >/dev/null 2>&1; then
|
||||
fi
|
||||
else
|
||||
step_fail "Docker not available — cannot build container"
|
||||
STEP_RESULTS["3e-build"]="failed"
|
||||
record_step "3e-build" "failed"
|
||||
log "Container build: skipped (no Docker)"
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user