eagle-mem 4.13.0 → 4.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/lib/hooks.sh +37 -0
- package/package.json +1 -1
- package/scripts/install.sh +3 -41
- package/scripts/test.sh +20 -2
- package/scripts/update.sh +3 -17
- package/tests/test_compaction_survival_matrix.sh +13 -1
- package/tests/test_rust_migration_plan.sh +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to the **Eagle Mem** project are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## v4.13.1 Test-Suite & Packaging Hygiene
|
|
8
|
+
|
|
9
|
+
Follow-up cleanup that clears the bounded items left after the v4.13.0 review. No runtime behavior change for normal sessions.
|
|
10
|
+
|
|
11
|
+
- **`eagle-mem test` is now green from a published install.** Two suites failed when run from an installed package rather than a source checkout:
|
|
12
|
+
- *Compaction Survival Matrix* created its fixture repo inside `$ROOT_DIR`; from a published install that path is under `node_modules/`, which the code scanner excludes — so the fixture indexed 0 files and the post-compact "Relevant Code" recall never appeared. The fixture now lives in a neutral system temp dir and is indexed explicitly (no longer relying on a racy background auto-index).
|
|
13
|
+
- *Rust Migration Plan* guards `MIGRATION.md`, a maintainer roadmap intentionally not shipped in the npm package. It now **skips cleanly** when the doc is absent and runs strictly from a source checkout.
|
|
14
|
+
- The test runner learned an honest **"skipped"** state (a dev-only contract test with absent preconditions is neither a pass nor a failure).
|
|
15
|
+
- **Antigravity Python hook test is now in the suite.** `tests/test_antigravity_hook.py` (mocked, stdlib-only) ran only by hand before; it's now a guarded python lane that skips cleanly if `python3` is unavailable.
|
|
16
|
+
- **One source of truth for Claude hook registration.** `install.sh` and `update.sh` each held their own copy of the event→matcher→script mapping (the historical drift class). Extracted `eagle_register_claude_hooks` into `lib/hooks.sh`; both call it (installer verbose, updater quiet). Behavior preserved exactly.
|
|
17
|
+
- **Dead-function sweep — analyzed, nothing removed.** A full cross-surface call-graph (`.sh`/`.py`/`.js`/skills/`bin`, 280 functions) found zero unreferenced functions and no computed-name dispatch; the "no shell caller" candidates are all reached via tests, skills, adapters, or the public CLI. Removing any would be regression risk with no benefit.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
7
21
|
## v4.13.0 Full-Spectrum Security & Reliability Hardening
|
|
8
22
|
|
|
9
23
|
A six-lens fix-in-place review of the whole codebase (security, data integrity, reliability, token economy, code quality, architecture). 32 files hardened, 6 new regression suites, full smoke suite green. No behavioral surface for normal sessions changed — recall and capture are byte-for-byte the same; what changed is the failure, concurrency, and trust behavior underneath.
|
package/lib/hooks.sh
CHANGED
|
@@ -100,3 +100,40 @@ eagle_patch_hook() {
|
|
|
100
100
|
[ -n "$description" ] && eagle_ok "$description"
|
|
101
101
|
return 0
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
# Register (idempotently) the full Claude Code hook set into a settings.json.
|
|
105
|
+
# Single source of truth for the event→matcher→script mapping so install.sh and
|
|
106
|
+
# update.sh can never drift (the historical bug class). Requires $EAGLE_MEM_DIR.
|
|
107
|
+
# $1 = settings.json path
|
|
108
|
+
# $2 = "verbose" to print a "✓ <Event> hook" line per registration (installer);
|
|
109
|
+
# omitted/anything else = quiet (updater prints its own summary line).
|
|
110
|
+
eagle_register_claude_hooks() {
|
|
111
|
+
local settings="$1"
|
|
112
|
+
local V=""
|
|
113
|
+
[ "${2:-}" = "verbose" ] && V=1
|
|
114
|
+
|
|
115
|
+
# Clean old registrations before re-registering (handles matcher changes across versions).
|
|
116
|
+
eagle_clean_hook_entries "$settings" "Stop" "$EAGLE_MEM_DIR/hooks/stop.sh"
|
|
117
|
+
eagle_clean_hook_entries "$settings" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
118
|
+
eagle_clean_hook_entries "$settings" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
119
|
+
|
|
120
|
+
# ${V:+label} expands to the label only in verbose mode; otherwise to "",
|
|
121
|
+
# which makes eagle_patch_hook silent (it only prints when given a description).
|
|
122
|
+
eagle_patch_hook "$settings" "SessionStart" "" "$EAGLE_MEM_DIR/hooks/session-start.sh" "${V:+SessionStart hook}"
|
|
123
|
+
eagle_patch_hook "$settings" "Stop" "" "bash \"$EAGLE_MEM_DIR/hooks/stop.sh\"" "${V:+Stop hook}"
|
|
124
|
+
eagle_patch_hook "$settings" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh" "${V:+PostToolUse hook}"
|
|
125
|
+
eagle_patch_hook "$settings" "TaskCreated" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh" "${V:+TaskCreated hook}"
|
|
126
|
+
eagle_patch_hook "$settings" "TaskCompleted" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh" "${V:+TaskCompleted hook}"
|
|
127
|
+
eagle_patch_hook "$settings" "SessionEnd" "" "$EAGLE_MEM_DIR/hooks/session-end.sh" "${V:+SessionEnd hook}"
|
|
128
|
+
eagle_patch_hook "$settings" "UserPromptSubmit" "" "$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh" "${V:+UserPromptSubmit hook}"
|
|
129
|
+
eagle_patch_hook "$settings" "PreToolUse" "Bash|Read|Edit|Write" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" "${V:+PreToolUse hook}"
|
|
130
|
+
|
|
131
|
+
# Allow agent-issued session capture to run without a permission prompt.
|
|
132
|
+
if eagle_patch_permission_allow "$settings" "Bash(eagle-mem session save:*)"; then
|
|
133
|
+
[ -n "$V" ] && eagle_ok "Capture permission ${DIM}(eagle-mem session save)${RESET}"
|
|
134
|
+
fi
|
|
135
|
+
# Explicit success: the trailing conditional above evaluates false in quiet
|
|
136
|
+
# mode (V empty), which would otherwise make this function return 1 and abort
|
|
137
|
+
# a `set -e` caller (update.sh) right after a fully successful registration.
|
|
138
|
+
return 0
|
|
139
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eagle-mem",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.1",
|
|
4
4
|
"description": "Shared memory, release guardrails, RTK token protection, and worker lanes for Claude Code, Codex, OpenCode, Grok, and Google Antigravity",
|
|
5
5
|
"bin": {
|
|
6
6
|
"eagle-mem": "bin/eagle-mem"
|
package/scripts/install.sh
CHANGED
|
@@ -283,47 +283,9 @@ if [ "$claude_found" = true ]; then
|
|
|
283
283
|
echo '{}' > "$SETTINGS"
|
|
284
284
|
fi
|
|
285
285
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
# Clean old registrations before re-registering (handles matcher changes across versions)
|
|
291
|
-
eagle_clean_hook_entries "$SETTINGS" "Stop" "$EAGLE_MEM_DIR/hooks/stop.sh"
|
|
292
|
-
eagle_clean_hook_entries "$SETTINGS" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
293
|
-
eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
294
|
-
|
|
295
|
-
eagle_patch_hook "$SETTINGS" "Stop" "" \
|
|
296
|
-
"bash \"$EAGLE_MEM_DIR/hooks/stop.sh\"" \
|
|
297
|
-
"Stop hook"
|
|
298
|
-
|
|
299
|
-
eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" \
|
|
300
|
-
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
301
|
-
"PostToolUse hook"
|
|
302
|
-
|
|
303
|
-
eagle_patch_hook "$SETTINGS" "TaskCreated" "" \
|
|
304
|
-
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
305
|
-
"TaskCreated hook"
|
|
306
|
-
|
|
307
|
-
eagle_patch_hook "$SETTINGS" "TaskCompleted" "" \
|
|
308
|
-
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
309
|
-
"TaskCompleted hook"
|
|
310
|
-
|
|
311
|
-
eagle_patch_hook "$SETTINGS" "SessionEnd" "" \
|
|
312
|
-
"$EAGLE_MEM_DIR/hooks/session-end.sh" \
|
|
313
|
-
"SessionEnd hook"
|
|
314
|
-
|
|
315
|
-
eagle_patch_hook "$SETTINGS" "UserPromptSubmit" "" \
|
|
316
|
-
"$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh" \
|
|
317
|
-
"UserPromptSubmit hook"
|
|
318
|
-
|
|
319
|
-
eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash|Read|Edit|Write" \
|
|
320
|
-
"$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
|
|
321
|
-
"PreToolUse hook"
|
|
322
|
-
|
|
323
|
-
# Allow agent-issued session capture to run without a permission prompt
|
|
324
|
-
if eagle_patch_permission_allow "$SETTINGS" "Bash(eagle-mem session save:*)"; then
|
|
325
|
-
eagle_ok "Capture permission ${DIM}(eagle-mem session save)${RESET}"
|
|
326
|
-
fi
|
|
286
|
+
# Single source of truth for the Claude hook set (see lib/hooks.sh);
|
|
287
|
+
# verbose mode prints a line per registration.
|
|
288
|
+
eagle_register_claude_hooks "$SETTINGS" verbose
|
|
327
289
|
fi
|
|
328
290
|
else
|
|
329
291
|
eagle_info "Claude hooks skipped ${DIM}(Claude Code not detected)${RESET}"
|
package/scripts/test.sh
CHANGED
|
@@ -16,13 +16,24 @@ eagle_banner
|
|
|
16
16
|
eagle_header "Smoke Tests"
|
|
17
17
|
|
|
18
18
|
errors=0
|
|
19
|
+
skipped=0
|
|
19
20
|
|
|
20
21
|
run_check() {
|
|
21
22
|
local name="$1"
|
|
22
23
|
local cmd="$2"
|
|
23
24
|
echo -e " ${BOLD}→${RESET} $name"
|
|
24
|
-
|
|
25
|
+
local rc=0
|
|
26
|
+
eval "$cmd" >/dev/null 2>&1 || rc=$?
|
|
27
|
+
if [ "$rc" -eq 0 ]; then
|
|
25
28
|
eagle_ok "$name"
|
|
29
|
+
elif [ "$rc" -eq 2 ]; then
|
|
30
|
+
# Exit code 2 = the check skipped itself because its preconditions are
|
|
31
|
+
# absent in this environment — e.g. a dev-only contract test running
|
|
32
|
+
# from a published install, where the maintainer doc it guards is not
|
|
33
|
+
# shipped in the npm package. A skip is neither a pass nor a failure, so
|
|
34
|
+
# it must not increment the error count or fail the suite.
|
|
35
|
+
eagle_info "skipped: $name (preconditions not present here)"
|
|
36
|
+
skipped=$((skipped + 1))
|
|
26
37
|
else
|
|
27
38
|
eagle_fail "$name"
|
|
28
39
|
# Assignment form (not ((errors++))) so a failing check does not abort
|
|
@@ -80,10 +91,17 @@ run_check "Data Integrity Hardening (migrate idempotency, SQL escaping, summary
|
|
|
80
91
|
run_check "Mod-Tracker Concurrency (lock TTL, no lost append, observation dedup race)" "bash \"$SCRIPTS_DIR/../tests/test_mod_tracker_concurrency.sh\""
|
|
81
92
|
run_check "Reliability Retention (scan in-flight vs freshness, eagle_events prune)" "bash \"$SCRIPTS_DIR/../tests/test_reliability_retention.sh\""
|
|
82
93
|
run_check "Test Runner No-Abort (failing check does not kill the suite under set -e)" "bash \"$SCRIPTS_DIR/../tests/test_test_runner_no_abort.sh\""
|
|
94
|
+
# Python lane: the native Antigravity hook (mocked). Subshell-wrapped so a
|
|
95
|
+
# missing python3 yields a clean skip (exit 2) instead of aborting the suite.
|
|
96
|
+
run_check "Antigravity Hook (native Python SDK lifecycle, mocked)" "( command -v python3 >/dev/null 2>&1 || exit 2; python3 \"$SCRIPTS_DIR/../tests/test_antigravity_hook.py\" )"
|
|
83
97
|
|
|
84
98
|
echo ""
|
|
85
99
|
if [ "$errors" -eq 0 ]; then
|
|
86
|
-
|
|
100
|
+
if [ "$skipped" -gt 0 ]; then
|
|
101
|
+
eagle_ok "All smoke tests passed ($skipped skipped — preconditions not present here)"
|
|
102
|
+
else
|
|
103
|
+
eagle_ok "All smoke tests passed"
|
|
104
|
+
fi
|
|
87
105
|
|
|
88
106
|
# Auto-verify the 7 core features in the database
|
|
89
107
|
for feat in "compaction-survival" "feature-verification" "grok-cli-integration" "agent-orchestration" "Cross Agent Memory" "Installer And Updater" "Code Scan And Index"; do
|
package/scripts/update.sh
CHANGED
|
@@ -86,23 +86,9 @@ fi
|
|
|
86
86
|
# ─── Re-register hooks (idempotent) ───────────────────────
|
|
87
87
|
|
|
88
88
|
if [ "$claude_found" = true ] && [ -f "$SETTINGS" ] && command -v jq &>/dev/null; then
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
93
|
-
|
|
94
|
-
eagle_patch_hook "$SETTINGS" "SessionStart" "" "$EAGLE_MEM_DIR/hooks/session-start.sh"
|
|
95
|
-
eagle_patch_hook "$SETTINGS" "Stop" "" "bash \"$EAGLE_MEM_DIR/hooks/stop.sh\""
|
|
96
|
-
eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
97
|
-
eagle_patch_hook "$SETTINGS" "TaskCreated" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
98
|
-
eagle_patch_hook "$SETTINGS" "TaskCompleted" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
99
|
-
eagle_patch_hook "$SETTINGS" "SessionEnd" "" "$EAGLE_MEM_DIR/hooks/session-end.sh"
|
|
100
|
-
eagle_patch_hook "$SETTINGS" "UserPromptSubmit" "" "$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh"
|
|
101
|
-
eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash|Read|Edit|Write" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
102
|
-
|
|
103
|
-
# Allow agent-issued session capture to run without a permission prompt
|
|
104
|
-
eagle_patch_permission_allow "$SETTINGS" "Bash(eagle-mem session save:*)"
|
|
105
|
-
|
|
89
|
+
# Single source of truth for the Claude hook set (see lib/hooks.sh); quiet
|
|
90
|
+
# mode — the updater prints one summary line instead of per-hook lines.
|
|
91
|
+
eagle_register_claude_hooks "$SETTINGS"
|
|
106
92
|
eagle_ok "Hooks registered"
|
|
107
93
|
fi
|
|
108
94
|
|
|
@@ -7,7 +7,12 @@ set -euo pipefail
|
|
|
7
7
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
8
|
EAGLE_BIN="$ROOT_DIR/bin/eagle-mem"
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# Use a neutral system temp dir, NOT one inside $ROOT_DIR. From a published
|
|
11
|
+
# install $ROOT_DIR lives under node_modules/, and the code scanner excludes
|
|
12
|
+
# node_modules — so a fixture repo created here would index 0 files and the
|
|
13
|
+
# post-compact "Relevant Code" recall would never appear (the suite is run from
|
|
14
|
+
# the installed package via `eagle-mem test`).
|
|
15
|
+
tmp_dir=$(mktemp -d "${TMPDIR:-/tmp}/eagle-compaction-survival.XXXXXX")
|
|
11
16
|
trap 'rm -rf "$tmp_dir"' EXIT
|
|
12
17
|
|
|
13
18
|
export HOME="$tmp_dir/home"
|
|
@@ -190,6 +195,13 @@ assert_json "$compaction_json" '
|
|
|
190
195
|
and .metrics.semantic_graph_nodes >= 5
|
|
191
196
|
' "compaction --json did not report durable survival metrics"
|
|
192
197
|
|
|
198
|
+
# Index the fixture code deterministically so the post-compact recall can
|
|
199
|
+
# surface "Relevant Code". This previously relied on a background auto-index
|
|
200
|
+
# that only won the race from a warm source checkout, so the assertion failed
|
|
201
|
+
# when the suite ran from a published install via `eagle-mem test`. The
|
|
202
|
+
# `index` command is synchronous, so chunks exist by the time the hook runs.
|
|
203
|
+
( cd "$repo" && "$EAGLE_BIN" index >/dev/null 2>&1 )
|
|
204
|
+
|
|
193
205
|
eagle_upsert_session "$post_session" "$project" "$repo" "test-model" "test" "codex" >/dev/null
|
|
194
206
|
hook_input=$(jq -nc \
|
|
195
207
|
--arg sid "$post_session" \
|
|
@@ -18,7 +18,14 @@ require_contains() {
|
|
|
18
18
|
fi
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
# MIGRATION.md is a maintainer-only roadmap and is intentionally NOT shipped in
|
|
22
|
+
# the npm package (`files` allowlist), so this contract test has nothing to
|
|
23
|
+
# guard when the suite runs from a published install via `eagle-mem test`.
|
|
24
|
+
# Skip cleanly (exit 2) in that case; run strictly from a source checkout.
|
|
25
|
+
if [ ! -f "$PLAN" ]; then
|
|
26
|
+
echo "skip: MIGRATION.md not present (dev-only contract test)" >&2
|
|
27
|
+
exit 2
|
|
28
|
+
fi
|
|
22
29
|
|
|
23
30
|
require_contains "~/.eagle-mem/memory\\.db" "the existing user database path"
|
|
24
31
|
require_contains "compatibility wrapper" "the Bash compatibility wrapper"
|