eagle-mem 4.9.8 → 4.9.9

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.
@@ -17,13 +17,10 @@ LIB_DIR="$SCRIPT_DIR/../lib"
17
17
  input=$(eagle_read_stdin)
18
18
  [ -z "$input" ] && exit 0
19
19
 
20
- session_id=$(echo "$input" | jq -r '.session_id // empty')
21
- cwd=$(echo "$input" | jq -r '.cwd // empty')
22
- tool_name=$(echo "$input" | jq -r '.tool_name // empty')
20
+ IFS=$'\x1f' read -r session_id cwd tool_name hook_event <<< \
21
+ "$(echo "$input" | jq -r '[.session_id, .cwd, .tool_name, .hook_event_name] | map(. // "") | join("")')"
23
22
  agent=$(eagle_agent_source_from_json "$input")
24
23
 
25
- hook_event=$(echo "$input" | jq -r '.hook_event_name // empty')
26
-
27
24
  if [ -z "$session_id" ]; then exit 0; fi
28
25
 
29
26
  # TaskCreated/TaskCompleted dedicated events — parse top-level fields and exit
@@ -73,7 +70,7 @@ esac
73
70
 
74
71
  # Only track relevant tools
75
72
  case "$tool_name" in
76
- Read|Write|Edit|TaskCreate|TaskUpdate|apply_patch) ;;
73
+ Read|Write|Edit|apply_patch|TaskUpdate) ;;
77
74
  *) eagle_is_shell_tool "$tool_name" || exit 0 ;;
78
75
  esac
79
76
 
@@ -153,9 +150,18 @@ case "$tool_name" in
153
150
  *) command_category="other" ;;
154
151
  esac
155
152
  ;;
156
- TaskCreate|TaskUpdate)
157
- task_subject=$(echo "$input" | jq -r '.tool_input.subject // empty')
158
- tool_summary="$tool_name: $task_subject"
153
+ TaskUpdate)
154
+ task_id=$(echo "$input" | jq -r '.tool_input.taskId // empty')
155
+ task_status=$(echo "$input" | jq -r '.tool_input.status // empty')
156
+ tool_summary="TaskUpdate: ${task_id} → ${task_status}"
157
+ if [ -n "$task_id" ] && [ -n "$task_status" ]; then
158
+ fp_sql=$(eagle_sql_escape "event://${session_id}/${task_id}")
159
+ stat_sql=$(eagle_sql_escape "$task_status")
160
+ eagle_db_pipe <<SQL
161
+ UPDATE agent_tasks SET status = '$stat_sql', updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
162
+ WHERE file_path = '$fp_sql';
163
+ SQL
164
+ fi
159
165
  ;;
160
166
  esac
161
167
 
@@ -199,7 +205,6 @@ esac
199
205
  # ─── Dispatch to extracted responsibilities ───────────────
200
206
 
201
207
  eagle_posttool_mirror_writes "$tool_name" "$fp" "$session_id" "$project" "$agent"
202
- eagle_posttool_mirror_tasks "$tool_name" "$session_id" "$project" "$input" "$agent"
203
208
  eagle_posttool_stale_hint "$tool_name" "$fp" "$project" "$agent"
204
209
  eagle_posttool_decision_surface "$tool_name" "$fp" "$project" "$agent"
205
210
 
@@ -21,7 +21,8 @@ LIB_DIR="$SCRIPT_DIR/../lib"
21
21
  input=$(eagle_read_stdin)
22
22
  [ -z "$input" ] && exit 0
23
23
 
24
- tool_name=$(echo "$input" | jq -r '.tool_name // empty')
24
+ IFS=$'\x1f' read -r tool_name session_id cwd <<< \
25
+ "$(echo "$input" | jq -r '[.tool_name, .session_id, .cwd] | map(. // "") | join("")')"
25
26
  agent=$(eagle_agent_source_from_json "$input")
26
27
 
27
28
  case "$tool_name" in
@@ -30,9 +31,6 @@ case "$tool_name" in
30
31
  esac
31
32
 
32
33
  [ ! -f "$EAGLE_MEM_DB" ] && exit 0
33
-
34
- session_id=$(echo "$input" | jq -r '.session_id // empty')
35
- cwd=$(echo "$input" | jq -r '.cwd // empty')
36
34
  project=$(eagle_project_from_hook_input "$input")
37
35
  [ -z "$project" ] && exit 0
38
36
 
@@ -77,8 +75,6 @@ Pending checks:"
77
75
  done <<< "$pending_rows"
78
76
 
79
77
  jq -nc --arg reason "$block_reason" '{
80
- "decision":"block",
81
- "reason":$reason,
82
78
  "hookSpecificOutput":{
83
79
  "hookEventName":"PreToolUse",
84
80
  "permissionDecision":"deny",
@@ -104,8 +100,6 @@ Recommended compact command:
104
100
  One-off developer bypass:
105
101
  touch $EAGLE_RAW_BASH_UNLOCK"
106
102
  jq -nc --arg reason "$reason" '{
107
- "decision":"block",
108
- "reason":$reason,
109
103
  "hookSpecificOutput":{
110
104
  "hookEventName":"PreToolUse",
111
105
  "permissionDecision":"deny",
@@ -131,8 +125,6 @@ Install RTK or switch enforcement to auto:
131
125
  One-off developer bypass:
132
126
  touch $EAGLE_RAW_BASH_UNLOCK"
133
127
  jq -nc --arg reason "$reason" '{
134
- "decision":"block",
135
- "reason":$reason,
136
128
  "hookSpecificOutput":{
137
129
  "hookEventName":"PreToolUse",
138
130
  "permissionDecision":"deny",
package/hooks/stop.sh CHANGED
@@ -21,16 +21,12 @@ eagle_ensure_db
21
21
  input=$(eagle_read_stdin)
22
22
  [ -z "$input" ] && exit 0
23
23
 
24
- session_id=$(echo "$input" | jq -r '.session_id // empty')
25
- cwd=$(echo "$input" | jq -r '.cwd // empty')
26
- transcript_path=$(echo "$input" | jq -r '.transcript_path // empty')
24
+ IFS=$'\x1f' read -r session_id cwd transcript_path agent_type <<< \
25
+ "$(echo "$input" | jq -r '[.session_id, .cwd, .transcript_path, .agent_type] | map(. // "") | join("")')"
27
26
  last_assistant_message=$(echo "$input" | jq -r '.last_assistant_message // empty')
28
27
  agent=$(eagle_agent_source_from_json "$input")
29
28
 
30
29
  [ -z "$session_id" ] && exit 0
31
-
32
- # Skip subagent contexts
33
- agent_type=$(echo "$input" | jq -r '.agent_type // empty')
34
30
  [ -n "$agent_type" ] && [ "$agent_type" != "main" ] && exit 0
35
31
 
36
32
  project=$(eagle_project_from_hook_input "$input")
@@ -18,8 +18,8 @@ LIB_DIR="$SCRIPT_DIR/../lib"
18
18
  input=$(eagle_read_stdin)
19
19
  [ -z "$input" ] && exit 0
20
20
 
21
- session_id=$(echo "$input" | jq -r '.session_id // empty')
22
- cwd=$(echo "$input" | jq -r '.cwd // empty')
21
+ IFS=$'\x1f' read -r session_id cwd <<< \
22
+ "$(echo "$input" | jq -r '[.session_id, .cwd] | map(. // "") | join("")')"
23
23
  user_prompt=$(echo "$input" | jq -r '.prompt // empty')
24
24
  agent=$(eagle_agent_source_from_json "$input")
25
25
 
package/lib/common.sh CHANGED
@@ -672,6 +672,15 @@ eagle_project_from_hook_input() {
672
672
  cwd=$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null)
673
673
  transcript_path=$(printf '%s' "$input" | jq -r '.transcript_path // empty' 2>/dev/null)
674
674
 
675
+ if [ -n "${CLAUDE_PROJECT_DIR:-}" ]; then
676
+ project=$(eagle_project_from_workspace_path "$CLAUDE_PROJECT_DIR")
677
+ if [ -n "$project" ]; then
678
+ [ -n "$session_id" ] && eagle_remember_session_project "$session_id" "$project" 1 >/dev/null 2>&1
679
+ printf '%s\n' "$project"
680
+ return
681
+ fi
682
+ fi
683
+
675
684
  workspace_project=$(printf '%s' "$input" | jq -r '.workspace.project_dir // empty' 2>/dev/null)
676
685
  if [ -n "$workspace_project" ]; then
677
686
  project=$(eagle_project_from_workspace_path "$workspace_project")
@@ -110,16 +110,16 @@ eagle_record_pending_feature_verifications() {
110
110
  local fid; fid=$(eagle_sql_int "$feature_id")
111
111
  local name_esc; name_esc=$(eagle_sql_escape "$feature_name")
112
112
 
113
- if [ -n "$change_fingerprint" ]; then
114
- already_resolved=$(eagle_db "SELECT 1 FROM pending_feature_verifications
115
- WHERE project = '$p_esc'
116
- AND feature_id = $fid
117
- AND file_path = '$fp_esc'
118
- AND change_fingerprint = '$fp_hash_esc'
119
- AND status IN ('verified', 'waived')
120
- LIMIT 1;")
121
- [ -n "$already_resolved" ] && continue
122
- fi
113
+ already_resolved=$(eagle_db "SELECT 1 FROM pending_feature_verifications
114
+ WHERE project = '$p_esc'
115
+ AND feature_id = $fid
116
+ AND file_path = '$fp_esc'
117
+ AND (
118
+ (change_fingerprint = '$fp_hash_esc' AND status = 'verified')
119
+ OR status = 'waived'
120
+ )
121
+ LIMIT 1;")
122
+ [ -n "$already_resolved" ] && continue
123
123
 
124
124
  eagle_db "INSERT INTO pending_feature_verifications
125
125
  (project, feature_id, feature_name, file_path, reason, source_session_id, trigger_tool, change_fingerprint)
@@ -33,31 +33,6 @@ eagle_posttool_mirror_writes() {
33
33
  esac
34
34
  }
35
35
 
36
- eagle_posttool_mirror_tasks() {
37
- local tool_name="$1" session_id="$2" project="$3" input="$4"
38
- local agent="${5:-$(eagle_agent_source)}"
39
-
40
- case "$tool_name" in
41
- TaskCreate|TaskUpdate)
42
- if eagle_validate_session_id "$session_id"; then
43
- local task_dir="$EAGLE_CLAUDE_TASKS_DIR/$session_id"
44
- if [ -d "$task_dir" ]; then
45
- local task_id
46
- task_id=$(echo "$input" | jq -r '.tool_input.id // empty')
47
- if [ -z "$task_id" ]; then
48
- local newest
49
- newest=$(ls -t "$task_dir"/*.json 2>/dev/null | head -1)
50
- [ -n "$newest" ] && [ -f "$newest" ] && eagle_capture_agent_task "$newest" "$session_id" "$project" "$agent"
51
- elif eagle_validate_session_id "$task_id"; then
52
- local task_json="$task_dir/$task_id.json"
53
- [ -f "$task_json" ] && eagle_capture_agent_task "$task_json" "$session_id" "$project" "$agent"
54
- fi
55
- fi
56
- fi
57
- ;;
58
- esac
59
- }
60
-
61
36
  eagle_posttool_stale_hint() {
62
37
  local tool_name="$1" fp="$2" project="$3"
63
38
  local agent="${4:-$(eagle_agent_source)}"
package/lib/hooks.sh CHANGED
@@ -4,6 +4,18 @@
4
4
  # Shared by install.sh and update.sh
5
5
  # ═══════════════════════════════════════════════════════════
6
6
 
7
+ eagle_clean_hook_entries() {
8
+ local settings="$1"
9
+ local event="$2"
10
+ local command="$3"
11
+
12
+ local tmp
13
+ tmp=$(mktemp)
14
+ jq --arg cmd "$command" \
15
+ ".hooks.${event} = ((.hooks.${event} // []) | map(select(.hooks | all(.command != \$cmd))))" \
16
+ "$settings" > "$tmp" && mv "$tmp" "$settings"
17
+ }
18
+
7
19
  eagle_patch_hook() {
8
20
  local settings="$1"
9
21
  local event="$2"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eagle-mem",
3
- "version": "4.9.8",
3
+ "version": "4.9.9",
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"
@@ -125,13 +125,7 @@ case "$subcommand" in
125
125
 
126
126
  waive)
127
127
  id="${1:-}"
128
- [ -z "$id" ] && { eagle_err "Usage: eagle-mem feature waive <id> --reason <text>"; exit 1; }
129
- case "$id" in
130
- *[!0-9]*)
131
- eagle_err "Invalid ID: '$id' (must be numeric)"
132
- exit 1
133
- ;;
134
- esac
128
+ [ -z "$id" ] && { eagle_err "Usage: eagle-mem feature waive <id|name> --reason <text>"; exit 1; }
135
129
  shift
136
130
  reason=""
137
131
  while [ $# -gt 0 ]; do
@@ -147,14 +141,27 @@ case "$subcommand" in
147
141
  *) reason="$1"; shift ;;
148
142
  esac
149
143
  done
150
- [ -z "$reason" ] && { eagle_err "Usage: eagle-mem feature waive <id> --reason <text>"; exit 1; }
151
- waived=$(eagle_waive_pending_feature_verification "$project" "$id" "$reason" | tail -1)
152
- if [ "${waived:-0}" -gt 0 ] 2>/dev/null; then
153
- eagle_ok "Pending verification #$id waived"
154
- else
155
- eagle_err "No pending verification found with ID $id"
156
- exit 1
157
- fi
144
+ [ -z "$reason" ] && { eagle_err "Usage: eagle-mem feature waive <id|name> --reason <text>"; exit 1; }
145
+ case "$id" in
146
+ *[!0-9]*)
147
+ waived=$(eagle_resolve_pending_feature_verifications "$project" "$id" "waived" "$reason" | tail -1)
148
+ if [ "${waived:-0}" -gt 0 ] 2>/dev/null; then
149
+ eagle_ok "Waived $waived pending verification(s) for '$id'"
150
+ else
151
+ eagle_err "No pending verifications found for feature '$id'"
152
+ exit 1
153
+ fi
154
+ ;;
155
+ *)
156
+ waived=$(eagle_waive_pending_feature_verification "$project" "$id" "$reason" | tail -1)
157
+ if [ "${waived:-0}" -gt 0 ] 2>/dev/null; then
158
+ eagle_ok "Pending verification #$id waived"
159
+ else
160
+ eagle_err "No pending verification found with ID $id"
161
+ exit 1
162
+ fi
163
+ ;;
164
+ esac
158
165
  ;;
159
166
 
160
167
  add)
@@ -226,7 +226,11 @@ if [ "$claude_found" = true ]; then
226
226
  "$EAGLE_MEM_DIR/hooks/stop.sh" \
227
227
  "Stop hook"
228
228
 
229
- eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskCreate|TaskUpdate" \
229
+ # Clean old registrations before re-registering (handles matcher changes across versions)
230
+ eagle_clean_hook_entries "$SETTINGS" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
231
+ eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
232
+
233
+ eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" \
230
234
  "$EAGLE_MEM_DIR/hooks/post-tool-use.sh" \
231
235
  "PostToolUse hook"
232
236
 
@@ -246,21 +250,9 @@ if [ "$claude_found" = true ]; then
246
250
  "$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh" \
247
251
  "UserPromptSubmit hook"
248
252
 
249
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash" \
250
- "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
251
- "PreToolUse hook (Bash)"
252
-
253
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Read" \
254
- "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
255
- "PreToolUse hook (Read)"
256
-
257
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Edit" \
258
- "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
259
- "PreToolUse hook (Edit)"
260
-
261
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Write" \
253
+ eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash|Read|Edit|Write" \
262
254
  "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh" \
263
- "PreToolUse hook (Write)"
255
+ "PreToolUse hook"
264
256
  else
265
257
  eagle_info "Claude hooks skipped ${DIM}(Claude Code not detected)${RESET}"
266
258
  fi
package/scripts/update.sh CHANGED
@@ -76,23 +76,18 @@ fi
76
76
  # ─── Re-register hooks (idempotent) ───────────────────────
77
77
 
78
78
  if [ "$claude_found" = true ] && [ -f "$SETTINGS" ] && command -v jq &>/dev/null; then
79
- # Update PostToolUse matcher if it has the old value (pre-v1.3.0)
80
- if jq -e '.hooks.PostToolUse[]? | select(.matcher == "Read|Write|Edit|Bash")' "$SETTINGS" &>/dev/null; then
81
- _tmp=$(mktemp)
82
- jq '(.hooks.PostToolUse[] | select(.matcher == "Read|Write|Edit|Bash")).matcher = "Read|Write|Edit|Bash|TaskCreate|TaskUpdate"' "$SETTINGS" > "$_tmp" && mv "$_tmp" "$SETTINGS"
83
- fi
79
+ # Clean old registrations before re-registering (handles matcher changes across versions)
80
+ eagle_clean_hook_entries "$SETTINGS" "PostToolUse" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
81
+ eagle_clean_hook_entries "$SETTINGS" "PreToolUse" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
84
82
 
85
83
  eagle_patch_hook "$SETTINGS" "SessionStart" "" "$EAGLE_MEM_DIR/hooks/session-start.sh"
86
84
  eagle_patch_hook "$SETTINGS" "Stop" "" "$EAGLE_MEM_DIR/hooks/stop.sh"
87
- eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskCreate|TaskUpdate" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
85
+ eagle_patch_hook "$SETTINGS" "PostToolUse" "Read|Write|Edit|Bash|TaskUpdate" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
88
86
  eagle_patch_hook "$SETTINGS" "TaskCreated" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
89
87
  eagle_patch_hook "$SETTINGS" "TaskCompleted" "" "$EAGLE_MEM_DIR/hooks/post-tool-use.sh"
90
88
  eagle_patch_hook "$SETTINGS" "SessionEnd" "" "$EAGLE_MEM_DIR/hooks/session-end.sh"
91
89
  eagle_patch_hook "$SETTINGS" "UserPromptSubmit" "" "$EAGLE_MEM_DIR/hooks/user-prompt-submit.sh"
92
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
93
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Read" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
94
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Edit" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
95
- eagle_patch_hook "$SETTINGS" "PreToolUse" "Write" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
90
+ eagle_patch_hook "$SETTINGS" "PreToolUse" "Bash|Read|Edit|Write" "$EAGLE_MEM_DIR/hooks/pre-tool-use.sh"
96
91
 
97
92
  eagle_ok "Hooks registered"
98
93
  fi
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: eagle-mem-feature
3
+ description: >
4
+ Manage Eagle Mem feature verification and anti-regression guardrails. Use when:
5
+ 'feature pending', 'verify feature', 'waive feature', 'feature verification',
6
+ 'pending verifications', 'release blocked', 'feature guard', 'smoke test',
7
+ 'what needs verification', 'mark feature verified', 'skip verification'.
8
+ Uses the eagle-mem CLI.
9
+ ---
10
+
11
+ # Eagle Mem — Feature Verification
12
+
13
+ ## Purpose
14
+
15
+ **For the user:** Every tracked feature has files, dependencies, and smoke tests. When you edit a tracked file, Eagle Mem automatically flags the feature as needing re-verification. Release-boundary commands stay blocked until all pending verifications are resolved. This prevents shipping regressions.
16
+
17
+ **For you:** The pending verification list tells you what's at risk after your edits. Resolve each one: run smoke tests and `verify`, or explain why it's safe and `waive`. Don't leave pending items unresolved — they block the user's workflow.
18
+
19
+ ## Core Concepts
20
+
21
+ ### Verify vs Waive
22
+
23
+ These are semantically different operations:
24
+
25
+ **Verify** = "I tested this exact change and it works." Fingerprint-specific — tied to the current diff hash. If the file changes again, a new pending verification appears.
26
+
27
+ **Waive** = "I accept changes to this feature+file pair." Fingerprint-agnostic — covers the current change AND all future changes to that file for that feature. Use when the change is known-safe (e.g., comment-only edit, unrelated code path).
28
+
29
+ **Decision rule:** Did you run the smoke test or manually confirm behavior? Use `verify`. Is the change structurally irrelevant to the feature? Use `waive`.
30
+
31
+ ### Pending Verifications
32
+
33
+ When you Edit/Write a file tracked by a feature, PostToolUse automatically creates a pending verification record. Each record is keyed by (project, feature, file, fingerprint). The `pending` list shows what needs attention before release.
34
+
35
+ ### Release Boundary
36
+
37
+ Release-boundary commands (publish, deploy) check for unresolved pending verifications. If any exist, the command is blocked with a list of what's pending. This is the enforcement mechanism — it only gates release, not development.
38
+
39
+ ## Steps
40
+
41
+ ### 1. Check what's pending
42
+
43
+ ```bash
44
+ eagle-mem feature pending # current project
45
+ eagle-mem feature pending --raw # include trigger, fingerprint, timestamp
46
+ eagle-mem feature pending --limit 100 # show more than default 50
47
+ ```
48
+
49
+ Each entry shows: feature name, file path, reason, and smoke test command (if registered).
50
+
51
+ ### 2. Resolve by verifying
52
+
53
+ After running smoke tests or confirming the feature works:
54
+
55
+ ```bash
56
+ eagle-mem feature verify <feature-name> --notes "smoke tests pass, tested login flow"
57
+ ```
58
+
59
+ This marks ALL pending verifications for that feature as verified (for the current fingerprints) and updates the feature's `last_verified_at` timestamp.
60
+
61
+ ### 3. Resolve by waiving
62
+
63
+ When a change is known-safe without testing — waive by feature name:
64
+
65
+ ```bash
66
+ eagle-mem feature waive <feature-name> --reason "comment-only change, no behavior impact"
67
+ ```
68
+
69
+ Or waive a single pending record by ID:
70
+
71
+ ```bash
72
+ eagle-mem feature waive <id> --reason "unrelated code path"
73
+ ```
74
+
75
+ **Prefer waive-by-name** over waive-by-ID. IDs are ephemeral (new edits create new IDs), but names are stable. Waiving by name resolves all pending records for that feature at once.
76
+
77
+ A reason is always required — it's the audit trail for why verification was skipped.
78
+
79
+ ### 4. Register a new feature
80
+
81
+ ```bash
82
+ eagle-mem feature add auth-flow \
83
+ --desc "User authentication and session management" \
84
+ --file src/auth/login.ts \
85
+ --file src/auth/session.ts \
86
+ --smoke "npm test -- --grep auth" \
87
+ --requires env_var:AUTH_SECRET
88
+ ```
89
+
90
+ ### 5. List and inspect features
91
+
92
+ ```bash
93
+ eagle-mem feature list # all active features
94
+ eagle-mem feature show <name> # files, deps, smoke tests, last verified
95
+ ```
96
+
97
+ ## Judgment
98
+
99
+ **Always verify when:**
100
+ - You edited core logic in a tracked file
101
+ - The smoke test exists and is quick to run
102
+ - Multiple features depend on the changed file
103
+
104
+ **Waive when:**
105
+ - The edit is cosmetic (formatting, comments, imports)
106
+ - The changed code path is unrelated to the feature's functionality
107
+ - The feature's smoke test would test something you already tested another way
108
+
109
+ **Don't ignore pending verifications.** If you see them in the recall block, address them before your session ends. The user will be blocked on release otherwise.
110
+
111
+ ## Reference
112
+
113
+ | Command | What it does |
114
+ |---|---|
115
+ | `feature list` | All active features with file/dep/test counts |
116
+ | `feature show <name>` | Full detail: files, dependencies, smoke tests |
117
+ | `feature pending` | All unresolved pending verifications |
118
+ | `feature verify <name>` | Mark feature verified (fingerprint-specific) |
119
+ | `feature waive <name\|id>` | Waive verification (fingerprint-agnostic for name) |
120
+ | `feature add <name>` | Register a new feature with files/deps/tests |
121
+ | `--notes "text"` | Attach notes to verify/waive (audit trail) |
122
+ | `--reason "text"` | Required for waive — explains why safe |
123
+ | `--raw` | Show trigger, fingerprint, and timestamp in pending |