cleanup and remote only
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
#!/bin/bash
|
||||
# MEMPALACE PRE-COMPACT HOOK (REMOTE) — emergency save before compaction.
|
||||
#
|
||||
# Drop-in replacement for mempal_precompact_hook.sh when MemPalace runs
|
||||
# on a server. Always synchronous: we wait for the upload to complete
|
||||
# before returning so the transcript is on the server before the
|
||||
# conversation gets compressed.
|
||||
#
|
||||
# Required env vars (same as the save hook):
|
||||
# MEMPAL_REMOTE_URL e.g. https://unraid.local:8443
|
||||
# MEMPAL_REMOTE_TOKEN bearer token
|
||||
# Optional:
|
||||
# MEMPAL_REMOTE_WING explicit wing override
|
||||
# MEMPAL_REMOTE_INSECURE "1" for self-signed cert
|
||||
#
|
||||
# === INSTALL ===
|
||||
# Add to .claude/settings.local.json:
|
||||
#
|
||||
# "hooks": {
|
||||
# "PreCompact": [{
|
||||
# "hooks": [{
|
||||
# "type": "command",
|
||||
# "command": "/abs/path/to/mempal_precompact_hook_remote.sh",
|
||||
# "timeout": 60
|
||||
# }]
|
||||
# }]
|
||||
# }
|
||||
|
||||
set -u
|
||||
|
||||
STATE_DIR="$HOME/.mempalace/hook_state"
|
||||
mkdir -p "$STATE_DIR"
|
||||
|
||||
MEMPAL_PYTHON_BIN="${MEMPAL_PYTHON:-}"
|
||||
if [ -z "$MEMPAL_PYTHON_BIN" ] || [ ! -x "$MEMPAL_PYTHON_BIN" ]; then
|
||||
MEMPAL_PYTHON_BIN="$(command -v python3 2>/dev/null || echo python3)"
|
||||
fi
|
||||
|
||||
if [ -z "${MEMPAL_REMOTE_URL:-}" ] || [ -z "${MEMPAL_REMOTE_TOKEN:-}" ]; then
|
||||
echo "[$(date '+%H:%M:%S')] PRE-COMPACT: MEMPAL_REMOTE_URL/TOKEN not set — skipping" \
|
||||
>> "$STATE_DIR/hook.log"
|
||||
echo "{}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
mapfile -t _mempal_parsed < <(echo "$INPUT" | "$MEMPAL_PYTHON_BIN" -c "
|
||||
import sys, json, re
|
||||
data = json.load(sys.stdin)
|
||||
sid = data.get('session_id', 'unknown')
|
||||
tp = data.get('transcript_path', '')
|
||||
safe = lambda s: re.sub(r'[^a-zA-Z0-9_/.\-~]', '', str(s))
|
||||
print(safe(sid))
|
||||
print(safe(tp))
|
||||
" 2>/dev/null)
|
||||
SESSION_ID="${_mempal_parsed[0]:-unknown}"
|
||||
TRANSCRIPT_PATH="${_mempal_parsed[1]:-}"
|
||||
TRANSCRIPT_PATH="${TRANSCRIPT_PATH/#\~/$HOME}"
|
||||
|
||||
is_valid_transcript_path() {
|
||||
local path="$1"
|
||||
[ -n "$path" ] || return 1
|
||||
case "$path" in
|
||||
*.json|*.jsonl) ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
case "/$path/" in
|
||||
*/../*) return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
echo "[$(date '+%H:%M:%S')] PRE-COMPACT triggered for session $SESSION_ID" \
|
||||
>> "$STATE_DIR/hook.log"
|
||||
|
||||
# Synchronous upload — pre-compact is the safety net, blocking is correct
|
||||
# here. The Claude Code hook timeout (set in settings.local.json) bounds
|
||||
# how long we'll wait.
|
||||
if is_valid_transcript_path "$TRANSCRIPT_PATH" && [ -f "$TRANSCRIPT_PATH" ]; then
|
||||
CURL_OPTS=("-sS" "--max-time" "55" "-X" "POST")
|
||||
[ "${MEMPAL_REMOTE_INSECURE:-0}" = "1" ] && CURL_OPTS+=("-k")
|
||||
WING_HEADER=()
|
||||
[ -n "${MEMPAL_REMOTE_WING:-}" ] && WING_HEADER=(-H "X-Wing: $MEMPAL_REMOTE_WING")
|
||||
|
||||
curl "${CURL_OPTS[@]}" \
|
||||
-H "Authorization: Bearer $MEMPAL_REMOTE_TOKEN" \
|
||||
-H "X-Session-Id: $SESSION_ID" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
"${WING_HEADER[@]}" \
|
||||
--data-binary "@$TRANSCRIPT_PATH" \
|
||||
"$MEMPAL_REMOTE_URL/ingest/transcript" \
|
||||
>> "$STATE_DIR/hook.log" 2>&1 \
|
||||
&& echo "[$(date '+%H:%M:%S')] PRE-COMPACT ingest ok" >> "$STATE_DIR/hook.log" \
|
||||
|| echo "[$(date '+%H:%M:%S')] PRE-COMPACT ingest FAILED — context will compact unsaved" \
|
||||
>> "$STATE_DIR/hook.log"
|
||||
elif [ -n "$TRANSCRIPT_PATH" ]; then
|
||||
echo "[$(date '+%H:%M:%S')] PRE-COMPACT: invalid transcript path: $TRANSCRIPT_PATH" \
|
||||
>> "$STATE_DIR/hook.log"
|
||||
fi
|
||||
|
||||
echo "{}"
|
||||
Reference in New Issue
Block a user