nexo-brain 5.4.6 → 5.4.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/.claude-plugin/plugin.json +1 -1
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/crons/manifest.json +1 -1
- package/src/plugins/update.py +27 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.7",
|
|
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,9 +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 `5.4.
|
|
21
|
+
Version `5.4.7` is the current packaged-runtime line: tool-enforcement-map.json for Protocol Enforcer — canonical map of all 247 tools with enforcement metadata, plus verify script.
|
|
22
22
|
|
|
23
|
-
Previously in `5.4.
|
|
23
|
+
Previously in `5.4.6`: runtime dependency management in `nexo update` + daily auto-update cron.
|
|
24
24
|
|
|
25
25
|
Start here:
|
|
26
26
|
- [5-minute quickstart](docs/quickstart-5-minutes.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.7",
|
|
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",
|
package/src/crons/manifest.json
CHANGED
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
{
|
|
208
208
|
"id": "auto-update",
|
|
209
209
|
"script": "scripts/nexo-auto-update.py",
|
|
210
|
-
"schedule": {"hour":
|
|
210
|
+
"schedule": {"hour": 2, "minute": 0},
|
|
211
211
|
"description": "Daily auto-update — Brain + runtime dependencies",
|
|
212
212
|
"core": true,
|
|
213
213
|
"recovery_policy": "catchup",
|
package/src/plugins/update.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
"""Update plugin — pull latest code, backup DBs, run migrations, verify."""
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import shutil
|
|
6
7
|
import sqlite3
|
|
7
8
|
import subprocess
|
|
@@ -347,6 +348,14 @@ def _read_runtime_dependencies() -> list[dict]:
|
|
|
347
348
|
return []
|
|
348
349
|
|
|
349
350
|
|
|
351
|
+
_VALID_NPM_NAME = re.compile(r'^(@[a-z0-9\-_.]+/)?[a-z0-9\-_.]+$')
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _validate_npm_name(name: str) -> bool:
|
|
355
|
+
"""Validate that a package name follows npm naming conventions."""
|
|
356
|
+
return bool(name) and bool(_VALID_NPM_NAME.match(name)) and ".." not in name
|
|
357
|
+
|
|
358
|
+
|
|
350
359
|
def _get_npm_global_version(package_name: str) -> str | None:
|
|
351
360
|
"""Return the currently installed global npm package version, or None."""
|
|
352
361
|
try:
|
|
@@ -354,7 +363,9 @@ def _get_npm_global_version(package_name: str) -> str | None:
|
|
|
354
363
|
["npm", "list", "-g", package_name, "--json", "--depth=0"],
|
|
355
364
|
capture_output=True, text=True, timeout=15,
|
|
356
365
|
)
|
|
357
|
-
|
|
366
|
+
# npm list returns exit 1 with valid JSON for peer dep issues;
|
|
367
|
+
# always try to parse the output regardless of returncode.
|
|
368
|
+
if result.stdout.strip():
|
|
358
369
|
data = json.loads(result.stdout)
|
|
359
370
|
deps = data.get("dependencies", {})
|
|
360
371
|
info = deps.get(package_name)
|
|
@@ -362,6 +373,8 @@ def _get_npm_global_version(package_name: str) -> str | None:
|
|
|
362
373
|
return info.get("version")
|
|
363
374
|
except subprocess.TimeoutExpired:
|
|
364
375
|
pass
|
|
376
|
+
except FileNotFoundError:
|
|
377
|
+
pass # npm not installed
|
|
365
378
|
except Exception:
|
|
366
379
|
pass
|
|
367
380
|
return None
|
|
@@ -378,6 +391,8 @@ def _get_npm_registry_version(package_name: str) -> str | None:
|
|
|
378
391
|
return result.stdout.strip()
|
|
379
392
|
except subprocess.TimeoutExpired:
|
|
380
393
|
pass
|
|
394
|
+
except FileNotFoundError:
|
|
395
|
+
pass # npm not installed
|
|
381
396
|
except Exception:
|
|
382
397
|
pass
|
|
383
398
|
return None
|
|
@@ -401,7 +416,7 @@ def _update_runtime_dependencies(progress_fn=None) -> list[dict]:
|
|
|
401
416
|
for dep in deps:
|
|
402
417
|
name = dep.get("name", "")
|
|
403
418
|
dep_type = dep.get("type", "")
|
|
404
|
-
optional = dep.get("optional",
|
|
419
|
+
optional = dep.get("optional", False)
|
|
405
420
|
|
|
406
421
|
if not name or dep_type != "npm-global":
|
|
407
422
|
results.append({
|
|
@@ -412,6 +427,16 @@ def _update_runtime_dependencies(progress_fn=None) -> list[dict]:
|
|
|
412
427
|
})
|
|
413
428
|
continue
|
|
414
429
|
|
|
430
|
+
if not _validate_npm_name(name):
|
|
431
|
+
results.append({
|
|
432
|
+
"name": name,
|
|
433
|
+
"old_version": None,
|
|
434
|
+
"new_version": None,
|
|
435
|
+
"status": "failed",
|
|
436
|
+
"error": f"invalid npm package name: {name!r}",
|
|
437
|
+
})
|
|
438
|
+
continue
|
|
439
|
+
|
|
415
440
|
_emit_progress(progress_fn, f"Checking runtime dependency: {name}...")
|
|
416
441
|
|
|
417
442
|
old_version = _get_npm_global_version(name)
|