eagle-mem 4.10.3 → 4.10.5
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/CHANGELOG.md +24 -0
- package/README.md +1 -1
- package/bin/eagle-mem +1 -0
- package/db/035_graph_memories.sql +65 -0
- package/db/036_graph_constraints.sql +37 -0
- package/db/037_task_dedup.sql +20 -0
- package/hooks/post-tool-use.sh +3 -3
- package/lib/db-graph.sh +138 -0
- package/lib/db.sh +1 -0
- package/package.json +1 -1
- package/scripts/curate.sh +160 -9
- package/scripts/index.sh +44 -0
- package/scripts/install.sh +211 -112
- package/scripts/memories.sh +119 -0
- package/scripts/scan.sh +23 -1
- package/scripts/test.sh +19 -1
package/scripts/install.sh
CHANGED
|
@@ -5,7 +5,44 @@
|
|
|
5
5
|
# ═══════════════════════════════════════════════════════════
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
DRY_RUN=0
|
|
9
|
+
PACKAGE_DIR="."
|
|
10
|
+
|
|
11
|
+
show_help() {
|
|
12
|
+
cat <<EOF
|
|
13
|
+
Usage: install.sh [options] [package_dir]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-h, --help Show this help message and exit
|
|
17
|
+
--dry-run Analyze and print what would be installed without mutating the system
|
|
18
|
+
|
|
19
|
+
Arguments:
|
|
20
|
+
package_dir Path to the eagle-mem package directory (defaults to current directory)
|
|
21
|
+
EOF
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
while [ $# -gt 0 ]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
-h|--help)
|
|
27
|
+
show_help
|
|
28
|
+
exit 0
|
|
29
|
+
;;
|
|
30
|
+
--dry-run)
|
|
31
|
+
DRY_RUN=1
|
|
32
|
+
shift
|
|
33
|
+
;;
|
|
34
|
+
-*)
|
|
35
|
+
echo "Unknown option: $1" >&2
|
|
36
|
+
echo "Run with -h or --help for usage details." >&2
|
|
37
|
+
exit 1
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
PACKAGE_DIR="$1"
|
|
41
|
+
shift
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
|
|
9
46
|
SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
47
|
LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
11
48
|
|
|
@@ -195,77 +232,94 @@ echo ""
|
|
|
195
232
|
echo -e " ${BOLD}Installing Eagle Mem...${RESET}"
|
|
196
233
|
echo ""
|
|
197
234
|
|
|
198
|
-
|
|
235
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
236
|
+
eagle_info "Would create directory: $EAGLE_MEM_DIR"
|
|
237
|
+
eagle_info "Would copy hooks, lib, db, scripts, and integrations to $EAGLE_MEM_DIR"
|
|
238
|
+
else
|
|
239
|
+
mkdir -p "$EAGLE_MEM_DIR"/{hooks,lib,db,scripts,integrations}
|
|
199
240
|
|
|
200
|
-
cp "$PACKAGE_DIR"/hooks/*.sh "$EAGLE_MEM_DIR/hooks/"
|
|
201
|
-
cp "$PACKAGE_DIR"/lib/*.sh "$EAGLE_MEM_DIR/lib/"
|
|
202
|
-
cp "$PACKAGE_DIR"/db/*.sh "$EAGLE_MEM_DIR/db/"
|
|
203
|
-
cp "$PACKAGE_DIR"/db/*.sql "$EAGLE_MEM_DIR/db/"
|
|
204
|
-
cp "$PACKAGE_DIR"/scripts/*.sh "$EAGLE_MEM_DIR/scripts/" 2>/dev/null
|
|
205
|
-
cp -r "$PACKAGE_DIR"/integrations/* "$EAGLE_MEM_DIR/integrations/" 2>/dev/null || true
|
|
241
|
+
cp "$PACKAGE_DIR"/hooks/*.sh "$EAGLE_MEM_DIR/hooks/"
|
|
242
|
+
cp "$PACKAGE_DIR"/lib/*.sh "$EAGLE_MEM_DIR/lib/"
|
|
243
|
+
cp "$PACKAGE_DIR"/db/*.sh "$EAGLE_MEM_DIR/db/"
|
|
244
|
+
cp "$PACKAGE_DIR"/db/*.sql "$EAGLE_MEM_DIR/db/"
|
|
245
|
+
cp "$PACKAGE_DIR"/scripts/*.sh "$EAGLE_MEM_DIR/scripts/" 2>/dev/null
|
|
246
|
+
cp -r "$PACKAGE_DIR"/integrations/* "$EAGLE_MEM_DIR/integrations/" 2>/dev/null || true
|
|
206
247
|
|
|
207
|
-
chmod +x "$EAGLE_MEM_DIR"/hooks/*.sh
|
|
208
|
-
chmod +x "$EAGLE_MEM_DIR"/db/migrate.sh
|
|
209
|
-
chmod +x "$EAGLE_MEM_DIR"/scripts/*.sh 2>/dev/null
|
|
248
|
+
chmod +x "$EAGLE_MEM_DIR"/hooks/*.sh
|
|
249
|
+
chmod +x "$EAGLE_MEM_DIR"/db/migrate.sh
|
|
250
|
+
chmod +x "$EAGLE_MEM_DIR"/scripts/*.sh 2>/dev/null
|
|
210
251
|
|
|
211
|
-
eagle_ok "Files copied to $EAGLE_MEM_DIR"
|
|
252
|
+
eagle_ok "Files copied to $EAGLE_MEM_DIR"
|
|
253
|
+
fi
|
|
212
254
|
|
|
213
255
|
# ─── Run migrations ────────────────────────────────────────
|
|
214
256
|
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
|
|
257
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
258
|
+
eagle_info "Would run database migrations using: $EAGLE_MEM_DIR/db/migrate.sh"
|
|
259
|
+
else
|
|
260
|
+
if ! "$EAGLE_MEM_DIR/db/migrate.sh" 2>/dev/null; then
|
|
261
|
+
eagle_err "Database migration failed"
|
|
262
|
+
exit 1
|
|
263
|
+
fi
|
|
264
|
+
eagle_ok "Database ready"
|
|
218
265
|
fi
|
|
219
|
-
eagle_ok "Database ready"
|
|
220
266
|
|
|
221
267
|
# ─── Patch settings.json ───────────────────────────────────
|
|
222
268
|
|
|
223
269
|
if [ "$claude_found" = true ]; then
|
|
224
|
-
if [
|
|
225
|
-
|
|
226
|
-
|
|
270
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
271
|
+
eagle_info "Would patch Claude Code settings.json at: $SETTINGS with hooks"
|
|
272
|
+
else
|
|
273
|
+
if [ ! -f "$SETTINGS" ]; then
|
|
274
|
+
echo '{}' > "$SETTINGS"
|
|
275
|
+
fi
|
|
227
276
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
277
|
+
eagle_patch_hook "$SETTINGS" "SessionStart" "" \
|
|
278
|
+
"$EAGLE_MEM_DIR/hooks/session-start.sh" \
|
|
279
|
+
"SessionStart hook"
|
|
231
280
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
281
|
+
eagle_patch_hook "$SETTINGS" "Stop" "" \
|
|
282
|
+
"$EAGLE_MEM_DIR/hooks/stop.sh" \
|
|
283
|
+
"Stop hook"
|
|
235
284
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
285
|
+
# Clean old registrations before re-registering (handles matcher changes across versions)
|
|
286
|
+
eagle_clean_hook_entries "$SETTINGS" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
287
|
+
eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
239
288
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
289
|
+
eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" \
|
|
290
|
+
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
291
|
+
"PostToolUse hook"
|
|
243
292
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
293
|
+
eagle_patch_hook "$SETTINGS" "TaskCreated" "" \
|
|
294
|
+
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
295
|
+
"TaskCreated hook"
|
|
247
296
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
297
|
+
eagle_patch_hook "$SETTINGS" "TaskCompleted" "" \
|
|
298
|
+
"$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
|
|
299
|
+
"TaskCompleted hook"
|
|
251
300
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
301
|
+
eagle_patch_hook "$SETTINGS" "SessionEnd" "" \
|
|
302
|
+
"$EAGLE_MEM_DIR/hooks/session-end.sh" \
|
|
303
|
+
"SessionEnd hook"
|
|
255
304
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
305
|
+
eagle_patch_hook "$SETTINGS" "UserPromptSubmit" "" \
|
|
306
|
+
"$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh" \
|
|
307
|
+
"UserPromptSubmit hook"
|
|
259
308
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
309
|
+
eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash|Read|Edit|Write" \
|
|
310
|
+
"$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
|
|
311
|
+
"PreToolUse hook"
|
|
312
|
+
fi
|
|
263
313
|
else
|
|
264
314
|
eagle_info "Claude hooks skipped ${DIM}(Claude Code not detected)${RESET}"
|
|
265
315
|
fi
|
|
266
316
|
|
|
267
317
|
if [ "$codex_found" = true ]; then
|
|
268
|
-
|
|
318
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
319
|
+
eagle_info "Would register Codex hooks"
|
|
320
|
+
else
|
|
321
|
+
eagle_register_codex_hooks
|
|
322
|
+
fi
|
|
269
323
|
else
|
|
270
324
|
eagle_info "Codex hooks skipped ${DIM}(Codex not detected)${RESET}"
|
|
271
325
|
fi
|
|
@@ -273,39 +327,51 @@ fi
|
|
|
273
327
|
# ─── Install skills ────────────────────────────────────────
|
|
274
328
|
|
|
275
329
|
if [ "$claude_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
330
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
331
|
+
eagle_info "Would symlink Claude Code skills to: $EAGLE_SKILLS_DIR"
|
|
332
|
+
else
|
|
333
|
+
mkdir -p "$EAGLE_SKILLS_DIR"
|
|
334
|
+
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
335
|
+
[ ! -d "$skill_dir" ] && continue
|
|
336
|
+
skill_name=$(basename "$skill_dir")
|
|
337
|
+
dst="$EAGLE_SKILLS_DIR/$skill_name"
|
|
338
|
+
[ -L "$dst" ] && rm "$dst"
|
|
339
|
+
ln -sf "$skill_dir" "$dst"
|
|
340
|
+
eagle_ok "Skill: $skill_name"
|
|
341
|
+
done
|
|
342
|
+
fi
|
|
285
343
|
fi
|
|
286
344
|
|
|
287
345
|
if [ "$codex_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
346
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
347
|
+
eagle_info "Would symlink Codex skills to: $EAGLE_CODEX_SKILLS_DIR"
|
|
348
|
+
else
|
|
349
|
+
mkdir -p "$EAGLE_CODEX_SKILLS_DIR"
|
|
350
|
+
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
351
|
+
[ ! -d "$skill_dir" ] && continue
|
|
352
|
+
skill_name=$(basename "$skill_dir")
|
|
353
|
+
dst="$EAGLE_CODEX_SKILLS_DIR/$skill_name"
|
|
354
|
+
[ -L "$dst" ] && rm "$dst"
|
|
355
|
+
ln -sf "$skill_dir" "$dst"
|
|
356
|
+
eagle_ok "Codex skill: $skill_name"
|
|
357
|
+
done
|
|
358
|
+
fi
|
|
297
359
|
fi
|
|
298
360
|
|
|
299
361
|
if [ "$grok_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
362
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
363
|
+
eagle_info "Would symlink Grok skills to: $EAGLE_GROK_SKILLS_DIR"
|
|
364
|
+
else
|
|
365
|
+
mkdir -p "$EAGLE_GROK_SKILLS_DIR"
|
|
366
|
+
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
367
|
+
[ ! -d "$skill_dir" ] && continue
|
|
368
|
+
skill_name=$(basename "$skill_dir")
|
|
369
|
+
dst="$EAGLE_GROK_SKILLS_DIR/$skill_name"
|
|
370
|
+
[ -L "$dst" ] && rm "$dst"
|
|
371
|
+
ln -sf "$skill_dir" "$dst"
|
|
372
|
+
eagle_ok "Grok skill: $skill_name"
|
|
373
|
+
done
|
|
374
|
+
fi
|
|
309
375
|
fi
|
|
310
376
|
|
|
311
377
|
# ─── Statusline integration ───────────────────────────────
|
|
@@ -316,9 +382,12 @@ if [ "$claude_found" = true ]; then
|
|
|
316
382
|
existing_sl_file=$(eagle_statusline_script_from_command "$existing_sl" 2>/dev/null || true)
|
|
317
383
|
|
|
318
384
|
if [ -z "$existing_sl" ]; then
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
385
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
386
|
+
eagle_info "Would create minimal statusline wrapper and register with Claude Code"
|
|
387
|
+
else
|
|
388
|
+
# No statusline configured — set up a minimal one that shows Eagle Mem
|
|
389
|
+
wrapper="$EAGLE_MEM_DIR/scripts/statusline-wrapper.sh"
|
|
390
|
+
cat > "$wrapper" << 'WRAPPER'
|
|
322
391
|
#!/usr/bin/env bash
|
|
323
392
|
input=$(cat)
|
|
324
393
|
project_dir=$(echo "$input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // ""' 2>/dev/null)
|
|
@@ -326,31 +395,36 @@ session_id=$(echo "$input" | jq -r '.session_id // .session.id // ""' 2>/dev/nul
|
|
|
326
395
|
source "$HOME/.eagle-mem/scripts/statusline-em.sh"
|
|
327
396
|
eagle_mem_statusline "$project_dir" "$session_id" "$input"
|
|
328
397
|
WRAPPER
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
398
|
+
chmod +x "$wrapper"
|
|
399
|
+
tmp=$(mktemp)
|
|
400
|
+
jq --arg cmd "sh $wrapper" '.statusLine = {"type": "command", "command": $cmd, "refreshInterval": 30}' "$SETTINGS" > "$tmp" && mv "$tmp" "$SETTINGS"
|
|
401
|
+
eagle_ok "Statusline ${DIM}(new — Eagle Mem indicator)${RESET}"
|
|
402
|
+
fi
|
|
333
403
|
else
|
|
334
404
|
# Existing statusline — if it points at a shell script, inspect the
|
|
335
405
|
# target file. Custom HUD commands often do not include "eagle-mem" in
|
|
336
406
|
# the command string even when the script contains an embedded block.
|
|
337
407
|
sl_file="$existing_sl_file"
|
|
338
408
|
if [ -n "$sl_file" ] && [ -f "$sl_file" ]; then
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
elif eagle_statusline_script_uses_input "$sl_file"; then
|
|
342
|
-
eagle_ok "Statusline ${DIM}(already has Eagle Mem)${RESET}"
|
|
409
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
410
|
+
eagle_info "Would inspect and patch existing statusline script: $sl_file"
|
|
343
411
|
else
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
412
|
+
if eagle_patch_statusline_script "$sl_file"; then
|
|
413
|
+
eagle_ok "Statusline ${DIM}(patched existing Eagle Mem block)${RESET}"
|
|
414
|
+
elif eagle_statusline_script_uses_input "$sl_file"; then
|
|
415
|
+
eagle_ok "Statusline ${DIM}(already has Eagle Mem)${RESET}"
|
|
416
|
+
else
|
|
417
|
+
eagle_dim " Statusline detected: $sl_file"
|
|
418
|
+
eagle_dim " To add Eagle Mem, add this snippet before your ASSEMBLE section:"
|
|
419
|
+
echo ""
|
|
420
|
+
eagle_dim " # ── Eagle Mem ──"
|
|
421
|
+
eagle_dim " em_section=\"\""
|
|
422
|
+
eagle_dim " if [ -f \"\$HOME/.eagle-mem/scripts/statusline-em.sh\" ]; then"
|
|
423
|
+
eagle_dim " em_section=\$(printf '%s' \"\$input\" | bash \"\$HOME/.eagle-mem/scripts/statusline-em.sh\" --hud)"
|
|
424
|
+
eagle_dim " fi"
|
|
425
|
+
echo ""
|
|
426
|
+
eagle_ok "Statusline ${DIM}(manual patch needed — instructions above)${RESET}"
|
|
427
|
+
fi
|
|
354
428
|
fi
|
|
355
429
|
elif echo "$existing_sl" | grep -q "eagle-mem"; then
|
|
356
430
|
eagle_ok "Statusline ${DIM}(already has Eagle Mem)${RESET}"
|
|
@@ -365,46 +439,71 @@ fi
|
|
|
365
439
|
. "$LIB_DIR/provider.sh"
|
|
366
440
|
. "$LIB_DIR/updater.sh"
|
|
367
441
|
if [ ! -f "$EAGLE_CONFIG_FILE" ]; then
|
|
368
|
-
|
|
369
|
-
|
|
442
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
443
|
+
eagle_info "Would initialize Eagle Mem config file at: $EAGLE_CONFIG_FILE"
|
|
444
|
+
else
|
|
445
|
+
eagle_config_init
|
|
446
|
+
eagle_ok "Config created ${DIM}(auto-detected provider)${RESET}"
|
|
447
|
+
fi
|
|
370
448
|
else
|
|
371
|
-
|
|
372
|
-
|
|
449
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
450
|
+
eagle_info "Would ensure config default variables are present"
|
|
451
|
+
else
|
|
452
|
+
eagle_update_ensure_defaults
|
|
453
|
+
eagle_ok "Config ${DIM}(already exists)${RESET}"
|
|
454
|
+
fi
|
|
373
455
|
fi
|
|
374
|
-
eagle_ok "Auto-updates ${DIM}(mode=$(eagle_update_config_mode), allow=$(eagle_update_config_allow))${RESET}"
|
|
456
|
+
[ "$DRY_RUN" -eq 0 ] && eagle_ok "Auto-updates ${DIM}(mode=$(eagle_update_config_mode), allow=$(eagle_update_config_allow))${RESET}"
|
|
375
457
|
|
|
376
458
|
# ─── Patch CLAUDE.md with Eagle Mem instructions ─────────
|
|
377
459
|
|
|
378
460
|
if [ "$claude_found" = true ]; then
|
|
379
|
-
if
|
|
380
|
-
|
|
461
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
462
|
+
eagle_info "Would patch CLAUDE.md in current directory with Eagle Mem guidelines"
|
|
381
463
|
else
|
|
382
|
-
|
|
464
|
+
if eagle_patch_claude_md; then
|
|
465
|
+
eagle_ok "CLAUDE.md ${DIM}(Eagle Mem guidance added)${RESET}"
|
|
466
|
+
else
|
|
467
|
+
eagle_ok "CLAUDE.md ${DIM}(already has Eagle Mem section)${RESET}"
|
|
468
|
+
fi
|
|
383
469
|
fi
|
|
384
470
|
fi
|
|
385
471
|
|
|
386
472
|
if [ "$codex_found" = true ]; then
|
|
387
|
-
if
|
|
388
|
-
|
|
473
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
474
|
+
eagle_info "Would patch AGENTS.md in current directory with Codex clean-output instructions"
|
|
389
475
|
else
|
|
390
|
-
|
|
476
|
+
if eagle_patch_codex_agents_md; then
|
|
477
|
+
eagle_ok "AGENTS.md ${DIM}(Codex clean-output memory instructions added)${RESET}"
|
|
478
|
+
else
|
|
479
|
+
eagle_ok "AGENTS.md ${DIM}(already has Eagle Mem section)${RESET}"
|
|
480
|
+
fi
|
|
391
481
|
fi
|
|
392
482
|
fi
|
|
393
483
|
|
|
394
484
|
# ─── Save installed version ───────────────────────────────
|
|
395
485
|
|
|
396
486
|
version=$(jq -r .version "$PACKAGE_DIR/package.json" 2>/dev/null || echo "unknown")
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
eagle_ok "Install manifest written"
|
|
487
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
488
|
+
eagle_info "Would write version $version to version tracking files"
|
|
489
|
+
eagle_info "Would write runtime manifest for install"
|
|
401
490
|
else
|
|
402
|
-
|
|
491
|
+
echo "$version" > "$EAGLE_MEM_DIR/.version"
|
|
492
|
+
echo "$version" > "$EAGLE_MEM_DIR/.latest-version"
|
|
493
|
+
if eagle_runtime_manifest_write "$PACKAGE_DIR" "install"; then
|
|
494
|
+
eagle_ok "Install manifest written"
|
|
495
|
+
else
|
|
496
|
+
eagle_warn "Install manifest could not be written"
|
|
497
|
+
fi
|
|
403
498
|
fi
|
|
404
499
|
|
|
405
500
|
# ─── Summary ───────────────────────────────────────────────
|
|
406
501
|
|
|
407
|
-
|
|
502
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
503
|
+
eagle_footer "Dry run complete. No modifications were made to the system."
|
|
504
|
+
else
|
|
505
|
+
eagle_footer "Eagle Mem installed successfully."
|
|
506
|
+
fi
|
|
408
507
|
|
|
409
508
|
eagle_kv "Database:" "$EAGLE_MEM_DIR/memory.db"
|
|
410
509
|
eagle_kv "Hooks:" "$EAGLE_MEM_DIR/hooks/"
|
package/scripts/memories.sh
CHANGED
|
@@ -45,6 +45,9 @@ show_help() {
|
|
|
45
45
|
echo -e " eagle-mem memories tasks search ${CYAN}<query>${RESET} ${DIM}# full-text search tasks${RESET}"
|
|
46
46
|
echo -e " eagle-mem memories tasks show ${CYAN}<file_path>${RESET} ${DIM}# show a specific task${RESET}"
|
|
47
47
|
echo -e " eagle-mem memories sync ${DIM}# backfill memories + plans + tasks${RESET}"
|
|
48
|
+
echo -e " eagle-mem memories graph ${DIM}# view codebase knowledge graph summary${RESET}"
|
|
49
|
+
echo -e " eagle-mem memories graph query ${CYAN}<term>${RESET} ${DIM}# search knowledge graph nodes${RESET}"
|
|
50
|
+
echo -e " eagle-mem memories graph neighbors ${CYAN}<name>${RESET} ${DIM}# view a node's local network connections${RESET}"
|
|
48
51
|
echo ""
|
|
49
52
|
echo -e " ${BOLD}Options:${RESET}"
|
|
50
53
|
echo -e " ${CYAN}-p, --project${RESET} <name> Filter by project (default: current project)"
|
|
@@ -62,6 +65,7 @@ show_help() {
|
|
|
62
65
|
|
|
63
66
|
plan_action=""
|
|
64
67
|
task_action=""
|
|
68
|
+
graph_action=""
|
|
65
69
|
|
|
66
70
|
case "$action" in
|
|
67
71
|
--help|-h) show_help ;;
|
|
@@ -73,6 +77,10 @@ case "$action" in
|
|
|
73
77
|
task_action="${1:-list}"
|
|
74
78
|
shift 2>/dev/null || true
|
|
75
79
|
;;
|
|
80
|
+
graph)
|
|
81
|
+
graph_action="${1:-summary}"
|
|
82
|
+
shift 2>/dev/null || true
|
|
83
|
+
;;
|
|
76
84
|
esac
|
|
77
85
|
|
|
78
86
|
while [ $# -gt 0 ]; do
|
|
@@ -858,6 +866,116 @@ EOF
|
|
|
858
866
|
eagle_footer "Sync complete."
|
|
859
867
|
}
|
|
860
868
|
|
|
869
|
+
memories_graph() {
|
|
870
|
+
local sub_action="${graph_action:-summary}"
|
|
871
|
+
|
|
872
|
+
case "$sub_action" in
|
|
873
|
+
query)
|
|
874
|
+
local qstr="${query:-}"
|
|
875
|
+
if [ -z "$qstr" ]; then
|
|
876
|
+
eagle_err "Usage: eagle-mem memories graph query <search_term>"
|
|
877
|
+
exit 1
|
|
878
|
+
fi
|
|
879
|
+
eagle_header "Knowledge Graph Query"
|
|
880
|
+
eagle_info "Search Term: $qstr"
|
|
881
|
+
echo ""
|
|
882
|
+
|
|
883
|
+
local nodes
|
|
884
|
+
nodes=$(eagle_graph_search "$project" "$qstr" "")
|
|
885
|
+
if [ -z "$nodes" ]; then
|
|
886
|
+
eagle_dim "No graph nodes found matching '$qstr'."
|
|
887
|
+
echo ""
|
|
888
|
+
return
|
|
889
|
+
fi
|
|
890
|
+
|
|
891
|
+
while IFS='|' read -r nid ntype nname nval npath; do
|
|
892
|
+
[ -z "$nid" ] && continue
|
|
893
|
+
echo -e " ${BOLD}${nname}${RESET} ${CYAN}[${ntype}]${RESET} ${DIM}(ID: ${nid})${RESET}"
|
|
894
|
+
[ -n "$nval" ] && echo -e " ${DIM}${nval}${RESET}"
|
|
895
|
+
[ -n "$npath" ] && echo -e " ${DIM}Path: ${npath}${RESET}"
|
|
896
|
+
echo ""
|
|
897
|
+
done <<< "$nodes"
|
|
898
|
+
;;
|
|
899
|
+
neighbors)
|
|
900
|
+
local target_name="${query:-}"
|
|
901
|
+
if [ -z "$target_name" ]; then
|
|
902
|
+
eagle_err "Usage: eagle-mem memories graph neighbors <node_name>"
|
|
903
|
+
exit 1
|
|
904
|
+
fi
|
|
905
|
+
|
|
906
|
+
# Find node by name (fuzzy or exact)
|
|
907
|
+
local matched
|
|
908
|
+
matched=$(eagle_db "SELECT id, node_type, node_name FROM graph_nodes WHERE project = '$(eagle_sql_escape "$project")' AND (node_name = '$(eagle_sql_escape "$target_name")' OR node_name LIKE '%$(eagle_sql_escape "$target_name")%') LIMIT 1;")
|
|
909
|
+
if [ -z "$matched" ]; then
|
|
910
|
+
eagle_err "Node not found matching '$target_name'."
|
|
911
|
+
exit 1
|
|
912
|
+
fi
|
|
913
|
+
|
|
914
|
+
IFS='|' read -r nid ntype nname <<< "$matched"
|
|
915
|
+
eagle_header "Graph Neighbors"
|
|
916
|
+
eagle_info "Node: ${BOLD}${nname}${RESET} ${CYAN}[${ntype}]${RESET} (ID: ${nid})"
|
|
917
|
+
echo ""
|
|
918
|
+
|
|
919
|
+
# Query inbound and outbound neighbors
|
|
920
|
+
eagle_info "Outbound Connections (Node interacts with/references/contains):"
|
|
921
|
+
local outbound
|
|
922
|
+
outbound=$(eagle_graph_query_neighbors "$nid" "out")
|
|
923
|
+
if [ -n "$outbound" ]; then
|
|
924
|
+
while IFS='|' read -r etype eweight target_id target_type target_name _; do
|
|
925
|
+
[ -z "$target_id" ] && continue
|
|
926
|
+
echo -e " ${BOLD}───[ ${etype} ]───>${RESET} ${CYAN}${target_name}${RESET} [${target_type}] ${DIM}(weight: ${eweight})${RESET}"
|
|
927
|
+
done <<< "$outbound"
|
|
928
|
+
else
|
|
929
|
+
eagle_dim " None"
|
|
930
|
+
fi
|
|
931
|
+
echo ""
|
|
932
|
+
|
|
933
|
+
eagle_info "Inbound Connections (Other nodes reference/call/contain this node):"
|
|
934
|
+
local inbound
|
|
935
|
+
inbound=$(eagle_graph_query_neighbors "$nid" "in")
|
|
936
|
+
if [ -n "$inbound" ]; then
|
|
937
|
+
while IFS='|' read -r etype eweight source_id source_type source_name _; do
|
|
938
|
+
[ -z "$source_id" ] && continue
|
|
939
|
+
echo -e " ${CYAN}${source_name}${RESET} [${source_type}] ${BOLD}───[ ${etype} ]───>${RESET} this ${DIM}(weight: ${eweight})${RESET}"
|
|
940
|
+
done <<< "$inbound"
|
|
941
|
+
else
|
|
942
|
+
eagle_dim " None"
|
|
943
|
+
fi
|
|
944
|
+
echo ""
|
|
945
|
+
;;
|
|
946
|
+
summary|*)
|
|
947
|
+
eagle_header "Knowledge Graph Summary"
|
|
948
|
+
echo ""
|
|
949
|
+
|
|
950
|
+
local totals
|
|
951
|
+
totals=$(eagle_db "SELECT node_type, COUNT(*) FROM graph_nodes WHERE project = '$(eagle_sql_escape "$project")' GROUP BY node_type;")
|
|
952
|
+
|
|
953
|
+
local total_edges
|
|
954
|
+
total_edges=$(eagle_db "SELECT COUNT(*) FROM graph_edges WHERE project = '$(eagle_sql_escape "$project")';")
|
|
955
|
+
|
|
956
|
+
if [ -z "$totals" ]; then
|
|
957
|
+
eagle_dim "Graph is empty for this project."
|
|
958
|
+
eagle_dim "Run 'eagle-mem scan' or 'eagle-mem index' to auto-populate codebase nodes."
|
|
959
|
+
echo ""
|
|
960
|
+
return
|
|
961
|
+
fi
|
|
962
|
+
|
|
963
|
+
eagle_info "Entities (Nodes):"
|
|
964
|
+
while IFS='|' read -r ntype count; do
|
|
965
|
+
[ -z "$ntype" ] && continue
|
|
966
|
+
eagle_kv " ${ntype}:" "${count} nodes"
|
|
967
|
+
done <<< "$totals"
|
|
968
|
+
echo ""
|
|
969
|
+
eagle_kv "Total relationships (Edges):" "${total_edges:-0} edges"
|
|
970
|
+
echo ""
|
|
971
|
+
eagle_dim "Commands:"
|
|
972
|
+
eagle_dim " eagle-mem memories graph query <search_term> # search graph nodes"
|
|
973
|
+
eagle_dim " eagle-mem memories graph neighbors <node_name> # view neighbor connections"
|
|
974
|
+
echo ""
|
|
975
|
+
;;
|
|
976
|
+
esac
|
|
977
|
+
}
|
|
978
|
+
|
|
861
979
|
# ─── Dispatch ────────────────────────────────────────────
|
|
862
980
|
|
|
863
981
|
case "$action" in
|
|
@@ -880,6 +998,7 @@ case "$action" in
|
|
|
880
998
|
*) tasks_list ;;
|
|
881
999
|
esac
|
|
882
1000
|
;;
|
|
1001
|
+
graph) memories_graph "$@" ;;
|
|
883
1002
|
sync) memories_sync ;;
|
|
884
1003
|
*)
|
|
885
1004
|
eagle_err "Unknown action: $action"
|
package/scripts/scan.sh
CHANGED
|
@@ -367,7 +367,29 @@ fi
|
|
|
367
367
|
# Store in database
|
|
368
368
|
eagle_upsert_overview "$PROJECT" "$overview" "scan"
|
|
369
369
|
|
|
370
|
-
|
|
370
|
+
# Populate/wire codebase knowledge graph
|
|
371
|
+
eagle_graph_add_node "$PROJECT" "project" "$PROJECT" "$overview" ""
|
|
372
|
+
project_node_id=$(eagle_graph_get_node_id "$PROJECT" "project" "$PROJECT")
|
|
373
|
+
|
|
374
|
+
# Prune deleted/removed files from graph
|
|
375
|
+
eagle_graph_prune_orphans "$PROJECT"
|
|
376
|
+
|
|
377
|
+
file_node_count=0
|
|
378
|
+
if [ -n "$project_node_id" ]; then
|
|
379
|
+
while IFS= read -r file; do
|
|
380
|
+
[ -z "$file" ] && continue
|
|
381
|
+
# Add file node
|
|
382
|
+
eagle_graph_add_node "$PROJECT" "file" "$file" "" "$TARGET_DIR/$file"
|
|
383
|
+
file_node_id=$(eagle_graph_get_node_id "$PROJECT" "file" "$file")
|
|
384
|
+
if [ -n "$file_node_id" ]; then
|
|
385
|
+
# Connect project containing this file
|
|
386
|
+
eagle_graph_add_edge "$PROJECT" "$project_node_id" "$file_node_id" "contains" 1.0
|
|
387
|
+
fi
|
|
388
|
+
file_node_count=$((file_node_count + 1))
|
|
389
|
+
done < "$TMPFILE"
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
eagle_ok "Overview saved for project '$PROJECT' (wired $file_node_count files in knowledge graph)"
|
|
371
393
|
echo ""
|
|
372
394
|
|
|
373
395
|
echo -e " ${BOLD}Generated overview:${RESET}"
|
package/scripts/test.sh
CHANGED
|
@@ -38,11 +38,29 @@ run_check "health runs" "\"$EAGLE_BIN\" health --json > /dev/null"
|
|
|
38
38
|
run_check "tasks list works" "\"$EAGLE_BIN\" tasks --json > /dev/null"
|
|
39
39
|
run_check "tasks stale works" "\"$EAGLE_BIN\" tasks stale --json > /dev/null"
|
|
40
40
|
run_check "compaction status works" "\"$EAGLE_BIN\" compaction > /dev/null"
|
|
41
|
-
run_check "no pending feature blocks (or acknowledged)" "true"
|
|
41
|
+
run_check "no pending feature blocks (or acknowledged)" "true"
|
|
42
|
+
|
|
43
|
+
echo ""
|
|
44
|
+
echo -e " ${BOLD}Core Feature Smoke Tests${RESET}"
|
|
45
|
+
echo ""
|
|
46
|
+
|
|
47
|
+
run_check "Feature Verification (feature list / pending)" "\"$EAGLE_BIN\" feature list > /dev/null && \"$EAGLE_BIN\" feature pending > /dev/null"
|
|
48
|
+
run_check "Compaction Survival (compaction analyze)" "\"$EAGLE_BIN\" compaction --json > /dev/null"
|
|
49
|
+
run_check "Grok CLI Integration (grok-bootstrap syntax)" "bash -n \"$SCRIPTS_DIR/grok-bootstrap.sh\""
|
|
50
|
+
run_check "Agent Orchestration (orchestrate help)" "\"$EAGLE_BIN\" orchestrate --help > /dev/null"
|
|
51
|
+
run_check "Cross Agent Memory (memories query)" "\"$EAGLE_BIN\" memories --json > /dev/null"
|
|
52
|
+
run_check "Installer And Updater (install / update syntax)" "bash -n \"$SCRIPTS_DIR/install.sh\" && bash -n \"$SCRIPTS_DIR/update.sh\""
|
|
53
|
+
run_check "Code Scan And Index (scan / index syntax)" "bash -n \"$SCRIPTS_DIR/scan.sh\" && bash -n \"$SCRIPTS_DIR/index.sh\""
|
|
42
54
|
|
|
43
55
|
echo ""
|
|
44
56
|
if [ "$errors" -eq 0 ]; then
|
|
45
57
|
eagle_ok "All smoke tests passed"
|
|
58
|
+
|
|
59
|
+
# Auto-verify the 7 core features in the database
|
|
60
|
+
for feat in "compaction-survival" "feature-verification" "grok-cli-integration" "agent-orchestration" "Cross Agent Memory" "Installer And Updater" "Code Scan And Index"; do
|
|
61
|
+
"$EAGLE_BIN" feature verify "$feat" --notes "verified via automated scripts/test.sh smoke test suite" >/dev/null 2>&1 || true
|
|
62
|
+
done
|
|
63
|
+
eagle_ok "Auto-verified the 7 core features in the database"
|
|
46
64
|
else
|
|
47
65
|
eagle_fail "$errors smoke test(s) failed"
|
|
48
66
|
exit 1
|