eagle-mem 4.10.13 → 4.11.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 +13 -0
- package/README.md +20 -20
- 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/docs/agent-compatibility/README.md +38 -0
- package/docs/agent-compatibility/claude-code.md +50 -0
- package/docs/agent-compatibility/codex.md +51 -0
- package/docs/agent-compatibility/opencode.md +71 -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 +7 -0
- package/hooks/stop.sh +10 -1
- package/hooks/user-prompt-submit.sh +79 -6
- package/integrations/opencode_eagle_mem_plugin.js +387 -0
- package/lib/codex-hooks.sh +13 -6
- package/lib/common.sh +63 -0
- 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.sh +2 -0
- package/lib/hooks.sh +12 -7
- package/lib/opencode-hooks.sh +105 -0
- package/lib/provider.sh +2 -2
- package/package.json +5 -2
- package/scripts/compaction.sh +108 -8
- package/scripts/dashboard.sh +372 -0
- package/scripts/doctor.sh +30 -3
- package/scripts/health.sh +40 -2
- package/scripts/help.sh +10 -2
- package/scripts/inspect.sh +285 -0
- package/scripts/install.sh +31 -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/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 +18 -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_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
package/scripts/uninstall.sh
CHANGED
|
@@ -11,6 +11,7 @@ LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
|
11
11
|
. "$SCRIPTS_DIR/style.sh"
|
|
12
12
|
. "$LIB_DIR/common.sh"
|
|
13
13
|
. "$LIB_DIR/codex-hooks.sh"
|
|
14
|
+
. "$LIB_DIR/opencode-hooks.sh"
|
|
14
15
|
|
|
15
16
|
SETTINGS="$EAGLE_SETTINGS"
|
|
16
17
|
dry_run=false
|
|
@@ -66,6 +67,12 @@ else
|
|
|
66
67
|
eagle_warn "Could not patch Codex hooks.json (jq not found or file missing)"
|
|
67
68
|
fi
|
|
68
69
|
|
|
70
|
+
if eagle_remove_opencode_plugin; then
|
|
71
|
+
eagle_ok "OpenCode plugin removed"
|
|
72
|
+
else
|
|
73
|
+
eagle_info "OpenCode plugin not present or not Eagle Mem-owned"
|
|
74
|
+
fi
|
|
75
|
+
|
|
69
76
|
# ─── Remove instruction blocks and statusline integration ───
|
|
70
77
|
|
|
71
78
|
claude_md="$HOME/.claude/CLAUDE.md"
|
|
@@ -132,6 +139,8 @@ if [ -d "$EAGLE_GROK_SKILLS_DIR" ]; then
|
|
|
132
139
|
done
|
|
133
140
|
fi
|
|
134
141
|
|
|
142
|
+
eagle_remove_opencode_skills >/dev/null 2>&1 || true
|
|
143
|
+
|
|
135
144
|
# ─── Optionally wipe data ─────────────────────────────────
|
|
136
145
|
|
|
137
146
|
if [ -d "$EAGLE_MEM_DIR" ]; then
|
package/scripts/update.sh
CHANGED
|
@@ -16,11 +16,13 @@ LIB_DIR="$SCRIPTS_DIR/../lib"
|
|
|
16
16
|
. "$LIB_DIR/updater.sh"
|
|
17
17
|
. "$LIB_DIR/hooks.sh"
|
|
18
18
|
. "$LIB_DIR/codex-hooks.sh"
|
|
19
|
+
. "$LIB_DIR/opencode-hooks.sh"
|
|
19
20
|
|
|
20
21
|
SETTINGS="$EAGLE_SETTINGS"
|
|
21
22
|
claude_found=false
|
|
22
23
|
codex_found=false
|
|
23
24
|
grok_found=false
|
|
25
|
+
opencode_found=false
|
|
24
26
|
|
|
25
27
|
eagle_header "Update"
|
|
26
28
|
|
|
@@ -43,8 +45,11 @@ fi
|
|
|
43
45
|
if [ -d "$EAGLE_GROK_DIR" ]; then
|
|
44
46
|
grok_found=true
|
|
45
47
|
fi
|
|
48
|
+
if eagle_opencode_detected; then
|
|
49
|
+
opencode_found=true
|
|
50
|
+
fi
|
|
46
51
|
|
|
47
|
-
eagle_runtime_change_plan "update" "$PACKAGE_DIR" "$claude_found" "$codex_found"
|
|
52
|
+
eagle_runtime_change_plan "update" "$PACKAGE_DIR" "$claude_found" "$codex_found" "$opencode_found"
|
|
48
53
|
|
|
49
54
|
# ─── Update files ──────────────────────────────────────────
|
|
50
55
|
|
|
@@ -82,11 +87,12 @@ fi
|
|
|
82
87
|
|
|
83
88
|
if [ "$claude_found" = true ] && [ -f "$SETTINGS" ] && command -v jq &>/dev/null; then
|
|
84
89
|
# Clean old registrations before re-registering (handles matcher changes across versions)
|
|
90
|
+
eagle_clean_hook_entries "$SETTINGS" "Stop" "$EAGLE_MEM_DIR/hooks/stop.sh"
|
|
85
91
|
eagle_clean_hook_entries "$SETTINGS" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
86
92
|
eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
|
|
87
93
|
|
|
88
94
|
eagle_patch_hook "$SETTINGS" "SessionStart" "" "$EAGLE_MEM_DIR/hooks/session-start.sh"
|
|
89
|
-
eagle_patch_hook "$SETTINGS" "Stop" "" "$EAGLE_MEM_DIR/hooks/stop.sh"
|
|
95
|
+
eagle_patch_hook "$SETTINGS" "Stop" "" "bash \"$EAGLE_MEM_DIR/hooks/stop.sh\""
|
|
90
96
|
eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
91
97
|
eagle_patch_hook "$SETTINGS" "TaskCreated" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
92
98
|
eagle_patch_hook "$SETTINGS" "TaskCompleted" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
|
|
@@ -104,6 +110,12 @@ elif [ "$codex_found" = false ]; then
|
|
|
104
110
|
eagle_info "Codex hooks skipped ${DIM}(Codex not detected)${RESET}"
|
|
105
111
|
fi
|
|
106
112
|
|
|
113
|
+
if [ "$opencode_found" = true ]; then
|
|
114
|
+
eagle_install_opencode_plugin "$PACKAGE_DIR" "0"
|
|
115
|
+
else
|
|
116
|
+
eagle_info "OpenCode plugin skipped ${DIM}(OpenCode not detected)${RESET}"
|
|
117
|
+
fi
|
|
118
|
+
|
|
107
119
|
# ─── Update skill symlinks ────────────────────────────────
|
|
108
120
|
|
|
109
121
|
if [ "$claude_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
@@ -164,6 +176,10 @@ if [ "$grok_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
|
164
176
|
eagle_ok "Grok skills updated"
|
|
165
177
|
fi
|
|
166
178
|
|
|
179
|
+
if [ "$opencode_found" = true ] && [ -d "$PACKAGE_DIR/skills" ]; then
|
|
180
|
+
eagle_install_opencode_skills "$PACKAGE_DIR" "0"
|
|
181
|
+
fi
|
|
182
|
+
|
|
167
183
|
# ─── Refresh generated Claude statusline wrapper ───────────
|
|
168
184
|
|
|
169
185
|
statusline_wrapper="$EAGLE_MEM_DIR/scripts/statusline-wrapper.sh"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hook_event_name": "Status",
|
|
3
|
+
"session_id": "claude-status-fixture",
|
|
4
|
+
"transcript_path": "/tmp/eagle-mem/claude-status-fixture.jsonl",
|
|
5
|
+
"cwd": "/tmp/eagle-mem/project",
|
|
6
|
+
"model": {
|
|
7
|
+
"id": "claude-opus-4-1",
|
|
8
|
+
"display_name": "Opus"
|
|
9
|
+
},
|
|
10
|
+
"workspace": {
|
|
11
|
+
"current_dir": "/tmp/eagle-mem/project",
|
|
12
|
+
"project_dir": "/tmp/eagle-mem/project"
|
|
13
|
+
},
|
|
14
|
+
"version": "2.1.145",
|
|
15
|
+
"output_style": {
|
|
16
|
+
"name": "default"
|
|
17
|
+
},
|
|
18
|
+
"cost": {
|
|
19
|
+
"total_cost_usd": 0.01234,
|
|
20
|
+
"total_duration_ms": 45000,
|
|
21
|
+
"total_api_duration_ms": 2300,
|
|
22
|
+
"total_lines_added": 12,
|
|
23
|
+
"total_lines_removed": 2
|
|
24
|
+
},
|
|
25
|
+
"thinking": {
|
|
26
|
+
"enabled": true
|
|
27
|
+
},
|
|
28
|
+
"effort": {
|
|
29
|
+
"level": "xhigh"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"session_id": "claude-session-fixture",
|
|
3
|
+
"transcript_path": "/tmp/eagle-mem/claude-session-fixture.jsonl",
|
|
4
|
+
"cwd": "/tmp/eagle-mem/project",
|
|
5
|
+
"permission_mode": "default",
|
|
6
|
+
"hook_event_name": "UserPromptSubmit",
|
|
7
|
+
"prompt": "Review the OAuth memory before editing auth files"
|
|
8
|
+
}
|
|
9
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sessionID": "opencode-session-fixture",
|
|
3
|
+
"input": {
|
|
4
|
+
"sessionID": "opencode-session-fixture",
|
|
5
|
+
"agent": "build",
|
|
6
|
+
"model": {
|
|
7
|
+
"providerID": "openai",
|
|
8
|
+
"modelID": "gpt-5"
|
|
9
|
+
},
|
|
10
|
+
"messageID": "opencode-user-message-fixture"
|
|
11
|
+
},
|
|
12
|
+
"output": {
|
|
13
|
+
"message": {
|
|
14
|
+
"id": "opencode-user-message-fixture",
|
|
15
|
+
"sessionID": "opencode-session-fixture",
|
|
16
|
+
"role": "user",
|
|
17
|
+
"time": {
|
|
18
|
+
"created": 1780372800000
|
|
19
|
+
},
|
|
20
|
+
"agent": "build",
|
|
21
|
+
"model": {
|
|
22
|
+
"providerID": "openai",
|
|
23
|
+
"modelID": "gpt-5"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"parts": [
|
|
27
|
+
{
|
|
28
|
+
"id": "opencode-text-part-fixture",
|
|
29
|
+
"sessionID": "opencode-session-fixture",
|
|
30
|
+
"messageID": "opencode-user-message-fixture",
|
|
31
|
+
"type": "text",
|
|
32
|
+
"text": "Review the OAuth memory before editing auth files"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"input": {
|
|
3
|
+
"tool": "read",
|
|
4
|
+
"sessionID": "opencode-session-fixture",
|
|
5
|
+
"callID": "opencode-call-fixture",
|
|
6
|
+
"args": {
|
|
7
|
+
"filePath": "/tmp/eagle-mem/project/lib/auth.ts"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"output": {
|
|
11
|
+
"title": "Read lib/auth.ts",
|
|
12
|
+
"output": "export function refreshToken() {}",
|
|
13
|
+
"metadata": {}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Guard against stale agent lifecycle assumptions when editing hook, statusline,
|
|
3
|
+
# config-installation, or instruction-file integration code.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
7
|
+
DOC_DIR="$ROOT_DIR/docs/agent-compatibility"
|
|
8
|
+
FIXTURE_DIR="$ROOT_DIR/tests/fixtures/agent-hooks"
|
|
9
|
+
|
|
10
|
+
fail() {
|
|
11
|
+
echo "agent compatibility docs gate failed: $*" >&2
|
|
12
|
+
exit 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
require_file() {
|
|
16
|
+
local file="$1"
|
|
17
|
+
[ -f "$file" ] || fail "missing required file: ${file#$ROOT_DIR/}"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
require_contains() {
|
|
21
|
+
local file="$1"
|
|
22
|
+
local pattern="$2"
|
|
23
|
+
local label="$3"
|
|
24
|
+
if ! grep -Eq "$pattern" "$file"; then
|
|
25
|
+
fail "${file#$ROOT_DIR/} does not mention $label"
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
require_json() {
|
|
30
|
+
local file="$1"
|
|
31
|
+
jq -e . "$file" >/dev/null || fail "invalid JSON fixture: ${file#$ROOT_DIR/}"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
require_file "$DOC_DIR/README.md"
|
|
35
|
+
require_file "$DOC_DIR/claude-code.md"
|
|
36
|
+
require_file "$DOC_DIR/codex.md"
|
|
37
|
+
require_file "$DOC_DIR/opencode.md"
|
|
38
|
+
require_file "$FIXTURE_DIR/claude-user-prompt-submit.json"
|
|
39
|
+
require_file "$FIXTURE_DIR/claude-statusline.json"
|
|
40
|
+
require_file "$FIXTURE_DIR/codex-user-prompt-submit.json"
|
|
41
|
+
require_file "$FIXTURE_DIR/codex-pre-tool-use.json"
|
|
42
|
+
require_file "$FIXTURE_DIR/opencode-chat-message.json"
|
|
43
|
+
require_file "$FIXTURE_DIR/opencode-tool-execute-before.json"
|
|
44
|
+
require_file "$FIXTURE_DIR/opencode-tool-execute-after.json"
|
|
45
|
+
require_file "$FIXTURE_DIR/opencode-todo-updated.json"
|
|
46
|
+
require_file "$FIXTURE_DIR/opencode-session-compacting.json"
|
|
47
|
+
|
|
48
|
+
require_json "$FIXTURE_DIR/claude-user-prompt-submit.json"
|
|
49
|
+
require_json "$FIXTURE_DIR/claude-statusline.json"
|
|
50
|
+
require_json "$FIXTURE_DIR/codex-user-prompt-submit.json"
|
|
51
|
+
require_json "$FIXTURE_DIR/codex-pre-tool-use.json"
|
|
52
|
+
require_json "$FIXTURE_DIR/opencode-chat-message.json"
|
|
53
|
+
require_json "$FIXTURE_DIR/opencode-tool-execute-before.json"
|
|
54
|
+
require_json "$FIXTURE_DIR/opencode-tool-execute-after.json"
|
|
55
|
+
require_json "$FIXTURE_DIR/opencode-todo-updated.json"
|
|
56
|
+
require_json "$FIXTURE_DIR/opencode-session-compacting.json"
|
|
57
|
+
|
|
58
|
+
require_contains "$DOC_DIR/README.md" "Before modifying" "the required pre-edit workflow"
|
|
59
|
+
require_contains "$DOC_DIR/README.md" "official documentation" "official documentation"
|
|
60
|
+
require_contains "$DOC_DIR/README.md" "fixture|golden-test" "fixture or golden-test coverage"
|
|
61
|
+
|
|
62
|
+
require_contains "$DOC_DIR/claude-code.md" "Last verified: [0-9]{4}-[0-9]{2}-[0-9]{2}" "a Last verified date"
|
|
63
|
+
require_contains "$DOC_DIR/claude-code.md" "https://code\\.claude\\.com/docs/en/hooks" "Claude Code hooks source"
|
|
64
|
+
require_contains "$DOC_DIR/claude-code.md" "https://code\\.claude\\.com/docs/en/statusline" "Claude Code statusline source"
|
|
65
|
+
require_contains "$DOC_DIR/claude-code.md" "UserPromptSubmit" "Claude UserPromptSubmit"
|
|
66
|
+
require_contains "$DOC_DIR/claude-code.md" "PreCompact" "Claude PreCompact"
|
|
67
|
+
require_contains "$DOC_DIR/claude-code.md" "PostCompact" "Claude PostCompact"
|
|
68
|
+
require_contains "$DOC_DIR/claude-code.md" "statusLine" "Claude statusLine config"
|
|
69
|
+
require_contains "$DOC_DIR/claude-code.md" "tests/fixtures/agent-hooks/claude-statusline\\.json" "Claude statusline fixture"
|
|
70
|
+
|
|
71
|
+
require_contains "$DOC_DIR/codex.md" "Last verified: [0-9]{4}-[0-9]{2}-[0-9]{2}" "a Last verified date"
|
|
72
|
+
require_contains "$DOC_DIR/codex.md" "https://developers\\.openai\\.com/codex/codex-manual\\.md" "Codex manual source"
|
|
73
|
+
require_contains "$DOC_DIR/codex.md" "https://developers\\.openai\\.com/codex/hooks\\.md" "Codex hooks source"
|
|
74
|
+
require_contains "$DOC_DIR/codex.md" "AGENTS\\.md" "Codex AGENTS.md behavior"
|
|
75
|
+
require_contains "$DOC_DIR/codex.md" "features\\.hooks" "canonical Codex hooks feature flag"
|
|
76
|
+
require_contains "$DOC_DIR/codex.md" "deprecated alias" "deprecated Codex hook alias"
|
|
77
|
+
require_contains "$DOC_DIR/codex.md" "UserPromptSubmit" "Codex UserPromptSubmit"
|
|
78
|
+
require_contains "$DOC_DIR/codex.md" "tests/fixtures/agent-hooks/codex-pre-tool-use\\.json" "Codex PreToolUse fixture"
|
|
79
|
+
|
|
80
|
+
require_contains "$DOC_DIR/opencode.md" "Last verified: [0-9]{4}-[0-9]{2}-[0-9]{2}" "an OpenCode Last verified date"
|
|
81
|
+
require_contains "$DOC_DIR/opencode.md" "https://opencode\\.ai/docs/plugins/" "OpenCode plugins source"
|
|
82
|
+
require_contains "$DOC_DIR/opencode.md" "https://opencode\\.ai/docs/config/" "OpenCode config source"
|
|
83
|
+
require_contains "$DOC_DIR/opencode.md" "https://opencode\\.ai/config\\.json" "OpenCode config schema source"
|
|
84
|
+
require_contains "$DOC_DIR/opencode.md" "~/.config/opencode/plugins/" "OpenCode global local plugin directory"
|
|
85
|
+
require_contains "$DOC_DIR/opencode.md" "chat\\.message" "OpenCode chat.message hook"
|
|
86
|
+
require_contains "$DOC_DIR/opencode.md" "tool\\.execute\\.before" "OpenCode tool.execute.before hook"
|
|
87
|
+
require_contains "$DOC_DIR/opencode.md" "tool\\.execute\\.after" "OpenCode tool.execute.after hook"
|
|
88
|
+
require_contains "$DOC_DIR/opencode.md" "todo\\.updated" "OpenCode todo.updated event"
|
|
89
|
+
require_contains "$DOC_DIR/opencode.md" "experimental\\.session\\.compacting" "OpenCode compaction hook"
|
|
90
|
+
require_contains "$DOC_DIR/opencode.md" "opencode --pure" "OpenCode pure-mode caveat"
|
|
91
|
+
require_contains "$DOC_DIR/opencode.md" "tests/fixtures/agent-hooks/opencode-tool-execute-before\\.json" "OpenCode PreToolUse fixture"
|
|
92
|
+
require_contains "$DOC_DIR/opencode.md" "tests/test_opencode_plugin_adapter\\.sh" "OpenCode adapter regression test"
|
|
93
|
+
|
|
94
|
+
if grep -R "features\\.codex_hooks" "$ROOT_DIR/lib" "$ROOT_DIR/scripts" "$ROOT_DIR/hooks" "$ROOT_DIR/bin" >/dev/null 2>&1; then
|
|
95
|
+
fail "implementation still uses deprecated Codex features.codex_hooks instead of features.hooks"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
if grep -R "codex_hooks[[:space:]]*=[[:space:]]*true" "$ROOT_DIR/lib" "$ROOT_DIR/scripts" "$ROOT_DIR/hooks" "$ROOT_DIR/bin" >/dev/null 2>&1; then
|
|
99
|
+
fail "implementation still writes deprecated Codex codex_hooks config instead of hooks"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
changed_sensitive=$(
|
|
103
|
+
{
|
|
104
|
+
git -C "$ROOT_DIR" diff --name-only HEAD -- 2>/dev/null || true
|
|
105
|
+
git -C "$ROOT_DIR" ls-files --others --exclude-standard 2>/dev/null || true
|
|
106
|
+
} | awk '
|
|
107
|
+
/^(hooks\/.*\.sh|lib\/hooks\.sh|lib\/codex-hooks\.sh|lib\/opencode-hooks\.sh|integrations\/opencode_eagle_mem_plugin\.js|scripts\/install\.sh|scripts\/update\.sh|scripts\/uninstall\.sh|scripts\/doctor\.sh|scripts\/statusline-em\.sh|lib\/common\.sh|AGENTS\.md|CLAUDE\.md)$/ { print }
|
|
108
|
+
' | sort -u
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if [ -n "$changed_sensitive" ]; then
|
|
112
|
+
changed_evidence=$(
|
|
113
|
+
{
|
|
114
|
+
git -C "$ROOT_DIR" diff --name-only HEAD -- 2>/dev/null || true
|
|
115
|
+
git -C "$ROOT_DIR" ls-files --others --exclude-standard 2>/dev/null || true
|
|
116
|
+
} | awk '
|
|
117
|
+
/^(docs\/agent-compatibility\/.*\.md|tests\/fixtures\/agent-hooks\/.*\.json|tests\/test_agent_compatibility_docs_gate\.sh)$/ { print }
|
|
118
|
+
' | sort -u
|
|
119
|
+
)
|
|
120
|
+
[ -n "$changed_evidence" ] || fail "sensitive integration files changed without updated compatibility docs or fixtures: $changed_sensitive"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo "agent compatibility docs gate passed"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Broad prompts should create durable orchestration state automatically. This
|
|
3
|
+
# proves Eagle detects the need for lanes instead of relying only on agent
|
|
4
|
+
# obedience to instructions.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
+
EAGLE_BIN="$ROOT_DIR/bin/eagle-mem"
|
|
9
|
+
|
|
10
|
+
tmp_dir=$(mktemp -d "$ROOT_DIR/.tmp-auto-orchestration.XXXXXX")
|
|
11
|
+
trap 'rm -rf "$tmp_dir"' EXIT
|
|
12
|
+
|
|
13
|
+
export HOME="$tmp_dir/home"
|
|
14
|
+
export EAGLE_MEM_DIR="$tmp_dir/eagle-mem"
|
|
15
|
+
mkdir -p "$HOME" "$EAGLE_MEM_DIR"
|
|
16
|
+
|
|
17
|
+
. "$ROOT_DIR/lib/common.sh"
|
|
18
|
+
"$ROOT_DIR/db/migrate.sh" >/dev/null
|
|
19
|
+
. "$ROOT_DIR/lib/db.sh"
|
|
20
|
+
|
|
21
|
+
assert_json() {
|
|
22
|
+
local json="$1" filter="$2" message="$3"
|
|
23
|
+
if ! printf '%s' "$json" | jq -e "$filter" >/dev/null; then
|
|
24
|
+
echo "$message" >&2
|
|
25
|
+
echo "$json" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
assert_contains() {
|
|
31
|
+
local haystack="$1" needle="$2" message="$3"
|
|
32
|
+
case "$haystack" in
|
|
33
|
+
*"$needle"*) ;;
|
|
34
|
+
*)
|
|
35
|
+
echo "$message" >&2
|
|
36
|
+
echo "Expected to find: $needle" >&2
|
|
37
|
+
echo "$haystack" >&2
|
|
38
|
+
exit 1
|
|
39
|
+
;;
|
|
40
|
+
esac
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
project="project-auto-orchestration"
|
|
44
|
+
repo="$HOME/$project"
|
|
45
|
+
mkdir -p "$repo"
|
|
46
|
+
|
|
47
|
+
hook_input=$(jq -nc \
|
|
48
|
+
--arg sid "auto-orchestration-session" \
|
|
49
|
+
--arg cwd "$repo" \
|
|
50
|
+
--arg prompt "Please plan and get started on a broad full codebase release. Split the work into lanes, coordinate workers, implement the fixes, and verify the ship path." \
|
|
51
|
+
'{session_id:$sid, cwd:$cwd, prompt:$prompt, transcript_path:"/tmp/transcript.jsonl"}')
|
|
52
|
+
|
|
53
|
+
hook_output=$(EAGLE_MEM_PROJECT="$project" EAGLE_MEM_DIR="$EAGLE_MEM_DIR" EAGLE_AGENT_SOURCE="codex" bash "$ROOT_DIR/hooks/user-prompt-submit.sh" <<< "$hook_input")
|
|
54
|
+
assert_contains "$hook_output" "created durable orchestration 'auto'" "broad prompt did not report auto orchestration creation"
|
|
55
|
+
assert_contains "$hook_output" "Continue from the durable lanes" "hook did not tell the agent to continue from durable lanes"
|
|
56
|
+
|
|
57
|
+
orchestration_json=$(cd "$repo" && EAGLE_MEM_PROJECT="$project" EAGLE_MEM_DIR="$EAGLE_MEM_DIR" "$EAGLE_BIN" orchestrate --name auto --json)
|
|
58
|
+
assert_json "$orchestration_json" '
|
|
59
|
+
length == 3
|
|
60
|
+
and ([.[].lane_key] | sort == ["implementation","scope","verification"])
|
|
61
|
+
and all(.[]; .status == "pending")
|
|
62
|
+
' "auto orchestration did not create the expected pending lanes"
|
|
63
|
+
|
|
64
|
+
task_json=$(cd "$repo" && EAGLE_MEM_PROJECT="$project" EAGLE_MEM_DIR="$EAGLE_MEM_DIR" "$EAGLE_BIN" tasks --json)
|
|
65
|
+
assert_json "$task_json" '
|
|
66
|
+
length >= 3
|
|
67
|
+
and ([.[] | select(.source_task_id | startswith("lane-auto-"))] | length == 3)
|
|
68
|
+
' "auto orchestration did not mirror lanes into durable tasks"
|
|
69
|
+
|
|
70
|
+
event_json=$(eagle_db_json "SELECT session_id, project, agent, prompt_snippet, orchestration_name, lanes, status
|
|
71
|
+
FROM orchestration_auto_events
|
|
72
|
+
WHERE project = '$project'
|
|
73
|
+
ORDER BY id DESC;")
|
|
74
|
+
assert_json "$event_json" '
|
|
75
|
+
length == 1
|
|
76
|
+
and .[0].session_id == "auto-orchestration-session"
|
|
77
|
+
and .[0].orchestration_name == "auto"
|
|
78
|
+
and .[0].status == "created"
|
|
79
|
+
and ((.[0].lanes | fromjson) | length == 3)
|
|
80
|
+
' "auto orchestration event was not recorded"
|
|
81
|
+
|
|
82
|
+
hook_output_again=$(EAGLE_MEM_PROJECT="$project" EAGLE_MEM_DIR="$EAGLE_MEM_DIR" EAGLE_AGENT_SOURCE="codex" bash "$ROOT_DIR/hooks/user-prompt-submit.sh" <<< "$hook_input")
|
|
83
|
+
assert_contains "$hook_output_again" "created durable orchestration 'auto'" "repeated broad prompt did not reuse auto orchestration"
|
|
84
|
+
|
|
85
|
+
lane_count=$(eagle_db "SELECT COUNT(*)
|
|
86
|
+
FROM orchestration_lanes l
|
|
87
|
+
JOIN orchestrations o ON o.id = l.orchestration_id
|
|
88
|
+
WHERE o.project = '$project'
|
|
89
|
+
AND o.name = 'auto';")
|
|
90
|
+
task_count=$(eagle_db "SELECT COUNT(*)
|
|
91
|
+
FROM agent_tasks
|
|
92
|
+
WHERE project = '$project'
|
|
93
|
+
AND source_task_id LIKE 'lane-auto-%';")
|
|
94
|
+
event_count=$(eagle_db "SELECT COUNT(*) FROM orchestration_auto_events WHERE project = '$project';")
|
|
95
|
+
|
|
96
|
+
[ "$lane_count" = "3" ] || { echo "expected 3 auto lanes after repeat, got $lane_count" >&2; exit 1; }
|
|
97
|
+
[ "$task_count" = "3" ] || { echo "expected 3 auto tasks after repeat, got $task_count" >&2; exit 1; }
|
|
98
|
+
[ "$event_count" = "2" ] || { echo "expected 2 auto events after repeat, got $event_count" >&2; exit 1; }
|
|
99
|
+
|
|
100
|
+
quiet_input=$(jq -nc \
|
|
101
|
+
--arg sid "quiet-session" \
|
|
102
|
+
--arg cwd "$repo" \
|
|
103
|
+
--arg prompt "Please inspect the config value." \
|
|
104
|
+
'{session_id:$sid, cwd:$cwd, prompt:$prompt}')
|
|
105
|
+
EAGLE_MEM_PROJECT="$project" EAGLE_MEM_DIR="$EAGLE_MEM_DIR" EAGLE_AGENT_SOURCE="codex" bash "$ROOT_DIR/hooks/user-prompt-submit.sh" <<< "$quiet_input" >/dev/null
|
|
106
|
+
quiet_event_count=$(eagle_db "SELECT COUNT(*) FROM orchestration_auto_events WHERE project = '$project';")
|
|
107
|
+
[ "$quiet_event_count" = "2" ] || { echo "quiet prompt should not create auto orchestration event" >&2; exit 1; }
|
|
108
|
+
|
|
109
|
+
echo "auto orchestration detection regressions passed"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Regression coverage for Claude Stop hook registration.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
6
|
+
tmp_dir=$(mktemp -d "$ROOT_DIR/.tmp-claude-stop.XXXXXX")
|
|
7
|
+
trap 'rm -rf "$tmp_dir"' EXIT
|
|
8
|
+
|
|
9
|
+
export HOME="$tmp_dir/home"
|
|
10
|
+
export EAGLE_MEM_DIR="$tmp_dir/eagle-mem"
|
|
11
|
+
mkdir -p "$HOME" "$EAGLE_MEM_DIR/hooks"
|
|
12
|
+
|
|
13
|
+
. "$ROOT_DIR/scripts/style.sh"
|
|
14
|
+
. "$ROOT_DIR/lib/common.sh"
|
|
15
|
+
. "$ROOT_DIR/lib/hooks.sh"
|
|
16
|
+
|
|
17
|
+
settings="$tmp_dir/settings.json"
|
|
18
|
+
old_stop="$EAGLE_MEM_DIR/hooks/stop.sh"
|
|
19
|
+
new_stop="bash \"$EAGLE_MEM_DIR/hooks/stop.sh\""
|
|
20
|
+
|
|
21
|
+
fail() {
|
|
22
|
+
echo "claude stop hook registration test failed: $*" >&2
|
|
23
|
+
exit 1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
cat > "$settings" <<JSON
|
|
27
|
+
{
|
|
28
|
+
"hooks": {
|
|
29
|
+
"Stop": [
|
|
30
|
+
{
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "$old_stop"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
JSON
|
|
42
|
+
|
|
43
|
+
eagle_clean_hook_entries "$settings" "Stop" "$old_stop"
|
|
44
|
+
eagle_patch_hook "$settings" "Stop" "" "$new_stop" >/dev/null
|
|
45
|
+
|
|
46
|
+
jq -e --arg cmd "$old_stop" 'all(.hooks.Stop[]?.hooks[]?; .command != $cmd)' "$settings" >/dev/null \
|
|
47
|
+
|| fail "path-only Stop hook registration remained"
|
|
48
|
+
|
|
49
|
+
jq -e --arg cmd "$new_stop" '.hooks.Stop[]? | select(.matcher == null and (.hooks[]?.command == $cmd))' "$settings" >/dev/null \
|
|
50
|
+
|| fail "bash-wrapped Stop hook registration missing"
|
|
51
|
+
|
|
52
|
+
eagle_patch_hook "$settings" "Stop" "" "$new_stop" >/dev/null
|
|
53
|
+
count=$(jq --arg cmd "$new_stop" '[.hooks.Stop[]?.hooks[]? | select(.command == $cmd)] | length' "$settings")
|
|
54
|
+
[ "$count" -eq 1 ] || fail "bash-wrapped Stop hook registration duplicated: $count"
|
|
55
|
+
|
|
56
|
+
echo "claude stop hook registration test passed"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Codex hook enablement should use the current canonical features.hooks flag
|
|
3
|
+
# while cleaning up the older codex_hooks alias when encountered.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
7
|
+
|
|
8
|
+
tmp_dir=$(mktemp -d "$ROOT_DIR/.tmp-codex-hooks-config.XXXXXX")
|
|
9
|
+
trap 'rm -rf "$tmp_dir"' EXIT
|
|
10
|
+
|
|
11
|
+
export HOME="$tmp_dir/home"
|
|
12
|
+
export EAGLE_MEM_DIR="$tmp_dir/eagle-mem"
|
|
13
|
+
export EAGLE_CODEX_DIR="$HOME/.codex"
|
|
14
|
+
export EAGLE_CODEX_CONFIG="$EAGLE_CODEX_DIR/config.toml"
|
|
15
|
+
export EAGLE_CODEX_HOOKS="$EAGLE_CODEX_DIR/hooks.json"
|
|
16
|
+
|
|
17
|
+
mkdir -p "$HOME" "$EAGLE_MEM_DIR" "$EAGLE_CODEX_DIR"
|
|
18
|
+
|
|
19
|
+
. "$ROOT_DIR/lib/common.sh"
|
|
20
|
+
. "$ROOT_DIR/lib/codex-hooks.sh"
|
|
21
|
+
|
|
22
|
+
fail() {
|
|
23
|
+
echo "codex hooks config regression failed: $*" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert_has_hooks_true() {
|
|
28
|
+
grep -q '^hooks = true$' "$EAGLE_CODEX_CONFIG" || fail "missing canonical hooks = true"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
assert_no_legacy_write() {
|
|
32
|
+
if grep -q '^codex_hooks[[:space:]]*=' "$EAGLE_CODEX_CONFIG"; then
|
|
33
|
+
fail "deprecated codex_hooks key was left in generated config"
|
|
34
|
+
fi
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
rm -f "$EAGLE_CODEX_CONFIG"
|
|
38
|
+
eagle_enable_codex_hooks
|
|
39
|
+
assert_has_hooks_true
|
|
40
|
+
assert_no_legacy_write
|
|
41
|
+
|
|
42
|
+
cat > "$EAGLE_CODEX_CONFIG" <<'TOML'
|
|
43
|
+
[other]
|
|
44
|
+
name = "preserve-me"
|
|
45
|
+
|
|
46
|
+
[features]
|
|
47
|
+
codex_hooks = false
|
|
48
|
+
memories = true
|
|
49
|
+
|
|
50
|
+
[sandbox]
|
|
51
|
+
mode = "workspace-write"
|
|
52
|
+
TOML
|
|
53
|
+
|
|
54
|
+
eagle_enable_codex_hooks
|
|
55
|
+
assert_has_hooks_true
|
|
56
|
+
assert_no_legacy_write
|
|
57
|
+
grep -q '^memories = true$' "$EAGLE_CODEX_CONFIG" || fail "features table values were not preserved"
|
|
58
|
+
grep -q '^name = "preserve-me"$' "$EAGLE_CODEX_CONFIG" || fail "other config sections were not preserved"
|
|
59
|
+
grep -q '^mode = "workspace-write"$' "$EAGLE_CODEX_CONFIG" || fail "later config sections were not preserved"
|
|
60
|
+
|
|
61
|
+
cat > "$EAGLE_CODEX_CONFIG" <<'TOML'
|
|
62
|
+
[features]
|
|
63
|
+
hooks = false
|
|
64
|
+
TOML
|
|
65
|
+
|
|
66
|
+
eagle_enable_codex_hooks
|
|
67
|
+
assert_has_hooks_true
|
|
68
|
+
assert_no_legacy_write
|
|
69
|
+
hook_lines=$(grep -c '^hooks = true$' "$EAGLE_CODEX_CONFIG")
|
|
70
|
+
[ "$hook_lines" -eq 1 ] || fail "expected one hooks = true line, found $hook_lines"
|
|
71
|
+
|
|
72
|
+
echo "codex hooks config regressions passed"
|
|
73
|
+
|