eagle-mem 4.10.13 → 4.12.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/CHANGELOG.md +25 -0
- package/README.md +22 -22
- package/architecture.html +26 -14
- package/bin/eagle-mem +4 -0
- package/db/039_recall_events.sql +27 -0
- package/db/040_graph_decision_nodes.sql +21 -0
- package/db/041_graph_semantic_edge_types.sql +21 -0
- package/db/042_orchestration_auto_events.sql +23 -0
- package/db/043_eagle_events.sql +22 -0
- package/db/044_summary_capture_source.sql +12 -0
- package/docs/agent-compatibility/README.md +38 -0
- package/docs/agent-compatibility/claude-code.md +58 -0
- package/docs/agent-compatibility/codex.md +57 -0
- package/docs/agent-compatibility/opencode.md +72 -0
- package/hooks/post-tool-use.sh +8 -0
- package/hooks/pre-tool-use.sh +10 -1
- package/hooks/session-end.sh +3 -0
- package/hooks/session-start.sh +15 -17
- package/hooks/stop.sh +34 -5
- package/hooks/user-prompt-submit.sh +85 -10
- package/integrations/opencode_eagle_mem_plugin.js +387 -0
- package/lib/codex-hooks.sh +13 -6
- package/lib/common.sh +77 -7
- package/lib/db-events.sh +89 -0
- package/lib/db-graph.sh +154 -0
- package/lib/db-observations.sh +34 -0
- package/lib/db-orchestration.sh +149 -0
- package/lib/db-summaries.sh +70 -3
- package/lib/db.sh +2 -0
- package/lib/hooks.sh +41 -7
- package/lib/opencode-hooks.sh +105 -0
- package/lib/provider.sh +2 -2
- package/package.json +5 -2
- package/scripts/compaction.sh +109 -9
- package/scripts/dashboard.sh +372 -0
- package/scripts/doctor.sh +30 -3
- package/scripts/enrich-summary.sh +8 -2
- package/scripts/health.sh +40 -2
- package/scripts/help.sh +10 -2
- package/scripts/inspect.sh +285 -0
- package/scripts/install.sh +36 -7
- package/scripts/memories.sh +13 -0
- package/scripts/repair.sh +187 -0
- package/scripts/replay.sh +248 -0
- package/scripts/search.sh +44 -3
- package/scripts/session.sh +155 -18
- package/scripts/statusline-em.sh +34 -7
- package/scripts/tasks.sh +34 -0
- package/scripts/test.sh +13 -0
- package/scripts/uninstall.sh +9 -0
- package/scripts/update.sh +21 -2
- package/tests/fixtures/agent-hooks/claude-statusline.json +32 -0
- package/tests/fixtures/agent-hooks/claude-user-prompt-submit.json +9 -0
- package/tests/fixtures/agent-hooks/codex-pre-tool-use.json +10 -0
- package/tests/fixtures/agent-hooks/codex-user-prompt-submit.json +7 -0
- package/tests/fixtures/agent-hooks/opencode-chat-message.json +36 -0
- package/tests/fixtures/agent-hooks/opencode-session-compacting.json +9 -0
- package/tests/fixtures/agent-hooks/opencode-todo-updated.json +13 -0
- package/tests/fixtures/agent-hooks/opencode-tool-execute-after.json +15 -0
- package/tests/fixtures/agent-hooks/opencode-tool-execute-before.json +12 -0
- package/tests/test_agent_compatibility_docs_gate.sh +123 -0
- package/tests/test_auto_orchestration_detection.sh +109 -0
- package/tests/test_claude_stop_hook_registration.sh +56 -0
- package/tests/test_clean_session_capture.sh +105 -0
- package/tests/test_codex_hooks_config.sh +73 -0
- package/tests/test_compaction_survival_matrix.sh +237 -0
- package/tests/test_dashboard.sh +96 -0
- package/tests/test_eagle_events.sh +96 -0
- package/tests/test_opencode_hooks_config.sh +56 -0
- package/tests/test_opencode_plugin_adapter.sh +202 -0
- package/tests/test_recall_observability.sh +144 -0
- package/tests/test_repair.sh +63 -0
- package/tests/test_rust_migration_plan.sh +75 -0
- package/tests/test_trust_surfaces.sh +123 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Codex Compatibility
|
|
2
|
+
|
|
3
|
+
Last verified: 2026-06-10
|
|
4
|
+
|
|
5
|
+
## Official Sources
|
|
6
|
+
|
|
7
|
+
- Codex manual: https://developers.openai.com/codex/codex-manual.md
|
|
8
|
+
- Hooks reference: https://developers.openai.com/codex/hooks.md
|
|
9
|
+
- AGENTS.md reference: https://developers.openai.com/codex/guides/agents-md.md
|
|
10
|
+
- Advanced config reference: https://developers.openai.com/codex/config-advanced.md
|
|
11
|
+
- Memories reference: https://developers.openai.com/codex/memories.md
|
|
12
|
+
|
|
13
|
+
## Behavior Relied On
|
|
14
|
+
|
|
15
|
+
- `AGENTS.md` is the durable repo-instruction surface for Codex. Closer nested files override earlier guidance because Codex concatenates instruction files from the project root down to the current working directory.
|
|
16
|
+
- Codex hooks are discovered from active config layers through `hooks.json` or inline `[hooks]` tables in `config.toml`.
|
|
17
|
+
- `features.hooks` is the canonical feature key. `features.codex_hooks` is a deprecated alias and should not be the primary setting.
|
|
18
|
+
- `SessionStart`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `UserPromptSubmit`, `SubagentStop`, and `Stop` run at the documented lifecycle scopes.
|
|
19
|
+
- `SessionStart` matchers use `startup`, `resume`, `clear`, and `compact`.
|
|
20
|
+
- `PreToolUse` and `PostToolUse` match tool names, including `Bash`, `apply_patch`, MCP tool names, and aliases such as `Edit` and `Write` for `apply_patch`.
|
|
21
|
+
- `UserPromptSubmit` and `Stop` do not support matchers; configured matchers are ignored for those events.
|
|
22
|
+
- Hook `timeout` is measured in seconds; `statusMessage` is optional.
|
|
23
|
+
- Codex memory files are generated state. Required team guidance belongs in `AGENTS.md` or checked-in documentation, not only in local memories.
|
|
24
|
+
|
|
25
|
+
## Session Capture Behavior
|
|
26
|
+
|
|
27
|
+
- Codex replies stay prose-only; Eagle Mem never asks Codex to print summary blocks, XML, or hook payloads. The `Stop` hook captures a summary from the Codex rollout transcript automatically.
|
|
28
|
+
- For a richer structured capture, Codex may run `eagle-mem session save --session-id <session_id> --agent codex ...` once at wrap-up (injected by `SessionStart` and the `AGENTS.md` section). This sets `capture_source = agent`, which is authoritative: later Stop-hook heuristics only fill empty fields and background enrichment is skipped, so the capture is never clobbered.
|
|
29
|
+
- Modified-file lists are most reliable when Codex passes `--files-modified` explicitly; the transcript heuristic is Claude-shaped and may not populate file lists from Codex rollout tool calls.
|
|
30
|
+
|
|
31
|
+
## Eagle Mem Files Depending On This
|
|
32
|
+
|
|
33
|
+
- `lib/codex-hooks.sh`
|
|
34
|
+
- `lib/provider.sh`
|
|
35
|
+
- `scripts/install.sh`
|
|
36
|
+
- `scripts/update.sh`
|
|
37
|
+
- `scripts/uninstall.sh`
|
|
38
|
+
- `hooks/session-start.sh`
|
|
39
|
+
- `hooks/user-prompt-submit.sh`
|
|
40
|
+
- `hooks/pre-tool-use.sh`
|
|
41
|
+
- `hooks/post-tool-use.sh`
|
|
42
|
+
- `hooks/stop.sh`
|
|
43
|
+
- `AGENTS.md`
|
|
44
|
+
|
|
45
|
+
## Fixtures And Tests
|
|
46
|
+
|
|
47
|
+
- `tests/fixtures/agent-hooks/codex-user-prompt-submit.json`
|
|
48
|
+
- `tests/fixtures/agent-hooks/codex-pre-tool-use.json`
|
|
49
|
+
- `tests/test_agent_compatibility_docs_gate.sh`
|
|
50
|
+
- `tests/test_codex_hooks_config.sh`
|
|
51
|
+
- `tests/test_auto_orchestration_detection.sh`
|
|
52
|
+
- `tests/test_recall_observability.sh`
|
|
53
|
+
- `tests/test_trust_surfaces.sh`
|
|
54
|
+
|
|
55
|
+
## Reverification Notes
|
|
56
|
+
|
|
57
|
+
When editing Codex hooks or install/update behavior, update this file with the new verification date and source URLs. If a future Codex version changes hook feature flags, matcher support, trust review, event names, or input/output schema, update fixtures first and then implementation.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# OpenCode Compatibility
|
|
2
|
+
|
|
3
|
+
Last verified: 2026-06-10
|
|
4
|
+
|
|
5
|
+
## Official Sources
|
|
6
|
+
|
|
7
|
+
- Plugins reference: https://opencode.ai/docs/plugins/
|
|
8
|
+
- Config reference: https://opencode.ai/docs/config/
|
|
9
|
+
- Config schema: https://opencode.ai/config.json
|
|
10
|
+
|
|
11
|
+
## Installed Surface Verified Locally
|
|
12
|
+
|
|
13
|
+
- OpenCode CLI: `opencode --version` reported `1.14.24`.
|
|
14
|
+
- OpenCode plugin package: `@opencode-ai/plugin@1.14.24`.
|
|
15
|
+
- Resolved config path: `~/.config/opencode/opencode.json`.
|
|
16
|
+
- Global plugin directory: `~/.config/opencode/plugins/`.
|
|
17
|
+
|
|
18
|
+
## Behavior Relied On
|
|
19
|
+
|
|
20
|
+
- OpenCode local plugins are JavaScript or TypeScript modules placed in `.opencode/plugins/` for project scope or `~/.config/opencode/plugins/` for global scope.
|
|
21
|
+
- Files in those plugin directories are loaded automatically at startup.
|
|
22
|
+
- NPM plugins are declared with the top-level `plugin` array in `opencode.json`, but Eagle Mem uses the global local-plugin directory so it does not need to mutate the user plugin array.
|
|
23
|
+
- Plugin functions receive a context object with `project`, `directory`, `worktree`, `client`, and `$`, then return a hooks object.
|
|
24
|
+
- The plugin event bus includes `session.created`, `session.updated`, `session.idle`, `session.compacted`, `session.deleted`, `message.updated`, `message.part.updated`, and `todo.updated`.
|
|
25
|
+
- Direct hook keys include `chat.message`, `tool.execute.before`, `tool.execute.after`, `shell.env`, and `experimental.session.compacting`.
|
|
26
|
+
- `tool.execute.before` can deny a tool call by throwing an error and can mutate `output.args` before execution.
|
|
27
|
+
- `tool.execute.after` receives tool output fields that can be annotated for the model.
|
|
28
|
+
- `experimental.session.compacting` fires before compaction and can push additional strings into `output.context`.
|
|
29
|
+
- `opencode --pure` runs without external plugins; doctor checks should report that Eagle Mem OpenCode support depends on non-pure OpenCode sessions.
|
|
30
|
+
|
|
31
|
+
## Eagle Mem Mapping
|
|
32
|
+
|
|
33
|
+
- `chat.message` maps to Eagle Mem `SessionStart` once per session and `UserPromptSubmit` on each user message.
|
|
34
|
+
- `tool.execute.before` maps to Eagle Mem `PreToolUse`; denial becomes a thrown OpenCode plugin error and `updatedInput` mutates `output.args`.
|
|
35
|
+
- `tool.execute.after` maps to Eagle Mem `PostToolUse`; additional context is appended to the tool output so the agent can see guardrail or stale-memory hints.
|
|
36
|
+
- `todo.updated` maps OpenCode todos into Eagle Mem task records through synthetic `TaskCreated` and `TaskUpdate` hook payloads.
|
|
37
|
+
- `session.idle` maps to Eagle Mem `Stop` using the latest assistant text accumulated from message events.
|
|
38
|
+
- `session.deleted` maps to Eagle Mem `SessionEnd`.
|
|
39
|
+
- `experimental.session.compacting` maps to Eagle Mem compact recall by running `SessionStart` with `source=compact` and appending the returned context.
|
|
40
|
+
- Session capture follows the shared clean-capture flow: the agent may run `eagle-mem session save --session-id <id> ...` at wrap-up (sets `capture_source = agent`, authoritative) and keep replies prose-only. The `session.idle` → `Stop` path then only fills gaps and never clobbers an agent-authored row.
|
|
41
|
+
|
|
42
|
+
## Eagle Mem Files Depending On This
|
|
43
|
+
|
|
44
|
+
- `integrations/opencode_eagle_mem_plugin.js`
|
|
45
|
+
- `lib/opencode-hooks.sh`
|
|
46
|
+
- `lib/common.sh`
|
|
47
|
+
- `scripts/install.sh`
|
|
48
|
+
- `scripts/update.sh`
|
|
49
|
+
- `scripts/uninstall.sh`
|
|
50
|
+
- `scripts/doctor.sh`
|
|
51
|
+
- `scripts/test.sh`
|
|
52
|
+
- `hooks/session-start.sh`
|
|
53
|
+
- `hooks/user-prompt-submit.sh`
|
|
54
|
+
- `hooks/pre-tool-use.sh`
|
|
55
|
+
- `hooks/post-tool-use.sh`
|
|
56
|
+
- `hooks/stop.sh`
|
|
57
|
+
- `hooks/session-end.sh`
|
|
58
|
+
|
|
59
|
+
## Fixtures And Tests
|
|
60
|
+
|
|
61
|
+
- `tests/fixtures/agent-hooks/opencode-chat-message.json`
|
|
62
|
+
- `tests/fixtures/agent-hooks/opencode-tool-execute-before.json`
|
|
63
|
+
- `tests/fixtures/agent-hooks/opencode-tool-execute-after.json`
|
|
64
|
+
- `tests/fixtures/agent-hooks/opencode-todo-updated.json`
|
|
65
|
+
- `tests/fixtures/agent-hooks/opencode-session-compacting.json`
|
|
66
|
+
- `tests/test_agent_compatibility_docs_gate.sh`
|
|
67
|
+
- `tests/test_opencode_hooks_config.sh`
|
|
68
|
+
- `tests/test_opencode_plugin_adapter.sh`
|
|
69
|
+
|
|
70
|
+
## Reverification Notes
|
|
71
|
+
|
|
72
|
+
When editing OpenCode support, re-read the plugins and config docs first. If OpenCode changes plugin load order, local plugin directories, hook names, `tool.execute.*` mutation semantics, `chat.message` payloads, or compaction hooks, update these fixtures before implementation.
|
package/hooks/post-tool-use.sh
CHANGED
|
@@ -122,6 +122,7 @@ esac
|
|
|
122
122
|
|
|
123
123
|
project=$(eagle_project_from_hook_input "$input")
|
|
124
124
|
[ -z "$project" ] && exit 0
|
|
125
|
+
eagle_hook_observability_begin "$input" "PostToolUse"
|
|
125
126
|
|
|
126
127
|
# Ensure session row exists before inserting observations (FK constraint).
|
|
127
128
|
# PostToolUse can race SessionStart — the session row might not exist yet.
|
|
@@ -249,5 +250,12 @@ eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
|
|
|
249
250
|
if ! eagle_insert_observation "$session_id" "$project" "$tool_name" "$tool_summary" "$files_read" "$files_modified" "$output_bytes" "$output_lines" "$command_category" "$agent"; then
|
|
250
251
|
eagle_log "ERROR" "PostToolUse: observation insert failed for session=$session_id tool=$tool_name"
|
|
251
252
|
fi
|
|
253
|
+
eagle_hook_observability_set_detail "$(jq -nc \
|
|
254
|
+
--arg tool "$tool_name" \
|
|
255
|
+
--arg summary "$tool_summary" \
|
|
256
|
+
--arg files_read "$files_read" \
|
|
257
|
+
--arg files_modified "$files_modified" \
|
|
258
|
+
'{tool_name:$tool, summary:$summary, files_read:($files_read | fromjson? // []), files_modified:($files_modified | fromjson? // [])}')"
|
|
259
|
+
eagle_hook_observability_complete 0
|
|
252
260
|
|
|
253
261
|
exit 0
|
package/hooks/pre-tool-use.sh
CHANGED
|
@@ -33,6 +33,7 @@ esac
|
|
|
33
33
|
[ ! -f "$EAGLE_MEM_DB" ] && exit 0
|
|
34
34
|
project=$(eagle_project_from_hook_input "$input")
|
|
35
35
|
[ -z "$project" ] && exit 0
|
|
36
|
+
eagle_hook_observability_begin "$input" "PreToolUse"
|
|
36
37
|
|
|
37
38
|
context=""
|
|
38
39
|
updated_input=""
|
|
@@ -382,15 +383,23 @@ Use the existing context, run a narrower search, or bypass once with:
|
|
|
382
383
|
;;
|
|
383
384
|
esac
|
|
384
385
|
|
|
385
|
-
[ -z "$context" ] && [ -z "$updated_input" ]
|
|
386
|
+
if [ -z "$context" ] && [ -z "$updated_input" ]; then
|
|
387
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "no_action" '{tool_name:$tool, action:$action}')"
|
|
388
|
+
eagle_hook_observability_complete 0
|
|
389
|
+
exit 0
|
|
390
|
+
fi
|
|
386
391
|
|
|
387
392
|
# Codex PreToolUse now natively receives both blocking decisions and advisory context.
|
|
388
393
|
# Removing the old early-exit to align Codex's pre-tool capabilities with Claude and Antigravity.
|
|
389
394
|
|
|
390
395
|
if [ -n "$updated_input" ]; then
|
|
396
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "updated_input" '{tool_name:$tool, action:$action}')"
|
|
397
|
+
eagle_hook_observability_complete 0
|
|
391
398
|
jq -nc --arg ctx "$context" --argjson ui "$updated_input" \
|
|
392
399
|
'{"hookSpecificOutput":{"hookEventName":"PreToolUse","updatedInput":$ui,"additionalContext":$ctx}}'
|
|
393
400
|
else
|
|
401
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg tool "$tool_name" --arg action "additional_context" '{tool_name:$tool, action:$action}')"
|
|
402
|
+
eagle_hook_observability_complete 0
|
|
394
403
|
jq -nc --arg ctx "$context" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":$ctx}}'
|
|
395
404
|
fi
|
|
396
405
|
|
package/hooks/session-end.sh
CHANGED
|
@@ -24,6 +24,7 @@ agent=$(eagle_agent_source_from_json "$input")
|
|
|
24
24
|
cwd=$(echo "$input" | jq -r '.cwd // empty')
|
|
25
25
|
project=$(eagle_project_from_hook_input "$input")
|
|
26
26
|
[ -z "$project" ] && exit 0
|
|
27
|
+
eagle_hook_observability_begin "$input" "SessionEnd"
|
|
27
28
|
|
|
28
29
|
# Final sweep: re-capture all task files to catch status changes
|
|
29
30
|
# Claude Code may update task status without triggering PostToolUse
|
|
@@ -40,6 +41,8 @@ fi
|
|
|
40
41
|
|
|
41
42
|
eagle_end_session "$session_id"
|
|
42
43
|
eagle_log "INFO" "SessionEnd: session=$session_id marked completed"
|
|
44
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg action "session_completed" '{action:$action}')"
|
|
45
|
+
eagle_hook_observability_complete 0
|
|
43
46
|
|
|
44
47
|
# Prune observations older than 90 days (keeps DB size bounded)
|
|
45
48
|
eagle_prune_observations 90 "$project"
|
package/hooks/session-start.sh
CHANGED
|
@@ -35,6 +35,7 @@ codex_compact=0
|
|
|
35
35
|
|
|
36
36
|
project=$(eagle_project_from_hook_input "$input")
|
|
37
37
|
[ -z "$project" ] && exit 0
|
|
38
|
+
eagle_hook_observability_begin "$input" "SessionStart"
|
|
38
39
|
|
|
39
40
|
p_esc=$(eagle_sql_escape "$project")
|
|
40
41
|
recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
|
|
@@ -624,38 +625,35 @@ fi
|
|
|
624
625
|
if [ "$agent" = "codex" ]; then
|
|
625
626
|
context+="
|
|
626
627
|
=== Eagle Mem: Active ===
|
|
627
|
-
Memory active for '$project'. Keep user-facing Codex replies clean: do not print Eagle Mem summary capture blocks, XML, JSON hook payloads, or internal templates unless the user explicitly asks. The Stop hook captures summaries from the transcript automatically.
|
|
628
|
+
Memory active for '$project'. Keep user-facing Codex replies clean: do not print Eagle Mem summary capture blocks, XML, JSON hook payloads, or internal templates unless the user explicitly asks. The Stop hook captures summaries from the transcript automatically. When you wrap up substantive work, you may persist a richer structured capture by running once: eagle-mem session save --session-id $session_id --agent codex --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" --files-modified \"a.ts,b.ts\" (fill what applies). Keep the visible reply prose-only.
|
|
628
629
|
"
|
|
629
630
|
elif [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
|
|
630
631
|
context+="
|
|
631
632
|
=== Eagle Mem: Active ===
|
|
632
|
-
Memory active. Attribute recalled context to Eagle Mem. Do not revert PostToolUse-surfaced decisions without asking.
|
|
633
|
+
Memory active. Attribute recalled context to Eagle Mem. Do not revert PostToolUse-surfaced decisions without asking. Before your final response, capture the session quietly via the Bash tool (pre-approved): eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" (fill what applies, omit the rest). Then give a short human recap — NEVER print <eagle-summary> tags or raw field lists.
|
|
633
634
|
"
|
|
634
635
|
else
|
|
635
636
|
context+="
|
|
636
637
|
=== Eagle Mem: Active ===
|
|
637
638
|
Memory active for '$project'. Scan, index, prune, and self-learning run automatically — never ask the user to run these. Attribute recalled context: \"Eagle Mem recalls:\" Do not revert PostToolUse-surfaced decisions without user request. No raw secrets in summaries. If you contradict a loaded memory, update the memory file.
|
|
638
639
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
request
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
gotchas: [what surprised]
|
|
646
|
-
next_steps: [concrete actions]
|
|
647
|
-
key_files: [path — role]
|
|
648
|
-
files_read: [path, ...]
|
|
649
|
-
files_modified: [path, ...]
|
|
650
|
-
affected_features: [feature, ...]
|
|
651
|
-
verified_features: [feature, ...]
|
|
652
|
-
regression_risks: [risk, ...]
|
|
653
|
-
</eagle-summary>
|
|
640
|
+
Session capture is clean: NEVER print <eagle-summary> tags, XML, or raw field lists (request:/completed:/...) in your visible reply. When you wrap up substantive work (shipped a change, made decisions worth remembering, the user signals done, or Eagle Mem warns of context pressure), capture it by running this ONCE via the Bash tool — it is pre-approved and prints only a short confirmation. Fill the flags you have; omit the rest:
|
|
641
|
+
|
|
642
|
+
eagle-mem session save --session-id $session_id --request \"...\" --completed \"...\" --learned \"...\" --decisions \"choice — why; choice — why\" --gotchas \"...\" --next-steps \"...\" --key-files \"path — role\" --files-modified \"a.ts,b.ts\" --affected-features \"...\" --verified-features \"...\" --regression-risks \"...\"
|
|
643
|
+
|
|
644
|
+
Then end with a brief, human recap of the session in prose, followed by one line:
|
|
645
|
+
**Eagle Mem** | Session captured — N decisions, M gotchas
|
|
654
646
|
"
|
|
655
647
|
fi
|
|
656
648
|
|
|
657
649
|
if [ -n "$context" ]; then
|
|
650
|
+
eagle_hook_observability_set_detail "$(jq -nc \
|
|
651
|
+
--arg source_type "$source_type" \
|
|
652
|
+
--arg recall_scope "$recall_scope" \
|
|
653
|
+
--argjson injected_chars "${#context}" \
|
|
654
|
+
'{source_type:$source_type, recall_scope:$recall_scope, injected_chars:$injected_chars}')"
|
|
658
655
|
eagle_emit_context_for_agent "$agent" "SessionStart" "$context"
|
|
659
656
|
fi
|
|
657
|
+
eagle_hook_observability_complete 0
|
|
660
658
|
|
|
661
659
|
exit 0
|
package/hooks/stop.sh
CHANGED
|
@@ -31,6 +31,7 @@ agent=$(eagle_agent_source_from_json "$input")
|
|
|
31
31
|
|
|
32
32
|
project=$(eagle_project_from_hook_input "$input")
|
|
33
33
|
[ -z "$project" ] && exit 0
|
|
34
|
+
eagle_hook_observability_begin "$input" "Stop"
|
|
34
35
|
|
|
35
36
|
eagle_log "INFO" "Stop: session=$session_id project=$project transcript=$transcript_path agent=$agent"
|
|
36
37
|
|
|
@@ -237,7 +238,7 @@ if [ "$needs_enrichment" -eq 1 ]; then
|
|
|
237
238
|
# lifecycle timeouts and make the hook look broken to users.
|
|
238
239
|
if [ "${EAGLE_MEM_STOP_ENRICH:-0}" != "1" ]; then
|
|
239
240
|
defer_enrichment=1
|
|
240
|
-
eagle_log "INFO" "Stop: LLM enrichment skipped
|
|
241
|
+
eagle_log "INFO" "Stop: LLM enrichment skipped on fast hook path; provider=$provider"
|
|
241
242
|
elif [ "$provider" != "none" ] && [ -n "$text_content" ]; then
|
|
242
243
|
excerpt=$(echo "$text_content" | tail -c 3000)
|
|
243
244
|
|
|
@@ -395,16 +396,44 @@ if [ -n "$regression_notes" ]; then
|
|
|
395
396
|
fi
|
|
396
397
|
|
|
397
398
|
# ─── Write to database ─────────────────────────────────────
|
|
399
|
+
#
|
|
400
|
+
# Capture-source precedence:
|
|
401
|
+
# - A parsed <eagle-summary> block this turn is agent-authored → write 'agent'.
|
|
402
|
+
# - An existing 'agent' row (CLI `eagle-mem session save` or an earlier block)
|
|
403
|
+
# is authoritative → fill empty gaps only, never overwrite with heuristics.
|
|
404
|
+
# - Otherwise this is a heuristic capture → normal 'hook' write.
|
|
405
|
+
# agent_authored also gates background enrichment so it can't clobber later.
|
|
406
|
+
|
|
407
|
+
existing_source=$(eagle_summary_capture_source "$session_id" 2>/dev/null || true)
|
|
408
|
+
agent_authored=0
|
|
409
|
+
[ -n "$summary_block" ] && agent_authored=1
|
|
410
|
+
[ "$existing_source" = "agent" ] && agent_authored=1
|
|
398
411
|
|
|
399
412
|
if [ -n "$request" ] || [ -n "$completed" ] || [ -n "$learned" ]; then
|
|
400
|
-
|
|
401
|
-
|
|
413
|
+
write_rc=0
|
|
414
|
+
if [ -n "$summary_block" ]; then
|
|
415
|
+
eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "agent" || write_rc=$?
|
|
416
|
+
elif [ "$existing_source" = "agent" ]; then
|
|
417
|
+
eagle_insert_summary_fill_only "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "hook" || write_rc=$?
|
|
418
|
+
else
|
|
419
|
+
eagle_insert_summary "$session_id" "$project" "$request" "$investigated" "$learned" "$completed" "$next_steps" "$files_read" "$files_modified" "$notes" "$decisions" "$gotchas" "$key_files" "$agent" "hook" || write_rc=$?
|
|
420
|
+
fi
|
|
421
|
+
if [ "$write_rc" -eq 0 ]; then
|
|
422
|
+
eagle_log "INFO" "Stop: summary saved for session=$session_id (prior_source=${existing_source:-none}, block=$([ -n "$summary_block" ] && echo yes || echo no))"
|
|
423
|
+
eagle_insert_event "$project" "$session_id" "$agent" "memory_created" "" "Stop" "ok" "$(jq -nc --arg source "summary" '{source:$source}')" >/dev/null 2>&1 || true
|
|
402
424
|
else
|
|
403
425
|
eagle_log "ERROR" "Stop: summary insert FAILED for session=$session_id — check DB constraints"
|
|
404
426
|
fi
|
|
405
427
|
fi
|
|
406
|
-
|
|
407
|
-
|
|
428
|
+
eagle_hook_observability_set_detail "$(jq -nc \
|
|
429
|
+
--argjson files_read "$files_read" \
|
|
430
|
+
--argjson files_modified "$files_modified" \
|
|
431
|
+
--arg request "$request" \
|
|
432
|
+
--arg completed "$completed" \
|
|
433
|
+
'{request_chars:($request | length), completed_chars:($completed | length), files_read:$files_read, files_modified:$files_modified}')"
|
|
434
|
+
eagle_hook_observability_complete 0
|
|
435
|
+
|
|
436
|
+
if [ "$defer_enrichment" -eq 1 ] && [ "${EAGLE_MEM_STOP_BACKGROUND_ENRICH:-1}" = "1" ] && [ -n "$text_content" ] && [ "$agent_authored" -eq 0 ]; then
|
|
408
437
|
mkdir -p "$EAGLE_MEM_DIR/tmp" 2>/dev/null || true
|
|
409
438
|
enrich_job=$(mktemp "$EAGLE_MEM_DIR/tmp/summary-enrich.XXXXXX.json" 2>/dev/null)
|
|
410
439
|
if [ -n "$enrich_job" ]; then
|
|
@@ -30,11 +30,22 @@ recall_scope=$(eagle_recall_project_scope_from_cwd "$cwd" "$project")
|
|
|
30
30
|
[ -z "$recall_scope" ] && recall_scope="$project"
|
|
31
31
|
codex_compact=0
|
|
32
32
|
[ "$agent" = "codex" ] && codex_compact=1
|
|
33
|
+
eagle_hook_observability_begin "$input" "UserPromptSubmit"
|
|
33
34
|
|
|
34
35
|
# ─── Context pressure detection (turn counter since last compact) ──
|
|
35
36
|
# Must run before any early exits so every prompt is counted
|
|
36
37
|
|
|
37
38
|
context=""
|
|
39
|
+
summary_matches=0
|
|
40
|
+
memory_matches=0
|
|
41
|
+
code_matches=0
|
|
42
|
+
summary_refs="[]"
|
|
43
|
+
memory_refs="[]"
|
|
44
|
+
code_refs="[]"
|
|
45
|
+
|
|
46
|
+
count_pipe_rows() {
|
|
47
|
+
awk -F'|' '($1 != "" || $2 != "") { c++ } END { print c + 0 }'
|
|
48
|
+
}
|
|
38
49
|
|
|
39
50
|
if [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
|
|
40
51
|
counter_file="$EAGLE_MEM_DIR/.turn-counter.${session_id}"
|
|
@@ -56,8 +67,9 @@ Eagle Mem context pressure: critical ($turn_count turns since compact)
|
|
|
56
67
|
else
|
|
57
68
|
context+="
|
|
58
69
|
=== Eagle Mem: Context Pressure Critical ($turn_count turns since compact) ===
|
|
59
|
-
IMMEDIATELY
|
|
60
|
-
|
|
70
|
+
IMMEDIATELY capture ALL work this session by running (pre-approved, quiet):
|
|
71
|
+
eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" --learned \"...\" --next-steps \"...\" --key-files \"path — role\"
|
|
72
|
+
Then tell the user to run /compact NOW. Do NOT print <eagle-summary> tags or raw field lists.
|
|
61
73
|
"
|
|
62
74
|
fi
|
|
63
75
|
echo "$turn_count" > "$EAGLE_MEM_DIR/.context-pressure"
|
|
@@ -72,8 +84,9 @@ Eagle Mem context pressure: high ($turn_count turns since compact)
|
|
|
72
84
|
else
|
|
73
85
|
context+="
|
|
74
86
|
=== Eagle Mem: Context Pressure High ($turn_count turns since compact) ===
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
Capture your work before compaction by running (pre-approved, quiet):
|
|
88
|
+
eagle-mem session save --session-id $session_id --completed \"...\" --decisions \"choice — why\" --gotchas \"...\" --learned \"...\"
|
|
89
|
+
Then suggest the user run /compact. Do NOT print <eagle-summary> tags or raw field lists.
|
|
77
90
|
"
|
|
78
91
|
fi
|
|
79
92
|
echo "$turn_count" > "$EAGLE_MEM_DIR/.context-pressure"
|
|
@@ -85,6 +98,9 @@ fi
|
|
|
85
98
|
# Skip short prompts — not enough signal for meaningful search
|
|
86
99
|
word_count=$(echo "$user_prompt" | wc -w | tr -d ' ')
|
|
87
100
|
if [ "$word_count" -lt 3 ]; then
|
|
101
|
+
eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "" 0 0 0 "${#context}" "skipped_short_prompt" "" >/dev/null 2>&1 || true
|
|
102
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg recall_status "skipped_short_prompt" --argjson injected_chars "${#context}" '{recall_status:$recall_status, injected_chars:$injected_chars}')"
|
|
103
|
+
eagle_hook_observability_complete 0
|
|
88
104
|
eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
|
|
89
105
|
exit 0
|
|
90
106
|
fi
|
|
@@ -105,6 +121,9 @@ fts_query=$(echo "$user_prompt" | tr -cs '[:alnum:]' ' ' | tr '[:upper:]' '[:low
|
|
|
105
121
|
}')
|
|
106
122
|
|
|
107
123
|
if [ -z "$fts_query" ]; then
|
|
124
|
+
eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "" 0 0 0 "${#context}" "skipped_no_query" "" >/dev/null 2>&1 || true
|
|
125
|
+
eagle_hook_observability_set_detail "$(jq -nc --arg recall_status "skipped_no_query" --argjson injected_chars "${#context}" '{recall_status:$recall_status, injected_chars:$injected_chars}')"
|
|
126
|
+
eagle_hook_observability_complete 0
|
|
108
127
|
eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
|
|
109
128
|
exit 0
|
|
110
129
|
fi
|
|
@@ -113,19 +132,27 @@ fi
|
|
|
113
132
|
|
|
114
133
|
lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
|
|
115
134
|
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
|
|
135
|
+
auto_orchestration=$(eagle_auto_orchestrate_from_prompt "$project" "$session_id" "$agent" "$user_prompt" "$cwd" "broad_prompt" 2>/dev/null || true)
|
|
136
|
+
if [ -n "$auto_orchestration" ]; then
|
|
137
|
+
IFS='|' read -r auto_name auto_id auto_lane_count _auto_lanes_json <<< "$auto_orchestration"
|
|
138
|
+
context+="
|
|
139
|
+
Eagle Mem orchestration: detected broad work and created durable orchestration '$auto_name' with $auto_lane_count lanes.
|
|
140
|
+
- Inspect it with: eagle-mem orchestrate --name $auto_name
|
|
141
|
+
- Lanes already exist as durable tasks; update them instead of relying on memory alone.
|
|
142
|
+
"
|
|
143
|
+
fi
|
|
116
144
|
if [ "$codex_compact" -eq 1 ]; then
|
|
117
145
|
context+="
|
|
118
146
|
Eagle Mem orchestration:
|
|
119
|
-
-
|
|
120
|
-
-
|
|
147
|
+
- Continue from the durable lanes Eagle already created.
|
|
148
|
+
- Keep lane/task status current as work progresses.
|
|
121
149
|
"
|
|
122
150
|
else
|
|
123
151
|
context+="=== Eagle Mem: Orchestration Protocol ===
|
|
124
|
-
|
|
152
|
+
Eagle has already detected broad work and registered durable orchestration state.
|
|
125
153
|
|
|
126
154
|
Use:
|
|
127
|
-
eagle-mem orchestrate
|
|
128
|
-
eagle-mem orchestrate lane add <key> --agent codex|claude-code --desc \"<self-contained scope>\" --validate \"<command>\"
|
|
155
|
+
eagle-mem orchestrate --name auto
|
|
129
156
|
eagle-mem orchestrate lane start|block|complete <key>
|
|
130
157
|
|
|
131
158
|
Keep this mostly invisible to the user; surface only concise status or handoff when useful.
|
|
@@ -146,6 +173,8 @@ memory_limit=3
|
|
|
146
173
|
|
|
147
174
|
results=$(eagle_search_summaries "$fts_query" "$recall_scope" "$summary_limit")
|
|
148
175
|
memory_results=$(eagle_search_agent_memories "$fts_query" "$recall_scope" "$memory_limit" 2>/dev/null || true)
|
|
176
|
+
summary_matches=$(printf '%s\n' "$results" | count_pipe_rows)
|
|
177
|
+
memory_matches=$(printf '%s\n' "$memory_results" | count_pipe_rows)
|
|
149
178
|
|
|
150
179
|
if [ -n "$results" ] || [ -n "$memory_results" ]; then
|
|
151
180
|
if [ "$codex_compact" -eq 1 ]; then
|
|
@@ -195,6 +224,13 @@ Eagle Mem recalls:
|
|
|
195
224
|
context+="
|
|
196
225
|
"
|
|
197
226
|
fi
|
|
227
|
+
summary_refs=$(printf '%s' "$summary_refs" | jq -c \
|
|
228
|
+
--arg created_at "$created_at" \
|
|
229
|
+
--arg agent "$summary_agent" \
|
|
230
|
+
--arg request "$req" \
|
|
231
|
+
--arg completed "$completed" \
|
|
232
|
+
--arg learned "$learned" \
|
|
233
|
+
'. + [{created_at:$created_at, agent:$agent, request:$request, completed:$completed, learned:$learned}]' 2>/dev/null || printf '[]')
|
|
198
234
|
done <<< "$results"
|
|
199
235
|
|
|
200
236
|
while IFS='|' read -r mname mtype mdesc msnippet _mfile _mupdated morigin; do
|
|
@@ -219,6 +255,12 @@ Eagle Mem recalls:
|
|
|
219
255
|
context+="
|
|
220
256
|
"
|
|
221
257
|
fi
|
|
258
|
+
memory_refs=$(printf '%s' "$memory_refs" | jq -c \
|
|
259
|
+
--arg name "$mname" \
|
|
260
|
+
--arg type "$mtype" \
|
|
261
|
+
--arg description "$mdesc" \
|
|
262
|
+
--arg agent "$morigin" \
|
|
263
|
+
'. + [{name:$name, type:$type, description:$description, agent:$agent}]' 2>/dev/null || printf '[]')
|
|
222
264
|
done <<< "$memory_results"
|
|
223
265
|
fi
|
|
224
266
|
|
|
@@ -226,6 +268,7 @@ fi
|
|
|
226
268
|
has_chunks=$(eagle_count_code_chunks "$project")
|
|
227
269
|
if [ "${has_chunks:-0}" -gt 0 ]; then
|
|
228
270
|
code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
|
|
271
|
+
code_matches=$(printf '%s\n' "$code_results" | count_pipe_rows)
|
|
229
272
|
|
|
230
273
|
if [ -n "$code_results" ]; then
|
|
231
274
|
if [ "$codex_compact" -eq 1 ]; then
|
|
@@ -246,11 +289,27 @@ Relevant code:
|
|
|
246
289
|
[ -n "$lang" ] && context+=" ($lang)"
|
|
247
290
|
context+="
|
|
248
291
|
"
|
|
292
|
+
code_refs=$(printf '%s' "$code_refs" | jq -c \
|
|
293
|
+
--arg file "$fpath" \
|
|
294
|
+
--arg start_line "$sline" \
|
|
295
|
+
--arg end_line "$eline" \
|
|
296
|
+
--arg language "$lang" \
|
|
297
|
+
'. + [{file:$file, start_line:$start_line, end_line:$end_line, language:$language}]' 2>/dev/null || printf '[]')
|
|
249
298
|
done <<< "$code_results"
|
|
250
299
|
fi
|
|
251
300
|
fi
|
|
252
301
|
|
|
253
|
-
[ -z "$context" ]
|
|
302
|
+
if [ -z "$context" ]; then
|
|
303
|
+
eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "$fts_query" "$summary_matches" "$memory_matches" "$code_matches" 0 "no_context" "" "$summary_refs" "$memory_refs" "$code_refs" >/dev/null 2>&1 || true
|
|
304
|
+
eagle_hook_observability_set_detail "$(jq -nc \
|
|
305
|
+
--arg recall_status "no_context" \
|
|
306
|
+
--argjson summary_matches "${summary_matches:-0}" \
|
|
307
|
+
--argjson memory_matches "${memory_matches:-0}" \
|
|
308
|
+
--argjson code_matches "${code_matches:-0}" \
|
|
309
|
+
'{recall_status:$recall_status, summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:0}')"
|
|
310
|
+
eagle_hook_observability_complete 0
|
|
311
|
+
exit 0
|
|
312
|
+
fi
|
|
254
313
|
|
|
255
314
|
if [ "$codex_compact" -eq 1 ]; then
|
|
256
315
|
context+="
|
|
@@ -264,5 +323,21 @@ IMPORTANT: If directly useful, start with one short Eagle Mem attribution line,
|
|
|
264
323
|
"
|
|
265
324
|
fi
|
|
266
325
|
|
|
326
|
+
eagle_insert_recall_event "$session_id" "$recall_scope" "$cwd" "$agent" "$user_prompt" "$fts_query" "$summary_matches" "$memory_matches" "$code_matches" "${#context}" "ok" "" "$summary_refs" "$memory_refs" "$code_refs" >/dev/null 2>&1 || true
|
|
327
|
+
eagle_insert_event "$recall_scope" "$session_id" "$agent" "context_injected" "" "UserPromptSubmit" "ok" "$(jq -nc \
|
|
328
|
+
--argjson summary_matches "${summary_matches:-0}" \
|
|
329
|
+
--argjson memory_matches "${memory_matches:-0}" \
|
|
330
|
+
--argjson code_matches "${code_matches:-0}" \
|
|
331
|
+
--argjson injected_chars "${#context}" \
|
|
332
|
+
'{summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:$injected_chars}')" >/dev/null 2>&1 || true
|
|
333
|
+
eagle_hook_observability_set_detail "$(jq -nc \
|
|
334
|
+
--arg recall_status "ok" \
|
|
335
|
+
--argjson summary_matches "${summary_matches:-0}" \
|
|
336
|
+
--argjson memory_matches "${memory_matches:-0}" \
|
|
337
|
+
--argjson code_matches "${code_matches:-0}" \
|
|
338
|
+
--argjson injected_chars "${#context}" \
|
|
339
|
+
'{recall_status:$recall_status, summary_matches:$summary_matches, memory_matches:$memory_matches, code_matches:$code_matches, injected_chars:$injected_chars}')"
|
|
340
|
+
eagle_hook_observability_complete 0
|
|
341
|
+
|
|
267
342
|
eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
|
|
268
343
|
exit 0
|