eagle-mem 1.1.0 → 1.3.0
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/bin/eagle-mem +2 -0
- package/db/004_observation_indexes.sql +9 -0
- package/db/005_claude_memories.sql +49 -0
- package/db/006_claude_plans.sql +45 -0
- package/db/007_claude_tasks.sql +50 -0
- package/db/migrate.sh +12 -0
- package/db/schema.sql +2 -0
- package/hooks/post-tool-use.sh +50 -6
- package/hooks/session-start.sh +6 -29
- package/hooks/stop.sh +3 -5
- package/hooks/user-prompt-submit.sh +4 -19
- package/lib/common.sh +13 -0
- package/lib/db.sh +349 -9
- package/package.json +1 -1
- package/scripts/help.sh +8 -0
- package/scripts/install.sh +7 -16
- package/scripts/memories.sh +575 -0
- package/scripts/overview.sh +17 -3
- package/scripts/prune.sh +154 -0
- package/scripts/search.sh +14 -5
- package/scripts/tasks.sh +67 -16
- package/scripts/uninstall.sh +5 -5
- package/scripts/update.sh +11 -6
package/bin/eagle-mem
CHANGED
|
@@ -24,6 +24,8 @@ 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
|
+
prune) bash "$SCRIPTS_DIR/prune.sh" "$@" ;;
|
|
28
|
+
memories) bash "$SCRIPTS_DIR/memories.sh" "$@" ;;
|
|
27
29
|
help|--help|-h)
|
|
28
30
|
bash "$SCRIPTS_DIR/help.sh" ;;
|
|
29
31
|
version|--version|-v|-V)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Eagle Mem — Migration 004: Observation indexes
|
|
3
|
+
-- Adds created_at index for efficient pruning and time-bound queries
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_observations_created_at ON observations(created_at);
|
|
9
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_ended_at ON sessions(status, ended_at);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Eagle Mem — Migration 005: Claude Code memory mirror
|
|
3
|
+
-- Captures Claude Code auto-memory writes into Eagle Mem
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS claude_memories (
|
|
9
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
10
|
+
project TEXT NOT NULL,
|
|
11
|
+
file_path TEXT NOT NULL UNIQUE,
|
|
12
|
+
memory_name TEXT,
|
|
13
|
+
description TEXT,
|
|
14
|
+
memory_type TEXT,
|
|
15
|
+
content TEXT,
|
|
16
|
+
content_hash TEXT,
|
|
17
|
+
origin_session_id TEXT,
|
|
18
|
+
captured_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
19
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_claude_memories_project ON claude_memories(project);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_claude_memories_type ON claude_memories(memory_type);
|
|
24
|
+
|
|
25
|
+
-- FTS5 for searching across memory content
|
|
26
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS claude_memories_fts USING fts5(
|
|
27
|
+
memory_name,
|
|
28
|
+
description,
|
|
29
|
+
content,
|
|
30
|
+
content='claude_memories',
|
|
31
|
+
content_rowid='id'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
CREATE TRIGGER IF NOT EXISTS claude_memories_ai AFTER INSERT ON claude_memories BEGIN
|
|
35
|
+
INSERT INTO claude_memories_fts(rowid, memory_name, description, content)
|
|
36
|
+
VALUES (new.id, new.memory_name, new.description, new.content);
|
|
37
|
+
END;
|
|
38
|
+
|
|
39
|
+
CREATE TRIGGER IF NOT EXISTS claude_memories_ad AFTER DELETE ON claude_memories BEGIN
|
|
40
|
+
INSERT INTO claude_memories_fts(claude_memories_fts, rowid, memory_name, description, content)
|
|
41
|
+
VALUES ('delete', old.id, old.memory_name, old.description, old.content);
|
|
42
|
+
END;
|
|
43
|
+
|
|
44
|
+
CREATE TRIGGER IF NOT EXISTS claude_memories_au AFTER UPDATE ON claude_memories BEGIN
|
|
45
|
+
INSERT INTO claude_memories_fts(claude_memories_fts, rowid, memory_name, description, content)
|
|
46
|
+
VALUES ('delete', old.id, old.memory_name, old.description, old.content);
|
|
47
|
+
INSERT INTO claude_memories_fts(rowid, memory_name, description, content)
|
|
48
|
+
VALUES (new.id, new.memory_name, new.description, new.content);
|
|
49
|
+
END;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Eagle Mem — Migration 006: Claude Code plan mirror
|
|
3
|
+
-- Captures Claude Code plan documents into Eagle Mem
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
PRAGMA foreign_keys = ON;
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS claude_plans (
|
|
9
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
10
|
+
project TEXT NOT NULL DEFAULT '',
|
|
11
|
+
file_path TEXT NOT NULL UNIQUE,
|
|
12
|
+
title TEXT,
|
|
13
|
+
content TEXT,
|
|
14
|
+
content_hash TEXT,
|
|
15
|
+
origin_session_id TEXT,
|
|
16
|
+
captured_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
17
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_claude_plans_project ON claude_plans(project);
|
|
21
|
+
|
|
22
|
+
-- FTS5 for searching across plan content
|
|
23
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS claude_plans_fts USING fts5(
|
|
24
|
+
title,
|
|
25
|
+
content,
|
|
26
|
+
content='claude_plans',
|
|
27
|
+
content_rowid='id'
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
CREATE TRIGGER IF NOT EXISTS claude_plans_ai AFTER INSERT ON claude_plans BEGIN
|
|
31
|
+
INSERT INTO claude_plans_fts(rowid, title, content)
|
|
32
|
+
VALUES (new.id, new.title, new.content);
|
|
33
|
+
END;
|
|
34
|
+
|
|
35
|
+
CREATE TRIGGER IF NOT EXISTS claude_plans_ad AFTER DELETE ON claude_plans BEGIN
|
|
36
|
+
INSERT INTO claude_plans_fts(claude_plans_fts, rowid, title, content)
|
|
37
|
+
VALUES ('delete', old.id, old.title, old.content);
|
|
38
|
+
END;
|
|
39
|
+
|
|
40
|
+
CREATE TRIGGER IF NOT EXISTS claude_plans_au AFTER UPDATE ON claude_plans BEGIN
|
|
41
|
+
INSERT INTO claude_plans_fts(claude_plans_fts, rowid, title, content)
|
|
42
|
+
VALUES ('delete', old.id, old.title, old.content);
|
|
43
|
+
INSERT INTO claude_plans_fts(rowid, title, content)
|
|
44
|
+
VALUES (new.id, new.title, new.content);
|
|
45
|
+
END;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
-- ═══════════════════════════════════════════════════════════
|
|
2
|
+
-- Migration 007: Claude Code task mirror
|
|
3
|
+
-- Mirrors TaskCreate/TaskUpdate artifacts from ~/.claude/tasks/
|
|
4
|
+
-- ═══════════════════════════════════════════════════════════
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS claude_tasks (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
project TEXT NOT NULL DEFAULT '',
|
|
9
|
+
source_session_id TEXT NOT NULL,
|
|
10
|
+
source_task_id TEXT NOT NULL,
|
|
11
|
+
file_path TEXT UNIQUE,
|
|
12
|
+
subject TEXT,
|
|
13
|
+
description TEXT,
|
|
14
|
+
active_form TEXT,
|
|
15
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
16
|
+
blocks TEXT DEFAULT '[]',
|
|
17
|
+
blocked_by TEXT DEFAULT '[]',
|
|
18
|
+
content_hash TEXT,
|
|
19
|
+
captured_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
20
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_claude_tasks_project ON claude_tasks(project);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_claude_tasks_session ON claude_tasks(source_session_id);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_claude_tasks_status ON claude_tasks(status);
|
|
26
|
+
|
|
27
|
+
-- FTS5 for full-text search on subject + description
|
|
28
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS claude_tasks_fts USING fts5(
|
|
29
|
+
subject,
|
|
30
|
+
description,
|
|
31
|
+
content='claude_tasks',
|
|
32
|
+
content_rowid='id'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
CREATE TRIGGER IF NOT EXISTS claude_tasks_ai AFTER INSERT ON claude_tasks BEGIN
|
|
36
|
+
INSERT INTO claude_tasks_fts(rowid, subject, description)
|
|
37
|
+
VALUES (new.id, new.subject, new.description);
|
|
38
|
+
END;
|
|
39
|
+
|
|
40
|
+
CREATE TRIGGER IF NOT EXISTS claude_tasks_ad AFTER DELETE ON claude_tasks BEGIN
|
|
41
|
+
INSERT INTO claude_tasks_fts(claude_tasks_fts, rowid, subject, description)
|
|
42
|
+
VALUES ('delete', old.id, old.subject, old.description);
|
|
43
|
+
END;
|
|
44
|
+
|
|
45
|
+
CREATE TRIGGER IF NOT EXISTS claude_tasks_au AFTER UPDATE ON claude_tasks BEGIN
|
|
46
|
+
INSERT INTO claude_tasks_fts(claude_tasks_fts, rowid, subject, description)
|
|
47
|
+
VALUES ('delete', old.id, old.subject, old.description);
|
|
48
|
+
INSERT INTO claude_tasks_fts(rowid, subject, description)
|
|
49
|
+
VALUES (new.id, new.subject, new.description);
|
|
50
|
+
END;
|
package/db/migrate.sh
CHANGED
|
@@ -44,4 +44,16 @@ run_migration "002_overviews" "$SCRIPT_DIR/002_overviews.sql"
|
|
|
44
44
|
# ─── Migration 003: Code chunks ───────────────────────────
|
|
45
45
|
run_migration "003_code_chunks" "$SCRIPT_DIR/003_code_chunks.sql"
|
|
46
46
|
|
|
47
|
+
# ─── Migration 004: Observation indexes ──────────────────
|
|
48
|
+
run_migration "004_observation_indexes" "$SCRIPT_DIR/004_observation_indexes.sql"
|
|
49
|
+
|
|
50
|
+
# ─── Migration 005: Claude Code memory mirror ────────────
|
|
51
|
+
run_migration "005_claude_memories" "$SCRIPT_DIR/005_claude_memories.sql"
|
|
52
|
+
|
|
53
|
+
# ─── Migration 006: Claude Code plan mirror ──────────────
|
|
54
|
+
run_migration "006_claude_plans" "$SCRIPT_DIR/006_claude_plans.sql"
|
|
55
|
+
|
|
56
|
+
# ─── Migration 007: Claude Code task mirror ──────────────
|
|
57
|
+
run_migration "007_claude_tasks" "$SCRIPT_DIR/007_claude_tasks.sql"
|
|
58
|
+
|
|
47
59
|
echo " Eagle Mem database ready: $DB"
|
package/db/schema.sql
CHANGED
|
@@ -20,6 +20,8 @@ CREATE TABLE IF NOT EXISTS _migrations (
|
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
-- ─── Sessions ──────────────────────────────────────────────
|
|
23
|
+
-- Sessions are parent rows for summaries, tasks, and observations (FK).
|
|
24
|
+
-- Never delete sessions — prune children instead.
|
|
23
25
|
|
|
24
26
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
25
27
|
id TEXT PRIMARY KEY,
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -19,11 +19,11 @@ session_id=$(echo "$input" | jq -r '.session_id // empty')
|
|
|
19
19
|
cwd=$(echo "$input" | jq -r '.cwd // empty')
|
|
20
20
|
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
|
|
21
21
|
|
|
22
|
-
[ -z "$session_id" ] || [ -z "$tool_name" ]
|
|
22
|
+
if [ -z "$session_id" ] || [ -z "$tool_name" ]; then exit 0; fi
|
|
23
23
|
|
|
24
|
-
# Only track
|
|
24
|
+
# Only track relevant tools
|
|
25
25
|
case "$tool_name" in
|
|
26
|
-
Read|Write|Edit|Bash) ;;
|
|
26
|
+
Read|Write|Edit|Bash|TaskCreate|TaskUpdate) ;;
|
|
27
27
|
*) exit 0 ;;
|
|
28
28
|
esac
|
|
29
29
|
|
|
@@ -38,17 +38,17 @@ tool_summary=""
|
|
|
38
38
|
case "$tool_name" in
|
|
39
39
|
Read)
|
|
40
40
|
fp=$(echo "$input" | jq -r '.tool_input.file_path // empty')
|
|
41
|
-
[ -n "$fp" ] && files_read
|
|
41
|
+
[ -n "$fp" ] && files_read=$(printf '%s' "$fp" | jq -Rsc '[.]')
|
|
42
42
|
tool_summary="Read $fp"
|
|
43
43
|
;;
|
|
44
44
|
Write)
|
|
45
45
|
fp=$(echo "$input" | jq -r '.tool_input.file_path // empty')
|
|
46
|
-
[ -n "$fp" ] && files_modified
|
|
46
|
+
[ -n "$fp" ] && files_modified=$(printf '%s' "$fp" | jq -Rsc '[.]')
|
|
47
47
|
tool_summary="Write $fp"
|
|
48
48
|
;;
|
|
49
49
|
Edit)
|
|
50
50
|
fp=$(echo "$input" | jq -r '.tool_input.file_path // empty')
|
|
51
|
-
[ -n "$fp" ] && files_modified
|
|
51
|
+
[ -n "$fp" ] && files_modified=$(printf '%s' "$fp" | jq -Rsc '[.]')
|
|
52
52
|
tool_summary="Edit $fp"
|
|
53
53
|
;;
|
|
54
54
|
Bash)
|
|
@@ -63,6 +63,50 @@ case "$tool_name" in
|
|
|
63
63
|
-e 's/(Authorization: )[^ ]*/\1[REDACTED]/gi')
|
|
64
64
|
tool_summary="Bash: $cmd"
|
|
65
65
|
;;
|
|
66
|
+
TaskCreate|TaskUpdate)
|
|
67
|
+
task_subject=$(echo "$input" | jq -r '.tool_input.subject // empty')
|
|
68
|
+
tool_summary="$tool_name: $task_subject"
|
|
69
|
+
;;
|
|
70
|
+
esac
|
|
71
|
+
|
|
72
|
+
# ─── Claude memory + plan mirror ─────────────────────────
|
|
73
|
+
# Intercept writes to Claude Code's auto-memory and plan files
|
|
74
|
+
case "$tool_name" in
|
|
75
|
+
Write|Edit)
|
|
76
|
+
if [ -n "$fp" ]; then
|
|
77
|
+
case "$fp" in
|
|
78
|
+
"$HOME/.claude/projects"/*/memory/*.md)
|
|
79
|
+
mem_base=$(basename "$fp")
|
|
80
|
+
if [ "$mem_base" != "MEMORY.md" ] && [ -f "$fp" ]; then
|
|
81
|
+
eagle_capture_claude_memory "$fp" "$session_id" "$project"
|
|
82
|
+
fi
|
|
83
|
+
;;
|
|
84
|
+
"$HOME/.claude/plans/"*.md)
|
|
85
|
+
if [ -f "$fp" ]; then
|
|
86
|
+
eagle_capture_claude_plan "$fp" "$session_id" "$project"
|
|
87
|
+
fi
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
fi
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
|
|
94
|
+
# ─── Claude task mirror ─────────────────────────────────
|
|
95
|
+
# Intercept TaskCreate/TaskUpdate and capture the resulting JSON files
|
|
96
|
+
case "$tool_name" in
|
|
97
|
+
TaskCreate|TaskUpdate)
|
|
98
|
+
task_dir="$HOME/.claude/tasks/$session_id"
|
|
99
|
+
if [ -d "$task_dir" ]; then
|
|
100
|
+
task_id=$(echo "$input" | jq -r '.tool_input.id // empty')
|
|
101
|
+
if [ -z "$task_id" ]; then
|
|
102
|
+
newest=$(ls -t "$task_dir"/*.json 2>/dev/null | head -1)
|
|
103
|
+
[ -n "$newest" ] && [ -f "$newest" ] && eagle_capture_claude_task "$newest" "$session_id" "$project"
|
|
104
|
+
else
|
|
105
|
+
task_json="$task_dir/$task_id.json"
|
|
106
|
+
[ -f "$task_json" ] && eagle_capture_claude_task "$task_json" "$session_id" "$project"
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
;;
|
|
66
110
|
esac
|
|
67
111
|
|
|
68
112
|
# Deduplicate: skip if exact same observation within last 5 seconds
|
package/hooks/session-start.sh
CHANGED
|
@@ -25,7 +25,6 @@ model=$(echo "$input" | jq -r '.model // empty')
|
|
|
25
25
|
[ -z "$session_id" ] && exit 0
|
|
26
26
|
|
|
27
27
|
project=$(eagle_project_from_cwd "$cwd")
|
|
28
|
-
project_sql=$(eagle_sql_escape "$project")
|
|
29
28
|
|
|
30
29
|
eagle_log "INFO" "SessionStart: session=$session_id project=$project source=$source_type"
|
|
31
30
|
|
|
@@ -48,13 +47,7 @@ $overview
|
|
|
48
47
|
fi
|
|
49
48
|
|
|
50
49
|
# Recent summaries for this project (last 5 sessions)
|
|
51
|
-
recent=$(
|
|
52
|
-
SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
53
|
-
FROM summaries s
|
|
54
|
-
WHERE s.project = '$project_sql'
|
|
55
|
-
ORDER BY s.created_at DESC
|
|
56
|
-
LIMIT 5;
|
|
57
|
-
")
|
|
50
|
+
recent=$(eagle_get_recent_summaries "$project" 5)
|
|
58
51
|
|
|
59
52
|
if [ -n "$recent" ]; then
|
|
60
53
|
context+="=== EAGLE MEM ===
|
|
@@ -78,13 +71,7 @@ Next steps: $next_steps"
|
|
|
78
71
|
fi
|
|
79
72
|
|
|
80
73
|
# Pending tasks from TaskAware loop
|
|
81
|
-
pending_tasks=$(
|
|
82
|
-
SELECT id, title, instructions, status
|
|
83
|
-
FROM tasks
|
|
84
|
-
WHERE project = '$project_sql' AND status IN ('pending', 'active')
|
|
85
|
-
ORDER BY ordinal ASC, id ASC
|
|
86
|
-
LIMIT 10;
|
|
87
|
-
")
|
|
74
|
+
pending_tasks=$(eagle_get_pending_tasks "$project")
|
|
88
75
|
|
|
89
76
|
if [ -n "$pending_tasks" ]; then
|
|
90
77
|
context+="
|
|
@@ -92,7 +79,7 @@ if [ -n "$pending_tasks" ]; then
|
|
|
92
79
|
Pending tasks for '$project':
|
|
93
80
|
"
|
|
94
81
|
first_pending=""
|
|
95
|
-
while IFS='|' read -r tid title instructions status; do
|
|
82
|
+
while IFS='|' read -r tid title instructions status _ordinal; do
|
|
96
83
|
[ -z "$tid" ] && continue
|
|
97
84
|
local_marker=""
|
|
98
85
|
if [ "$status" = "active" ]; then
|
|
@@ -108,22 +95,12 @@ Pending tasks for '$project':
|
|
|
108
95
|
done <<< "$pending_tasks"
|
|
109
96
|
|
|
110
97
|
# Load context snapshot for the active/next task
|
|
111
|
-
active_task=$(
|
|
112
|
-
SELECT id, title, instructions, context_snapshot
|
|
113
|
-
FROM tasks
|
|
114
|
-
WHERE project = '$project_sql' AND status = 'active'
|
|
115
|
-
ORDER BY ordinal ASC, id ASC
|
|
116
|
-
LIMIT 1;
|
|
117
|
-
")
|
|
98
|
+
active_task=$(eagle_get_active_task "$project")
|
|
118
99
|
|
|
119
100
|
if [ -z "$active_task" ] && [ -n "$first_pending" ]; then
|
|
120
101
|
# Auto-activate the next pending task
|
|
121
|
-
|
|
122
|
-
active_task=$(
|
|
123
|
-
SELECT id, title, instructions, context_snapshot
|
|
124
|
-
FROM tasks
|
|
125
|
-
WHERE id = $first_pending;
|
|
126
|
-
")
|
|
102
|
+
eagle_activate_task "$first_pending"
|
|
103
|
+
active_task=$(eagle_get_active_task "$project")
|
|
127
104
|
fi
|
|
128
105
|
|
|
129
106
|
if [ -n "$active_task" ]; then
|
package/hooks/stop.sh
CHANGED
|
@@ -29,7 +29,6 @@ agent_type=$(echo "$input" | jq -r '.agent_type // empty')
|
|
|
29
29
|
[ -n "$agent_type" ] && [ "$agent_type" != "main" ] && exit 0
|
|
30
30
|
|
|
31
31
|
project=$(eagle_project_from_cwd "$cwd")
|
|
32
|
-
project_sql=$(eagle_sql_escape "$project")
|
|
33
32
|
|
|
34
33
|
eagle_log "INFO" "Stop: session=$session_id project=$project transcript=$transcript_path"
|
|
35
34
|
|
|
@@ -137,10 +136,9 @@ fi
|
|
|
137
136
|
|
|
138
137
|
# Mark active task as done if eagle-summary mentions completion
|
|
139
138
|
if [ -n "$completed" ]; then
|
|
140
|
-
|
|
141
|
-
if [ -n "$
|
|
142
|
-
|
|
143
|
-
eagle_log "INFO" "Stop: marked task #$active_task_id as done"
|
|
139
|
+
completed_task_id=$(eagle_complete_active_task "$project")
|
|
140
|
+
if [ -n "$completed_task_id" ]; then
|
|
141
|
+
eagle_log "INFO" "Stop: marked task #$completed_task_id as done"
|
|
144
142
|
fi
|
|
145
143
|
fi
|
|
146
144
|
|
|
@@ -24,7 +24,6 @@ user_prompt=$(echo "$input" | jq -r '.prompt // empty')
|
|
|
24
24
|
[ -z "$user_prompt" ] && exit 0
|
|
25
25
|
|
|
26
26
|
project=$(eagle_project_from_cwd "$cwd")
|
|
27
|
-
project_sql=$(eagle_sql_escape "$project")
|
|
28
27
|
|
|
29
28
|
# Skip short prompts — not enough signal for meaningful search
|
|
30
29
|
word_count=$(echo "$user_prompt" | wc -w | tr -d ' ')
|
|
@@ -45,23 +44,15 @@ fts_query=$(echo "$user_prompt" | tr -cs '[:alnum:]' ' ' | tr '[:upper:]' '[:low
|
|
|
45
44
|
|
|
46
45
|
[ -z "$fts_query" ] && exit 0
|
|
47
46
|
|
|
48
|
-
fts_query_escaped=$(eagle_sql_escape "$fts_query")
|
|
49
|
-
|
|
50
47
|
# Search for relevant past summaries (cross-session)
|
|
51
|
-
results=$(
|
|
52
|
-
FROM summaries s
|
|
53
|
-
JOIN summaries_fts f ON f.rowid = s.id
|
|
54
|
-
WHERE summaries_fts MATCH '$fts_query_escaped'
|
|
55
|
-
AND s.project = '$project_sql'
|
|
56
|
-
ORDER BY rank
|
|
57
|
-
LIMIT 3;")
|
|
48
|
+
results=$(eagle_search_summaries "$fts_query" "$project" 3)
|
|
58
49
|
|
|
59
50
|
context=""
|
|
60
51
|
|
|
61
52
|
if [ -n "$results" ]; then
|
|
62
53
|
context+="=== EAGLE MEM — Relevant Memory ===
|
|
63
54
|
"
|
|
64
|
-
while IFS='|' read -r req learned
|
|
55
|
+
while IFS='|' read -r req completed learned _next_steps created_at _proj; do
|
|
65
56
|
[ -z "$req" ] && [ -z "$completed" ] && continue
|
|
66
57
|
context+="[$created_at] "
|
|
67
58
|
[ -n "$req" ] && context+="$req"
|
|
@@ -73,15 +64,9 @@ if [ -n "$results" ]; then
|
|
|
73
64
|
fi
|
|
74
65
|
|
|
75
66
|
# Search indexed code chunks (if any exist for this project)
|
|
76
|
-
has_chunks=$(
|
|
67
|
+
has_chunks=$(eagle_count_code_chunks "$project")
|
|
77
68
|
if [ "${has_chunks:-0}" -gt 0 ]; then
|
|
78
|
-
code_results=$(
|
|
79
|
-
FROM code_chunks c
|
|
80
|
-
JOIN code_chunks_fts f ON f.rowid = c.id
|
|
81
|
-
WHERE code_chunks_fts MATCH '$fts_query_escaped'
|
|
82
|
-
AND c.project = '$project_sql'
|
|
83
|
-
ORDER BY rank
|
|
84
|
-
LIMIT 5;")
|
|
69
|
+
code_results=$(eagle_search_code_chunks "$fts_query" "$project" 5)
|
|
85
70
|
|
|
86
71
|
if [ -n "$code_results" ]; then
|
|
87
72
|
context+="=== EAGLE MEM — Relevant Code ===
|
package/lib/common.sh
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
EAGLE_MEM_DIR="${EAGLE_MEM_DIR:-$HOME/.eagle-mem}"
|
|
8
8
|
EAGLE_MEM_DB="$EAGLE_MEM_DIR/memory.db"
|
|
9
9
|
EAGLE_MEM_LOG="$EAGLE_MEM_DIR/eagle-mem.log"
|
|
10
|
+
EAGLE_SETTINGS="${EAGLE_SETTINGS:-$HOME/.claude/settings.json}"
|
|
11
|
+
EAGLE_SKILLS_DIR="$HOME/.claude/skills"
|
|
10
12
|
|
|
11
13
|
eagle_log() {
|
|
12
14
|
local level="$1"
|
|
@@ -23,6 +25,17 @@ eagle_sql_escape() {
|
|
|
23
25
|
printf '%s' "$1" | sed "s/'/''/g"
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
eagle_sql_int() {
|
|
29
|
+
case "$1" in
|
|
30
|
+
''|*[!0-9]*) echo "0" ;;
|
|
31
|
+
*) printf '%s' "$1" ;;
|
|
32
|
+
esac
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
eagle_fts_sanitize() {
|
|
36
|
+
printf '%s' "$1" | sed 's/[*"(){}^~:]/ /g' | sed 's/ */ /g; s/^ //; s/ $//'
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
eagle_read_stdin() {
|
|
27
40
|
local input=""
|
|
28
41
|
if [ ! -t 0 ]; then
|