eagle-mem 2.0.5 → 2.0.7

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 CHANGED
@@ -1,6 +1,7 @@
1
1
  ```
2
- █▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
3
- ██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █
2
+ ======================================
3
+ Eagle Mem
4
+ ======================================
4
5
  ```
5
6
 
6
7
  # Eagle Mem
@@ -21,12 +22,19 @@ eagle-mem install
21
22
  **2. Open Claude Code** in any project directory. Eagle Mem activates and shows what it loaded:
22
23
 
23
24
  ```
24
- █▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
25
- ██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █
26
-
27
- Project: my-app
28
- Sessions: 5 recent | Memories: 3 | Tasks: 2 pending
29
- Last: Added auth middleware with JWT validation
25
+ ======================================
26
+ Eagle Mem Loaded
27
+ ======================================
28
+ Project | my-app
29
+ Sessions | 42 total (18 with summaries)
30
+ Memories | 7 stored
31
+ Plans | 2 saved
32
+ Tasks | 1 in progress, 3 pending, 12 completed
33
+ Code Index | 156 chunks indexed
34
+ Observations | 340 captured
35
+ Last Active | 2026-04-28
36
+ Last Work | Added auth middleware with JWT validation
37
+ ======================================
30
38
  ```
31
39
 
32
40
  From here, everything is automatic. You don't run any commands — Eagle Mem captures session summaries, mirrors Claude's memories and tasks, and re-injects context after every `/compact` or new session.
@@ -0,0 +1,51 @@
1
+ -- Migration 012: Add decisions, gotchas, key_files columns to summaries
2
+ -- These capture WHY choices were made, WHAT went wrong, and WHERE to start reading.
3
+ -- Also adds them to FTS5 so they're searchable across sessions.
4
+
5
+ -- Add new columns
6
+ ALTER TABLE summaries ADD COLUMN decisions TEXT;
7
+ ALTER TABLE summaries ADD COLUMN gotchas TEXT;
8
+ ALTER TABLE summaries ADD COLUMN key_files TEXT;
9
+
10
+ -- Rebuild FTS5 to include new columns
11
+ DROP TRIGGER IF EXISTS summaries_ai;
12
+ DROP TRIGGER IF EXISTS summaries_ad;
13
+ DROP TRIGGER IF EXISTS summaries_au;
14
+
15
+ DROP TABLE IF EXISTS summaries_fts;
16
+
17
+ CREATE VIRTUAL TABLE summaries_fts USING fts5(
18
+ request,
19
+ investigated,
20
+ learned,
21
+ completed,
22
+ next_steps,
23
+ notes,
24
+ decisions,
25
+ gotchas,
26
+ key_files,
27
+ content='summaries',
28
+ content_rowid='id'
29
+ );
30
+
31
+ -- Backfill FTS from existing data
32
+ INSERT INTO summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files)
33
+ SELECT id, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files FROM summaries;
34
+
35
+ -- Recreate content-sync triggers with new columns
36
+ CREATE TRIGGER summaries_ai AFTER INSERT ON summaries BEGIN
37
+ INSERT INTO summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files)
38
+ VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes, new.decisions, new.gotchas, new.key_files);
39
+ END;
40
+
41
+ CREATE TRIGGER summaries_ad AFTER DELETE ON summaries BEGIN
42
+ INSERT INTO summaries_fts(summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files)
43
+ VALUES ('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes, old.decisions, old.gotchas, old.key_files);
44
+ END;
45
+
46
+ CREATE TRIGGER summaries_au AFTER UPDATE ON summaries BEGIN
47
+ INSERT INTO summaries_fts(summaries_fts, rowid, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files)
48
+ VALUES ('delete', old.id, old.request, old.investigated, old.learned, old.completed, old.next_steps, old.notes, old.decisions, old.gotchas, old.key_files);
49
+ INSERT INTO summaries_fts(rowid, request, investigated, learned, completed, next_steps, notes, decisions, gotchas, key_files)
50
+ VALUES (new.id, new.request, new.investigated, new.learned, new.completed, new.next_steps, new.notes, new.decisions, new.gotchas, new.key_files);
51
+ END;
@@ -124,6 +124,40 @@ case "$tool_name" in
124
124
  ;;
125
125
  esac
126
126
 
127
+ # ─── Stale memory hint ──────────────────────────────────
128
+ # After editing a project file, FTS5-search memories for the filename.
129
+ # If a memory mentions this file, remind Claude to check for staleness.
130
+ case "$tool_name" in
131
+ Write|Edit)
132
+ if [ -n "$fp" ]; then
133
+ fname=$(basename "$fp")
134
+ fname_stem="${fname%.*}"
135
+ case "$fp" in
136
+ "$HOME/.claude/"*) ;; # skip Claude config files
137
+ *)
138
+ if [ ${#fname_stem} -ge 3 ]; then
139
+ fts_query=$(eagle_fts_sanitize "$fname_stem")
140
+ if [ -n "$fts_query" ]; then
141
+ fts_esc=$(eagle_sql_escape "$fts_query")
142
+ p_esc=$(eagle_sql_escape "$project")
143
+ stale_hit=$(eagle_db "SELECT m.memory_name
144
+ FROM claude_memories m
145
+ JOIN claude_memories_fts f ON f.rowid = m.id
146
+ WHERE claude_memories_fts MATCH '$fts_esc'
147
+ AND m.project = '$p_esc'
148
+ LIMIT 1;")
149
+ if [ -n "$stale_hit" ]; then
150
+ stale_msg="Eagle Mem: Memory '${stale_hit}' may reference '${fname}'. If your edit contradicts it, update the memory."
151
+ jq -nc --arg ctx "$stale_msg" '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":$ctx}}'
152
+ fi
153
+ fi
154
+ fi
155
+ ;;
156
+ esac
157
+ fi
158
+ ;;
159
+ esac
160
+
127
161
  eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified"
128
162
 
129
163
  exit 0
@@ -38,18 +38,108 @@ eagle_db "UPDATE sessions SET status = 'abandoned'
38
38
  AND id != '$(eagle_sql_escape "$session_id")'
39
39
  AND COALESCE(last_activity_at, started_at) < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days');"
40
40
 
41
- # ─── Build context injection ────────────────────────────────
41
+ # ─── Version check (non-blocking) ────────────────────────────
42
+
43
+ update_notice=""
44
+ version_file="$EAGLE_MEM_DIR/.version"
45
+ latest_file="$EAGLE_MEM_DIR/.latest-version"
42
46
 
43
- eagle_logo="█▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
44
- ██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █"
47
+ if [ -f "$version_file" ] && [ -s "$version_file" ]; then
48
+ installed_version=$(tr -d '[:space:]' < "$version_file")
45
49
 
46
- context="$eagle_logo
50
+ if [ -f "$latest_file" ] && [ -s "$latest_file" ]; then
51
+ latest_version=$(tr -d '[:space:]' < "$latest_file")
52
+ newest=$(printf '%s\n' "$installed_version" "$latest_version" | sort -V | tail -1)
53
+ if [ "$newest" != "$installed_version" ]; then
54
+ update_notice="Update available: v${installed_version} → v${latest_version} — run: npm update -g eagle-mem && eagle-mem update"
55
+ fi
56
+ fi
57
+
58
+ if [ ! -f "$latest_file" ] || [ -n "$(find "$latest_file" -mtime +0 2>/dev/null)" ]; then
59
+ (tmp_latest=$(mktemp)
60
+ npm view eagle-mem version 2>/dev/null | tr -d '[:space:]' > "$tmp_latest"
61
+ if [ -s "$tmp_latest" ]; then
62
+ mv "$tmp_latest" "$latest_file"
63
+ else
64
+ rm -f "$tmp_latest"
65
+ fi) &
66
+ fi
67
+ fi
68
+
69
+ # ─── Gather stats ───────────────────────────────────────────
70
+
71
+ p_esc=$(eagle_sql_escape "$project")
72
+
73
+ stat_sessions=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p_esc';")
74
+ stat_summaries=$(eagle_db "SELECT COUNT(*) FROM summaries WHERE project = '$p_esc';")
75
+ stat_memories=$(eagle_db "SELECT COUNT(*) FROM claude_memories WHERE project = '$p_esc';")
76
+ stat_tasks_pending=$(eagle_db "SELECT COUNT(*) FROM claude_tasks WHERE project = '$p_esc' AND status = 'pending';")
77
+ stat_tasks_progress=$(eagle_db "SELECT COUNT(*) FROM claude_tasks WHERE project = '$p_esc' AND status = 'in_progress';")
78
+ stat_tasks_done=$(eagle_db "SELECT COUNT(*) FROM claude_tasks WHERE project = '$p_esc' AND status = 'completed';")
79
+ stat_chunks=$(eagle_db "SELECT COUNT(*) FROM code_chunks WHERE project = '$p_esc';")
80
+ stat_observations=$(eagle_db "SELECT COUNT(*) FROM observations WHERE session_id IN (SELECT id FROM sessions WHERE project = '$p_esc');")
81
+ stat_plans=$(eagle_db "SELECT COUNT(*) FROM claude_plans WHERE project = '$p_esc';")
82
+ stat_last_active=$(eagle_db "SELECT COALESCE(MAX(date(COALESCE(last_activity_at, started_at))), 'never') FROM sessions WHERE project = '$p_esc';")
83
+ stat_last_summary=$(eagle_db "SELECT request FROM summaries WHERE project = '$p_esc' ORDER BY created_at DESC LIMIT 1;")
84
+
85
+ # Trim to defaults
86
+ stat_sessions="${stat_sessions:-0}"
87
+ stat_summaries="${stat_summaries:-0}"
88
+ stat_memories="${stat_memories:-0}"
89
+ stat_tasks_pending="${stat_tasks_pending:-0}"
90
+ stat_tasks_progress="${stat_tasks_progress:-0}"
91
+ stat_tasks_done="${stat_tasks_done:-0}"
92
+ stat_chunks="${stat_chunks:-0}"
93
+ stat_observations="${stat_observations:-0}"
94
+ stat_plans="${stat_plans:-0}"
95
+
96
+ # Build task summary line
97
+ task_parts=""
98
+ [ "$stat_tasks_progress" -gt 0 ] && task_parts="${stat_tasks_progress} in progress"
99
+ if [ "$stat_tasks_pending" -gt 0 ]; then
100
+ [ -n "$task_parts" ] && task_parts+=", "
101
+ task_parts+="${stat_tasks_pending} pending"
102
+ fi
103
+ if [ "$stat_tasks_done" -gt 0 ]; then
104
+ [ -n "$task_parts" ] && task_parts+=", "
105
+ task_parts+="${stat_tasks_done} completed"
106
+ fi
107
+ [ -z "$task_parts" ] && task_parts="none"
108
+
109
+ # Truncate last summary for display
110
+ stat_last_display="${stat_last_summary:0:60}"
111
+ [ ${#stat_last_summary} -gt 60 ] && stat_last_display+="..."
112
+ [ -z "$stat_last_display" ] && stat_last_display="(no sessions yet)"
113
+
114
+ # ─── Build context injection ────────────────────────────────
115
+
116
+ eagle_banner="======================================
117
+ Eagle Mem Loaded
118
+ ======================================
119
+ Project | $project
120
+ Sessions | $stat_sessions total ($stat_summaries with summaries)
121
+ Memories | $stat_memories stored
122
+ Plans | $stat_plans saved
123
+ Tasks | $task_parts
124
+ Code Index | $stat_chunks chunks indexed
125
+ Observations | $stat_observations captured
126
+ Last Active | $stat_last_active
127
+ Last Work | $stat_last_display
128
+ ======================================"
129
+
130
+ context="$eagle_banner
47
131
 
48
132
  === EAGLE MEM — Active (trigger: $source_type) ===
49
133
  Eagle Mem (https://github.com/eagleisbatman/eagle-mem) is providing persistent memory for this session. It tracks summaries, observations, tasks, and code context across sessions via SQLite + FTS5. Mention Eagle Mem by name when referencing recalled context.
50
134
 
51
135
  "
52
136
 
137
+ if [ -n "$update_notice" ]; then
138
+ context+="=== EAGLE MEM — $update_notice ===
139
+
140
+ "
141
+ fi
142
+
53
143
  # Project overview
54
144
  overview=$(eagle_get_overview "$project")
55
145
  if [ -n "$overview" ]; then
@@ -71,7 +161,7 @@ if [ -n "$recent" ]; then
71
161
  context+="=== EAGLE MEM ===
72
162
  Recent sessions for project '$project':
73
163
  "
74
- while IFS='|' read -r request completed learned next_steps created_at; do
164
+ while IFS='|' read -r request completed learned next_steps created_at decisions gotchas key_files; do
75
165
  [ -z "$request" ] && [ -z "$completed" ] && continue
76
166
  context+="
77
167
  --- $created_at ---"
@@ -81,6 +171,12 @@ Request: $request"
81
171
  Completed: $completed"
82
172
  [ -n "$learned" ] && context+="
83
173
  Learned: $learned"
174
+ [ -n "$decisions" ] && context+="
175
+ Decisions: $decisions"
176
+ [ -n "$gotchas" ] && context+="
177
+ Gotchas: $gotchas"
178
+ [ -n "$key_files" ] && context+="
179
+ Key files: $key_files"
84
180
  [ -n "$next_steps" ] && context+="
85
181
  Next steps: $next_steps"
86
182
  done <<< "$recent"
@@ -88,17 +184,32 @@ Next steps: $next_steps"
88
184
  "
89
185
  fi
90
186
 
91
- # ─── Mirrored Claude memories ──────────────────────────────
187
+ # ─── Mirrored Claude memories (with age) ─────────────────
92
188
 
93
- memories=$(eagle_list_claude_memories "$project" 5)
189
+ memories=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at,
190
+ CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
191
+ FROM claude_memories
192
+ WHERE project = '$p_esc'
193
+ ORDER BY updated_at DESC
194
+ LIMIT 5;")
94
195
  if [ -n "$memories" ]; then
95
196
  context+="
96
197
  === EAGLE MEM — Memories ===
97
198
  Recent memories for '$project':
98
199
  "
99
- while IFS='|' read -r mname mtype mdesc _fpath _updated; do
200
+ while IFS='|' read -r mname mtype mdesc _fpath _updated days_ago; do
100
201
  [ -z "$mname" ] && continue
101
- context+=" - [$mtype] $mname: $mdesc
202
+ age_label=""
203
+ if [ -n "$days_ago" ] && [ "$days_ago" -gt 0 ] 2>/dev/null; then
204
+ if [ "$days_ago" -eq 1 ]; then
205
+ age_label=" (1 day ago)"
206
+ else
207
+ age_label=" (${days_ago} days ago)"
208
+ fi
209
+ else
210
+ age_label=" (today)"
211
+ fi
212
+ context+=" - [$mtype] $mname: $mdesc$age_label
102
213
  "
103
214
  done <<< "$memories"
104
215
  fi
@@ -121,7 +232,7 @@ fi
121
232
  # ─── Claude Code tasks ───────────────────────────────────
122
233
 
123
234
  synced_tasks=$(eagle_db "SELECT subject, status, blocked_by FROM claude_tasks
124
- WHERE project = '$(eagle_sql_escape "$project")'
235
+ WHERE project = '$p_esc'
125
236
  AND status IN ('in_progress', 'pending')
126
237
  AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
127
238
  ORDER BY
@@ -149,29 +260,62 @@ context+="
149
260
  === EAGLE MEM INSTRUCTIONS ===
150
261
  You have persistent memory powered by Eagle Mem. When you recall context from a previous session or use injected memory, attribute it: \"From Eagle Mem:\" or \"Eagle Mem recalls:\". This helps the user understand where the context came from.
151
262
 
152
- IMPORTANT: At the start of your VERY NEXT response (this fires on session start, /clear, AND context compaction — always show this block, even if you think you showed it before, because prior context may have been compressed away). Show the user what Eagle Mem loaded using this exact format:
263
+ IMPORTANT: At the start of your VERY NEXT response (this fires on session start, /clear, AND context compaction — always show this block, even if you think you showed it before, because prior context may have been compressed away). Show the user what Eagle Mem loaded by reproducing this exact banner:
153
264
 
154
265
  \`\`\`
155
- $eagle_logo
156
-
157
- Project: <project name>
158
- Sessions: N recent | Memories: N | Tasks: N pending
159
- Last: [one-line summary of most recent session]
266
+ $eagle_banner
160
267
  \`\`\`
161
268
 
162
- This gives the user visibility into the context you received.
269
+ This gives the user visibility into the full context Eagle Mem loaded for this session.
270
+
271
+ MEMORY FRESHNESS: The memories above include age indicators. If you make a change (edit a file, update a config, change a pattern) that contradicts what a loaded memory says, you MUST update that memory file immediately. Read the memory file, edit it to reflect the new reality, and the PostToolUse hook will sync the update to Eagle Mem. Stale memories mislead future sessions — keeping them current is as important as writing good code.
272
+
273
+ === EAGLE MEM — SESSION SUMMARY (MANDATORY) ===
274
+ You MUST emit an <eagle-summary> block before your FINAL response in this session. This is how Eagle Mem captures what happened — without it, the next session starts blind and wastes tokens rediscovering context.
275
+
276
+ FORMAT — emit this block exactly. Every field is REQUIRED. Do not skip fields, do not leave them empty, do not write \"N/A\".
277
+
278
+ <eagle-summary>
279
+ request: [One sentence: what did the user ask for?]
280
+ investigated: [Comma-separated file paths you read or explored]
281
+ learned: [Non-obvious technical discoveries — things a future session could not guess from reading the code]
282
+ completed: [What was accomplished — be specific about what shipped, not what was \"worked on\"]
283
+ next_steps: [Concrete actions for the next session, not vague aspirations]
284
+ decisions:
285
+ - [Choice made] Why: [the reason — what constraint or tradeoff drove this choice]
286
+ - [Choice made] Why: [reason]
287
+ gotchas:
288
+ - [What failed, surprised, or does not work the obvious way. Be specific — \"X does not work because Y\" not just \"X was tricky\"]
289
+ key_files:
290
+ - [path/to/file.ext] — [one-line role: what this file does in the context of this work]
291
+ - [path/to/other.ext] — [role]
292
+ files_read: [file1, file2, ...]
293
+ files_modified: [file1, file2, ...]
294
+ </eagle-summary>
295
+
296
+ EXAMPLE — this is what a well-written summary looks like:
163
297
 
164
- Before your final response in this session, emit a summary block:
165
298
  <eagle-summary>
166
- request: What the user asked for
167
- investigated: Key files/areas explored
168
- learned: Non-obvious discoveries
169
- completed: What was accomplished
170
- next_steps: What should happen next
171
- files_read: [list of files read]
172
- files_modified: [list of files modified]
299
+ request: Add JWT authentication middleware to the API
300
+ investigated: src/middleware/auth.ts, src/routes/users.ts, package.json, src/config/env.ts
301
+ learned: express-jwt v8 changed its API — req.auth replaces req.user. The error handler must check err.name === 'UnauthorizedError', not err.status === 401.
302
+ completed: JWT middleware deployed on all /api routes. Token validation, role-based guards, and 401/403 error responses all working. Added JWKS endpoint support for key rotation.
303
+ next_steps: Add refresh token rotation; rate-limit the /auth/token endpoint
304
+ decisions:
305
+ - Chose RS256 over HS256 for JWT signing. Why: allows key rotation via JWKS without redeploying; HS256 requires shared secret on every service.
306
+ - Put auth middleware at router level, not app level. Why: healthcheck and public routes must remain unauthenticated; per-router mounting is explicit about what is protected.
307
+ gotchas:
308
+ - express-jwt v8 is ESM-only — require() fails silently and returns undefined. Must use dynamic import().
309
+ - Setting token expiry below 5 min causes refresh storms under load — the refresh endpoint itself requires a valid (but expired) token, creating a chicken-and-egg problem.
310
+ key_files:
311
+ - src/middleware/auth.ts — JWT validation + role guard middleware
312
+ - src/config/env.ts — JWKS_URI and JWT_ISSUER environment config
313
+ - src/routes/users.ts — first route to use the new auth guard (reference implementation)
314
+ files_read: [src/middleware/auth.ts, src/routes/users.ts, package.json, src/config/env.ts]
315
+ files_modified: [src/middleware/auth.ts, src/config/env.ts, src/routes/users.ts, package.json]
173
316
  </eagle-summary>
174
- This helps Eagle Mem track what happened for future sessions.
317
+
318
+ WHY THIS MATTERS: Eagle Mem re-injects this summary at the start of future sessions. The 'decisions' field prevents re-debating settled choices. The 'gotchas' field prevents repeating the same mistakes. The 'key_files' field tells the next session exactly where to start reading instead of exploring blindly. Write these fields as if you are briefing a colleague who will pick up your work tomorrow — because that is exactly what happens.
175
319
  "
176
320
 
177
321
  # Output context (plain text stdout = additionalContext for SessionStart)
package/hooks/stop.sh CHANGED
@@ -67,7 +67,7 @@ parse_field() {
67
67
  $0 ~ "^"f":" {
68
68
  sub("^"f":[[:space:]]*", ""); found=1; val=$0; next
69
69
  }
70
- found && /^(request|investigated|learned|completed|next_steps|files_read|files_modified|notes):/ { exit }
70
+ found && /^(request|investigated|learned|completed|next_steps|files_read|files_modified|notes|decisions|gotchas|key_files):/ { exit }
71
71
  found { val = val " " $0 }
72
72
  END { if (found) print val }
73
73
  '
@@ -81,6 +81,9 @@ next_steps=""
81
81
  files_read="[]"
82
82
  files_modified="[]"
83
83
  notes=""
84
+ decisions=""
85
+ gotchas=""
86
+ key_files=""
84
87
 
85
88
  if [ -n "$summary_block" ]; then
86
89
  request=$(parse_field "$summary_block" "request")
@@ -88,6 +91,9 @@ if [ -n "$summary_block" ]; then
88
91
  learned=$(parse_field "$summary_block" "learned")
89
92
  completed=$(parse_field "$summary_block" "completed")
90
93
  next_steps=$(parse_field "$summary_block" "next_steps")
94
+ decisions=$(parse_field "$summary_block" "decisions")
95
+ gotchas=$(parse_field "$summary_block" "gotchas")
96
+ key_files=$(parse_field "$summary_block" "key_files")
91
97
 
92
98
  raw_fr=$(parse_field "$summary_block" "files_read")
93
99
  raw_fm=$(parse_field "$summary_block" "files_modified")
@@ -137,7 +143,7 @@ fi
137
143
  # ─── Write to database ─────────────────────────────────────
138
144
 
139
145
  if [ -n "$request" ] || [ -n "$completed" ] || [ -n "$learned" ]; then
140
- eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes"
146
+ eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files"
141
147
  eagle_log "INFO" "Stop: summary saved for session=$session_id"
142
148
  fi
143
149
 
@@ -52,12 +52,18 @@ context=""
52
52
  if [ -n "$results" ]; then
53
53
  context+="=== EAGLE MEM — Relevant Memory ===
54
54
  "
55
- while IFS='|' read -r req completed learned _next_steps created_at _proj; do
55
+ while IFS='|' read -r req completed learned _next_steps created_at _proj decisions gotchas key_files; do
56
56
  [ -z "$req" ] && [ -z "$completed" ] && continue
57
57
  context+="[$created_at] "
58
58
  [ -n "$req" ] && context+="$req"
59
59
  [ -n "$completed" ] && context+=" → $completed"
60
60
  [ -n "$learned" ] && context+=" (Learned: $learned)"
61
+ [ -n "$decisions" ] && context+="
62
+ Decisions: $decisions"
63
+ [ -n "$gotchas" ] && context+="
64
+ Gotchas: $gotchas"
65
+ [ -n "$key_files" ] && context+="
66
+ Key files: $key_files"
61
67
  context+="
62
68
  "
63
69
  done <<< "$results"
package/lib/db.sh CHANGED
@@ -85,9 +85,12 @@ eagle_insert_summary() {
85
85
  local files_read; files_read=$(eagle_sql_escape "$8")
86
86
  local files_modified; files_modified=$(eagle_sql_escape "$9")
87
87
  local notes; notes=$(eagle_sql_escape "${10:-}")
88
+ local decisions; decisions=$(eagle_sql_escape "${11:-}")
89
+ local gotchas; gotchas=$(eagle_sql_escape "${12:-}")
90
+ local key_files; key_files=$(eagle_sql_escape "${13:-}")
88
91
 
89
92
  eagle_db_pipe <<SQL
90
- INSERT INTO summaries (session_id, project, request, investigated, learned, completed, next_steps, files_read, files_modified, notes)
93
+ INSERT INTO summaries (session_id, project, request, investigated, learned, completed, next_steps, files_read, files_modified, notes, decisions, gotchas, key_files)
91
94
  VALUES (
92
95
  '$session_id',
93
96
  '$project',
@@ -98,7 +101,10 @@ VALUES (
98
101
  '$next_steps',
99
102
  '$files_read',
100
103
  '$files_modified',
101
- '$notes'
104
+ '$notes',
105
+ '$decisions',
106
+ '$gotchas',
107
+ '$key_files'
102
108
  )
103
109
  ON CONFLICT(session_id) DO UPDATE SET
104
110
  project = excluded.project,
@@ -109,7 +115,10 @@ ON CONFLICT(session_id) DO UPDATE SET
109
115
  next_steps = COALESCE(NULLIF(excluded.next_steps, ''), summaries.next_steps),
110
116
  files_read = COALESCE(NULLIF(excluded.files_read, '[]'), summaries.files_read),
111
117
  files_modified = COALESCE(NULLIF(excluded.files_modified, '[]'), summaries.files_modified),
112
- notes = COALESCE(NULLIF(excluded.notes, ''), summaries.notes);
118
+ notes = COALESCE(NULLIF(excluded.notes, ''), summaries.notes),
119
+ decisions = COALESCE(NULLIF(excluded.decisions, ''), summaries.decisions),
120
+ gotchas = COALESCE(NULLIF(excluded.gotchas, ''), summaries.gotchas),
121
+ key_files = COALESCE(NULLIF(excluded.key_files, ''), summaries.key_files);
113
122
  SQL
114
123
  }
115
124
 
@@ -117,7 +126,7 @@ eagle_get_recent_summaries() {
117
126
  local project; project=$(eagle_sql_escape "$1")
118
127
  local limit; limit=$(eagle_sql_int "${2:-5}")
119
128
 
120
- eagle_db "SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at
129
+ eagle_db "SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at, s.decisions, s.gotchas, s.key_files
121
130
  FROM summaries s
122
131
  WHERE s.project = '$project'
123
132
  AND s.request NOT LIKE '%<local-command-caveat>%'
@@ -137,7 +146,7 @@ eagle_search_summaries() {
137
146
  where_clause="AND s.project = '$project'"
138
147
  fi
139
148
 
140
- eagle_db "SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at, s.project
149
+ eagle_db "SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at, s.project, s.decisions, s.gotchas, s.key_files
141
150
  FROM summaries s
142
151
  JOIN summaries_fts f ON f.rowid = s.id
143
152
  WHERE summaries_fts MATCH '$query'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eagle-mem",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Persistent memory for Claude Code — SQLite + FTS5, no daemon, no bloat",
5
5
  "bin": {
6
6
  "eagle-mem": "bin/eagle-mem"
@@ -242,6 +242,11 @@ else
242
242
  fi
243
243
  fi
244
244
 
245
+ # ─── Save installed version ───────────────────────────────
246
+
247
+ version=$(jq -r .version "$PACKAGE_DIR/package.json" 2>/dev/null || echo "unknown")
248
+ echo "$version" > "$EAGLE_MEM_DIR/.version"
249
+
245
250
  # ─── Summary ───────────────────────────────────────────────
246
251
 
247
252
  eagle_footer "Eagle Mem installed successfully."
package/scripts/style.sh CHANGED
@@ -43,12 +43,10 @@ eagle_footer() {
43
43
  }
44
44
 
45
45
  eagle_banner() {
46
- echo -e "${CYAN}"
47
- cat << 'BANNER'
48
- █▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
49
- ██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █
50
- BANNER
51
- echo -e "${RESET}"
46
+ echo -e " ${CYAN}======================================${RESET}"
47
+ echo -e " ${CYAN}${BOLD} Eagle Mem${RESET}"
48
+ echo -e " ${CYAN}======================================${RESET}"
49
+ echo ""
52
50
  }
53
51
 
54
52
  eagle_is_tty() {
package/scripts/update.sh CHANGED
@@ -106,7 +106,9 @@ else
106
106
  eagle_ok "Project names up to date"
107
107
  fi
108
108
 
109
- # ─── Summary ───────────────────────────────────────────────
109
+ # ─── Save installed version ───────────────────────────────
110
110
 
111
111
  version=$(jq -r .version "$PACKAGE_DIR/package.json" 2>/dev/null || echo "unknown")
112
+ echo "$version" > "$EAGLE_MEM_DIR/.version"
113
+
112
114
  eagle_footer "Eagle Mem updated to v${version}."