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.
@@ -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
@@ -89,7 +89,7 @@ overview_set() {
89
89
  eagle_upsert_overview "$project" "$content"
90
90
 
91
91
  if [ "$json_output" = true ]; then
92
- printf '{"project":"%s","updated":true}\n' "$project"
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
- printf '{"project":"%s","deleted":true}\n' "$project"
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 " Run ${CYAN}eagle-mem overview --help${RESET} for usage"
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"