#!/usr/bin/env bash
# Reapply "reply session initialization conflicted" retry-hardening patch.
# Safe to run after OpenClaw updates. Idempotent: skips if already patched.
set -euo pipefail

DIST_DIR="/home/linuxbrew/.linuxbrew/lib/node_modules/openclaw/dist"
# Find get-reply-*.js (hash suffix may change between versions)
TARGET="$(ls -1 "$DIST_DIR"/get-reply-*.js 2>/dev/null | grep -v '\.bak' | head -1)"

if [[ -z "$TARGET" ]]; then
  echo "❌ get-reply-*.js not found in $DIST_DIR" >&2
  exit 1
fi

if grep -q "REPLY_SESSION_INIT_MAX_RETRIES" "$TARGET"; then
  echo "✓ Patch already applied in $(basename "$TARGET")"
  exit 0
fi

TS="$(date +%Y%m%d-%H%M%S)"
cp "$TARGET" "$TARGET.bak-reply-conflict-fix-$TS"
echo "→ Backup: $TARGET.bak-reply-conflict-fix-$TS"

python3 - "$TARGET" <<'PY'
import re, sys
path = sys.argv[1]
src = open(path).read()

old1 = "/** Initializes or reuses the reply session state for one inbound turn. */\nasync function initSessionState(params) {\n\treturn await initSessionStateAttempt(params, false);\n}\nasync function initSessionStateAttempt(params, staleSnapshotRetried) {"
new1 = "/** Initializes or reuses the reply session state for one inbound turn. */\nconst REPLY_SESSION_INIT_MAX_RETRIES = 8;\nconst REPLY_SESSION_INIT_BACKOFF_BASE_MS = 25;\nconst REPLY_SESSION_INIT_BACKOFF_MAX_MS = 400;\nasync function initSessionState(params) {\n\treturn await initSessionStateAttempt(params, 0);\n}\nasync function initSessionStateAttempt(params, staleSnapshotRetried) {"

old2 = "\tif (!committed.ok) {\n\t\tif (!staleSnapshotRetried) return await initSessionStateAttempt(params, true);\n\t\tthrow new Error(`reply session initialization conflicted for ${sessionKey}`);\n\t}"
new2 = "\tif (!committed.ok) {\n\t\tconst retryCount = typeof staleSnapshotRetried === \"number\" ? staleSnapshotRetried : (staleSnapshotRetried ? 1 : 0);\n\t\tif (retryCount < REPLY_SESSION_INIT_MAX_RETRIES) {\n\t\t\tconst delay = Math.min(REPLY_SESSION_INIT_BACKOFF_MAX_MS, REPLY_SESSION_INIT_BACKOFF_BASE_MS * (2 ** retryCount));\n\t\t\tconst jitter = Math.floor(Math.random() * (delay / 2));\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay + jitter));\n\t\t\treturn await initSessionStateAttempt(params, retryCount + 1);\n\t\t}\n\t\tthrow new Error(`reply session initialization conflicted for ${sessionKey} (after ${retryCount} retries)`);\n\t}"

if old1 not in src:
    print("❌ upstream code changed for block1 — inspect manually", file=sys.stderr); sys.exit(2)
if old2 not in src:
    print("❌ upstream code changed for block2 — inspect manually", file=sys.stderr); sys.exit(2)

src = src.replace(old1, new1).replace(old2, new2)
open(path, "w").write(src)
print("✓ Patch applied")
PY

node --check "$TARGET" && echo "✓ Syntax OK: $(basename "$TARGET")"
echo ""
echo "🔄 Gateway restart required: gateway restart tool"
