nexo-brain 5.3.27 → 5.3.28

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "5.3.27",
3
+ "version": "5.3.28",
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "5.3.27",
3
+ "version": "5.3.28",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO Brain — 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",
@@ -225,6 +225,23 @@ def _session_has_guard_check(conn, sid: str) -> bool:
225
225
  return bool(row)
226
226
 
227
227
 
228
+ def _session_has_guard_for_file(conn, sid: str, filepath: str) -> bool:
229
+ """Check if guard_check was called for a specific file in this session."""
230
+ if not filepath:
231
+ return False
232
+ normalized = _normalize_file_path(filepath)
233
+ basename = os.path.basename(filepath)
234
+ # guard_checks.files is a comma-separated or JSON list of paths/areas
235
+ row = conn.execute(
236
+ """SELECT 1 FROM guard_checks
237
+ WHERE session_id = ?
238
+ AND (files LIKE ? OR files LIKE ? OR files LIKE ?)
239
+ LIMIT 1""",
240
+ (sid, f"%{normalized}%", f"%{basename}%", f"%{filepath}%"),
241
+ ).fetchone()
242
+ return bool(row)
243
+
244
+
228
245
  def _find_open_debt(conn, *, session_id: str, task_id: str, debt_type: str, file_token: str) -> dict | None:
229
246
  row = conn.execute(
230
247
  """SELECT *
@@ -548,6 +565,28 @@ def process_pre_tool_event(payload: dict) -> dict:
548
565
  "reason_code": "guard_unacknowledged",
549
566
  }
550
567
  )
568
+ continue
569
+
570
+ # Check if guard_check was called for this specific file
571
+ if not _session_has_guard_for_file(conn, sid, filepath):
572
+ debt = _ensure_protocol_debt(
573
+ conn,
574
+ session_id=sid,
575
+ task_id=task["task_id"],
576
+ debt_type="write_without_file_guard_check",
577
+ severity="warn",
578
+ evidence=f"{tool_name} attempted on {filepath} without a prior guard_check covering that file.",
579
+ file_token=filepath,
580
+ )
581
+ blocks.append(
582
+ {
583
+ "file": filepath,
584
+ "task_id": task["task_id"],
585
+ "debt_id": debt.get("id"),
586
+ "debt_type": "write_without_file_guard_check",
587
+ "reason_code": "missing_file_guard",
588
+ }
589
+ )
551
590
 
552
591
  return {
553
592
  "ok": True,
@@ -728,6 +767,11 @@ def format_pretool_block_message(result: dict) -> str:
728
767
  lines.append(
729
768
  f"- {file_note}: task {item['task_id']} still has blocking guard debt. Acknowledge it with `nexo_task_acknowledge_guard` before retrying."
730
769
  )
770
+ elif item.get("reason_code") == "missing_file_guard":
771
+ lines.append(
772
+ f"- {file_note}: `nexo_guard_check` obligatorio antes de editar. "
773
+ f"Run `nexo_guard_check(files='{file_note}')` first, then retry the edit."
774
+ )
731
775
  elif strictness == "learning":
732
776
  lines.append(
733
777
  f"- {file_note}: open `nexo_task_open(task_type='edit', files=['{file_note}'])` first, then rerun the edit."