refactor: consolidate hook scripts and fixed issue from review
This commit is contained in:
@@ -4,7 +4,7 @@ Give your AI a persistent memory -- mine projects and conversations into a searc
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.9+
|
||||||
- Codex CLI installed and configured
|
- Codex CLI installed and configured
|
||||||
- `pip install mempalace`
|
- `pip install mempalace`
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "./hooks/mempal-session-start-hook.sh"
|
"command": "${CODEX_PLUGIN_ROOT}/hooks/mempal-hook.sh session-start"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "./hooks/mempal-stop-hook.sh"
|
"command": "${CODEX_PLUGIN_ROOT}/hooks/mempal-hook.sh stop"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"hooks": [
|
"hooks": [
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "./hooks/mempal-precompact-hook.sh"
|
"command": "${CODEX_PLUGIN_ROOT}/hooks/mempal-hook.sh precompact"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
HOOK_NAME="${1:?Usage: mempal-hook.sh <hook-name>}"
|
||||||
|
INPUT_FILE=$(mktemp) || { echo "Failed to create temp file" >&2; exit 1; }
|
||||||
|
cat > "$INPUT_FILE"
|
||||||
|
cat "$INPUT_FILE" | python3 -m mempalace hook run --hook "$HOOK_NAME" --harness codex
|
||||||
|
EXIT_CODE=$?
|
||||||
|
rm -f "$INPUT_FILE" 2>/dev/null
|
||||||
|
exit $EXIT_CODE
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
PLUGIN_ROOT="${CODEX_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
||||||
|
|
||||||
# Capture stdin (hook input from Codex)
|
|
||||||
INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/mempal-precompact-hook-$$.json")
|
|
||||||
cat > "$INPUT_FILE"
|
|
||||||
|
|
||||||
# Pipe to Python CLI with codex harness
|
|
||||||
cat "$INPUT_FILE" | python3 -m mempalace hook run --hook precompact --harness codex
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f "$INPUT_FILE" 2>/dev/null
|
|
||||||
exit $EXIT_CODE
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
PLUGIN_ROOT="${CODEX_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
||||||
|
|
||||||
# Capture stdin (hook input from Codex)
|
|
||||||
INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/mempal-session-start-hook-$$.json")
|
|
||||||
cat > "$INPUT_FILE"
|
|
||||||
|
|
||||||
# Pipe to Python CLI with codex harness
|
|
||||||
cat "$INPUT_FILE" | python3 -m mempalace hook run --hook session-start --harness codex
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f "$INPUT_FILE" 2>/dev/null
|
|
||||||
exit $EXIT_CODE
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
PLUGIN_ROOT="${CODEX_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
||||||
|
|
||||||
# Capture stdin (hook input from Codex)
|
|
||||||
INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/mempal-stop-hook-$$.json")
|
|
||||||
cat > "$INPUT_FILE"
|
|
||||||
|
|
||||||
# Pipe to Python CLI with codex harness
|
|
||||||
cat "$INPUT_FILE" | python3 -m mempalace hook run --hook stop --harness codex
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
rm -f "$INPUT_FILE" 2>/dev/null
|
|
||||||
exit $EXIT_CODE
|
|
||||||
+19
-26
@@ -53,8 +53,15 @@ def _count_human_messages(transcript_path: str) -> int:
|
|||||||
msg = entry.get("message", {})
|
msg = entry.get("message", {})
|
||||||
if isinstance(msg, dict) and msg.get("role") == "user":
|
if isinstance(msg, dict) and msg.get("role") == "user":
|
||||||
content = msg.get("content", "")
|
content = msg.get("content", "")
|
||||||
if isinstance(content, str) and "<command-message>" in content:
|
if isinstance(content, str):
|
||||||
continue
|
if "<command-message>" in content:
|
||||||
|
continue
|
||||||
|
elif isinstance(content, list):
|
||||||
|
text = " ".join(
|
||||||
|
b.get("text", "") for b in content if isinstance(b, dict)
|
||||||
|
)
|
||||||
|
if "<command-message>" in text:
|
||||||
|
continue
|
||||||
count += 1
|
count += 1
|
||||||
except (json.JSONDecodeError, AttributeError):
|
except (json.JSONDecodeError, AttributeError):
|
||||||
pass
|
pass
|
||||||
@@ -96,35 +103,19 @@ def _maybe_auto_ingest():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _parse_claude_code_input(data: dict) -> dict:
|
SUPPORTED_HARNESSES = {"claude-code", "codex"}
|
||||||
"""Parse stdin JSON for the claude-code harness."""
|
|
||||||
return {
|
|
||||||
"session_id": _sanitize_session_id(str(data.get("session_id", "unknown"))),
|
|
||||||
"stop_hook_active": data.get("stop_hook_active", False),
|
|
||||||
"transcript_path": str(data.get("transcript_path", "")),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_codex_input(data: dict) -> dict:
|
|
||||||
"""Parse stdin JSON for the codex harness."""
|
|
||||||
return {
|
|
||||||
"session_id": _sanitize_session_id(str(data.get("session_id", "unknown"))),
|
|
||||||
"stop_hook_active": data.get("stop_hook_active", False),
|
|
||||||
"transcript_path": str(data.get("transcript_path", "")),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_harness_input(data: dict, harness: str) -> dict:
|
def _parse_harness_input(data: dict, harness: str) -> dict:
|
||||||
"""Parse stdin JSON according to the harness type."""
|
"""Parse stdin JSON according to the harness type."""
|
||||||
parsers = {
|
if harness not in SUPPORTED_HARNESSES:
|
||||||
"claude-code": _parse_claude_code_input,
|
|
||||||
"codex": _parse_codex_input,
|
|
||||||
}
|
|
||||||
parser = parsers.get(harness)
|
|
||||||
if parser is None:
|
|
||||||
print(f"Unknown harness: {harness}", file=sys.stderr)
|
print(f"Unknown harness: {harness}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return parser(data)
|
return {
|
||||||
|
"session_id": _sanitize_session_id(str(data.get("session_id", "unknown"))),
|
||||||
|
"stop_hook_active": data.get("stop_hook_active", False),
|
||||||
|
"transcript_path": str(data.get("transcript_path", "")),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def hook_stop(data: dict, harness: str):
|
def hook_stop(data: dict, harness: str):
|
||||||
@@ -135,7 +126,7 @@ def hook_stop(data: dict, harness: str):
|
|||||||
transcript_path = parsed["transcript_path"]
|
transcript_path = parsed["transcript_path"]
|
||||||
|
|
||||||
# If already in a save cycle, let through (infinite-loop prevention)
|
# If already in a save cycle, let through (infinite-loop prevention)
|
||||||
if stop_hook_active in (True, "True", "true"):
|
if str(stop_hook_active).lower() in ("true", "1", "yes"):
|
||||||
_output({})
|
_output({})
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -204,6 +195,7 @@ def hook_precompact(data: dict, harness: str):
|
|||||||
[sys.executable, "-m", "mempalace", "mine", mempal_dir],
|
[sys.executable, "-m", "mempalace", "mine", mempal_dir],
|
||||||
stdout=log_f,
|
stdout=log_f,
|
||||||
stderr=log_f,
|
stderr=log_f,
|
||||||
|
timeout=60,
|
||||||
)
|
)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
@@ -217,6 +209,7 @@ def run_hook(hook_name: str, harness: str):
|
|||||||
try:
|
try:
|
||||||
data = json.load(sys.stdin)
|
data = json.load(sys.stdin)
|
||||||
except (json.JSONDecodeError, EOFError):
|
except (json.JSONDecodeError, EOFError):
|
||||||
|
_log("WARNING: Failed to parse stdin JSON, proceeding with empty data")
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
hooks = {
|
hooks = {
|
||||||
|
|||||||
Reference in New Issue
Block a user