eagle-mem 1.6.3 → 2.0.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/README.md +68 -200
- package/bin/eagle-mem +1 -0
- package/db/010_session_activity.sql +15 -0
- package/db/011_overview_source.sql +10 -0
- package/hooks/post-tool-use.sh +0 -6
- package/hooks/session-start.sh +13 -7
- package/lib/db.sh +55 -37
- package/package.json +2 -2
- package/scripts/help.sh +23 -44
- package/scripts/overview.sh +1 -1
- package/scripts/refresh.sh +82 -0
- package/scripts/scan.sh +23 -2
- package/scripts/update.sh +10 -0
- package/skills/eagle-mem-index/SKILL.md +95 -24
- package/skills/eagle-mem-memories/SKILL.md +109 -38
- package/skills/eagle-mem-overview/SKILL.md +62 -48
- package/skills/eagle-mem-prune/SKILL.md +99 -31
- package/skills/eagle-mem-scan/SKILL.md +93 -25
- package/skills/eagle-mem-search/SKILL.md +87 -47
- package/skills/eagle-mem-tasks/SKILL.md +105 -58
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
# Eagle Mem
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Persistent memory for [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Every session starts with context from previous sessions — summaries, memories, tasks, and project overviews — injected automatically via hooks.
|
|
9
9
|
|
|
10
10
|
**Zero per-instance overhead.** No daemon, no vector DB, no MCP server. Just bash scripts, sqlite3, and jq.
|
|
11
11
|
|
|
@@ -16,33 +16,7 @@ npm install -g eagle-mem
|
|
|
16
16
|
eagle-mem install
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
█▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
|
|
23
|
-
██▄ █▀█ █▄█ █▄▄ ██▄ █ ▀ █ ██▄ █ ▀ █
|
|
24
|
-
|
|
25
|
-
Eagle Mem Install
|
|
26
|
-
─────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
Checking prerequisites...
|
|
29
|
-
|
|
30
|
-
✓ sqlite3 (3.39.5)
|
|
31
|
-
✓ FTS5 support
|
|
32
|
-
✓ jq (1.7.1)
|
|
33
|
-
✓ Claude Code (~/.claude/)
|
|
34
|
-
|
|
35
|
-
Installing Eagle Mem...
|
|
36
|
-
|
|
37
|
-
✓ Files copied to ~/.eagle-mem
|
|
38
|
-
✓ Database ready
|
|
39
|
-
✓ Hooks registered
|
|
40
|
-
✓ Skills installed
|
|
41
|
-
|
|
42
|
-
Eagle Mem installed successfully.
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Start a new Claude Code session — Eagle Mem activates automatically and shows:
|
|
19
|
+
Start a new Claude Code session — Eagle Mem activates automatically:
|
|
46
20
|
|
|
47
21
|
```
|
|
48
22
|
█▀▀ ▄▀█ █▀▀ █ █▀▀ █▀▄▀█ █▀▀ █▀▄▀█
|
|
@@ -53,154 +27,71 @@ Sessions: 5 recent | Memories: 3 | Tasks: 2 pending
|
|
|
53
27
|
Last: Added auth middleware with JWT validation
|
|
54
28
|
```
|
|
55
29
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
| Command | What it does |
|
|
59
|
-
|---------|-------------|
|
|
60
|
-
| `eagle-mem install` | First-time setup: checks prerequisites, deploys hooks, creates database, installs skills |
|
|
61
|
-
| `eagle-mem update` | Re-deploys hooks/lib files, runs pending migrations, backfills project names |
|
|
62
|
-
| `eagle-mem scan .` | Analyze a project and generate an overview (auto-injected at session start) |
|
|
63
|
-
| `eagle-mem index .` | Index source files into FTS5-searchable chunks (incremental via mtime) |
|
|
64
|
-
| `eagle-mem search <query>` | Full-text search across summaries, observations, and code chunks |
|
|
65
|
-
| `eagle-mem tasks` | View mirrored Claude Code tasks (read-only — Claude Code manages task state) |
|
|
66
|
-
| `eagle-mem overview` | View or regenerate project overviews |
|
|
67
|
-
| `eagle-mem memories` | List, search, and sync Claude Code auto-memories, plans, and tasks |
|
|
68
|
-
| `eagle-mem memories sync` | Backfill all Claude Code memories, plans, and tasks into Eagle Mem |
|
|
69
|
-
| `eagle-mem prune` | Clean up orphan code chunks and stale data |
|
|
70
|
-
| `eagle-mem uninstall` | Removes hooks from settings.json and optionally deletes data |
|
|
71
|
-
| `eagle-mem help` | Shows usage, commands, and available skills |
|
|
72
|
-
| `eagle-mem version` | Shows current version |
|
|
73
|
-
|
|
74
|
-
## Why
|
|
30
|
+
## What It Does
|
|
75
31
|
|
|
76
|
-
|
|
32
|
+
Eagle Mem hooks into Claude Code's lifecycle to solve the context loss problem:
|
|
77
33
|
|
|
78
|
-
- **
|
|
79
|
-
- **
|
|
80
|
-
- **
|
|
81
|
-
- **Compact
|
|
82
|
-
- **
|
|
83
|
-
- **FTS5 full-text search** across all sessions and projects
|
|
84
|
-
- **Contextual memory injection** — relevant past sessions surfaced when you ask related questions
|
|
85
|
-
- **Privacy controls** — `<private>` tags strip sensitive content before storage
|
|
86
|
-
- **Observation deduplication** — prevents DB bloat from repeated tool calls
|
|
87
|
-
- **Project overviews** — persistent one-paragraph project summaries injected at session start
|
|
88
|
-
- **Concurrent-safe** WAL mode with busy timeout — runs fine across 4-5 simultaneous sessions
|
|
89
|
-
- **Codebase scanning** — auto-generates project overviews from structure analysis
|
|
90
|
-
- **Code indexing** — FTS5-searchable source chunks with incremental re-indexing
|
|
91
|
-
- **Stale data filtering** — noisy auto-captured summaries and 7-day-old tasks are excluded from injection
|
|
34
|
+
- **Session summaries** — automatically captured when Claude's turn ends, stored in SQLite with FTS5 search
|
|
35
|
+
- **Memory mirror** — mirrors Claude Code's auto-memories, plans, and tasks into a searchable database
|
|
36
|
+
- **Context injection** — at session start, injects project overview + recent summaries + relevant memories + in-progress tasks
|
|
37
|
+
- **Compact survival** — after `/compact`, Eagle Mem re-injects full context so Claude picks up where it left off
|
|
38
|
+
- **Privacy** — wrap sensitive content in `<private>` tags and it's stripped before storage
|
|
92
39
|
|
|
93
|
-
##
|
|
94
|
-
|
|
95
|
-
### Hook Lifecycle
|
|
40
|
+
## Hook Lifecycle
|
|
96
41
|
|
|
97
42
|
| Hook | Fires When | What It Does |
|
|
98
43
|
|------|-----------|--------------|
|
|
99
|
-
| **SessionStart** | startup, resume, clear, compact |
|
|
100
|
-
| **UserPromptSubmit** | user sends a message | Searches FTS5 for memories relevant to the
|
|
101
|
-
| **Stop** | Claude's turn ends | Parses `<eagle-summary>` from transcript
|
|
102
|
-
| **PostToolUse** | after
|
|
103
|
-
| **SessionEnd** | session closes | Re-syncs
|
|
104
|
-
|
|
105
|
-
### Claude Code Memory Mirror
|
|
106
|
-
|
|
107
|
-
Eagle Mem intercepts Claude Code's built-in memory, plan, and task writes via the PostToolUse hook:
|
|
108
|
-
|
|
109
|
-
- **Memories** — when Claude writes to `~/.claude/projects/*/memory/*.md`, Eagle Mem mirrors the content with FTS5 indexing
|
|
110
|
-
- **Plans** — when Claude writes to `~/.claude/plans/*.md`, Eagle Mem captures the plan
|
|
111
|
-
- **Tasks** — when Claude calls `TaskCreate` or `TaskUpdate`, Eagle Mem captures the task JSON
|
|
112
|
-
|
|
113
|
-
These are injected at session start (top 5 memories, top 3 plans, in-progress tasks) and can be searched via CLI:
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
eagle-mem memories # list all mirrored memories
|
|
117
|
-
eagle-mem memories search "auth" # full-text search
|
|
118
|
-
eagle-mem memories plans # list captured plans
|
|
119
|
-
eagle-mem memories tasks # list captured tasks
|
|
120
|
-
eagle-mem memories sync # backfill everything from Claude Code
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
**Task resync:** At session end, Eagle Mem re-reads all task JSON files to catch status changes that bypassed the PostToolUse hook (Claude Code can update tasks internally without tool calls).
|
|
124
|
-
|
|
125
|
-
### Summary Extraction
|
|
126
|
-
|
|
127
|
-
Eagle Mem injects instructions for Claude to emit an `<eagle-summary>` block before its final response:
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
<eagle-summary>
|
|
131
|
-
request: What the user asked for
|
|
132
|
-
investigated: Key files/areas explored
|
|
133
|
-
learned: Non-obvious discoveries
|
|
134
|
-
completed: What was accomplished
|
|
135
|
-
next_steps: What should happen next
|
|
136
|
-
files_read: [list of files read]
|
|
137
|
-
files_modified: [list of files modified]
|
|
138
|
-
</eagle-summary>
|
|
139
|
-
```
|
|
44
|
+
| **SessionStart** | startup, resume, clear, compact | Injects project overview, recent summaries, memories, and in-progress tasks |
|
|
45
|
+
| **UserPromptSubmit** | user sends a message | Searches FTS5 for memories relevant to the prompt |
|
|
46
|
+
| **Stop** | Claude's turn ends | Parses `<eagle-summary>` from transcript, saves to DB |
|
|
47
|
+
| **PostToolUse** | after tool calls | Captures observations, mirrors memory/plan/task writes |
|
|
48
|
+
| **SessionEnd** | session closes | Re-syncs tasks, marks session completed |
|
|
140
49
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
### Privacy
|
|
144
|
-
|
|
145
|
-
Wrap sensitive content in `<private>` tags and it will be stripped before storage:
|
|
146
|
-
|
|
147
|
-
```
|
|
148
|
-
<private>
|
|
149
|
-
API_KEY=sk-secret-123
|
|
150
|
-
DB_PASSWORD=hunter2
|
|
151
|
-
</private>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
The Stop hook removes `<private>` blocks at the edge — before any data reaches the database.
|
|
50
|
+
## Commands
|
|
155
51
|
|
|
156
|
-
|
|
52
|
+
| Command | What it does |
|
|
53
|
+
|---------|-------------|
|
|
54
|
+
| `eagle-mem refresh` | Full project sync: scan + index + memories sync in one command |
|
|
55
|
+
| `eagle-mem search <query>` | FTS5 search across summaries, memories, and code chunks |
|
|
56
|
+
| `eagle-mem search --timeline` | Recent sessions in chronological order |
|
|
57
|
+
| `eagle-mem overview` | View or set the project overview |
|
|
58
|
+
| `eagle-mem scan` | Analyze codebase structure (languages, frameworks, entry points) |
|
|
59
|
+
| `eagle-mem index` | Index source files into FTS5-searchable chunks |
|
|
60
|
+
| `eagle-mem memories` | View/sync mirrored Claude Code memories, plans, and tasks |
|
|
61
|
+
| `eagle-mem tasks` | View mirrored Claude Code tasks |
|
|
62
|
+
| `eagle-mem prune` | Remove old observations and orphaned chunks |
|
|
63
|
+
| `eagle-mem install` | First-time setup: hooks, database, skills |
|
|
64
|
+
| `eagle-mem update` | Re-deploy hooks and run pending migrations |
|
|
65
|
+
| `eagle-mem uninstall` | Remove hooks and optionally delete data |
|
|
157
66
|
|
|
158
|
-
|
|
67
|
+
## Skills
|
|
159
68
|
|
|
160
|
-
|
|
161
|
-
2. **Execute** — Work on one task at a time (`TaskUpdate` to `in_progress`)
|
|
162
|
-
3. **Complete** — Mark done via `TaskUpdate` to `completed`
|
|
163
|
-
4. **Compact** — Run `/compact` when context fills up
|
|
164
|
-
5. **Resume** — SessionStart re-injects memory + mirrored task state from Eagle Mem
|
|
69
|
+
Seven skills available inside Claude Code sessions:
|
|
165
70
|
|
|
166
|
-
|
|
71
|
+
| Skill | What it does |
|
|
72
|
+
|-------|-------------|
|
|
73
|
+
| `/eagle-mem-search` | Progressive memory recall — search, expand, drill into sessions |
|
|
74
|
+
| `/eagle-mem-overview` | Build a structured project briefing from code, README, and git history |
|
|
75
|
+
| `/eagle-mem-scan` | Analyze codebase structure — languages, frameworks, entry points |
|
|
76
|
+
| `/eagle-mem-index` | Index source files for FTS5 code search across sessions |
|
|
77
|
+
| `/eagle-mem-memories` | View, search, and sync Claude Code's mirrored memories and plans |
|
|
78
|
+
| `/eagle-mem-tasks` | TaskAware Compact Loop — break work into tasks that survive compaction |
|
|
79
|
+
| `/eagle-mem-prune` | Database hygiene — graduated cleanup of stale data |
|
|
167
80
|
|
|
168
81
|
## Database
|
|
169
82
|
|
|
170
|
-
Single shared SQLite database at `~/.eagle-mem/memory.db
|
|
171
|
-
|
|
172
|
-
### Tables
|
|
173
|
-
|
|
174
|
-
- **sessions** — Track active/completed sessions per project
|
|
175
|
-
- **observations** — Per-tool-use records with deduplication (files read/modified)
|
|
176
|
-
- **summaries** — Per-session summaries with FTS5 search (UNIQUE on session_id, merge UPSERT)
|
|
177
|
-
- **overviews** — One rolling overview per project (injected at session start)
|
|
178
|
-
- **code_chunks** — FTS5-indexed source file chunks for code-level search
|
|
179
|
-
- **claude_memories** — Mirror of Claude Code auto-memories with FTS5 search
|
|
180
|
-
- **claude_plans** — Mirror of Claude Code plan files with FTS5 search
|
|
181
|
-
- **claude_tasks** — Mirror of Claude Code tasks with FTS5 search (statuses: pending/in_progress/completed/deleted)
|
|
182
|
-
|
|
183
|
-
### Key Design Choices
|
|
184
|
-
|
|
185
|
-
- **WAL mode** for concurrent readers across sessions
|
|
186
|
-
- **busy_timeout=5000** to retry on write contention instead of failing
|
|
187
|
-
- **FTS5 content-sync** with auto-triggers to keep search indexes in sync
|
|
188
|
-
- **trusted_schema=ON** required for FTS5 virtual tables
|
|
189
|
-
- **Project identification** via `git rev-parse --show-toplevel` (handles monorepo subdirectories correctly)
|
|
190
|
-
- **Backfill system** resolves project names from Claude Code transcript files at `~/.claude/projects/`
|
|
191
|
-
- PRAGMAs set on every connection (they're connection-scoped, not persistent)
|
|
83
|
+
Single shared SQLite database at `~/.eagle-mem/memory.db`. WAL mode for concurrent sessions, FTS5 for full-text search.
|
|
192
84
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
- **eagle-mem-prune** — Clean up old observations and orphaned chunks
|
|
85
|
+
| Table | Purpose |
|
|
86
|
+
|-------|---------|
|
|
87
|
+
| sessions | Active/completed sessions per project |
|
|
88
|
+
| summaries | Per-session summaries with FTS5 (UPSERT on session_id) |
|
|
89
|
+
| observations | Per-tool-use records with deduplication |
|
|
90
|
+
| overviews | One rolling overview per project (scan vs manual source tracking) |
|
|
91
|
+
| code_chunks | FTS5-indexed source file chunks |
|
|
92
|
+
| claude_memories | Mirror of Claude Code auto-memories |
|
|
93
|
+
| claude_plans | Mirror of Claude Code plans |
|
|
94
|
+
| claude_tasks | Mirror of Claude Code tasks |
|
|
204
95
|
|
|
205
96
|
## Architecture
|
|
206
97
|
|
|
@@ -208,36 +99,28 @@ Eagle Mem ships with seven skills for use inside Claude Code sessions:
|
|
|
208
99
|
Package (npm) Runtime (~/.eagle-mem/)
|
|
209
100
|
├── bin/eagle-mem CLI ├── memory.db SQLite + FTS5
|
|
210
101
|
├── scripts/ ├── eagle-mem.log Debug log
|
|
211
|
-
│ ├──
|
|
212
|
-
│ ├──
|
|
102
|
+
│ ├── install.sh ├── hooks/
|
|
103
|
+
│ ├── update.sh │ ├── session-start.sh
|
|
213
104
|
│ ├── uninstall.sh │ ├── user-prompt-submit.sh
|
|
214
|
-
│ ├──
|
|
215
|
-
│ ├──
|
|
216
|
-
│ ├──
|
|
217
|
-
│ ├──
|
|
218
|
-
│ ├──
|
|
219
|
-
│ ├──
|
|
105
|
+
│ ├── search.sh │ ├── stop.sh
|
|
106
|
+
│ ├── overview.sh │ ├── post-tool-use.sh
|
|
107
|
+
│ ├── tasks.sh │ └── session-end.sh
|
|
108
|
+
│ ├── prune.sh ├── lib/
|
|
109
|
+
│ ├── scan.sh │ ├── common.sh
|
|
110
|
+
│ ├── index.sh │ ├── db.sh
|
|
220
111
|
│ ├── memories.sh │ └── hooks.sh
|
|
221
|
-
│
|
|
222
|
-
│
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
├──
|
|
226
|
-
|
|
227
|
-
│ ├── common.sh ├── 005_claude_memories.sql
|
|
228
|
-
│ ├── db.sh ├── 006_claude_plans.sql
|
|
229
|
-
│ └── hooks.sh ├── 007_claude_tasks.sql
|
|
230
|
-
├── db/ Source ├── 008_summary_upsert.sql
|
|
231
|
-
│ ├── migrate.sh └── 009_drop_dead_tasks.sql
|
|
232
|
-
│ ├── schema.sql
|
|
233
|
-
│ └── [0-9]*.sql Migrations
|
|
234
|
-
└── skills/ Symlinked → ~/.claude/skills/
|
|
112
|
+
│ ├── refresh.sh └── db/
|
|
113
|
+
│ └── help.sh ├── schema.sql
|
|
114
|
+
├── hooks/ Source └── [0-9]*.sql Migrations
|
|
115
|
+
├── lib/ Source
|
|
116
|
+
├── db/ Source
|
|
117
|
+
└── skills/ → ~/.claude/skills/
|
|
235
118
|
├── eagle-mem-search/
|
|
236
|
-
├── eagle-mem-tasks/
|
|
237
119
|
├── eagle-mem-overview/
|
|
238
|
-
├── eagle-mem-index/
|
|
239
120
|
├── eagle-mem-scan/
|
|
121
|
+
├── eagle-mem-index/
|
|
240
122
|
├── eagle-mem-memories/
|
|
123
|
+
├── eagle-mem-tasks/
|
|
241
124
|
└── eagle-mem-prune/
|
|
242
125
|
```
|
|
243
126
|
|
|
@@ -245,13 +128,6 @@ Package (npm) Runtime (~/.eagle-mem/)
|
|
|
245
128
|
|
|
246
129
|
```bash
|
|
247
130
|
eagle-mem uninstall
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
Removes hooks from `~/.claude/settings.json` and skill symlinks. Optionally deletes `~/.eagle-mem/` (prompts for confirmation).
|
|
251
|
-
|
|
252
|
-
To also remove the npm package:
|
|
253
|
-
|
|
254
|
-
```bash
|
|
255
131
|
npm uninstall -g eagle-mem
|
|
256
132
|
```
|
|
257
133
|
|
|
@@ -261,14 +137,6 @@ npm uninstall -g eagle-mem
|
|
|
261
137
|
- `jq` (the installer offers to install if missing)
|
|
262
138
|
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed (`~/.claude/` must exist)
|
|
263
139
|
|
|
264
|
-
## Roadmap
|
|
265
|
-
|
|
266
|
-
- [ ] **v2**: sqlite-vec embeddings for semantic code search
|
|
267
|
-
- [ ] Timeline report skill (narrative project history from pure SQL)
|
|
268
|
-
- [x] ~~Claude Code memory/plan/task mirror~~
|
|
269
|
-
- [x] ~~ASCII eagle branding across hooks and CLI~~
|
|
270
|
-
- [x] ~~Compact-safe context reload~~
|
|
271
|
-
|
|
272
140
|
## License
|
|
273
141
|
|
|
274
142
|
MIT
|
package/bin/eagle-mem
CHANGED
|
@@ -24,6 +24,7 @@ case "$command" in
|
|
|
24
24
|
search) bash "$SCRIPTS_DIR/search.sh" "$@" ;;
|
|
25
25
|
tasks) bash "$SCRIPTS_DIR/tasks.sh" "$@" ;;
|
|
26
26
|
overview) bash "$SCRIPTS_DIR/overview.sh" "$@" ;;
|
|
27
|
+
refresh) bash "$SCRIPTS_DIR/refresh.sh" "$@" ;;
|
|
27
28
|
prune) bash "$SCRIPTS_DIR/prune.sh" "$@" ;;
|
|
28
29
|
memories) bash "$SCRIPTS_DIR/memories.sh" "$@" ;;
|
|
29
30
|
help|--help|-h)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Eagle Mem — Migration 010: Session activity tracking
|
|
3
|
+
-- Adds last_activity_at for accurate stuck-session sweeping
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
|
|
8
|
+
ALTER TABLE sessions ADD COLUMN last_activity_at TEXT;
|
|
9
|
+
|
|
10
|
+
UPDATE sessions SET last_activity_at = COALESCE(ended_at, started_at);
|
|
11
|
+
|
|
12
|
+
CREATE TRIGGER IF NOT EXISTS observations_touch_session AFTER INSERT ON observations
|
|
13
|
+
BEGIN
|
|
14
|
+
UPDATE sessions SET last_activity_at = NEW.created_at WHERE id = NEW.session_id;
|
|
15
|
+
END;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Eagle Mem — Migration 011: Overview source tracking
|
|
3
|
+
-- Tracks whether overview was written by scan or manually
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
|
|
8
|
+
ALTER TABLE overviews ADD COLUMN source TEXT NOT NULL DEFAULT 'manual';
|
|
9
|
+
|
|
10
|
+
UPDATE overviews SET source = 'scan' WHERE length(content) <= 300;
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -124,12 +124,6 @@ case "$tool_name" in
|
|
|
124
124
|
;;
|
|
125
125
|
esac
|
|
126
126
|
|
|
127
|
-
# Deduplicate: skip if exact same observation within last 5 seconds
|
|
128
|
-
dup_count=$(eagle_observation_exists "$session_id" "$tool_name" "$tool_summary")
|
|
129
|
-
if [ "$dup_count" != "0" ]; then
|
|
130
|
-
exit 0
|
|
131
|
-
fi
|
|
132
|
-
|
|
133
127
|
eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified"
|
|
134
128
|
|
|
135
129
|
exit 0
|
package/hooks/session-start.sh
CHANGED
|
@@ -30,12 +30,13 @@ eagle_log "INFO" "SessionStart: session=$session_id project=$project source=$sou
|
|
|
30
30
|
|
|
31
31
|
eagle_upsert_session "$session_id" "$project" "$cwd" "$model" "$source_type"
|
|
32
32
|
|
|
33
|
-
# ─── Sweep stuck sessions (
|
|
34
|
-
#
|
|
33
|
+
# ─── Sweep stuck sessions (no activity for 7 days) ─────────
|
|
34
|
+
# Uses last_activity_at (updated by trigger on every observation insert)
|
|
35
|
+
# so long-lived sessions with regular compactions aren't falsely abandoned
|
|
35
36
|
eagle_db "UPDATE sessions SET status = 'abandoned'
|
|
36
37
|
WHERE status = 'active'
|
|
37
38
|
AND id != '$(eagle_sql_escape "$session_id")'
|
|
38
|
-
AND started_at < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-
|
|
39
|
+
AND COALESCE(last_activity_at, started_at) < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days');"
|
|
39
40
|
|
|
40
41
|
# ─── Build context injection ────────────────────────────────
|
|
41
42
|
|
|
@@ -49,12 +50,17 @@ Eagle Mem (https://github.com/eagleisbatman/eagle-mem) is providing persistent m
|
|
|
49
50
|
|
|
50
51
|
"
|
|
51
52
|
|
|
52
|
-
# Project overview
|
|
53
|
+
# Project overview
|
|
53
54
|
overview=$(eagle_get_overview "$project")
|
|
54
55
|
if [ -n "$overview" ]; then
|
|
55
56
|
context+="=== EAGLE MEM — Project Overview ===
|
|
56
57
|
$overview
|
|
57
58
|
|
|
59
|
+
"
|
|
60
|
+
else
|
|
61
|
+
context+="=== EAGLE MEM — Action Required ===
|
|
62
|
+
No overview exists for '$project'. On the user's first prompt, run /eagle-mem-overview to build a structured project briefing. The skill has full instructions for what to read and how to write a rich overview.
|
|
63
|
+
|
|
58
64
|
"
|
|
59
65
|
fi
|
|
60
66
|
|
|
@@ -129,11 +135,11 @@ Tasks for '$project':
|
|
|
129
135
|
"
|
|
130
136
|
while IFS='|' read -r tsubject tstatus tblocked; do
|
|
131
137
|
[ -z "$tsubject" ] && continue
|
|
132
|
-
|
|
138
|
+
block_marker=""
|
|
133
139
|
if [ "$tblocked" != "[]" ] && [ -n "$tblocked" ]; then
|
|
134
|
-
|
|
140
|
+
block_marker=" (blocked)"
|
|
135
141
|
fi
|
|
136
|
-
context+=" - [$tstatus] $tsubject$
|
|
142
|
+
context+=" - [$tstatus] $tsubject$block_marker
|
|
137
143
|
"
|
|
138
144
|
done <<< "$synced_tasks"
|
|
139
145
|
fi
|
package/lib/db.sh
CHANGED
|
@@ -40,13 +40,14 @@ eagle_upsert_session() {
|
|
|
40
40
|
local model; model=$(eagle_sql_escape "${4:-}")
|
|
41
41
|
local source; source=$(eagle_sql_escape "${5:-}")
|
|
42
42
|
|
|
43
|
-
eagle_db "INSERT INTO sessions (id, project, cwd, model, source)
|
|
44
|
-
VALUES ('$session_id', '$project', '$cwd', '$model', '$source')
|
|
43
|
+
eagle_db "INSERT INTO sessions (id, project, cwd, model, source, last_activity_at)
|
|
44
|
+
VALUES ('$session_id', '$project', '$cwd', '$model', '$source', strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
45
45
|
ON CONFLICT(id) DO UPDATE SET
|
|
46
46
|
cwd = COALESCE(excluded.cwd, sessions.cwd),
|
|
47
47
|
model = COALESCE(excluded.model, sessions.model),
|
|
48
48
|
source = COALESCE(excluded.source, sessions.source),
|
|
49
|
-
status = 'active'
|
|
49
|
+
status = 'active',
|
|
50
|
+
last_activity_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now');"
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
eagle_end_session() {
|
|
@@ -63,7 +64,14 @@ eagle_insert_observation() {
|
|
|
63
64
|
local files_modified; files_modified=$(eagle_sql_escape "$6")
|
|
64
65
|
|
|
65
66
|
eagle_db "INSERT INTO observations (session_id, project, tool_name, tool_input_summary, files_read, files_modified)
|
|
66
|
-
|
|
67
|
+
SELECT '$session_id', '$project', '$tool_name', '$tool_input_summary', '$files_read', '$files_modified'
|
|
68
|
+
WHERE NOT EXISTS (
|
|
69
|
+
SELECT 1 FROM observations
|
|
70
|
+
WHERE session_id = '$session_id'
|
|
71
|
+
AND tool_name = '$tool_name'
|
|
72
|
+
AND tool_input_summary = '$tool_input_summary'
|
|
73
|
+
AND created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-5 seconds')
|
|
74
|
+
);"
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
eagle_insert_summary() {
|
|
@@ -138,29 +146,31 @@ eagle_search_summaries() {
|
|
|
138
146
|
LIMIT $limit;"
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
eagle_observation_exists() {
|
|
142
|
-
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
143
|
-
local tool_name; tool_name=$(eagle_sql_escape "$2")
|
|
144
|
-
local tool_summary; tool_summary=$(eagle_sql_escape "$3")
|
|
145
|
-
|
|
146
|
-
eagle_db "SELECT COUNT(*) FROM observations
|
|
147
|
-
WHERE session_id = '$session_id'
|
|
148
|
-
AND tool_name = '$tool_name'
|
|
149
|
-
AND tool_input_summary = '$tool_summary'
|
|
150
|
-
AND created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-5 seconds');"
|
|
151
|
-
}
|
|
152
|
-
|
|
153
149
|
eagle_upsert_overview() {
|
|
154
150
|
local project; project=$(eagle_sql_escape "$1")
|
|
155
|
-
local
|
|
151
|
+
local raw_content="$2"
|
|
152
|
+
local ov_source; ov_source=$(eagle_sql_escape "${3:-manual}")
|
|
153
|
+
|
|
154
|
+
if [ ${#raw_content} -gt 16384 ]; then
|
|
155
|
+
raw_content="${raw_content:0:16384}"
|
|
156
|
+
eagle_log "WARN" "Overview for '$1' truncated to 16 KB (was ${#2} bytes)"
|
|
157
|
+
fi
|
|
156
158
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
local content; content=$(eagle_sql_escape "$raw_content")
|
|
160
|
+
|
|
161
|
+
eagle_db "INSERT INTO overviews (project, content, source, updated_at)
|
|
162
|
+
VALUES ('$project', '$content', '$ov_source', strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
159
163
|
ON CONFLICT(project) DO UPDATE SET
|
|
160
164
|
content = excluded.content,
|
|
165
|
+
source = excluded.source,
|
|
161
166
|
updated_at = excluded.updated_at;"
|
|
162
167
|
}
|
|
163
168
|
|
|
169
|
+
eagle_get_overview_source() {
|
|
170
|
+
local project; project=$(eagle_sql_escape "$1")
|
|
171
|
+
eagle_db "SELECT source FROM overviews WHERE project = '$project';"
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
eagle_get_overview() {
|
|
165
175
|
local project; project=$(eagle_sql_escape "$1")
|
|
166
176
|
|
|
@@ -495,24 +505,24 @@ eagle_backfill_projects() {
|
|
|
495
505
|
sid_sql=$(eagle_sql_escape "$sid")
|
|
496
506
|
proj_sql=$(eagle_sql_escape "$project")
|
|
497
507
|
|
|
508
|
+
# All six tables updated atomically per session to prevent
|
|
509
|
+
# partial backfill if the process is interrupted.
|
|
510
|
+
# Note: total_changes() includes FTS trigger changes, so the
|
|
511
|
+
# reported count may be higher than actual rows updated.
|
|
512
|
+
# This is cosmetic — the count is only used for status messages.
|
|
498
513
|
local ch
|
|
499
|
-
ch=$(
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
ch=$(eagle_db "UPDATE summaries SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
512
|
-
SELECT changes();")
|
|
513
|
-
[ "${ch:-0}" -gt 0 ] && updated=$((updated + ch))
|
|
514
|
-
ch=$(eagle_db "UPDATE observations SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
515
|
-
SELECT changes();")
|
|
514
|
+
ch=$(eagle_db_pipe <<SQL
|
|
515
|
+
BEGIN;
|
|
516
|
+
UPDATE sessions SET project = '$proj_sql' WHERE id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
517
|
+
UPDATE claude_tasks SET project = '$proj_sql' WHERE source_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
518
|
+
UPDATE claude_memories SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
519
|
+
UPDATE claude_plans SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
520
|
+
UPDATE summaries SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
521
|
+
UPDATE observations SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
|
|
522
|
+
SELECT total_changes();
|
|
523
|
+
COMMIT;
|
|
524
|
+
SQL
|
|
525
|
+
)
|
|
516
526
|
[ "${ch:-0}" -gt 0 ] && updated=$((updated + ch))
|
|
517
527
|
done <<< "$map"
|
|
518
528
|
|
|
@@ -528,13 +538,21 @@ eagle_prune_orphan_chunks() {
|
|
|
528
538
|
paths=$(eagle_db "SELECT DISTINCT file_path FROM code_chunks WHERE project = '$project';")
|
|
529
539
|
|
|
530
540
|
local removed=0
|
|
541
|
+
local txn_sql="BEGIN;"
|
|
531
542
|
while IFS= read -r fpath; do
|
|
532
543
|
[ -z "$fpath" ] && continue
|
|
533
544
|
if [ ! -f "$target_dir/$fpath" ]; then
|
|
534
545
|
local fpath_sql; fpath_sql=$(eagle_sql_escape "$fpath")
|
|
535
|
-
|
|
546
|
+
txn_sql+="
|
|
547
|
+
DELETE FROM code_chunks WHERE project = '$project' AND file_path = '$fpath_sql';"
|
|
536
548
|
removed=$((removed + 1))
|
|
537
549
|
fi
|
|
538
550
|
done <<< "$paths"
|
|
551
|
+
txn_sql+="
|
|
552
|
+
COMMIT;"
|
|
553
|
+
|
|
554
|
+
if [ "$removed" -gt 0 ]; then
|
|
555
|
+
eagle_db_pipe <<< "$txn_sql"
|
|
556
|
+
fi
|
|
539
557
|
echo "$removed"
|
|
540
558
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eagle-mem",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Persistent memory for Claude Code — SQLite + FTS5, no daemon, no bloat",
|
|
5
5
|
"bin": {
|
|
6
6
|
"eagle-mem": "bin/eagle-mem"
|
|
7
7
|
},
|