eagle-mem 4.7.0 → 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 +11 -9
- package/db/028_agent_artifact_tables.sql +124 -0
- package/hooks/post-tool-use.sh +2 -1
- package/hooks/pre-tool-use.sh +1 -0
- package/hooks/session-end.sh +2 -1
- package/hooks/session-start.sh +11 -3
- package/hooks/stop.sh +1 -0
- package/hooks/user-prompt-submit.sh +1 -0
- package/lib/common.sh +4 -0
- package/lib/db-backfill.sh +3 -3
- package/lib/db-mirrors.sh +59 -32
- package/lib/db-sessions.sh +5 -5
- package/lib/db-summaries.sh +3 -3
- package/lib/hooks-posttool.sh +4 -4
- package/lib/provider.sh +190 -4
- package/package.json +1 -1
- package/scripts/config.sh +2 -0
- package/scripts/health.sh +5 -1
- package/scripts/help.sh +6 -6
- package/scripts/install.sh +12 -0
- package/scripts/memories.sh +50 -27
- package/scripts/refresh.sh +3 -3
- package/scripts/search.sh +21 -19
- package/scripts/statusline-em.sh +1 -1
- package/scripts/tasks.sh +186 -15
- package/scripts/update.sh +20 -1
- 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}"
|
|
@@ -269,7 +269,7 @@ search_stats() {
|
|
|
269
269
|
sessions_codex=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p' AND agent = 'codex';")
|
|
270
270
|
summaries=$(eagle_db "SELECT COUNT(*) FROM summaries WHERE project = '$p';")
|
|
271
271
|
observations=$(eagle_db "SELECT COUNT(*) FROM observations o JOIN sessions s ON s.id = o.session_id WHERE s.project = '$p';")
|
|
272
|
-
tasks=$(eagle_db "SELECT COUNT(*) FROM
|
|
272
|
+
tasks=$(eagle_db "SELECT COUNT(*) FROM agent_tasks WHERE project = '$p';")
|
|
273
273
|
local chunks
|
|
274
274
|
chunks=$(eagle_db "SELECT COUNT(*) FROM code_chunks WHERE project = '$p';")
|
|
275
275
|
|
|
@@ -349,15 +349,15 @@ search_memories() {
|
|
|
349
349
|
exit 1
|
|
350
350
|
fi
|
|
351
351
|
local q; q=$(eagle_sql_escape "$sanitized_mq")
|
|
352
|
-
local where_match="WHERE
|
|
352
|
+
local where_match="WHERE agent_memories_fts MATCH '$q'"
|
|
353
353
|
if [ "$cross_project" = false ]; then
|
|
354
354
|
where_match="$where_match AND m.project = '$p'"
|
|
355
355
|
fi
|
|
356
356
|
|
|
357
357
|
if [ "$json_output" = true ]; then
|
|
358
358
|
eagle_db_json "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at, m.origin_agent
|
|
359
|
-
FROM
|
|
360
|
-
JOIN
|
|
359
|
+
FROM agent_memories m
|
|
360
|
+
JOIN agent_memories_fts f ON f.rowid = m.id
|
|
361
361
|
$where_match
|
|
362
362
|
ORDER BY rank
|
|
363
363
|
LIMIT $limit;"
|
|
@@ -366,8 +366,8 @@ search_memories() {
|
|
|
366
366
|
|
|
367
367
|
local results
|
|
368
368
|
results=$(eagle_db "SELECT m.memory_name, m.memory_type, m.description, m.project, m.updated_at, m.origin_agent
|
|
369
|
-
FROM
|
|
370
|
-
JOIN
|
|
369
|
+
FROM agent_memories m
|
|
370
|
+
JOIN agent_memories_fts f ON f.rowid = m.id
|
|
371
371
|
$where_match
|
|
372
372
|
ORDER BY rank
|
|
373
373
|
LIMIT $limit;")
|
|
@@ -390,14 +390,14 @@ search_memories() {
|
|
|
390
390
|
|
|
391
391
|
if [ "$json_output" = true ]; then
|
|
392
392
|
eagle_db_json "SELECT memory_name, memory_type, description, project, updated_at, origin_agent
|
|
393
|
-
FROM
|
|
393
|
+
FROM agent_memories $where_project
|
|
394
394
|
ORDER BY updated_at DESC LIMIT $limit;"
|
|
395
395
|
return
|
|
396
396
|
fi
|
|
397
397
|
|
|
398
398
|
local results
|
|
399
399
|
results=$(eagle_db "SELECT memory_name, memory_type, description, updated_at, origin_agent
|
|
400
|
-
FROM
|
|
400
|
+
FROM agent_memories $where_project
|
|
401
401
|
ORDER BY updated_at DESC LIMIT $limit;")
|
|
402
402
|
|
|
403
403
|
if [ -z "$results" ]; then
|
|
@@ -424,8 +424,10 @@ search_tasks() {
|
|
|
424
424
|
local p; p=$(eagle_sql_escape "$project")
|
|
425
425
|
|
|
426
426
|
local where_project=""
|
|
427
|
+
local where_task_project=""
|
|
427
428
|
if [ "$cross_project" = false ]; then
|
|
428
429
|
where_project="AND project = '$p'"
|
|
430
|
+
where_task_project="AND t.project = '$p'"
|
|
429
431
|
fi
|
|
430
432
|
|
|
431
433
|
if [ -n "$query" ]; then
|
|
@@ -439,10 +441,10 @@ search_tasks() {
|
|
|
439
441
|
|
|
440
442
|
if [ "$json_output" = true ]; then
|
|
441
443
|
eagle_db_json "SELECT t.subject, t.status, t.project, t.updated_at, t.origin_agent
|
|
442
|
-
FROM
|
|
443
|
-
JOIN
|
|
444
|
-
WHERE
|
|
445
|
-
$
|
|
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
|
|
446
448
|
ORDER BY rank
|
|
447
449
|
LIMIT $limit;"
|
|
448
450
|
return
|
|
@@ -450,10 +452,10 @@ search_tasks() {
|
|
|
450
452
|
|
|
451
453
|
local results
|
|
452
454
|
results=$(eagle_db "SELECT t.subject, t.status, t.project, t.updated_at, t.origin_agent
|
|
453
|
-
FROM
|
|
454
|
-
JOIN
|
|
455
|
-
WHERE
|
|
456
|
-
$
|
|
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
|
|
457
459
|
ORDER BY rank
|
|
458
460
|
LIMIT $limit;")
|
|
459
461
|
|
|
@@ -479,7 +481,7 @@ search_tasks() {
|
|
|
479
481
|
|
|
480
482
|
if [ "$json_output" = true ]; then
|
|
481
483
|
eagle_db_json "SELECT subject, status, project, updated_at, origin_agent
|
|
482
|
-
FROM
|
|
484
|
+
FROM agent_tasks
|
|
483
485
|
WHERE status IN ('in_progress', 'pending')
|
|
484
486
|
$where_project
|
|
485
487
|
ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
|
|
@@ -489,7 +491,7 @@ search_tasks() {
|
|
|
489
491
|
|
|
490
492
|
local results
|
|
491
493
|
results=$(eagle_db "SELECT subject, status, updated_at, origin_agent
|
|
492
|
-
FROM
|
|
494
|
+
FROM agent_tasks
|
|
493
495
|
WHERE status IN ('in_progress', 'pending')
|
|
494
496
|
$where_project
|
|
495
497
|
ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
|
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/update.sh
CHANGED
|
@@ -119,7 +119,26 @@ if [ "$claude_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
|
119
119
|
[ -L "$dst" ] && rm "$dst"
|
|
120
120
|
ln -sf "$skill_dir" "$dst"
|
|
121
121
|
done
|
|
122
|
-
eagle_ok "
|
|
122
|
+
eagle_ok "Claude skills updated"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
if [ "$codex_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
126
|
+
mkdir -p "$EAGLE_CODEX_SKILLS_DIR"
|
|
127
|
+
find "$EAGLE_CODEX_SKILLS_DIR" -maxdepth 1 -name "eagle-mem-*" -type l 2>/dev/null | while read -r existing; do
|
|
128
|
+
skill_name=$(basename "$existing")
|
|
129
|
+
if [ ! -d "$PACKAGE_DIR/skills/$skill_name" ]; then
|
|
130
|
+
rm "$existing"
|
|
131
|
+
eagle_ok "Removed stale Codex skill: $skill_name"
|
|
132
|
+
fi
|
|
133
|
+
done
|
|
134
|
+
for skill_dir in "$PACKAGE_DIR"/skills/*/; do
|
|
135
|
+
[ ! -d "$skill_dir" ] && continue
|
|
136
|
+
skill_name=$(basename "$skill_dir")
|
|
137
|
+
dst="$EAGLE_CODEX_SKILLS_DIR/$skill_name"
|
|
138
|
+
[ -L "$dst" ] && rm "$dst"
|
|
139
|
+
ln -sf "$skill_dir" "$dst"
|
|
140
|
+
done
|
|
141
|
+
eagle_ok "Codex skills updated"
|
|
123
142
|
fi
|
|
124
143
|
|
|
125
144
|
# ─── Backfill project names ───────────────────────────────
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eagle-mem-memories
|
|
3
3
|
description: >
|
|
4
|
-
View and sync Claude Code
|
|
5
|
-
'eagle memories', 'show memories', 'sync memories', 'what does
|
|
4
|
+
View and sync Claude Code and Codex memories, plans, and tasks mirrored in Eagle Mem. Use when:
|
|
5
|
+
'eagle memories', 'show memories', 'sync memories', 'what does the agent remember',
|
|
6
6
|
'show plans', 'show tasks', 'mirror memories', 'onboard project',
|
|
7
7
|
'what did past sessions learn'. Uses the eagle-mem CLI.
|
|
8
8
|
---
|
|
@@ -11,9 +11,9 @@ description: >
|
|
|
11
11
|
|
|
12
12
|
## Purpose
|
|
13
13
|
|
|
14
|
-
**For the user:** Claude Code
|
|
14
|
+
**For the user:** Claude Code and Codex remember across sessions. Decisions, preferences, project context, and architectural plans survive session boundaries. The user never has to re-explain "we chose Postgres because..." or "don't use semicolons in this project."
|
|
15
15
|
|
|
16
|
-
**For you
|
|
16
|
+
**For you:** Access to what past Claude Code and Codex sessions learned about this project. Memories tell you *why* decisions were made. Plans tell you *what's coming*. Tasks tell you *what's in flight*. Together they're the knowledge bridge that makes you effective from message one.
|
|
17
17
|
|
|
18
18
|
## Judgment
|
|
19
19
|
|
|
@@ -21,7 +21,7 @@ description: >
|
|
|
21
21
|
- The user references a past decision ("remember when we decided to...", "what's our convention for...")
|
|
22
22
|
- You're about to make an architectural or style choice -- memories may record the user's preference
|
|
23
23
|
- You need project context that isn't in CLAUDE.md or README (relationships between services, deployment quirks, naming conventions)
|
|
24
|
-
- The user asks "what does Claude remember about X?"
|
|
24
|
+
- The user asks "what does Claude/Codex/Eagle Mem remember about X?"
|
|
25
25
|
|
|
26
26
|
**Check plans when:**
|
|
27
27
|
- The user asks about upcoming work or roadmap
|
|
@@ -43,21 +43,21 @@ description: >
|
|
|
43
43
|
|
|
44
44
|
### 1. Know the three data types
|
|
45
45
|
|
|
46
|
-
**Memories** -- Claude Code
|
|
46
|
+
**Memories** -- Claude Code auto-memory files (`~/.claude/projects/*/memory/*.md`) plus top-level Codex memory files (`~/.codex/memories/MEMORY.md`, `memory_summary.md`). These contain user preferences, project conventions, and feedback. Each mirrored row is source-attributed.
|
|
47
47
|
```bash
|
|
48
48
|
eagle-mem memories list # all memories
|
|
49
49
|
eagle-mem memories search "typescript" # FTS5 search
|
|
50
50
|
eagle-mem memories show <file_path> # full content
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
**Plans** -- Claude Code
|
|
53
|
+
**Plans** -- Claude Code plan files (`~/.claude/plans/*.md`) and future agent plan files as support is added. Multi-step strategies for complex work. Each has a title, optional project tag, and markdown content.
|
|
54
54
|
```bash
|
|
55
55
|
eagle-mem memories plans # all plans
|
|
56
56
|
eagle-mem memories plans search "migration"
|
|
57
57
|
eagle-mem memories plans show <file_path>
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
**Tasks** -- Claude Code
|
|
60
|
+
**Tasks** -- Claude Code task JSON (`~/.claude/tasks/<session>/*.json`) and Eagle Mem task records created directly by agents such as Codex. Individual units of work with status tracking (pending/in_progress/completed).
|
|
61
61
|
```bash
|
|
62
62
|
eagle-mem memories tasks # all tasks
|
|
63
63
|
eagle-mem memories tasks search "refactor"
|
|
@@ -68,13 +68,13 @@ eagle-mem memories tasks show <file_path>
|
|
|
68
68
|
|
|
69
69
|
Two paths feed the mirror:
|
|
70
70
|
|
|
71
|
-
**Real-time
|
|
71
|
+
**Real-time hooks.** Claude Code memory/plan/task files are mirrored when written. Codex sessions are captured through SessionStart/UserPromptSubmit/PostToolUse/Stop hooks, and important durable facts should be placed in `<eagle-summary>` so they become shared recall.
|
|
72
72
|
|
|
73
|
-
**Backfill (sync command).** For memories, plans, and tasks that existed before Eagle Mem was installed, or that were written outside a
|
|
73
|
+
**Backfill (sync command).** For memories, plans, and tasks that existed before Eagle Mem was installed, or that were written outside a hooked session:
|
|
74
74
|
```bash
|
|
75
75
|
eagle-mem memories sync
|
|
76
76
|
```
|
|
77
|
-
This scans
|
|
77
|
+
This scans known Claude Code and Codex memory/task locations, hashes each file, skips unchanged ones, and mirrors anything new or modified. It also backfills project names from transcripts. Safe to run repeatedly -- content-hash dedup prevents double-insertion.
|
|
78
78
|
|
|
79
79
|
### 3. Search effectively
|
|
80
80
|
|
|
@@ -104,7 +104,7 @@ This asymmetry is intentional but easy to forget. If you're getting too many irr
|
|
|
104
104
|
|
|
105
105
|
### 5. Onboard an existing project
|
|
106
106
|
|
|
107
|
-
When Eagle Mem is installed on a project that already has Claude Code history:
|
|
107
|
+
When Eagle Mem is installed on a project that already has Claude Code or Codex history:
|
|
108
108
|
```bash
|
|
109
109
|
eagle-mem memories sync
|
|
110
110
|
```
|
|
@@ -117,7 +117,7 @@ After sync or after expecting the hook to fire:
|
|
|
117
117
|
eagle-mem memories list # should show recent memories
|
|
118
118
|
eagle-mem search --stats # check counts are non-zero
|
|
119
119
|
```
|
|
120
|
-
If memories list is empty after sync, check that `~/.claude/projects/` contains memory files
|
|
120
|
+
If memories list is empty after sync, check that `~/.claude/projects/` or `~/.codex/memories/` contains memory files. If the hook isn't capturing new writes, check Claude Code `settings.json` or Codex `hooks.json`.
|
|
121
121
|
|
|
122
122
|
## What makes a good memory lookup
|
|
123
123
|
|
|
@@ -10,9 +10,9 @@ description: >
|
|
|
10
10
|
|
|
11
11
|
## Purpose
|
|
12
12
|
|
|
13
|
-
**For the user:** Multi-step work doesn't get lost when Claude Code compacts. A 6-task implementation plan survives intact across compactions — no re-explaining what was decided, no drift from the original direction.
|
|
13
|
+
**For the user:** Multi-step work doesn't get lost when Claude Code or Codex compacts. A 6-task implementation plan survives intact across compactions — no re-explaining what was decided, no drift from the original direction.
|
|
14
14
|
|
|
15
|
-
**For you
|
|
15
|
+
**For you:** Each task description is a message to a future context window with ZERO memory of what happened before. After compaction, SessionStart re-injects pending/in-progress tasks from Eagle Mem's `agent_tasks` table. That re-injected text is all the next context window gets. If the description says "implement auth middleware," the next window has nothing to work with. If it says "implement auth middleware — JWT with RS256, sessions in Redis, errors use RFC 7807 format (decided in task 1)," the next window can execute immediately.
|
|
16
16
|
|
|
17
17
|
## Judgment
|
|
18
18
|
|
|
@@ -42,12 +42,12 @@ Break the request into tasks that are each completable in one context window. Th
|
|
|
42
42
|
|
|
43
43
|
### 2. Create — write self-contained descriptions
|
|
44
44
|
|
|
45
|
-
Use `TaskCreate` for
|
|
45
|
+
Use the agent-native task mechanism when available. In Claude Code, use `TaskCreate`. In Codex, use `update_plan` for the live UI and `eagle-mem tasks add --agent codex` for durable cross-session task records. The description is the most important field — it must carry forward every decision from the planning conversation.
|
|
46
46
|
|
|
47
47
|
**Context transfer pattern:** For each task, ask: "If I read only this description with zero prior context, can I execute it?" If not, add what's missing.
|
|
48
48
|
|
|
49
49
|
```
|
|
50
|
-
TaskCreate:
|
|
50
|
+
TaskCreate / eagle-mem tasks add:
|
|
51
51
|
subject: "Add JWT auth middleware"
|
|
52
52
|
description: "Add Express middleware that validates JWT tokens on protected
|
|
53
53
|
routes. Decisions: RS256 algorithm, public key from env JWT_PUBLIC_KEY,
|
|
@@ -60,15 +60,15 @@ TaskCreate:
|
|
|
60
60
|
|
|
61
61
|
### 3. Execute — one task at a time
|
|
62
62
|
|
|
63
|
-
`TaskUpdate(in_progress)`
|
|
63
|
+
Mark the current task in progress (`TaskUpdate(in_progress)` in Claude Code, or `eagle-mem tasks start <id> --agent codex` in Codex). Do the work. Stay focused on that task — don't drift into adjacent tasks.
|
|
64
64
|
|
|
65
65
|
### 4. Complete — record what happened
|
|
66
66
|
|
|
67
|
-
`TaskUpdate(completed)
|
|
67
|
+
Mark the task completed (`TaskUpdate(completed)` in Claude Code, or `eagle-mem tasks complete <id> --agent codex` in Codex). Emit `<eagle-summary>` so Eagle Mem captures what was accomplished.
|
|
68
68
|
|
|
69
69
|
If the task produced decisions that downstream tasks need, update those task descriptions now:
|
|
70
70
|
```
|
|
71
|
-
TaskUpdate:
|
|
71
|
+
TaskUpdate / update durable task description:
|
|
72
72
|
taskId: "3"
|
|
73
73
|
description: "...original description... Note from task 2: the user table
|
|
74
74
|
uses UUID primary keys, not auto-increment. Auth tokens table FKs to
|
|
@@ -90,7 +90,7 @@ After compaction, SessionStart re-injects all pending/in-progress tasks. Pick th
|
|
|
90
90
|
**A task fails or produces unexpected results:** Update the task description with what was learned and what went wrong. Don't just retry blindly — the description should carry the failure context so the next attempt (or the next context window) doesn't repeat the same mistake.
|
|
91
91
|
|
|
92
92
|
```
|
|
93
|
-
TaskUpdate:
|
|
93
|
+
TaskUpdate / task record update:
|
|
94
94
|
taskId: "4"
|
|
95
95
|
description: "...original description... FAILED ATTEMPT: Prisma migrate
|
|
96
96
|
errored because the users table already has a conflicting unique
|
|
@@ -102,11 +102,11 @@ TaskUpdate:
|
|
|
102
102
|
|
|
103
103
|
## The compact cycle — how task state survives
|
|
104
104
|
|
|
105
|
-
1.
|
|
106
|
-
2.
|
|
107
|
-
3. Eagle Mem
|
|
108
|
-
4. SessionEnd
|
|
109
|
-
5. On compaction (or new session), SessionStart queries `
|
|
105
|
+
1. Claude Code path: you call `TaskCreate`/`TaskUpdate`; Claude Code writes task JSON to `~/.claude/tasks/$session_id/*.json`; Eagle Mem mirrors it.
|
|
106
|
+
2. Codex path: you call `update_plan` for live progress and `eagle-mem tasks add/start/complete --agent codex` for durable records.
|
|
107
|
+
3. Eagle Mem stores both paths in the shared `agent_tasks` FTS5 table with `origin_agent`.
|
|
108
|
+
4. SessionEnd does a final Claude Code task sweep where native task files exist.
|
|
109
|
+
5. On compaction (or new session), SessionStart queries `agent_tasks` for pending/in-progress tasks from the last 7 days and injects them into context.
|
|
110
110
|
|
|
111
111
|
The task descriptions you write ARE the context that survives. Everything else — your reasoning, the conversation, the files you read — gets compacted away.
|
|
112
112
|
|
|
@@ -126,14 +126,20 @@ The bad version forces the next context window to re-discover every decision. Th
|
|
|
126
126
|
## Reference
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
|
-
# Viewing tasks
|
|
129
|
+
# Viewing tasks
|
|
130
130
|
eagle-mem tasks # pending/in-progress for current project
|
|
131
131
|
eagle-mem tasks list # all tasks (including completed)
|
|
132
132
|
eagle-mem tasks completed # completed tasks only
|
|
133
133
|
eagle-mem tasks search <q> # FTS5 search across task history
|
|
134
134
|
eagle-mem tasks --json # JSON output for scripting
|
|
135
135
|
|
|
136
|
-
#
|
|
136
|
+
# Codex durable task records
|
|
137
|
+
eagle-mem tasks add "Implement auth middleware" --agent codex --desc "Use RS256, Redis sessions, RFC 7807 errors"
|
|
138
|
+
eagle-mem tasks update <id> --agent codex --desc "New context or failure details"
|
|
139
|
+
eagle-mem tasks start <id> --agent codex
|
|
140
|
+
eagle-mem tasks complete <id> --agent codex
|
|
141
|
+
|
|
142
|
+
# Claude Code task tools
|
|
137
143
|
TaskCreate # create a new task
|
|
138
144
|
TaskUpdate # update status, description, dependencies
|
|
139
145
|
```
|