eagle-mem 4.9.6 → 4.9.7

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/bin/eagle-mem CHANGED
@@ -21,6 +21,7 @@ case "$command" in
21
21
  uninstall) bash "$SCRIPTS_DIR/uninstall.sh" "$@" ;;
22
22
  search) bash "$SCRIPTS_DIR/search.sh" "$@" ;;
23
23
  health) bash "$SCRIPTS_DIR/health.sh" "$@" ;;
24
+ doctor) bash "$SCRIPTS_DIR/doctor.sh" "$PACKAGE_DIR" "$@" ;;
24
25
  config) bash "$SCRIPTS_DIR/config.sh" "$@" ;;
25
26
  updates) bash "$SCRIPTS_DIR/updates.sh" "$@" ;;
26
27
  statusline) "$SCRIPTS_DIR/statusline-em.sh" "$@" ;;
package/db/migrate.sh CHANGED
@@ -44,7 +44,18 @@ run_migration() {
44
44
 
45
45
  # Set connection PRAGMAs, then run migration body + tracking insert atomically
46
46
  # .bail on ensures sqlite3 stops on the first error instead of continuing
47
- { echo ".bail on"; echo "PRAGMA trusted_schema=ON;"; echo "PRAGMA foreign_keys=ON;"; echo "PRAGMA busy_timeout=5000;"; echo "BEGIN;"; echo "$body"; echo "INSERT INTO _migrations (name) VALUES ('$name');"; echo "COMMIT;"; } | "$SQLITE_BIN" "$DB"
47
+ {
48
+ echo ".bail on"
49
+ echo ".output /dev/null"
50
+ echo "PRAGMA trusted_schema=ON;"
51
+ echo "PRAGMA foreign_keys=ON;"
52
+ echo "PRAGMA busy_timeout=5000;"
53
+ echo ".output stdout"
54
+ echo "BEGIN;"
55
+ echo "$body"
56
+ echo "INSERT INTO _migrations (name) VALUES ('$name');"
57
+ echo "COMMIT;"
58
+ } | "$SQLITE_BIN" "$DB"
48
59
  echo " applied: $name"
49
60
  fi
50
61
  }
@@ -57,7 +68,7 @@ run_migration() {
57
68
  );"
58
69
 
59
70
  # Set PRAGMAs (these must be set on every connection)
60
- "$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;"
71
+ "$SQLITE_BIN" "$DB" "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;" >/dev/null
61
72
 
62
73
  # ─── Migration 001: Initial schema (special name) ──────────
63
74
  run_migration "001_initial_schema" "$SCRIPT_DIR/schema.sql"
@@ -0,0 +1,53 @@
1
+ # Eagle Mem Visible Surface UX Contract
2
+
3
+ Eagle Mem has two audiences for visible output:
4
+
5
+ - The user, who should see a calm product surface.
6
+ - The active agent, which needs compact operational context without raw internals.
7
+
8
+ Default output must be useful without exposing implementation details. Raw database
9
+ IDs, file paths, session IDs, backing JSON, hook payloads, and source file content
10
+ belong behind `--raw`, `--debug`, or `--json`.
11
+
12
+ ## Output Modes
13
+
14
+ | Mode | Purpose | Allowed Content |
15
+ | --- | --- | --- |
16
+ | Default | Human product UX | Brand, status, concise summaries, freshness, next action |
17
+ | `--json` | Machine-readable automation | Structured complete fields |
18
+ | `--raw` | Developer inspection | IDs, source paths, backing files, raw task JSON |
19
+ | `--debug` | Troubleshooting | Same as `--raw`, plus diagnostic hints where useful |
20
+
21
+ ## Visible Surfaces
22
+
23
+ | Surface | User Sees It? | Default Standard |
24
+ | --- | --- | --- |
25
+ | `SessionStart` | Yes, in agent transcript | Branded compact briefing: project, memory, relevant now, work state, guardrails |
26
+ | `UserPromptSubmit` | Yes, in agent transcript | `Eagle Mem recalls` with 1-2 useful bullets and relevant code |
27
+ | `PreToolUse` | Sometimes, when blocking | Calm explanation, recommended fix, one-off bypass if appropriate |
28
+ | `PostToolUse` | Sometimes, after reads/edits | Structured memory/decision/feature notes, no separator blocks for Codex |
29
+ | `statusline` | Yes | Short branded status: version, sessions, memories, turn |
30
+ | `search` | Yes | Freshness-aware results, no raw IDs in headings |
31
+ | `memories` | Yes | Project-scoped list by default, no source paths unless raw/debug |
32
+ | `tasks` | Yes | Task subject/status/source, no session/task IDs unless raw/debug |
33
+ | `feature` | Yes | Pending work grouped by action, raw diff fingerprints only when needed |
34
+ | `health` | Yes | Overall verdict first, then sectioned checks and next action |
35
+ | `install/update/uninstall` | Yes | Explain changed footprint, reversibility, backups, and success/failure plainly |
36
+ | `doctor` | Yes | Trust report: installed runtime, hooks, SQLite/FTS5, install manifest, drift, uninstall coverage |
37
+
38
+ ## Product Voice
39
+
40
+ - Use `Eagle Mem` or `Eagle`; avoid cryptic `EM` in user-facing output.
41
+ - Prefer headings like `Relevant now`, `Work state`, `Guardrail`, and `Next`.
42
+ - Prefer freshness labels like `Fresh`, `Recent`, `Older`, or `may be stale`.
43
+ - Avoid dumping raw hook payloads, XML templates, SQL results, or JSON unless the user requested raw/debug output.
44
+ - Keep Codex transcript injections more compact than Claude Code injections.
45
+
46
+ ## Install/Update/Uninstall Standard
47
+
48
+ - Before mutating user config or runtime files, show a short "What will change" plan.
49
+ - Treat `--dry-run` as a first-class product path for destructive or cleanup commands.
50
+ - Back up user-owned config files before editing `~/.claude` or `~/.codex` state.
51
+ - Preserve `~/.eagle-mem/memory.db` by default; require explicit confirmation before deleting stored memory.
52
+ - After install/update, write a manifest with runtime file metadata so `doctor` can verify drift without noisy shell dumps.
53
+ - Prefer one clear verdict first (`Healthy`, `Needs attention`, or `Broken`), then details.
@@ -200,8 +200,8 @@ esac
200
200
 
201
201
  eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project" "$agent"
202
202
  eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input" "$agent"
203
- eagle_posttool_stale_hint "$tool_name" "$fp" "$project"
204
- eagle_posttool_decision_surface "$tool_name" "$fp" "$project"
203
+ eagle_posttool_stale_hint "$tool_name" "$fp" "$project" "$agent"
204
+ eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
205
205
 
206
206
  # ─── Record observation ──────────────────────────────────
207
207
 
@@ -96,12 +96,12 @@ Pending checks:"
96
96
  rtk_cmd=$(eagle_rtk_rewrite_command "$cmd")
97
97
  if [ -n "$rtk_cmd" ]; then
98
98
  if [ "$agent" = "codex" ] && [ "$raw_bash_mode" != "allow" ] && ! eagle_raw_bash_unlock_active; then
99
- reason="Eagle Mem token guard blocked raw shell output.
99
+ reason="Eagle Mem blocked raw shell output to keep Codex context clean.
100
100
 
101
- Use RTK so large output is compact before it enters context:
101
+ Recommended compact command:
102
102
  $rtk_cmd
103
103
 
104
- Temporary escape hatch for one-off raw output:
104
+ One-off developer bypass:
105
105
  touch $EAGLE_RAW_BASH_UNLOCK"
106
106
  jq -nc --arg reason "$reason" '{
107
107
  "decision":"block",
@@ -120,15 +120,15 @@ Temporary escape hatch for one-off raw output:
120
120
  context+="Eagle Mem token guard: rewrote raw shell command through RTK to reduce context load: ${rtk_cmd}. "
121
121
  fi
122
122
  elif [ "$rtk_mode" = "enforce" ] && ! command -v rtk >/dev/null 2>&1 && eagle_raw_output_command_needs_guard "$cmd" && ! eagle_raw_bash_unlock_active; then
123
- reason="Eagle Mem token guard is set to enforce, but RTK is not installed or not on PATH.
123
+ reason="Eagle Mem blocked this command because RTK enforcement is on, but RTK is not installed or not on PATH.
124
124
 
125
125
  This command can dump raw output into agent context:
126
126
  $cmd
127
127
 
128
- Install RTK or disable enforcement:
128
+ Install RTK or switch enforcement to auto:
129
129
  eagle-mem config set token_guard.rtk auto
130
130
 
131
- Temporary escape hatch:
131
+ One-off developer bypass:
132
132
  touch $EAGLE_RAW_BASH_UNLOCK"
133
133
  jq -nc --arg reason "$reason" '{
134
134
  "decision":"block",
@@ -139,6 +139,186 @@ eagle_banner+="
139
139
  context="$eagle_banner
140
140
  "
141
141
 
142
+ if [ "$codex_compact" -eq 1 ]; then
143
+ codex_context="Eagle Mem Recall Ready
144
+ Project: $project | Agent: $agent_label
145
+ Memory: $stat_sessions sessions"
146
+ [ "$stat_with_summaries" -gt 0 ] && codex_context+=", $stat_with_summaries summarized"
147
+ [ "$stat_memories" -gt 0 ] && codex_context+=", $stat_memories memories"
148
+ [ "$stat_chunks" -gt 0 ] && codex_context+=", $stat_chunks code chunks"
149
+ codex_context+="
150
+ "
151
+
152
+ if [ -n "$update_notice" ]; then
153
+ codex_context+="
154
+ Update: $(eagle_trim_text "$update_notice" 180)
155
+ "
156
+ fi
157
+
158
+ if [ "${stat_with_summaries:-0}" -eq 0 ] 2>/dev/null; then
159
+ codex_context+="
160
+ Capture: Codex hooks are active. Eagle Mem will summarize decisions and gotchas from the transcript automatically.
161
+ "
162
+ fi
163
+
164
+ overview=$(eagle_get_overview "$project")
165
+ if [ -n "$overview" ]; then
166
+ codex_context+="
167
+ Project brief: $(eagle_trim_text "$overview" 260)
168
+ "
169
+ else
170
+ codex_context+="
171
+ Project brief: no overview yet; background scan is running.
172
+ "
173
+ fi
174
+
175
+ recent=$(eagle_get_recent_summaries "$project" 1)
176
+ if [ -n "$recent" ]; then
177
+ codex_context+="
178
+ Relevant now:
179
+ "
180
+ while IFS='|' read -r request completed learned _next_steps created_at _decisions gotchas _key_files summary_agent; do
181
+ [ -z "$request" ] && [ -z "$completed" ] && continue
182
+ summary_agent_label=$(eagle_agent_label "$summary_agent")
183
+ recent_line="$completed"
184
+ [ -z "$recent_line" ] && recent_line="$request"
185
+ codex_context+="- Recent [$summary_agent_label]: $(eagle_trim_text "$recent_line" 180)
186
+ "
187
+ [ -n "$learned" ] && codex_context+=" Learned: $(eagle_trim_text "$learned" 140)
188
+ "
189
+ [ -n "$gotchas" ] && codex_context+=" Watch: $(eagle_trim_text "$gotchas" 120)
190
+ "
191
+ done <<< "$recent"
192
+ fi
193
+
194
+ memories=$(eagle_db "SELECT memory_name, memory_type, description, origin_agent,
195
+ CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
196
+ FROM agent_memories
197
+ WHERE project = '$p_esc'
198
+ ORDER BY
199
+ CASE
200
+ WHEN lower(memory_name) LIKE 'current status%' THEN 4
201
+ WHEN memory_type IN ('feedback', 'user', 'reference') THEN 0
202
+ WHEN memory_type = 'project' THEN 1
203
+ ELSE 2
204
+ END,
205
+ updated_at DESC
206
+ LIMIT 2;")
207
+ if [ -n "$memories" ]; then
208
+ [ -z "$recent" ] && codex_context+="
209
+ Relevant now:
210
+ "
211
+ while IFS='|' read -r mname mtype mdesc morigin days_ago; do
212
+ [ -z "$mname" ] && continue
213
+ origin_label=$(eagle_agent_label "$morigin")
214
+ age_label="fresh"
215
+ if [ -n "$days_ago" ] && [ "$days_ago" -gt 14 ] 2>/dev/null; then
216
+ age_label="older"
217
+ elif [ -n "$days_ago" ] && [ "$days_ago" -gt 0 ] 2>/dev/null; then
218
+ age_label="${days_ago}d old"
219
+ fi
220
+ codex_context+="- Memory [$mtype][$origin_label][$age_label]: $mname"
221
+ [ -n "$mdesc" ] && codex_context+=" — $(eagle_trim_text "$mdesc" 120)"
222
+ codex_context+="
223
+ "
224
+ done <<< "$memories"
225
+ fi
226
+
227
+ synced_tasks=$(eagle_db "SELECT subject, status, blocked_by, origin_agent FROM agent_tasks
228
+ WHERE project = '$p_esc'
229
+ AND status IN ('in_progress', 'pending')
230
+ AND source_session_id != 'orchestration'
231
+ AND updated_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-7 days')
232
+ ORDER BY CASE status WHEN 'in_progress' THEN 0 ELSE 1 END, updated_at DESC
233
+ LIMIT 3;")
234
+ orchestration_lanes=$(eagle_db "SELECT o.name, l.lane_key, l.title, l.agent, l.status
235
+ FROM orchestration_lanes l
236
+ JOIN orchestrations o ON o.id = l.orchestration_id
237
+ WHERE l.project = '$p_esc'
238
+ AND o.status = 'active'
239
+ AND l.status IN ('in_progress', 'pending', 'blocked')
240
+ ORDER BY CASE l.status WHEN 'in_progress' THEN 0 WHEN 'blocked' THEN 1 ELSE 2 END, l.updated_at DESC
241
+ LIMIT 3;" 2>/dev/null)
242
+ if [ -n "$synced_tasks" ] || [ -n "$orchestration_lanes" ]; then
243
+ codex_context+="
244
+ Work state:
245
+ "
246
+ while IFS='|' read -r tsubject tstatus tblocked torigin; do
247
+ [ -z "$tsubject" ] && continue
248
+ origin_label=$(eagle_agent_label "$torigin")
249
+ block_marker=""
250
+ [ "$tblocked" != "[]" ] && [ -n "$tblocked" ] && block_marker=" blocked"
251
+ codex_context+="- Task [$tstatus][$origin_label$block_marker]: $(eagle_trim_text "$tsubject" 130)
252
+ "
253
+ done <<< "$synced_tasks"
254
+ while IFS='|' read -r oname lkey ltitle lagent lstatus; do
255
+ [ -z "$lkey" ] && continue
256
+ origin_label=$(eagle_agent_label "$lagent")
257
+ codex_context+="- Lane [$lstatus][$origin_label]: $lkey"
258
+ [ -n "$ltitle" ] && codex_context+=" — $(eagle_trim_text "$ltitle" 100)"
259
+ [ -n "$oname" ] && codex_context+=" ($oname)"
260
+ codex_context+="
261
+ "
262
+ done <<< "$orchestration_lanes"
263
+ [ -n "$orchestration_lanes" ] && codex_context+=" Agent rule: you update lane status with eagle-mem orchestrate; do not ask the user to run it.
264
+ "
265
+ fi
266
+
267
+ pending_features=$(eagle_list_pending_feature_verifications "$project" 3 2>/dev/null)
268
+ if [ -n "$pending_features" ]; then
269
+ codex_context+="
270
+ Guardrail:
271
+ "
272
+ while IFS='|' read -r pf_id pf_name pf_file pf_reason _pf_trigger _pf_created pf_smoke _pfingerprint; do
273
+ [ -z "$pf_id" ] && continue
274
+ codex_context+="- Pending verification #$pf_id: $pf_name"
275
+ [ -n "$pf_file" ] && codex_context+=" ($pf_file)"
276
+ [ -n "$pf_reason" ] && codex_context+=" — $(eagle_trim_text "$pf_reason" 90)"
277
+ [ -n "$pf_smoke" ] && codex_context+=" | smoke: $(eagle_trim_text "$pf_smoke" 100)"
278
+ codex_context+="
279
+ "
280
+ done <<< "$pending_features"
281
+ codex_context+=" Release commands are blocked until these are verified or waived.
282
+ "
283
+ fi
284
+
285
+ hot_files=$(eagle_get_hot_files "$project")
286
+ if [ -n "$hot_files" ]; then
287
+ core_files=""
288
+ IFS=',' read -ra hf_arr <<< "$hot_files"
289
+ hf_count=0
290
+ for hf in "${hf_arr[@]}"; do
291
+ [ "$hf_count" -ge 5 ] && break
292
+ [ -z "$hf" ] && continue
293
+ [ -n "$core_files" ] && core_files+=", "
294
+ core_files+="$(basename "$hf")"
295
+ hf_count=$((hf_count + 1))
296
+ done
297
+ [ -n "$core_files" ] && codex_context+="
298
+ Core files: $core_files
299
+ "
300
+ fi
301
+
302
+ if [ "$source_type" = "compact" ] || [ "$source_type" = "clear" ]; then
303
+ working_set=$(eagle_get_working_set "$session_id")
304
+ if [ -n "$working_set" ]; then
305
+ codex_context+="
306
+ Working set:
307
+ "
308
+ while IFS='|' read -r ws_path ws_edits; do
309
+ [ -z "$ws_path" ] && continue
310
+ codex_context+="- $(basename "$ws_path") (${ws_edits} edits)
311
+ "
312
+ done <<< "$working_set"
313
+ fi
314
+ fi
315
+
316
+ codex_context+="
317
+ Use recalled context only when relevant. Keep user-facing replies clean; do not print raw Eagle Mem internals."
318
+ eagle_emit_context_for_agent "$agent" "SessionStart" "$codex_context"
319
+ exit 0
320
+ fi
321
+
142
322
  if [ -n "$update_notice" ]; then
143
323
  context+="
144
324
  === Eagle Mem: Update Available ===
@@ -236,7 +416,14 @@ memories=$(eagle_db "SELECT memory_name, memory_type, description, file_path, up
236
416
  CAST(julianday('now') - julianday(updated_at) AS INTEGER) as days_ago
237
417
  FROM agent_memories
238
418
  WHERE project = '$p_esc'
239
- ORDER BY updated_at DESC
419
+ ORDER BY
420
+ CASE
421
+ WHEN lower(memory_name) LIKE 'current status%' THEN 4
422
+ WHEN memory_type IN ('feedback', 'user', 'reference') THEN 0
423
+ WHEN memory_type = 'project' THEN 1
424
+ ELSE 2
425
+ END,
426
+ updated_at DESC
240
427
  LIMIT $memory_limit;")
241
428
  if [ -n "$memories" ]; then
242
429
  context+="
@@ -46,8 +46,10 @@ if [ -n "$session_id" ] && eagle_validate_session_id "$session_id"; then
46
46
  if [ "$turn_count" -ge 30 ]; then
47
47
  if [ "$codex_compact" -eq 1 ]; then
48
48
  context+="
49
- === Eagle Mem: Context Pressure Critical ($turn_count turns since compact) ===
50
- Keep the next Codex reply user-clean. Do not print Eagle Mem summary capture blocks or other internals. Include a short normal handoff note if useful, then ask the user to run /compact.
49
+ Eagle Mem context pressure: critical ($turn_count turns since compact)
50
+ - Keep the next Codex reply user-clean.
51
+ - Do not print Eagle Mem summary blocks or internals.
52
+ - Add a short normal handoff note if useful, then ask the user to run /compact.
51
53
  "
52
54
  else
53
55
  context+="
@@ -60,8 +62,10 @@ Tell the user to run /compact NOW to avoid losing context.
60
62
  elif [ "$turn_count" -ge 20 ]; then
61
63
  if [ "$codex_compact" -eq 1 ]; then
62
64
  context+="
63
- === Eagle Mem: Context Pressure High ($turn_count turns since compact) ===
64
- Keep the next Codex reply clean. Do not print Eagle Mem summary capture blocks or other internals. Summarize any durable decisions in normal prose only.
65
+ Eagle Mem context pressure: high ($turn_count turns since compact)
66
+ - Keep the next Codex reply clean.
67
+ - Do not print Eagle Mem summary blocks or internals.
68
+ - Summarize durable decisions in normal prose only.
65
69
  "
66
70
  else
67
71
  context+="
@@ -106,8 +110,10 @@ fi
106
110
  lower_prompt=$(printf '%s' "$user_prompt" | tr '[:upper:]' '[:lower:]')
107
111
  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
108
112
  if [ "$codex_compact" -eq 1 ]; then
109
- context+="=== Eagle Mem: Orchestration Protocol ===
110
- For broad work, you run eagle-mem orchestrate yourself. Use durable lanes, opposite-agent workers, and concise user-visible status.
113
+ context+="
114
+ Eagle Mem orchestration:
115
+ - For broad work, you run eagle-mem orchestrate yourself.
116
+ - Use durable lanes, opposite-agent workers, and concise user-visible status.
111
117
  "
112
118
  else
113
119
  context+="=== Eagle Mem: Orchestration Protocol ===
@@ -134,8 +140,14 @@ fi
134
140
  results=$(eagle_search_summaries "$fts_query" "$project" "$summary_limit")
135
141
 
136
142
  if [ -n "$results" ]; then
137
- context+="=== Eagle Mem: Relevant Recall ===
143
+ if [ "$codex_compact" -eq 1 ]; then
144
+ context+="
145
+ Eagle Mem recalls:
138
146
  "
147
+ else
148
+ context+="=== Eagle Mem: Relevant Recall ===
149
+ "
150
+ fi
139
151
  while IFS='|' read -r req completed learned _next_steps created_at _proj decisions gotchas key_files summary_agent; do
140
152
  [ -z "$req" ] && [ -z "$completed" ] && continue
141
153
  origin_label=$(eagle_agent_label "$summary_agent")
@@ -143,13 +155,14 @@ if [ -n "$results" ]; then
143
155
  req=$(eagle_trim_text "$req" 90)
144
156
  completed=$(eagle_trim_text "$completed" 150)
145
157
  learned=$(eagle_trim_text "$learned" 110)
146
- context+="- [$origin_label] "
158
+ context+="- Recent [$origin_label]: "
147
159
  if [ -n "$completed" ]; then
148
160
  context+="$completed"
149
161
  else
150
162
  context+="$req"
151
163
  fi
152
- [ -n "$learned" ] && context+=" | learned: $learned"
164
+ [ -n "$learned" ] && context+="
165
+ Learned: $learned"
153
166
  context+="
154
167
  "
155
168
  else
@@ -181,11 +194,21 @@ if [ "${has_chunks:-0}" -gt 0 ]; then
181
194
  code_results=$(eagle_search_code_chunks "$fts_query" "$project" "$code_limit")
182
195
 
183
196
  if [ -n "$code_results" ]; then
184
- context+="=== Eagle Mem: Relevant Code ===
197
+ if [ "$codex_compact" -eq 1 ]; then
198
+ context+="
199
+ Relevant code:
200
+ "
201
+ else
202
+ context+="=== Eagle Mem: Relevant Code ===
185
203
  "
204
+ fi
186
205
  while IFS='|' read -r fpath sline eline lang; do
187
206
  [ -z "$fpath" ] && continue
188
- context+="$fpath:${sline}-${eline}"
207
+ if [ "$codex_compact" -eq 1 ]; then
208
+ context+="- $fpath:${sline}-${eline}"
209
+ else
210
+ context+="$fpath:${sline}-${eline}"
211
+ fi
189
212
  [ -n "$lang" ] && context+=" ($lang)"
190
213
  context+="
191
214
  "
@@ -197,7 +220,7 @@ fi
197
220
 
198
221
  if [ "$codex_compact" -eq 1 ]; then
199
222
  context+="
200
- Use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
223
+ Note: use only if directly useful. If you mention it to the user, keep Eagle Mem attribution to one short line.
201
224
  "
202
225
  else
203
226
  context+="