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/lib/db.sh
CHANGED
|
@@ -34,7 +34,7 @@ eagle_ensure_db() {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
eagle_upsert_session() {
|
|
37
|
-
local session_id
|
|
37
|
+
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
38
38
|
local project; project=$(eagle_sql_escape "$2")
|
|
39
39
|
local cwd; cwd=$(eagle_sql_escape "${3:-}")
|
|
40
40
|
local model; model=$(eagle_sql_escape "${4:-}")
|
|
@@ -49,17 +49,17 @@ eagle_upsert_session() {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
eagle_end_session() {
|
|
52
|
-
local session_id
|
|
52
|
+
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
53
53
|
eagle_db "UPDATE sessions SET status = 'completed', ended_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = '$session_id';"
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
eagle_insert_observation() {
|
|
57
|
-
local session_id
|
|
57
|
+
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
58
58
|
local project; project=$(eagle_sql_escape "$2")
|
|
59
59
|
local tool_name; tool_name=$(eagle_sql_escape "$3")
|
|
60
60
|
local tool_input_summary; tool_input_summary=$(eagle_sql_escape "$4")
|
|
61
|
-
local files_read
|
|
62
|
-
local files_modified
|
|
61
|
+
local files_read; files_read=$(eagle_sql_escape "$5")
|
|
62
|
+
local files_modified; files_modified=$(eagle_sql_escape "$6")
|
|
63
63
|
|
|
64
64
|
eagle_db "INSERT INTO observations (session_id, project, tool_name, tool_input_summary, files_read, files_modified)
|
|
65
65
|
VALUES ('$session_id', '$project', '$tool_name', '$tool_input_summary', '$files_read', '$files_modified');"
|
|
@@ -96,7 +96,7 @@ SQL
|
|
|
96
96
|
|
|
97
97
|
eagle_get_recent_summaries() {
|
|
98
98
|
local project; project=$(eagle_sql_escape "$1")
|
|
99
|
-
local limit
|
|
99
|
+
local limit; limit=$(eagle_sql_int "${2:-5}")
|
|
100
100
|
|
|
101
101
|
eagle_db "SELECT s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
102
102
|
FROM summaries s
|
|
@@ -108,7 +108,7 @@ eagle_get_recent_summaries() {
|
|
|
108
108
|
eagle_search_summaries() {
|
|
109
109
|
local query; query=$(eagle_sql_escape "$1")
|
|
110
110
|
local project="${2:-}"
|
|
111
|
-
local limit
|
|
111
|
+
local limit; limit=$(eagle_sql_int "${3:-10}")
|
|
112
112
|
|
|
113
113
|
local where_clause=""
|
|
114
114
|
if [ -n "$project" ]; then
|
|
@@ -146,18 +146,19 @@ eagle_get_next_task() {
|
|
|
146
146
|
|
|
147
147
|
eagle_get_active_files() {
|
|
148
148
|
local project; project=$(eagle_sql_escape "$1")
|
|
149
|
-
local limit
|
|
149
|
+
local limit; limit=$(eagle_sql_int "${2:-20}")
|
|
150
150
|
|
|
151
151
|
eagle_db "SELECT json_each.value
|
|
152
152
|
FROM observations, json_each(observations.files_modified)
|
|
153
153
|
WHERE observations.project = '$project'
|
|
154
|
+
AND observations.created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-30 days')
|
|
154
155
|
GROUP BY json_each.value
|
|
155
156
|
ORDER BY MAX(observations.created_at) DESC
|
|
156
157
|
LIMIT $limit;"
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
eagle_observation_exists() {
|
|
160
|
-
local session_id
|
|
161
|
+
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
161
162
|
local tool_name; tool_name=$(eagle_sql_escape "$2")
|
|
162
163
|
local tool_summary; tool_summary=$(eagle_sql_escape "$3")
|
|
163
164
|
|
|
@@ -184,3 +185,342 @@ eagle_get_overview() {
|
|
|
184
185
|
|
|
185
186
|
eagle_db "SELECT content FROM overviews WHERE project = '$project';"
|
|
186
187
|
}
|
|
188
|
+
|
|
189
|
+
eagle_activate_task() {
|
|
190
|
+
local task_id; task_id=$(eagle_sql_int "$1")
|
|
191
|
+
eagle_db "UPDATE tasks SET status = 'active', started_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = $task_id;"
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
eagle_complete_active_task() {
|
|
195
|
+
local project; project=$(eagle_sql_escape "$1")
|
|
196
|
+
local active_id
|
|
197
|
+
active_id=$(eagle_db "SELECT id FROM tasks WHERE project = '$project' AND status = 'active' LIMIT 1;")
|
|
198
|
+
if [ -n "$active_id" ]; then
|
|
199
|
+
local safe_id; safe_id=$(eagle_sql_int "$active_id")
|
|
200
|
+
eagle_db "UPDATE tasks SET status = 'done', completed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = $safe_id;"
|
|
201
|
+
echo "$active_id"
|
|
202
|
+
fi
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
eagle_get_active_task() {
|
|
206
|
+
local project; project=$(eagle_sql_escape "$1")
|
|
207
|
+
eagle_db "SELECT id, title, instructions, context_snapshot
|
|
208
|
+
FROM tasks
|
|
209
|
+
WHERE project = '$project' AND status = 'active'
|
|
210
|
+
ORDER BY ordinal ASC, id ASC
|
|
211
|
+
LIMIT 1;"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
eagle_search_code_chunks() {
|
|
215
|
+
local query; query=$(eagle_sql_escape "$1")
|
|
216
|
+
local project; project=$(eagle_sql_escape "$2")
|
|
217
|
+
local limit; limit=$(eagle_sql_int "${3:-5}")
|
|
218
|
+
|
|
219
|
+
eagle_db "SELECT c.file_path, c.start_line, c.end_line, c.language
|
|
220
|
+
FROM code_chunks c
|
|
221
|
+
JOIN code_chunks_fts f ON f.rowid = c.id
|
|
222
|
+
WHERE code_chunks_fts MATCH '$query'
|
|
223
|
+
AND c.project = '$project'
|
|
224
|
+
ORDER BY rank
|
|
225
|
+
LIMIT $limit;"
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
eagle_count_code_chunks() {
|
|
229
|
+
local project; project=$(eagle_sql_escape "$1")
|
|
230
|
+
eagle_db "SELECT COUNT(*) FROM code_chunks WHERE project = '$project' LIMIT 1;"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
eagle_prune_observations() {
|
|
234
|
+
local days; days=$(eagle_sql_int "${1:-90}")
|
|
235
|
+
local project_filter=""
|
|
236
|
+
if [ -n "${2:-}" ]; then
|
|
237
|
+
local proj; proj=$(eagle_sql_escape "$2")
|
|
238
|
+
project_filter="AND session_id IN (SELECT id FROM sessions WHERE project = '$proj')"
|
|
239
|
+
fi
|
|
240
|
+
eagle_db "DELETE FROM observations WHERE created_at < strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-$days days') $project_filter;"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
eagle_capture_claude_memory() {
|
|
244
|
+
local file_path="$1"
|
|
245
|
+
local session_id="${2:-}"
|
|
246
|
+
local project="${3:-}"
|
|
247
|
+
|
|
248
|
+
[ ! -f "$file_path" ] && return 0
|
|
249
|
+
|
|
250
|
+
local chash
|
|
251
|
+
chash=$(shasum -a 256 "$file_path" | awk '{print $1}')
|
|
252
|
+
|
|
253
|
+
local fm body
|
|
254
|
+
fm=$(awk '/^---$/{c++; next} c==1' "$file_path")
|
|
255
|
+
body=$(awk '/^---$/{c++; next} c>=2' "$file_path")
|
|
256
|
+
|
|
257
|
+
_fm_field() { printf '%s\n' "$fm" | awk -F': *' -v k="$1" '$1==k{sub(/^[^:]+: */,""); gsub(/^"|"$/,""); print; exit}'; }
|
|
258
|
+
|
|
259
|
+
local mname mdesc mtype morigin
|
|
260
|
+
mname=$(_fm_field "name")
|
|
261
|
+
mdesc=$(_fm_field "description")
|
|
262
|
+
mtype=$(_fm_field "type")
|
|
263
|
+
morigin=$(_fm_field "originSessionId")
|
|
264
|
+
[ -z "$morigin" ] && morigin="$session_id"
|
|
265
|
+
|
|
266
|
+
local fp_sql proj_sql name_sql desc_sql type_sql content_sql hash_sql origin_sql
|
|
267
|
+
fp_sql=$(eagle_sql_escape "$file_path")
|
|
268
|
+
proj_sql=$(eagle_sql_escape "$project")
|
|
269
|
+
name_sql=$(eagle_sql_escape "$mname")
|
|
270
|
+
desc_sql=$(eagle_sql_escape "$mdesc")
|
|
271
|
+
type_sql=$(eagle_sql_escape "$mtype")
|
|
272
|
+
content_sql=$(eagle_sql_escape "$body")
|
|
273
|
+
hash_sql=$(eagle_sql_escape "$chash")
|
|
274
|
+
origin_sql=$(eagle_sql_escape "$morigin")
|
|
275
|
+
|
|
276
|
+
eagle_db_pipe <<SQL
|
|
277
|
+
INSERT INTO claude_memories (project, file_path, memory_name, description, memory_type, content, content_hash, origin_session_id)
|
|
278
|
+
VALUES ('$proj_sql', '$fp_sql', '$name_sql', '$desc_sql', '$type_sql', '$content_sql', '$hash_sql', '$origin_sql')
|
|
279
|
+
ON CONFLICT(file_path) DO UPDATE SET
|
|
280
|
+
memory_name = excluded.memory_name,
|
|
281
|
+
description = excluded.description,
|
|
282
|
+
memory_type = excluded.memory_type,
|
|
283
|
+
content = excluded.content,
|
|
284
|
+
content_hash = excluded.content_hash,
|
|
285
|
+
origin_session_id = excluded.origin_session_id,
|
|
286
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
287
|
+
WHERE claude_memories.content_hash != excluded.content_hash;
|
|
288
|
+
SQL
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
eagle_search_claude_memories() {
|
|
292
|
+
local query; query=$(eagle_fts_sanitize "$1")
|
|
293
|
+
query=$(eagle_sql_escape "$query")
|
|
294
|
+
local project="${2:-}"
|
|
295
|
+
local limit; limit=$(eagle_sql_int "${3:-10}")
|
|
296
|
+
|
|
297
|
+
local where_clause=""
|
|
298
|
+
if [ -n "$project" ]; then
|
|
299
|
+
project=$(eagle_sql_escape "$project")
|
|
300
|
+
where_clause="AND m.project = '$project'"
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
eagle_db "SELECT m.memory_name, m.memory_type, m.description,
|
|
304
|
+
replace(substr(m.content, 1, 200), char(10), ' '),
|
|
305
|
+
m.file_path, m.updated_at
|
|
306
|
+
FROM claude_memories m
|
|
307
|
+
JOIN claude_memories_fts f ON f.rowid = m.id
|
|
308
|
+
WHERE claude_memories_fts MATCH '$query'
|
|
309
|
+
$where_clause
|
|
310
|
+
ORDER BY rank
|
|
311
|
+
LIMIT $limit;"
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
eagle_list_claude_memories() {
|
|
315
|
+
local project="${1:-}"
|
|
316
|
+
local limit; limit=$(eagle_sql_int "${2:-20}")
|
|
317
|
+
|
|
318
|
+
local where_clause=""
|
|
319
|
+
if [ -n "$project" ]; then
|
|
320
|
+
project=$(eagle_sql_escape "$project")
|
|
321
|
+
where_clause="WHERE project = '$project'"
|
|
322
|
+
fi
|
|
323
|
+
|
|
324
|
+
eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at
|
|
325
|
+
FROM claude_memories
|
|
326
|
+
$where_clause
|
|
327
|
+
ORDER BY updated_at DESC
|
|
328
|
+
LIMIT $limit;"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
eagle_get_claude_memory() {
|
|
332
|
+
local file_path; file_path=$(eagle_sql_escape "$1")
|
|
333
|
+
eagle_db "SELECT memory_name, memory_type, description, content, file_path, updated_at, origin_session_id
|
|
334
|
+
FROM claude_memories
|
|
335
|
+
WHERE file_path = '$file_path';"
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
eagle_capture_claude_plan() {
|
|
339
|
+
local file_path="$1"
|
|
340
|
+
local session_id="${2:-}"
|
|
341
|
+
local project="${3:-}"
|
|
342
|
+
|
|
343
|
+
[ ! -f "$file_path" ] && return 0
|
|
344
|
+
|
|
345
|
+
local chash
|
|
346
|
+
chash=$(shasum -a 256 "$file_path" | awk '{print $1}')
|
|
347
|
+
|
|
348
|
+
local title content
|
|
349
|
+
title=$(awk '/^# /{print; exit}' "$file_path" | sed 's/^# //')
|
|
350
|
+
content=$(cat "$file_path")
|
|
351
|
+
|
|
352
|
+
local fp_sql proj_sql title_sql content_sql hash_sql origin_sql
|
|
353
|
+
fp_sql=$(eagle_sql_escape "$file_path")
|
|
354
|
+
proj_sql=$(eagle_sql_escape "$project")
|
|
355
|
+
title_sql=$(eagle_sql_escape "$title")
|
|
356
|
+
content_sql=$(eagle_sql_escape "$content")
|
|
357
|
+
hash_sql=$(eagle_sql_escape "$chash")
|
|
358
|
+
origin_sql=$(eagle_sql_escape "$session_id")
|
|
359
|
+
|
|
360
|
+
eagle_db_pipe <<SQL
|
|
361
|
+
INSERT INTO claude_plans (project, file_path, title, content, content_hash, origin_session_id)
|
|
362
|
+
VALUES ('$proj_sql', '$fp_sql', '$title_sql', '$content_sql', '$hash_sql', '$origin_sql')
|
|
363
|
+
ON CONFLICT(file_path) DO UPDATE SET
|
|
364
|
+
title = excluded.title,
|
|
365
|
+
content = excluded.content,
|
|
366
|
+
content_hash = excluded.content_hash,
|
|
367
|
+
origin_session_id = COALESCE(NULLIF(excluded.origin_session_id, ''), claude_plans.origin_session_id),
|
|
368
|
+
project = CASE WHEN excluded.project != '' THEN excluded.project ELSE claude_plans.project END,
|
|
369
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
370
|
+
WHERE claude_plans.content_hash != excluded.content_hash;
|
|
371
|
+
SQL
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
eagle_search_claude_plans() {
|
|
375
|
+
local query; query=$(eagle_fts_sanitize "$1")
|
|
376
|
+
query=$(eagle_sql_escape "$query")
|
|
377
|
+
local project="${2:-}"
|
|
378
|
+
local limit; limit=$(eagle_sql_int "${3:-10}")
|
|
379
|
+
|
|
380
|
+
local where_clause=""
|
|
381
|
+
if [ -n "$project" ]; then
|
|
382
|
+
project=$(eagle_sql_escape "$project")
|
|
383
|
+
where_clause="AND p.project = '$project'"
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
eagle_db "SELECT p.title, p.project,
|
|
387
|
+
replace(substr(p.content, 1, 200), char(10), ' '),
|
|
388
|
+
p.file_path, p.updated_at
|
|
389
|
+
FROM claude_plans p
|
|
390
|
+
JOIN claude_plans_fts f ON f.rowid = p.id
|
|
391
|
+
WHERE claude_plans_fts MATCH '$query'
|
|
392
|
+
$where_clause
|
|
393
|
+
ORDER BY rank
|
|
394
|
+
LIMIT $limit;"
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
eagle_list_claude_plans() {
|
|
398
|
+
local project="${1:-}"
|
|
399
|
+
local limit; limit=$(eagle_sql_int "${2:-20}")
|
|
400
|
+
|
|
401
|
+
local where_clause=""
|
|
402
|
+
if [ -n "$project" ]; then
|
|
403
|
+
project=$(eagle_sql_escape "$project")
|
|
404
|
+
where_clause="WHERE project = '$project'"
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
eagle_db "SELECT title, project, file_path, updated_at
|
|
408
|
+
FROM claude_plans
|
|
409
|
+
$where_clause
|
|
410
|
+
ORDER BY updated_at DESC
|
|
411
|
+
LIMIT $limit;"
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
eagle_capture_claude_task() {
|
|
415
|
+
local file_path="$1"
|
|
416
|
+
local session_id="${2:-}"
|
|
417
|
+
local project="${3:-}"
|
|
418
|
+
|
|
419
|
+
[ ! -f "$file_path" ] && return 0
|
|
420
|
+
|
|
421
|
+
local chash
|
|
422
|
+
chash=$(shasum -a 256 "$file_path" | awk '{print $1}')
|
|
423
|
+
|
|
424
|
+
local task_json
|
|
425
|
+
task_json=$(cat "$file_path")
|
|
426
|
+
|
|
427
|
+
local task_id subject desc active_form status blocks blocked_by
|
|
428
|
+
task_id=$(printf '%s' "$task_json" | jq -r '.id // empty')
|
|
429
|
+
subject=$(printf '%s' "$task_json" | jq -r '.subject // empty')
|
|
430
|
+
desc=$(printf '%s' "$task_json" | jq -r '.description // empty')
|
|
431
|
+
active_form=$(printf '%s' "$task_json" | jq -r '.activeForm // empty')
|
|
432
|
+
status=$(printf '%s' "$task_json" | jq -r '.status // "pending"')
|
|
433
|
+
blocks=$(printf '%s' "$task_json" | jq -c '.blocks // []')
|
|
434
|
+
blocked_by=$(printf '%s' "$task_json" | jq -c '.blockedBy // []')
|
|
435
|
+
|
|
436
|
+
[ -z "$task_id" ] && return 0
|
|
437
|
+
|
|
438
|
+
local fp_sql proj_sql sid_sql tid_sql subj_sql desc_sql af_sql status_sql blocks_sql bb_sql hash_sql
|
|
439
|
+
fp_sql=$(eagle_sql_escape "$file_path")
|
|
440
|
+
proj_sql=$(eagle_sql_escape "$project")
|
|
441
|
+
sid_sql=$(eagle_sql_escape "$session_id")
|
|
442
|
+
tid_sql=$(eagle_sql_escape "$task_id")
|
|
443
|
+
subj_sql=$(eagle_sql_escape "$subject")
|
|
444
|
+
desc_sql=$(eagle_sql_escape "$desc")
|
|
445
|
+
af_sql=$(eagle_sql_escape "$active_form")
|
|
446
|
+
status_sql=$(eagle_sql_escape "$status")
|
|
447
|
+
blocks_sql=$(eagle_sql_escape "$blocks")
|
|
448
|
+
bb_sql=$(eagle_sql_escape "$blocked_by")
|
|
449
|
+
hash_sql=$(eagle_sql_escape "$chash")
|
|
450
|
+
|
|
451
|
+
eagle_db_pipe <<SQL
|
|
452
|
+
INSERT INTO claude_tasks (project, source_session_id, source_task_id, file_path, subject, description, active_form, status, blocks, blocked_by, content_hash)
|
|
453
|
+
VALUES ('$proj_sql', '$sid_sql', '$tid_sql', '$fp_sql', '$subj_sql', '$desc_sql', '$af_sql', '$status_sql', '$blocks_sql', '$bb_sql', '$hash_sql')
|
|
454
|
+
ON CONFLICT(file_path) DO UPDATE SET
|
|
455
|
+
subject = excluded.subject,
|
|
456
|
+
description = excluded.description,
|
|
457
|
+
active_form = excluded.active_form,
|
|
458
|
+
status = excluded.status,
|
|
459
|
+
blocks = excluded.blocks,
|
|
460
|
+
blocked_by = excluded.blocked_by,
|
|
461
|
+
content_hash = excluded.content_hash,
|
|
462
|
+
project = CASE WHEN excluded.project != '' THEN excluded.project ELSE claude_tasks.project END,
|
|
463
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
464
|
+
WHERE claude_tasks.content_hash != excluded.content_hash;
|
|
465
|
+
SQL
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
eagle_list_claude_tasks() {
|
|
469
|
+
local project="${1:-}"
|
|
470
|
+
local limit; limit=$(eagle_sql_int "${2:-20}")
|
|
471
|
+
|
|
472
|
+
local where_clause=""
|
|
473
|
+
if [ -n "$project" ]; then
|
|
474
|
+
project=$(eagle_sql_escape "$project")
|
|
475
|
+
where_clause="WHERE project = '$project'"
|
|
476
|
+
fi
|
|
477
|
+
|
|
478
|
+
eagle_db "SELECT subject, status, source_session_id, source_task_id, updated_at
|
|
479
|
+
FROM claude_tasks
|
|
480
|
+
$where_clause
|
|
481
|
+
ORDER BY updated_at DESC
|
|
482
|
+
LIMIT $limit;"
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
eagle_search_claude_tasks() {
|
|
486
|
+
local query; query=$(eagle_fts_sanitize "$1")
|
|
487
|
+
query=$(eagle_sql_escape "$query")
|
|
488
|
+
local project="${2:-}"
|
|
489
|
+
local limit; limit=$(eagle_sql_int "${3:-10}")
|
|
490
|
+
|
|
491
|
+
local where_clause=""
|
|
492
|
+
if [ -n "$project" ]; then
|
|
493
|
+
project=$(eagle_sql_escape "$project")
|
|
494
|
+
where_clause="AND t.project = '$project'"
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
eagle_db "SELECT t.subject, t.status,
|
|
498
|
+
replace(substr(t.description, 1, 200), char(10), ' '),
|
|
499
|
+
t.source_session_id, t.source_task_id, t.updated_at
|
|
500
|
+
FROM claude_tasks t
|
|
501
|
+
JOIN claude_tasks_fts f ON f.rowid = t.id
|
|
502
|
+
WHERE claude_tasks_fts MATCH '$query'
|
|
503
|
+
$where_clause
|
|
504
|
+
ORDER BY rank
|
|
505
|
+
LIMIT $limit;"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
eagle_prune_orphan_chunks() {
|
|
509
|
+
local project; project=$(eagle_sql_escape "$1")
|
|
510
|
+
local target_dir="$2"
|
|
511
|
+
|
|
512
|
+
# Get all indexed file paths for this project
|
|
513
|
+
local paths
|
|
514
|
+
paths=$(eagle_db "SELECT DISTINCT file_path FROM code_chunks WHERE project = '$project';")
|
|
515
|
+
|
|
516
|
+
local removed=0
|
|
517
|
+
while IFS= read -r fpath; do
|
|
518
|
+
[ -z "$fpath" ] && continue
|
|
519
|
+
if [ ! -f "$target_dir/$fpath" ]; then
|
|
520
|
+
local fpath_sql; fpath_sql=$(eagle_sql_escape "$fpath")
|
|
521
|
+
eagle_db "DELETE FROM code_chunks WHERE project = '$project' AND file_path = '$fpath_sql';"
|
|
522
|
+
removed=$((removed + 1))
|
|
523
|
+
fi
|
|
524
|
+
done <<< "$paths"
|
|
525
|
+
echo "$removed"
|
|
526
|
+
}
|
package/package.json
CHANGED
package/scripts/help.sh
CHANGED
|
@@ -22,8 +22,10 @@ echo -e " ${BOLD}Commands:${RESET}"
|
|
|
22
22
|
echo -e " ${CYAN}search${RESET} Search past sessions, files, and observations"
|
|
23
23
|
echo -e " ${CYAN}tasks${RESET} Manage tracked tasks (add, done, block, list)"
|
|
24
24
|
echo -e " ${CYAN}overview${RESET} View or set project overview"
|
|
25
|
+
echo -e " ${CYAN}memories${RESET} Browse and search Claude Code memories, plans, and tasks"
|
|
25
26
|
echo -e " ${CYAN}scan${RESET} Analyze a project and generate an overview"
|
|
26
27
|
echo -e " ${CYAN}index${RESET} Index source files for code-level search"
|
|
28
|
+
echo -e " ${CYAN}prune${RESET} Remove old observations and orphaned chunks"
|
|
27
29
|
echo -e " ${CYAN}install${RESET} Set up hooks, database, and skills"
|
|
28
30
|
echo -e " ${CYAN}uninstall${RESET} Remove hooks and optionally delete data"
|
|
29
31
|
echo -e " ${CYAN}update${RESET} Re-deploy hooks and run new migrations"
|
|
@@ -38,6 +40,11 @@ echo -e " ${DIM}\$${RESET} eagle-mem tasks add \"Fix X\" ${DIM}# Add a task$
|
|
|
38
40
|
echo -e " ${DIM}\$${RESET} eagle-mem overview ${DIM}# View overview${RESET}"
|
|
39
41
|
echo -e " ${DIM}\$${RESET} eagle-mem scan . ${DIM}# Scan current project${RESET}"
|
|
40
42
|
echo -e " ${DIM}\$${RESET} eagle-mem index . ${DIM}# Index source files${RESET}"
|
|
43
|
+
echo -e " ${DIM}\$${RESET} eagle-mem memories ${DIM}# List mirrored memories${RESET}"
|
|
44
|
+
echo -e " ${DIM}\$${RESET} eagle-mem memories sync ${DIM}# Backfill memories + plans + tasks${RESET}"
|
|
45
|
+
echo -e " ${DIM}\$${RESET} eagle-mem memories plans ${DIM}# List captured plans${RESET}"
|
|
46
|
+
echo -e " ${DIM}\$${RESET} eagle-mem memories tasks ${DIM}# List captured tasks${RESET}"
|
|
47
|
+
echo -e " ${DIM}\$${RESET} eagle-mem prune ${DIM}# Clean old data${RESET}"
|
|
41
48
|
echo -e " ${DIM}\$${RESET} eagle-mem install ${DIM}# First-time setup${RESET}"
|
|
42
49
|
echo ""
|
|
43
50
|
echo -e " ${BOLD}What it does:${RESET}"
|
|
@@ -45,6 +52,7 @@ echo -e " ${DOT} Saves session summaries to a shared SQLite database"
|
|
|
45
52
|
echo -e " ${DOT} Injects relevant memory at session start"
|
|
46
53
|
echo -e " ${DOT} Searches past sessions when you ask related questions"
|
|
47
54
|
echo -e " ${DOT} Tracks file operations across sessions"
|
|
55
|
+
echo -e " ${DOT} Mirrors Claude Code memories, plans, and tasks into FTS5-searchable storage"
|
|
48
56
|
echo -e " ${DOT} Provides task management for complex multi-step work"
|
|
49
57
|
echo ""
|
|
50
58
|
echo -e " ${BOLD}Skills${RESET} ${DIM}(available inside Claude Code):${RESET}"
|
package/scripts/install.sh
CHANGED
|
@@ -7,11 +7,12 @@ set -euo pipefail
|
|
|
7
7
|
|
|
8
8
|
PACKAGE_DIR="${1:-.}"
|
|
9
9
|
SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
10
11
|
|
|
11
12
|
. "$SCRIPTS_DIR/style.sh"
|
|
13
|
+
. "$LIB_DIR/common.sh"
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
SETTINGS="$HOME/.claude/settings.json"
|
|
15
|
+
SETTINGS="$EAGLE_SETTINGS"
|
|
15
16
|
|
|
16
17
|
eagle_banner
|
|
17
18
|
eagle_header "Install"
|
|
@@ -189,7 +190,7 @@ patch_hook "Stop" "" \
|
|
|
189
190
|
"$EAGLE_MEM_DIR/hooks/stop.sh" \
|
|
190
191
|
"Stop hook"
|
|
191
192
|
|
|
192
|
-
patch_hook "PostToolUse" "Read|Write|Edit|Bash" \
|
|
193
|
+
patch_hook "PostToolUse" "Read|Write|Edit|Bash|TaskCreate|TaskUpdate" \
|
|
193
194
|
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
194
195
|
"PostToolUse hook"
|
|
195
196
|
|
|
@@ -203,22 +204,12 @@ patch_hook "UserPromptSubmit" "" \
|
|
|
203
204
|
|
|
204
205
|
# ─── Install skills ────────────────────────────────────────
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
if [ -d "$PACKAGE_DIR/skills" ]; then
|
|
208
|
+
mkdir -p "$EAGLE_SKILLS_DIR"
|
|
208
209
|
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
209
210
|
[ ! -d "$skill_dir" ] && continue
|
|
210
211
|
skill_name=$(basename "$skill_dir")
|
|
211
|
-
dst="$
|
|
212
|
-
[ -L "$dst" ] && rm "$dst"
|
|
213
|
-
ln -sf "$skill_dir" "$dst"
|
|
214
|
-
eagle_ok "Skill: $skill_name"
|
|
215
|
-
done
|
|
216
|
-
elif [ -d "$PACKAGE_DIR/skills" ]; then
|
|
217
|
-
mkdir -p "$SKILLS_DIR"
|
|
218
|
-
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
219
|
-
[ ! -d "$skill_dir" ] && continue
|
|
220
|
-
skill_name=$(basename "$skill_dir")
|
|
221
|
-
dst="$SKILLS_DIR/$skill_name"
|
|
212
|
+
dst="$EAGLE_SKILLS_DIR/$skill_name"
|
|
222
213
|
[ -L "$dst" ] && rm "$dst"
|
|
223
214
|
ln -sf "$skill_dir" "$dst"
|
|
224
215
|
eagle_ok "Skill: $skill_name"
|