eagle-mem 4.6.2 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -15
- package/db/023_guardrails.sql +3 -2
- package/db/024_guardrails_unique.sql +46 -0
- package/db/025_pending_feature_verifications.sql +30 -0
- package/db/026_agent_source.sql +18 -0
- package/db/027_feature_verification_fingerprints.sql +9 -0
- package/db/028_agent_artifact_tables.sql +124 -0
- package/hooks/post-tool-use.sh +42 -13
- package/hooks/pre-tool-use.sh +107 -14
- package/hooks/session-end.sh +3 -1
- package/hooks/session-start.sh +64 -15
- package/hooks/stop.sh +115 -21
- package/hooks/user-prompt-submit.sh +14 -5
- package/lib/codex-hooks.sh +194 -0
- package/lib/common.sh +345 -0
- package/lib/db-backfill.sh +3 -3
- package/lib/db-features.sh +222 -0
- package/lib/db-guardrails.sh +2 -1
- package/lib/db-mirrors.sh +79 -43
- package/lib/db-observations.sh +3 -2
- package/lib/db-sessions.sh +11 -7
- package/lib/db-summaries.sh +9 -6
- package/lib/hooks-posttool.sh +8 -6
- package/lib/provider.sh +190 -4
- package/package.json +7 -3
- package/scripts/config.sh +2 -0
- package/scripts/feature.sh +70 -2
- package/scripts/guard.sh +4 -1
- package/scripts/health.sh +5 -1
- package/scripts/help.sh +13 -8
- package/scripts/install.sh +130 -76
- package/scripts/memories.sh +71 -45
- package/scripts/refresh.sh +3 -3
- package/scripts/search.sh +57 -47
- package/scripts/statusline-em.sh +1 -1
- package/scripts/tasks.sh +186 -15
- package/scripts/uninstall.sh +7 -0
- package/scripts/update.sh +51 -7
- package/skills/eagle-mem-memories/SKILL.md +13 -13
- package/skills/eagle-mem-tasks/SKILL.md +21 -15
package/lib/hooks-posttool.sh
CHANGED
|
@@ -8,9 +8,10 @@ _EAGLE_HOOKS_POSTTOOL_LOADED=1
|
|
|
8
8
|
|
|
9
9
|
eagle_posttool_mirror_writes() {
|
|
10
10
|
local tool_name="$1" fp="$2" session_id="$3" project="$4"
|
|
11
|
+
local agent="${5:-$(eagle_agent_source)}"
|
|
11
12
|
|
|
12
13
|
case "$tool_name" in
|
|
13
|
-
Write|Edit)
|
|
14
|
+
Write|Edit|apply_patch)
|
|
14
15
|
if [ -n "$fp" ]; then
|
|
15
16
|
case "$fp" in
|
|
16
17
|
*..*) ;; # path traversal — skip
|
|
@@ -18,12 +19,12 @@ eagle_posttool_mirror_writes() {
|
|
|
18
19
|
local mem_base
|
|
19
20
|
mem_base=$(basename "$fp")
|
|
20
21
|
if [ "$mem_base" != "MEMORY.md" ] && [ -f "$fp" ]; then
|
|
21
|
-
|
|
22
|
+
eagle_capture_agent_memory "$fp" "$session_id" "$project" "$agent"
|
|
22
23
|
fi
|
|
23
24
|
;;
|
|
24
25
|
"$EAGLE_CLAUDE_PLANS_DIR/"*.md)
|
|
25
26
|
if [ -f "$fp" ]; then
|
|
26
|
-
|
|
27
|
+
eagle_capture_agent_plan "$fp" "$session_id" "$project" "$agent"
|
|
27
28
|
fi
|
|
28
29
|
;;
|
|
29
30
|
esac
|
|
@@ -34,6 +35,7 @@ eagle_posttool_mirror_writes() {
|
|
|
34
35
|
|
|
35
36
|
eagle_posttool_mirror_tasks() {
|
|
36
37
|
local tool_name="$1" session_id="$2" project="$3" input="$4"
|
|
38
|
+
local agent="${5:-$(eagle_agent_source)}"
|
|
37
39
|
|
|
38
40
|
case "$tool_name" in
|
|
39
41
|
TaskCreate|TaskUpdate)
|
|
@@ -45,10 +47,10 @@ eagle_posttool_mirror_tasks() {
|
|
|
45
47
|
if [ -z "$task_id" ]; then
|
|
46
48
|
local newest
|
|
47
49
|
newest=$(ls -t "$task_dir"/*.json 2>/dev/null | head -1)
|
|
48
|
-
[ -n "$newest" ] && [ -f "$newest" ] &&
|
|
50
|
+
[ -n "$newest" ] && [ -f "$newest" ] && eagle_capture_agent_task "$newest" "$session_id" "$project" "$agent"
|
|
49
51
|
elif eagle_validate_session_id "$task_id"; then
|
|
50
52
|
local task_json="$task_dir/$task_id.json"
|
|
51
|
-
[ -f "$task_json" ] &&
|
|
53
|
+
[ -f "$task_json" ] && eagle_capture_agent_task "$task_json" "$session_id" "$project" "$agent"
|
|
52
54
|
fi
|
|
53
55
|
fi
|
|
54
56
|
fi
|
|
@@ -60,7 +62,7 @@ eagle_posttool_stale_hint() {
|
|
|
60
62
|
local tool_name="$1" fp="$2" project="$3"
|
|
61
63
|
|
|
62
64
|
case "$tool_name" in
|
|
63
|
-
Write|Edit)
|
|
65
|
+
Write|Edit|apply_patch)
|
|
64
66
|
if [ -n "$fp" ]; then
|
|
65
67
|
local fname fname_stem
|
|
66
68
|
fname=$(basename "$fp")
|
package/lib/provider.sh
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ═══════════════════════════════════════════════════════════
|
|
3
3
|
# Eagle Mem — LLM Provider Abstraction
|
|
4
|
-
# Config parsing + unified eagle_llm_call for Ollama/
|
|
4
|
+
# Config parsing + unified eagle_llm_call for Ollama/agent CLI/API providers
|
|
5
5
|
# ═══════════════════════════════════════════════════════════
|
|
6
6
|
|
|
7
7
|
EAGLE_CONFIG_FILE="${EAGLE_MEM_DIR}/config.toml"
|
|
@@ -121,12 +121,17 @@ eagle_config_init() {
|
|
|
121
121
|
local ollama_url="$EAGLE_DEFAULT_OLLAMA_URL"
|
|
122
122
|
local provider="none"
|
|
123
123
|
local model=""
|
|
124
|
+
local ollama_model="mistral"
|
|
124
125
|
|
|
125
126
|
local ollama_response
|
|
126
127
|
ollama_response=$(eagle_detect_ollama "$ollama_url")
|
|
127
128
|
if [ -n "$ollama_response" ]; then
|
|
128
129
|
provider="ollama"
|
|
129
130
|
model=$(eagle_ollama_best_model "$ollama_url")
|
|
131
|
+
ollama_model="$model"
|
|
132
|
+
elif command -v codex &>/dev/null || command -v claude &>/dev/null; then
|
|
133
|
+
provider="agent_cli"
|
|
134
|
+
model="native"
|
|
130
135
|
elif [ -n "${ANTHROPIC_API_KEY:-}" ]; then
|
|
131
136
|
provider="anthropic"
|
|
132
137
|
model="claude-haiku-4-5-20251001"
|
|
@@ -144,12 +149,20 @@ eagle_config_init() {
|
|
|
144
149
|
|
|
145
150
|
[provider]
|
|
146
151
|
# Which LLM provider to use for the curator and analysis features
|
|
147
|
-
# Options: "ollama" (free, local), "anthropic", "openai"
|
|
152
|
+
# Options: "ollama" (free, local), "agent_cli" (Codex/Claude CLI auth), "anthropic", "openai"
|
|
148
153
|
type = "$provider"
|
|
149
154
|
|
|
150
155
|
[ollama]
|
|
151
156
|
url = "$ollama_url"
|
|
152
|
-
model = "$
|
|
157
|
+
model = "$ollama_model"
|
|
158
|
+
|
|
159
|
+
[agent_cli]
|
|
160
|
+
# Uses the already-installed Codex/Claude CLI instead of direct API keys.
|
|
161
|
+
# preferred = "current" uses EAGLE_AGENT_SOURCE when hooks invoke Eagle Mem.
|
|
162
|
+
# If run manually with no agent source, it prefers Codex when available.
|
|
163
|
+
preferred = "current"
|
|
164
|
+
codex_model = ""
|
|
165
|
+
claude_model = ""
|
|
153
166
|
|
|
154
167
|
[anthropic]
|
|
155
168
|
# Uses ANTHROPIC_API_KEY env var for authentication
|
|
@@ -184,6 +197,7 @@ eagle_llm_call() {
|
|
|
184
197
|
|
|
185
198
|
case "$provider" in
|
|
186
199
|
ollama) _eagle_call_ollama "$prompt" "$system_prompt" "$max_tokens" ;;
|
|
200
|
+
agent_cli) _eagle_call_agent_cli "$prompt" "$system_prompt" "$max_tokens" ;;
|
|
187
201
|
anthropic) _eagle_call_anthropic "$prompt" "$system_prompt" "$max_tokens" ;;
|
|
188
202
|
openai) _eagle_call_openai "$prompt" "$system_prompt" "$max_tokens" ;;
|
|
189
203
|
none)
|
|
@@ -235,6 +249,170 @@ _eagle_call_ollama() {
|
|
|
235
249
|
echo "$response" | jq -r '.message.content // empty'
|
|
236
250
|
}
|
|
237
251
|
|
|
252
|
+
_eagle_agent_cli_target() {
|
|
253
|
+
local preferred
|
|
254
|
+
preferred=$(eagle_config_get "agent_cli" "preferred" "current")
|
|
255
|
+
|
|
256
|
+
case "$preferred" in
|
|
257
|
+
codex|openai-codex) echo "codex"; return 0 ;;
|
|
258
|
+
claude|claude-code|cloud-code) echo "claude-code"; return 0 ;;
|
|
259
|
+
auto)
|
|
260
|
+
if [ -n "${EAGLE_AGENT_SOURCE:-${EAGLE_AGENT:-}}" ]; then
|
|
261
|
+
eagle_agent_source
|
|
262
|
+
elif command -v codex &>/dev/null; then
|
|
263
|
+
echo "codex"
|
|
264
|
+
elif command -v claude &>/dev/null; then
|
|
265
|
+
echo "claude-code"
|
|
266
|
+
else
|
|
267
|
+
echo "none"
|
|
268
|
+
fi
|
|
269
|
+
;;
|
|
270
|
+
current|*)
|
|
271
|
+
if [ -n "${EAGLE_AGENT_SOURCE:-${EAGLE_AGENT:-}}" ]; then
|
|
272
|
+
eagle_agent_source
|
|
273
|
+
elif command -v codex &>/dev/null; then
|
|
274
|
+
echo "codex"
|
|
275
|
+
elif command -v claude &>/dev/null; then
|
|
276
|
+
echo "claude-code"
|
|
277
|
+
else
|
|
278
|
+
echo "none"
|
|
279
|
+
fi
|
|
280
|
+
;;
|
|
281
|
+
esac
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
_eagle_agent_cli_prompt_file() {
|
|
285
|
+
local prompt="$1" system="$2" max_tokens="$3" file="$4"
|
|
286
|
+
{
|
|
287
|
+
printf 'System instruction:\n%s\n\n' "$system"
|
|
288
|
+
printf 'Task:\n%s\n\n' "$prompt"
|
|
289
|
+
printf 'Output contract:\n'
|
|
290
|
+
printf -- '- Return only the requested curator text.\n'
|
|
291
|
+
printf -- '- Do not use markdown fences unless the task explicitly asks for them.\n'
|
|
292
|
+
printf -- '- Do not edit files, run project commands, or inspect the repository; all needed data is in this prompt.\n'
|
|
293
|
+
printf -- '- Keep the response within roughly %s tokens.\n' "$max_tokens"
|
|
294
|
+
} > "$file"
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
_eagle_call_agent_cli() {
|
|
298
|
+
local prompt="$1" system="$2" max_tokens="$3"
|
|
299
|
+
local target
|
|
300
|
+
target=$(_eagle_agent_cli_target)
|
|
301
|
+
|
|
302
|
+
case "$target" in
|
|
303
|
+
codex) _eagle_call_codex_cli "$prompt" "$system" "$max_tokens" ;;
|
|
304
|
+
claude-code) _eagle_call_claude_cli "$prompt" "$system" "$max_tokens" ;;
|
|
305
|
+
*)
|
|
306
|
+
eagle_log "ERROR" "agent_cli provider unavailable: no Codex or Claude CLI found"
|
|
307
|
+
return 1
|
|
308
|
+
;;
|
|
309
|
+
esac
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
_eagle_call_codex_cli() {
|
|
313
|
+
local prompt="$1" system="$2" max_tokens="$3"
|
|
314
|
+
command -v codex &>/dev/null || {
|
|
315
|
+
eagle_log "ERROR" "agent_cli provider selected Codex, but codex command was not found"
|
|
316
|
+
return 1
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
mkdir -p "$EAGLE_MEM_DIR/tmp"
|
|
320
|
+
local prompt_file out_file
|
|
321
|
+
prompt_file=$(mktemp "$EAGLE_MEM_DIR/tmp/codex-provider-prompt.XXXXXX")
|
|
322
|
+
out_file=$(mktemp "$EAGLE_MEM_DIR/tmp/codex-provider-output.XXXXXX")
|
|
323
|
+
_eagle_agent_cli_prompt_file "$prompt" "$system" "$max_tokens" "$prompt_file"
|
|
324
|
+
|
|
325
|
+
local model
|
|
326
|
+
model=$(eagle_config_get "agent_cli" "codex_model" "")
|
|
327
|
+
|
|
328
|
+
local rc _had_errexit=0
|
|
329
|
+
case "$-" in *e*) _had_errexit=1; set +e ;; esac
|
|
330
|
+
if [ -n "$model" ]; then
|
|
331
|
+
EAGLE_MEM_DISABLE_HOOKS=1 codex exec \
|
|
332
|
+
--ephemeral \
|
|
333
|
+
--skip-git-repo-check \
|
|
334
|
+
--ignore-rules \
|
|
335
|
+
-c features.codex_hooks=false \
|
|
336
|
+
--sandbox read-only \
|
|
337
|
+
--cd "${EAGLE_AGENT_CWD:-$(pwd)}" \
|
|
338
|
+
--model "$model" \
|
|
339
|
+
--output-last-message "$out_file" \
|
|
340
|
+
- < "$prompt_file" >> "$EAGLE_MEM_LOG" 2>&1
|
|
341
|
+
rc=$?
|
|
342
|
+
else
|
|
343
|
+
EAGLE_MEM_DISABLE_HOOKS=1 codex exec \
|
|
344
|
+
--ephemeral \
|
|
345
|
+
--skip-git-repo-check \
|
|
346
|
+
--ignore-rules \
|
|
347
|
+
-c features.codex_hooks=false \
|
|
348
|
+
--sandbox read-only \
|
|
349
|
+
--cd "${EAGLE_AGENT_CWD:-$(pwd)}" \
|
|
350
|
+
--output-last-message "$out_file" \
|
|
351
|
+
- < "$prompt_file" >> "$EAGLE_MEM_LOG" 2>&1
|
|
352
|
+
rc=$?
|
|
353
|
+
fi
|
|
354
|
+
[ "$_had_errexit" -eq 1 ] && set -e
|
|
355
|
+
|
|
356
|
+
rm -f "$prompt_file"
|
|
357
|
+
if [ "$rc" -ne 0 ] || [ ! -s "$out_file" ]; then
|
|
358
|
+
rm -f "$out_file"
|
|
359
|
+
eagle_log "ERROR" "Codex agent_cli provider call failed"
|
|
360
|
+
return 1
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
cat "$out_file"
|
|
364
|
+
rm -f "$out_file"
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
_eagle_call_claude_cli() {
|
|
368
|
+
local prompt="$1" system="$2" max_tokens="$3"
|
|
369
|
+
command -v claude &>/dev/null || {
|
|
370
|
+
eagle_log "ERROR" "agent_cli provider selected Claude Code, but claude command was not found"
|
|
371
|
+
return 1
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
mkdir -p "$EAGLE_MEM_DIR/tmp"
|
|
375
|
+
local prompt_file out_file model rc
|
|
376
|
+
prompt_file=$(mktemp "$EAGLE_MEM_DIR/tmp/claude-provider-prompt.XXXXXX")
|
|
377
|
+
out_file=$(mktemp "$EAGLE_MEM_DIR/tmp/claude-provider-output.XXXXXX")
|
|
378
|
+
_eagle_agent_cli_prompt_file "$prompt" "$system" "$max_tokens" "$prompt_file"
|
|
379
|
+
model=$(eagle_config_get "agent_cli" "claude_model" "")
|
|
380
|
+
|
|
381
|
+
local _had_errexit=0
|
|
382
|
+
case "$-" in *e*) _had_errexit=1; set +e ;; esac
|
|
383
|
+
if [ -n "$model" ]; then
|
|
384
|
+
EAGLE_MEM_DISABLE_HOOKS=1 CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 claude -p \
|
|
385
|
+
--no-session-persistence \
|
|
386
|
+
--disable-slash-commands \
|
|
387
|
+
--permission-mode dontAsk \
|
|
388
|
+
--tools "" \
|
|
389
|
+
--output-format text \
|
|
390
|
+
--model "$model" \
|
|
391
|
+
"$(cat "$prompt_file")" > "$out_file" 2>> "$EAGLE_MEM_LOG"
|
|
392
|
+
rc=$?
|
|
393
|
+
else
|
|
394
|
+
EAGLE_MEM_DISABLE_HOOKS=1 CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 claude -p \
|
|
395
|
+
--no-session-persistence \
|
|
396
|
+
--disable-slash-commands \
|
|
397
|
+
--permission-mode dontAsk \
|
|
398
|
+
--tools "" \
|
|
399
|
+
--output-format text \
|
|
400
|
+
"$(cat "$prompt_file")" > "$out_file" 2>> "$EAGLE_MEM_LOG"
|
|
401
|
+
rc=$?
|
|
402
|
+
fi
|
|
403
|
+
[ "$_had_errexit" -eq 1 ] && set -e
|
|
404
|
+
|
|
405
|
+
rm -f "$prompt_file"
|
|
406
|
+
if [ "$rc" -ne 0 ] || [ ! -s "$out_file" ]; then
|
|
407
|
+
rm -f "$out_file"
|
|
408
|
+
eagle_log "ERROR" "Claude agent_cli provider call failed"
|
|
409
|
+
return 1
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
cat "$out_file"
|
|
413
|
+
rm -f "$out_file"
|
|
414
|
+
}
|
|
415
|
+
|
|
238
416
|
_eagle_call_anthropic() {
|
|
239
417
|
local prompt="$1" system="$2" max_tokens="$3"
|
|
240
418
|
local model api_key
|
|
@@ -332,7 +510,11 @@ eagle_show_config() {
|
|
|
332
510
|
|
|
333
511
|
local provider model
|
|
334
512
|
provider=$(eagle_config_get "provider" "type" "none")
|
|
335
|
-
|
|
513
|
+
if [ "$provider" = "agent_cli" ]; then
|
|
514
|
+
model=$(_eagle_agent_cli_target)
|
|
515
|
+
else
|
|
516
|
+
model=$(eagle_config_get "$provider" "model" "unknown")
|
|
517
|
+
fi
|
|
336
518
|
|
|
337
519
|
echo "Provider: $provider"
|
|
338
520
|
echo "Model: $model"
|
|
@@ -349,6 +531,10 @@ eagle_show_config() {
|
|
|
349
531
|
else
|
|
350
532
|
echo "Status: not running"
|
|
351
533
|
fi
|
|
534
|
+
elif [ "$provider" = "agent_cli" ]; then
|
|
535
|
+
echo "Preferred: $(eagle_config_get "agent_cli" "preferred" "current")"
|
|
536
|
+
echo "Codex: $(command -v codex 2>/dev/null || echo "not found")"
|
|
537
|
+
echo "Claude: $(command -v claude 2>/dev/null || echo "not found")"
|
|
352
538
|
fi
|
|
353
539
|
|
|
354
540
|
echo ""
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eagle-mem",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "Context that survives /compact for Claude Code — SQLite + FTS5, no daemon, no bloat",
|
|
3
|
+
"version": "4.7.1",
|
|
4
|
+
"description": "Context that survives /compact for Claude Code and Codex — SQLite + FTS5, no daemon, no bloat",
|
|
5
5
|
"bin": {
|
|
6
6
|
"eagle-mem": "bin/eagle-mem"
|
|
7
7
|
},
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"keywords": [
|
|
17
17
|
"claude-code",
|
|
18
|
+
"codex",
|
|
18
19
|
"memory",
|
|
19
20
|
"sqlite",
|
|
20
21
|
"fts5",
|
|
@@ -27,5 +28,8 @@
|
|
|
27
28
|
"type": "git",
|
|
28
29
|
"url": "git+https://github.com/eagleisbatman/eagle-mem.git"
|
|
29
30
|
},
|
|
30
|
-
"homepage": "https://github.
|
|
31
|
+
"homepage": "https://eagleisbatman.github.io/eagle-mem/",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/eagleisbatman/eagle-mem/issues"
|
|
34
|
+
}
|
|
31
35
|
}
|
package/scripts/config.sh
CHANGED
|
@@ -36,6 +36,8 @@ case "$subcommand" in
|
|
|
36
36
|
eagle_err "Usage: eagle-mem config set <section.key> <value>"
|
|
37
37
|
eagle_info "Examples:"
|
|
38
38
|
eagle_info " eagle-mem config set provider.type ollama"
|
|
39
|
+
eagle_info " eagle-mem config set provider.type agent_cli"
|
|
40
|
+
eagle_info " eagle-mem config set agent_cli.preferred current"
|
|
39
41
|
eagle_info " eagle-mem config set ollama.model mistral"
|
|
40
42
|
eagle_info " eagle-mem config set anthropic.model claude-haiku-4-5-20251001"
|
|
41
43
|
exit 1
|
package/scripts/feature.sh
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ═══════════════════════════════════════════════════════════
|
|
3
3
|
# Eagle Mem — Feature management
|
|
4
|
-
# eagle-mem feature [list|show|verify|add]
|
|
4
|
+
# eagle-mem feature [list|show|verify|pending|waive|add]
|
|
5
5
|
# ═══════════════════════════════════════════════════════════
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
@@ -59,8 +59,76 @@ case "$subcommand" in
|
|
|
59
59
|
*) notes="$1"; shift ;;
|
|
60
60
|
esac
|
|
61
61
|
done
|
|
62
|
+
fid=$(eagle_get_feature_id "$project" "$name")
|
|
63
|
+
if [ -z "$fid" ]; then
|
|
64
|
+
eagle_err "Feature not found: $name"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
62
67
|
eagle_verify_feature "$project" "$name" "$notes"
|
|
68
|
+
resolved=$(eagle_resolve_pending_feature_verifications "$project" "$name" "verified" "$notes" | tail -1)
|
|
63
69
|
eagle_ok "Feature '$name' marked as verified"
|
|
70
|
+
if [ "${resolved:-0}" -gt 0 ] 2>/dev/null; then
|
|
71
|
+
eagle_info "Resolved pending verification records: $resolved"
|
|
72
|
+
fi
|
|
73
|
+
;;
|
|
74
|
+
|
|
75
|
+
pending)
|
|
76
|
+
results=$(eagle_list_pending_feature_verifications "$project" 50)
|
|
77
|
+
if [ -z "$results" ]; then
|
|
78
|
+
eagle_ok "No pending feature verifications for '$project'"
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
echo -e " ${BOLD}ID Feature File Trigger Diff${RESET}"
|
|
83
|
+
echo -e " ${DIM}──── ────────────────────────────── ──────────────────────────── ───────── ────────────${RESET}"
|
|
84
|
+
while IFS='|' read -r id feat file reason trigger created smoke fingerprint; do
|
|
85
|
+
[ -z "$id" ] && continue
|
|
86
|
+
feat_display="${feat:0:30}"
|
|
87
|
+
file_display="${file:0:28}"
|
|
88
|
+
trigger_display="${trigger:-hook}"
|
|
89
|
+
fingerprint_display="${fingerprint:-unknown}"
|
|
90
|
+
printf " %-4s %-30s %-28s %-9s %-12s\n" "$id" "$feat_display" "$file_display" "$trigger_display" "$fingerprint_display"
|
|
91
|
+
[ -n "$reason" ] && echo -e " ${DIM}${reason}${RESET}"
|
|
92
|
+
[ -n "$smoke" ] && echo -e " ${CYAN}smoke:${RESET} $smoke"
|
|
93
|
+
[ -n "$created" ] && echo -e " ${DIM}created: $created${RESET}"
|
|
94
|
+
done <<< "$results"
|
|
95
|
+
echo ""
|
|
96
|
+
eagle_info "Verify after testing: eagle-mem feature verify <name> --notes \"what passed\""
|
|
97
|
+
eagle_info "Waive intentionally: eagle-mem feature waive <id> --reason \"why safe\""
|
|
98
|
+
;;
|
|
99
|
+
|
|
100
|
+
waive)
|
|
101
|
+
id="${1:-}"
|
|
102
|
+
[ -z "$id" ] && { eagle_err "Usage: eagle-mem feature waive <id> --reason <text>"; exit 1; }
|
|
103
|
+
case "$id" in
|
|
104
|
+
*[!0-9]*)
|
|
105
|
+
eagle_err "Invalid ID: '$id' (must be numeric)"
|
|
106
|
+
exit 1
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
shift
|
|
110
|
+
reason=""
|
|
111
|
+
while [ $# -gt 0 ]; do
|
|
112
|
+
case "$1" in
|
|
113
|
+
--reason|--notes)
|
|
114
|
+
if [ $# -lt 2 ] || [ -z "${2:-}" ]; then
|
|
115
|
+
eagle_err "$1 requires a value"
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
reason="$2"
|
|
119
|
+
shift 2
|
|
120
|
+
;;
|
|
121
|
+
*) reason="$1"; shift ;;
|
|
122
|
+
esac
|
|
123
|
+
done
|
|
124
|
+
[ -z "$reason" ] && { eagle_err "Usage: eagle-mem feature waive <id> --reason <text>"; exit 1; }
|
|
125
|
+
waived=$(eagle_waive_pending_feature_verification "$project" "$id" "$reason" | tail -1)
|
|
126
|
+
if [ "${waived:-0}" -gt 0 ] 2>/dev/null; then
|
|
127
|
+
eagle_ok "Pending verification #$id waived"
|
|
128
|
+
else
|
|
129
|
+
eagle_err "No pending verification found with ID $id"
|
|
130
|
+
exit 1
|
|
131
|
+
fi
|
|
64
132
|
;;
|
|
65
133
|
|
|
66
134
|
add)
|
|
@@ -104,7 +172,7 @@ case "$subcommand" in
|
|
|
104
172
|
|
|
105
173
|
*)
|
|
106
174
|
eagle_err "Unknown feature command: $subcommand"
|
|
107
|
-
eagle_info "Usage: eagle-mem feature [list|show|verify|add]"
|
|
175
|
+
eagle_info "Usage: eagle-mem feature [list|show|verify|pending|waive|add]"
|
|
108
176
|
exit 1
|
|
109
177
|
;;
|
|
110
178
|
esac
|
package/scripts/guard.sh
CHANGED
|
@@ -55,7 +55,10 @@ case "$subcommand" in
|
|
|
55
55
|
esac
|
|
56
56
|
done
|
|
57
57
|
|
|
58
|
-
eagle_add_guardrail "$project" "$rule" "$file_pattern" "manual"
|
|
58
|
+
if ! eagle_add_guardrail "$project" "$rule" "$file_pattern" "manual"; then
|
|
59
|
+
eagle_err "Failed to add guardrail. Check $EAGLE_MEM_LOG for SQLite details."
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
59
62
|
eagle_ok "Guardrail added for project: $project"
|
|
60
63
|
if [ -n "$file_pattern" ]; then
|
|
61
64
|
eagle_info "File pattern: $file_pattern"
|
package/scripts/health.sh
CHANGED
|
@@ -133,7 +133,11 @@ max_score=$((max_score + 15))
|
|
|
133
133
|
|
|
134
134
|
provider=$(eagle_config_get "provider" "type" "none")
|
|
135
135
|
if [ "$provider" != "none" ]; then
|
|
136
|
-
|
|
136
|
+
if [ "$provider" = "agent_cli" ]; then
|
|
137
|
+
model=$(_eagle_agent_cli_target)
|
|
138
|
+
else
|
|
139
|
+
model=$(eagle_config_get "$provider" "model" "default")
|
|
140
|
+
fi
|
|
137
141
|
eagle_ok "Provider: ${provider} (${model})"
|
|
138
142
|
score=$((score + 15))
|
|
139
143
|
else
|
package/scripts/help.sh
CHANGED
|
@@ -13,7 +13,7 @@ version=$(jq -r .version "$PACKAGE_DIR/package.json" 2>/dev/null || echo "unknow
|
|
|
13
13
|
eagle_banner
|
|
14
14
|
|
|
15
15
|
echo -e " ${BOLD}Eagle Mem${RESET} ${DIM}v${version}${RESET}"
|
|
16
|
-
echo -e " ${DIM}Context that survives /compact for Claude Code${RESET}"
|
|
16
|
+
echo -e " ${DIM}Context that survives /compact for Claude Code and Codex${RESET}"
|
|
17
17
|
echo ""
|
|
18
18
|
echo -e " ${BOLD}Commands:${RESET}"
|
|
19
19
|
echo -e " ${CYAN}install${RESET} First-time setup: hooks, database, skills"
|
|
@@ -24,10 +24,10 @@ echo -e " ${CYAN}health${RESET} Diagnose pipeline health and background
|
|
|
24
24
|
echo -e " ${CYAN}config${RESET} View or change LLM provider settings"
|
|
25
25
|
echo -e " ${CYAN}guard${RESET} Manage regression guardrails for files"
|
|
26
26
|
echo -e " ${CYAN}overview${RESET} Build or view project overview"
|
|
27
|
-
echo -e " ${CYAN}memories${RESET} View/sync
|
|
27
|
+
echo -e " ${CYAN}memories${RESET} View/sync agent memories"
|
|
28
28
|
echo -e " ${CYAN}tasks${RESET} View mirrored tasks"
|
|
29
29
|
echo -e " ${CYAN}curate${RESET} Run curator (co-edits, hot files, guardrails)"
|
|
30
|
-
echo -e " ${CYAN}feature${RESET} Track and
|
|
30
|
+
echo -e " ${CYAN}feature${RESET} Track, verify, and unblock features"
|
|
31
31
|
echo -e " ${CYAN}prune${RESET} Clean old sessions and stale data"
|
|
32
32
|
echo ""
|
|
33
33
|
echo -e " ${BOLD}Search modes:${RESET}"
|
|
@@ -39,11 +39,16 @@ echo -e " ${DIM}\$${RESET} eagle-mem search --tasks ${DIM}# in-flight
|
|
|
39
39
|
echo -e " ${DIM}\$${RESET} eagle-mem search --files ${DIM}# hot files${RESET}"
|
|
40
40
|
echo -e " ${DIM}\$${RESET} eagle-mem search --stats ${DIM}# project stats${RESET}"
|
|
41
41
|
echo ""
|
|
42
|
-
echo -e " ${BOLD}
|
|
43
|
-
echo -e " ${
|
|
44
|
-
echo -e " ${
|
|
45
|
-
echo -e " ${
|
|
46
|
-
echo
|
|
42
|
+
echo -e " ${BOLD}Anti-regression:${RESET}"
|
|
43
|
+
echo -e " ${DIM}\$${RESET} eagle-mem feature pending ${DIM}# pending release blockers${RESET}"
|
|
44
|
+
echo -e " ${DIM}\$${RESET} eagle-mem feature verify NAME ${DIM}# verify current diff after testing${RESET}"
|
|
45
|
+
echo -e " ${DIM}\$${RESET} eagle-mem feature waive ID ${DIM}# intentional exception${RESET}"
|
|
46
|
+
echo ""
|
|
47
|
+
echo -e " ${BOLD}Skills${RESET} ${DIM}(inside Claude Code and Codex sessions):${RESET}"
|
|
48
|
+
echo -e " ${CYAN}eagle-mem-search${RESET} Search memory and past sessions"
|
|
49
|
+
echo -e " ${CYAN}eagle-mem-overview${RESET} Build or update project overview"
|
|
50
|
+
echo -e " ${CYAN}eagle-mem-memories${RESET} View/sync agent memories"
|
|
51
|
+
echo -e " ${CYAN}eagle-mem-tasks${RESET} TaskAware Compact Loop for multi-step work"
|
|
47
52
|
echo ""
|
|
48
53
|
echo -e " ${DIM}Everything else is automatic — scan, index, prune, and${RESET}"
|
|
49
54
|
echo -e " ${DIM}curator all run in the background via hooks.${RESET}"
|