eagle-mem 4.9.6 → 4.9.8
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/README.md +31 -4
- package/architecture.html +1791 -0
- package/bin/eagle-mem +1 -0
- package/db/migrate.sh +13 -2
- package/docs/visible-surface-ux-contract.md +53 -0
- package/hooks/post-tool-use.sh +2 -2
- package/hooks/pre-tool-use.sh +6 -6
- package/hooks/session-start.sh +216 -9
- package/hooks/user-prompt-submit.sh +72 -15
- package/lib/common.sh +485 -35
- package/lib/db-mirrors.sh +9 -18
- package/lib/db-sessions.sh +22 -15
- package/lib/db-summaries.sh +19 -7
- package/lib/hooks-posttool.sh +44 -10
- package/lib/updater.sh +12 -0
- package/package.json +4 -2
- package/scripts/doctor.sh +262 -0
- package/scripts/feature.sh +37 -11
- package/scripts/health.sh +10 -7
- package/scripts/help.sh +1 -0
- package/scripts/install.sh +9 -3
- package/scripts/memories.sh +258 -65
- package/scripts/orchestrate.sh +2 -2
- package/scripts/search.sh +240 -56
- package/scripts/statusline-em.sh +130 -26
- package/scripts/uninstall.sh +67 -0
- package/scripts/update.sh +8 -1
package/scripts/statusline-em.sh
CHANGED
|
@@ -1,35 +1,80 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Eagle Mem statusline
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# Eagle Mem statusline renderers.
|
|
3
|
+
# Usage:
|
|
4
|
+
# source this file and call eagle_mem_statusline "$project_dir" "$session_id" "$input"
|
|
5
|
+
# printf '%s' "$input" | bash ~/.eagle-mem/scripts/statusline-em.sh --hud
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
_eagle_statusline_load_common() {
|
|
8
|
+
local script_dir
|
|
9
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
. "$script_dir/../lib/common.sh"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
_eagle_statusline_relative_time() {
|
|
14
|
+
local raw="${1:-}"
|
|
15
|
+
[ -n "$raw" ] && [ "$raw" != "never" ] || { printf 'never\n'; return; }
|
|
16
|
+
|
|
17
|
+
local last_epoch now_epoch diff_sec
|
|
18
|
+
last_epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "${raw%%.*}" "+%s" 2>/dev/null \
|
|
19
|
+
|| date -u -d "$raw" "+%s" 2>/dev/null \
|
|
20
|
+
|| true)
|
|
21
|
+
now_epoch=$(date "+%s" 2>/dev/null || true)
|
|
22
|
+
if [ -z "$last_epoch" ] || [ -z "$now_epoch" ]; then
|
|
23
|
+
printf '%s\n' "$raw"
|
|
24
|
+
return
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
diff_sec=$((now_epoch - last_epoch))
|
|
28
|
+
if [ "$diff_sec" -lt 60 ]; then
|
|
29
|
+
printf 'just now\n'
|
|
30
|
+
elif [ "$diff_sec" -lt 3600 ]; then
|
|
31
|
+
printf '%sm ago\n' "$((diff_sec / 60))"
|
|
32
|
+
elif [ "$diff_sec" -lt 86400 ]; then
|
|
33
|
+
printf '%sh ago\n' "$((diff_sec / 3600))"
|
|
34
|
+
else
|
|
35
|
+
printf '%sd ago\n' "$((diff_sec / 86400))"
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
eagle_mem_statusline_stats() {
|
|
7
40
|
local project_dir="${1:-}"
|
|
8
41
|
local session_id="${2:-}"
|
|
9
42
|
local statusline_input="${3:-}"
|
|
43
|
+
local current_dir="${4:-}"
|
|
10
44
|
local em_db="$HOME/.eagle-mem/memory.db"
|
|
11
45
|
[ -f "$em_db" ] || return
|
|
12
46
|
|
|
13
|
-
|
|
14
|
-
|
|
47
|
+
_eagle_statusline_load_common
|
|
48
|
+
|
|
15
49
|
local sqlite_bin
|
|
16
50
|
sqlite_bin=$(eagle_sqlite_path)
|
|
17
51
|
[ -n "$sqlite_bin" ] || return
|
|
18
52
|
|
|
19
|
-
|
|
53
|
+
if [ -n "$statusline_input" ]; then
|
|
54
|
+
[ -z "$session_id" ] && session_id=$(printf '%s' "$statusline_input" | jq -r '.session_id // .session.id // empty' 2>/dev/null)
|
|
55
|
+
[ -z "$project_dir" ] && project_dir=$(printf '%s' "$statusline_input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
56
|
+
[ -z "$current_dir" ] && current_dir=$(printf '%s' "$statusline_input" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
57
|
+
fi
|
|
20
58
|
[ -z "$project_dir" ] && project_dir="$(pwd)"
|
|
21
|
-
|
|
22
|
-
[ -z "$proj" ] && return
|
|
59
|
+
[ -z "$current_dir" ] && current_dir="$project_dir"
|
|
23
60
|
|
|
24
|
-
|
|
61
|
+
local project_key project_scope project_condition stats sessions memories last_raw turns version latest
|
|
62
|
+
project_key=$(eagle_project_from_statusline_input "$statusline_input" "$project_dir" "$current_dir" "$session_id")
|
|
63
|
+
[ -n "$project_key" ] || return
|
|
64
|
+
project_scope=$(eagle_recall_project_scope_from_cwd "${current_dir:-$project_dir}" "$project_key")
|
|
65
|
+
project_condition=$(eagle_sql_project_scope_condition "project" "$project_scope")
|
|
66
|
+
|
|
67
|
+
stats=$("$sqlite_bin" "$em_db" "SELECT
|
|
68
|
+
COUNT(*) || '|' ||
|
|
69
|
+
(SELECT COUNT(*) FROM agent_memories WHERE $project_condition) || '|' ||
|
|
70
|
+
COALESCE(MAX(COALESCE(last_activity_at, started_at)), 'never')
|
|
71
|
+
FROM sessions
|
|
72
|
+
WHERE $project_condition;" 2>/dev/null)
|
|
73
|
+
IFS='|' read -r sessions memories last_raw <<< "${stats:-0|0|never}"
|
|
74
|
+
sessions=${sessions:-0}
|
|
75
|
+
memories=${memories:-0}
|
|
76
|
+
last_raw=${last_raw:-never}
|
|
25
77
|
|
|
26
|
-
local version cnt mem turns
|
|
27
|
-
version=$(tr -d '[:space:]' < "$HOME/.eagle-mem/.version" 2>/dev/null)
|
|
28
|
-
[ -z "$version" ] && version="?"
|
|
29
|
-
cnt=$(echo ".headers off
|
|
30
|
-
SELECT COUNT(*) FROM sessions WHERE project = '${proj}';" | "$sqlite_bin" "$em_db" 2>/dev/null | tr -d '[:space:]')
|
|
31
|
-
mem=$(echo ".headers off
|
|
32
|
-
SELECT COUNT(*) FROM agent_memories WHERE project = '${proj}';" | "$sqlite_bin" "$em_db" 2>/dev/null | tr -d '[:space:]')
|
|
33
78
|
if [ -n "$session_id" ] && [ -f "$HOME/.eagle-mem/.turn-counter.${session_id}" ]; then
|
|
34
79
|
turns=$(tr -d '[:space:]' < "$HOME/.eagle-mem/.turn-counter.${session_id}" 2>/dev/null)
|
|
35
80
|
else
|
|
@@ -40,26 +85,85 @@ SELECT COUNT(*) FROM agent_memories WHERE project = '${proj}';" | "$sqlite_bin"
|
|
|
40
85
|
done \
|
|
41
86
|
| awk '($1+0)>max{max=$1+0} END{print max+0}')
|
|
42
87
|
fi
|
|
43
|
-
cnt=${cnt:-0}; mem=${mem:-0}
|
|
44
88
|
turns=${turns:-0}
|
|
45
89
|
|
|
90
|
+
version=$(tr -d '[:space:]' < "$HOME/.eagle-mem/.version" 2>/dev/null)
|
|
91
|
+
latest=$(tr -d '[:space:]' < "$HOME/.eagle-mem/.latest-version" 2>/dev/null)
|
|
92
|
+
[ -z "$version" ] && version="?"
|
|
93
|
+
[ -z "$latest" ] && latest="$version"
|
|
94
|
+
|
|
95
|
+
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$project_key" "$version" "$latest" "$sessions" "$memories" "$turns" "$last_raw"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
eagle_mem_statusline() {
|
|
99
|
+
local stats project_key version latest sessions memories turns last_raw
|
|
100
|
+
stats=$(eagle_mem_statusline_stats "${1:-}" "${2:-}" "${3:-}" "${4:-}") || return
|
|
101
|
+
IFS=$'\t' read -r project_key version latest sessions memories turns last_raw <<< "$stats"
|
|
102
|
+
|
|
46
103
|
local R='\033[0m' CYAN='\033[96m' WHT='\033[97m' DIM='\033[2m'
|
|
47
|
-
printf "%
|
|
104
|
+
printf "%bEagle%b %bv%s%b | %b%s%b sessions | %b%s%b memories | turn %b%s%b" \
|
|
48
105
|
"$CYAN" "$R" \
|
|
49
106
|
"$WHT" "$version" "$DIM" \
|
|
50
|
-
"$WHT" "$
|
|
51
|
-
"$WHT" "$
|
|
52
|
-
"$WHT" "$turns" "$R"
|
|
107
|
+
"$WHT" "${sessions:-0}" "$DIM" \
|
|
108
|
+
"$WHT" "${memories:-0}" "$DIM" \
|
|
109
|
+
"$WHT" "${turns:-0}" "$R"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
eagle_mem_statusline_hud() {
|
|
113
|
+
local stats project_key version latest sessions memories turns last_raw last_label
|
|
114
|
+
stats=$(eagle_mem_statusline_stats "${1:-}" "${2:-}" "${3:-}" "${4:-}") || return
|
|
115
|
+
IFS=$'\t' read -r project_key version latest sessions memories turns last_raw <<< "$stats"
|
|
116
|
+
last_label=$(_eagle_statusline_relative_time "$last_raw")
|
|
117
|
+
|
|
118
|
+
local R='\033[0m' CYAN='\033[96m' WHT='\033[97m' DIM='\033[2m'
|
|
119
|
+
local GRN='\033[92m' ORG='\033[38;5;214m' RED='\033[91m'
|
|
120
|
+
local turn_color pressure_label em_ver newest
|
|
121
|
+
|
|
122
|
+
turns=${turns:-0}
|
|
123
|
+
if [ "$turns" -ge 30 ] 2>/dev/null; then
|
|
124
|
+
turn_color="$RED"; pressure_label="CRITICAL"
|
|
125
|
+
elif [ "$turns" -ge 20 ] 2>/dev/null; then
|
|
126
|
+
turn_color="$ORG"; pressure_label="HIGH"
|
|
127
|
+
else
|
|
128
|
+
turn_color="$GRN"; pressure_label="OK"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
em_ver="v${version:-?}"
|
|
132
|
+
newest=$(printf '%s\n' "${version:-}" "${latest:-}" | sort -V 2>/dev/null | tail -1 || true)
|
|
133
|
+
if [ -n "$latest" ] && [ -n "$newest" ] && [ "$newest" != "$version" ]; then
|
|
134
|
+
em_ver="${em_ver} ${ORG}↑${latest}${R}"
|
|
135
|
+
elif [ -n "$latest" ] && [ "$latest" = "$version" ]; then
|
|
136
|
+
em_ver="${em_ver} ${GRN}✓${R}"
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
printf "%bEagle Mem%b %b %b│%b %bSessions:%b %b%s%b %b│%b %bMemories:%b %b%s%b %b│%b %bTurns:%b %b%s/30%b %b(%s)%b %b│%b %bUpdated:%b %b%s%b" \
|
|
140
|
+
"$CYAN" "$R" "$em_ver" \
|
|
141
|
+
"$DIM" "$R" "$DIM" "$R" "$WHT" "${sessions:-0}" "$R" "$DIM" "$R" \
|
|
142
|
+
"$DIM" "$R" "$WHT" "${memories:-0}" "$R" "$DIM" "$R" \
|
|
143
|
+
"$DIM" "$R" "$turn_color" "$turns" "$R" "$turn_color" "$pressure_label" "$R" "$DIM" "$R" \
|
|
144
|
+
"$DIM" "$R" "$WHT" "$last_label" "$R"
|
|
53
145
|
}
|
|
54
146
|
|
|
55
|
-
# When run directly, read project_dir from stdin JSON (statusline format)
|
|
56
147
|
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
148
|
+
mode="${1:-compact}"
|
|
57
149
|
if [ -t 0 ]; then
|
|
58
150
|
input=""
|
|
59
151
|
else
|
|
60
152
|
input=$(cat)
|
|
61
153
|
fi
|
|
62
|
-
project_dir=$(
|
|
63
|
-
|
|
64
|
-
|
|
154
|
+
project_dir=$(printf '%s' "$input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
155
|
+
current_dir=$(printf '%s' "$input" | jq -r '.workspace.current_dir // .cwd // empty' 2>/dev/null)
|
|
156
|
+
session_id=$(printf '%s' "$input" | jq -r '.session_id // .session.id // empty' 2>/dev/null)
|
|
157
|
+
|
|
158
|
+
case "$mode" in
|
|
159
|
+
--hud|hud)
|
|
160
|
+
eagle_mem_statusline_hud "${project_dir:-$(pwd)}" "$session_id" "$input" "$current_dir"
|
|
161
|
+
;;
|
|
162
|
+
--stats|stats)
|
|
163
|
+
eagle_mem_statusline_stats "${project_dir:-$(pwd)}" "$session_id" "$input" "$current_dir"
|
|
164
|
+
;;
|
|
165
|
+
*)
|
|
166
|
+
eagle_mem_statusline "${project_dir:-$(pwd)}" "$session_id" "$input" "$current_dir"
|
|
167
|
+
;;
|
|
168
|
+
esac
|
|
65
169
|
fi
|
package/scripts/uninstall.sh
CHANGED
|
@@ -13,12 +13,32 @@ LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
|
13
13
|
. "$LIB_DIR/codex-hooks.sh"
|
|
14
14
|
|
|
15
15
|
SETTINGS="$EAGLE_SETTINGS"
|
|
16
|
+
dry_run=false
|
|
17
|
+
|
|
18
|
+
for arg in "$@"; do
|
|
19
|
+
case "$arg" in
|
|
20
|
+
--dry-run|--check)
|
|
21
|
+
dry_run=true
|
|
22
|
+
;;
|
|
23
|
+
--help|-h)
|
|
24
|
+
echo "Usage: eagle-mem uninstall [--dry-run]"
|
|
25
|
+
exit 0
|
|
26
|
+
;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
16
29
|
|
|
17
30
|
eagle_header "Uninstall"
|
|
31
|
+
eagle_uninstall_change_plan
|
|
32
|
+
|
|
33
|
+
if [ "$dry_run" = true ]; then
|
|
34
|
+
eagle_footer "Dry run complete. No files changed."
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
18
37
|
|
|
19
38
|
# ─── Remove hooks from settings.json ──────────────────────
|
|
20
39
|
|
|
21
40
|
if [ -f "$SETTINGS" ] && command -v jq &>/dev/null; then
|
|
41
|
+
settings_backup=$(eagle_backup_user_file "$SETTINGS" 2>/dev/null || true)
|
|
22
42
|
for event in SessionStart Stop PostToolUse PreToolUse SessionEnd UserPromptSubmit; do
|
|
23
43
|
if jq -e ".hooks.${event}" "$SETTINGS" &>/dev/null; then
|
|
24
44
|
tmp=$(mktemp)
|
|
@@ -30,16 +50,55 @@ if [ -f "$SETTINGS" ] && command -v jq &>/dev/null; then
|
|
|
30
50
|
tmp=$(mktemp)
|
|
31
51
|
jq 'if .hooks == {} then del(.hooks) else . end' "$SETTINGS" > "$tmp" && mv "$tmp" "$SETTINGS"
|
|
32
52
|
eagle_ok "Hooks removed from settings.json"
|
|
53
|
+
[ -n "${settings_backup:-}" ] && eagle_dim " Backup: $settings_backup"
|
|
33
54
|
else
|
|
34
55
|
eagle_warn "Could not patch settings.json (jq not found or file missing)"
|
|
35
56
|
fi
|
|
36
57
|
|
|
58
|
+
codex_hooks_backup=""
|
|
59
|
+
if [ -f "$EAGLE_CODEX_HOOKS" ]; then
|
|
60
|
+
codex_hooks_backup=$(eagle_backup_user_file "$EAGLE_CODEX_HOOKS" 2>/dev/null || true)
|
|
61
|
+
fi
|
|
37
62
|
if eagle_remove_codex_hooks; then
|
|
38
63
|
eagle_ok "Hooks removed from Codex hooks.json"
|
|
64
|
+
[ -n "$codex_hooks_backup" ] && eagle_dim " Backup: $codex_hooks_backup"
|
|
39
65
|
else
|
|
40
66
|
eagle_warn "Could not patch Codex hooks.json (jq not found or file missing)"
|
|
41
67
|
fi
|
|
42
68
|
|
|
69
|
+
# ─── Remove instruction blocks and statusline integration ───
|
|
70
|
+
|
|
71
|
+
claude_md="$HOME/.claude/CLAUDE.md"
|
|
72
|
+
if [ -f "$claude_md" ] && grep -qF "## Eagle Mem — Persistent Memory" "$claude_md" 2>/dev/null; then
|
|
73
|
+
claude_md_backup=$(eagle_backup_user_file "$claude_md" 2>/dev/null || true)
|
|
74
|
+
if eagle_remove_marked_markdown_section "$claude_md"; then
|
|
75
|
+
eagle_ok "Eagle Mem block removed from Claude CLAUDE.md"
|
|
76
|
+
[ -n "${claude_md_backup:-}" ] && eagle_dim " Backup: $claude_md_backup"
|
|
77
|
+
else
|
|
78
|
+
eagle_warn "Could not remove Eagle Mem block from Claude CLAUDE.md"
|
|
79
|
+
fi
|
|
80
|
+
else
|
|
81
|
+
eagle_info "Claude CLAUDE.md block not present"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if [ -f "$EAGLE_CODEX_AGENTS_MD" ] && grep -qF "## Eagle Mem — Persistent Memory" "$EAGLE_CODEX_AGENTS_MD" 2>/dev/null; then
|
|
85
|
+
codex_agents_backup=$(eagle_backup_user_file "$EAGLE_CODEX_AGENTS_MD" 2>/dev/null || true)
|
|
86
|
+
if eagle_remove_marked_markdown_section "$EAGLE_CODEX_AGENTS_MD"; then
|
|
87
|
+
eagle_ok "Eagle Mem block removed from Codex AGENTS.md"
|
|
88
|
+
[ -n "${codex_agents_backup:-}" ] && eagle_dim " Backup: $codex_agents_backup"
|
|
89
|
+
else
|
|
90
|
+
eagle_warn "Could not remove Eagle Mem block from Codex AGENTS.md"
|
|
91
|
+
fi
|
|
92
|
+
else
|
|
93
|
+
eagle_info "Codex AGENTS.md block not present"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if eagle_remove_statusline_integration "$SETTINGS"; then
|
|
97
|
+
eagle_ok "Eagle Mem statusline integration removed"
|
|
98
|
+
else
|
|
99
|
+
eagle_info "Statusline integration not present or not auto-removable"
|
|
100
|
+
fi
|
|
101
|
+
|
|
43
102
|
# ─── Remove skill symlinks ────────────────────────────────
|
|
44
103
|
|
|
45
104
|
if [ -d "$EAGLE_SKILLS_DIR" ]; then
|
|
@@ -50,6 +109,14 @@ if [ -d "$EAGLE_SKILLS_DIR" ]; then
|
|
|
50
109
|
done
|
|
51
110
|
fi
|
|
52
111
|
|
|
112
|
+
if [ -d "$EAGLE_CODEX_SKILLS_DIR" ]; then
|
|
113
|
+
for target in "$EAGLE_CODEX_SKILLS_DIR"/eagle-mem-*; do
|
|
114
|
+
[ -L "$target" ] || [ -d "$target" ] || continue
|
|
115
|
+
rm -rf "$target"
|
|
116
|
+
eagle_ok "Codex skill removed: $(basename "$target")"
|
|
117
|
+
done
|
|
118
|
+
fi
|
|
119
|
+
|
|
53
120
|
# ─── Optionally wipe data ─────────────────────────────────
|
|
54
121
|
|
|
55
122
|
if [ -d "$EAGLE_MEM_DIR" ]; then
|
package/scripts/update.sh
CHANGED
|
@@ -40,6 +40,8 @@ if [ -d "$EAGLE_CODEX_DIR" ] || command -v codex &>/dev/null; then
|
|
|
40
40
|
codex_found=true
|
|
41
41
|
fi
|
|
42
42
|
|
|
43
|
+
eagle_runtime_change_plan "update" "$PACKAGE_DIR" "$claude_found" "$codex_found"
|
|
44
|
+
|
|
43
45
|
# ─── Update files ──────────────────────────────────────────
|
|
44
46
|
|
|
45
47
|
mkdir -p "$EAGLE_MEM_DIR"/{hooks,lib,db,scripts}
|
|
@@ -195,7 +197,7 @@ eagle_ok "Auto-updates ${DIM}(mode=$(eagle_update_config_mode), allow=$(eagle_up
|
|
|
195
197
|
|
|
196
198
|
if [ "$claude_found" = true ]; then
|
|
197
199
|
if eagle_patch_claude_md; then
|
|
198
|
-
|
|
200
|
+
eagle_ok "CLAUDE.md updated ${DIM}(Eagle Mem guidance refreshed)${RESET}"
|
|
199
201
|
else
|
|
200
202
|
eagle_ok "CLAUDE.md up to date"
|
|
201
203
|
fi
|
|
@@ -214,5 +216,10 @@ fi
|
|
|
214
216
|
version=$(jq -r .version "$PACKAGE_DIR/package.json" 2>/dev/null || echo "unknown")
|
|
215
217
|
echo "$version" > "$EAGLE_MEM_DIR/.version"
|
|
216
218
|
echo "$version" > "$EAGLE_MEM_DIR/.latest-version"
|
|
219
|
+
if eagle_runtime_manifest_write "$PACKAGE_DIR" "update"; then
|
|
220
|
+
eagle_ok "Install manifest refreshed"
|
|
221
|
+
else
|
|
222
|
+
eagle_warn "Install manifest could not be refreshed"
|
|
223
|
+
fi
|
|
217
224
|
|
|
218
225
|
eagle_footer "Eagle Mem updated to v${version}."
|