nexo-brain 7.8.0 → 7.8.1
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/hooks/pre-compact.sh +26 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.8.
|
|
3
|
+
"version": "7.8.1",
|
|
4
4
|
"description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
[Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
|
|
20
20
|
|
|
21
|
-
Version `7.8.
|
|
21
|
+
Version `7.8.1` is the current packaged-runtime line. Patch release that closes the last compaction-continuity gap Francisco flagged after v7.8.0: `pre-compact.sh` Layer 2 emergency auto-diary and Layer 3 `compaction_memory.record_auto_flush` now use the exact `TARGET_SID` resolved from `CLAUDE_SESSION_ID` instead of falling back to `ORDER BY last_update_epoch DESC LIMIT 1` ("latest active session"). In multi-conversation Desktop that fallback routinely wrote the emergency diary against the wrong conversation even though the main restore path was already exact-SID in v7.8.0. `last_diary_ts` is also scoped by `session_id` now. Fail-closed when no `CLAUDE_SESSION_ID` resolves. New behavioural tests drive the real shell script with two sessions in the DB to pin the invariant. Fixed a latent bash-escape bug in `pre-compact.sh` where a double-quoted string inside a Python comment silently closed the `python3 -c "..."` argument early — caught by adding the behavioural tests. Pytest 2092 passing (+2 new behavioural). No Desktop bump.
|
|
22
|
+
|
|
23
|
+
Previously in `7.8.0`: minor release that closed the PostCompact continuity work Francisco requested after v7.7: `src/hooks/post_compact.py` is a real registered hook (part of the canonical 9-hook set, was 8), `pre-compact.sh` resolves the exact NEXO SID from `CLAUDE_SESSION_ID` instead of falling back to "latest active session" (that was actively wrong in multi-conversation Desktop), the sidecar moves from `/tmp` to `$NEXO_HOME/runtime/data/compacting-sid.txt` so two concurrent compactions on two conversations cannot race on `/tmp`, `post-compact.sh` removes its "latest checkpoint" fallback (fail-closed to a diagnostic systemMessage instead of restoring the wrong conversation), and the hook cross-checks the sidecar SID against the env-resolved one so a "SID mismatch" is logged as such. Pre- and post-compact now emit NDJSON events the engine drains on every periodic tick via `_consume_pending_hook_events()`; the queue file is truncated after read so an event never fires twice. A new contract test (`tests/test_v78_compaction_continuity.py`) pins 11 invariants across ten rails including the hook registration, the exact-SID resolution path, fail-closed behaviour, and that `compaction_count` only increments on real restore. Pytest 2086 passing (+16 vs v7.7). No Desktop bump — v0.27.0 continues to ship.
|
|
22
24
|
|
|
23
25
|
Previously in `7.7.0`: minor release that closed the six gaps left partial after v7.6.0's constructor-guardian-90 pass 1 (autonomous detector for `multi_step_task_detected`, R16 vocabulary expansion, R_CATALOG extended to plain Edit/Write, new `R_PRIMITIVE_CHOICE` rule, `R11_plugin_load_pre_inventory` hardened, 12 new contract tests). Post-review hotfix on the same release wired `task_open` rearm properly (discarded from `tools_called` + per-instance pin cleared on `task_close`), added live `on_event` triggers in R14 and R16, and called `on_tool_call_before` before `on_tool_call` in `run_with_enforcement` so before_tool rules fire in Brain the same way Desktop fires `onBeforeToolCall`.
|
|
24
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.8.
|
|
3
|
+
"version": "7.8.1",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain \u2014 Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
|
|
6
6
|
"homepage": "https://nexo-brain.com",
|
package/src/hooks/pre-compact.sh
CHANGED
|
@@ -117,10 +117,17 @@ except Exception:
|
|
|
117
117
|
fi
|
|
118
118
|
|
|
119
119
|
# ── Layer 2: Emergency auto-diary before compaction ──────────────────
|
|
120
|
-
# Write an actual session_diary entry (not draft) with mechanical summary
|
|
121
|
-
# This is the parachute — if the LLM never wrote a diary, at least this exists
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
# Write an actual session_diary entry (not draft) with mechanical summary.
|
|
121
|
+
# This is the parachute — if the LLM never wrote a diary, at least this exists.
|
|
122
|
+
#
|
|
123
|
+
# v7.8.1 hotfix: must target the EXACT session compacting. Pre-v7.8.1 used
|
|
124
|
+
# "latest active session" (ORDER BY last_update_epoch DESC LIMIT 1) which in
|
|
125
|
+
# multi-conversation Desktop routinely wrote the diary onto the wrong conv.
|
|
126
|
+
# Now we read TARGET_SID resolved from CLAUDE_SESSION_ID above. If it is
|
|
127
|
+
# missing or does not exist in sessions, we fail-closed: no emergency diary
|
|
128
|
+
# > wrong emergency diary. Layer 3 auto_flush is wired to the same SID.
|
|
129
|
+
if [ -f "$NEXO_DB" ] && [ -n "$TARGET_SID" ] && [[ "$TARGET_SID" =~ ^nexo-[0-9]+-[0-9]+$ ]]; then
|
|
130
|
+
NEXO_PRECOMPACT_SID="$TARGET_SID" python3 -c "
|
|
124
131
|
import json, sqlite3, os, sys
|
|
125
132
|
from datetime import datetime
|
|
126
133
|
|
|
@@ -130,15 +137,21 @@ log_file = '$LOG_FILE'
|
|
|
130
137
|
conn = sqlite3.connect(db_path, timeout=3)
|
|
131
138
|
conn.row_factory = sqlite3.Row
|
|
132
139
|
|
|
133
|
-
#
|
|
140
|
+
# v7.8.1 — use the EXACT SID resolved by Layer 1 (from CLAUDE_SESSION_ID),
|
|
141
|
+
# not the pre-v7.8 latest-active row which routinely belongs to a
|
|
142
|
+
# different conversation.
|
|
143
|
+
sid = os.environ.get('NEXO_PRECOMPACT_SID', '')
|
|
144
|
+
if not sid:
|
|
145
|
+
conn.close()
|
|
146
|
+
sys.exit(0)
|
|
134
147
|
row = conn.execute(
|
|
135
|
-
'SELECT sid, task FROM sessions
|
|
148
|
+
'SELECT sid, task FROM sessions WHERE sid = ? LIMIT 1', (sid,)
|
|
136
149
|
).fetchone()
|
|
137
150
|
if not row:
|
|
151
|
+
# SID not present — fail-closed, better skip than write against the
|
|
152
|
+
# wrong session.
|
|
138
153
|
conn.close()
|
|
139
154
|
sys.exit(0)
|
|
140
|
-
|
|
141
|
-
sid = row['sid']
|
|
142
155
|
task = row['task'] or 'unknown'
|
|
143
156
|
|
|
144
157
|
# Check if a real diary already exists for this session
|
|
@@ -149,9 +162,12 @@ if has_diary:
|
|
|
149
162
|
conn.close()
|
|
150
163
|
sys.exit(0) # LLM already wrote one, no need for emergency diary
|
|
151
164
|
|
|
152
|
-
#
|
|
165
|
+
# v7.8.1 — last_diary_ts must be scoped to THIS session too. Otherwise
|
|
166
|
+
# a recent diary of another conversation would truncate this conv's
|
|
167
|
+
# mechanical summary window.
|
|
153
168
|
last_diary = conn.execute(
|
|
154
|
-
'SELECT created_at FROM session_diary ORDER BY created_at DESC LIMIT 1'
|
|
169
|
+
'SELECT created_at FROM session_diary WHERE session_id = ? ORDER BY created_at DESC LIMIT 1',
|
|
170
|
+
(sid,),
|
|
155
171
|
).fetchone()
|
|
156
172
|
last_diary_ts = last_diary['created_at'] if last_diary else '1970-01-01T00:00:00Z'
|
|
157
173
|
|