From 08e70525ed7ea7bf44c70467d1ce4664026a8d8e Mon Sep 17 00:00:00 2001 From: xsser Date: Sun, 19 Apr 2026 22:20:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20pua-loop=20state=20file=20isolation=20?= =?UTF-8?q?=E2=80=94=20prevent=20cross-directory=20task=20bleed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State file was written to a single global path (~/.claude/pua/loop-active.md), causing two Claude Code instances in different directories to overwrite each other's loop state. Now uses cwd hash in filename (loop-.md) so each project directory has an independent loop instance. Fixes: multiple users reporting task A executing task B's commands when running pua-loop in two directories simultaneously. --- hooks/pua-loop-hook.sh | 14 +++++++++++++- scripts/setup-pua-loop.sh | 7 ++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/hooks/pua-loop-hook.sh b/hooks/pua-loop-hook.sh index 77ab4d3..fddcd74 100755 --- a/hooks/pua-loop-hook.sh +++ b/hooks/pua-loop-hook.sh @@ -42,11 +42,23 @@ fi # ═══════════════════════════════════════════════════════════════ HOOK_SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id // ""' 2>/dev/null || echo "") PUA_DIR="${HOME}/.claude/pua" -ABS_STATE_FILE="${PUA_DIR}/loop-active.md" +CWD_HASH=$(printf '%s' "$(pwd)" | md5sum 2>/dev/null | cut -c1-8 || printf '%s' "$(pwd)" | md5 2>/dev/null | cut -c1-8 || echo "default") +ABS_STATE_FILE="${PUA_DIR}/loop-${CWD_HASH}.md" +LEGACY_ABS_STATE_FILE="${PUA_DIR}/loop-active.md" LEGACY_STATE_FILE=".claude/pua-loop.local.md" if [[ -f "$ABS_STATE_FILE" ]]; then RALPH_STATE_FILE="$ABS_STATE_FILE" +elif [[ -f "$LEGACY_ABS_STATE_FILE" ]]; then + # v3.1 兼容:旧版单文件,检查 started_cwd 是否匹配当前目录 + LEGACY_CWD=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$LEGACY_ABS_STATE_FILE" | grep '^started_cwd:' | sed 's/started_cwd: *//' | sed 's/^"\(.*\)"$/\1/' || true) + if [[ "$LEGACY_CWD" == "$(pwd)" ]] || [[ -z "$LEGACY_CWD" ]]; then + RALPH_STATE_FILE="$LEGACY_ABS_STATE_FILE" + elif [[ -f "$LEGACY_STATE_FILE" ]]; then + RALPH_STATE_FILE="$LEGACY_STATE_FILE" + else + exit 0 + fi elif [[ -f "$LEGACY_STATE_FILE" ]]; then RALPH_STATE_FILE="$LEGACY_STATE_FILE" else diff --git a/scripts/setup-pua-loop.sh b/scripts/setup-pua-loop.sh index 5ea06c7..8633966 100755 --- a/scripts/setup-pua-loop.sh +++ b/scripts/setup-pua-loop.sh @@ -114,13 +114,14 @@ if [[ -z "$PROMPT" ]]; then fi # Create state file -# v3.1: 写绝对路径为主($HOME/.claude/pua/loop-active.md),跨 cwd 可找 -# 兼容:同时写 legacy 相对路径,老 hook 或用户工具链仍能访问 +# v3.2: 用 cwd 哈希命名状态文件,解决多目录 loop 实例互相覆盖的 bug +# 每个项目目录有独立的 loop-.md,不再共享单一 loop-active.md PUA_HOME_DIR="${HOME}/.claude/pua" mkdir -p "$PUA_HOME_DIR" mkdir -p .claude -ABS_STATE="${PUA_HOME_DIR}/loop-active.md" +CWD_HASH=$(printf '%s' "$(pwd)" | md5sum 2>/dev/null | cut -c1-8 || printf '%s' "$(pwd)" | md5 2>/dev/null | cut -c1-8 || echo "default") +ABS_STATE="${PUA_HOME_DIR}/loop-${CWD_HASH}.md" LEGACY_STATE=".claude/pua-loop.local.md" # YAML quoting