nexo-brain 1.2.0 → 1.2.2

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
@@ -1,6 +1,6 @@
1
1
  # NEXO Brain — Your AI Gets a Brain
2
2
 
3
- [![npm v1.2.0](https://img.shields.io/npm/v/nexo-brain?label=npm&color=purple)](https://www.npmjs.com/package/nexo-brain)
3
+ [![npm v1.2.1](https://img.shields.io/npm/v/nexo-brain?label=npm&color=purple)](https://www.npmjs.com/package/nexo-brain)
4
4
  [![F1 0.588 on LoCoMo](https://img.shields.io/badge/LoCoMo_F1-0.588-brightgreen)](https://github.com/wazionapps/nexo/blob/main/benchmarks/locomo/results/)
5
5
  [![+55% vs GPT-4](https://img.shields.io/badge/vs_GPT--4-%2B55%25-blue)](https://github.com/snap-research/locomo/issues/33)
6
6
  [![GitHub stars](https://img.shields.io/github/stars/wazionapps/nexo?style=social)](https://github.com/wazionapps/nexo/stargazers)
@@ -604,6 +604,12 @@ If NEXO Brain is useful to you, consider:
604
604
 
605
605
  ## Changelog
606
606
 
607
+ ### v1.2.1 — Stop Hook Hotfix (2026-03-27)
608
+ - **Fix**: v1.2.0 deleted the flag on approve, causing infinite block loops if session didn't close immediately
609
+ - **Fix**: Removed TTL on flag — it persists until SessionStart cleans it up next session
610
+ - **New**: Trivial sessions (<5 meaningful tool calls) skip post-mortem entirely and approve immediately
611
+ - SessionStart hook now cleans up `.postmortem-complete` flag on session start
612
+
607
613
  ### v1.2.0 — Blocking Stop Hook (2026-03-27)
608
614
  - **Fix**: Stop hook now uses `"decision": "block"` instead of `"approve"` to enforce post-mortem execution
609
615
  - Previous behavior: hook injected `systemMessage` but AI had already responded — instructions were never processed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO \u2014 Cognitive co-operator for Claude Code. Atkinson-Shiffrin memory, semantic RAG, trust scoring, and metacognitive error prevention.",
6
6
  "bin": {
@@ -8,7 +8,10 @@ NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
8
8
  BRIEFING_FILE="$NEXO_HOME/coordination/session-briefing.txt"
9
9
  MAX_AGE_SECONDS=3600 # 1 hour cache
10
10
 
11
- mkdir -p "$NEXO_HOME/coordination"
11
+ mkdir -p "$NEXO_HOME/coordination" "$NEXO_HOME/operations"
12
+
13
+ # Clean up post-mortem flag from previous session
14
+ rm -f "$NEXO_HOME/operations/.postmortem-complete" 2>/dev/null
12
15
 
13
16
  # If briefing exists and is less than 1 hour old, skip regeneration
14
17
  if [ -f "$BRIEFING_FILE" ]; then
@@ -1,24 +1,30 @@
1
1
  #!/bin/bash
2
- # NEXO Stop hook (v6 — BLOCKING post-mortem)
2
+ # NEXO Stop hook (v7 — BLOCKING post-mortem with trivial session detection)
3
3
  #
4
- # v5 bug: used "decision": "approve" + systemMessage. The AI already responded
5
- # with a goodbye and never processed the post-mortem instructions. The
6
- # systemMessage appeared but the AI had no turn to act on it.
7
- #
8
- # v6 fix: uses "decision": "block" to PREVENT session close until the
9
- # post-mortem is done. A flag file (.postmortem-complete) signals completion
10
- # next close attempt will approve.
4
+ # v5 bug: used "approve" + systemMessage AI never processed post-mortem.
5
+ # v6 bug: used "block" but deleted flag on approve — caused infinite block loop.
6
+ # Also had TTL on flag that expired between close attempts.
7
+ # v7 fix: trivial sessions (<5 tool calls) approve immediately.
8
+ # Non-trivial sessions block until post-mortem is done.
9
+ # Flag has NO TTL and is NOT deleted on approve.
10
+ # SessionStart hook cleans up the flag for the next session.
11
11
  #
12
12
  # Flow:
13
- # 1. User says goodbye / Ctrl+C
14
- # 2. Hook checks for recent flag not found BLOCK with instructions
15
- # 3. AI gets another turn → executes post-mortem → creates flag
16
- # 4. User closes again → hook sees flag → APPROVE
13
+ # Trivial session (quick question, <5 meaningful tool calls):
14
+ # APPROVE immediately, no post-mortem needed
15
+ #
16
+ # Non-trivial session:
17
+ # 1. User closes → hook checks flag → not found → BLOCK
18
+ # 2. AI executes post-mortem → creates flag
19
+ # 3. User closes again → hook sees flag → APPROVE
20
+ # 4. Next session start → SessionStart hook deletes flag
17
21
  set -euo pipefail
18
22
 
19
23
  NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
20
24
  NEXO_NAME="${NEXO_NAME:-NEXO}"
21
25
  FLAG_FILE="$NEXO_HOME/operations/.postmortem-complete"
26
+ TODAY=$(date +%Y-%m-%d)
27
+ TOOL_LOG="$NEXO_HOME/operations/tool-logs/${TODAY}.jsonl"
22
28
 
23
29
  # 0. Refresh diary draft with latest changes/decisions (best-effort)
24
30
  python3 -c "
@@ -50,25 +56,51 @@ except Exception:
50
56
  pass
51
57
  " 2>/dev/null || true
52
58
 
53
- # 1. Check if post-mortem was already completed (flag < 120 seconds old)
59
+ # 1. Detect trivial session count meaningful tool calls from today's log
60
+ # A session with <5 tool calls (excluding Read/Grep/Glob/Bash/ToolSearch) is trivial
61
+ TOOL_COUNT=0
62
+ if [ -f "$TOOL_LOG" ]; then
63
+ TOOL_COUNT=$(python3 -c "
64
+ import json, sys
65
+ count = 0
66
+ for line in open('$TOOL_LOG'):
67
+ try:
68
+ d = json.loads(line)
69
+ t = d.get('tool_name', '')
70
+ if t and t not in ('Read', 'Grep', 'Glob', 'Bash', 'ToolSearch'):
71
+ count += 1
72
+ except:
73
+ pass
74
+ print(count)
75
+ " 2>/dev/null || echo "0")
76
+ fi
77
+
78
+ # Trivial session → approve immediately, write minimal buffer, skip post-mortem
79
+ if [ "$TOOL_COUNT" -lt 5 ]; then
80
+ BUFFER="$NEXO_HOME/brain/session_buffer.jsonl"
81
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S")
82
+ mkdir -p "$(dirname "$BUFFER")"
83
+ echo "{\"ts\":\"$TIMESTAMP\",\"tasks\":[\"trivial session\"],\"decisions\":[],\"user_patterns\":[],\"files_modified\":[],\"errors_resolved\":[],\"self_critique\":\"trivial session — no post-mortem needed\",\"mood\":\"neutral\",\"source\":\"hook-trivial\"}" >> "$BUFFER" 2>/dev/null
84
+
85
+ cat << 'HOOKEOF'
86
+ {
87
+ "decision": "approve"
88
+ }
89
+ HOOKEOF
90
+ exit 0
91
+ fi
92
+
93
+ # 2. Non-trivial session — check if post-mortem was already completed
94
+ # Flag has NO TTL — it persists until SessionStart cleans it up next session.
95
+ # IMPORTANT: do NOT delete flag here — that causes an infinite block loop
96
+ # if the session doesn't close immediately after approve.
54
97
  POSTMORTEM_DONE=false
55
98
  if [ -f "$FLAG_FILE" ]; then
56
- FLAG_AGE=$(python3 -c "
57
- import os, time
58
- try:
59
- age = time.time() - os.path.getmtime('$FLAG_FILE')
60
- print('recent' if age < 120 else 'stale')
61
- except:
62
- print('stale')
63
- " 2>/dev/null || echo "stale")
64
- if [ "$FLAG_AGE" = "recent" ]; then
65
- POSTMORTEM_DONE=true
66
- fi
99
+ POSTMORTEM_DONE=true
67
100
  fi
68
101
 
69
102
  if [ "$POSTMORTEM_DONE" = true ]; then
70
103
  # Post-mortem was done — allow session to close
71
- rm -f "$FLAG_FILE" 2>/dev/null
72
104
  cat << 'HOOKEOF'
73
105
  {
74
106
  "decision": "approve"
@@ -76,16 +108,15 @@ if [ "$POSTMORTEM_DONE" = true ]; then
76
108
  HOOKEOF
77
109
  else
78
110
  # Post-mortem NOT done — BLOCK session close and inject instructions
79
- # Uses "reason" field which Claude Code shows to the AI as context
80
111
  cat << HOOKEOF
81
112
  {
82
113
  "decision": "block",
83
- "reason": "STOP HOOK — MANDATORY POST-MORTEM before ending (do NOT ask permission, do NOT skip):\n\n## 1. SELF-CRITIQUE (MANDATORY — write to session diary)\nAnswer these questions in the self_critique field of nexo_session_diary_write:\n- Did the user have to ask me for something I should have detected or done on my own?\n- Did I wait for the user to tell me something I could have verified proactively?\n- Are there systems/states I can check next session without being asked?\n- Did I repeat an error that already had a registered learning?\n- What would I do differently if I repeated this session?\nIf any answer is YES — write the specific rule that would prevent repetition.\nIf the session was flawless, write 'No self-critique — clean session.'\n\n## 2. SESSION BUFFER\nIf the session was NOT trivial, append ONE JSON line to ${NEXO_HOME}/brain/session_buffer.jsonl:\n{\"ts\":\"YYYY-MM-DDTHH:MM:SS\",\"tasks\":[...],\"decisions\":[...],\"user_patterns\":[...],\"files_modified\":[...],\"errors_resolved\":[...],\"self_critique\":\"short summary\",\"mood\":\"focused|impatient|exploratory|frustrated|satisfied|neutral\",\"source\":\"claude\"}\n\n## 3. FOLLOWUPS\nIf there were deploys/cron changes/fixes — nexo_followup_create with verification date.\n\n## 4. PROACTIVE SEEDS\nWhat can I leave prepared so the next session starts doing useful work without the user asking?\n\n## 5. MARK COMPLETE\nWhen ALL of the above is done, run:\nbash -c 'mkdir -p ${NEXO_HOME}/operations && date +%s > ${NEXO_HOME}/operations/.postmortem-complete'\nThen say goodbye. The user will close again and the hook will approve."
114
+ "reason": "STOP HOOK — MANDATORY POST-MORTEM before ending (do NOT ask permission, do NOT skip):\n\n## 1. SELF-CRITIQUE (MANDATORY — write to session diary)\nAnswer these questions in the self_critique field of nexo_session_diary_write:\n- Did the user have to ask me for something I should have detected or done on my own?\n- Did I wait for the user to tell me something I could have verified proactively?\n- Are there systems/states I can check next session without being asked?\n- Did I repeat an error that already had a registered learning?\n- What would I do differently if I repeated this session?\nIf any answer is YES — write the specific rule that would prevent repetition.\nIf the session was flawless, write 'No self-critique — clean session.'\n\n## 2. SESSION BUFFER\nIf the session was NOT trivial, append ONE JSON line to ${NEXO_HOME}/brain/session_buffer.jsonl:\n{\"ts\":\"YYYY-MM-DDTHH:MM:SS\",\"tasks\":[...],\"decisions\":[...],\"user_patterns\":[...],\"files_modified\":[...],\"errors_resolved\":[...],\"self_critique\":\"short summary\",\"mood\":\"focused|impatient|exploratory|frustrated|satisfied|neutral\",\"source\":\"claude\"}\n\n## 3. FOLLOWUPS\nIf there were deploys/cron changes/fixes — nexo_followup_create with verification date.\n\n## 4. PROACTIVE SEEDS\nWhat can I leave prepared so the next session starts doing useful work without the user asking?\n\n## 5. MARK COMPLETE\nWhen ALL of the above is done, run:\nbash -c 'mkdir -p ${NEXO_HOME}/operations && date +%s > ${NEXO_HOME}/operations/.postmortem-complete'\nThe user will close again and the hook will approve.\n\nIMPORTANT: Do NOT say goodbye, do NOT say goodnight or any farewell. Just execute the steps and mark complete."
84
115
  }
85
116
  HOOKEOF
86
117
  fi
87
118
 
88
- # 2. Direct session buffer fallback (runs regardless safety net)
119
+ # 3. Direct session buffer fallback (runs for non-trivial sessions)
89
120
  BUFFER="$NEXO_HOME/brain/session_buffer.jsonl"
90
121
  TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S")
91
122
 
@@ -132,8 +163,7 @@ except:
132
163
  echo "{\"ts\":\"$TIMESTAMP\",\"tasks\":[\"session ended\"],\"decisions\":[],\"user_patterns\":[],\"files_modified\":[],\"errors_resolved\":[],\"self_critique\":\"hook-fallback, no self-critique captured\",\"mood\":\"unknown\",\"session_end_mode\":\"$ADAPTIVE_MODE\",\"source\":\"hook-fallback\"}" >> "$BUFFER" 2>/dev/null
133
164
  fi
134
165
 
135
- # 3. Intra-day reflection trigger
136
- # Check if buffer has >=3 sessions AND last reflection was >4h ago
166
+ # 4. Intra-day reflection trigger
137
167
  REFLECTION_SCRIPT="$NEXO_HOME/scripts/nexo-reflection.py"
138
168
  REFLECTION_STATE="$NEXO_HOME/coordination/reflection-log.json"
139
169
  TRIGGER_THRESHOLD=3