eagle-mem 4.9.6 → 4.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -4
- package/architecture.html +1791 -0
- package/bin/eagle-mem +1 -0
- package/db/migrate.sh +13 -2
- package/docs/visible-surface-ux-contract.md +53 -0
- package/hooks/post-tool-use.sh +2 -2
- package/hooks/pre-tool-use.sh +6 -6
- package/hooks/session-start.sh +216 -9
- package/hooks/user-prompt-submit.sh +72 -15
- package/lib/common.sh +485 -35
- package/lib/db-mirrors.sh +9 -18
- package/lib/db-sessions.sh +22 -15
- package/lib/db-summaries.sh +19 -7
- package/lib/hooks-posttool.sh +44 -10
- package/lib/updater.sh +12 -0
- package/package.json +4 -2
- package/scripts/doctor.sh +262 -0
- package/scripts/feature.sh +37 -11
- package/scripts/health.sh +10 -7
- package/scripts/help.sh +1 -0
- package/scripts/install.sh +9 -3
- package/scripts/memories.sh +258 -65
- package/scripts/orchestrate.sh +2 -2
- package/scripts/search.sh +240 -56
- package/scripts/statusline-em.sh +130 -26
- package/scripts/uninstall.sh +67 -0
- package/scripts/update.sh +8 -1
package/bin/eagle-mem
CHANGED
|
@@ -21,6 +21,7 @@ case "$command" in
|
|
|
21
21
|
uninstall) bash "$SCRIPTS_DIR/uninstall.sh" "$@" ;;
|
|
22
22
|
search) bash "$SCRIPTS_DIR/search.sh" "$@" ;;
|
|
23
23
|
health) bash "$SCRIPTS_DIR/health.sh" "$@" ;;
|
|
24
|
+
doctor) bash "$SCRIPTS_DIR/doctor.sh" "$PACKAGE_DIR" "$@" ;;
|
|
24
25
|
config) bash "$SCRIPTS_DIR/config.sh" "$@" ;;
|
|
25
26
|
updates) bash "$SCRIPTS_DIR/updates.sh" "$@" ;;
|
|
26
27
|
statusline) "$SCRIPTS_DIR/statusline-em.sh" "$@" ;;
|
package/db/migrate.sh
CHANGED
|
@@ -44,7 +44,18 @@ run_migration() {
|
|
|
44
44
|
|
|
45
45
|
# Set connection PRAGMAs, then run migration body + tracking insert atomically
|
|
46
46
|
# .bail on ensures sqlite3 stops on the first error instead of continuing
|
|
47
|
-
{
|
|
47
|
+
{
|
|
48
|
+
echo ".bail on"
|
|
49
|
+
echo ".output /dev/null"
|
|
50
|
+
echo "PRAGMA trusted_schema=ON;"
|
|
51
|
+
echo "PRAGMA foreign_keys=ON;"
|
|
52
|
+
echo "PRAGMA busy_timeout=5000;"
|
|
53
|
+
echo ".output stdout"
|
|
54
|
+
echo "BEGIN;"
|
|
55
|
+
echo "$body"
|
|
56
|
+
echo "INSERT INTO _migrations (name) VALUES ('$name');"
|
|
57
|
+
echo "COMMIT;"
|
|
58
|
+
} | "$SQLITE_BIN" "$DB"
|
|
48
59
|
echo " applied: $name"
|
|
49
60
|
fi
|
|
50
61
|
}
|
|
@@ -57,7 +68,7 @@ run_migration() {
|
|
|
57
68
|
);"
|
|
58
69
|
|
|
59
70
|
# Set PRAGMAs (these must be set on every connection)
|
|
60
|
-
"$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;"
|
|
71
|
+
"$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;" >/dev/null
|
|
61
72
|
|
|
62
73
|
# ─── Migration 001: Initial schema (special name) ──────────
|
|
63
74
|
run_migration "001_initial_schema" "$SCRIPT_DIR/schema.sql"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Eagle Mem Visible Surface UX Contract
|
|
2
|
+
|
|
3
|
+
Eagle Mem has two audiences for visible output:
|
|
4
|
+
|
|
5
|
+
- The user, who should see a calm product surface.
|
|
6
|
+
- The active agent, which needs compact operational context without raw internals.
|
|
7
|
+
|
|
8
|
+
Default output must be useful without exposing implementation details. Raw database
|
|
9
|
+
IDs, file paths, session IDs, backing JSON, hook payloads, and source file content
|
|
10
|
+
belong behind `--raw`, `--debug`, or `--json`.
|
|
11
|
+
|
|
12
|
+
## Output Modes
|
|
13
|
+
|
|
14
|
+
| Mode | Purpose | Allowed Content |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| Default | Human product UX | Brand, status, concise summaries, freshness, next action |
|
|
17
|
+
| `--json` | Machine-readable automation | Structured complete fields |
|
|
18
|
+
| `--raw` | Developer inspection | IDs, source paths, backing files, raw task JSON |
|
|
19
|
+
| `--debug` | Troubleshooting | Same as `--raw`, plus diagnostic hints where useful |
|
|
20
|
+
|
|
21
|
+
## Visible Surfaces
|
|
22
|
+
|
|
23
|
+
| Surface | User Sees It? | Default Standard |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `SessionStart` | Yes, in agent transcript | Branded compact briefing: project, memory, relevant now, work state, guardrails |
|
|
26
|
+
| `UserPromptSubmit` | Yes, in agent transcript | `Eagle Mem recalls` with 1-2 useful bullets and relevant code |
|
|
27
|
+
| `PreToolUse` | Sometimes, when blocking | Calm explanation, recommended fix, one-off bypass if appropriate |
|
|
28
|
+
| `PostToolUse` | Sometimes, after reads/edits | Structured memory/decision/feature notes, no separator blocks for Codex |
|
|
29
|
+
| `statusline` | Yes | Short branded status: version, sessions, memories, turn |
|
|
30
|
+
| `search` | Yes | Freshness-aware results, no raw IDs in headings |
|
|
31
|
+
| `memories` | Yes | Project-scoped list by default, no source paths unless raw/debug |
|
|
32
|
+
| `tasks` | Yes | Task subject/status/source, no session/task IDs unless raw/debug |
|
|
33
|
+
| `feature` | Yes | Pending work grouped by action, raw diff fingerprints only when needed |
|
|
34
|
+
| `health` | Yes | Overall verdict first, then sectioned checks and next action |
|
|
35
|
+
| `install/update/uninstall` | Yes | Explain changed footprint, reversibility, backups, and success/failure plainly |
|
|
36
|
+
| `doctor` | Yes | Trust report: installed runtime, hooks, SQLite/FTS5, install manifest, drift, uninstall coverage |
|
|
37
|
+
|
|
38
|
+
## Product Voice
|
|
39
|
+
|
|
40
|
+
- Use `Eagle Mem` or `Eagle`; avoid cryptic `EM` in user-facing output.
|
|
41
|
+
- Prefer headings like `Relevant now`, `Work state`, `Guardrail`, and `Next`.
|
|
42
|
+
- Prefer freshness labels like `Fresh`, `Recent`, `Older`, or `may be stale`.
|
|
43
|
+
- Avoid dumping raw hook payloads, XML templates, SQL results, or JSON unless the user requested raw/debug output.
|
|
44
|
+
- Keep Codex transcript injections more compact than Claude Code injections.
|
|
45
|
+
|
|
46
|
+
## Install/Update/Uninstall Standard
|
|
47
|
+
|
|
48
|
+
- Before mutating user config or runtime files, show a short "What will change" plan.
|
|
49
|
+
- Treat `--dry-run` as a first-class product path for destructive or cleanup commands.
|
|
50
|
+
- Back up user-owned config files before editing `~/.claude` or `~/.codex` state.
|
|
51
|
+
- Preserve `~/.eagle-mem/memory.db` by default; require explicit confirmation before deleting stored memory.
|
|
52
|
+
- After install/update, write a manifest with runtime file metadata so `doctor` can verify drift without noisy shell dumps.
|
|
53
|
+
- Prefer one clear verdict first (`Healthy`, `Needs attention`, or `Broken`), then details.
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -200,8 +200,8 @@ esac
|
|
|
200
200
|
|
|
201
201
|
eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project" "$agent"
|
|
202
202
|
eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input" "$agent"
|
|
203
|
-
eagle_posttool_stale_hint "$tool_name" "$fp" "$project"
|
|
204
|
-
eagle_posttool_decision_surface "$tool_name" "$fp" "$project"
|
|
203
|
+
eagle_posttool_stale_hint "$tool_name" "$fp" "$project" "$agent"
|
|
204
|
+
eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
|
|
205
205
|
|
|
206
206
|
# ─── Record observation ──────────────────────────────────
|
|
207
207
|
|
package/hooks/pre-tool-use.sh
CHANGED
|
@@ -96,12 +96,12 @@ Pending checks:"
|
|
|
96
96
|
rtk_cmd=$(eagle_rtk_rewrite_command "$cmd")
|
|
97
97
|
if [ -n "$rtk_cmd" ]; then
|
|
98
98
|
if [ "$agent" = "codex" ] && [ "$raw_bash_mode" != "allow" ] && ! eagle_raw_bash_unlock_active; then
|
|
99
|
-
reason="Eagle Mem
|
|
99
|
+
reason="Eagle Mem blocked raw shell output to keep Codex context clean.
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Recommended compact command:
|
|
102
102
|
$rtk_cmd
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
One-off developer bypass:
|
|
105
105
|
touch $EAGLE_RAW_BASH_UNLOCK"
|
|
106
106
|
jq -nc --arg reason "$reason" '{
|
|
107
107
|
"decision":"block",
|
|
@@ -120,15 +120,15 @@ Temporary escape hatch for one-off raw output:
|
|
|
120
120
|
context+="Eagle Mem token guard: rewrote raw shell command through RTK to reduce context load: ${rtk_cmd}. "
|
|
121
121
|
fi
|
|
122
122
|
elif [ "$rtk_mode" = "enforce" ] && ! command -v rtk >/dev/null 2>&1 && eagle_raw_output_command_needs_guard "$cmd" && ! eagle_raw_bash_unlock_active; then
|
|
123
|
-
reason="Eagle Mem
|
|
123
|
+
reason="Eagle Mem blocked this command because RTK enforcement is on, but RTK is not installed or not on PATH.
|
|
124
124
|
|
|
125
125
|
This command can dump raw output into agent context:
|
|
126
126
|
$cmd
|
|
127
127
|
|
|
128
|
-
Install RTK or
|
|
128
|
+
Install RTK or switch enforcement to auto:
|
|
129
129
|
eagle-mem config set token_guard.rtk auto
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
One-off developer bypass:
|
|
132
132
|
touch $EAGLE_RAW_BASH_UNLOCK"
|
|
133
133
|
jq -nc --arg reason "$reason" '{
|
|
134
134
|
"decision":"block",
|
package/hooks/session-start.sh
CHANGED
|
@@ -37,6 +37,12 @@ project=$(eagle_project_from_hook_input "$input")
|
|
|
37
37
|
[ -z "$project" ] && exit 0
|
|
38
38
|
|
|
39
39
|
p_esc=$(eagle_sql_escape "$project")
|
|
40
|
+
recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
|
|
41
|
+
[ -z "$recall_scope" ] && recall_scope="$project"
|
|
42
|
+
recall_scope_label=$(eagle_project_scope_label "$recall_scope")
|
|
43
|
+
recall_project_filter=$(eagle_sql_project_scope_condition "project" "$recall_scope")
|
|
44
|
+
recall_memory_filter=$(eagle_sql_project_scope_condition "m.project" "$recall_scope")
|
|
45
|
+
recall_lane_filter=$(eagle_sql_project_scope_condition "l.project" "$recall_scope")
|
|
40
46
|
|
|
41
47
|
eagle_log "INFO" "SessionStart: session=$session_id project=$project source=$source_type agent=$agent"
|
|
42
48
|
|
|
@@ -96,7 +102,7 @@ while IFS='|' read -r key val; do
|
|
|
96
102
|
last_active) stat_last_active="$val" ;;
|
|
97
103
|
last_summary) stat_last_summary="$val" ;;
|
|
98
104
|
esac
|
|
99
|
-
done <<< "$(eagle_get_project_stats "$
|
|
105
|
+
done <<< "$(eagle_get_project_stats "$recall_scope")"
|
|
100
106
|
|
|
101
107
|
# ─── Build compressed banner (elide zero-value lines) ────
|
|
102
108
|
|
|
@@ -119,6 +125,10 @@ eagle_banner="======================================
|
|
|
119
125
|
Project | $project
|
|
120
126
|
Agent | $agent_label
|
|
121
127
|
Sessions | $stat_sessions ($stat_with_summaries with summaries)"
|
|
128
|
+
if [ "$recall_scope_label" != "$project" ]; then
|
|
129
|
+
eagle_banner+="
|
|
130
|
+
Recall Scope | $recall_scope_label"
|
|
131
|
+
fi
|
|
122
132
|
if [ "$stat_sessions_codex" -gt 0 ] || [ "$stat_sessions_claude" -gt 0 ]; then
|
|
123
133
|
eagle_banner+="
|
|
124
134
|
Sources | Claude $stat_sessions_claude, Codex $stat_sessions_codex"
|
|
@@ -137,8 +147,196 @@ eagle_banner+="
|
|
|
137
147
|
======================================"
|
|
138
148
|
|
|
139
149
|
context="$eagle_banner
|
|
150
|
+
Eagle Mem recalls: use the project memory below before making design or implementation claims. If it affects your answer, mention the recall in one short attribution line.
|
|
140
151
|
"
|
|
141
152
|
|
|
153
|
+
if [ "$codex_compact" -eq 1 ]; then
|
|
154
|
+
codex_context="Eagle Mem Recall Ready
|
|
155
|
+
Project: $project | Agent: $agent_label
|
|
156
|
+
Memory: $stat_sessions sessions"
|
|
157
|
+
if [ "$recall_scope_label" != "$project" ]; then
|
|
158
|
+
codex_context="Eagle Mem Recall Ready
|
|
159
|
+
Project: $project | Recall: $recall_scope_label | Agent: $agent_label
|
|
160
|
+
Memory: $stat_sessions sessions"
|
|
161
|
+
fi
|
|
162
|
+
[ "$stat_with_summaries" -gt 0 ] && codex_context+=", $stat_with_summaries summarized"
|
|
163
|
+
[ "$stat_memories" -gt 0 ] && codex_context+=", $stat_memories memories"
|
|
164
|
+
[ "$stat_chunks" -gt 0 ] && codex_context+=", $stat_chunks code chunks"
|
|
165
|
+
codex_context+="
|
|
166
|
+
"
|
|
167
|
+
|
|
168
|
+
if [ -n "$update_notice" ]; then
|
|
169
|
+
codex_context+="
|
|
170
|
+
Update: $(eagle_trim_text "$update_notice" 180)
|
|
171
|
+
"
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
if [ "${stat_with_summaries:-0}" -eq 0 ] 2>/dev/null; then
|
|
175
|
+
codex_context+="
|
|
176
|
+
Capture: Codex hooks are active. Eagle Mem will summarize decisions and gotchas from the transcript automatically.
|
|
177
|
+
"
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
overview=$(eagle_get_overview "$project")
|
|
181
|
+
if [ -n "$overview" ]; then
|
|
182
|
+
codex_context+="
|
|
183
|
+
Project brief: $(eagle_trim_text "$overview" 260)
|
|
184
|
+
"
|
|
185
|
+
else
|
|
186
|
+
codex_context+="
|
|
187
|
+
Project brief: no overview yet; background scan is running.
|
|
188
|
+
"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
recent=$(eagle_get_recent_summaries "$recall_scope" 1)
|
|
192
|
+
if [ -n "$recent" ]; then
|
|
193
|
+
codex_context+="
|
|
194
|
+
Relevant now:
|
|
195
|
+
"
|
|
196
|
+
while IFS='|' read -r request completed learned _next_steps created_at _decisions gotchas _key_files summary_agent; do
|
|
197
|
+
[ -z "$request" ] && [ -z "$completed" ] && continue
|
|
198
|
+
summary_agent_label=$(eagle_agent_label "$summary_agent")
|
|
199
|
+
recent_line="$completed"
|
|
200
|
+
[ -z "$recent_line" ] && recent_line="$request"
|
|
201
|
+
codex_context+="- Recent [$summary_agent_label]: $(eagle_trim_text "$recent_line" 180)
|
|
202
|
+
"
|
|
203
|
+
[ -n "$learned" ] && codex_context+=" Learned: $(eagle_trim_text "$learned" 140)
|
|
204
|
+
"
|
|
205
|
+
[ -n "$gotchas" ] && codex_context+=" Watch: $(eagle_trim_text "$gotchas" 120)
|
|
206
|
+
"
|
|
207
|
+
done <<< "$recent"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
memories=$(eagle_db "SELECT memory_name, memory_type, description, origin_agent,
|
|
211
|
+
CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
|
|
212
|
+
FROM agent_memories
|
|
213
|
+
WHERE $recall_project_filter
|
|
214
|
+
AND memory_name NOT IN ('Codex Memory Registry', 'Codex Memory Summary')
|
|
215
|
+
ORDER BY
|
|
216
|
+
CASE
|
|
217
|
+
WHEN lower(memory_name) LIKE 'current status%' THEN 4
|
|
218
|
+
WHEN memory_type = 'project' THEN 0
|
|
219
|
+
WHEN memory_type = 'feedback' THEN 1
|
|
220
|
+
WHEN memory_type IN ('user', 'reference') THEN 2
|
|
221
|
+
ELSE 3
|
|
222
|
+
END,
|
|
223
|
+
updated_at DESC
|
|
224
|
+
LIMIT 4;")
|
|
225
|
+
if [ -n "$memories" ]; then
|
|
226
|
+
[ -z "$recent" ] && codex_context+="
|
|
227
|
+
Relevant now:
|
|
228
|
+
"
|
|
229
|
+
while IFS='|' read -r mname mtype mdesc morigin days_ago; do
|
|
230
|
+
[ -z "$mname" ] && continue
|
|
231
|
+
origin_label=$(eagle_agent_label "$morigin")
|
|
232
|
+
age_label="fresh"
|
|
233
|
+
if [ -n "$days_ago" ] && [ "$days_ago" -gt 14 ] 2>/dev/null; then
|
|
234
|
+
age_label="older"
|
|
235
|
+
elif [ -n "$days_ago" ] && [ "$days_ago" -gt 0 ] 2>/dev/null; then
|
|
236
|
+
age_label="${days_ago}d old"
|
|
237
|
+
fi
|
|
238
|
+
codex_context+="- Memory [$mtype][$origin_label][$age_label]: $mname"
|
|
239
|
+
[ -n "$mdesc" ] && codex_context+=" — $(eagle_trim_text "$mdesc" 120)"
|
|
240
|
+
codex_context+="
|
|
241
|
+
"
|
|
242
|
+
done <<< "$memories"
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
|
|
246
|
+
WHERE $recall_project_filter
|
|
247
|
+
AND status IN ('in_progress', 'pending')
|
|
248
|
+
AND source_session_id != 'orchestration'
|
|
249
|
+
AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
|
|
250
|
+
ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
|
|
251
|
+
LIMIT 3;")
|
|
252
|
+
orchestration_lanes=$(eagle_db "SELECT o.name, l.lane_key, l.title, l.agent, l.status
|
|
253
|
+
FROM orchestration_lanes l
|
|
254
|
+
JOIN orchestrations o ON o.id = l.orchestration_id
|
|
255
|
+
WHERE $recall_lane_filter
|
|
256
|
+
AND o.status = 'active'
|
|
257
|
+
AND l.status IN ('in_progress', 'pending', 'blocked')
|
|
258
|
+
ORDER BY CASE l.status WHEN 'in_progress' THEN 0 WHEN 'blocked' THEN 1 ELSE 2 END, l.updated_at DESC
|
|
259
|
+
LIMIT 3;" 2>/dev/null)
|
|
260
|
+
if [ -n "$synced_tasks" ] || [ -n "$orchestration_lanes" ]; then
|
|
261
|
+
codex_context+="
|
|
262
|
+
Work state:
|
|
263
|
+
"
|
|
264
|
+
while IFS='|' read -r tsubject tstatus tblocked torigin; do
|
|
265
|
+
[ -z "$tsubject" ] && continue
|
|
266
|
+
origin_label=$(eagle_agent_label "$torigin")
|
|
267
|
+
block_marker=""
|
|
268
|
+
[ "$tblocked" != "[]" ] && [ -n "$tblocked" ] && block_marker=" blocked"
|
|
269
|
+
codex_context+="- Task [$tstatus][$origin_label$block_marker]: $(eagle_trim_text "$tsubject" 130)
|
|
270
|
+
"
|
|
271
|
+
done <<< "$synced_tasks"
|
|
272
|
+
while IFS='|' read -r oname lkey ltitle lagent lstatus; do
|
|
273
|
+
[ -z "$lkey" ] && continue
|
|
274
|
+
origin_label=$(eagle_agent_label "$lagent")
|
|
275
|
+
codex_context+="- Lane [$lstatus][$origin_label]: $lkey"
|
|
276
|
+
[ -n "$ltitle" ] && codex_context+=" — $(eagle_trim_text "$ltitle" 100)"
|
|
277
|
+
[ -n "$oname" ] && codex_context+=" ($oname)"
|
|
278
|
+
codex_context+="
|
|
279
|
+
"
|
|
280
|
+
done <<< "$orchestration_lanes"
|
|
281
|
+
[ -n "$orchestration_lanes" ] && codex_context+=" Agent rule: you update lane status with eagle-mem orchestrate; do not ask the user to run it.
|
|
282
|
+
"
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
pending_features=$(eagle_list_pending_feature_verifications "$project" 3 2>/dev/null)
|
|
286
|
+
if [ -n "$pending_features" ]; then
|
|
287
|
+
codex_context+="
|
|
288
|
+
Guardrail:
|
|
289
|
+
"
|
|
290
|
+
while IFS='|' read -r pf_id pf_name pf_file pf_reason _pf_trigger _pf_created pf_smoke _pfingerprint; do
|
|
291
|
+
[ -z "$pf_id" ] && continue
|
|
292
|
+
codex_context+="- Pending verification #$pf_id: $pf_name"
|
|
293
|
+
[ -n "$pf_file" ] && codex_context+=" ($pf_file)"
|
|
294
|
+
[ -n "$pf_reason" ] && codex_context+=" — $(eagle_trim_text "$pf_reason" 90)"
|
|
295
|
+
[ -n "$pf_smoke" ] && codex_context+=" | smoke: $(eagle_trim_text "$pf_smoke" 100)"
|
|
296
|
+
codex_context+="
|
|
297
|
+
"
|
|
298
|
+
done <<< "$pending_features"
|
|
299
|
+
codex_context+=" Release commands are blocked until these are verified or waived.
|
|
300
|
+
"
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
hot_files=$(eagle_get_hot_files "$project")
|
|
304
|
+
if [ -n "$hot_files" ]; then
|
|
305
|
+
core_files=""
|
|
306
|
+
IFS=',' read -ra hf_arr <<< "$hot_files"
|
|
307
|
+
hf_count=0
|
|
308
|
+
for hf in "${hf_arr[@]}"; do
|
|
309
|
+
[ "$hf_count" -ge 5 ] && break
|
|
310
|
+
[ -z "$hf" ] && continue
|
|
311
|
+
[ -n "$core_files" ] && core_files+=", "
|
|
312
|
+
core_files+="$(basename "$hf")"
|
|
313
|
+
hf_count=$((hf_count + 1))
|
|
314
|
+
done
|
|
315
|
+
[ -n "$core_files" ] && codex_context+="
|
|
316
|
+
Core files: $core_files
|
|
317
|
+
"
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
if [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
|
|
321
|
+
working_set=$(eagle_get_working_set "$session_id")
|
|
322
|
+
if [ -n "$working_set" ]; then
|
|
323
|
+
codex_context+="
|
|
324
|
+
Working set:
|
|
325
|
+
"
|
|
326
|
+
while IFS='|' read -r ws_path ws_edits; do
|
|
327
|
+
[ -z "$ws_path" ] && continue
|
|
328
|
+
codex_context+="- $(basename "$ws_path") (${ws_edits} edits)
|
|
329
|
+
"
|
|
330
|
+
done <<< "$working_set"
|
|
331
|
+
fi
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
codex_context+="
|
|
335
|
+
Use recalled context only when relevant. Keep user-facing replies clean; do not print raw Eagle Mem internals."
|
|
336
|
+
eagle_emit_context_for_agent "$agent" "SessionStart" "$codex_context"
|
|
337
|
+
exit 0
|
|
338
|
+
fi
|
|
339
|
+
|
|
142
340
|
if [ -n "$update_notice" ]; then
|
|
143
341
|
context+="
|
|
144
342
|
=== Eagle Mem: Update Available ===
|
|
@@ -181,7 +379,7 @@ else
|
|
|
181
379
|
_summary_limit=2
|
|
182
380
|
fi
|
|
183
381
|
|
|
184
|
-
recent=$(eagle_get_recent_summaries "$
|
|
382
|
+
recent=$(eagle_get_recent_summaries "$recall_scope" "$_summary_limit")
|
|
185
383
|
|
|
186
384
|
if [ -n "$recent" ]; then
|
|
187
385
|
context+="
|
|
@@ -230,13 +428,22 @@ fi
|
|
|
230
428
|
|
|
231
429
|
# ─── Memories (skip if none) ─────────────────────────────
|
|
232
430
|
|
|
233
|
-
memory_limit=
|
|
234
|
-
[ "$codex_compact" -eq 1 ] && memory_limit=
|
|
431
|
+
memory_limit=5
|
|
432
|
+
[ "$codex_compact" -eq 1 ] && memory_limit=3
|
|
235
433
|
memories=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at, origin_agent,
|
|
236
434
|
CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
|
|
237
435
|
FROM agent_memories
|
|
238
|
-
WHERE
|
|
239
|
-
|
|
436
|
+
WHERE $recall_project_filter
|
|
437
|
+
AND memory_name NOT IN ('Codex Memory Registry', 'Codex Memory Summary')
|
|
438
|
+
ORDER BY
|
|
439
|
+
CASE
|
|
440
|
+
WHEN lower(memory_name) LIKE 'current status%' THEN 4
|
|
441
|
+
WHEN memory_type = 'project' THEN 0
|
|
442
|
+
WHEN memory_type = 'feedback' THEN 1
|
|
443
|
+
WHEN memory_type IN ('user', 'reference') THEN 2
|
|
444
|
+
ELSE 3
|
|
445
|
+
END,
|
|
446
|
+
updated_at DESC
|
|
240
447
|
LIMIT $memory_limit;")
|
|
241
448
|
if [ -n "$memories" ]; then
|
|
242
449
|
context+="
|
|
@@ -263,7 +470,7 @@ fi
|
|
|
263
470
|
|
|
264
471
|
# ─── Plans (skip if none) ────────────────────────────────
|
|
265
472
|
|
|
266
|
-
plans=$(eagle_list_agent_plans "$
|
|
473
|
+
plans=$(eagle_list_agent_plans "$recall_scope" 3)
|
|
267
474
|
if [ -n "$plans" ]; then
|
|
268
475
|
context+="
|
|
269
476
|
=== Eagle Mem: Plans ===
|
|
@@ -281,7 +488,7 @@ fi
|
|
|
281
488
|
task_limit=5
|
|
282
489
|
[ "$codex_compact" -eq 1 ] && task_limit=3
|
|
283
490
|
synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
|
|
284
|
-
WHERE
|
|
491
|
+
WHERE $recall_project_filter
|
|
285
492
|
AND status IN ('in_progress', 'pending')
|
|
286
493
|
AND source_session_id != 'orchestration'
|
|
287
494
|
AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
|
|
@@ -314,7 +521,7 @@ orchestration_lanes=$(eagle_db "SELECT o.name, o.goal, l.lane_key, l.title,
|
|
|
314
521
|
l.agent, l.status, l.validation, l.worktree_path, l.notes
|
|
315
522
|
FROM orchestration_lanes l
|
|
316
523
|
JOIN orchestrations o ON o.id = l.orchestration_id
|
|
317
|
-
WHERE
|
|
524
|
+
WHERE $recall_lane_filter
|
|
318
525
|
AND o.status = 'active'
|
|
319
526
|
AND l.status IN ('in_progress', 'pending', 'blocked')
|
|
320
527
|
ORDER BY
|
|
@@ -26,6 +26,8 @@ agent=$(eagle_agent_source_from_json "$input")
|
|
|
26
26
|
[ -z "$user_prompt" ] && exit 0
|
|
27
27
|
|
|
28
28
|
project=$(eagle_project_from_hook_input "$input")
|
|
29
|
+
recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
|
|
30
|
+
[ -z "$recall_scope" ] && recall_scope="$project"
|
|
29
31
|
codex_compact=0
|
|
30
32
|
[ "$agent" = "codex" ] && codex_compact=1
|
|
31
33
|
|
|
@@ -46,8 +48,10 @@ if [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
|
|
|
46
48
|
if [ "$turn_count" -ge 30 ]; then
|
|
47
49
|
if [ "$codex_compact" -eq 1 ]; then
|
|
48
50
|
context+="
|
|
49
|
-
|
|
50
|
-
Keep the next Codex reply user-clean.
|
|
51
|
+
Eagle Mem context pressure: critical ($turn_count turns since compact)
|
|
52
|
+
- Keep the next Codex reply user-clean.
|
|
53
|
+
- Do not print Eagle Mem summary blocks or internals.
|
|
54
|
+
- Add a short normal handoff note if useful, then ask the user to run /compact.
|
|
51
55
|
"
|
|
52
56
|
else
|
|
53
57
|
context+="
|
|
@@ -60,8 +64,10 @@ Tell the user to run /compact NOW to avoid losing context.
|
|
|
60
64
|
elif [ "$turn_count" -ge 20 ]; then
|
|
61
65
|
if [ "$codex_compact" -eq 1 ]; then
|
|
62
66
|
context+="
|
|
63
|
-
|
|
64
|
-
Keep the next Codex reply clean.
|
|
67
|
+
Eagle Mem context pressure: high ($turn_count turns since compact)
|
|
68
|
+
- Keep the next Codex reply clean.
|
|
69
|
+
- Do not print Eagle Mem summary blocks or internals.
|
|
70
|
+
- Summarize durable decisions in normal prose only.
|
|
65
71
|
"
|
|
66
72
|
else
|
|
67
73
|
context+="
|
|
@@ -89,8 +95,10 @@ fts_query=$(echo "$user_prompt" | tr -cs '[:alnum:]' ' ' | tr '[:upper:]' '[:low
|
|
|
89
95
|
split("the a an is are was were be been being have has had do does did will would shall should may might can could of in to for on with at by from", sw, " ")
|
|
90
96
|
for (i in sw) stop[sw[i]]=1
|
|
91
97
|
n=0
|
|
98
|
+
split("ad ai ui ux db", keep, " ")
|
|
99
|
+
for (i in keep) short_keep[keep[i]]=1
|
|
92
100
|
for (i=1; i<=NF && n<6; i++) {
|
|
93
|
-
if (length($i) > 2 && !($i in stop)) {
|
|
101
|
+
if ((length($i) > 2 || ($i in short_keep)) && !($i in stop)) {
|
|
94
102
|
printf "%s%s", (n>0?" OR ":""), $i; n++
|
|
95
103
|
}
|
|
96
104
|
}
|
|
@@ -106,8 +114,10 @@ fi
|
|
|
106
114
|
lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
|
|
107
115
|
if printf '%s\n' "$lower_prompt" | grep -Eq '(orchestrat|worker|parallel|multi-agent|multi agent|split|lane|scope out|plan and get started|broad|full codebase|release|publish|ship)'; then
|
|
108
116
|
if [ "$codex_compact" -eq 1 ]; then
|
|
109
|
-
context+="
|
|
110
|
-
|
|
117
|
+
context+="
|
|
118
|
+
Eagle Mem orchestration:
|
|
119
|
+
- For broad work, you run eagle-mem orchestrate yourself.
|
|
120
|
+
- Use durable lanes, opposite-agent workers, and concise user-visible status.
|
|
111
121
|
"
|
|
112
122
|
else
|
|
113
123
|
context+="=== Eagle Mem: Orchestration Protocol ===
|
|
@@ -131,11 +141,23 @@ if [ "$codex_compact" -eq 1 ]; then
|
|
|
131
141
|
code_limit=2
|
|
132
142
|
fi
|
|
133
143
|
|
|
134
|
-
|
|
144
|
+
memory_limit=3
|
|
145
|
+
[ "$codex_compact" -eq 1 ] && memory_limit=2
|
|
146
|
+
|
|
147
|
+
results=$(eagle_search_summaries "$fts_query" "$recall_scope" "$summary_limit")
|
|
148
|
+
memory_results=$(eagle_search_agent_memories "$fts_query" "$recall_scope" "$memory_limit" 2>/dev/null || true)
|
|
149
|
+
|
|
150
|
+
if [ -n "$results" ] || [ -n "$memory_results" ]; then
|
|
151
|
+
if [ "$codex_compact" -eq 1 ]; then
|
|
152
|
+
context+="
|
|
153
|
+
Eagle Mem recalls:
|
|
154
|
+
"
|
|
155
|
+
else
|
|
156
|
+
context+="Eagle Mem recalls: apply these retrieved project facts before answering. If they are relevant to the user's prompt, start with one short \"Eagle Mem recalls:\" attribution line.
|
|
135
157
|
|
|
136
|
-
|
|
137
|
-
context+="=== Eagle Mem: Relevant Recall ===
|
|
158
|
+
=== Eagle Mem: Relevant Recall ===
|
|
138
159
|
"
|
|
160
|
+
fi
|
|
139
161
|
while IFS='|' read -r req completed learned _next_steps created_at _proj decisions gotchas key_files summary_agent; do
|
|
140
162
|
[ -z "$req" ] && [ -z "$completed" ] && continue
|
|
141
163
|
origin_label=$(eagle_agent_label "$summary_agent")
|
|
@@ -143,13 +165,14 @@ if [ -n "$results" ]; then
|
|
|
143
165
|
req=$(eagle_trim_text "$req" 90)
|
|
144
166
|
completed=$(eagle_trim_text "$completed" 150)
|
|
145
167
|
learned=$(eagle_trim_text "$learned" 110)
|
|
146
|
-
context+="- [$origin_label] "
|
|
168
|
+
context+="- Recent [$origin_label]: "
|
|
147
169
|
if [ -n "$completed" ]; then
|
|
148
170
|
context+="$completed"
|
|
149
171
|
else
|
|
150
172
|
context+="$req"
|
|
151
173
|
fi
|
|
152
|
-
[ -n "$learned" ] && context+="
|
|
174
|
+
[ -n "$learned" ] && context+="
|
|
175
|
+
Learned: $learned"
|
|
153
176
|
context+="
|
|
154
177
|
"
|
|
155
178
|
else
|
|
@@ -173,6 +196,30 @@ if [ -n "$results" ]; then
|
|
|
173
196
|
"
|
|
174
197
|
fi
|
|
175
198
|
done <<< "$results"
|
|
199
|
+
|
|
200
|
+
while IFS='|' read -r mname mtype mdesc msnippet _mfile _mupdated morigin; do
|
|
201
|
+
[ -z "$mname" ] && continue
|
|
202
|
+
case "$mname" in
|
|
203
|
+
"Codex Memory Registry"|"Codex Memory Summary") continue ;;
|
|
204
|
+
esac
|
|
205
|
+
origin_label=$(eagle_agent_label "$morigin")
|
|
206
|
+
if [ "$codex_compact" -eq 1 ]; then
|
|
207
|
+
mdesc=$(eagle_trim_text "$mdesc" 120)
|
|
208
|
+
context+="- Memory [$mtype][$origin_label]: $mname"
|
|
209
|
+
[ -n "$mdesc" ] && context+=" — $mdesc"
|
|
210
|
+
context+="
|
|
211
|
+
"
|
|
212
|
+
else
|
|
213
|
+
mdesc=$(eagle_trim_text "$mdesc" 180)
|
|
214
|
+
msnippet=$(eagle_trim_text "$msnippet" 220)
|
|
215
|
+
context+="[Memory][$origin_label][$mtype] $mname"
|
|
216
|
+
[ -n "$mdesc" ] && context+=" — $mdesc"
|
|
217
|
+
[ -n "$msnippet" ] && context+="
|
|
218
|
+
Snippet: $msnippet"
|
|
219
|
+
context+="
|
|
220
|
+
"
|
|
221
|
+
fi
|
|
222
|
+
done <<< "$memory_results"
|
|
176
223
|
fi
|
|
177
224
|
|
|
178
225
|
# Search indexed code chunks (if any exist for this project)
|
|
@@ -181,11 +228,21 @@ if [ "${has_chunks:-0}" -gt 0 ]; then
|
|
|
181
228
|
code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
|
|
182
229
|
|
|
183
230
|
if [ -n "$code_results" ]; then
|
|
184
|
-
|
|
231
|
+
if [ "$codex_compact" -eq 1 ]; then
|
|
232
|
+
context+="
|
|
233
|
+
Relevant code:
|
|
234
|
+
"
|
|
235
|
+
else
|
|
236
|
+
context+="=== Eagle Mem: Relevant Code ===
|
|
185
237
|
"
|
|
238
|
+
fi
|
|
186
239
|
while IFS='|' read -r fpath sline eline lang; do
|
|
187
240
|
[ -z "$fpath" ] && continue
|
|
188
|
-
|
|
241
|
+
if [ "$codex_compact" -eq 1 ]; then
|
|
242
|
+
context+="- $fpath:${sline}-${eline}"
|
|
243
|
+
else
|
|
244
|
+
context+="$fpath:${sline}-${eline}"
|
|
245
|
+
fi
|
|
189
246
|
[ -n "$lang" ] && context+=" ($lang)"
|
|
190
247
|
context+="
|
|
191
248
|
"
|
|
@@ -197,7 +254,7 @@ fi
|
|
|
197
254
|
|
|
198
255
|
if [ "$codex_compact" -eq 1 ]; then
|
|
199
256
|
context+="
|
|
200
|
-
|
|
257
|
+
Note: use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
|
|
201
258
|
"
|
|
202
259
|
else
|
|
203
260
|
context+="
|