eagle-mem 2.0.6 → 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 +16 -8
- package/db/012_enriched_summaries.sql +51 -0
- package/hooks/post-tool-use.sh +34 -0
- package/hooks/session-start.sh +136 -26
- package/hooks/stop.sh +8 -2
- package/hooks/user-prompt-submit.sh +7 -1
- package/lib/db.sh +14 -5
- package/package.json +1 -1
- package/scripts/style.sh +4 -6
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
|
|
28
|
-
Sessions
|
|
29
|
-
|
|
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;
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -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
|
package/hooks/session-start.sh
CHANGED
|
@@ -66,12 +66,68 @@ if [ -f "$version_file" ] && [ -s "$version_file" ]; then
|
|
|
66
66
|
fi
|
|
67
67
|
fi
|
|
68
68
|
|
|
69
|
-
# ───
|
|
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)"
|
|
70
113
|
|
|
71
|
-
|
|
72
|
-
██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █"
|
|
114
|
+
# ─── Build context injection ────────────────────────────────
|
|
73
115
|
|
|
74
|
-
|
|
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
|
|
75
131
|
|
|
76
132
|
=== EAGLE MEM — Active (trigger: $source_type) ===
|
|
77
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.
|
|
@@ -105,7 +161,7 @@ if [ -n "$recent" ]; then
|
|
|
105
161
|
context+="=== EAGLE MEM ===
|
|
106
162
|
Recent sessions for project '$project':
|
|
107
163
|
"
|
|
108
|
-
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
|
|
109
165
|
[ -z "$request" ] && [ -z "$completed" ] && continue
|
|
110
166
|
context+="
|
|
111
167
|
--- $created_at ---"
|
|
@@ -115,6 +171,12 @@ Request: $request"
|
|
|
115
171
|
Completed: $completed"
|
|
116
172
|
[ -n "$learned" ] && context+="
|
|
117
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"
|
|
118
180
|
[ -n "$next_steps" ] && context+="
|
|
119
181
|
Next steps: $next_steps"
|
|
120
182
|
done <<< "$recent"
|
|
@@ -122,17 +184,32 @@ Next steps: $next_steps"
|
|
|
122
184
|
"
|
|
123
185
|
fi
|
|
124
186
|
|
|
125
|
-
# ─── Mirrored Claude memories
|
|
187
|
+
# ─── Mirrored Claude memories (with age) ─────────────────
|
|
126
188
|
|
|
127
|
-
memories=$(
|
|
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;")
|
|
128
195
|
if [ -n "$memories" ]; then
|
|
129
196
|
context+="
|
|
130
197
|
=== EAGLE MEM — Memories ===
|
|
131
198
|
Recent memories for '$project':
|
|
132
199
|
"
|
|
133
|
-
while IFS='|' read -r mname mtype mdesc _fpath _updated; do
|
|
200
|
+
while IFS='|' read -r mname mtype mdesc _fpath _updated days_ago; do
|
|
134
201
|
[ -z "$mname" ] && continue
|
|
135
|
-
|
|
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
|
|
136
213
|
"
|
|
137
214
|
done <<< "$memories"
|
|
138
215
|
fi
|
|
@@ -155,7 +232,7 @@ fi
|
|
|
155
232
|
# ─── Claude Code tasks ───────────────────────────────────
|
|
156
233
|
|
|
157
234
|
synced_tasks=$(eagle_db "SELECT subject, status, blocked_by FROM claude_tasks
|
|
158
|
-
WHERE project = '$
|
|
235
|
+
WHERE project = '$p_esc'
|
|
159
236
|
AND status IN ('in_progress', 'pending')
|
|
160
237
|
AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
|
|
161
238
|
ORDER BY
|
|
@@ -183,29 +260,62 @@ context+="
|
|
|
183
260
|
=== EAGLE MEM INSTRUCTIONS ===
|
|
184
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.
|
|
185
262
|
|
|
186
|
-
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
|
|
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:
|
|
187
264
|
|
|
188
265
|
\`\`\`
|
|
189
|
-
$
|
|
190
|
-
|
|
191
|
-
Project: <project name>
|
|
192
|
-
Sessions: N recent | Memories: N | Tasks: N pending
|
|
193
|
-
Last: [one-line summary of most recent session]
|
|
266
|
+
$eagle_banner
|
|
194
267
|
\`\`\`
|
|
195
268
|
|
|
196
|
-
This gives the user visibility into the context
|
|
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\".
|
|
197
277
|
|
|
198
|
-
Before your final response in this session, emit a summary block:
|
|
199
278
|
<eagle-summary>
|
|
200
|
-
request:
|
|
201
|
-
investigated:
|
|
202
|
-
learned: Non-obvious discoveries
|
|
203
|
-
completed: What was accomplished
|
|
204
|
-
next_steps:
|
|
205
|
-
|
|
206
|
-
|
|
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, ...]
|
|
207
294
|
</eagle-summary>
|
|
208
|
-
|
|
295
|
+
|
|
296
|
+
EXAMPLE — this is what a well-written summary looks like:
|
|
297
|
+
|
|
298
|
+
<eagle-summary>
|
|
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]
|
|
316
|
+
</eagle-summary>
|
|
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.
|
|
209
319
|
"
|
|
210
320
|
|
|
211
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
package/scripts/style.sh
CHANGED
|
@@ -43,12 +43,10 @@ eagle_footer() {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
eagle_banner() {
|
|
46
|
-
echo -e "${CYAN}"
|
|
47
|
-
|
|
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() {
|