eagle-mem 4.8.4 → 4.8.6

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 CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  Eagle Mem turns AI coding sessions into compounding project knowledge. It gives Claude Code and Codex the same local memory, labels which agent created each memory, blocks risky release commands until affected features are verified, and lets broad work split into durable worker lanes.
13
13
 
14
- **v4.8.4 proves the worker-lane path end to end:** Codex can create an orchestration, route a lane to Claude Code by default, launch the Claude worker in an isolated worktree, mirror the lane into `agent_tasks`, and generate a durable handoff without crashing on Bash 3.2.
14
+ **v4.8.5 hardens first-run setup:** `eagle-mem config init` now falls through cleanly when Ollama is not running, and DB-backed commands fail loudly when the active `sqlite3` lacks FTS5 support.
15
15
 
16
16
  **Website:** [Product](https://eagleisbatman.github.io/eagle-mem/) |
17
17
  [Architecture](https://eagleisbatman.github.io/eagle-mem/architecture.html) |
@@ -140,6 +140,7 @@ Eagle Mem prevents Claude from repeating past mistakes:
140
140
  | `eagle-mem config` | View or change LLM provider and token-guard settings |
141
141
  | `eagle-mem guard` | Manage regression guardrails for files |
142
142
  | `eagle-mem overview` | Build or view project overview |
143
+ | `eagle-mem session` | Save a manual fallback session summary |
143
144
  | `eagle-mem memories` | View/sync agent memories |
144
145
  | `eagle-mem tasks` | View mirrored tasks |
145
146
  | `eagle-mem orchestrate` | Coordinate durable worker lanes across agents |
@@ -149,6 +150,14 @@ Eagle Mem prevents Claude from repeating past mistakes:
149
150
  | `eagle-mem scan` | Scan codebase and generate overview |
150
151
  | `eagle-mem index` | Index source files for FTS5 code search |
151
152
 
153
+ ### v4.8.6 Patch
154
+
155
+ `eagle-mem session save --summary "..."` now exists as a clean manual fallback for agents that need to persist an explicit session note. It writes through the same `sessions` and `summaries` tables used by Stop hooks, keeps Claude Code/Codex source attribution, and is immediately searchable through normal recall.
156
+
157
+ ### v4.8.5 Patch
158
+
159
+ First-run configuration no longer exits silently when Ollama is not listening on `localhost:11434`; Eagle Mem falls through to the installed Codex/Claude CLI provider or API-key providers. SQLite/FTS5 failures are now surfaced before DB-backed commands run, including the exact `sqlite3` binary being used and PATH guidance for common macOS Android SDK shadowing. Worker worktree paths are also canonicalized back to the main project key so backfill cannot move feature guardrails into disposable orchestration worktrees.
160
+
152
161
  ### v4.8.4 Patch
153
162
 
154
163
  The orchestration handoff path is now Bash 3.2-safe, so `eagle-mem orchestrate handoff` works even when no lane options are present. This patch was verified with a real Codex coordinator -> Claude Code worker proof lane using `claude-opus-4-7` at `xhigh`; the completed lane is visible through `eagle-mem orchestrate --json`, `eagle-mem tasks completed`, and the generated handoff output. Release-boundary detection also ignores Eagle Mem's own `feature verify`/`waive` commands, so verification notes can mention dry-run checks without blocking themselves.
@@ -176,6 +185,7 @@ eagle-mem search --tasks # in-flight tasks (pending/in-progress)
176
185
  eagle-mem search --files # most frequently modified files
177
186
  eagle-mem search --stats # project statistics
178
187
  eagle-mem search --session <id> # full observation trail for one session
188
+ eagle-mem session save --summary "fixed auth flow" # manual fallback capture
179
189
  ```
180
190
 
181
191
  ### Feature Verification
package/bin/eagle-mem CHANGED
@@ -24,6 +24,8 @@ case "$command" in
24
24
  config) bash "$SCRIPTS_DIR/config.sh" "$@" ;;
25
25
  guard) bash "$SCRIPTS_DIR/guard.sh" "$@" ;;
26
26
  overview) bash "$SCRIPTS_DIR/overview.sh" "$@" ;;
27
+ session|sessions)
28
+ bash "$SCRIPTS_DIR/session.sh" "$@" ;;
27
29
  memories) bash "$SCRIPTS_DIR/memories.sh" "$@" ;;
28
30
  tasks) bash "$SCRIPTS_DIR/tasks.sh" "$@" ;;
29
31
  orchestrate) bash "$SCRIPTS_DIR/orchestrate.sh" "$@" ;;
package/db/migrate.sh CHANGED
@@ -9,6 +9,20 @@ EAGLE_MEM_DIR="${EAGLE_MEM_DIR:-$HOME/.eagle-mem}"
9
9
  DB="$EAGLE_MEM_DIR/memory.db"
10
10
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
11
 
12
+ COMMON_SH="$SCRIPT_DIR/../lib/common.sh"
13
+ if [ -f "$COMMON_SH" ]; then
14
+ . "$COMMON_SH"
15
+ eagle_require_sqlite_fts5 || exit 1
16
+ else
17
+ sqlite_path=$(command -v sqlite3 2>/dev/null || true)
18
+ if [ -z "$sqlite_path" ] || ! sqlite3 :memory: "CREATE VIRTUAL TABLE eagle_mem_fts5_probe USING fts5(value);" >/dev/null 2>&1; then
19
+ echo "Eagle Mem requires SQLite FTS5, but the active sqlite3 does not support it." >&2
20
+ [ -n "$sqlite_path" ] && echo "Detected sqlite3: $sqlite_path" >&2
21
+ echo "Fix PATH so an FTS5-capable sqlite3 is first, then re-run the command." >&2
22
+ exit 1
23
+ fi
24
+ fi
25
+
12
26
  # Restrict permissions: DB and config contain session data and may contain
13
27
  # residual secrets despite redaction. Owner-only access (700 dir, 600 files).
14
28
  umask 077
package/lib/common.sh CHANGED
@@ -20,6 +20,47 @@ EAGLE_CODEX_SKILLS_DIR="${EAGLE_CODEX_SKILLS_DIR:-$EAGLE_CODEX_DIR/skills}"
20
20
  EAGLE_CODEX_MEMORIES_DIR="${EAGLE_CODEX_MEMORIES_DIR:-$EAGLE_CODEX_DIR/memories}"
21
21
  EAGLE_RAW_BASH_UNLOCK="${EAGLE_RAW_BASH_UNLOCK:-/tmp/eagle-mem-raw-bash-unlock}"
22
22
 
23
+ eagle_sqlite_path() {
24
+ command -v sqlite3 2>/dev/null || true
25
+ }
26
+
27
+ eagle_sqlite_version() {
28
+ sqlite3 --version 2>/dev/null | awk '{print $1}'
29
+ }
30
+
31
+ eagle_sqlite_supports_fts5() {
32
+ command -v sqlite3 >/dev/null 2>&1 || return 1
33
+ sqlite3 :memory: "CREATE VIRTUAL TABLE eagle_mem_fts5_probe USING fts5(value);" >/dev/null 2>&1
34
+ }
35
+
36
+ eagle_print_sqlite_fts5_error() {
37
+ local sqlite_path sqlite_version probe_error
38
+ sqlite_path=$(eagle_sqlite_path)
39
+ sqlite_version=$(eagle_sqlite_version)
40
+ probe_error=$(sqlite3 :memory: "CREATE VIRTUAL TABLE eagle_mem_fts5_probe USING fts5(value);" 2>&1 >/dev/null || true)
41
+
42
+ printf '%s\n' "Eagle Mem requires SQLite FTS5, but the active sqlite3 does not support it." >&2
43
+ if [ -n "$sqlite_path" ]; then
44
+ printf '%s\n' "Detected sqlite3: $sqlite_path" >&2
45
+ else
46
+ printf '%s\n' "Detected sqlite3: not found on PATH" >&2
47
+ fi
48
+ [ -n "$sqlite_version" ] && printf '%s\n' "SQLite version: $sqlite_version" >&2
49
+ [ -n "$probe_error" ] && printf '%s\n' "SQLite error: $probe_error" >&2
50
+ printf '%s\n' "Fix: put an FTS5-capable sqlite3 earlier in PATH, then re-run the command." >&2
51
+ printf '%s\n' "macOS: check 'command -v sqlite3'; /usr/bin/sqlite3 usually has FTS5. If Android SDK platform-tools is first, move it later in PATH." >&2
52
+ printf '%s\n' "Homebrew: install sqlite and prepend its bin directory, for example: export PATH=\"/opt/homebrew/opt/sqlite/bin:\$PATH\"" >&2
53
+ printf '%s\n' "Linux: install a sqlite3 package compiled with ENABLE_FTS5." >&2
54
+ }
55
+
56
+ eagle_require_sqlite_fts5() {
57
+ if eagle_sqlite_supports_fts5; then
58
+ return 0
59
+ fi
60
+ eagle_print_sqlite_fts5_error
61
+ return 1
62
+ }
63
+
23
64
  eagle_log() {
24
65
  local level="$1"
25
66
  shift
@@ -51,6 +92,23 @@ eagle_project_from_cwd() {
51
92
  "$HOME/Desktop"|"$HOME/Desktop/"*) echo ""; return ;;
52
93
  esac
53
94
 
95
+ # Eagle Mem worker lanes run in sibling git worktrees under
96
+ # <parent>/.eagle-worktrees/<repo>/<lane>. Keep their observations attached
97
+ # to the real project, not to the disposable worktree path.
98
+ case "$resolved" in
99
+ "$HOME"/*/.eagle-worktrees/*)
100
+ local worktree_parent worktree_tail worktree_repo worktree_project
101
+ worktree_parent="${resolved%%/.eagle-worktrees/*}"
102
+ worktree_tail="${resolved#"$worktree_parent/.eagle-worktrees/"}"
103
+ worktree_repo="${worktree_tail%%/*}"
104
+ worktree_project="$worktree_parent/$worktree_repo"
105
+ if [ -n "$worktree_repo" ] && [ -d "$worktree_project" ]; then
106
+ echo "${worktree_project#$HOME/}"
107
+ return
108
+ fi
109
+ ;;
110
+ esac
111
+
54
112
  local target_dir
55
113
  local git_root
56
114
  git_root=$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null)
package/lib/db-core.sh CHANGED
@@ -57,6 +57,8 @@ eagle_db_json() {
57
57
  }
58
58
 
59
59
  eagle_ensure_db() {
60
+ eagle_require_sqlite_fts5 || return 1
61
+
60
62
  if [ ! -f "$EAGLE_MEM_DB" ]; then
61
63
  local script_dir
62
64
  script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../db" && pwd)"
package/lib/provider.sh CHANGED
@@ -124,10 +124,10 @@ eagle_config_init() {
124
124
  local ollama_model="mistral"
125
125
 
126
126
  local ollama_response
127
- ollama_response=$(eagle_detect_ollama "$ollama_url")
127
+ ollama_response=$(eagle_detect_ollama "$ollama_url" || true)
128
128
  if [ -n "$ollama_response" ]; then
129
129
  provider="ollama"
130
- model=$(eagle_ollama_best_model "$ollama_url")
130
+ model=$(eagle_ollama_best_model "$ollama_url" || true)
131
131
  ollama_model="$model"
132
132
  elif command -v codex &>/dev/null || command -v claude &>/dev/null; then
133
133
  provider="agent_cli"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eagle-mem",
3
- "version": "4.8.4",
3
+ "version": "4.8.6",
4
4
  "description": "Shared memory, release guardrails, RTK token protection, and worker lanes for Claude Code and Codex",
5
5
  "bin": {
6
6
  "eagle-mem": "bin/eagle-mem"
package/scripts/help.sh CHANGED
@@ -23,6 +23,7 @@ echo -e " ${CYAN}uninstall${RESET} Remove hooks and optionally delete data"
23
23
  echo -e " ${CYAN}search${RESET} Search past sessions, memories, and code"
24
24
  echo -e " ${CYAN}health${RESET} Diagnose pipeline health and background automation"
25
25
  echo -e " ${CYAN}overview${RESET} Build or view project overview"
26
+ echo -e " ${CYAN}session${RESET} Save a manual session summary"
26
27
  echo -e " ${CYAN}memories${RESET} View/sync agent memories"
27
28
  echo -e " ${CYAN}tasks${RESET} View mirrored tasks"
28
29
  echo ""
@@ -50,6 +51,7 @@ echo -e " ${DIM}\$${RESET} eagle-mem search --memories ${DIM}# mirrored m
50
51
  echo -e " ${DIM}\$${RESET} eagle-mem search --tasks ${DIM}# in-flight tasks${RESET}"
51
52
  echo -e " ${DIM}\$${RESET} eagle-mem search --files ${DIM}# hot files${RESET}"
52
53
  echo -e " ${DIM}\$${RESET} eagle-mem search --stats ${DIM}# project stats${RESET}"
54
+ echo -e " ${DIM}\$${RESET} eagle-mem session save --summary \"fixed auth\""
53
55
  echo ""
54
56
  echo -e " ${BOLD}Anti-regression:${RESET}"
55
57
  echo -e " ${DIM}\$${RESET} eagle-mem feature pending ${DIM}# pending release blockers${RESET}"
@@ -81,12 +81,19 @@ fi
81
81
 
82
82
  # FTS5 support
83
83
  if command -v sqlite3 &>/dev/null; then
84
- if sqlite3 :memory: "SELECT sqlite_compileoption_used('ENABLE_FTS5');" 2>/dev/null | grep -q "1"; then
85
- eagle_ok "FTS5 support"
84
+ sqlite_path=$(eagle_sqlite_path)
85
+ if eagle_sqlite_supports_fts5; then
86
+ eagle_ok "FTS5 support ${DIM}($sqlite_path)${RESET}"
86
87
  else
87
88
  eagle_fail "SQLite was compiled without FTS5 support"
88
- eagle_dim "On macOS: brew install sqlite3 (system sqlite3 includes FTS5)"
89
- eagle_dim "On Linux: install libsqlite3-dev or rebuild with --enable-fts5"
89
+ eagle_dim "Detected sqlite3: $sqlite_path"
90
+ sqlite_version=$(eagle_sqlite_version)
91
+ [ -n "$sqlite_version" ] && eagle_dim "SQLite version: $sqlite_version"
92
+ eagle_dim "Run: command -v sqlite3"
93
+ eagle_dim "Fix PATH so an FTS5-capable sqlite3 is first."
94
+ eagle_dim "macOS: /usr/bin/sqlite3 usually has FTS5; move Android SDK platform-tools later if it shadows sqlite3."
95
+ eagle_dim "Homebrew: brew install sqlite, then prepend /opt/homebrew/opt/sqlite/bin or /usr/local/opt/sqlite/bin."
96
+ eagle_dim "Linux: install a sqlite3 package compiled with ENABLE_FTS5."
90
97
  prereqs_ok=false
91
98
  fi
92
99
  fi
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env bash
2
+ # ═══════════════════════════════════════════════════════════
3
+ # Eagle Mem — Manual session capture
4
+ # ═══════════════════════════════════════════════════════════
5
+ set -euo pipefail
6
+
7
+ SCRIPTS_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ LIB_DIR="$SCRIPTS_DIR/../lib"
9
+
10
+ . "$SCRIPTS_DIR/style.sh"
11
+ . "$LIB_DIR/common.sh"
12
+ . "$LIB_DIR/db.sh"
13
+
14
+ show_help() {
15
+ echo -e " ${BOLD}eagle-mem session${RESET} — Save or inspect session records"
16
+ echo ""
17
+ echo -e " ${BOLD}Usage:${RESET}"
18
+ echo -e " eagle-mem session ${CYAN}save --summary <text>${RESET}"
19
+ echo -e " eagle-mem session ${CYAN}save <text>${RESET}"
20
+ echo ""
21
+ echo -e " ${BOLD}Options for save:${RESET}"
22
+ echo -e " ${CYAN}--summary${RESET} <text> Summary to store"
23
+ echo -e " ${CYAN}--request${RESET} <text> User request that caused the work"
24
+ echo -e " ${CYAN}--learned${RESET} <text> Non-obvious discoveries"
25
+ echo -e " ${CYAN}--decisions${RESET} <text> Decisions and why"
26
+ echo -e " ${CYAN}--gotchas${RESET} <text> Surprises or pitfalls"
27
+ echo -e " ${CYAN}--next-steps${RESET} <text> Follow-up work"
28
+ echo -e " ${CYAN}--key-files${RESET} <text> Important files"
29
+ echo -e " ${CYAN}--notes${RESET} <text> Extra notes"
30
+ echo -e " ${CYAN}-p, --project${RESET} <name> Project name (default: current git root)"
31
+ echo -e " ${CYAN}--agent${RESET} <name> Source agent: codex or claude-code"
32
+ echo -e " ${CYAN}--cwd${RESET} <path> Working directory for project detection"
33
+ echo -e " ${CYAN}--json${RESET} Output JSON"
34
+ echo ""
35
+ echo -e " ${DIM}This command is mainly for agent fallbacks. Normal sessions are captured${RESET}"
36
+ echo -e " ${DIM}automatically by hooks when Claude Code or Codex stops a turn.${RESET}"
37
+ echo ""
38
+ }
39
+
40
+ require_value() {
41
+ local flag="$1"
42
+ if [ $# -lt 2 ] || [ -z "${2:-}" ]; then
43
+ eagle_err "$flag requires a value"
44
+ exit 1
45
+ fi
46
+ }
47
+
48
+ json_string() {
49
+ jq -Rn --arg v "${1:-}" '$v'
50
+ }
51
+
52
+ save_session() {
53
+ local summary=""
54
+ local request="Manual session save"
55
+ local learned=""
56
+ local decisions=""
57
+ local gotchas=""
58
+ local next_steps=""
59
+ local key_files=""
60
+ local notes=""
61
+ local project=""
62
+ local cwd
63
+ cwd="$(pwd)"
64
+ local agent=""
65
+ local json_output=false
66
+
67
+ while [ $# -gt 0 ]; do
68
+ case "$1" in
69
+ --summary)
70
+ require_value "$1" "${2:-}"
71
+ summary="$2"
72
+ shift 2
73
+ ;;
74
+ --request)
75
+ require_value "$1" "${2:-}"
76
+ request="$2"
77
+ shift 2
78
+ ;;
79
+ --learned)
80
+ require_value "$1" "${2:-}"
81
+ learned="$2"
82
+ shift 2
83
+ ;;
84
+ --decisions)
85
+ require_value "$1" "${2:-}"
86
+ decisions="$2"
87
+ shift 2
88
+ ;;
89
+ --gotchas)
90
+ require_value "$1" "${2:-}"
91
+ gotchas="$2"
92
+ shift 2
93
+ ;;
94
+ --next-steps)
95
+ require_value "$1" "${2:-}"
96
+ next_steps="$2"
97
+ shift 2
98
+ ;;
99
+ --key-files)
100
+ require_value "$1" "${2:-}"
101
+ key_files="$2"
102
+ shift 2
103
+ ;;
104
+ --notes)
105
+ require_value "$1" "${2:-}"
106
+ notes="$2"
107
+ shift 2
108
+ ;;
109
+ --project|-p)
110
+ require_value "$1" "${2:-}"
111
+ project="$2"
112
+ shift 2
113
+ ;;
114
+ --cwd)
115
+ require_value "$1" "${2:-}"
116
+ cwd="$2"
117
+ shift 2
118
+ ;;
119
+ --agent)
120
+ require_value "$1" "${2:-}"
121
+ agent="$2"
122
+ shift 2
123
+ ;;
124
+ --json|-j)
125
+ json_output=true
126
+ shift
127
+ ;;
128
+ --help|-h)
129
+ show_help
130
+ exit 0
131
+ ;;
132
+ --)
133
+ shift
134
+ if [ $# -gt 0 ]; then
135
+ summary="${summary}${summary:+ }$*"
136
+ shift $#
137
+ fi
138
+ ;;
139
+ -*)
140
+ eagle_err "Unknown option for session save: $1"
141
+ exit 1
142
+ ;;
143
+ *)
144
+ summary="${summary}${summary:+ }$1"
145
+ shift
146
+ ;;
147
+ esac
148
+ done
149
+
150
+ if [ -z "$summary" ]; then
151
+ eagle_err "Nothing to save. Pass --summary <text>."
152
+ exit 1
153
+ fi
154
+
155
+ [ -z "$project" ] && project=$(eagle_project_from_cwd "$cwd")
156
+ if [ -z "$project" ]; then
157
+ eagle_err "Could not determine project. Re-run with --project <name>."
158
+ exit 1
159
+ fi
160
+
161
+ if [ -z "$agent" ]; then
162
+ agent=$(eagle_agent_source)
163
+ else
164
+ case "$agent" in
165
+ codex|openai-codex) agent="codex" ;;
166
+ claude|claude-code|cloud-code) agent="claude-code" ;;
167
+ *)
168
+ eagle_err "--agent must be codex or claude-code"
169
+ exit 1
170
+ ;;
171
+ esac
172
+ fi
173
+
174
+ summary=$(printf '%s' "$summary" | eagle_redact)
175
+ request=$(printf '%s' "$request" | eagle_redact)
176
+ learned=$(printf '%s' "$learned" | eagle_redact)
177
+ decisions=$(printf '%s' "$decisions" | eagle_redact)
178
+ gotchas=$(printf '%s' "$gotchas" | eagle_redact)
179
+ next_steps=$(printf '%s' "$next_steps" | eagle_redact)
180
+ key_files=$(printf '%s' "$key_files" | eagle_redact)
181
+ notes=$(printf '%s' "$notes" | eagle_redact)
182
+
183
+ eagle_ensure_db
184
+
185
+ local stamp session_id
186
+ stamp=$(date -u +%Y%m%dT%H%M%SZ)
187
+ session_id="manual-${stamp}-$$-${RANDOM:-0}"
188
+
189
+ eagle_upsert_session "$session_id" "$project" "$cwd" "" "manual" "$agent"
190
+ eagle_insert_summary "$session_id" "$project" "$request" "" "$learned" "$summary" "$next_steps" "[]" "[]" "$notes" "$decisions" "$gotchas" "$key_files" "$agent"
191
+ eagle_end_session "$session_id"
192
+
193
+ if [ "$json_output" = true ]; then
194
+ printf '{'
195
+ printf '"session_id":%s,' "$(json_string "$session_id")"
196
+ printf '"project":%s,' "$(json_string "$project")"
197
+ printf '"agent":%s,' "$(json_string "$agent")"
198
+ printf '"summary":%s' "$(json_string "$summary")"
199
+ printf '}\n'
200
+ else
201
+ eagle_ok "Session summary saved"
202
+ eagle_kv "Project:" "$project"
203
+ eagle_kv "Source:" "$(eagle_agent_label "$agent")"
204
+ eagle_kv "Session:" "$session_id"
205
+ fi
206
+ }
207
+
208
+ command="${1:-help}"
209
+ shift 2>/dev/null || true
210
+
211
+ case "$command" in
212
+ save) save_session "$@" ;;
213
+ help|--help|-h) show_help ;;
214
+ *)
215
+ eagle_err "Unknown session command: $command"
216
+ echo ""
217
+ show_help
218
+ exit 1
219
+ ;;
220
+ esac