eagle-mem 4.6.2 → 4.7.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 +49 -15
- package/db/023_guardrails.sql +3 -2
- package/db/024_guardrails_unique.sql +46 -0
- package/db/025_pending_feature_verifications.sql +30 -0
- package/db/026_agent_source.sql +18 -0
- package/db/027_feature_verification_fingerprints.sql +9 -0
- package/db/028_agent_artifact_tables.sql +124 -0
- package/hooks/post-tool-use.sh +42 -13
- package/hooks/pre-tool-use.sh +107 -14
- package/hooks/session-end.sh +3 -1
- package/hooks/session-start.sh +64 -15
- package/hooks/stop.sh +115 -21
- package/hooks/user-prompt-submit.sh +14 -5
- package/lib/codex-hooks.sh +194 -0
- package/lib/common.sh +345 -0
- package/lib/db-backfill.sh +3 -3
- package/lib/db-features.sh +222 -0
- package/lib/db-guardrails.sh +2 -1
- package/lib/db-mirrors.sh +79 -43
- package/lib/db-observations.sh +3 -2
- package/lib/db-sessions.sh +11 -7
- package/lib/db-summaries.sh +9 -6
- package/lib/hooks-posttool.sh +8 -6
- package/lib/provider.sh +190 -4
- package/package.json +7 -3
- package/scripts/config.sh +2 -0
- package/scripts/feature.sh +70 -2
- package/scripts/guard.sh +4 -1
- package/scripts/health.sh +5 -1
- package/scripts/help.sh +13 -8
- package/scripts/install.sh +130 -76
- package/scripts/memories.sh +71 -45
- package/scripts/refresh.sh +3 -3
- package/scripts/search.sh +57 -47
- package/scripts/statusline-em.sh +1 -1
- package/scripts/tasks.sh +186 -15
- package/scripts/uninstall.sh +7 -0
- package/scripts/update.sh +51 -7
- package/skills/eagle-mem-memories/SKILL.md +13 -13
- package/skills/eagle-mem-tasks/SKILL.md +21 -15
package/README.md
CHANGED
|
@@ -9,15 +9,18 @@
|
|
|
9
9
|
|
|
10
10
|
**Context that survives `/compact`.**
|
|
11
11
|
|
|
12
|
+
**v4.7.1 hardens first-class Codex support and enforced anti-regression checks.**
|
|
13
|
+
Claude Code and Codex can now share the same local Eagle Mem database, while every captured row records which agent created it.
|
|
14
|
+
|
|
12
15
|
## The Problem
|
|
13
16
|
|
|
14
|
-
Claude Code
|
|
17
|
+
Claude Code and Codex start every session with amnesia. They don't remember what you built yesterday, what decisions you made, what files matter, or what broke last time. Every `/compact` wipes context. Every new session is a cold start. You waste tokens re-explaining your project, re-reading files, and watching agents repeat mistakes you already corrected.
|
|
15
18
|
|
|
16
19
|
The longer you work with Claude Code, the worse this gets. Projects accumulate history — decisions, gotchas, architectural patterns, feature dependencies — and none of it survives across sessions.
|
|
17
20
|
|
|
18
21
|
## The Solution
|
|
19
22
|
|
|
20
|
-
Eagle Mem is a recall layer for Claude Code. Every session starts with context from previous sessions — summaries, decisions, memories, tasks, project overviews, and relevant code — injected automatically via hooks.
|
|
23
|
+
Eagle Mem is a recall and regression-control layer for Claude Code and Codex. Every session starts with context from previous sessions — summaries, decisions, memories, tasks, project overviews, and relevant code — injected automatically via hooks. Both agents share the same SQLite database at `~/.eagle-mem/memory.db`, and captured rows are source-attributed as `Claude Code` or `Codex`.
|
|
21
24
|
|
|
22
25
|
**Zero per-instance overhead.** No daemon, no vector DB, no MCP server. Just bash scripts, sqlite3 (WAL mode, FTS5 full-text search), and jq.
|
|
23
26
|
|
|
@@ -41,29 +44,33 @@ npm install -g eagle-mem
|
|
|
41
44
|
eagle-mem install
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
That's it. Open Claude Code in any project directory. Eagle Mem activates automatically.
|
|
47
|
+
That's it. Open Claude Code or Codex in any project directory. Eagle Mem activates automatically.
|
|
45
48
|
|
|
46
49
|
Everything is automatic from here. Eagle Mem scans your codebase, indexes source files, captures session summaries, mirrors Claude's memories and tasks, learns which commands are noisy, and prunes stale data — all in the background via hooks.
|
|
47
50
|
|
|
51
|
+
For Codex, the installer enables `codex_hooks` in `~/.codex/config.toml`, registers hooks in `~/.codex/hooks.json`, symlinks Eagle Mem skills into `~/.codex/skills`, and patches `~/.codex/AGENTS.md` with the Eagle Mem summary contract. For Claude Code, it keeps using `~/.claude/settings.json`, `CLAUDE.md`, `~/.claude/skills`, and the existing Claude memory/task locations.
|
|
52
|
+
|
|
48
53
|
### Prerequisites
|
|
49
54
|
|
|
50
55
|
- `sqlite3` with FTS5 support (ships with macOS; the installer offers to install if missing)
|
|
51
56
|
- `jq` (the installer offers to install if missing)
|
|
52
|
-
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
|
|
57
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code), Codex, or both installed
|
|
53
58
|
|
|
54
59
|
## How It Works
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
Hooks fire automatically at different points in the agent lifecycle:
|
|
57
62
|
|
|
58
63
|
| Hook | Fires When | What It Does |
|
|
59
64
|
|------|-----------|--------------|
|
|
60
65
|
| **SessionStart** | startup, resume, clear, compact | Injects overview, summaries, memories, tasks, core files, working set. Auto-provisions new projects (scan, index). |
|
|
61
|
-
| **PreToolUse** | before Bash, Read, Edit, Write | Surfaces guardrails and decisions before edits. Rewrites noisy commands
|
|
66
|
+
| **PreToolUse** | before Bash/shell, Read, Edit, Write, apply_patch | Surfaces guardrails and decisions before edits. Blocks release-boundary commands while feature verification is pending. Rewrites noisy commands through RTK when available. Detects redundant reads, nudges co-edit partners, detects stuck loops. |
|
|
62
67
|
| **UserPromptSubmit** | user sends a message | FTS5 search across past sessions and indexed code for relevant context |
|
|
63
68
|
| **PostToolUse** | after tool calls | Records file touches, mirrors memory/plan/task writes, surfaces decision history and feature impacts on reads, stale memory warnings on edits |
|
|
64
|
-
| **Stop** |
|
|
69
|
+
| **Stop** | agent turn ends | Extracts `<eagle-summary>` blocks for rich session summaries from Claude Code and Codex transcripts |
|
|
65
70
|
| **SessionEnd** | session closes | Re-syncs tasks, marks session completed |
|
|
66
71
|
|
|
72
|
+
Codex shell hooks are registered for `Bash`, `exec_command`, `shell_command`, and `unified_exec` tool names so release-boundary protection works across current Codex shell paths.
|
|
73
|
+
|
|
67
74
|
### Background Automation
|
|
68
75
|
|
|
69
76
|
These run automatically via SessionStart — no commands needed:
|
|
@@ -92,9 +99,10 @@ Eagle Mem prevents Claude from repeating past mistakes:
|
|
|
92
99
|
|
|
93
100
|
- **Decision surfacing** — when you edit a file that has past decisions recorded (from `<eagle-summary>` blocks), PreToolUse reminds Claude not to revert without asking
|
|
94
101
|
- **Guardrails** — file-level rules (manual or curator-discovered) that fire before every Edit/Write
|
|
95
|
-
- **Feature verification** — tracks features with smoke tests and dependencies;
|
|
102
|
+
- **Feature verification** — tracks features with smoke tests and dependencies; current git diffs create fingerprinted pending verification records, and release-boundary commands such as `git push`, `gh pr create`, and package publish are blocked until the current fingerprint is verified or waived
|
|
96
103
|
- **Gotcha surfacing** — past surprises and gotchas are surfaced when editing related files
|
|
97
104
|
- **Stale memory detection** — warns when edits may contradict stored memories
|
|
105
|
+
- **Token guard** — when `rtk` is installed, raw shell output commands are rewritten or blocked with an RTK equivalent so large output is compacted before it enters agent context
|
|
98
106
|
|
|
99
107
|
## Commands
|
|
100
108
|
|
|
@@ -108,7 +116,7 @@ Eagle Mem prevents Claude from repeating past mistakes:
|
|
|
108
116
|
| `eagle-mem config` | View or change LLM provider settings |
|
|
109
117
|
| `eagle-mem guard` | Manage regression guardrails for files |
|
|
110
118
|
| `eagle-mem overview` | Build or view project overview |
|
|
111
|
-
| `eagle-mem memories` | View/sync
|
|
119
|
+
| `eagle-mem memories` | View/sync agent memories |
|
|
112
120
|
| `eagle-mem tasks` | View mirrored tasks |
|
|
113
121
|
| `eagle-mem curate` | Run curator (co-edits, hot files, guardrails) |
|
|
114
122
|
| `eagle-mem feature` | Track and verify features |
|
|
@@ -122,20 +130,43 @@ Eagle Mem prevents Claude from repeating past mistakes:
|
|
|
122
130
|
eagle-mem search "auth bug" # keyword search across summaries
|
|
123
131
|
eagle-mem search --timeline # recent sessions in chronological order
|
|
124
132
|
eagle-mem search --overview # project overview
|
|
125
|
-
eagle-mem search --memories # mirrored
|
|
133
|
+
eagle-mem search --memories # mirrored agent memories
|
|
126
134
|
eagle-mem search --tasks # in-flight tasks (pending/in-progress)
|
|
127
135
|
eagle-mem search --files # most frequently modified files
|
|
128
136
|
eagle-mem search --stats # project statistics
|
|
129
137
|
eagle-mem search --session <id> # full observation trail for one session
|
|
130
138
|
```
|
|
131
139
|
|
|
140
|
+
### Feature Verification
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
eagle-mem feature pending
|
|
144
|
+
eagle-mem feature verify "Feature name" --notes "smoke test passed"
|
|
145
|
+
eagle-mem feature waive 12 --reason "docs-only change, no runtime impact"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Verification is tied to the current git diff fingerprint. If the same diff was already verified, release-boundary hooks do not reopen it. If the file changes again, Eagle Mem creates a new pending verification for the new fingerprint.
|
|
149
|
+
|
|
150
|
+
Dry-run validation stays unblocked. For example, `gh pr create --dry-run` and `npm publish --dry-run` are treated as validation. Explicit real commands such as `npm publish --dry-run=false` are treated as release boundaries and will enforce pending feature verification.
|
|
151
|
+
|
|
152
|
+
### Shared Claude Code + Codex Memory
|
|
153
|
+
|
|
154
|
+
Both agents write to `~/.eagle-mem/memory.db`:
|
|
155
|
+
|
|
156
|
+
- `sessions.agent` records whether a session came from Claude Code or Codex
|
|
157
|
+
- `summaries.agent` records which agent produced the session summary
|
|
158
|
+
- mirrored memories, plans, and tasks include `origin_agent`
|
|
159
|
+
- SessionStart recall labels sources as `Claude Code` or `Codex`
|
|
160
|
+
|
|
161
|
+
That means opening the same project in Claude Code and Codex does not create two isolated memory worlds. They recall the same project history while preserving the source of each memory.
|
|
162
|
+
|
|
132
163
|
## Skills (Inside Claude Code)
|
|
133
164
|
|
|
134
165
|
| Skill | What It Does |
|
|
135
166
|
|-------|-------------|
|
|
136
167
|
| `/eagle-mem-search` | Search memory and past sessions — Claude interprets results in context |
|
|
137
168
|
| `/eagle-mem-overview` | Build a rich project briefing from README, entry points, and git history |
|
|
138
|
-
| `/eagle-mem-memories` | View and search mirrored
|
|
169
|
+
| `/eagle-mem-memories` | View and search mirrored agent memories and plans |
|
|
139
170
|
| `/eagle-mem-tasks` | TaskAware Compact Loop — break complex work into tasks that survive `/compact` |
|
|
140
171
|
|
|
141
172
|
## Data
|
|
@@ -156,10 +187,11 @@ Single SQLite database at `~/.eagle-mem/memory.db` (WAL mode, FTS5 full-text sea
|
|
|
156
187
|
| `feature_files` | Files belonging to each feature |
|
|
157
188
|
| `feature_dependencies` | Inter-feature dependency relationships |
|
|
158
189
|
| `feature_smoke_tests` | Smoke test definitions for feature verification |
|
|
190
|
+
| `pending_feature_verifications` | Release blockers created when files tied to features change |
|
|
159
191
|
| `eagle_meta` | Internal metadata (last scan, last curate, etc.) |
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
192
|
+
| `agent_memories` | Mirror of agent memory files, with source attribution |
|
|
193
|
+
| `agent_plans` | Mirror of agent plan files, with source attribution |
|
|
194
|
+
| `agent_tasks` | Mirror of agent task records, with source attribution |
|
|
163
195
|
|
|
164
196
|
### Project Identity
|
|
165
197
|
|
|
@@ -175,9 +207,11 @@ Some features (curator auto-enrichment, overview generation) can use an LLM for
|
|
|
175
207
|
|
|
176
208
|
```bash
|
|
177
209
|
eagle-mem config
|
|
210
|
+
eagle-mem config set provider.type agent_cli
|
|
211
|
+
eagle-mem config set agent_cli.preferred current
|
|
178
212
|
```
|
|
179
213
|
|
|
180
|
-
|
|
214
|
+
Provider preference is local-first: Ollama is auto-detected when running, then Eagle Mem can use the installed Codex/Claude CLI via `agent_cli` before falling back to explicit Anthropic/OpenAI API providers. Eagle Mem works fully without a provider — LLM features gracefully degrade to heuristic fallbacks.
|
|
181
215
|
|
|
182
216
|
## License
|
|
183
217
|
|
package/db/023_guardrails.sql
CHANGED
|
@@ -11,8 +11,9 @@ CREATE TABLE IF NOT EXISTS guardrails (
|
|
|
11
11
|
source TEXT NOT NULL DEFAULT 'manual',
|
|
12
12
|
active INTEGER NOT NULL DEFAULT 1,
|
|
13
13
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
14
|
-
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
15
|
-
UNIQUE(project, source, file_pattern, rule)
|
|
14
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
16
15
|
);
|
|
17
16
|
|
|
18
17
|
CREATE INDEX IF NOT EXISTS idx_guardrails_project ON guardrails(project, active);
|
|
18
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_guardrails_dedup
|
|
19
|
+
ON guardrails(project, COALESCE(file_pattern, ''), rule);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
-- Migration 024: Normalize guardrail de-duplication
|
|
2
|
+
-- Older installs used UNIQUE(project, source, file_pattern, rule). Runtime
|
|
3
|
+
-- installs already moved to project+file_pattern+rule, so rebuild the table
|
|
4
|
+
-- to make fresh and upgraded databases agree.
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS guardrails_new (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
project TEXT NOT NULL,
|
|
9
|
+
file_pattern TEXT NOT NULL DEFAULT '',
|
|
10
|
+
rule TEXT NOT NULL,
|
|
11
|
+
source TEXT NOT NULL DEFAULT 'manual',
|
|
12
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
13
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
14
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
INSERT OR IGNORE INTO guardrails_new (id, project, file_pattern, rule, source, active, created_at, updated_at)
|
|
18
|
+
SELECT
|
|
19
|
+
MIN(g.id) AS id,
|
|
20
|
+
g.project,
|
|
21
|
+
COALESCE(g.file_pattern, '') AS file_pattern,
|
|
22
|
+
g.rule,
|
|
23
|
+
COALESCE((
|
|
24
|
+
SELECT g2.source
|
|
25
|
+
FROM guardrails g2
|
|
26
|
+
WHERE g2.project = g.project
|
|
27
|
+
AND COALESCE(g2.file_pattern, '') = COALESCE(g.file_pattern, '')
|
|
28
|
+
AND g2.rule = g.rule
|
|
29
|
+
ORDER BY
|
|
30
|
+
CASE g2.source WHEN 'manual' THEN 0 ELSE 1 END,
|
|
31
|
+
g2.updated_at DESC,
|
|
32
|
+
g2.id DESC
|
|
33
|
+
LIMIT 1
|
|
34
|
+
), 'manual') AS source,
|
|
35
|
+
MAX(g.active) AS active,
|
|
36
|
+
MIN(g.created_at) AS created_at,
|
|
37
|
+
MAX(g.updated_at) AS updated_at
|
|
38
|
+
FROM guardrails g
|
|
39
|
+
GROUP BY g.project, COALESCE(g.file_pattern, ''), g.rule;
|
|
40
|
+
|
|
41
|
+
DROP TABLE guardrails;
|
|
42
|
+
ALTER TABLE guardrails_new RENAME TO guardrails;
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_guardrails_project ON guardrails(project, active);
|
|
45
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_guardrails_dedup
|
|
46
|
+
ON guardrails(project, COALESCE(file_pattern, ''), rule);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Migration 025: Enforced anti-regression verification state
|
|
2
|
+
-- Hooks record affected features here after edits. Release-boundary commands
|
|
3
|
+
-- are blocked while pending rows remain for the project.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS pending_feature_verifications (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
project TEXT NOT NULL,
|
|
8
|
+
feature_id INTEGER NOT NULL,
|
|
9
|
+
feature_name TEXT NOT NULL,
|
|
10
|
+
file_path TEXT NOT NULL DEFAULT '',
|
|
11
|
+
reason TEXT NOT NULL DEFAULT '',
|
|
12
|
+
source_session_id TEXT,
|
|
13
|
+
trigger_tool TEXT,
|
|
14
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
15
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
16
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
17
|
+
resolved_at TEXT,
|
|
18
|
+
notes TEXT,
|
|
19
|
+
FOREIGN KEY (feature_id) REFERENCES features(id) ON DELETE CASCADE
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_pending_feature_verifications_open
|
|
23
|
+
ON pending_feature_verifications(project, feature_id, file_path)
|
|
24
|
+
WHERE status = 'pending';
|
|
25
|
+
|
|
26
|
+
CREATE INDEX IF NOT EXISTS idx_pending_feature_verifications_project
|
|
27
|
+
ON pending_feature_verifications(project, status, updated_at);
|
|
28
|
+
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_pending_feature_verifications_feature
|
|
30
|
+
ON pending_feature_verifications(feature_id, status);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Migration 026: Multi-agent source attribution
|
|
2
|
+
-- Eagle Mem is shared by Claude Code and Codex. Keep lifecycle source
|
|
3
|
+
-- (startup/resume/clear) separate from the agent that wrote each row.
|
|
4
|
+
|
|
5
|
+
ALTER TABLE sessions ADD COLUMN agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
6
|
+
ALTER TABLE observations ADD COLUMN agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
7
|
+
ALTER TABLE summaries ADD COLUMN agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
8
|
+
|
|
9
|
+
ALTER TABLE claude_memories ADD COLUMN origin_agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
10
|
+
ALTER TABLE claude_plans ADD COLUMN origin_agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
11
|
+
ALTER TABLE claude_tasks ADD COLUMN origin_agent TEXT NOT NULL DEFAULT 'claude-code';
|
|
12
|
+
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_agent ON sessions(agent);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_observations_agent ON observations(agent);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_summaries_agent ON summaries(agent);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_claude_memories_origin_agent ON claude_memories(origin_agent);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_claude_plans_origin_agent ON claude_plans(origin_agent);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_claude_tasks_origin_agent ON claude_tasks(origin_agent);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- Migration 027: Diff-fingerprint feature verification
|
|
2
|
+
-- Verification must attach to the current repository change, not only to a
|
|
3
|
+
-- feature/file pair. This prevents release hooks from reopening already
|
|
4
|
+
-- verified rows when the diff has not changed.
|
|
5
|
+
|
|
6
|
+
ALTER TABLE pending_feature_verifications ADD COLUMN change_fingerprint TEXT NOT NULL DEFAULT '';
|
|
7
|
+
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_pending_feature_verifications_fingerprint
|
|
9
|
+
ON pending_feature_verifications(project, feature_id, file_path, change_fingerprint, status);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
-- Migration 028: Promote mirrored artifact tables from Claude-specific names
|
|
2
|
+
-- to agent-generic names. The original names were correct when Eagle Mem only
|
|
3
|
+
-- mirrored Claude Code artifacts; Codex support made the stored data model
|
|
4
|
+
-- multi-agent. Keep read-only legacy views so older ad-hoc SELECT queries do
|
|
5
|
+
-- not break immediately.
|
|
6
|
+
|
|
7
|
+
DROP TRIGGER IF EXISTS claude_memories_ai;
|
|
8
|
+
DROP TRIGGER IF EXISTS claude_memories_ad;
|
|
9
|
+
DROP TRIGGER IF EXISTS claude_memories_au;
|
|
10
|
+
DROP TRIGGER IF EXISTS claude_plans_ai;
|
|
11
|
+
DROP TRIGGER IF EXISTS claude_plans_ad;
|
|
12
|
+
DROP TRIGGER IF EXISTS claude_plans_au;
|
|
13
|
+
DROP TRIGGER IF EXISTS claude_tasks_ai;
|
|
14
|
+
DROP TRIGGER IF EXISTS claude_tasks_ad;
|
|
15
|
+
DROP TRIGGER IF EXISTS claude_tasks_au;
|
|
16
|
+
|
|
17
|
+
DROP TABLE IF EXISTS claude_memories_fts;
|
|
18
|
+
DROP TABLE IF EXISTS claude_plans_fts;
|
|
19
|
+
DROP TABLE IF EXISTS claude_tasks_fts;
|
|
20
|
+
|
|
21
|
+
ALTER TABLE claude_memories RENAME TO agent_memories;
|
|
22
|
+
ALTER TABLE claude_plans RENAME TO agent_plans;
|
|
23
|
+
ALTER TABLE claude_tasks RENAME TO agent_tasks;
|
|
24
|
+
|
|
25
|
+
DROP INDEX IF EXISTS idx_claude_memories_project;
|
|
26
|
+
DROP INDEX IF EXISTS idx_claude_memories_type;
|
|
27
|
+
DROP INDEX IF EXISTS idx_claude_memories_origin_agent;
|
|
28
|
+
DROP INDEX IF EXISTS idx_claude_plans_project;
|
|
29
|
+
DROP INDEX IF EXISTS idx_claude_plans_origin_agent;
|
|
30
|
+
DROP INDEX IF EXISTS idx_claude_tasks_project;
|
|
31
|
+
DROP INDEX IF EXISTS idx_claude_tasks_session;
|
|
32
|
+
DROP INDEX IF EXISTS idx_claude_tasks_status;
|
|
33
|
+
DROP INDEX IF EXISTS idx_claude_tasks_origin_agent;
|
|
34
|
+
|
|
35
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memories_project ON agent_memories(project);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memories_type ON agent_memories(memory_type);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memories_origin_agent ON agent_memories(origin_agent);
|
|
38
|
+
CREATE INDEX IF NOT EXISTS idx_agent_plans_project ON agent_plans(project);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_agent_plans_origin_agent ON agent_plans(origin_agent);
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_agent_tasks_project ON agent_tasks(project);
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_agent_tasks_session ON agent_tasks(source_session_id);
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_agent_tasks_status ON agent_tasks(status);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_agent_tasks_origin_agent ON agent_tasks(origin_agent);
|
|
44
|
+
|
|
45
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS agent_memories_fts USING fts5(
|
|
46
|
+
memory_name,
|
|
47
|
+
description,
|
|
48
|
+
content,
|
|
49
|
+
content='agent_memories',
|
|
50
|
+
content_rowid='id'
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS agent_plans_fts USING fts5(
|
|
54
|
+
title,
|
|
55
|
+
content,
|
|
56
|
+
content='agent_plans',
|
|
57
|
+
content_rowid='id'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS agent_tasks_fts USING fts5(
|
|
61
|
+
subject,
|
|
62
|
+
description,
|
|
63
|
+
content='agent_tasks',
|
|
64
|
+
content_rowid='id'
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
INSERT INTO agent_memories_fts(agent_memories_fts) VALUES('rebuild');
|
|
68
|
+
INSERT INTO agent_plans_fts(agent_plans_fts) VALUES('rebuild');
|
|
69
|
+
INSERT INTO agent_tasks_fts(agent_tasks_fts) VALUES('rebuild');
|
|
70
|
+
|
|
71
|
+
CREATE TRIGGER IF NOT EXISTS agent_memories_ai AFTER INSERT ON agent_memories BEGIN
|
|
72
|
+
INSERT INTO agent_memories_fts(rowid, memory_name, description, content)
|
|
73
|
+
VALUES (new.id, new.memory_name, new.description, new.content);
|
|
74
|
+
END;
|
|
75
|
+
|
|
76
|
+
CREATE TRIGGER IF NOT EXISTS agent_memories_ad AFTER DELETE ON agent_memories BEGIN
|
|
77
|
+
INSERT INTO agent_memories_fts(agent_memories_fts, rowid, memory_name, description, content)
|
|
78
|
+
VALUES ('delete', old.id, old.memory_name, old.description, old.content);
|
|
79
|
+
END;
|
|
80
|
+
|
|
81
|
+
CREATE TRIGGER IF NOT EXISTS agent_memories_au AFTER UPDATE ON agent_memories BEGIN
|
|
82
|
+
INSERT INTO agent_memories_fts(agent_memories_fts, rowid, memory_name, description, content)
|
|
83
|
+
VALUES ('delete', old.id, old.memory_name, old.description, old.content);
|
|
84
|
+
INSERT INTO agent_memories_fts(rowid, memory_name, description, content)
|
|
85
|
+
VALUES (new.id, new.memory_name, new.description, new.content);
|
|
86
|
+
END;
|
|
87
|
+
|
|
88
|
+
CREATE TRIGGER IF NOT EXISTS agent_plans_ai AFTER INSERT ON agent_plans BEGIN
|
|
89
|
+
INSERT INTO agent_plans_fts(rowid, title, content)
|
|
90
|
+
VALUES (new.id, new.title, new.content);
|
|
91
|
+
END;
|
|
92
|
+
|
|
93
|
+
CREATE TRIGGER IF NOT EXISTS agent_plans_ad AFTER DELETE ON agent_plans BEGIN
|
|
94
|
+
INSERT INTO agent_plans_fts(agent_plans_fts, rowid, title, content)
|
|
95
|
+
VALUES ('delete', old.id, old.title, old.content);
|
|
96
|
+
END;
|
|
97
|
+
|
|
98
|
+
CREATE TRIGGER IF NOT EXISTS agent_plans_au AFTER UPDATE ON agent_plans BEGIN
|
|
99
|
+
INSERT INTO agent_plans_fts(agent_plans_fts, rowid, title, content)
|
|
100
|
+
VALUES ('delete', old.id, old.title, old.content);
|
|
101
|
+
INSERT INTO agent_plans_fts(rowid, title, content)
|
|
102
|
+
VALUES (new.id, new.title, new.content);
|
|
103
|
+
END;
|
|
104
|
+
|
|
105
|
+
CREATE TRIGGER IF NOT EXISTS agent_tasks_ai AFTER INSERT ON agent_tasks BEGIN
|
|
106
|
+
INSERT INTO agent_tasks_fts(rowid, subject, description)
|
|
107
|
+
VALUES (new.id, new.subject, new.description);
|
|
108
|
+
END;
|
|
109
|
+
|
|
110
|
+
CREATE TRIGGER IF NOT EXISTS agent_tasks_ad AFTER DELETE ON agent_tasks BEGIN
|
|
111
|
+
INSERT INTO agent_tasks_fts(agent_tasks_fts, rowid, subject, description)
|
|
112
|
+
VALUES ('delete', old.id, old.subject, old.description);
|
|
113
|
+
END;
|
|
114
|
+
|
|
115
|
+
CREATE TRIGGER IF NOT EXISTS agent_tasks_au AFTER UPDATE ON agent_tasks BEGIN
|
|
116
|
+
INSERT INTO agent_tasks_fts(agent_tasks_fts, rowid, subject, description)
|
|
117
|
+
VALUES ('delete', old.id, old.subject, old.description);
|
|
118
|
+
INSERT INTO agent_tasks_fts(rowid, subject, description)
|
|
119
|
+
VALUES (new.id, new.subject, new.description);
|
|
120
|
+
END;
|
|
121
|
+
|
|
122
|
+
CREATE VIEW IF NOT EXISTS claude_memories AS SELECT * FROM agent_memories;
|
|
123
|
+
CREATE VIEW IF NOT EXISTS claude_plans AS SELECT * FROM agent_plans;
|
|
124
|
+
CREATE VIEW IF NOT EXISTS claude_tasks AS SELECT * FROM agent_tasks;
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# Captures observations + dispatches to extracted responsibilities
|
|
6
6
|
# ═══════════════════════════════════════════════════════════
|
|
7
7
|
set +e
|
|
8
|
+
[ "${EAGLE_MEM_DISABLE_HOOKS:-}" = "1" ] && exit 0
|
|
8
9
|
|
|
9
10
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
11
|
LIB_DIR="$SCRIPT_DIR/../lib"
|
|
@@ -19,6 +20,7 @@ input=$(eagle_read_stdin)
|
|
|
19
20
|
session_id=$(echo "$input" | jq -r '.session_id // empty')
|
|
20
21
|
cwd=$(echo "$input" | jq -r '.cwd // empty')
|
|
21
22
|
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
|
|
23
|
+
agent=$(eagle_agent_source_from_json "$input")
|
|
22
24
|
|
|
23
25
|
hook_event=$(echo "$input" | jq -r '.hook_event_name // empty')
|
|
24
26
|
|
|
@@ -30,7 +32,7 @@ case "$hook_event" in
|
|
|
30
32
|
[ ! -f "$EAGLE_MEM_DB" ] && exit 0
|
|
31
33
|
project=$(eagle_project_from_cwd "$cwd")
|
|
32
34
|
[ -z "$project" ] && exit 0
|
|
33
|
-
eagle_upsert_session "$session_id" "$project" "$cwd" "" ""
|
|
35
|
+
eagle_upsert_session "$session_id" "$project" "$cwd" "" "" "$agent"
|
|
34
36
|
|
|
35
37
|
task_id=$(echo "$input" | jq -r '.task_id // empty')
|
|
36
38
|
task_subject=$(echo "$input" | jq -r '.task_subject // empty')
|
|
@@ -50,14 +52,16 @@ case "$hook_event" in
|
|
|
50
52
|
subj_sql=$(eagle_sql_escape "$task_subject")
|
|
51
53
|
desc_sql=$(eagle_sql_escape "$task_desc")
|
|
52
54
|
stat_sql=$(eagle_sql_escape "$local_status")
|
|
55
|
+
agent_sql=$(eagle_sql_escape "$agent")
|
|
53
56
|
|
|
54
57
|
eagle_db_pipe <<SQL
|
|
55
|
-
INSERT INTO
|
|
56
|
-
VALUES ('$proj_sql', '$sid_sql', '$tid_sql', '$fp_sql', '$subj_sql', '$desc_sql', '$stat_sql')
|
|
58
|
+
INSERT INTO agent_tasks (project, source_session_id, source_task_id, file_path, subject, description, status, origin_agent)
|
|
59
|
+
VALUES ('$proj_sql', '$sid_sql', '$tid_sql', '$fp_sql', '$subj_sql', '$desc_sql', '$stat_sql', '$agent_sql')
|
|
57
60
|
ON CONFLICT(file_path) DO UPDATE SET
|
|
58
61
|
subject = excluded.subject,
|
|
59
62
|
description = excluded.description,
|
|
60
63
|
status = excluded.status,
|
|
64
|
+
origin_agent = excluded.origin_agent,
|
|
61
65
|
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now');
|
|
62
66
|
SQL
|
|
63
67
|
fi
|
|
@@ -69,8 +73,8 @@ esac
|
|
|
69
73
|
|
|
70
74
|
# Only track relevant tools
|
|
71
75
|
case "$tool_name" in
|
|
72
|
-
Read|Write|Edit|
|
|
73
|
-
*) exit 0 ;;
|
|
76
|
+
Read|Write|Edit|TaskCreate|TaskUpdate|apply_patch) ;;
|
|
77
|
+
*) eagle_is_shell_tool "$tool_name" || exit 0 ;;
|
|
74
78
|
esac
|
|
75
79
|
|
|
76
80
|
[ ! -f "$EAGLE_MEM_DB" ] && exit 0
|
|
@@ -80,7 +84,7 @@ project=$(eagle_project_from_cwd "$cwd")
|
|
|
80
84
|
|
|
81
85
|
# Ensure session row exists before inserting observations (FK constraint).
|
|
82
86
|
# PostToolUse can race SessionStart — the session row might not exist yet.
|
|
83
|
-
eagle_upsert_session "$session_id" "$project" "$cwd" "" ""
|
|
87
|
+
eagle_upsert_session "$session_id" "$project" "$cwd" "" "" "$agent"
|
|
84
88
|
|
|
85
89
|
# ─── Extract observation data from tool call ──────────────
|
|
86
90
|
|
|
@@ -108,10 +112,22 @@ case "$tool_name" in
|
|
|
108
112
|
[ -n "$fp" ] && files_modified=$(printf '%s' "$fp" | jq -Rsc '[.]')
|
|
109
113
|
tool_summary="Edit $fp"
|
|
110
114
|
;;
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
apply_patch)
|
|
116
|
+
patch_cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
|
|
117
|
+
patch_files=$(printf '%s\n' "$patch_cmd" | eagle_extract_apply_patch_files)
|
|
118
|
+
if [ -n "$patch_files" ]; then
|
|
119
|
+
fp=$(printf '%s\n' "$patch_files" | head -1)
|
|
120
|
+
files_modified=$(printf '%s\n' "$patch_files" | jq -Rsc 'split("\n") | map(select(. != ""))')
|
|
121
|
+
patch_count=$(printf '%s\n' "$patch_files" | sed '/^[[:space:]]*$/d' | wc -l | tr -d ' ')
|
|
122
|
+
tool_summary="apply_patch: ${patch_count} file(s)"
|
|
123
|
+
else
|
|
124
|
+
tool_summary="apply_patch"
|
|
125
|
+
fi
|
|
126
|
+
;;
|
|
127
|
+
Bash|exec_command|shell_command|unified_exec)
|
|
128
|
+
cmd=$(eagle_tool_command_from_json "$input" | cut -c1-200)
|
|
113
129
|
cmd=$(echo "$cmd" | eagle_redact)
|
|
114
|
-
tool_summary="
|
|
130
|
+
tool_summary="${tool_name}: $cmd"
|
|
115
131
|
|
|
116
132
|
tool_output=$(echo "$input" | jq -r '.tool_response.stdout // empty' 2>/dev/null)
|
|
117
133
|
if [ -n "$tool_output" ]; then
|
|
@@ -147,7 +163,7 @@ esac
|
|
|
147
163
|
|
|
148
164
|
if [ -n "$fp" ] && [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
|
|
149
165
|
case "$tool_name" in
|
|
150
|
-
Edit|Write)
|
|
166
|
+
Edit|Write|apply_patch)
|
|
151
167
|
mod_dir="$EAGLE_MEM_DIR/mod-tracker"
|
|
152
168
|
mkdir -p "$mod_dir" 2>/dev/null
|
|
153
169
|
mod_file="$mod_dir/${session_id}"
|
|
@@ -167,16 +183,29 @@ if [ -n "$fp" ] && [ -n "$session_id" ] && eagle_validate_session_id "$session_i
|
|
|
167
183
|
esac
|
|
168
184
|
fi
|
|
169
185
|
|
|
186
|
+
# ─── Enforced anti-regression: mark affected features pending ──
|
|
187
|
+
|
|
188
|
+
case "$tool_name" in
|
|
189
|
+
Edit|Write|apply_patch)
|
|
190
|
+
if [ -n "$files_modified" ] && [ "$files_modified" != "[]" ]; then
|
|
191
|
+
while IFS= read -r mod_file; do
|
|
192
|
+
[ -z "$mod_file" ] && continue
|
|
193
|
+
eagle_record_current_feature_verifications_for_file "$project" "$cwd" "$mod_file" "$session_id" "$tool_name" "File changed by ${tool_name}" >/dev/null
|
|
194
|
+
done < <(echo "$files_modified" | jq -r '.[]?' 2>/dev/null)
|
|
195
|
+
fi
|
|
196
|
+
;;
|
|
197
|
+
esac
|
|
198
|
+
|
|
170
199
|
# ─── Dispatch to extracted responsibilities ───────────────
|
|
171
200
|
|
|
172
|
-
eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project"
|
|
173
|
-
eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input"
|
|
201
|
+
eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project" "$agent"
|
|
202
|
+
eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input" "$agent"
|
|
174
203
|
eagle_posttool_stale_hint "$tool_name" "$fp" "$project"
|
|
175
204
|
eagle_posttool_decision_surface "$tool_name" "$fp" "$project"
|
|
176
205
|
|
|
177
206
|
# ─── Record observation ──────────────────────────────────
|
|
178
207
|
|
|
179
|
-
if ! eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified" "$output_bytes" "$output_lines" "$command_category"; then
|
|
208
|
+
if ! eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified" "$output_bytes" "$output_lines" "$command_category" "$agent"; then
|
|
180
209
|
eagle_log "ERROR" "PostToolUse: observation insert failed for session=$session_id tool=$tool_name"
|
|
181
210
|
fi
|
|
182
211
|
|