nexo-brain 7.13.8 → 7.13.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.13.8",
3
+ "version": "7.13.9",
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.13.8` is the current packaged-runtime line. Patch release over v7.13.7 — Brain now rejects Python <3.10 during Desktop-managed fresh installs, honors the Python interpreter prepared by Desktop, and fails clearly before dependency resolution if an unsupported Apple Python 3.9 reaches the installer.
21
+ Version `7.13.9` is the current packaged-runtime line. Patch release over v7.13.8 — Brain now moves aside an existing managed `.venv` when it was created with unsupported Python <3.10, then recreates it with the supported interpreter prepared by Desktop.
22
+
23
+ Previously in `7.13.8`: patch release — Brain rejects Python <3.10 during Desktop-managed fresh installs, honors the Python interpreter prepared by Desktop, and fails clearly before dependency resolution if an unsupported Apple Python 3.9 reaches the installer.
22
24
 
23
25
  Previously in `7.13.7`: patch release — Brain adds an authenticated official protocol-card client (`nexo_card_catalog`, `nexo_card_get`, `nexo_card_match`) so agents can ask the NEXO Desktop backend for the right task protocol at runtime. The protocol corpus stays private on the server; this open-source package ships only the client, tool map, and agent guidance.
24
26
 
package/bin/nexo-brain.js CHANGED
@@ -303,6 +303,46 @@ function pythonHasPip(pythonBin) {
303
303
  }
304
304
  }
305
305
 
306
+ function managedVenvPythonPath(nexoHome = NEXO_HOME) {
307
+ const venvPath = path.join(nexoHome, ".venv");
308
+ return process.platform === "win32"
309
+ ? path.join(venvPath, "Scripts", "python.exe")
310
+ : path.join(venvPath, "bin", "python3");
311
+ }
312
+
313
+ function safeTimestampForPath() {
314
+ return new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
315
+ }
316
+
317
+ function uniqueBackupPath(targetPath, suffix) {
318
+ const dir = path.dirname(targetPath);
319
+ const base = path.basename(targetPath);
320
+ const stamp = safeTimestampForPath();
321
+ let candidate = path.join(dir, `${base}.${suffix}-${stamp}`);
322
+ if (!fs.existsSync(candidate)) return candidate;
323
+ for (let i = 2; i < 100; i += 1) {
324
+ candidate = path.join(dir, `${base}.${suffix}-${stamp}-${i}`);
325
+ if (!fs.existsSync(candidate)) return candidate;
326
+ }
327
+ return path.join(dir, `${base}.${suffix}-${stamp}-${process.pid}`);
328
+ }
329
+
330
+ function ensureManagedVenvCompatible(venvPath, venvPython) {
331
+ if (!fs.existsSync(venvPython)) return;
332
+ const version = pythonVersion(venvPython);
333
+ if (version && pythonVersionMeetsMinimum(version)) return;
334
+
335
+ const reason = version ? `Python ${version}` : "an unreadable Python executable";
336
+ const backupPath = uniqueBackupPath(venvPath, "unsupported-python");
337
+ log(` Existing Python virtual environment uses ${reason}; moving it aside to recreate.`);
338
+ try {
339
+ fs.renameSync(venvPath, backupPath);
340
+ } catch (err) {
341
+ throw new Error(`Existing NEXO Python virtual environment is incompatible and could not be moved aside: ${err.message || err}`);
342
+ }
343
+ log(` Previous Python virtual environment moved to ${backupPath}`);
344
+ }
345
+
306
346
  function seedPipFromBundledWheels(venvPython, bundledWheelsDir) {
307
347
  if (!fs.existsSync(venvPython) || !fs.existsSync(bundledWheelsDir)) return false;
308
348
  if (pythonHasPip(venvPython)) return true;
@@ -576,15 +616,13 @@ function resolveSystemPython() {
576
616
  }
577
617
 
578
618
  function ensureWarmupPython(nexoHome = NEXO_HOME) {
579
- const existing = findVenvPython(nexoHome);
580
- if (existing) return existing;
581
-
582
- const basePython = resolveSystemPython();
583
619
  const venvPath = path.join(nexoHome, ".venv");
584
- const venvPython = process.platform === "win32"
585
- ? path.join(venvPath, "Scripts", "python.exe")
586
- : path.join(venvPath, "bin", "python3");
620
+ const venvPython = managedVenvPythonPath(nexoHome);
587
621
  fs.mkdirSync(nexoHome, { recursive: true });
622
+ ensureManagedVenvCompatible(venvPath, venvPython);
623
+ if (fs.existsSync(venvPython)) return venvPython;
624
+
625
+ const basePython = resolveInstallerPython() || resolveSystemPython();
588
626
  if (!fs.existsSync(venvPython)) {
589
627
  log(" Creating Python virtual environment for model warmup...");
590
628
  const result = spawnSync(basePython, ["-m", "venv", venvPath], { stdio: "inherit", timeout: 120000 });
@@ -2398,7 +2436,7 @@ async function maybeConfigurePublicContribution(schedule, useDefaults) {
2398
2436
  * Resolve the venv python path for an existing NEXO_HOME installation.
2399
2437
  */
2400
2438
  function findVenvPython(nexoHome) {
2401
- const venvPy = path.join(nexoHome, ".venv", "bin", "python3");
2439
+ const venvPy = managedVenvPythonPath(nexoHome);
2402
2440
  if (fs.existsSync(venvPy)) return venvPy;
2403
2441
  return null;
2404
2442
  }
@@ -3702,11 +3740,11 @@ async function runSetup() {
3702
3740
  log("Installing cognitive engine dependencies...");
3703
3741
  fs.mkdirSync(NEXO_HOME, { recursive: true });
3704
3742
  const venvPath = path.join(NEXO_HOME, ".venv");
3705
- const venvPython = platform === "win32"
3706
- ? path.join(venvPath, "Scripts", "python.exe")
3707
- : path.join(venvPath, "bin", "python3");
3743
+ const venvPython = managedVenvPythonPath(NEXO_HOME);
3708
3744
  const bundledWheelsDir = path.join(__dirname, "..", "python-wheels");
3709
3745
 
3746
+ ensureManagedVenvCompatible(venvPath, venvPython);
3747
+
3710
3748
  // Create venv if it doesn't exist
3711
3749
  if (!fs.existsSync(venvPython)) {
3712
3750
  log(" Creating Python virtual environment...");
@@ -3724,6 +3762,13 @@ async function runSetup() {
3724
3762
  }
3725
3763
  }
3726
3764
  }
3765
+ if (fs.existsSync(venvPython)) {
3766
+ const venvVersion = pythonVersion(venvPython);
3767
+ if (!venvVersion || !pythonVersionMeetsMinimum(venvVersion)) {
3768
+ log(`Python virtual environment is unsupported after creation (${venvVersion || "unknown version"}).`);
3769
+ process.exit(1);
3770
+ }
3771
+ }
3727
3772
  if (fs.existsSync(venvPython) && !pythonHasPip(venvPython)) {
3728
3773
  seedPipFromBundledWheels(venvPython, bundledWheelsDir);
3729
3774
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.13.8",
3
+ "version": "7.13.9",
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",