eagle-mem 4.9.6 → 4.9.8

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.
@@ -24,8 +24,11 @@ case "${1:-}" in
24
24
  esac
25
25
 
26
26
  project=""
27
+ project_was_explicit=false
27
28
  limit=20
28
29
  query=""
30
+ raw_output=false
31
+ cross_project=false
29
32
 
30
33
  show_help() {
31
34
  echo -e " ${BOLD}eagle-mem memories${RESET} — Agent memory, plan & task mirror"
@@ -44,8 +47,10 @@ show_help() {
44
47
  echo -e " eagle-mem memories sync ${DIM}# backfill memories + plans + tasks${RESET}"
45
48
  echo ""
46
49
  echo -e " ${BOLD}Options:${RESET}"
47
- echo -e " ${CYAN}-p, --project${RESET} <name> Filter by project"
50
+ echo -e " ${CYAN}-p, --project${RESET} <name> Filter by project (default: current project)"
48
51
  echo -e " ${CYAN}-l, --limit${RESET} <N> Max results (default: 20)"
52
+ echo -e " ${CYAN}-a, --all${RESET} Show all projects"
53
+ echo -e " ${CYAN}--raw, --debug${RESET} Show source paths, sessions, and raw backing data"
49
54
  echo ""
50
55
  echo -e " ${BOLD}How it works:${RESET}"
51
56
  echo -e " ${DOT} Eagle Mem mirrors agent memory, plan, and task writes"
@@ -72,8 +77,10 @@ esac
72
77
 
73
78
  while [ $# -gt 0 ]; do
74
79
  case "$1" in
75
- --project|-p) project="$2"; shift 2 ;;
80
+ --project|-p) project="$2"; project_was_explicit=true; shift 2 ;;
76
81
  --limit|-l) limit="$2"; shift 2 ;;
82
+ --all|-a) cross_project=true; shift ;;
83
+ --raw|--debug) raw_output=true; shift ;;
77
84
  --help|-h) show_help ;;
78
85
  *)
79
86
  if [ -z "$query" ]; then
@@ -86,6 +93,42 @@ while [ $# -gt 0 ]; do
86
93
  esac
87
94
  done
88
95
 
96
+ if [ -z "$project" ] && [ "$cross_project" = false ]; then
97
+ project=$(eagle_project_from_cwd "$(pwd)")
98
+ fi
99
+ if [ "$cross_project" = false ] && [ "$project_was_explicit" = false ]; then
100
+ project=$(eagle_recall_project_scope_from_cwd "$(pwd)" "$project")
101
+ fi
102
+
103
+ eagle_age_label() {
104
+ local updated="${1:-}"
105
+ [ -z "$updated" ] && { printf 'unknown'; return; }
106
+ local days
107
+ days=$(eagle_db "SELECT CAST(julianday('now') - julianday('$(eagle_sql_escape "$updated")') AS INTEGER);" 2>/dev/null | awk 'NF {print; exit}')
108
+ if [ -z "$days" ]; then
109
+ printf 'unknown'
110
+ elif [ "$days" -le 0 ] 2>/dev/null; then
111
+ printf 'Fresh'
112
+ elif [ "$days" -le 14 ] 2>/dev/null; then
113
+ printf '%sd old' "$days"
114
+ elif [ "$days" -le 45 ] 2>/dev/null; then
115
+ printf 'Recent'
116
+ else
117
+ printf 'Older'
118
+ fi
119
+ }
120
+
121
+ eagle_print_wrapped_block() {
122
+ local text="${1:-}" indent="${2:- }" max_chars="${3:-1200}"
123
+ [ -z "$text" ] && return
124
+ printf '%s' "$text" | head -c "$max_chars" | while IFS= read -r line; do
125
+ printf '%s%s\n' "$indent" "$line"
126
+ done
127
+ if [ "${#text}" -gt "$max_chars" ] 2>/dev/null; then
128
+ printf '%s%s\n' "$indent" "..."
129
+ fi
130
+ }
131
+
89
132
  # ─── Actions ─────────────────────────────────────────────
90
133
 
91
134
  memories_list() {
@@ -116,9 +159,14 @@ memories_list() {
116
159
  reference) type_color="$BLUE" ;;
117
160
  esac
118
161
 
119
- echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
162
+ local age_label
163
+ age_label=$(eagle_age_label "$updated")
164
+ echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
120
165
  [ -n "$desc" ] && echo -e " ${DIM}${desc}${RESET}"
121
- echo -e " ${DIM}updated: ${updated}${RESET}"
166
+ if [ "$raw_output" = true ]; then
167
+ echo -e " ${DIM}file: $_fp${RESET}"
168
+ echo -e " ${DIM}updated: ${updated}${RESET}"
169
+ fi
122
170
  echo ""
123
171
  done <<< "$result"
124
172
 
@@ -158,12 +206,17 @@ memories_search() {
158
206
  reference) type_color="$BLUE" ;;
159
207
  esac
160
208
 
161
- echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
209
+ local age_label
210
+ age_label=$(eagle_age_label "$updated")
211
+ echo -e " ${BOLD}${name}${RESET} ${type_color}[${mtype}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
162
212
  [ -n "$desc" ] && echo -e " ${DIM}${desc}${RESET}"
163
213
  local snippet
164
214
  snippet=$(printf '%s' "$content" | head -c 200)
165
215
  [ -n "$snippet" ] && echo -e " ${snippet}"
166
- echo -e " ${DIM}updated: ${updated}${RESET}"
216
+ if [ "$raw_output" = true ]; then
217
+ echo -e " ${DIM}file: $_fp${RESET}"
218
+ echo -e " ${DIM}updated: ${updated}${RESET}"
219
+ fi
167
220
  echo ""
168
221
  done <<< "$result"
169
222
 
@@ -177,37 +230,63 @@ memories_show() {
177
230
  exit 1
178
231
  fi
179
232
 
180
- local meta
181
- meta=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at, origin_session_id, origin_agent
182
- FROM agent_memories WHERE file_path = '$(eagle_sql_escape "$query")';")
233
+ local query_sql project_filter meta_json
234
+ query_sql=$(eagle_sql_escape "$query")
235
+ project_filter=""
236
+ if [ -n "$project" ]; then
237
+ project_filter="AND $(eagle_sql_project_scope_condition "project" "$project")"
238
+ fi
183
239
 
184
- if [ -z "$meta" ]; then
240
+ meta_json=$(eagle_db_json "SELECT memory_name, memory_type, description, content, file_path, updated_at, origin_session_id, origin_agent
241
+ FROM agent_memories
242
+ WHERE (file_path = '$query_sql' OR memory_name = '$query_sql')
243
+ $project_filter
244
+ ORDER BY updated_at DESC
245
+ LIMIT 1;")
246
+
247
+ if [ -z "$meta_json" ] || [ "$(printf '%s' "$meta_json" | jq 'length' 2>/dev/null)" = "0" ]; then
185
248
  eagle_err "Memory not found: $query"
186
249
  exit 1
187
250
  fi
188
251
 
189
- IFS='|' read -r name mtype desc fp updated origin origin_agent <<< "$meta"
252
+ name=$(printf '%s' "$meta_json" | jq -r '.[0].memory_name // ""')
253
+ mtype=$(printf '%s' "$meta_json" | jq -r '.[0].memory_type // ""')
254
+ desc=$(printf '%s' "$meta_json" | jq -r '.[0].description // ""')
255
+ content=$(printf '%s' "$meta_json" | jq -r '.[0].content // ""')
256
+ fp=$(printf '%s' "$meta_json" | jq -r '.[0].file_path // ""')
257
+ updated=$(printf '%s' "$meta_json" | jq -r '.[0].updated_at // ""')
258
+ origin=$(printf '%s' "$meta_json" | jq -r '.[0].origin_session_id // ""')
259
+ origin_agent=$(printf '%s' "$meta_json" | jq -r '.[0].origin_agent // ""')
190
260
 
191
261
  eagle_header "Memory Detail"
192
262
 
193
263
  eagle_kv "Name:" "$name"
194
264
  eagle_kv "Type:" "$mtype"
195
- eagle_kv "File:" "$fp"
196
- eagle_kv "Updated:" "$updated"
197
265
  eagle_kv "Source:" "$(eagle_agent_label "$origin_agent")"
198
- [ -n "$origin" ] && eagle_kv "Session:" "$origin"
266
+ eagle_kv "Freshness:" "$(eagle_age_label "$updated")"
267
+ if [ "$raw_output" = true ]; then
268
+ eagle_kv "File:" "$fp"
269
+ eagle_kv "Updated:" "$updated"
270
+ [ -n "$origin" ] && eagle_kv "Session:" "$origin"
271
+ fi
199
272
  echo ""
200
273
 
201
274
  [ -n "$desc" ] && echo -e " ${BOLD}Description:${RESET} $desc"
202
275
  echo ""
203
276
 
204
- if [ -f "$fp" ]; then
277
+ if [ -n "$content" ]; then
205
278
  echo -e " ${BOLD}Content:${RESET}"
206
- awk '/^---$/{c++; next} c>=2' "$fp" | while IFS= read -r line; do
207
- echo " $line"
208
- done
209
- else
210
- eagle_dim "Source file no longer exists on disk."
279
+ eagle_print_wrapped_block "$content" " " 1600
280
+ fi
281
+
282
+ if [ "$raw_output" = true ]; then
283
+ echo ""
284
+ if [ -f "$fp" ]; then
285
+ echo -e " ${BOLD}Source file:${RESET}"
286
+ eagle_print_wrapped_block "$(cat "$fp")" " " 4000
287
+ else
288
+ eagle_dim "Source file no longer exists on disk."
289
+ fi
211
290
  fi
212
291
  echo ""
213
292
  }
@@ -235,8 +314,10 @@ plans_list() {
235
314
  local proj_label=""
236
315
  [ -n "$proj" ] && proj_label=" ${DIM}[${proj}]${RESET}"
237
316
 
238
- echo -e " ${BOLD}${title}${RESET}${proj_label} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
239
- echo -e " ${DIM}updated: ${updated}${RESET}"
317
+ local age_label
318
+ age_label=$(eagle_age_label "$updated")
319
+ echo -e " ${BOLD}${title}${RESET}${proj_label} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
320
+ [ "$raw_output" = true ] && echo -e " ${DIM}updated: ${updated}${RESET}"
240
321
  echo ""
241
322
  done <<< "$result"
242
323
 
@@ -271,9 +352,11 @@ plans_search() {
271
352
  local proj_label=""
272
353
  [ -n "$proj" ] && proj_label=" ${DIM}[${proj}]${RESET}"
273
354
 
274
- echo -e " ${BOLD}${title}${RESET}${proj_label} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
355
+ local age_label
356
+ age_label=$(eagle_age_label "$updated")
357
+ echo -e " ${BOLD}${title}${RESET}${proj_label} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
275
358
  [ -n "$snippet" ] && echo -e " ${snippet}"
276
- echo -e " ${DIM}updated: ${updated}${RESET}"
359
+ [ "$raw_output" = true ] && echo -e " ${DIM}updated: ${updated}${RESET}"
277
360
  echo ""
278
361
  done <<< "$result"
279
362
 
@@ -287,34 +370,58 @@ plans_show() {
287
370
  exit 1
288
371
  fi
289
372
 
290
- local meta
291
- meta=$(eagle_db "SELECT title, project, file_path, updated_at, origin_session_id, origin_agent
292
- FROM agent_plans WHERE file_path = '$(eagle_sql_escape "$query")';")
293
-
294
- if [ -z "$meta" ]; then
373
+ local query_sql project_filter meta_json
374
+ query_sql=$(eagle_sql_escape "$query")
375
+ project_filter=""
376
+ if [ -n "$project" ]; then
377
+ project_filter="AND $(eagle_sql_project_scope_condition "project" "$project")"
378
+ fi
379
+ meta_json=$(eagle_db_json "SELECT title, project, content, file_path, updated_at, origin_session_id, origin_agent
380
+ FROM agent_plans
381
+ WHERE (file_path = '$query_sql' OR title = '$query_sql')
382
+ $project_filter
383
+ ORDER BY updated_at DESC
384
+ LIMIT 1;")
385
+
386
+ if [ -z "$meta_json" ] || [ "$(printf '%s' "$meta_json" | jq 'length' 2>/dev/null)" = "0" ]; then
295
387
  eagle_err "Plan not found: $query"
296
388
  exit 1
297
389
  fi
298
390
 
299
- IFS='|' read -r title proj fp updated origin origin_agent <<< "$meta"
391
+ title=$(printf '%s' "$meta_json" | jq -r '.[0].title // ""')
392
+ proj=$(printf '%s' "$meta_json" | jq -r '.[0].project // ""')
393
+ content=$(printf '%s' "$meta_json" | jq -r '.[0].content // ""')
394
+ fp=$(printf '%s' "$meta_json" | jq -r '.[0].file_path // ""')
395
+ updated=$(printf '%s' "$meta_json" | jq -r '.[0].updated_at // ""')
396
+ origin=$(printf '%s' "$meta_json" | jq -r '.[0].origin_session_id // ""')
397
+ origin_agent=$(printf '%s' "$meta_json" | jq -r '.[0].origin_agent // ""')
300
398
 
301
399
  eagle_header "Plan Detail"
302
400
 
303
401
  eagle_kv "Title:" "$title"
304
402
  [ -n "$proj" ] && eagle_kv "Project:" "$proj"
305
- eagle_kv "File:" "$fp"
306
- eagle_kv "Updated:" "$updated"
307
403
  eagle_kv "Source:" "$(eagle_agent_label "$origin_agent")"
308
- [ -n "$origin" ] && eagle_kv "Session:" "$origin"
404
+ eagle_kv "Freshness:" "$(eagle_age_label "$updated")"
405
+ if [ "$raw_output" = true ]; then
406
+ eagle_kv "File:" "$fp"
407
+ eagle_kv "Updated:" "$updated"
408
+ [ -n "$origin" ] && eagle_kv "Session:" "$origin"
409
+ fi
309
410
  echo ""
310
411
 
311
- if [ -f "$fp" ]; then
412
+ if [ -n "$content" ]; then
312
413
  echo -e " ${BOLD}Content:${RESET}"
313
- cat "$fp" | while IFS= read -r line; do
314
- echo " $line"
315
- done
316
- else
317
- eagle_dim "Source file no longer exists on disk."
414
+ eagle_print_wrapped_block "$content" " " 2000
415
+ fi
416
+
417
+ if [ "$raw_output" = true ]; then
418
+ echo ""
419
+ if [ -f "$fp" ]; then
420
+ echo -e " ${BOLD}Source file:${RESET}"
421
+ eagle_print_wrapped_block "$(cat "$fp")" " " 4000
422
+ else
423
+ eagle_dim "Source file no longer exists on disk."
424
+ fi
318
425
  fi
319
426
  echo ""
320
427
  }
@@ -346,8 +453,12 @@ tasks_list() {
346
453
  completed) status_color="$GREEN" ;;
347
454
  esac
348
455
 
349
- echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
350
- echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
456
+ local age_label
457
+ age_label=$(eagle_age_label "$updated")
458
+ echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
459
+ if [ "$raw_output" = true ]; then
460
+ echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
461
+ fi
351
462
  echo ""
352
463
  done <<< "$result"
353
464
 
@@ -386,9 +497,13 @@ tasks_search() {
386
497
  completed) status_color="$GREEN" ;;
387
498
  esac
388
499
 
389
- echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")]${RESET}"
500
+ local age_label
501
+ age_label=$(eagle_age_label "$updated")
502
+ echo -e " ${BOLD}${subject}${RESET} ${status_color}[${status}]${RESET} ${DIM}[$(eagle_agent_label "$origin_agent")][$age_label]${RESET}"
390
503
  [ -n "$desc" ] && echo -e " ${desc}"
391
- echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
504
+ if [ "$raw_output" = true ]; then
505
+ echo -e " ${DIM}session: ${sid:0:8}… task: #${tid} updated: ${updated}${RESET}"
506
+ fi
392
507
  echo ""
393
508
  done <<< "$result"
394
509
 
@@ -402,38 +517,61 @@ tasks_show() {
402
517
  exit 1
403
518
  fi
404
519
 
405
- local meta
406
- meta=$(eagle_db "SELECT subject, status, description, active_form, source_session_id, source_task_id, file_path, updated_at, origin_agent
407
- FROM agent_tasks WHERE file_path = '$(eagle_sql_escape "$query")';")
408
-
409
- if [ -z "$meta" ]; then
520
+ local query_sql project_filter meta_json
521
+ query_sql=$(eagle_sql_escape "$query")
522
+ project_filter=""
523
+ if [ -n "$project" ]; then
524
+ project_filter="AND $(eagle_sql_project_scope_condition "project" "$project")"
525
+ fi
526
+ meta_json=$(eagle_db_json "SELECT subject, status, description, active_form, source_session_id, source_task_id, file_path, updated_at, origin_agent
527
+ FROM agent_tasks
528
+ WHERE (file_path = '$query_sql' OR source_task_id = '$query_sql' OR subject = '$query_sql')
529
+ $project_filter
530
+ ORDER BY updated_at DESC
531
+ LIMIT 1;")
532
+
533
+ if [ -z "$meta_json" ] || [ "$(printf '%s' "$meta_json" | jq 'length' 2>/dev/null)" = "0" ]; then
410
534
  eagle_err "Task not found: $query"
411
535
  exit 1
412
536
  fi
413
537
 
414
- IFS='|' read -r subject status desc af sid tid fp updated origin_agent <<< "$meta"
538
+ subject=$(printf '%s' "$meta_json" | jq -r '.[0].subject // ""')
539
+ status=$(printf '%s' "$meta_json" | jq -r '.[0].status // ""')
540
+ desc=$(printf '%s' "$meta_json" | jq -r '.[0].description // ""')
541
+ af=$(printf '%s' "$meta_json" | jq -r '.[0].active_form // ""')
542
+ sid=$(printf '%s' "$meta_json" | jq -r '.[0].source_session_id // ""')
543
+ tid=$(printf '%s' "$meta_json" | jq -r '.[0].source_task_id // ""')
544
+ fp=$(printf '%s' "$meta_json" | jq -r '.[0].file_path // ""')
545
+ updated=$(printf '%s' "$meta_json" | jq -r '.[0].updated_at // ""')
546
+ origin_agent=$(printf '%s' "$meta_json" | jq -r '.[0].origin_agent // ""')
415
547
 
416
548
  eagle_header "Task Detail"
417
549
 
418
550
  eagle_kv "Subject:" "$subject"
419
551
  eagle_kv "Status:" "$status"
420
- eagle_kv "Task ID:" "$tid"
421
- eagle_kv "Session:" "$sid"
422
- eagle_kv "File:" "$fp"
423
- eagle_kv "Updated:" "$updated"
424
552
  eagle_kv "Source:" "$(eagle_agent_label "$origin_agent")"
553
+ eagle_kv "Freshness:" "$(eagle_age_label "$updated")"
554
+ if [ "$raw_output" = true ]; then
555
+ eagle_kv "Task ID:" "$tid"
556
+ eagle_kv "Session:" "$sid"
557
+ eagle_kv "File:" "$fp"
558
+ eagle_kv "Updated:" "$updated"
559
+ fi
425
560
  echo ""
426
561
 
427
562
  [ -n "$desc" ] && echo -e " ${BOLD}Description:${RESET} $desc" && echo ""
428
563
  [ -n "$af" ] && echo -e " ${BOLD}Active Form:${RESET} $af" && echo ""
429
564
 
430
- if [ -f "$fp" ]; then
565
+ if [ "$raw_output" = true ]; then
566
+ echo ""
567
+ if [ -f "$fp" ]; then
431
568
  echo -e " ${BOLD}Raw JSON:${RESET}"
432
569
  jq '.' "$fp" 2>/dev/null | while IFS= read -r line; do
433
570
  echo " $line"
434
571
  done
435
- else
436
- eagle_dim "Source file no longer exists on disk."
572
+ else
573
+ eagle_dim "Source file no longer exists on disk."
574
+ fi
437
575
  fi
438
576
  echo ""
439
577
  }
@@ -441,6 +579,33 @@ tasks_show() {
441
579
  memories_sync() {
442
580
  eagle_header "Memory, Plan & Task Sync"
443
581
 
582
+ local lock_root="$EAGLE_MEM_DIR/locks"
583
+ local lock_dir="$lock_root/memories-sync.lock"
584
+ mkdir -p "$lock_root" 2>/dev/null || true
585
+ if mkdir "$lock_dir" 2>/dev/null; then
586
+ printf '%s\n' "$$" > "$lock_dir/pid" 2>/dev/null || true
587
+ _EAGLE_MEMORIES_SYNC_LOCK_DIR="$lock_dir"
588
+ trap 'rm -rf "${_EAGLE_MEMORIES_SYNC_LOCK_DIR:-}" 2>/dev/null || true' EXIT
589
+ else
590
+ local lock_pid=""
591
+ [ -f "$lock_dir/pid" ] && lock_pid=$(cat "$lock_dir/pid" 2>/dev/null | tr -cd '0-9')
592
+ if [ -n "$lock_pid" ] && kill -0 "$lock_pid" 2>/dev/null; then
593
+ eagle_info "Sync already running (pid $lock_pid). Skipping this duplicate run."
594
+ echo ""
595
+ eagle_footer "Sync skipped."
596
+ return 0
597
+ fi
598
+ rm -rf "$lock_dir" 2>/dev/null || true
599
+ if mkdir "$lock_dir" 2>/dev/null; then
600
+ printf '%s\n' "$$" > "$lock_dir/pid" 2>/dev/null || true
601
+ _EAGLE_MEMORIES_SYNC_LOCK_DIR="$lock_dir"
602
+ trap 'rm -rf "${_EAGLE_MEMORIES_SYNC_LOCK_DIR:-}" 2>/dev/null || true' EXIT
603
+ else
604
+ eagle_err "Could not acquire memories sync lock."
605
+ return 1
606
+ fi
607
+ fi
608
+
444
609
  # ─── Sync memories ───────────────────────────────────
445
610
  eagle_info "Scanning for agent memory files..."
446
611
  echo ""
@@ -449,15 +614,21 @@ memories_sync() {
449
614
  local mem_synced=0
450
615
  local mem_skipped=0
451
616
 
452
- if [ -d "$claude_mem_root" ]; then
453
- while IFS= read -r -d '' memfile; do
617
+ sync_one_memory_file() {
618
+ local memfile="$1"
619
+ [ -f "$memfile" ] || return 0
620
+
454
621
  local base
455
622
  base=$(basename "$memfile")
456
- [ "$base" = "MEMORY.md" ] && continue
623
+ [ "$base" = "MEMORY.md" ] && return 0
457
624
 
458
625
  local mem_project mem_project_dir existing_row existing_hash existing_project
459
626
  mem_project_dir="${memfile%/memory/*}"
460
627
  mem_project=$(eagle_project_from_claude_project_dir "$mem_project_dir" 2>/dev/null || true)
628
+ if [ "$cross_project" = false ] && [ -n "$project" ]; then
629
+ eagle_project_scope_contains "$project" "$mem_project" || return 0
630
+ fi
631
+
461
632
  existing_row=$(eagle_db "SELECT content_hash, project FROM agent_memories WHERE file_path = '$(eagle_sql_escape "$memfile")';")
462
633
  IFS='|' read -r existing_hash existing_project <<< "$existing_row"
463
634
  local new_hash
@@ -471,7 +642,25 @@ memories_sync() {
471
642
  eagle_capture_agent_memory "$memfile" "" "$mem_project" "claude-code"
472
643
  mem_synced=$((mem_synced + 1))
473
644
  eagle_ok "Memory: $base"
474
- done < <(find "$claude_mem_root" -path "*/memory/*.md" -print0 2>/dev/null)
645
+ }
646
+
647
+ if [ -d "$claude_mem_root" ]; then
648
+ if [ "$cross_project" = true ] || [ -z "$project" ]; then
649
+ while IFS= read -r -d '' memfile; do
650
+ sync_one_memory_file "$memfile"
651
+ done < <(find "$claude_mem_root" -path "*/memory/*.md" -print0 2>/dev/null)
652
+ else
653
+ while IFS= read -r scope_project; do
654
+ [ -z "$scope_project" ] && continue
655
+ scope_dir=$(eagle_claude_project_dir_for_key "$scope_project")
656
+ [ -d "$scope_dir/memory" ] || continue
657
+ while IFS= read -r -d '' memfile; do
658
+ sync_one_memory_file "$memfile"
659
+ done < <(find "$scope_dir/memory" -maxdepth 1 -type f -name "*.md" -print0 2>/dev/null)
660
+ done <<EOF
661
+ $(printf '%s' "$project" | tr '|' '\n')
662
+ EOF
663
+ fi
475
664
  fi
476
665
 
477
666
  local codex_mem_root="$EAGLE_CODEX_MEMORIES_DIR"
@@ -576,12 +765,16 @@ memories_sync() {
576
765
  # ─── Backfill project names ──────────────────────────
577
766
  eagle_info "Resolving project names from agent transcripts..."
578
767
 
579
- local backfilled
580
- backfilled=$(eagle_backfill_projects)
581
- if [ "${backfilled:-0}" -gt 0 ]; then
582
- eagle_ok "$backfilled rows updated with correct project names"
768
+ if [ "$cross_project" = true ]; then
769
+ local backfilled
770
+ backfilled=$(eagle_backfill_projects)
771
+ if [ "${backfilled:-0}" -gt 0 ]; then
772
+ eagle_ok "$backfilled rows updated with correct project names"
773
+ else
774
+ eagle_ok "All project names up to date"
775
+ fi
583
776
  else
584
- eagle_ok "All project names up to date"
777
+ eagle_ok "Scoped sync complete; use --all for global transcript backfill"
585
778
  fi
586
779
 
587
780
  eagle_footer "Sync complete."
@@ -797,9 +797,9 @@ orchestrate_worker_run_script() {
797
797
  printf 'printf "%%s\\n" "$rc" > %q\n' "$exit_path"
798
798
  printf 'date -u "+%%Y-%%m-%%dT%%H:%%M:%%SZ" > %q.done\n' "$exit_path"
799
799
  echo 'if [ "$rc" -eq 0 ]; then'
800
- printf ' bash %q orchestrate lane --project %q --name %q complete %q --notes %q >/dev/null 2>&1\n' "$bin_path" "$project" "$name" "$lane_key" "$complete_note"
800
+ printf ' bash %q orchestrate --project %q --name %q lane complete %q --notes %q >/dev/null 2>&1\n' "$bin_path" "$project" "$name" "$lane_key" "$complete_note"
801
801
  echo 'else'
802
- printf ' bash %q orchestrate lane --project %q --name %q block %q --notes %q >/dev/null 2>&1\n' "$bin_path" "$project" "$name" "$lane_key" "$block_note"
802
+ printf ' bash %q orchestrate --project %q --name %q lane block %q --notes %q >/dev/null 2>&1\n' "$bin_path" "$project" "$name" "$lane_key" "$block_note"
803
803
  echo 'fi'
804
804
  echo 'exit "$rc"'
805
805
  } > "$run_script"