diff --git a/mem0-plugin/hooks/cursor-hooks.json b/mem0-plugin/hooks/cursor-hooks.json index 442d3718e..124148bea 100644 --- a/mem0-plugin/hooks/cursor-hooks.json +++ b/mem0-plugin/hooks/cursor-hooks.json @@ -15,10 +15,6 @@ "preCompact": [ { "command": "${CURSOR_PLUGIN_ROOT}/scripts/on_pre_compact.sh" - }, - { - "command": "python3 ${CURSOR_PLUGIN_ROOT}/scripts/on_pre_compact.py", - "timeout": 30 } ], "stop": [ diff --git a/mem0-plugin/hooks/hooks.json b/mem0-plugin/hooks/hooks.json index 897a978d9..2c98eb9d3 100644 --- a/mem0-plugin/hooks/hooks.json +++ b/mem0-plugin/hooks/hooks.json @@ -30,12 +30,6 @@ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_pre_compact.sh", "statusMessage": "Preparing pre-compaction summary..." - }, - { - "type": "command", - "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/on_pre_compact.py", - "statusMessage": "Saving session state to mem0...", - "timeout": 30 } ] } diff --git a/mem0-plugin/scripts/block_memory_write.sh b/mem0-plugin/scripts/block_memory_write.sh index 0cf6dbc84..bb38686d6 100755 --- a/mem0-plugin/scripts/block_memory_write.sh +++ b/mem0-plugin/scripts/block_memory_write.sh @@ -13,6 +13,10 @@ set -euo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""' 2>/dev/null || echo "") @@ -22,7 +26,7 @@ if [ -z "$FILE_PATH" ]; then fi case "$FILE_PATH" in - */MEMORY.md|*/memory/*.md|*/.claude/*/memory/*) + */MEMORY.md|*/.claude/memory/*) echo "BLOCKED: Do not write to $FILE_PATH. Use the mem0 MCP \`add_memory\` tool instead to persist memories. This project uses mem0 for all memory storage." >&2 exit 2 ;; diff --git a/mem0-plugin/scripts/on_pre_compact.py b/mem0-plugin/scripts/on_pre_compact.py index fb59e8d5c..8bc34c261 100755 --- a/mem0-plugin/scripts/on_pre_compact.py +++ b/mem0-plugin/scripts/on_pre_compact.py @@ -27,6 +27,16 @@ _handler = logging.StreamHandler(sys.stderr) _handler.setFormatter(logging.Formatter("[mem0-capture] %(message)s")) log.addHandler(_handler) +if os.environ.get("MEM0_DEBUG"): + _log_dir = os.path.expanduser("~/.mem0") + try: + os.makedirs(_log_dir, exist_ok=True) + _file_handler = logging.FileHandler(os.path.join(_log_dir, "hooks.log")) + _file_handler.setFormatter(logging.Formatter("[mem0-capture] %(asctime)s %(message)s")) + log.addHandler(_file_handler) + except OSError: + pass + API_URL = "https://api.mem0.ai" MAX_TAIL_LINES = 500 MAX_USER_MESSAGES = 30 @@ -149,7 +159,7 @@ def build_content(state: dict, source: str) -> str: return "\n".join(parts) -def store_memory(api_key: str, content: str, user_id: str, source: str) -> bool: +def store_memory(api_key: str, content: str, user_id: str, source: str, session_id: str = "") -> bool: """Store session state as a memory via the Mem0 REST API.""" body = { "messages": [ @@ -159,6 +169,7 @@ def store_memory(api_key: str, content: str, user_id: str, source: str) -> bool: "metadata": { "type": "session_state", "source": source, + "session_id": session_id, }, } @@ -207,6 +218,7 @@ def main(): log.debug("No transcript_path provided") return + session_id = hook_input.get("session_id", "") user_id = os.environ.get("MEM0_USER_ID", os.environ.get("USER", "default")) lines = tail_lines(transcript_path, MAX_TAIL_LINES) @@ -228,7 +240,7 @@ def main(): len(state["bash_commands"]), ) - store_memory(api_key, content, user_id, source) + store_memory(api_key, content, user_id, source, session_id) if __name__ == "__main__": diff --git a/mem0-plugin/scripts/on_pre_compact.sh b/mem0-plugin/scripts/on_pre_compact.sh index 0cd1dead2..3f96620b9 100755 --- a/mem0-plugin/scripts/on_pre_compact.sh +++ b/mem0-plugin/scripts/on_pre_compact.sh @@ -11,6 +11,10 @@ set -euo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + cat <<'EOF' ## CRITICAL: Pre-Compaction Session Summary diff --git a/mem0-plugin/scripts/on_session_start.sh b/mem0-plugin/scripts/on_session_start.sh index 353a17130..bb832f10f 100755 --- a/mem0-plugin/scripts/on_session_start.sh +++ b/mem0-plugin/scripts/on_session_start.sh @@ -11,6 +11,16 @@ # even if jq is missing or stdin is malformed. set -uo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + +# Skip the bootstrap entirely if no API key is configured -- the agent +# would otherwise be told to call mem0 MCP tools that will all fail. +if [ -z "${MEM0_API_KEY:-}" ]; then + exit 0 +fi + INPUT=$(cat) SOURCE=$(echo "$INPUT" | jq -r '.source // "startup"' 2>/dev/null || echo "startup") diff --git a/mem0-plugin/scripts/on_stop.sh b/mem0-plugin/scripts/on_stop.sh index 5dd088f69..848ab9906 100755 --- a/mem0-plugin/scripts/on_stop.sh +++ b/mem0-plugin/scripts/on_stop.sh @@ -12,6 +12,10 @@ set -euo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" INPUT=$(cat) diff --git a/mem0-plugin/scripts/on_stop_codex.sh b/mem0-plugin/scripts/on_stop_codex.sh index 80c16d311..de80b0fed 100755 --- a/mem0-plugin/scripts/on_stop_codex.sh +++ b/mem0-plugin/scripts/on_stop_codex.sh @@ -17,6 +17,10 @@ set -uo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + INPUT=$(cat) STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null || echo "false") diff --git a/mem0-plugin/scripts/on_task_completed.sh b/mem0-plugin/scripts/on_task_completed.sh index befc1b34a..57a568027 100755 --- a/mem0-plugin/scripts/on_task_completed.sh +++ b/mem0-plugin/scripts/on_task_completed.sh @@ -9,6 +9,10 @@ set -euo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + INPUT=$(cat) TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject // "unknown task"' 2>/dev/null || echo "unknown task") diff --git a/mem0-plugin/scripts/on_user_prompt.sh b/mem0-plugin/scripts/on_user_prompt.sh index 70f8eaa44..5555cacfe 100755 --- a/mem0-plugin/scripts/on_user_prompt.sh +++ b/mem0-plugin/scripts/on_user_prompt.sh @@ -13,6 +13,10 @@ # must never block the user's prompt. set -uo pipefail +if [ -n "${MEM0_DEBUG:-}" ]; then + mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log" +fi + INPUT=$(cat) PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""' 2>/dev/null || echo "") diff --git a/pyproject.toml b/pyproject.toml index c5bf151c4..603fbde60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,3 +154,4 @@ known-first-party = ["mem0", "mem0_cli"] profile = "black" known_first_party = ["mem0", "mem0_cli"] # isort scope kept aligned with [tool.ruff.lint.isort] above. +# black-equivalent profile here matches the formatter behaviour ruff applies.