eagle-mem 4.6.2 → 4.7.1
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/README.md +49 -15
- package/db/023_guardrails.sql +3 -2
- package/db/024_guardrails_unique.sql +46 -0
- package/db/025_pending_feature_verifications.sql +30 -0
- package/db/026_agent_source.sql +18 -0
- package/db/027_feature_verification_fingerprints.sql +9 -0
- package/db/028_agent_artifact_tables.sql +124 -0
- package/hooks/post-tool-use.sh +42 -13
- package/hooks/pre-tool-use.sh +107 -14
- package/hooks/session-end.sh +3 -1
- package/hooks/session-start.sh +64 -15
- package/hooks/stop.sh +115 -21
- package/hooks/user-prompt-submit.sh +14 -5
- package/lib/codex-hooks.sh +194 -0
- package/lib/common.sh +345 -0
- package/lib/db-backfill.sh +3 -3
- package/lib/db-features.sh +222 -0
- package/lib/db-guardrails.sh +2 -1
- package/lib/db-mirrors.sh +79 -43
- package/lib/db-observations.sh +3 -2
- package/lib/db-sessions.sh +11 -7
- package/lib/db-summaries.sh +9 -6
- package/lib/hooks-posttool.sh +8 -6
- package/lib/provider.sh +190 -4
- package/package.json +7 -3
- package/scripts/config.sh +2 -0
- package/scripts/feature.sh +70 -2
- package/scripts/guard.sh +4 -1
- package/scripts/health.sh +5 -1
- package/scripts/help.sh +13 -8
- package/scripts/install.sh +130 -76
- package/scripts/memories.sh +71 -45
- package/scripts/refresh.sh +3 -3
- package/scripts/search.sh +57 -47
- package/scripts/statusline-em.sh +1 -1
- package/scripts/tasks.sh +186 -15
- package/scripts/uninstall.sh +7 -0
- package/scripts/update.sh +51 -7
- package/skills/eagle-mem-memories/SKILL.md +13 -13
- package/skills/eagle-mem-tasks/SKILL.md +21 -15
package/scripts/search.sh
CHANGED
|
@@ -26,7 +26,7 @@ show_help() {
|
|
|
26
26
|
echo -e " eagle-mem search ${CYAN}--files${RESET} ${DIM}# frequently modified files${RESET}"
|
|
27
27
|
echo -e " eagle-mem search ${CYAN}--stats${RESET} ${DIM}# project statistics${RESET}"
|
|
28
28
|
echo -e " eagle-mem search ${CYAN}--overview${RESET} ${DIM}# project overview${RESET}"
|
|
29
|
-
echo -e " eagle-mem search ${CYAN}--memories${RESET} ${DIM}# mirrored
|
|
29
|
+
echo -e " eagle-mem search ${CYAN}--memories${RESET} ${DIM}# mirrored agent memories${RESET}"
|
|
30
30
|
echo -e " eagle-mem search ${CYAN}--tasks${RESET} ${DIM}# in-flight tasks${RESET}"
|
|
31
31
|
echo ""
|
|
32
32
|
echo -e " ${BOLD}Options:${RESET}"
|
|
@@ -93,7 +93,7 @@ search_keyword() {
|
|
|
93
93
|
fi
|
|
94
94
|
|
|
95
95
|
if [ "$json_output" = true ]; then
|
|
96
|
-
eagle_db_json "SELECT s.id, s.project, s.request, s.completed, s.learned, s.created_at
|
|
96
|
+
eagle_db_json "SELECT s.id, s.project, s.agent, s.request, s.completed, s.learned, s.created_at
|
|
97
97
|
FROM summaries s
|
|
98
98
|
JOIN summaries_fts f ON f.rowid = s.id
|
|
99
99
|
WHERE summaries_fts MATCH '$q'
|
|
@@ -104,7 +104,7 @@ search_keyword() {
|
|
|
104
104
|
fi
|
|
105
105
|
|
|
106
106
|
local results
|
|
107
|
-
results=$(eagle_db "SELECT s.id, s.project, s.request, s.completed, s.learned, s.created_at
|
|
107
|
+
results=$(eagle_db "SELECT s.id, s.project, s.agent, s.request, s.completed, s.learned, s.created_at
|
|
108
108
|
FROM summaries s
|
|
109
109
|
JOIN summaries_fts f ON f.rowid = s.id
|
|
110
110
|
WHERE summaries_fts MATCH '$q'
|
|
@@ -118,12 +118,13 @@ search_keyword() {
|
|
|
118
118
|
fi
|
|
119
119
|
|
|
120
120
|
echo ""
|
|
121
|
-
while IFS='|' read -r sid sproj req completed learned created_at; do
|
|
121
|
+
while IFS='|' read -r sid sproj sagent req completed learned created_at; do
|
|
122
122
|
[ -z "$sid" ] && continue
|
|
123
123
|
echo -e " ${BOLD}#$sid${RESET} ${DIM}$created_at${RESET}"
|
|
124
124
|
if [ "$cross_project" = true ]; then
|
|
125
125
|
echo -e " ${DIM}project:${RESET} $sproj"
|
|
126
126
|
fi
|
|
127
|
+
echo -e " ${DIM}source:${RESET} $(eagle_agent_label "$sagent")"
|
|
127
128
|
[ -n "$req" ] && echo -e " ${CYAN}Request:${RESET} $req"
|
|
128
129
|
[ -n "$completed" ] && echo -e " ${GREEN}Done:${RESET} $completed"
|
|
129
130
|
[ -n "$learned" ] && echo -e " ${YELLOW}Learned:${RESET} $learned"
|
|
@@ -137,7 +138,7 @@ search_timeline() {
|
|
|
137
138
|
local p; p=$(eagle_sql_escape "$project")
|
|
138
139
|
|
|
139
140
|
if [ "$json_output" = true ]; then
|
|
140
|
-
eagle_db_json "SELECT s.id, s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
141
|
+
eagle_db_json "SELECT s.id, s.agent, s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
141
142
|
FROM summaries s
|
|
142
143
|
WHERE s.project = '$p'
|
|
143
144
|
ORDER BY s.created_at DESC
|
|
@@ -146,7 +147,7 @@ search_timeline() {
|
|
|
146
147
|
fi
|
|
147
148
|
|
|
148
149
|
local results
|
|
149
|
-
results=$(eagle_db "SELECT s.id, s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
150
|
+
results=$(eagle_db "SELECT s.id, s.agent, s.request, s.completed, s.learned, s.next_steps, s.created_at
|
|
150
151
|
FROM summaries s
|
|
151
152
|
WHERE s.project = '$p'
|
|
152
153
|
ORDER BY s.created_at DESC
|
|
@@ -162,9 +163,10 @@ search_timeline() {
|
|
|
162
163
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
163
164
|
echo ""
|
|
164
165
|
|
|
165
|
-
while IFS='|' read -r sid req completed learned next_steps created_at; do
|
|
166
|
+
while IFS='|' read -r sid sagent req completed learned next_steps created_at; do
|
|
166
167
|
[ -z "$sid" ] && continue
|
|
167
168
|
echo -e " ${BOLD}#$sid${RESET} ${DIM}$created_at${RESET}"
|
|
169
|
+
echo -e " ${DIM}source:${RESET} $(eagle_agent_label "$sagent")"
|
|
168
170
|
[ -n "$req" ] && echo -e " ${CYAN}Request:${RESET} $req"
|
|
169
171
|
[ -n "$completed" ] && echo -e " ${GREEN}Done:${RESET} $completed"
|
|
170
172
|
[ -n "$learned" ] && echo -e " ${YELLOW}Learned:${RESET} $learned"
|
|
@@ -179,7 +181,7 @@ search_session() {
|
|
|
179
181
|
local sid_sql; sid_sql=$(eagle_sql_escape "$session_id")
|
|
180
182
|
|
|
181
183
|
if [ "$json_output" = true ]; then
|
|
182
|
-
eagle_db_json "SELECT o.tool_name, o.tool_input_summary, o.files_read, o.files_modified, o.created_at
|
|
184
|
+
eagle_db_json "SELECT o.agent, o.tool_name, o.tool_input_summary, o.files_read, o.files_modified, o.created_at
|
|
183
185
|
FROM observations o
|
|
184
186
|
WHERE o.session_id = '$sid_sql'
|
|
185
187
|
ORDER BY o.created_at ASC;"
|
|
@@ -187,7 +189,7 @@ search_session() {
|
|
|
187
189
|
fi
|
|
188
190
|
|
|
189
191
|
local results
|
|
190
|
-
results=$(eagle_db "SELECT o.tool_name, o.tool_input_summary, o.files_read, o.files_modified, o.created_at
|
|
192
|
+
results=$(eagle_db "SELECT o.agent, o.tool_name, o.tool_input_summary, o.files_read, o.files_modified, o.created_at
|
|
191
193
|
FROM observations o
|
|
192
194
|
WHERE o.session_id = '$sid_sql'
|
|
193
195
|
ORDER BY o.created_at ASC;")
|
|
@@ -202,7 +204,7 @@ search_session() {
|
|
|
202
204
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
203
205
|
echo ""
|
|
204
206
|
|
|
205
|
-
while IFS='|' read -r tool_name summary files_r files_m created_at; do
|
|
207
|
+
while IFS='|' read -r oagent tool_name summary files_r files_m created_at; do
|
|
206
208
|
[ -z "$tool_name" ] && continue
|
|
207
209
|
local icon="$DOT"
|
|
208
210
|
case "$tool_name" in
|
|
@@ -211,7 +213,7 @@ search_session() {
|
|
|
211
213
|
Edit) icon="${YELLOW}E${RESET}" ;;
|
|
212
214
|
Bash) icon="${BLUE}\$${RESET}" ;;
|
|
213
215
|
esac
|
|
214
|
-
echo -e " ${icon} ${DIM}$created_at${RESET} $summary"
|
|
216
|
+
echo -e " ${icon} ${DIM}$created_at $(eagle_agent_label "$oagent")${RESET} $summary"
|
|
215
217
|
done <<< "$results"
|
|
216
218
|
echo ""
|
|
217
219
|
}
|
|
@@ -261,22 +263,26 @@ search_files() {
|
|
|
261
263
|
search_stats() {
|
|
262
264
|
local p; p=$(eagle_sql_escape "$project")
|
|
263
265
|
|
|
264
|
-
local sessions summaries observations tasks
|
|
266
|
+
local sessions sessions_claude sessions_codex summaries observations tasks
|
|
265
267
|
sessions=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p';")
|
|
268
|
+
sessions_claude=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p' AND agent = 'claude-code';")
|
|
269
|
+
sessions_codex=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p' AND agent = 'codex';")
|
|
266
270
|
summaries=$(eagle_db "SELECT COUNT(*) FROM summaries WHERE project = '$p';")
|
|
267
271
|
observations=$(eagle_db "SELECT COUNT(*) FROM observations o JOIN sessions s ON s.id = o.session_id WHERE s.project = '$p';")
|
|
268
|
-
tasks=$(eagle_db "SELECT COUNT(*) FROM
|
|
272
|
+
tasks=$(eagle_db "SELECT COUNT(*) FROM agent_tasks WHERE project = '$p';")
|
|
269
273
|
local chunks
|
|
270
274
|
chunks=$(eagle_db "SELECT COUNT(*) FROM code_chunks WHERE project = '$p';")
|
|
271
275
|
|
|
272
276
|
if [ "$json_output" = true ]; then
|
|
273
277
|
jq -nc --arg project "$project" \
|
|
274
278
|
--argjson sessions "${sessions:-0}" \
|
|
279
|
+
--argjson sessions_claude "${sessions_claude:-0}" \
|
|
280
|
+
--argjson sessions_codex "${sessions_codex:-0}" \
|
|
275
281
|
--argjson summaries "${summaries:-0}" \
|
|
276
282
|
--argjson observations "${observations:-0}" \
|
|
277
283
|
--argjson tasks "${tasks:-0}" \
|
|
278
284
|
--argjson code_chunks "${chunks:-0}" \
|
|
279
|
-
'{project: $project, sessions: $sessions, summaries: $summaries, observations: $observations, tasks: $tasks, code_chunks: $code_chunks}'
|
|
285
|
+
'{project: $project, sessions: $sessions, sessions_claude: $sessions_claude, sessions_codex: $sessions_codex, summaries: $summaries, observations: $observations, tasks: $tasks, code_chunks: $code_chunks}'
|
|
280
286
|
return
|
|
281
287
|
fi
|
|
282
288
|
|
|
@@ -285,6 +291,8 @@ search_stats() {
|
|
|
285
291
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
286
292
|
echo ""
|
|
287
293
|
eagle_kv "Sessions:" "${sessions:-0}"
|
|
294
|
+
eagle_kv "Claude Code:" "${sessions_claude:-0}"
|
|
295
|
+
eagle_kv "Codex:" "${sessions_codex:-0}"
|
|
288
296
|
eagle_kv "Summaries:" "${summaries:-0}"
|
|
289
297
|
eagle_kv "Observations:" "${observations:-0}"
|
|
290
298
|
eagle_kv "Tasks:" "${tasks:-0}"
|
|
@@ -341,15 +349,15 @@ search_memories() {
|
|
|
341
349
|
exit 1
|
|
342
350
|
fi
|
|
343
351
|
local q; q=$(eagle_sql_escape "$sanitized_mq")
|
|
344
|
-
local where_match="WHERE
|
|
352
|
+
local where_match="WHERE agent_memories_fts MATCH '$q'"
|
|
345
353
|
if [ "$cross_project" = false ]; then
|
|
346
354
|
where_match="$where_match AND m.project = '$p'"
|
|
347
355
|
fi
|
|
348
356
|
|
|
349
357
|
if [ "$json_output" = true ]; then
|
|
350
|
-
eagle_db_json "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at
|
|
351
|
-
FROM
|
|
352
|
-
JOIN
|
|
358
|
+
eagle_db_json "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at, m.origin_agent
|
|
359
|
+
FROM agent_memories m
|
|
360
|
+
JOIN agent_memories_fts f ON f.rowid = m.id
|
|
353
361
|
$where_match
|
|
354
362
|
ORDER BY rank
|
|
355
363
|
LIMIT $limit;"
|
|
@@ -357,9 +365,9 @@ search_memories() {
|
|
|
357
365
|
fi
|
|
358
366
|
|
|
359
367
|
local results
|
|
360
|
-
results=$(eagle_db "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at
|
|
361
|
-
FROM
|
|
362
|
-
JOIN
|
|
368
|
+
results=$(eagle_db "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at, m.origin_agent
|
|
369
|
+
FROM agent_memories m
|
|
370
|
+
JOIN agent_memories_fts f ON f.rowid = m.id
|
|
363
371
|
$where_match
|
|
364
372
|
ORDER BY rank
|
|
365
373
|
LIMIT $limit;")
|
|
@@ -370,9 +378,9 @@ search_memories() {
|
|
|
370
378
|
fi
|
|
371
379
|
|
|
372
380
|
echo ""
|
|
373
|
-
while IFS='|' read -r mname mtype mdesc mproj mupdated; do
|
|
381
|
+
while IFS='|' read -r mname mtype mdesc mproj mupdated morigin; do
|
|
374
382
|
[ -z "$mname" ] && continue
|
|
375
|
-
echo -e " ${BOLD}$mname${RESET} ${DIM}[$mtype]${RESET}"
|
|
383
|
+
echo -e " ${BOLD}$mname${RESET} ${DIM}[$mtype][$(eagle_agent_label "$morigin")]${RESET}"
|
|
376
384
|
[ "$cross_project" = true ] && echo -e " ${DIM}project:${RESET} $mproj"
|
|
377
385
|
[ -n "$mdesc" ] && echo -e " $mdesc"
|
|
378
386
|
echo ""
|
|
@@ -381,15 +389,15 @@ search_memories() {
|
|
|
381
389
|
fi
|
|
382
390
|
|
|
383
391
|
if [ "$json_output" = true ]; then
|
|
384
|
-
eagle_db_json "SELECT memory_name, memory_type, description, project, updated_at
|
|
385
|
-
FROM
|
|
392
|
+
eagle_db_json "SELECT memory_name, memory_type, description, project, updated_at, origin_agent
|
|
393
|
+
FROM agent_memories $where_project
|
|
386
394
|
ORDER BY updated_at DESC LIMIT $limit;"
|
|
387
395
|
return
|
|
388
396
|
fi
|
|
389
397
|
|
|
390
398
|
local results
|
|
391
|
-
results=$(eagle_db "SELECT memory_name, memory_type, description, updated_at
|
|
392
|
-
FROM
|
|
399
|
+
results=$(eagle_db "SELECT memory_name, memory_type, description, updated_at, origin_agent
|
|
400
|
+
FROM agent_memories $where_project
|
|
393
401
|
ORDER BY updated_at DESC LIMIT $limit;")
|
|
394
402
|
|
|
395
403
|
if [ -z "$results" ]; then
|
|
@@ -402,9 +410,9 @@ search_memories() {
|
|
|
402
410
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
403
411
|
echo ""
|
|
404
412
|
|
|
405
|
-
while IFS='|' read -r mname mtype mdesc mupdated; do
|
|
413
|
+
while IFS='|' read -r mname mtype mdesc mupdated morigin; do
|
|
406
414
|
[ -z "$mname" ] && continue
|
|
407
|
-
echo -e " ${CYAN}[$mtype]${RESET} ${BOLD}$mname${RESET}"
|
|
415
|
+
echo -e " ${CYAN}[$mtype][$(eagle_agent_label "$morigin")]${RESET} ${BOLD}$mname${RESET}"
|
|
408
416
|
[ -n "$mdesc" ] && echo -e " ${DIM}$mdesc${RESET}"
|
|
409
417
|
done <<< "$results"
|
|
410
418
|
echo ""
|
|
@@ -416,8 +424,10 @@ search_tasks() {
|
|
|
416
424
|
local p; p=$(eagle_sql_escape "$project")
|
|
417
425
|
|
|
418
426
|
local where_project=""
|
|
427
|
+
local where_task_project=""
|
|
419
428
|
if [ "$cross_project" = false ]; then
|
|
420
429
|
where_project="AND project = '$p'"
|
|
430
|
+
where_task_project="AND t.project = '$p'"
|
|
421
431
|
fi
|
|
422
432
|
|
|
423
433
|
if [ -n "$query" ]; then
|
|
@@ -430,22 +440,22 @@ search_tasks() {
|
|
|
430
440
|
local q; q=$(eagle_sql_escape "$sanitized_tq")
|
|
431
441
|
|
|
432
442
|
if [ "$json_output" = true ]; then
|
|
433
|
-
eagle_db_json "SELECT t.subject, t.status, t.project, t.updated_at
|
|
434
|
-
FROM
|
|
435
|
-
JOIN
|
|
436
|
-
WHERE
|
|
437
|
-
$
|
|
443
|
+
eagle_db_json "SELECT t.subject, t.status, t.project, t.updated_at, t.origin_agent
|
|
444
|
+
FROM agent_tasks t
|
|
445
|
+
JOIN agent_tasks_fts f ON f.rowid = t.id
|
|
446
|
+
WHERE agent_tasks_fts MATCH '$q'
|
|
447
|
+
$where_task_project
|
|
438
448
|
ORDER BY rank
|
|
439
449
|
LIMIT $limit;"
|
|
440
450
|
return
|
|
441
451
|
fi
|
|
442
452
|
|
|
443
453
|
local results
|
|
444
|
-
results=$(eagle_db "SELECT t.subject, t.status, t.project, t.updated_at
|
|
445
|
-
FROM
|
|
446
|
-
JOIN
|
|
447
|
-
WHERE
|
|
448
|
-
$
|
|
454
|
+
results=$(eagle_db "SELECT t.subject, t.status, t.project, t.updated_at, t.origin_agent
|
|
455
|
+
FROM agent_tasks t
|
|
456
|
+
JOIN agent_tasks_fts f ON f.rowid = t.id
|
|
457
|
+
WHERE agent_tasks_fts MATCH '$q'
|
|
458
|
+
$where_task_project
|
|
449
459
|
ORDER BY rank
|
|
450
460
|
LIMIT $limit;")
|
|
451
461
|
|
|
@@ -455,7 +465,7 @@ search_tasks() {
|
|
|
455
465
|
fi
|
|
456
466
|
|
|
457
467
|
echo ""
|
|
458
|
-
while IFS='|' read -r tsubject tstatus tproj tupdated; do
|
|
468
|
+
while IFS='|' read -r tsubject tstatus tproj tupdated torigin; do
|
|
459
469
|
[ -z "$tsubject" ] && continue
|
|
460
470
|
local color="$DIM"
|
|
461
471
|
case "$tstatus" in
|
|
@@ -463,15 +473,15 @@ search_tasks() {
|
|
|
463
473
|
completed) color="$GREEN" ;;
|
|
464
474
|
pending) color="$CYAN" ;;
|
|
465
475
|
esac
|
|
466
|
-
echo -e " ${color}[$tstatus]${RESET} $tsubject"
|
|
476
|
+
echo -e " ${color}[$tstatus][$(eagle_agent_label "$torigin")]${RESET} $tsubject"
|
|
467
477
|
done <<< "$results"
|
|
468
478
|
echo ""
|
|
469
479
|
return
|
|
470
480
|
fi
|
|
471
481
|
|
|
472
482
|
if [ "$json_output" = true ]; then
|
|
473
|
-
eagle_db_json "SELECT subject, status, project, updated_at
|
|
474
|
-
FROM
|
|
483
|
+
eagle_db_json "SELECT subject, status, project, updated_at, origin_agent
|
|
484
|
+
FROM agent_tasks
|
|
475
485
|
WHERE status IN ('in_progress', 'pending')
|
|
476
486
|
$where_project
|
|
477
487
|
ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
|
|
@@ -480,8 +490,8 @@ search_tasks() {
|
|
|
480
490
|
fi
|
|
481
491
|
|
|
482
492
|
local results
|
|
483
|
-
results=$(eagle_db "SELECT subject, status, updated_at
|
|
484
|
-
FROM
|
|
493
|
+
results=$(eagle_db "SELECT subject, status, updated_at, origin_agent
|
|
494
|
+
FROM agent_tasks
|
|
485
495
|
WHERE status IN ('in_progress', 'pending')
|
|
486
496
|
$where_project
|
|
487
497
|
ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
|
|
@@ -497,14 +507,14 @@ search_tasks() {
|
|
|
497
507
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
498
508
|
echo ""
|
|
499
509
|
|
|
500
|
-
while IFS='|' read -r tsubject tstatus tupdated; do
|
|
510
|
+
while IFS='|' read -r tsubject tstatus tupdated torigin; do
|
|
501
511
|
[ -z "$tsubject" ] && continue
|
|
502
512
|
local color="$DIM"
|
|
503
513
|
case "$tstatus" in
|
|
504
514
|
in_progress) color="$YELLOW" ;;
|
|
505
515
|
pending) color="$CYAN" ;;
|
|
506
516
|
esac
|
|
507
|
-
echo -e " ${color}[$tstatus]${RESET} $tsubject"
|
|
517
|
+
echo -e " ${color}[$tstatus][$(eagle_agent_label "$torigin")]${RESET} $tsubject"
|
|
508
518
|
done <<< "$results"
|
|
509
519
|
echo ""
|
|
510
520
|
}
|
package/scripts/statusline-em.sh
CHANGED
|
@@ -21,7 +21,7 @@ eagle_mem_statusline() {
|
|
|
21
21
|
cnt=$(echo ".headers off
|
|
22
22
|
SELECT COUNT(*) FROM sessions WHERE project = '${proj}';" | sqlite3 "$em_db" 2>/dev/null | tr -d '[:space:]')
|
|
23
23
|
mem=$(echo ".headers off
|
|
24
|
-
SELECT COUNT(*) FROM
|
|
24
|
+
SELECT COUNT(*) FROM agent_memories WHERE project = '${proj}';" | sqlite3 "$em_db" 2>/dev/null | tr -d '[:space:]')
|
|
25
25
|
cnt=${cnt:-0}; mem=${mem:-0}
|
|
26
26
|
|
|
27
27
|
local R='\033[0m' CYAN='\033[96m' WHT='\033[97m' DIM='\033[2m'
|
package/scripts/tasks.sh
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ═══════════════════════════════════════════════════════════
|
|
3
|
-
# Eagle Mem — Tasks
|
|
4
|
-
#
|
|
5
|
-
#
|
|
3
|
+
# Eagle Mem — Tasks
|
|
4
|
+
# Mirrors native task state and lets agents without native task files persist
|
|
5
|
+
# task handoff records directly.
|
|
6
6
|
# ═══════════════════════════════════════════════════════════
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
@@ -26,22 +26,29 @@ esac
|
|
|
26
26
|
|
|
27
27
|
project=""
|
|
28
28
|
json_output=false
|
|
29
|
+
agent=""
|
|
29
30
|
|
|
30
31
|
show_help() {
|
|
31
|
-
echo -e " ${BOLD}eagle-mem tasks${RESET} — View mirrored
|
|
32
|
+
echo -e " ${BOLD}eagle-mem tasks${RESET} — View mirrored agent tasks"
|
|
32
33
|
echo ""
|
|
33
34
|
echo -e " ${BOLD}Usage:${RESET}"
|
|
34
35
|
echo -e " eagle-mem tasks ${DIM}# list pending/in-progress tasks${RESET}"
|
|
35
36
|
echo -e " eagle-mem tasks ${CYAN}list${RESET} ${DIM}# list all tasks${RESET}"
|
|
36
37
|
echo -e " eagle-mem tasks ${CYAN}completed${RESET} ${DIM}# list completed tasks${RESET}"
|
|
37
38
|
echo -e " eagle-mem tasks ${CYAN}search${RESET} <query> ${DIM}# search tasks by keyword${RESET}"
|
|
39
|
+
echo -e " eagle-mem tasks ${CYAN}add${RESET} <subject> ${DIM}# create a persistent task record${RESET}"
|
|
40
|
+
echo -e " eagle-mem tasks ${CYAN}update${RESET} <id> ${DIM}# update subject/description/status${RESET}"
|
|
41
|
+
echo -e " eagle-mem tasks ${CYAN}start${RESET} <id> ${DIM}# mark task in_progress${RESET}"
|
|
42
|
+
echo -e " eagle-mem tasks ${CYAN}complete${RESET} <id> ${DIM}# mark task completed${RESET}"
|
|
43
|
+
echo -e " eagle-mem tasks ${CYAN}cancel${RESET} <id> ${DIM}# mark task cancelled${RESET}"
|
|
38
44
|
echo ""
|
|
39
45
|
echo -e " ${BOLD}Options:${RESET}"
|
|
40
46
|
echo -e " ${CYAN}-p, --project${RESET} <name> Project name (default: current dir)"
|
|
47
|
+
echo -e " ${CYAN}--agent${RESET} <name> Source agent (codex or claude-code)"
|
|
41
48
|
echo -e " ${CYAN}-j, --json${RESET} Output as JSON"
|
|
42
49
|
echo ""
|
|
43
|
-
echo -e " ${DIM}
|
|
44
|
-
echo -e " ${DIM}
|
|
50
|
+
echo -e " ${DIM}Claude Code task files are mirrored automatically.${RESET}"
|
|
51
|
+
echo -e " ${DIM}Codex can persist tasks with this CLI when using the eagle-mem-tasks skill.${RESET}"
|
|
45
52
|
echo ""
|
|
46
53
|
exit 0
|
|
47
54
|
}
|
|
@@ -50,6 +57,7 @@ args=()
|
|
|
50
57
|
while [ $# -gt 0 ]; do
|
|
51
58
|
case "$1" in
|
|
52
59
|
--project|-p) project="$2"; shift 2 ;;
|
|
60
|
+
--agent) agent="$2"; shift 2 ;;
|
|
53
61
|
--json|-j) json_output=true; shift ;;
|
|
54
62
|
--help|-h) show_help ;;
|
|
55
63
|
*) args+=("$1"); shift ;;
|
|
@@ -58,6 +66,8 @@ done
|
|
|
58
66
|
|
|
59
67
|
[ -z "$project" ] && project=$(eagle_project_from_cwd "$(pwd)")
|
|
60
68
|
project_sql=$(eagle_sql_escape "$project")
|
|
69
|
+
[ -z "$agent" ] && agent=$(eagle_agent_source)
|
|
70
|
+
agent_sql=$(eagle_sql_escape "$agent")
|
|
61
71
|
|
|
62
72
|
# ─── List tasks ───────────────────────────────────────────
|
|
63
73
|
|
|
@@ -73,7 +83,7 @@ tasks_list() {
|
|
|
73
83
|
|
|
74
84
|
if [ "$json_output" = true ]; then
|
|
75
85
|
eagle_db_json "SELECT source_task_id, subject, description, status, blocks, blocked_by, updated_at
|
|
76
|
-
FROM
|
|
86
|
+
FROM agent_tasks
|
|
77
87
|
WHERE project = '$project_sql' $where_status
|
|
78
88
|
ORDER BY updated_at DESC
|
|
79
89
|
LIMIT 20;"
|
|
@@ -82,7 +92,7 @@ tasks_list() {
|
|
|
82
92
|
|
|
83
93
|
local results
|
|
84
94
|
results=$(eagle_db "SELECT source_task_id, subject, status, blocked_by, description
|
|
85
|
-
FROM
|
|
95
|
+
FROM agent_tasks
|
|
86
96
|
WHERE project = '$project_sql' $where_status
|
|
87
97
|
ORDER BY
|
|
88
98
|
CASE status WHEN 'in_progress' THEN 0 WHEN 'pending' THEN 1 ELSE 2 END,
|
|
@@ -106,7 +116,7 @@ tasks_list() {
|
|
|
106
116
|
in_progress) icon="${CYAN}>${RESET}"; marker=" ${CYAN}[in_progress]${RESET}" ;;
|
|
107
117
|
pending) icon="${DIM}o${RESET}"; marker="" ;;
|
|
108
118
|
completed) icon="${GREEN}+${RESET}"; marker=" ${DIM}[completed]${RESET}" ;;
|
|
109
|
-
|
|
119
|
+
cancelled) icon="${RED}x${RESET}"; marker=" ${RED}[cancelled]${RESET}" ;;
|
|
110
120
|
*) icon="$DOT"; marker="" ;;
|
|
111
121
|
esac
|
|
112
122
|
if [ "$blocked_by" != "[]" ] && [ -n "$blocked_by" ]; then
|
|
@@ -137,9 +147,9 @@ tasks_search() {
|
|
|
137
147
|
if [ "$json_output" = true ]; then
|
|
138
148
|
local query_sql; query_sql=$(eagle_sql_escape "$sanitized_query")
|
|
139
149
|
eagle_db_json "SELECT t.source_task_id, t.subject, t.status, t.description, t.updated_at
|
|
140
|
-
FROM
|
|
141
|
-
JOIN
|
|
142
|
-
WHERE
|
|
150
|
+
FROM agent_tasks t
|
|
151
|
+
JOIN agent_tasks_fts f ON f.rowid = t.id
|
|
152
|
+
WHERE agent_tasks_fts MATCH '$query_sql'
|
|
143
153
|
AND t.project = '$project_sql'
|
|
144
154
|
ORDER BY rank
|
|
145
155
|
LIMIT 10;"
|
|
@@ -149,9 +159,9 @@ tasks_search() {
|
|
|
149
159
|
local results
|
|
150
160
|
local query_sql; query_sql=$(eagle_sql_escape "$sanitized_query")
|
|
151
161
|
results=$(eagle_db "SELECT t.source_task_id, t.subject, t.status, t.description
|
|
152
|
-
FROM
|
|
153
|
-
JOIN
|
|
154
|
-
WHERE
|
|
162
|
+
FROM agent_tasks t
|
|
163
|
+
JOIN agent_tasks_fts f ON f.rowid = t.id
|
|
164
|
+
WHERE agent_tasks_fts MATCH '$query_sql'
|
|
155
165
|
AND t.project = '$project_sql'
|
|
156
166
|
ORDER BY rank
|
|
157
167
|
LIMIT 10;")
|
|
@@ -174,6 +184,162 @@ tasks_search() {
|
|
|
174
184
|
echo ""
|
|
175
185
|
}
|
|
176
186
|
|
|
187
|
+
# ─── Mutate task records ──────────────────────────────────
|
|
188
|
+
|
|
189
|
+
tasks_add() {
|
|
190
|
+
local subject="${args[0]:-}"
|
|
191
|
+
if [ -z "$subject" ]; then
|
|
192
|
+
eagle_err "Usage: eagle-mem tasks add <subject> [--desc <text>] [--status pending|in_progress]"
|
|
193
|
+
exit 1
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
local desc=""
|
|
197
|
+
local status="pending"
|
|
198
|
+
local i=1
|
|
199
|
+
while [ "$i" -lt "${#args[@]}" ]; do
|
|
200
|
+
case "${args[$i]}" in
|
|
201
|
+
--desc|-d)
|
|
202
|
+
i=$((i + 1))
|
|
203
|
+
desc="${args[$i]:-}"
|
|
204
|
+
;;
|
|
205
|
+
--status)
|
|
206
|
+
i=$((i + 1))
|
|
207
|
+
status="${args[$i]:-pending}"
|
|
208
|
+
;;
|
|
209
|
+
esac
|
|
210
|
+
i=$((i + 1))
|
|
211
|
+
done
|
|
212
|
+
|
|
213
|
+
case "$status" in
|
|
214
|
+
pending|in_progress|completed|cancelled) ;;
|
|
215
|
+
*)
|
|
216
|
+
eagle_err "Invalid status: $status"
|
|
217
|
+
exit 1
|
|
218
|
+
;;
|
|
219
|
+
esac
|
|
220
|
+
|
|
221
|
+
local task_id file_path content_hash
|
|
222
|
+
task_id="agent-$(date -u +%Y%m%d%H%M%S)-$$"
|
|
223
|
+
file_path="agent-task://$project/$task_id"
|
|
224
|
+
content_hash=$(printf '%s|%s|%s|%s' "$subject" "$desc" "$status" "$agent" | shasum -a 256 | awk '{print $1}')
|
|
225
|
+
|
|
226
|
+
local tid_sql fp_sql subj_sql desc_sql status_sql hash_sql
|
|
227
|
+
tid_sql=$(eagle_sql_escape "$task_id")
|
|
228
|
+
fp_sql=$(eagle_sql_escape "$file_path")
|
|
229
|
+
subj_sql=$(eagle_sql_escape "$subject")
|
|
230
|
+
desc_sql=$(eagle_sql_escape "$desc")
|
|
231
|
+
status_sql=$(eagle_sql_escape "$status")
|
|
232
|
+
hash_sql=$(eagle_sql_escape "$content_hash")
|
|
233
|
+
|
|
234
|
+
eagle_db_pipe <<SQL
|
|
235
|
+
INSERT INTO agent_tasks (project, source_session_id, source_task_id, file_path, subject, description, active_form, status, blocks, blocked_by, content_hash, origin_agent)
|
|
236
|
+
VALUES ('$project_sql', 'manual', '$tid_sql', '$fp_sql', '$subj_sql', '$desc_sql', '', '$status_sql', '[]', '[]', '$hash_sql', '$agent_sql');
|
|
237
|
+
SQL
|
|
238
|
+
|
|
239
|
+
if [ "$json_output" = true ]; then
|
|
240
|
+
jq -nc --arg id "$task_id" --arg subject "$subject" --arg status "$status" --arg agent "$agent" \
|
|
241
|
+
'{source_task_id:$id, subject:$subject, status:$status, origin_agent:$agent}'
|
|
242
|
+
else
|
|
243
|
+
eagle_ok "Task '$task_id' created"
|
|
244
|
+
fi
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
tasks_set_status() {
|
|
248
|
+
local task_id="${args[0]:-}"
|
|
249
|
+
local status="$1"
|
|
250
|
+
if [ -z "$task_id" ]; then
|
|
251
|
+
eagle_err "Usage: eagle-mem tasks $action <id>"
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
local tid_sql status_sql
|
|
256
|
+
tid_sql=$(eagle_sql_escape "$task_id")
|
|
257
|
+
status_sql=$(eagle_sql_escape "$status")
|
|
258
|
+
|
|
259
|
+
changed=$(eagle_db_pipe <<SQL
|
|
260
|
+
UPDATE agent_tasks
|
|
261
|
+
SET status = '$status_sql',
|
|
262
|
+
origin_agent = COALESCE(NULLIF('$agent_sql', ''), origin_agent),
|
|
263
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
264
|
+
WHERE project = '$project_sql' AND source_task_id = '$tid_sql';
|
|
265
|
+
SELECT changes();
|
|
266
|
+
SQL
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
if [ "${changed:-0}" -gt 0 ] 2>/dev/null; then
|
|
270
|
+
eagle_ok "Task '$task_id' marked $status"
|
|
271
|
+
else
|
|
272
|
+
eagle_err "Task not found: $task_id"
|
|
273
|
+
exit 1
|
|
274
|
+
fi
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
tasks_update() {
|
|
278
|
+
local task_id="${args[0]:-}"
|
|
279
|
+
if [ -z "$task_id" ]; then
|
|
280
|
+
eagle_err "Usage: eagle-mem tasks update <id> [--subject <text>] [--desc <text>] [--status <status>]"
|
|
281
|
+
exit 1
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
local subject="" desc="" status=""
|
|
285
|
+
local i=1
|
|
286
|
+
while [ "$i" -lt "${#args[@]}" ]; do
|
|
287
|
+
case "${args[$i]}" in
|
|
288
|
+
--subject)
|
|
289
|
+
i=$((i + 1))
|
|
290
|
+
subject="${args[$i]:-}"
|
|
291
|
+
;;
|
|
292
|
+
--desc|-d)
|
|
293
|
+
i=$((i + 1))
|
|
294
|
+
desc="${args[$i]:-}"
|
|
295
|
+
;;
|
|
296
|
+
--status)
|
|
297
|
+
i=$((i + 1))
|
|
298
|
+
status="${args[$i]:-}"
|
|
299
|
+
;;
|
|
300
|
+
esac
|
|
301
|
+
i=$((i + 1))
|
|
302
|
+
done
|
|
303
|
+
|
|
304
|
+
if [ -n "$status" ]; then
|
|
305
|
+
case "$status" in
|
|
306
|
+
pending|in_progress|completed|cancelled) ;;
|
|
307
|
+
*)
|
|
308
|
+
eagle_err "Invalid status: $status"
|
|
309
|
+
exit 1
|
|
310
|
+
;;
|
|
311
|
+
esac
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
local tid_sql subj_sql desc_sql status_sql hash_sql
|
|
315
|
+
tid_sql=$(eagle_sql_escape "$task_id")
|
|
316
|
+
subj_sql=$(eagle_sql_escape "$subject")
|
|
317
|
+
desc_sql=$(eagle_sql_escape "$desc")
|
|
318
|
+
status_sql=$(eagle_sql_escape "$status")
|
|
319
|
+
hash_sql=$(printf '%s|%s|%s|%s|%s' "$task_id" "$subject" "$desc" "$status" "$agent" | shasum -a 256 | awk '{print $1}')
|
|
320
|
+
hash_sql=$(eagle_sql_escape "$hash_sql")
|
|
321
|
+
|
|
322
|
+
changed=$(eagle_db_pipe <<SQL
|
|
323
|
+
UPDATE agent_tasks
|
|
324
|
+
SET subject = CASE WHEN '$subj_sql' != '' THEN '$subj_sql' ELSE subject END,
|
|
325
|
+
description = CASE WHEN '$desc_sql' != '' THEN '$desc_sql' ELSE description END,
|
|
326
|
+
status = CASE WHEN '$status_sql' != '' THEN '$status_sql' ELSE status END,
|
|
327
|
+
origin_agent = COALESCE(NULLIF('$agent_sql', ''), origin_agent),
|
|
328
|
+
content_hash = '$hash_sql',
|
|
329
|
+
updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
330
|
+
WHERE project = '$project_sql' AND source_task_id = '$tid_sql';
|
|
331
|
+
SELECT changes();
|
|
332
|
+
SQL
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
if [ "${changed:-0}" -gt 0 ] 2>/dev/null; then
|
|
336
|
+
eagle_ok "Task '$task_id' updated"
|
|
337
|
+
else
|
|
338
|
+
eagle_err "Task not found: $task_id"
|
|
339
|
+
exit 1
|
|
340
|
+
fi
|
|
341
|
+
}
|
|
342
|
+
|
|
177
343
|
# ─── Dispatch ─────────────────────────────────────────────
|
|
178
344
|
|
|
179
345
|
case "$action" in
|
|
@@ -181,6 +347,11 @@ case "$action" in
|
|
|
181
347
|
pending) tasks_list "pending" ;;
|
|
182
348
|
completed) tasks_list "completed" ;;
|
|
183
349
|
search) tasks_search ;;
|
|
350
|
+
add) tasks_add ;;
|
|
351
|
+
update) tasks_update ;;
|
|
352
|
+
start) tasks_set_status "in_progress" ;;
|
|
353
|
+
complete) tasks_set_status "completed" ;;
|
|
354
|
+
cancel) tasks_set_status "cancelled" ;;
|
|
184
355
|
--help|-h) show_help ;;
|
|
185
356
|
*)
|
|
186
357
|
eagle_err "Unknown action: $action"
|
package/scripts/uninstall.sh
CHANGED
|
@@ -10,6 +10,7 @@ LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
|
10
10
|
|
|
11
11
|
. "$SCRIPTS_DIR/style.sh"
|
|
12
12
|
. "$LIB_DIR/common.sh"
|
|
13
|
+
. "$LIB_DIR/codex-hooks.sh"
|
|
13
14
|
|
|
14
15
|
SETTINGS="$EAGLE_SETTINGS"
|
|
15
16
|
|
|
@@ -33,6 +34,12 @@ else
|
|
|
33
34
|
eagle_warn "Could not patch settings.json (jq not found or file missing)"
|
|
34
35
|
fi
|
|
35
36
|
|
|
37
|
+
if eagle_remove_codex_hooks; then
|
|
38
|
+
eagle_ok "Hooks removed from Codex hooks.json"
|
|
39
|
+
else
|
|
40
|
+
eagle_warn "Could not patch Codex hooks.json (jq not found or file missing)"
|
|
41
|
+
fi
|
|
42
|
+
|
|
36
43
|
# ─── Remove skill symlinks ────────────────────────────────
|
|
37
44
|
|
|
38
45
|
if [ -d "$EAGLE_SKILLS_DIR" ]; then
|