eagle-mem 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks/session-start.sh +15 -59
- package/hooks/stop.sh +0 -8
- package/lib/db.sh +0 -44
- package/package.json +1 -1
- package/scripts/help.sh +5 -5
- package/scripts/search.sh +1 -1
- package/scripts/tasks.sh +74 -171
- package/skills/eagle-mem-tasks/SKILL.md +55 -63
package/hooks/session-start.sh
CHANGED
|
@@ -80,57 +80,6 @@ Next steps: $next_steps"
|
|
|
80
80
|
"
|
|
81
81
|
fi
|
|
82
82
|
|
|
83
|
-
# Pending tasks from TaskAware loop
|
|
84
|
-
pending_tasks=$(eagle_get_pending_tasks "$project")
|
|
85
|
-
|
|
86
|
-
if [ -n "$pending_tasks" ]; then
|
|
87
|
-
context+="
|
|
88
|
-
=== EAGLE MEM — Tasks ===
|
|
89
|
-
Pending tasks for '$project':
|
|
90
|
-
"
|
|
91
|
-
first_pending=""
|
|
92
|
-
while IFS='|' read -r tid title instructions status _ordinal; do
|
|
93
|
-
[ -z "$tid" ] && continue
|
|
94
|
-
local_marker=""
|
|
95
|
-
if [ "$status" = "active" ]; then
|
|
96
|
-
local_marker=" [ACTIVE]"
|
|
97
|
-
elif [ -z "$first_pending" ]; then
|
|
98
|
-
local_marker=" [NEXT]"
|
|
99
|
-
first_pending="$tid"
|
|
100
|
-
fi
|
|
101
|
-
context+=" $tid. $title$local_marker"
|
|
102
|
-
[ -n "$instructions" ] && context+=" — $instructions"
|
|
103
|
-
context+="
|
|
104
|
-
"
|
|
105
|
-
done <<< "$pending_tasks"
|
|
106
|
-
|
|
107
|
-
# Load context snapshot for the active/next task
|
|
108
|
-
active_task=$(eagle_get_active_task "$project")
|
|
109
|
-
|
|
110
|
-
if [ -z "$active_task" ] && [ -n "$first_pending" ]; then
|
|
111
|
-
# Auto-activate the next pending task (atomic to prevent races
|
|
112
|
-
# when multiple sessions start simultaneously)
|
|
113
|
-
eagle_db "UPDATE tasks SET status = 'active', started_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
114
|
-
WHERE id = $first_pending
|
|
115
|
-
AND status = 'pending'
|
|
116
|
-
AND NOT EXISTS (SELECT 1 FROM tasks WHERE project = '$(eagle_sql_escape "$project")' AND status = 'active');"
|
|
117
|
-
active_task=$(eagle_get_active_task "$project")
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
if [ -n "$active_task" ]; then
|
|
121
|
-
IFS='|' read -r atid atitle ainstructions asnapshot <<< "$active_task"
|
|
122
|
-
context+="
|
|
123
|
-
Current task (#$atid): $atitle
|
|
124
|
-
"
|
|
125
|
-
[ -n "$ainstructions" ] && context+="Instructions: $ainstructions
|
|
126
|
-
"
|
|
127
|
-
[ -n "$asnapshot" ] && context+="Context: $asnapshot
|
|
128
|
-
"
|
|
129
|
-
context+="When done, tell the user to run /compact so Eagle Mem can save progress and load the next task.
|
|
130
|
-
"
|
|
131
|
-
fi
|
|
132
|
-
fi
|
|
133
|
-
|
|
134
83
|
# ─── Mirrored Claude memories ──────────────────────────────
|
|
135
84
|
|
|
136
85
|
memories=$(eagle_list_claude_memories "$project" 5)
|
|
@@ -161,21 +110,28 @@ Recent plans for '$project':
|
|
|
161
110
|
done <<< "$plans"
|
|
162
111
|
fi
|
|
163
112
|
|
|
164
|
-
# ───
|
|
113
|
+
# ─── Claude Code tasks ───────────────────────────────────
|
|
165
114
|
|
|
166
|
-
synced_tasks=$(eagle_db "SELECT subject, status FROM claude_tasks
|
|
115
|
+
synced_tasks=$(eagle_db "SELECT subject, status, blocked_by FROM claude_tasks
|
|
167
116
|
WHERE project = '$(eagle_sql_escape "$project")'
|
|
168
|
-
AND status IN ('in_progress', 'pending'
|
|
117
|
+
AND status IN ('in_progress', 'pending')
|
|
169
118
|
AND updated_at > datetime('now', '-7 days')
|
|
170
|
-
ORDER BY
|
|
119
|
+
ORDER BY
|
|
120
|
+
CASE status WHEN 'in_progress' THEN 0 ELSE 1 END,
|
|
121
|
+
updated_at DESC
|
|
122
|
+
LIMIT 10;")
|
|
171
123
|
if [ -n "$synced_tasks" ]; then
|
|
172
124
|
context+="
|
|
173
|
-
=== EAGLE MEM —
|
|
174
|
-
|
|
125
|
+
=== EAGLE MEM — Tasks ===
|
|
126
|
+
Tasks for '$project':
|
|
175
127
|
"
|
|
176
|
-
while IFS='|' read -r tsubject tstatus; do
|
|
128
|
+
while IFS='|' read -r tsubject tstatus tblocked; do
|
|
177
129
|
[ -z "$tsubject" ] && continue
|
|
178
|
-
|
|
130
|
+
local_marker=""
|
|
131
|
+
if [ "$tblocked" != "[]" ] && [ -n "$tblocked" ]; then
|
|
132
|
+
local_marker=" (blocked)"
|
|
133
|
+
fi
|
|
134
|
+
context+=" - [$tstatus] $tsubject$local_marker
|
|
179
135
|
"
|
|
180
136
|
done <<< "$synced_tasks"
|
|
181
137
|
fi
|
package/hooks/stop.sh
CHANGED
|
@@ -141,12 +141,4 @@ if [ -n "$request" ] || [ -n "$completed" ] || [ -n "$learned" ]; then
|
|
|
141
141
|
eagle_log "INFO" "Stop: summary saved for session=$session_id"
|
|
142
142
|
fi
|
|
143
143
|
|
|
144
|
-
# Mark active task as done only when Claude explicitly provided a summary
|
|
145
|
-
if [ -n "$summary_block" ] && [ -n "$completed" ]; then
|
|
146
|
-
completed_task_id=$(eagle_complete_active_task "$project")
|
|
147
|
-
if [ -n "$completed_task_id" ]; then
|
|
148
|
-
eagle_log "INFO" "Stop: marked task #$completed_task_id as done"
|
|
149
|
-
fi
|
|
150
|
-
fi
|
|
151
|
-
|
|
152
144
|
exit 0
|
package/lib/db.sh
CHANGED
|
@@ -126,25 +126,6 @@ eagle_search_summaries() {
|
|
|
126
126
|
LIMIT $limit;"
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
eagle_get_pending_tasks() {
|
|
130
|
-
local project; project=$(eagle_sql_escape "$1")
|
|
131
|
-
|
|
132
|
-
eagle_db "SELECT id, title, instructions, status, ordinal
|
|
133
|
-
FROM tasks
|
|
134
|
-
WHERE project = '$project' AND status IN ('pending', 'active')
|
|
135
|
-
ORDER BY ordinal ASC, id ASC;"
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
eagle_get_next_task() {
|
|
139
|
-
local project; project=$(eagle_sql_escape "$1")
|
|
140
|
-
|
|
141
|
-
eagle_db "SELECT id, title, instructions, context_snapshot
|
|
142
|
-
FROM tasks
|
|
143
|
-
WHERE project = '$project' AND status = 'pending'
|
|
144
|
-
ORDER BY ordinal ASC, id ASC
|
|
145
|
-
LIMIT 1;"
|
|
146
|
-
}
|
|
147
|
-
|
|
148
129
|
eagle_observation_exists() {
|
|
149
130
|
local session_id; session_id=$(eagle_sql_escape "$1")
|
|
150
131
|
local tool_name; tool_name=$(eagle_sql_escape "$2")
|
|
@@ -174,31 +155,6 @@ eagle_get_overview() {
|
|
|
174
155
|
eagle_db "SELECT content FROM overviews WHERE project = '$project';"
|
|
175
156
|
}
|
|
176
157
|
|
|
177
|
-
eagle_activate_task() {
|
|
178
|
-
local task_id; task_id=$(eagle_sql_int "$1")
|
|
179
|
-
eagle_db "UPDATE tasks SET status = 'active', started_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = $task_id;"
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
eagle_complete_active_task() {
|
|
183
|
-
local project; project=$(eagle_sql_escape "$1")
|
|
184
|
-
local active_id
|
|
185
|
-
active_id=$(eagle_db "SELECT id FROM tasks WHERE project = '$project' AND status = 'active' LIMIT 1;")
|
|
186
|
-
if [ -n "$active_id" ]; then
|
|
187
|
-
local safe_id; safe_id=$(eagle_sql_int "$active_id")
|
|
188
|
-
eagle_db "UPDATE tasks SET status = 'done', completed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = $safe_id;"
|
|
189
|
-
echo "$active_id"
|
|
190
|
-
fi
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
eagle_get_active_task() {
|
|
194
|
-
local project; project=$(eagle_sql_escape "$1")
|
|
195
|
-
eagle_db "SELECT id, title, instructions, context_snapshot
|
|
196
|
-
FROM tasks
|
|
197
|
-
WHERE project = '$project' AND status = 'active'
|
|
198
|
-
ORDER BY ordinal ASC, id ASC
|
|
199
|
-
LIMIT 1;"
|
|
200
|
-
}
|
|
201
|
-
|
|
202
158
|
eagle_search_code_chunks() {
|
|
203
159
|
local query; query=$(eagle_sql_escape "$1")
|
|
204
160
|
local project; project=$(eagle_sql_escape "$2")
|
package/package.json
CHANGED
package/scripts/help.sh
CHANGED
|
@@ -20,7 +20,7 @@ echo -e " eagle-mem ${CYAN}<command>${RESET}"
|
|
|
20
20
|
echo ""
|
|
21
21
|
echo -e " ${BOLD}Commands:${RESET}"
|
|
22
22
|
echo -e " ${CYAN}search${RESET} Search past sessions, files, and observations"
|
|
23
|
-
echo -e " ${CYAN}tasks${RESET}
|
|
23
|
+
echo -e " ${CYAN}tasks${RESET} View mirrored Claude Code tasks"
|
|
24
24
|
echo -e " ${CYAN}overview${RESET} View or set project overview"
|
|
25
25
|
echo -e " ${CYAN}memories${RESET} Browse and search Claude Code memories, plans, and tasks"
|
|
26
26
|
echo -e " ${CYAN}scan${RESET} Analyze a project and generate an overview"
|
|
@@ -35,8 +35,8 @@ echo ""
|
|
|
35
35
|
echo -e " ${BOLD}Examples:${RESET}"
|
|
36
36
|
echo -e " ${DIM}\$${RESET} eagle-mem search \"auth bug\" ${DIM}# Search memory${RESET}"
|
|
37
37
|
echo -e " ${DIM}\$${RESET} eagle-mem search --timeline ${DIM}# Recent sessions${RESET}"
|
|
38
|
-
echo -e " ${DIM}\$${RESET} eagle-mem tasks ${DIM}#
|
|
39
|
-
echo -e " ${DIM}\$${RESET} eagle-mem tasks
|
|
38
|
+
echo -e " ${DIM}\$${RESET} eagle-mem tasks ${DIM}# View pending tasks${RESET}"
|
|
39
|
+
echo -e " ${DIM}\$${RESET} eagle-mem tasks search \"X\" ${DIM}# Search task history${RESET}"
|
|
40
40
|
echo -e " ${DIM}\$${RESET} eagle-mem overview ${DIM}# View overview${RESET}"
|
|
41
41
|
echo -e " ${DIM}\$${RESET} eagle-mem scan . ${DIM}# Scan current project${RESET}"
|
|
42
42
|
echo -e " ${DIM}\$${RESET} eagle-mem index . ${DIM}# Index source files${RESET}"
|
|
@@ -53,11 +53,11 @@ echo -e " ${DOT} Injects relevant memory at session start"
|
|
|
53
53
|
echo -e " ${DOT} Searches past sessions when you ask related questions"
|
|
54
54
|
echo -e " ${DOT} Tracks file operations across sessions"
|
|
55
55
|
echo -e " ${DOT} Mirrors Claude Code memories, plans, and tasks into FTS5-searchable storage"
|
|
56
|
-
echo -e " ${DOT}
|
|
56
|
+
echo -e " ${DOT} Uses Claude Code's native task system (TaskCreate/TaskUpdate) for multi-step work"
|
|
57
57
|
echo ""
|
|
58
58
|
echo -e " ${BOLD}Skills${RESET} ${DIM}(available inside Claude Code):${RESET}"
|
|
59
59
|
echo -e " ${CYAN}/eagle-mem-search${RESET} Search past sessions and observations"
|
|
60
|
-
echo -e " ${CYAN}/eagle-mem-tasks${RESET} Break work into
|
|
60
|
+
echo -e " ${CYAN}/eagle-mem-tasks${RESET} Break work into Claude Code tasks with dependencies"
|
|
61
61
|
echo -e " ${CYAN}/eagle-mem-overview${RESET} Generate a persistent project summary"
|
|
62
62
|
echo -e " ${CYAN}/eagle-mem-index${RESET} Index source files for code search"
|
|
63
63
|
echo -e " ${CYAN}/eagle-mem-scan${RESET} Scan and analyze a project"
|
package/scripts/search.sh
CHANGED
|
@@ -249,7 +249,7 @@ search_stats() {
|
|
|
249
249
|
sessions=$(eagle_db "SELECT COUNT(*) FROM sessions WHERE project = '$p';")
|
|
250
250
|
summaries=$(eagle_db "SELECT COUNT(*) FROM summaries WHERE project = '$p';")
|
|
251
251
|
observations=$(eagle_db "SELECT COUNT(*) FROM observations o JOIN sessions s ON s.id = o.session_id WHERE s.project = '$p';")
|
|
252
|
-
tasks=$(eagle_db "SELECT COUNT(*) FROM
|
|
252
|
+
tasks=$(eagle_db "SELECT COUNT(*) FROM claude_tasks WHERE project = '$p';")
|
|
253
253
|
local chunks
|
|
254
254
|
chunks=$(eagle_db "SELECT COUNT(*) FROM code_chunks WHERE project = '$p';")
|
|
255
255
|
|
package/scripts/tasks.sh
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ═══════════════════════════════════════════════════════════
|
|
3
|
-
# Eagle Mem — Tasks
|
|
4
|
-
#
|
|
3
|
+
# Eagle Mem — Tasks (read-only viewer of Claude Code tasks)
|
|
4
|
+
# Claude Code manages task state via TaskCreate/TaskUpdate;
|
|
5
|
+
# Eagle Mem mirrors it and displays it here.
|
|
5
6
|
# ═══════════════════════════════════════════════════════════
|
|
6
7
|
set -euo pipefail
|
|
7
8
|
|
|
@@ -22,28 +23,25 @@ shift 2>/dev/null || true
|
|
|
22
23
|
project=""
|
|
23
24
|
json_output=false
|
|
24
25
|
|
|
25
|
-
# Extract global options from remaining args
|
|
26
|
-
args=()
|
|
27
|
-
|
|
28
26
|
show_help() {
|
|
29
|
-
echo -e " ${BOLD}eagle-mem tasks${RESET} —
|
|
27
|
+
echo -e " ${BOLD}eagle-mem tasks${RESET} — View mirrored Claude Code tasks"
|
|
30
28
|
echo ""
|
|
31
29
|
echo -e " ${BOLD}Usage:${RESET}"
|
|
32
|
-
echo -e " eagle-mem tasks
|
|
33
|
-
echo -e " eagle-mem tasks ${CYAN}list${RESET}
|
|
34
|
-
echo -e " eagle-mem tasks ${CYAN}
|
|
35
|
-
echo -e " eagle-mem tasks ${CYAN}done${RESET} <id> ${DIM}# mark task complete${RESET}"
|
|
36
|
-
echo -e " eagle-mem tasks ${CYAN}block${RESET} <id> ${DIM}# mark task blocked${RESET}"
|
|
37
|
-
echo -e " eagle-mem tasks ${CYAN}context${RESET} <id> <snapshot> ${DIM}# set task context${RESET}"
|
|
38
|
-
echo -e " eagle-mem tasks ${CYAN}clear${RESET} ${DIM}# remove all done tasks${RESET}"
|
|
30
|
+
echo -e " eagle-mem tasks ${DIM}# list pending/in-progress tasks${RESET}"
|
|
31
|
+
echo -e " eagle-mem tasks ${CYAN}list${RESET} ${DIM}# list all tasks${RESET}"
|
|
32
|
+
echo -e " eagle-mem tasks ${CYAN}search${RESET} <query> ${DIM}# search tasks by keyword${RESET}"
|
|
39
33
|
echo ""
|
|
40
34
|
echo -e " ${BOLD}Options:${RESET}"
|
|
41
35
|
echo -e " ${CYAN}-p, --project${RESET} <name> Project name (default: current dir)"
|
|
42
36
|
echo -e " ${CYAN}-j, --json${RESET} Output as JSON"
|
|
43
37
|
echo ""
|
|
38
|
+
echo -e " ${DIM}Tasks are managed by Claude Code (TaskCreate/TaskUpdate).${RESET}"
|
|
39
|
+
echo -e " ${DIM}Eagle Mem automatically mirrors them for cross-session recall.${RESET}"
|
|
40
|
+
echo ""
|
|
44
41
|
exit 0
|
|
45
42
|
}
|
|
46
43
|
|
|
44
|
+
args=()
|
|
47
45
|
while [ $# -gt 0 ]; do
|
|
48
46
|
case "$1" in
|
|
49
47
|
--project|-p) project="$2"; shift 2 ;;
|
|
@@ -63,24 +61,28 @@ tasks_list() {
|
|
|
63
61
|
|
|
64
62
|
local where_status=""
|
|
65
63
|
case "$filter" in
|
|
66
|
-
pending) where_status="AND status IN ('pending', '
|
|
67
|
-
|
|
68
|
-
all)
|
|
64
|
+
pending) where_status="AND status IN ('pending', 'in_progress')" ;;
|
|
65
|
+
completed) where_status="AND status = 'completed'" ;;
|
|
66
|
+
all) where_status="" ;;
|
|
69
67
|
esac
|
|
70
68
|
|
|
71
69
|
if [ "$json_output" = true ]; then
|
|
72
|
-
eagle_db_json "SELECT
|
|
73
|
-
FROM
|
|
70
|
+
eagle_db_json "SELECT source_task_id, subject, description, status, blocks, blocked_by, updated_at
|
|
71
|
+
FROM claude_tasks
|
|
74
72
|
WHERE project = '$project_sql' $where_status
|
|
75
|
-
ORDER BY
|
|
73
|
+
ORDER BY updated_at DESC
|
|
74
|
+
LIMIT 20;"
|
|
76
75
|
return
|
|
77
76
|
fi
|
|
78
77
|
|
|
79
78
|
local results
|
|
80
|
-
results=$(eagle_db "SELECT
|
|
81
|
-
FROM
|
|
79
|
+
results=$(eagle_db "SELECT source_task_id, subject, status, blocked_by, description
|
|
80
|
+
FROM claude_tasks
|
|
82
81
|
WHERE project = '$project_sql' $where_status
|
|
83
|
-
ORDER BY
|
|
82
|
+
ORDER BY
|
|
83
|
+
CASE status WHEN 'in_progress' THEN 0 WHEN 'pending' THEN 1 ELSE 2 END,
|
|
84
|
+
updated_at DESC
|
|
85
|
+
LIMIT 20;")
|
|
84
86
|
|
|
85
87
|
if [ -z "$results" ]; then
|
|
86
88
|
eagle_dim "No tasks for project '$project'"
|
|
@@ -92,170 +94,74 @@ tasks_list() {
|
|
|
92
94
|
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
93
95
|
echo ""
|
|
94
96
|
|
|
95
|
-
while IFS='|' read -r tid
|
|
97
|
+
while IFS='|' read -r tid subject status blocked_by desc; do
|
|
96
98
|
[ -z "$tid" ] && continue
|
|
97
99
|
local icon marker
|
|
98
100
|
case "$status" in
|
|
99
|
-
|
|
100
|
-
pending)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*)
|
|
101
|
+
in_progress) icon="${CYAN}>${RESET}"; marker=" ${CYAN}[in_progress]${RESET}" ;;
|
|
102
|
+
pending) icon="${DIM}o${RESET}"; marker="" ;;
|
|
103
|
+
completed) icon="${GREEN}+${RESET}"; marker=" ${DIM}[completed]${RESET}" ;;
|
|
104
|
+
deleted) icon="${RED}x${RESET}"; marker=" ${RED}[deleted]${RESET}" ;;
|
|
105
|
+
*) icon="$DOT"; marker="" ;;
|
|
104
106
|
esac
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
if [ "$blocked_by" != "[]" ] && [ -n "$blocked_by" ]; then
|
|
108
|
+
marker+=" ${DIM}(blocked)${RESET}"
|
|
109
|
+
fi
|
|
110
|
+
echo -e " ${icon} ${BOLD}$tid${RESET} $subject$marker"
|
|
111
|
+
[ -n "$desc" ] && echo -e " ${DIM}$(echo "$desc" | cut -c1-80)${RESET}"
|
|
107
112
|
done <<< "$results"
|
|
108
113
|
echo ""
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
# ───
|
|
112
|
-
|
|
113
|
-
tasks_add() {
|
|
114
|
-
local title="${args[0]:-}"
|
|
115
|
-
local instructions="${args[1]:-}"
|
|
116
|
-
|
|
117
|
-
if [ -z "$title" ]; then
|
|
118
|
-
eagle_err "Usage: eagle-mem tasks add <title> [instructions]"
|
|
119
|
-
exit 1
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
local title_sql; title_sql=$(eagle_sql_escape "$title")
|
|
123
|
-
local instr_sql; instr_sql=$(eagle_sql_escape "$instructions")
|
|
124
|
-
|
|
125
|
-
local max_ord
|
|
126
|
-
max_ord=$(eagle_db "SELECT COALESCE(MAX(ordinal), 0) FROM tasks WHERE project = '$project_sql';")
|
|
127
|
-
local next_ord=$((max_ord + 1))
|
|
128
|
-
|
|
129
|
-
local new_id
|
|
130
|
-
new_id=$(eagle_db "INSERT INTO tasks (project, title, instructions, ordinal)
|
|
131
|
-
VALUES ('$project_sql', '$title_sql', '$instr_sql', $next_ord);
|
|
132
|
-
SELECT last_insert_rowid();")
|
|
133
|
-
|
|
134
|
-
if [ "$json_output" = true ]; then
|
|
135
|
-
jq -nc --arg id "$new_id" --arg title "$title" --argjson ord "$next_ord" \
|
|
136
|
-
'{id: ($id | tonumber), title: $title, ordinal: $ord}'
|
|
137
|
-
return
|
|
138
|
-
fi
|
|
139
|
-
|
|
140
|
-
eagle_ok "Task #$new_id added: $title"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
# ─── Done ─────────────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
tasks_done() {
|
|
146
|
-
local task_id="${args[0]:-}"
|
|
116
|
+
# ─── Search tasks ─────────────────────────────────────────
|
|
147
117
|
|
|
148
|
-
|
|
149
|
-
|
|
118
|
+
tasks_search() {
|
|
119
|
+
local query="${args[0]:-}"
|
|
120
|
+
if [ -z "$query" ]; then
|
|
121
|
+
eagle_err "Usage: eagle-mem tasks search <query>"
|
|
150
122
|
exit 1
|
|
151
123
|
fi
|
|
152
124
|
|
|
153
|
-
if ! [[ "$task_id" =~ ^[0-9]+$ ]]; then
|
|
154
|
-
eagle_err "Task ID must be a number, got: $task_id"
|
|
155
|
-
exit 1
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
local changed
|
|
159
|
-
changed=$(eagle_db "UPDATE tasks SET status = 'done', completed_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
160
|
-
WHERE id = $task_id AND project = '$project_sql';
|
|
161
|
-
SELECT changes();")
|
|
162
|
-
|
|
163
|
-
if [ "${changed:-0}" -eq 0 ]; then
|
|
164
|
-
eagle_err "Task #$task_id not found in project '$project'"
|
|
165
|
-
exit 1
|
|
166
|
-
fi
|
|
167
|
-
|
|
168
|
-
local title
|
|
169
|
-
title=$(eagle_db "SELECT title FROM tasks WHERE id = $task_id AND project = '$project_sql';")
|
|
170
|
-
|
|
171
125
|
if [ "$json_output" = true ]; then
|
|
172
|
-
|
|
126
|
+
local query_sql; query_sql=$(eagle_fts_sanitize "$query")
|
|
127
|
+
query_sql=$(eagle_sql_escape "$query_sql")
|
|
128
|
+
eagle_db_json "SELECT t.source_task_id, t.subject, t.status, t.description, t.updated_at
|
|
129
|
+
FROM claude_tasks t
|
|
130
|
+
JOIN claude_tasks_fts f ON f.rowid = t.id
|
|
131
|
+
WHERE claude_tasks_fts MATCH '$query_sql'
|
|
132
|
+
AND t.project = '$project_sql'
|
|
133
|
+
ORDER BY rank
|
|
134
|
+
LIMIT 10;"
|
|
173
135
|
return
|
|
174
136
|
fi
|
|
175
137
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
exit 1
|
|
187
|
-
fi
|
|
188
|
-
|
|
189
|
-
if ! [[ "$task_id" =~ ^[0-9]+$ ]]; then
|
|
190
|
-
eagle_err "Task ID must be a number, got: $task_id"
|
|
191
|
-
exit 1
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
|
-
local changed
|
|
195
|
-
changed=$(eagle_db "UPDATE tasks SET status = 'blocked' WHERE id = $task_id AND project = '$project_sql';
|
|
196
|
-
SELECT changes();")
|
|
197
|
-
|
|
198
|
-
if [ "${changed:-0}" -eq 0 ]; then
|
|
199
|
-
eagle_err "Task #$task_id not found in project '$project'"
|
|
200
|
-
exit 1
|
|
201
|
-
fi
|
|
202
|
-
|
|
203
|
-
if [ "$json_output" = true ]; then
|
|
204
|
-
jq -nc --arg id "$task_id" '{id: ($id | tonumber), status: "blocked"}'
|
|
205
|
-
return
|
|
206
|
-
fi
|
|
207
|
-
|
|
208
|
-
eagle_ok "Task #$task_id blocked"
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
# ─── Context snapshot ─────────────────────────────────────
|
|
212
|
-
|
|
213
|
-
tasks_context() {
|
|
214
|
-
local task_id="${args[0]:-}"
|
|
215
|
-
local snapshot="${args[1]:-}"
|
|
216
|
-
|
|
217
|
-
if [ -z "$task_id" ] || [ -z "$snapshot" ]; then
|
|
218
|
-
eagle_err "Usage: eagle-mem tasks context <id> <snapshot>"
|
|
219
|
-
exit 1
|
|
220
|
-
fi
|
|
221
|
-
|
|
222
|
-
if ! [[ "$task_id" =~ ^[0-9]+$ ]]; then
|
|
223
|
-
eagle_err "Task ID must be a number, got: $task_id"
|
|
224
|
-
exit 1
|
|
225
|
-
fi
|
|
226
|
-
|
|
227
|
-
local snap_sql; snap_sql=$(eagle_sql_escape "$snapshot")
|
|
228
|
-
local changed
|
|
229
|
-
changed=$(eagle_db "UPDATE tasks SET context_snapshot = '$snap_sql' WHERE id = $task_id AND project = '$project_sql';
|
|
230
|
-
SELECT changes();")
|
|
231
|
-
|
|
232
|
-
if [ "${changed:-0}" -eq 0 ]; then
|
|
233
|
-
eagle_err "Task #$task_id not found in project '$project'"
|
|
234
|
-
exit 1
|
|
235
|
-
fi
|
|
138
|
+
local results
|
|
139
|
+
local query_sql; query_sql=$(eagle_fts_sanitize "$query")
|
|
140
|
+
query_sql=$(eagle_sql_escape "$query_sql")
|
|
141
|
+
results=$(eagle_db "SELECT t.source_task_id, t.subject, t.status, t.description
|
|
142
|
+
FROM claude_tasks t
|
|
143
|
+
JOIN claude_tasks_fts f ON f.rowid = t.id
|
|
144
|
+
WHERE claude_tasks_fts MATCH '$query_sql'
|
|
145
|
+
AND t.project = '$project_sql'
|
|
146
|
+
ORDER BY rank
|
|
147
|
+
LIMIT 10;")
|
|
236
148
|
|
|
237
|
-
if [ "$
|
|
238
|
-
|
|
149
|
+
if [ -z "$results" ]; then
|
|
150
|
+
eagle_dim "No tasks matching '$query'"
|
|
239
151
|
return
|
|
240
152
|
fi
|
|
241
153
|
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
tasks_clear() {
|
|
248
|
-
local count
|
|
249
|
-
count=$(eagle_db "SELECT COUNT(*) FROM tasks WHERE project = '$project_sql' AND status = 'done';")
|
|
250
|
-
|
|
251
|
-
eagle_db "DELETE FROM tasks WHERE project = '$project_sql' AND status = 'done';"
|
|
252
|
-
|
|
253
|
-
if [ "$json_output" = true ]; then
|
|
254
|
-
jq -nc --argjson cleared "${count:-0}" '{cleared: $cleared}'
|
|
255
|
-
return
|
|
256
|
-
fi
|
|
154
|
+
echo ""
|
|
155
|
+
echo -e " ${BOLD}Task search:${RESET} $query"
|
|
156
|
+
echo -e " ${DIM}─────────────────────────────────────${RESET}"
|
|
157
|
+
echo ""
|
|
257
158
|
|
|
258
|
-
|
|
159
|
+
while IFS='|' read -r tid subject status desc; do
|
|
160
|
+
[ -z "$tid" ] && continue
|
|
161
|
+
echo -e " ${BOLD}$tid${RESET} [$status] $subject"
|
|
162
|
+
[ -n "$desc" ] && echo -e " ${DIM}$(echo "$desc" | cut -c1-80)${RESET}"
|
|
163
|
+
done <<< "$results"
|
|
164
|
+
echo ""
|
|
259
165
|
}
|
|
260
166
|
|
|
261
167
|
# ─── Dispatch ─────────────────────────────────────────────
|
|
@@ -263,12 +169,9 @@ tasks_clear() {
|
|
|
263
169
|
case "$action" in
|
|
264
170
|
list) tasks_list "all" ;;
|
|
265
171
|
pending) tasks_list "pending" ;;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
context) tasks_context ;;
|
|
270
|
-
clear) tasks_clear ;;
|
|
271
|
-
--help|-h) show_help ;;
|
|
172
|
+
completed) tasks_list "completed" ;;
|
|
173
|
+
search) tasks_search ;;
|
|
174
|
+
--help|-h) show_help ;;
|
|
272
175
|
*)
|
|
273
176
|
eagle_err "Unknown action: $action"
|
|
274
177
|
eagle_dim " Run 'eagle-mem tasks --help' for options"
|
|
@@ -1,100 +1,92 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eagle-mem-tasks
|
|
3
3
|
description: >
|
|
4
|
-
TaskAware Compact Loop — break complex work into
|
|
5
|
-
between each. Use when: 'eagle tasks', 'break this into tasks', 'create task plan',
|
|
6
|
-
'task loop', 'compact loop', 'eagle mem tasks'. Uses
|
|
4
|
+
TaskAware Compact Loop — break complex work into Claude Code tasks with dependencies,
|
|
5
|
+
compact between each. Use when: 'eagle tasks', 'break this into tasks', 'create task plan',
|
|
6
|
+
'task loop', 'compact loop', 'eagle mem tasks'. Uses Claude Code's native TaskCreate/TaskUpdate.
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Eagle Mem — TaskAware Compact Loop
|
|
10
10
|
|
|
11
|
-
Break complex work into subtasks
|
|
11
|
+
Break complex work into subtasks using Claude Code's native task system. Execute one task at a time, compact between each, and let Eagle Mem re-inject task state for the next task.
|
|
12
12
|
|
|
13
13
|
## How it works
|
|
14
14
|
|
|
15
15
|
1. **Plan**: Break the user's request into ordered subtasks
|
|
16
|
-
2. **
|
|
17
|
-
3. **Execute**: Work on the current task (
|
|
18
|
-
4. **
|
|
19
|
-
5. **
|
|
20
|
-
6. **
|
|
16
|
+
2. **Create**: Add each subtask via `TaskCreate` with dependencies via `addBlockedBy`
|
|
17
|
+
3. **Execute**: Work on the current task (mark `in_progress` with `TaskUpdate`)
|
|
18
|
+
4. **Complete**: Mark done with `TaskUpdate(completed)`, emit `<eagle-summary>`
|
|
19
|
+
5. **Compact**: Tell the user to run `/compact`
|
|
20
|
+
6. **Resume**: After compact, SessionStart re-injects memory + loads task state from Eagle Mem's mirror
|
|
21
|
+
7. **Repeat**: Until all tasks are done
|
|
21
22
|
|
|
22
|
-
##
|
|
23
|
+
## Creating tasks
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
Use Claude Code's `TaskCreate` tool. Each task gets `pending` status automatically.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
eagle-mem tasks
|
|
28
|
-
eagle-mem tasks list
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Add tasks
|
|
32
|
-
|
|
33
|
-
When the user invokes `/eagle-mem-tasks` or asks to break work into tasks:
|
|
34
|
-
|
|
35
|
-
1. Analyze the request and break it into 3-8 focused subtasks
|
|
36
|
-
2. Each task should be completable in one context window
|
|
37
|
-
3. Add tasks using the CLI:
|
|
27
|
+
For tasks that depend on earlier work, use `addBlockedBy` in `TaskUpdate`:
|
|
38
28
|
|
|
39
|
-
```bash
|
|
40
|
-
eagle-mem tasks add "Set up project structure" "Install deps, create folders, init config"
|
|
41
|
-
eagle-mem tasks add "Implement auth middleware" "JWT validation, role checks, error responses"
|
|
42
|
-
eagle-mem tasks add "Build CRUD endpoints" "Users and posts REST API with validation"
|
|
43
29
|
```
|
|
30
|
+
TaskCreate({ subject: "Set up project structure", description: "Install deps, create folders, init config" })
|
|
31
|
+
TaskCreate({ subject: "Implement auth middleware", description: "JWT validation, role checks, error responses" })
|
|
32
|
+
TaskCreate({ subject: "Build CRUD endpoints", description: "Users and posts REST API with validation" })
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### Complete a task
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
eagle-mem tasks done <id>
|
|
34
|
+
// Then set dependencies:
|
|
35
|
+
TaskUpdate({ taskId: "3", addBlockedBy: ["1", "2"] })
|
|
52
36
|
```
|
|
53
37
|
|
|
54
|
-
|
|
55
|
-
1. Emit your `<eagle-summary>` block
|
|
56
|
-
2. Tell the user: **"Task #N complete. Run `/compact` to save progress and load the next task."**
|
|
38
|
+
## Working on a task
|
|
57
39
|
|
|
58
|
-
|
|
40
|
+
1. Call `TaskUpdate({ taskId: "N", status: "in_progress" })` before starting work
|
|
41
|
+
2. Do the work
|
|
42
|
+
3. Call `TaskUpdate({ taskId: "N", status: "completed" })` when done
|
|
43
|
+
4. Emit your `<eagle-summary>` block
|
|
44
|
+
5. Tell the user: **"Task complete. Run `/compact` to save progress and load the next task."**
|
|
59
45
|
|
|
60
|
-
|
|
61
|
-
eagle-mem tasks block <id>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Set context snapshot
|
|
46
|
+
## Viewing tasks
|
|
65
47
|
|
|
66
|
-
|
|
48
|
+
Use `TaskList` to see all tasks, or the CLI for cross-session history:
|
|
67
49
|
|
|
68
50
|
```bash
|
|
69
|
-
eagle-mem tasks
|
|
51
|
+
eagle-mem tasks # pending/in-progress (from mirror)
|
|
52
|
+
eagle-mem tasks list # all tasks
|
|
53
|
+
eagle-mem tasks search <q> # FTS5 search across task history
|
|
70
54
|
```
|
|
71
55
|
|
|
72
|
-
|
|
56
|
+
## Cross-session context
|
|
73
57
|
|
|
74
|
-
|
|
75
|
-
eagle-mem tasks clear
|
|
76
|
-
```
|
|
58
|
+
When a task depends on decisions made in earlier tasks, put that context in the task's `description` field — it persists across compactions via Eagle Mem's mirror.
|
|
77
59
|
|
|
78
|
-
|
|
60
|
+
For example, if task 1 decides to use JWT with RS256:
|
|
79
61
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| `-j, --json` | Output as JSON |
|
|
62
|
+
```
|
|
63
|
+
TaskUpdate({ taskId: "2", description: "Implement auth middleware. Decision from task 1: using JWT with RS256, sessions stored in Redis." })
|
|
64
|
+
```
|
|
84
65
|
|
|
85
66
|
## Task design guidelines
|
|
86
67
|
|
|
87
|
-
- Each task should be **self-contained** — completable
|
|
88
|
-
- Include
|
|
89
|
-
- Use
|
|
90
|
-
- Order tasks so
|
|
68
|
+
- Each task should be **self-contained** — completable in one context window
|
|
69
|
+
- Include enough detail in `description` that a fresh context window can pick it up
|
|
70
|
+
- Use `addBlockedBy` for tasks that depend on earlier tasks
|
|
71
|
+
- Order tasks so foundational work comes first (schema before API, API before UI)
|
|
72
|
+
- Keep tasks focused: 3-8 tasks per plan
|
|
91
73
|
|
|
92
74
|
## The compact cycle
|
|
93
75
|
|
|
94
76
|
```
|
|
95
|
-
User request
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
77
|
+
User request -> Plan tasks (TaskCreate) -> Execute task 1 (TaskUpdate: in_progress)
|
|
78
|
+
-> Complete task 1 (TaskUpdate: completed) -> /compact
|
|
79
|
+
-> Eagle Mem saves summary -> Context cleared -> Task state re-injected
|
|
80
|
+
-> Execute task 2 -> /compact
|
|
81
|
+
-> ... repeat until all tasks done ...
|
|
82
|
+
-> Final summary: "All N tasks complete."
|
|
100
83
|
```
|
|
84
|
+
|
|
85
|
+
## Status reference
|
|
86
|
+
|
|
87
|
+
| Status | Meaning |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `pending` | Not started yet |
|
|
90
|
+
| `in_progress` | Currently being worked on |
|
|
91
|
+
| `completed` | Done |
|
|
92
|
+
| `deleted` | Removed |
|