eagle-mem 4.7.0 → 4.8.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.
@@ -5,6 +5,7 @@
5
5
  # Injects project memory + pending tasks into Claude's context
6
6
  # ═══════════════════════════════════════════════════════════
7
7
  set +e
8
+ [ "${EAGLE_MEM_DISABLE_HOOKS:-}" = "1" ] && exit 0
8
9
 
9
10
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
11
  LIB_DIR="$SCRIPT_DIR/../lib"
@@ -26,6 +27,8 @@ source_type=$(echo "$input" | jq -r '.source // empty')
26
27
  model=$(echo "$input" | jq -r '.model // empty')
27
28
  agent=$(eagle_agent_source_from_json "$input")
28
29
  agent_label=$(eagle_agent_label "$agent")
30
+ codex_compact=0
31
+ [ "$agent" = "codex" ] && codex_compact=1
29
32
 
30
33
  [ -z "$session_id" ] && exit 0
31
34
 
@@ -130,8 +133,7 @@ if [ "$stat_tasks_done" -gt 0 ]; then
130
133
  task_parts+="${stat_tasks_done} completed"
131
134
  fi
132
135
 
133
- stat_last_display="${stat_last_summary:0:60}"
134
- [ ${#stat_last_summary} -gt 60 ] && stat_last_display+="..."
136
+ stat_last_display=$(eagle_trim_text "$stat_last_summary" 60)
135
137
 
136
138
  eagle_banner="======================================
137
139
  Eagle Mem Recall Ready
@@ -166,13 +168,20 @@ $update_notice
166
168
  "
167
169
  fi
168
170
 
171
+ if [ "$agent" = "codex" ] && [ "${stat_with_summaries:-0}" -eq 0 ] 2>/dev/null; then
172
+ context+="
173
+ === Eagle Mem: Codex Capture Warming Up ===
174
+ Codex hooks are active. End important turns with an <eagle-summary> block so future Claude Code and Codex sessions can recall decisions, gotchas, key files, and next steps from this project.
175
+ "
176
+ fi
177
+
169
178
  # ─── Project overview (capped at 500 chars) ──────────────
170
179
 
171
180
  overview=$(eagle_get_overview "$project")
172
181
  if [ -n "$overview" ]; then
173
- if [ ${#overview} -gt 500 ]; then
174
- overview="${overview:0:497}..."
175
- fi
182
+ overview_limit=500
183
+ [ "$codex_compact" -eq 1 ] && overview_limit=320
184
+ overview=$(eagle_trim_text "$overview" "$overview_limit")
176
185
  context+="
177
186
  === Eagle Mem: Project Overview ===
178
187
  $overview
@@ -188,8 +197,10 @@ fi
188
197
 
189
198
  if [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
190
199
  _summary_limit=1
200
+ elif [ "$codex_compact" -eq 1 ]; then
201
+ _summary_limit=1
191
202
  else
192
- _summary_limit=3
203
+ _summary_limit=2
193
204
  fi
194
205
 
195
206
  recent=$(eagle_get_recent_summaries "$project" "$_summary_limit")
@@ -201,6 +212,21 @@ if [ -n "$recent" ]; then
201
212
  while IFS='|' read -r request completed learned next_steps created_at decisions gotchas key_files summary_agent; do
202
213
  [ -z "$request" ] && [ -z "$completed" ] && continue
203
214
  summary_agent_label=$(eagle_agent_label "$summary_agent")
215
+ request=$(eagle_trim_text "$request" 160)
216
+ completed=$(eagle_trim_text "$completed" 220)
217
+ learned=$(eagle_trim_text "$learned" 180)
218
+ decisions=$(eagle_trim_text "$decisions" 160)
219
+ gotchas=$(eagle_trim_text "$gotchas" 160)
220
+ key_files=$(eagle_trim_text "$key_files" 160)
221
+ next_steps=$(eagle_trim_text "$next_steps" 160)
222
+ if [ "$codex_compact" -eq 1 ]; then
223
+ request=$(eagle_trim_text "$request" 120)
224
+ completed=$(eagle_trim_text "$completed" 160)
225
+ learned=$(eagle_trim_text "$learned" 120)
226
+ decisions=""
227
+ key_files=""
228
+ next_steps=""
229
+ fi
204
230
  context+="
205
231
  --- $created_at ---"
206
232
  [ -n "$summary_agent" ] && context+="
@@ -226,12 +252,14 @@ fi
226
252
 
227
253
  # ─── Memories (skip if none) ─────────────────────────────
228
254
 
255
+ memory_limit=3
256
+ [ "$codex_compact" -eq 1 ] && memory_limit=2
229
257
  memories=$(eagle_db "SELECT memory_name, memory_type, description, file_path, updated_at, origin_agent,
230
258
  CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
231
- FROM claude_memories
259
+ FROM agent_memories
232
260
  WHERE project = '$p_esc'
233
261
  ORDER BY updated_at DESC
234
- LIMIT 5;")
262
+ LIMIT $memory_limit;")
235
263
  if [ -n "$memories" ]; then
236
264
  context+="
237
265
  === Eagle Mem: Stored Memories ===
@@ -239,6 +267,7 @@ if [ -n "$memories" ]; then
239
267
  while IFS='|' read -r mname mtype mdesc _fpath _updated morigin days_ago; do
240
268
  [ -z "$mname" ] && continue
241
269
  origin_label=$(eagle_agent_label "$morigin")
270
+ mdesc=$(eagle_trim_text "$mdesc" 180)
242
271
  age_label=""
243
272
  if [ -n "$days_ago" ] && [ "$days_ago" -gt 0 ] 2>/dev/null; then
244
273
  if [ "$days_ago" -eq 1 ]; then
@@ -256,7 +285,7 @@ fi
256
285
 
257
286
  # ─── Plans (skip if none) ────────────────────────────────
258
287
 
259
- plans=$(eagle_list_claude_plans "$project" 3)
288
+ plans=$(eagle_list_agent_plans "$project" 3)
260
289
  if [ -n "$plans" ]; then
261
290
  context+="
262
291
  === Eagle Mem: Plans ===
@@ -271,14 +300,17 @@ fi
271
300
 
272
301
  # ─── Tasks (skip if none) ────────────────────────────────
273
302
 
274
- synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM claude_tasks
303
+ task_limit=5
304
+ [ "$codex_compact" -eq 1 ] && task_limit=3
305
+ synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
275
306
  WHERE project = '$p_esc'
276
307
  AND status IN ('in_progress', 'pending')
308
+ AND source_session_id != 'orchestration'
277
309
  AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
278
310
  ORDER BY
279
311
  CASE status WHEN 'in_progress' THEN 0 ELSE 1 END,
280
312
  updated_at DESC
281
- LIMIT 10;")
313
+ LIMIT $task_limit;")
282
314
  if [ -n "$synced_tasks" ]; then
283
315
  context+="
284
316
  === Eagle Mem: Tasks ===
@@ -295,10 +327,54 @@ if [ -n "$synced_tasks" ]; then
295
327
  done <<< "$synced_tasks"
296
328
  fi
297
329
 
330
+ # ─── Orchestration lanes (skip if none) ───────────────────
331
+
332
+ lane_limit=8
333
+ [ "$codex_compact" -eq 1 ] && lane_limit=4
334
+ orchestration_lanes=$(eagle_db "SELECT o.name, o.goal, l.lane_key, l.title,
335
+ COALESCE(REPLACE(REPLACE(l.description, char(10), ' '), '|', '/'), ''),
336
+ l.agent, l.status, l.validation, l.worktree_path, l.notes
337
+ FROM orchestration_lanes l
338
+ JOIN orchestrations o ON o.id = l.orchestration_id
339
+ WHERE l.project = '$p_esc'
340
+ AND o.status = 'active'
341
+ AND l.status IN ('in_progress', 'pending', 'blocked')
342
+ ORDER BY
343
+ CASE l.status WHEN 'in_progress' THEN 0 WHEN 'blocked' THEN 1 ELSE 2 END,
344
+ l.updated_at DESC
345
+ LIMIT $lane_limit;" 2>/dev/null)
346
+ if [ -n "$orchestration_lanes" ]; then
347
+ context+="
348
+ === Eagle Mem: Orchestration Lanes ===
349
+ "
350
+ while IFS='|' read -r oname ogoal lkey ltitle ldesc lagent lstatus lvalidation lworktree lnotes; do
351
+ [ -z "$lkey" ] && continue
352
+ origin_label=$(eagle_agent_label "$lagent")
353
+ context+=" - [$lstatus][$origin_label] $lkey: $ltitle"
354
+ if [ -n "$ldesc" ]; then
355
+ desc_limit=220
356
+ [ "$codex_compact" -eq 1 ] && desc_limit=120
357
+ context+=" | scope: $(eagle_trim_text "$ldesc" "$desc_limit")"
358
+ fi
359
+ [ -n "$oname" ] && context+=" | plan: $oname"
360
+ [ -n "$lvalidation" ] && context+=" | validate: $lvalidation"
361
+ [ -n "$lworktree" ] && context+=" | worktree: $lworktree"
362
+ [ -n "$lnotes" ] && context+=" | notes: $lnotes"
363
+ context+="
364
+ "
365
+ done <<< "$orchestration_lanes"
366
+ context+="You, the active agent, must run 'eagle-mem orchestrate' before taking lane work. Do not ask the user to run these commands. Update lane status when work starts, blocks, or completes.
367
+ "
368
+ fi
369
+
298
370
  # ─── Pending feature verifications ───────────────────────
299
371
 
300
- pending_features=$(eagle_list_pending_feature_verifications "$project" 10 2>/dev/null)
372
+ pending_limit=5
373
+ [ "$codex_compact" -eq 1 ] && pending_limit=3
374
+ pending_features=$(eagle_list_pending_feature_verifications "$project" "$pending_limit" 2>/dev/null)
301
375
  if [ -n "$pending_features" ]; then
376
+ pending_total=$(eagle_db "SELECT COUNT(*) FROM pending_feature_verifications WHERE project = '$p_esc' AND status = 'pending';" 2>/dev/null)
377
+ pending_total=${pending_total:-0}
302
378
  context+="
303
379
  === Eagle Mem: Pending Feature Verification ===
304
380
  Release-boundary commands are blocked until these are verified or waived.
@@ -313,6 +389,10 @@ Release-boundary commands are blocked until these are verified or waived.
313
389
  context+="
314
390
  "
315
391
  done <<< "$pending_features"
392
+ if [ "$pending_total" -gt "$pending_limit" ] 2>/dev/null; then
393
+ context+=" - ... $((pending_total - pending_limit)) more pending; run: eagle-mem feature pending
394
+ "
395
+ fi
316
396
  context+="Resolve with: eagle-mem feature verify <name> --notes \"what passed\"; or eagle-mem feature waive <id> --reason \"why safe\".
317
397
  "
318
398
  fi
@@ -326,9 +406,14 @@ if [ -n "$hot_files" ]; then
326
406
  Frequently read — re-read sparingly if unchanged.
327
407
  "
328
408
  IFS=',' read -ra hf_arr <<< "$hot_files"
409
+ hf_count=0
410
+ hot_file_limit=8
411
+ [ "$codex_compact" -eq 1 ] && hot_file_limit=5
329
412
  for hf in "${hf_arr[@]}"; do
413
+ [ "$hf_count" -ge "$hot_file_limit" ] && break
330
414
  [ -n "$hf" ] && context+=" - $(basename "$hf")
331
415
  "
416
+ hf_count=$((hf_count + 1))
332
417
  done
333
418
  fi
334
419
 
@@ -351,7 +436,12 @@ fi
351
436
 
352
437
  # ─── Instructions (compressed) ───────────────────────────
353
438
 
354
- if [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
439
+ if [ "$agent" = "codex" ]; then
440
+ context+="
441
+ === Eagle Mem: Active ===
442
+ Memory active for '$project'. Emit <eagle-summary> in final responses with request, completed, learned, decisions, gotchas, next_steps, key_files, files_read, files_modified, affected_features, verified_features, and regression_risks.
443
+ "
444
+ elif [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
355
445
  context+="
356
446
  === Eagle Mem: Active ===
357
447
  Memory active. Attribute recalled context to Eagle Mem. Do not revert PostToolUse-surfaced decisions without asking. Emit <eagle-summary> before final response.
package/hooks/stop.sh CHANGED
@@ -7,6 +7,7 @@
7
7
  # LLM enrichment fills in decisions/gotchas/key_files
8
8
  # ═══════════════════════════════════════════════════════════
9
9
  set +e
10
+ [ "${EAGLE_MEM_DISABLE_HOOKS:-}" = "1" ] && exit 0
10
11
 
11
12
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
13
  LIB_DIR="$SCRIPT_DIR/../lib"
@@ -56,14 +57,22 @@ request=""
56
57
  heuristic_reads=""
57
58
  heuristic_writes=""
58
59
 
59
- if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
60
- request=$(jq -r 'select(.type == "user") | .message.content | if type == "string" then . elif type == "array" then [.[] | select(.type == "text") | .text] | join(" ") else "" end' "$transcript_path" 2>/dev/null \
61
- | grep -v '<local-command-caveat>' \
60
+ eagle_clean_request_candidates() {
61
+ grep -v '<local-command-caveat>' \
62
62
  | grep -v '<system-reminder>' \
63
63
  | grep -v '<command-name>' \
64
64
  | grep -v '<command-message>' \
65
65
  | grep -v '^\[{' \
66
- | head -1 | cut -c1-500)
66
+ | grep -v '^# AGENTS.md instructions' \
67
+ | grep -v '^<environment_context>' \
68
+ | awk 'NF' \
69
+ | tail -1 \
70
+ | cut -c1-500
71
+ }
72
+
73
+ if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
74
+ request=$(jq -r 'select(.type == "user") | .message.content | if type == "string" then . elif type == "array" then [.[] | select(.type == "text") | .text] | join(" ") else "" end' "$transcript_path" 2>/dev/null \
75
+ | eagle_clean_request_candidates)
67
76
 
68
77
  if [ -z "$request" ]; then
69
78
  request=$(jq -r '
@@ -73,19 +82,12 @@ if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then
73
82
  elif type == "array" then [.[]? | select(.type == "input_text" or .type == "text") | .text] | join(" ")
74
83
  else "" end
75
84
  ' "$transcript_path" 2>/dev/null \
76
- | grep -v '<local-command-caveat>' \
77
- | grep -v '<system-reminder>' \
78
- | grep -v '<command-name>' \
79
- | grep -v '<command-message>' \
80
- | grep -v '^\[{' \
81
- | head -1 | cut -c1-500)
85
+ | eagle_clean_request_candidates)
82
86
  fi
83
87
 
84
88
  if [ -z "$request" ]; then
85
89
  request=$(jq -r 'select(.type == "event_msg" and .payload.type == "user_message") | .payload.message // empty' "$transcript_path" 2>/dev/null \
86
- | grep -v '<local-command-caveat>' \
87
- | grep -v '<system-reminder>' \
88
- | head -1 | cut -c1-500)
90
+ | eagle_clean_request_candidates)
89
91
  fi
90
92
 
91
93
  heuristic_reads=$(jq -r 'select(.type == "assistant") | .message.content[]? | select(.type == "tool_use") | select(.name == "Read") | .input.file_path // empty' "$transcript_path" 2>/dev/null | sort -u | head -20)
@@ -5,6 +5,7 @@
5
5
  # Searches memory for relevant context and injects it
6
6
  # ═══════════════════════════════════════════════════════════
7
7
  set +e
8
+ [ "${EAGLE_MEM_DISABLE_HOOKS:-}" = "1" ] && exit 0
8
9
 
9
10
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
10
11
  LIB_DIR="$SCRIPT_DIR/../lib"
@@ -25,6 +26,8 @@ agent=$(eagle_agent_source_from_json "$input")
25
26
  [ -z "$user_prompt" ] && exit 0
26
27
 
27
28
  project=$(eagle_project_from_cwd "$cwd")
29
+ codex_compact=0
30
+ [ "$agent" = "codex" ] && codex_compact=1
28
31
 
29
32
  # ─── Context pressure detection (turn counter since last compact) ──
30
33
  # Must run before any early exits so every prompt is counted
@@ -84,8 +87,37 @@ if [ -z "$fts_query" ]; then
84
87
  exit 0
85
88
  fi
86
89
 
90
+ # ─── Agent-run orchestration nudge ────────────────────────
91
+
92
+ lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
93
+ 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
94
+ if [ "$codex_compact" -eq 1 ]; then
95
+ context+="=== Eagle Mem: Orchestration Protocol ===
96
+ For broad work, you run eagle-mem orchestrate yourself. Use durable lanes, opposite-agent workers, and concise user-visible status.
97
+ "
98
+ else
99
+ context+="=== Eagle Mem: Orchestration Protocol ===
100
+ If this request is broad enough to split into worker lanes, YOU run the orchestration commands. Do not ask the user to run them.
101
+
102
+ Use:
103
+ eagle-mem orchestrate init \"<goal>\"
104
+ eagle-mem orchestrate lane add <key> --agent codex|claude-code --desc \"<self-contained scope>\" --validate \"<command>\"
105
+ eagle-mem orchestrate lane start|block|complete <key>
106
+
107
+ Keep this mostly invisible to the user; surface only concise status or handoff when useful.
108
+ "
109
+ fi
110
+ fi
111
+
87
112
  # Search for relevant past summaries (cross-session)
88
- results=$(eagle_search_summaries "$fts_query" "$project" 3)
113
+ summary_limit=2
114
+ code_limit=3
115
+ if [ "$codex_compact" -eq 1 ]; then
116
+ summary_limit=1
117
+ code_limit=2
118
+ fi
119
+
120
+ results=$(eagle_search_summaries "$fts_query" "$project" "$summary_limit")
89
121
 
90
122
  if [ -n "$results" ]; then
91
123
  context+="=== Eagle Mem: Relevant Recall ===
@@ -93,25 +125,46 @@ if [ -n "$results" ]; then
93
125
  while IFS='|' read -r req completed learned _next_steps created_at _proj decisions gotchas key_files summary_agent; do
94
126
  [ -z "$req" ] && [ -z "$completed" ] && continue
95
127
  origin_label=$(eagle_agent_label "$summary_agent")
96
- context+="[$created_at][$origin_label] "
97
- [ -n "$req" ] && context+="$req"
98
- [ -n "$completed" ] && context+=" → $completed"
99
- [ -n "$learned" ] && context+=" (Learned: $learned)"
100
- [ -n "$decisions" ] && context+="
128
+ if [ "$codex_compact" -eq 1 ]; then
129
+ req=$(eagle_trim_text "$req" 90)
130
+ completed=$(eagle_trim_text "$completed" 150)
131
+ learned=$(eagle_trim_text "$learned" 110)
132
+ context+="- [$origin_label] "
133
+ if [ -n "$completed" ]; then
134
+ context+="$completed"
135
+ else
136
+ context+="$req"
137
+ fi
138
+ [ -n "$learned" ] && context+=" | learned: $learned"
139
+ context+="
140
+ "
141
+ else
142
+ req=$(eagle_trim_text "$req" 160)
143
+ completed=$(eagle_trim_text "$completed" 220)
144
+ learned=$(eagle_trim_text "$learned" 180)
145
+ decisions=$(eagle_trim_text "$decisions" 160)
146
+ gotchas=$(eagle_trim_text "$gotchas" 160)
147
+ key_files=$(eagle_trim_text "$key_files" 160)
148
+ context+="[$created_at][$origin_label] "
149
+ [ -n "$req" ] && context+="$req"
150
+ [ -n "$completed" ] && context+=" → $completed"
151
+ [ -n "$learned" ] && context+=" (Learned: $learned)"
152
+ [ -n "$decisions" ] && context+="
101
153
  Decisions: $decisions"
102
- [ -n "$gotchas" ] && context+="
154
+ [ -n "$gotchas" ] && context+="
103
155
  Gotchas: $gotchas"
104
- [ -n "$key_files" ] && context+="
156
+ [ -n "$key_files" ] && context+="
105
157
  Key files: $key_files"
106
- context+="
158
+ context+="
107
159
  "
160
+ fi
108
161
  done <<< "$results"
109
162
  fi
110
163
 
111
164
  # Search indexed code chunks (if any exist for this project)
112
165
  has_chunks=$(eagle_count_code_chunks "$project")
113
166
  if [ "${has_chunks:-0}" -gt 0 ]; then
114
- code_results=$(eagle_search_code_chunks "$fts_query" "$project" 5)
167
+ code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
115
168
 
116
169
  if [ -n "$code_results" ]; then
117
170
  context+="=== Eagle Mem: Relevant Code ===
@@ -128,11 +181,17 @@ fi
128
181
 
129
182
  [ -z "$context" ] && exit 0
130
183
 
131
- context+="
132
- IMPORTANT: When Eagle Mem finds relevant memories or code for the user's prompt, briefly mention it at the start of your response: \"Eagle Mem recalled N relevant sessions\" or \"Eagle Mem found related code in [files]\". One line max — then proceed with the answer.
184
+ if [ "$codex_compact" -eq 1 ]; then
185
+ context+="
186
+ Use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
187
+ "
188
+ else
189
+ context+="
190
+ IMPORTANT: If directly useful, start with one short Eagle Mem attribution line, then proceed.
133
191
 
134
192
  === Eagle Mem: Persistent Memory ===
135
193
  "
194
+ fi
136
195
 
137
196
  eagle_emit_context_for_agent "$agent" "UserPromptSubmit" "$context"
138
197
  exit 0
package/lib/common.sh CHANGED
@@ -16,6 +16,8 @@ EAGLE_CODEX_DIR="${EAGLE_CODEX_DIR:-$HOME/.codex}"
16
16
  EAGLE_CODEX_CONFIG="${EAGLE_CODEX_CONFIG:-$EAGLE_CODEX_DIR/config.toml}"
17
17
  EAGLE_CODEX_HOOKS="${EAGLE_CODEX_HOOKS:-$EAGLE_CODEX_DIR/hooks.json}"
18
18
  EAGLE_CODEX_AGENTS_MD="${EAGLE_CODEX_AGENTS_MD:-$EAGLE_CODEX_DIR/AGENTS.md}"
19
+ EAGLE_CODEX_SKILLS_DIR="${EAGLE_CODEX_SKILLS_DIR:-$EAGLE_CODEX_DIR/skills}"
20
+ EAGLE_CODEX_MEMORIES_DIR="${EAGLE_CODEX_MEMORIES_DIR:-$EAGLE_CODEX_DIR/memories}"
19
21
  EAGLE_RAW_BASH_UNLOCK="${EAGLE_RAW_BASH_UNLOCK:-/tmp/eagle-mem-raw-bash-unlock}"
20
22
 
21
23
  eagle_log() {
@@ -29,6 +31,11 @@ eagle_log() {
29
31
  }
30
32
 
31
33
  eagle_project_from_cwd() {
34
+ if [ -n "${EAGLE_MEM_PROJECT:-}" ]; then
35
+ echo "$EAGLE_MEM_PROJECT"
36
+ return
37
+ fi
38
+
32
39
  local cwd="${1:-$(pwd)}"
33
40
  local resolved="$cwd"
34
41
 
@@ -111,7 +118,13 @@ eagle_agent_source() {
111
118
  case "$agent" in
112
119
  codex|openai-codex) echo "codex" ;;
113
120
  claude|claude-code|cloud-code) echo "claude-code" ;;
114
- *) echo "claude-code" ;;
121
+ *)
122
+ if [ -n "${CODEX_THREAD_ID:-}" ] || [ -n "${CODEX_CI:-}" ] || [ -n "${CODEX_MANAGED_BY_NPM:-}" ]; then
123
+ echo "codex"
124
+ else
125
+ echo "claude-code"
126
+ fi
127
+ ;;
115
128
  esac
116
129
  }
117
130
 
@@ -145,6 +158,22 @@ eagle_agent_label() {
145
158
  esac
146
159
  }
147
160
 
161
+ eagle_trim_text() {
162
+ local text="${1:-}"
163
+ local max="${2:-240}"
164
+
165
+ text=$(printf '%s' "$text" | tr '\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//')
166
+ if [ "${#text}" -gt "$max" ] 2>/dev/null; then
167
+ if [ "$max" -gt 3 ] 2>/dev/null; then
168
+ printf '%s...' "${text:0:$((max - 3))}"
169
+ else
170
+ printf '%s' "${text:0:$max}"
171
+ fi
172
+ else
173
+ printf '%s' "$text"
174
+ fi
175
+ }
176
+
148
177
  eagle_is_shell_tool() {
149
178
  case "${1:-}" in
150
179
  Bash|exec_command|shell_command|unified_exec) return 0 ;;
@@ -188,8 +217,124 @@ eagle_emit_context_for_agent() {
188
217
  printf '%s\n' "$context"
189
218
  }
190
219
 
220
+ eagle_config_get_light() {
221
+ local section="$1"
222
+ local key="$2"
223
+ local default="${3:-}"
224
+ local cfg="${EAGLE_CONFIG_FILE:-$EAGLE_MEM_DIR/config.toml}"
225
+
226
+ if [ ! -f "$cfg" ]; then
227
+ echo "$default"
228
+ return
229
+ fi
230
+
231
+ local value
232
+ value=$(awk -v section="$section" -v key="$key" '
233
+ /^[[:space:]]*\[/ {
234
+ gsub(/[\[\][:space:]]/, "")
235
+ current = $0
236
+ }
237
+ current == section && /^[[:space:]]*[^#\[]/ {
238
+ split($0, parts, "=")
239
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", parts[1])
240
+ if (parts[1] == key) {
241
+ val = substr($0, index($0, "=") + 1)
242
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", val)
243
+ gsub(/^["'"'"']|["'"'"']$/, "", val)
244
+ print val
245
+ exit
246
+ }
247
+ }
248
+ ' "$cfg")
249
+
250
+ if [ -n "$value" ]; then
251
+ echo "$value"
252
+ else
253
+ echo "$default"
254
+ fi
255
+ }
256
+
257
+ eagle_token_guard_rtk_mode() {
258
+ if declare -F eagle_config_get >/dev/null 2>&1; then
259
+ eagle_config_get "token_guard" "rtk" "auto"
260
+ else
261
+ eagle_config_get_light "token_guard" "rtk" "auto"
262
+ fi
263
+ }
264
+
265
+ eagle_token_guard_raw_bash_mode() {
266
+ if declare -F eagle_config_get >/dev/null 2>&1; then
267
+ eagle_config_get "token_guard" "raw_bash" "block"
268
+ else
269
+ eagle_config_get_light "token_guard" "raw_bash" "block"
270
+ fi
271
+ }
272
+
273
+ eagle_raw_output_command_needs_guard() {
274
+ local cmd="$1"
275
+ local first
276
+ first=$(printf '%s\n' "$cmd" | awk 'NR == 1 {print $1}' | sed 's|.*/||')
277
+
278
+ case "$first" in
279
+ cat|head|tail|find|grep|rg|wc) return 0 ;;
280
+ esac
281
+
282
+ if printf '%s\n' "$cmd" \
283
+ | tr '\n' ';' \
284
+ | sed -E 's/(&&|[|][|]|;)/\
285
+ /g' \
286
+ | awk '
287
+ {
288
+ for (i = 1; i <= NF; i++) {
289
+ token = $i
290
+ sub(/^.*\//, "", token)
291
+ if (token ~ /^(cat|head|tail|find|grep|rg|wc)$/) found = 1
292
+ }
293
+ }
294
+ END { exit(found ? 0 : 1) }
295
+ '
296
+ then
297
+ return 0
298
+ fi
299
+
300
+ if printf '%s\n' "$cmd" \
301
+ | tr '\n' ';' \
302
+ | sed -E 's/(&&|[|][|]|;)/\
303
+ /g' \
304
+ | awk '
305
+ {
306
+ for (i = 1; i <= NF; i++) {
307
+ if ($i !~ /(^|\/)git$/) continue
308
+ j = i + 1
309
+ while (j <= NF && $j ~ /^-/) {
310
+ opt = $j
311
+ j++
312
+ if (opt == "-C" || opt == "-c" ||
313
+ opt == "--git-dir" || opt == "--work-tree" ||
314
+ opt == "--namespace" || opt == "--exec-path" ||
315
+ opt == "--config-env" || opt == "--super-prefix") {
316
+ j++
317
+ }
318
+ }
319
+ if ($j ~ /^(diff|show|log|blame|grep)$/) found = 1
320
+ }
321
+ }
322
+ END { exit(found ? 0 : 1) }
323
+ '
324
+ then
325
+ return 0
326
+ fi
327
+
328
+ if printf '%s\n' "$cmd" | grep -qE '\|\s*(head|tail|grep|rg|wc)\b'; then
329
+ return 0
330
+ fi
331
+
332
+ return 1
333
+ }
334
+
191
335
  eagle_rtk_rewrite_command() {
192
336
  local cmd="$1"
337
+ [ "$(eagle_token_guard_rtk_mode)" = "off" ] && return 1
193
338
  command -v rtk >/dev/null 2>&1 || return 1
194
339
 
195
340
  case "$cmd" in
@@ -462,7 +607,7 @@ _eagle_claude_md_section() {
462
607
 
463
608
  ## Eagle Mem — Persistent Memory
464
609
 
465
- Eagle Mem hooks are active in every project. SessionStart injects context (overview, recent sessions, memories, tasks, core files). Stop captures session summaries. PostToolUse mirrors memories/plans/tasks.
610
+ Eagle Mem hooks are active in every project. SessionStart injects context (overview, recent sessions, memories, tasks, orchestration lanes, core files). Stop captures session summaries. PostToolUse mirrors memories/plans/tasks.
466
611
 
467
612
  **Rule:** Before your final response in every session, emit an `<eagle-summary>` block so the Stop hook can capture a rich summary instead of just heuristics.
468
613
 
@@ -490,6 +635,7 @@ regression_risks: [risk, ...]
490
635
  - When Eagle Mem injects context at SessionStart, attribute it: "Eagle Mem recalls:"
491
636
  - Do not revert decisions surfaced by PostToolUse without asking the user
492
637
  - If Eagle Mem reports pending feature verification, verify or waive it before push/PR/publish
638
+ - For broad multi-agent work, YOU run `eagle-mem orchestrate`; do not ask the user to run these commands
493
639
  - Never put raw secrets in the summary — Eagle Mem redacts but defense in depth
494
640
  - If you contradict a loaded memory, update the memory file
495
641
  EAGLE_MD
@@ -520,6 +666,17 @@ eagle_patch_claude_md() {
520
666
  _eagle_claude_md_section >> "$claude_md"
521
667
  return 0
522
668
  fi
669
+ if ! grep -qF 'eagle-mem orchestrate' "$claude_md" 2>/dev/null; then
670
+ local tmp_md
671
+ tmp_md=$(mktemp)
672
+ awk '
673
+ { print }
674
+ /pending feature verification/ {
675
+ print "- For broad multi-agent work, YOU run `eagle-mem orchestrate`; do not ask the user to run these commands"
676
+ }
677
+ ' "$claude_md" > "$tmp_md" && mv "$tmp_md" "$claude_md"
678
+ return 0
679
+ fi
523
680
  return 1
524
681
  fi
525
682
 
@@ -556,6 +713,9 @@ regression_risks: [risk, ...]
556
713
 
557
714
  **How to apply:**
558
715
  - Attribute recalled context as "Eagle Mem recalls:" when it is injected
716
+ - Use the Eagle Mem skills when relevant: `eagle-mem-search`, `eagle-mem-overview`, `eagle-mem-memories`, `eagle-mem-tasks`, and `eagle-mem-orchestrate`
717
+ - For broad multi-agent work, YOU run `eagle-mem orchestrate`; do not ask the user to run these commands
718
+ - For important decisions, preferences, gotchas, or durable project facts, explicitly include them in the `<eagle-summary>` block so Codex-originated memories become available to future Claude Code and Codex sessions
559
719
  - Do not revert Eagle Mem-surfaced decisions without asking the user
560
720
  - If Eagle Mem reports pending feature verification, verify or waive it before push/PR/publish
561
721
  - Never put raw secrets in summaries
@@ -569,6 +729,17 @@ eagle_patch_codex_agents_md() {
569
729
  mkdir -p "$(dirname "$agents_md")"
570
730
 
571
731
  if [ -f "$agents_md" ] && grep -qF "$marker" "$agents_md" 2>/dev/null; then
732
+ if ! grep -qF 'eagle-mem orchestrate' "$agents_md" 2>/dev/null; then
733
+ local tmp_md
734
+ tmp_md=$(mktemp)
735
+ awk '
736
+ { print }
737
+ /eagle-mem-tasks/ {
738
+ print "- Use the `eagle-mem-orchestrate` skill for broad multi-agent work. YOU run `eagle-mem orchestrate`; do not ask the user to run these commands"
739
+ }
740
+ ' "$agents_md" > "$tmp_md" && mv "$tmp_md" "$agents_md"
741
+ return 0
742
+ fi
572
743
  return 1
573
744
  fi
574
745
 
@@ -65,9 +65,9 @@ eagle_backfill_projects() {
65
65
  ch=$(eagle_db_pipe <<SQL
66
66
  BEGIN;
67
67
  UPDATE sessions SET project = '$proj_sql' WHERE id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
68
- UPDATE claude_tasks SET project = '$proj_sql' WHERE source_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
69
- UPDATE claude_memories SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
70
- UPDATE claude_plans SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
68
+ UPDATE agent_tasks SET project = '$proj_sql' WHERE source_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
69
+ UPDATE agent_memories SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
70
+ UPDATE agent_plans SET project = '$proj_sql' WHERE origin_session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
71
71
  UPDATE summaries SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
72
72
  UPDATE observations SET project = '$proj_sql' WHERE session_id = '$sid_sql' AND (project = '' OR project != '$proj_sql');
73
73
  SELECT total_changes();