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
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ═══════════════════════════════════════════════════════════
|
|
3
|
+
# Eagle Mem — Claude Code Memory Mirror CLI
|
|
4
|
+
# List, show, search, and sync Claude Code auto-memories
|
|
5
|
+
# ═══════════════════════════════════════════════════════════
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
10
|
+
|
|
11
|
+
. "$SCRIPTS_DIR/style.sh"
|
|
12
|
+
. "$LIB_DIR/common.sh"
|
|
13
|
+
. "$LIB_DIR/db.sh"
|
|
14
|
+
|
|
15
|
+
eagle_ensure_db
|
|
16
|
+
|
|
17
|
+
# ─── Parse arguments ──────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
action="${1:-list}"
|
|
20
|
+
shift 2>/dev/null || true
|
|
21
|
+
|
|
22
|
+
project=""
|
|
23
|
+
limit=20
|
|
24
|
+
query=""
|
|
25
|
+
|
|
26
|
+
show_help() {
|
|
27
|
+
echo -e " ${BOLD}eagle-mem memories${RESET} — Claude Code memory, plan & task mirror"
|
|
28
|
+
echo ""
|
|
29
|
+
echo -e " ${BOLD}Usage:${RESET}"
|
|
30
|
+
echo -e " eagle-mem memories ${DIM}# list all mirrored memories${RESET}"
|
|
31
|
+
echo -e " eagle-mem memories list ${DIM}# same as above${RESET}"
|
|
32
|
+
echo -e " eagle-mem memories search ${CYAN}<query>${RESET} ${DIM}# full-text search memories${RESET}"
|
|
33
|
+
echo -e " eagle-mem memories show ${CYAN}<file_path>${RESET} ${DIM}# show a specific memory${RESET}"
|
|
34
|
+
echo -e " eagle-mem memories plans ${DIM}# list captured plans${RESET}"
|
|
35
|
+
echo -e " eagle-mem memories plans search ${CYAN}<query>${RESET} ${DIM}# full-text search plans${RESET}"
|
|
36
|
+
echo -e " eagle-mem memories plans show ${CYAN}<file_path>${RESET} ${DIM}# show a specific plan${RESET}"
|
|
37
|
+
echo -e " eagle-mem memories tasks ${DIM}# list captured tasks${RESET}"
|
|
38
|
+
echo -e " eagle-mem memories tasks search ${CYAN}<query>${RESET} ${DIM}# full-text search tasks${RESET}"
|
|
39
|
+
echo -e " eagle-mem memories tasks show ${CYAN}<file_path>${RESET} ${DIM}# show a specific task${RESET}"
|
|
40
|
+
echo -e " eagle-mem memories sync ${DIM}# backfill memories + plans + tasks${RESET}"
|
|
41
|
+
echo ""
|
|
42
|
+
echo -e " ${BOLD}Options:${RESET}"
|
|
43
|
+
echo -e " ${CYAN}-p, --project${RESET} <name> Filter by project"
|
|
44
|
+
echo -e " ${CYAN}-l, --limit${RESET} <N> Max results (default: 20)"
|
|
45
|
+
echo ""
|
|
46
|
+
echo -e " ${BOLD}How it works:${RESET}"
|
|
47
|
+
echo -e " ${DOT} Eagle Mem intercepts Claude Code's auto-memory, plan, and task writes"
|
|
48
|
+
echo -e " ${DOT} All are mirrored into Eagle Mem's SQLite + FTS5"
|
|
49
|
+
echo -e " ${DOT} Use ${CYAN}sync${RESET} to backfill items written before mirroring was enabled"
|
|
50
|
+
echo ""
|
|
51
|
+
exit 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
plan_action=""
|
|
55
|
+
task_action=""
|
|
56
|
+
|
|
57
|
+
case "$action" in
|
|
58
|
+
--help|-h) show_help ;;
|
|
59
|
+
plans)
|
|
60
|
+
plan_action="${1:-list}"
|
|
61
|
+
shift 2>/dev/null || true
|
|
62
|
+
;;
|
|
63
|
+
tasks)
|
|
64
|
+
task_action="${1:-list}"
|
|
65
|
+
shift 2>/dev/null || true
|
|
66
|
+
;;
|
|
67
|
+
esac
|
|
68
|
+
|
|
69
|
+
while [ $# -gt 0 ]; do
|
|
70
|
+
case "$1" in
|
|
71
|
+
--project|-p) project="$2"; shift 2 ;;
|
|
72
|
+
--limit|-l) limit="$2"; shift 2 ;;
|
|
73
|
+
--help|-h) show_help ;;
|
|
74
|
+
*)
|
|
75
|
+
if [ -z "$query" ]; then
|
|
76
|
+
query="$1"; shift
|
|
77
|
+
else
|
|
78
|
+
eagle_err "Unknown option: $1"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
;;
|
|
82
|
+
esac
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
# ─── Actions ─────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
memories_list() {
|
|
88
|
+
eagle_header "Memories"
|
|
89
|
+
|
|
90
|
+
local result
|
|
91
|
+
result=$(eagle_list_claude_memories "$project" "$limit")
|
|
92
|
+
|
|
93
|
+
if [ -z "$result" ]; then
|
|
94
|
+
eagle_dim "No mirrored memories found."
|
|
95
|
+
echo ""
|
|
96
|
+
eagle_dim "Memories are captured automatically when Claude Code writes to its auto-memory."
|
|
97
|
+
eagle_dim "Run 'eagle-mem memories sync' to backfill existing memories."
|
|
98
|
+
echo ""
|
|
99
|
+
return
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
local count=0
|
|
103
|
+
while IFS='|' read -r name mtype desc _fp updated; do
|
|
104
|
+
[ -z "$name" ] && continue
|
|
105
|
+
count=$((count + 1))
|
|
106
|
+
|
|
107
|
+
local type_color="$DIM"
|
|
108
|
+
case "$mtype" in
|
|
109
|
+
user) type_color="$CYAN" ;;
|
|
110
|
+
feedback) type_color="$YELLOW" ;;
|
|
111
|
+
project) type_color="$GREEN" ;;
|
|
112
|
+
reference) type_color="$BLUE" ;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET}"
|
|
116
|
+
[ -n "$desc" ] && echo -e " ${DIM}${desc}${RESET}"
|
|
117
|
+
echo -e " ${DIM}updated: ${updated}${RESET}"
|
|
118
|
+
echo ""
|
|
119
|
+
done <<< "$result"
|
|
120
|
+
|
|
121
|
+
eagle_dim "$count memories shown"
|
|
122
|
+
echo ""
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
memories_search() {
|
|
126
|
+
if [ -z "$query" ]; then
|
|
127
|
+
eagle_err "Usage: eagle-mem memories search <query>"
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
eagle_header "Memory Search"
|
|
132
|
+
eagle_info "Query: $query"
|
|
133
|
+
echo ""
|
|
134
|
+
|
|
135
|
+
local result
|
|
136
|
+
result=$(eagle_search_claude_memories "$query" "$project" "$limit")
|
|
137
|
+
|
|
138
|
+
if [ -z "$result" ]; then
|
|
139
|
+
eagle_dim "No memories matching '$query'"
|
|
140
|
+
echo ""
|
|
141
|
+
return
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
local count=0
|
|
145
|
+
while IFS='|' read -r name mtype desc content _fp updated; do
|
|
146
|
+
[ -z "$name" ] && continue
|
|
147
|
+
count=$((count + 1))
|
|
148
|
+
|
|
149
|
+
local type_color="$DIM"
|
|
150
|
+
case "$mtype" in
|
|
151
|
+
user) type_color="$CYAN" ;;
|
|
152
|
+
feedback) type_color="$YELLOW" ;;
|
|
153
|
+
project) type_color="$GREEN" ;;
|
|
154
|
+
reference) type_color="$BLUE" ;;
|
|
155
|
+
esac
|
|
156
|
+
|
|
157
|
+
echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET}"
|
|
158
|
+
[ -n "$desc" ] && echo -e " ${DIM}${desc}${RESET}"
|
|
159
|
+
local snippet
|
|
160
|
+
snippet=$(printf '%s' "$content" | head -c 200)
|
|
161
|
+
[ -n "$snippet" ] && echo -e " ${snippet}"
|
|
162
|
+
echo -e " ${DIM}updated: ${updated}${RESET}"
|
|
163
|
+
echo ""
|
|
164
|
+
done <<< "$result"
|
|
165
|
+
|
|
166
|
+
eagle_dim "$count results"
|
|
167
|
+
echo ""
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
memories_show() {
|
|
171
|
+
if [ -z "$query" ]; then
|
|
172
|
+
eagle_err "Usage: eagle-mem memories show <file_path>"
|
|
173
|
+
exit 1
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
local meta
|
|
177
|
+
meta=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at, origin_session_id
|
|
178
|
+
FROM claude_memories WHERE file_path = '$(eagle_sql_escape "$query")';")
|
|
179
|
+
|
|
180
|
+
if [ -z "$meta" ]; then
|
|
181
|
+
eagle_err "Memory not found: $query"
|
|
182
|
+
exit 1
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
IFS='|' read -r name mtype desc fp updated origin <<< "$meta"
|
|
186
|
+
|
|
187
|
+
eagle_header "Memory Detail"
|
|
188
|
+
|
|
189
|
+
eagle_kv "Name:" "$name"
|
|
190
|
+
eagle_kv "Type:" "$mtype"
|
|
191
|
+
eagle_kv "File:" "$fp"
|
|
192
|
+
eagle_kv "Updated:" "$updated"
|
|
193
|
+
[ -n "$origin" ] && eagle_kv "Session:" "$origin"
|
|
194
|
+
echo ""
|
|
195
|
+
|
|
196
|
+
[ -n "$desc" ] && echo -e " ${BOLD}Description:${RESET} $desc"
|
|
197
|
+
echo ""
|
|
198
|
+
|
|
199
|
+
if [ -f "$fp" ]; then
|
|
200
|
+
echo -e " ${BOLD}Content:${RESET}"
|
|
201
|
+
awk '/^---$/{c++; next} c>=2' "$fp" | while IFS= read -r line; do
|
|
202
|
+
echo " $line"
|
|
203
|
+
done
|
|
204
|
+
else
|
|
205
|
+
eagle_dim "Source file no longer exists on disk."
|
|
206
|
+
fi
|
|
207
|
+
echo ""
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
plans_list() {
|
|
211
|
+
eagle_header "Plans"
|
|
212
|
+
|
|
213
|
+
local result
|
|
214
|
+
result=$(eagle_list_claude_plans "$project" "$limit")
|
|
215
|
+
|
|
216
|
+
if [ -z "$result" ]; then
|
|
217
|
+
eagle_dim "No captured plans found."
|
|
218
|
+
echo ""
|
|
219
|
+
eagle_dim "Plans are captured when Claude Code writes to ~/.claude/plans/"
|
|
220
|
+
eagle_dim "Run 'eagle-mem memories sync' to backfill existing plans."
|
|
221
|
+
echo ""
|
|
222
|
+
return
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
local count=0
|
|
226
|
+
while IFS='|' read -r title proj _fp updated; do
|
|
227
|
+
[ -z "$title" ] && continue
|
|
228
|
+
count=$((count + 1))
|
|
229
|
+
|
|
230
|
+
local proj_label=""
|
|
231
|
+
[ -n "$proj" ] && proj_label=" ${DIM}[${proj}]${RESET}"
|
|
232
|
+
|
|
233
|
+
echo -e " ${BOLD}${title}${RESET}${proj_label}"
|
|
234
|
+
echo -e " ${DIM}updated: ${updated}${RESET}"
|
|
235
|
+
echo ""
|
|
236
|
+
done <<< "$result"
|
|
237
|
+
|
|
238
|
+
eagle_dim "$count plans shown"
|
|
239
|
+
echo ""
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
plans_search() {
|
|
243
|
+
if [ -z "$query" ]; then
|
|
244
|
+
eagle_err "Usage: eagle-mem memories plans search <query>"
|
|
245
|
+
exit 1
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
eagle_header "Plan Search"
|
|
249
|
+
eagle_info "Query: $query"
|
|
250
|
+
echo ""
|
|
251
|
+
|
|
252
|
+
local result
|
|
253
|
+
result=$(eagle_search_claude_plans "$query" "$project" "$limit")
|
|
254
|
+
|
|
255
|
+
if [ -z "$result" ]; then
|
|
256
|
+
eagle_dim "No plans matching '$query'"
|
|
257
|
+
echo ""
|
|
258
|
+
return
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
local count=0
|
|
262
|
+
while IFS='|' read -r title proj snippet _fp updated; do
|
|
263
|
+
[ -z "$title" ] && continue
|
|
264
|
+
count=$((count + 1))
|
|
265
|
+
|
|
266
|
+
local proj_label=""
|
|
267
|
+
[ -n "$proj" ] && proj_label=" ${DIM}[${proj}]${RESET}"
|
|
268
|
+
|
|
269
|
+
echo -e " ${BOLD}${title}${RESET}${proj_label}"
|
|
270
|
+
[ -n "$snippet" ] && echo -e " ${snippet}"
|
|
271
|
+
echo -e " ${DIM}updated: ${updated}${RESET}"
|
|
272
|
+
echo ""
|
|
273
|
+
done <<< "$result"
|
|
274
|
+
|
|
275
|
+
eagle_dim "$count results"
|
|
276
|
+
echo ""
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
plans_show() {
|
|
280
|
+
if [ -z "$query" ]; then
|
|
281
|
+
eagle_err "Usage: eagle-mem memories plans show <file_path>"
|
|
282
|
+
exit 1
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
local meta
|
|
286
|
+
meta=$(eagle_db "SELECT title, project, file_path, updated_at, origin_session_id
|
|
287
|
+
FROM claude_plans WHERE file_path = '$(eagle_sql_escape "$query")';")
|
|
288
|
+
|
|
289
|
+
if [ -z "$meta" ]; then
|
|
290
|
+
eagle_err "Plan not found: $query"
|
|
291
|
+
exit 1
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
IFS='|' read -r title proj fp updated origin <<< "$meta"
|
|
295
|
+
|
|
296
|
+
eagle_header "Plan Detail"
|
|
297
|
+
|
|
298
|
+
eagle_kv "Title:" "$title"
|
|
299
|
+
[ -n "$proj" ] && eagle_kv "Project:" "$proj"
|
|
300
|
+
eagle_kv "File:" "$fp"
|
|
301
|
+
eagle_kv "Updated:" "$updated"
|
|
302
|
+
[ -n "$origin" ] && eagle_kv "Session:" "$origin"
|
|
303
|
+
echo ""
|
|
304
|
+
|
|
305
|
+
if [ -f "$fp" ]; then
|
|
306
|
+
echo -e " ${BOLD}Content:${RESET}"
|
|
307
|
+
cat "$fp" | while IFS= read -r line; do
|
|
308
|
+
echo " $line"
|
|
309
|
+
done
|
|
310
|
+
else
|
|
311
|
+
eagle_dim "Source file no longer exists on disk."
|
|
312
|
+
fi
|
|
313
|
+
echo ""
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
tasks_list() {
|
|
317
|
+
eagle_header "Claude Code Tasks"
|
|
318
|
+
|
|
319
|
+
local result
|
|
320
|
+
result=$(eagle_list_claude_tasks "$project" "$limit")
|
|
321
|
+
|
|
322
|
+
if [ -z "$result" ]; then
|
|
323
|
+
eagle_dim "No captured tasks found."
|
|
324
|
+
echo ""
|
|
325
|
+
eagle_dim "Tasks are captured when Claude Code uses TaskCreate/TaskUpdate."
|
|
326
|
+
eagle_dim "Run 'eagle-mem memories sync' to backfill existing tasks."
|
|
327
|
+
echo ""
|
|
328
|
+
return
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
local count=0
|
|
332
|
+
while IFS='|' read -r subject status sid tid updated; do
|
|
333
|
+
[ -z "$subject" ] && continue
|
|
334
|
+
count=$((count + 1))
|
|
335
|
+
|
|
336
|
+
local status_color="$DIM"
|
|
337
|
+
case "$status" in
|
|
338
|
+
pending) status_color="$DIM" ;;
|
|
339
|
+
in_progress) status_color="$CYAN" ;;
|
|
340
|
+
completed) status_color="$GREEN" ;;
|
|
341
|
+
esac
|
|
342
|
+
|
|
343
|
+
echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET}"
|
|
344
|
+
echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
|
|
345
|
+
echo ""
|
|
346
|
+
done <<< "$result"
|
|
347
|
+
|
|
348
|
+
eagle_dim "$count tasks shown"
|
|
349
|
+
echo ""
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
tasks_search() {
|
|
353
|
+
if [ -z "$query" ]; then
|
|
354
|
+
eagle_err "Usage: eagle-mem memories tasks search <query>"
|
|
355
|
+
exit 1
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
eagle_header "Task Search"
|
|
359
|
+
eagle_info "Query: $query"
|
|
360
|
+
echo ""
|
|
361
|
+
|
|
362
|
+
local result
|
|
363
|
+
result=$(eagle_search_claude_tasks "$query" "$project" "$limit")
|
|
364
|
+
|
|
365
|
+
if [ -z "$result" ]; then
|
|
366
|
+
eagle_dim "No tasks matching '$query'"
|
|
367
|
+
echo ""
|
|
368
|
+
return
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
local count=0
|
|
372
|
+
while IFS='|' read -r subject status desc sid tid updated; do
|
|
373
|
+
[ -z "$subject" ] && continue
|
|
374
|
+
count=$((count + 1))
|
|
375
|
+
|
|
376
|
+
local status_color="$DIM"
|
|
377
|
+
case "$status" in
|
|
378
|
+
pending) status_color="$DIM" ;;
|
|
379
|
+
in_progress) status_color="$CYAN" ;;
|
|
380
|
+
completed) status_color="$GREEN" ;;
|
|
381
|
+
esac
|
|
382
|
+
|
|
383
|
+
echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET}"
|
|
384
|
+
[ -n "$desc" ] && echo -e " ${desc}"
|
|
385
|
+
echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
|
|
386
|
+
echo ""
|
|
387
|
+
done <<< "$result"
|
|
388
|
+
|
|
389
|
+
eagle_dim "$count results"
|
|
390
|
+
echo ""
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
tasks_show() {
|
|
394
|
+
if [ -z "$query" ]; then
|
|
395
|
+
eagle_err "Usage: eagle-mem memories tasks show <file_path>"
|
|
396
|
+
exit 1
|
|
397
|
+
fi
|
|
398
|
+
|
|
399
|
+
local meta
|
|
400
|
+
meta=$(eagle_db "SELECT subject, status, description, active_form, source_session_id, source_task_id, file_path, updated_at
|
|
401
|
+
FROM claude_tasks WHERE file_path = '$(eagle_sql_escape "$query")';")
|
|
402
|
+
|
|
403
|
+
if [ -z "$meta" ]; then
|
|
404
|
+
eagle_err "Task not found: $query"
|
|
405
|
+
exit 1
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
IFS='|' read -r subject status desc af sid tid fp updated <<< "$meta"
|
|
409
|
+
|
|
410
|
+
eagle_header "Task Detail"
|
|
411
|
+
|
|
412
|
+
eagle_kv "Subject:" "$subject"
|
|
413
|
+
eagle_kv "Status:" "$status"
|
|
414
|
+
eagle_kv "Task ID:" "$tid"
|
|
415
|
+
eagle_kv "Session:" "$sid"
|
|
416
|
+
eagle_kv "File:" "$fp"
|
|
417
|
+
eagle_kv "Updated:" "$updated"
|
|
418
|
+
echo ""
|
|
419
|
+
|
|
420
|
+
[ -n "$desc" ] && echo -e " ${BOLD}Description:${RESET} $desc" && echo ""
|
|
421
|
+
[ -n "$af" ] && echo -e " ${BOLD}Active Form:${RESET} $af" && echo ""
|
|
422
|
+
|
|
423
|
+
if [ -f "$fp" ]; then
|
|
424
|
+
echo -e " ${BOLD}Raw JSON:${RESET}"
|
|
425
|
+
jq '.' "$fp" 2>/dev/null | while IFS= read -r line; do
|
|
426
|
+
echo " $line"
|
|
427
|
+
done
|
|
428
|
+
else
|
|
429
|
+
eagle_dim "Source file no longer exists on disk."
|
|
430
|
+
fi
|
|
431
|
+
echo ""
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
memories_sync() {
|
|
435
|
+
eagle_header "Memory, Plan & Task Sync"
|
|
436
|
+
|
|
437
|
+
# ─── Sync memories ───────────────────────────────────
|
|
438
|
+
eagle_info "Scanning for Claude Code auto-memory files..."
|
|
439
|
+
echo ""
|
|
440
|
+
|
|
441
|
+
local claude_mem_root="$HOME/.claude/projects"
|
|
442
|
+
local mem_synced=0
|
|
443
|
+
local mem_skipped=0
|
|
444
|
+
|
|
445
|
+
if [ -d "$claude_mem_root" ]; then
|
|
446
|
+
while IFS= read -r -d '' memfile; do
|
|
447
|
+
local base
|
|
448
|
+
base=$(basename "$memfile")
|
|
449
|
+
[ "$base" = "MEMORY.md" ] && continue
|
|
450
|
+
|
|
451
|
+
local proj_slug proj_name
|
|
452
|
+
proj_slug=$(echo "$memfile" | sed "s|$claude_mem_root/||" | cut -d'/' -f1)
|
|
453
|
+
proj_name=$(echo "$proj_slug" | rev | cut -d'-' -f1 | rev)
|
|
454
|
+
|
|
455
|
+
local existing_hash
|
|
456
|
+
existing_hash=$(eagle_db "SELECT content_hash FROM claude_memories WHERE file_path = '$(eagle_sql_escape "$memfile")';")
|
|
457
|
+
local new_hash
|
|
458
|
+
new_hash=$(shasum -a 256 "$memfile" | awk '{print $1}')
|
|
459
|
+
|
|
460
|
+
if [ "$existing_hash" = "$new_hash" ]; then
|
|
461
|
+
mem_skipped=$((mem_skipped + 1))
|
|
462
|
+
continue
|
|
463
|
+
fi
|
|
464
|
+
|
|
465
|
+
eagle_capture_claude_memory "$memfile" "" "$proj_name"
|
|
466
|
+
mem_synced=$((mem_synced + 1))
|
|
467
|
+
eagle_ok "Memory: $base → $proj_name"
|
|
468
|
+
done < <(find "$claude_mem_root" -path "*/memory/*.md" -print0 2>/dev/null)
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
eagle_kv "Memories:" "$mem_synced synced, $mem_skipped unchanged"
|
|
472
|
+
echo ""
|
|
473
|
+
|
|
474
|
+
# ─── Sync plans ──────────────────────────────────────
|
|
475
|
+
eagle_info "Scanning for Claude Code plan files..."
|
|
476
|
+
echo ""
|
|
477
|
+
|
|
478
|
+
local plans_dir="$HOME/.claude/plans"
|
|
479
|
+
local plan_synced=0
|
|
480
|
+
local plan_skipped=0
|
|
481
|
+
|
|
482
|
+
if [ -d "$plans_dir" ]; then
|
|
483
|
+
for planfile in "$plans_dir"/*.md; do
|
|
484
|
+
[ ! -f "$planfile" ] && continue
|
|
485
|
+
|
|
486
|
+
local existing_hash
|
|
487
|
+
existing_hash=$(eagle_db "SELECT content_hash FROM claude_plans WHERE file_path = '$(eagle_sql_escape "$planfile")';")
|
|
488
|
+
local new_hash
|
|
489
|
+
new_hash=$(shasum -a 256 "$planfile" | awk '{print $1}')
|
|
490
|
+
|
|
491
|
+
if [ "$existing_hash" = "$new_hash" ]; then
|
|
492
|
+
plan_skipped=$((plan_skipped + 1))
|
|
493
|
+
continue
|
|
494
|
+
fi
|
|
495
|
+
|
|
496
|
+
eagle_capture_claude_plan "$planfile" "" ""
|
|
497
|
+
plan_synced=$((plan_synced + 1))
|
|
498
|
+
local ptitle
|
|
499
|
+
ptitle=$(awk '/^# /{print; exit}' "$planfile" | sed 's/^# //')
|
|
500
|
+
eagle_ok "Plan: $ptitle"
|
|
501
|
+
done
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
eagle_kv "Plans:" "$plan_synced synced, $plan_skipped unchanged"
|
|
505
|
+
echo ""
|
|
506
|
+
|
|
507
|
+
# ─── Sync tasks ──────────────────────────────────────
|
|
508
|
+
eagle_info "Scanning for Claude Code task files..."
|
|
509
|
+
echo ""
|
|
510
|
+
|
|
511
|
+
local tasks_dir="$HOME/.claude/tasks"
|
|
512
|
+
local task_synced=0
|
|
513
|
+
local task_skipped=0
|
|
514
|
+
|
|
515
|
+
if [ -d "$tasks_dir" ]; then
|
|
516
|
+
for session_dir in "$tasks_dir"/*/; do
|
|
517
|
+
[ ! -d "$session_dir" ] && continue
|
|
518
|
+
local sid
|
|
519
|
+
sid=$(basename "$session_dir")
|
|
520
|
+
|
|
521
|
+
local task_project=""
|
|
522
|
+
task_project=$(eagle_db "SELECT project FROM sessions WHERE id = '$(eagle_sql_escape "$sid")' LIMIT 1;")
|
|
523
|
+
|
|
524
|
+
for taskfile in "$session_dir"*.json; do
|
|
525
|
+
[ ! -f "$taskfile" ] && continue
|
|
526
|
+
|
|
527
|
+
local existing_hash
|
|
528
|
+
existing_hash=$(eagle_db "SELECT content_hash FROM claude_tasks WHERE file_path = '$(eagle_sql_escape "$taskfile")';")
|
|
529
|
+
local new_hash
|
|
530
|
+
new_hash=$(shasum -a 256 "$taskfile" | awk '{print $1}')
|
|
531
|
+
|
|
532
|
+
if [ "$existing_hash" = "$new_hash" ]; then
|
|
533
|
+
task_skipped=$((task_skipped + 1))
|
|
534
|
+
continue
|
|
535
|
+
fi
|
|
536
|
+
|
|
537
|
+
eagle_capture_claude_task "$taskfile" "$sid" "$task_project"
|
|
538
|
+
task_synced=$((task_synced + 1))
|
|
539
|
+
done
|
|
540
|
+
done
|
|
541
|
+
fi
|
|
542
|
+
|
|
543
|
+
eagle_kv "Tasks:" "$task_synced synced, $task_skipped unchanged"
|
|
544
|
+
eagle_footer "Sync complete."
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
# ─── Dispatch ────────────────────────────────────────────
|
|
548
|
+
|
|
549
|
+
case "$action" in
|
|
550
|
+
list) memories_list ;;
|
|
551
|
+
search) memories_search ;;
|
|
552
|
+
show) memories_show ;;
|
|
553
|
+
plans)
|
|
554
|
+
case "$plan_action" in
|
|
555
|
+
list) plans_list ;;
|
|
556
|
+
search) plans_search ;;
|
|
557
|
+
show) plans_show ;;
|
|
558
|
+
*) plans_list ;;
|
|
559
|
+
esac
|
|
560
|
+
;;
|
|
561
|
+
tasks)
|
|
562
|
+
case "$task_action" in
|
|
563
|
+
list) tasks_list ;;
|
|
564
|
+
search) tasks_search ;;
|
|
565
|
+
show) tasks_show ;;
|
|
566
|
+
*) tasks_list ;;
|
|
567
|
+
esac
|
|
568
|
+
;;
|
|
569
|
+
sync) memories_sync ;;
|
|
570
|
+
*)
|
|
571
|
+
eagle_err "Unknown action: $action"
|
|
572
|
+
echo -e " ${DIM}Available: list, search, show, plans, tasks, sync${RESET}"
|
|
573
|
+
exit 1
|
|
574
|
+
;;
|
|
575
|
+
esac
|
package/scripts/overview.sh
CHANGED
|
@@ -89,7 +89,7 @@ overview_set() {
|
|
|
89
89
|
eagle_upsert_overview "$project" "$content"
|
|
90
90
|
|
|
91
91
|
if [ "$json_output" = true ]; then
|
|
92
|
-
|
|
92
|
+
jq -nc --arg project "$project" '{project: $project, updated: true}'
|
|
93
93
|
return
|
|
94
94
|
fi
|
|
95
95
|
|
|
@@ -102,7 +102,7 @@ overview_delete() {
|
|
|
102
102
|
eagle_db "DELETE FROM overviews WHERE project = '$project_sql';"
|
|
103
103
|
|
|
104
104
|
if [ "$json_output" = true ]; then
|
|
105
|
-
|
|
105
|
+
jq -nc --arg project "$project" '{project: $project, deleted: true}'
|
|
106
106
|
return
|
|
107
107
|
fi
|
|
108
108
|
|
|
@@ -146,7 +146,21 @@ case "$action" in
|
|
|
146
146
|
delete|rm) overview_delete ;;
|
|
147
147
|
list|ls) overview_list ;;
|
|
148
148
|
--help|-h)
|
|
149
|
-
echo -e "
|
|
149
|
+
echo -e " ${BOLD}eagle-mem overview${RESET} — Manage project overviews"
|
|
150
|
+
echo ""
|
|
151
|
+
echo -e " ${BOLD}Usage:${RESET}"
|
|
152
|
+
echo -e " eagle-mem overview ${DIM}# show current overview${RESET}"
|
|
153
|
+
echo -e " eagle-mem overview ${CYAN}set${RESET} <text> ${DIM}# set/update overview${RESET}"
|
|
154
|
+
echo -e " eagle-mem overview ${CYAN}delete${RESET} ${DIM}# delete overview${RESET}"
|
|
155
|
+
echo -e " eagle-mem overview ${CYAN}list${RESET} ${DIM}# list all overviews${RESET}"
|
|
156
|
+
echo ""
|
|
157
|
+
echo -e " ${BOLD}Options:${RESET}"
|
|
158
|
+
echo -e " ${CYAN}-p, --project${RESET} <name> Project name (default: current dir)"
|
|
159
|
+
echo -e " ${CYAN}-j, --json${RESET} Output as JSON"
|
|
160
|
+
echo ""
|
|
161
|
+
echo -e " ${BOLD}Tip:${RESET} Use ${CYAN}eagle-mem scan${RESET} to auto-generate an overview from code."
|
|
162
|
+
echo ""
|
|
163
|
+
exit 0
|
|
150
164
|
;;
|
|
151
165
|
*)
|
|
152
166
|
eagle_err "Unknown action: $action"
|