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/lib/db.sh CHANGED
@@ -34,7 +34,7 @@ eagle_ensure_db() {
34
34
  }
35
35
 
36
36
  eagle_upsert_session() {
37
- local session_id="$1"
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="$1"
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="$1"
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="$5"
62
- local files_modified="$6"
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="${2:-5}"
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="${3:-10}"
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="${2:-20}"
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="$1"
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eagle-mem",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Lightweight persistent memory for Claude Code — SQLite + FTS5, no daemon, no bloat",
5
5
  "bin": {
6
6
  "eagle-mem": "bin/eagle-mem"
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}"
@@ -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
- EAGLE_MEM_DIR="${EAGLE_MEM_DIR:-$HOME/.eagle-mem}"
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
- SKILLS_DIR="$HOME/.claude/skills"
207
- if [ -d "$SKILLS_DIR" ] && [ -d "$PACKAGE_DIR/skills" ]; then
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="$SKILLS_DIR/$skill_name"
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"