nexo-brain 7.30.19 → 7.30.21

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.30.19",
3
+ "version": "7.30.21",
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,11 @@
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.30.19` is the current packaged-runtime line. Patch release over v7.30.18 - product capabilities now live in a structured, validated catalog with read-only discovery tools and preserved legacy system-catalog names.
21
+ Version `7.30.21` is the current packaged-runtime line. Patch release over v7.30.20 - Brain now ships managed default MCP catalog/lock reconciliation and the Operational Closure Plane, with Desktop v0.43.12 consuming the coordinated runtime contract.
22
22
 
23
- Previously in `7.30.17`: patch release over v7.30.16 - F0.6 repairs promoted helper imports for personal scripts by adding a core-backed compatibility shim without duplicating the script catalog.
23
+ Previously in `7.30.20`: patch release over v7.30.19 - packaged installs now copy the `product_knowledge` package into the installed runtime so `nexo update` can import the new product knowledge tools.
24
+
25
+ Previously in `7.30.19`: patch release over v7.30.18 - product capabilities now live in a structured, validated catalog with read-only discovery tools and preserved legacy system-catalog names.
24
26
 
25
27
  Previously in `7.30.16`: patch release over v7.30.14 - Desktop diagnostics can read embedding migration status without warming models, and the coordinated Desktop update path is covered for bundled model verification and obsolete managed model cleanup.
26
28
 
package/bin/nexo-brain.js CHANGED
@@ -1346,7 +1346,7 @@ function getCoreRuntimeFlatFiles(srcDir = path.join(__dirname, "..", "src")) {
1346
1346
  }
1347
1347
 
1348
1348
  function getCoreRuntimePackages() {
1349
- return ["db", "cognitive", "doctor", "local_context"];
1349
+ return ["db", "cognitive", "doctor", "local_context", "product_knowledge"];
1350
1350
  }
1351
1351
 
1352
1352
  // Brain contracts — files the NEXO Brain publishes to consumers like
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ const { spawn } = require("child_process");
7
+
8
+ function nexoHome() {
9
+ return process.env.NEXO_HOME || path.join(require("os").homedir(), ".nexo");
10
+ }
11
+
12
+ function readJson(file) {
13
+ try {
14
+ return JSON.parse(fs.readFileSync(file, "utf8"));
15
+ } catch (_) {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ function findEntry(capabilityId) {
21
+ const state = readJson(path.join(nexoHome(), "runtime", "managed-mcp", "installed-state.json"));
22
+ const desired = state && state.desired && typeof state.desired === "object" ? state.desired : {};
23
+ for (const clientEntries of Object.values(desired)) {
24
+ if (!clientEntries || typeof clientEntries !== "object") continue;
25
+ for (const entry of Object.values(clientEntries)) {
26
+ const meta = entry && entry.nexo;
27
+ if (meta && meta.capability_id === capabilityId) return entry;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+
33
+ function providerEnv() {
34
+ return {
35
+ PATH: process.env.PATH || "",
36
+ HOME: process.env.HOME || "",
37
+ NEXO_HOME: nexoHome(),
38
+ };
39
+ }
40
+
41
+ function stagedProviderCommand(providerId) {
42
+ return path.join(nexoHome(), "runtime", "managed-mcp", "artifacts", providerId, "bin", providerId);
43
+ }
44
+
45
+ function spawnProvider(command, args, env) {
46
+ const child = spawn(command, args, {
47
+ stdio: "inherit",
48
+ env,
49
+ });
50
+ child.on("exit", (code, signal) => {
51
+ if (signal) process.kill(process.pid, signal);
52
+ process.exit(typeof code === "number" ? code : 1);
53
+ });
54
+ child.on("error", (error) => {
55
+ console.error(`NEXO managed MCP failed to start: ${error && error.message ? error.message : String(error)}`);
56
+ process.exit(69);
57
+ });
58
+ }
59
+
60
+ function main() {
61
+ const [command, capabilityId] = process.argv.slice(2);
62
+ if (command !== "run" || !capabilityId) {
63
+ console.error("usage: nexo-managed-mcp run <capability_id>");
64
+ process.exit(64);
65
+ }
66
+ const entry = findEntry(capabilityId);
67
+ const meta = entry && entry.nexo ? entry.nexo : {};
68
+ const providerId = meta.provider_id || "";
69
+ if (!providerId) {
70
+ console.error(`NEXO managed MCP capability '${capabilityId}' is not installed yet.`);
71
+ process.exit(69);
72
+ }
73
+ const providerCommand = stagedProviderCommand(providerId);
74
+ const env = providerEnv();
75
+ if (!fs.existsSync(providerCommand)) {
76
+ const providerPackage = String(meta.provider_package || "");
77
+ const providerVersion = String(meta.provider_version || "");
78
+ const providerBin = String(meta.provider_bin || providerId);
79
+ if (!providerPackage || !providerVersion || providerVersion === "0.0.0-managed") {
80
+ console.error(`NEXO managed MCP provider '${providerId}' is not staged and has no exact locked npm package.`);
81
+ process.exit(69);
82
+ }
83
+ const npxBin = process.platform === "win32" ? "npx.cmd" : "npx";
84
+ spawnProvider(npxBin, ["--yes", "--package", `${providerPackage}@${providerVersion}`, providerBin], env);
85
+ return;
86
+ }
87
+ spawnProvider(providerCommand, [], env);
88
+ }
89
+
90
+ main();
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.30.19",
3
+ "version": "7.30.21",
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",
7
7
  "bin": {
8
8
  "nexo-brain": "bin/nexo-brain.js",
9
- "nexo": "bin/nexo.js"
9
+ "nexo": "bin/nexo.js",
10
+ "nexo-managed-mcp": "bin/nexo-managed-mcp.js"
10
11
  },
11
12
  "keywords": [
12
13
  "claude-code",
@@ -78,6 +79,7 @@
78
79
  "files": [
79
80
  "bin/nexo-brain.js",
80
81
  "bin/nexo.js",
82
+ "bin/nexo-managed-mcp.js",
81
83
  "bin/windows-wsl-bridge.js",
82
84
  "bin/postinstall.js",
83
85
  "scripts/sync_release_artifacts.py",
@@ -2753,6 +2753,7 @@ def _f06_legacy_shim_map() -> list[tuple[str, Path]]:
2753
2753
  ("hooks", core_root / "hooks"),
2754
2754
  ("rules", core_root / "rules"),
2755
2755
  ("local_context", core_root / "local_context"),
2756
+ ("product_knowledge", core_root / "product_knowledge"),
2756
2757
  ("data", NEXO_HOME / "runtime" / "data"),
2757
2758
  ("logs", NEXO_HOME / "runtime" / "logs"),
2758
2759
  ("operations", NEXO_HOME / "runtime" / "operations"),
@@ -2822,6 +2823,7 @@ def _f06_live_legacy_paths() -> list[Path]:
2822
2823
  "hooks",
2823
2824
  "rules",
2824
2825
  "local_context",
2826
+ "product_knowledge",
2825
2827
  "db",
2826
2828
  "dashboard",
2827
2829
  "skills-core",
@@ -2907,6 +2909,7 @@ def _promote_packaged_runtime_code_to_core() -> None:
2907
2909
  ("doctor", core_root / "doctor"),
2908
2910
  ("dashboard", core_root / "dashboard"),
2909
2911
  ("local_context", core_root / "local_context"),
2912
+ ("product_knowledge", core_root / "product_knowledge"),
2910
2913
  ("skills-core", core_root / "skills"),
2911
2914
  ]
2912
2915
 
@@ -4740,6 +4743,7 @@ def _backup_runtime_tree(dest: Path = NEXO_HOME) -> str:
4740
4743
  "cognitive",
4741
4744
  "dashboard",
4742
4745
  "local_context",
4746
+ "product_knowledge",
4743
4747
  "rules",
4744
4748
  "crons",
4745
4749
  "scripts",
@@ -4819,7 +4823,18 @@ def _restore_runtime_tree(backup_dir: str, dest: Path = NEXO_HOME) -> None:
4819
4823
  def _copy_runtime_from_source(src_dir: Path, repo_dir: Path, dest: Path = NEXO_HOME, progress_fn=None) -> dict:
4820
4824
  import shutil
4821
4825
 
4822
- packages = ["db", "cognitive", "doctor", "local_context", "dashboard", "rules", "crons", "hooks", "presets"]
4826
+ packages = [
4827
+ "db",
4828
+ "cognitive",
4829
+ "doctor",
4830
+ "local_context",
4831
+ "product_knowledge",
4832
+ "dashboard",
4833
+ "rules",
4834
+ "crons",
4835
+ "hooks",
4836
+ "presets",
4837
+ ]
4823
4838
  flat_files = _runtime_flat_files(src_dir)
4824
4839
  copied_packages = 0
4825
4840
  copied_files = 0
@@ -23,6 +23,13 @@ except ModuleNotFoundError: # Python < 3.11
23
23
  from bootstrap_docs import sync_client_bootstrap
24
24
  from runtime_home import resolve_nexo_home
25
25
 
26
+ try:
27
+ from managed_mcp import build_managed_server_entries, merge_json_mcp_servers, merge_toml_mcp_servers
28
+ except Exception:
29
+ build_managed_server_entries = None
30
+ merge_json_mcp_servers = None
31
+ merge_toml_mcp_servers = None
32
+
26
33
  try:
27
34
  from client_preferences import (
28
35
  BACKEND_NONE,
@@ -832,6 +839,32 @@ def build_server_config(
832
839
  return config
833
840
 
834
841
 
842
+ def _managed_mcp_entries_for(client: str, server_config: dict) -> dict:
843
+ if str(os.environ.get("NEXO_MANAGED_MCP_DISABLE", "")).strip().lower() in {"1", "true", "yes", "on"}:
844
+ return {}
845
+ if not build_managed_server_entries:
846
+ return {}
847
+ env = server_config.get("env") if isinstance(server_config.get("env"), dict) else {}
848
+ nexo_home = str(env.get("NEXO_HOME") or "").strip()
849
+ runtime_root = str(env.get("NEXO_CODE") or "").strip()
850
+ if not nexo_home:
851
+ return {}
852
+ target_platform = str(
853
+ os.environ.get("NEXO_MANAGED_MCP_PLATFORM")
854
+ or env.get("NEXO_MANAGED_MCP_PLATFORM")
855
+ or ""
856
+ ).strip()
857
+ try:
858
+ return build_managed_server_entries(
859
+ client=client,
860
+ nexo_home=nexo_home,
861
+ runtime_root=runtime_root or None,
862
+ platform=target_platform or None,
863
+ )
864
+ except Exception:
865
+ return {}
866
+
867
+
835
868
  def _claude_code_settings_path(home: Path | None = None) -> Path:
836
869
  base = home or _user_home()
837
870
  return base / ".claude" / "settings.json"
@@ -1001,6 +1034,11 @@ def _sync_codex_managed_config(
1001
1034
  "env": dict(server_config.get("env", {}) or {}),
1002
1035
  }
1003
1036
  codex_table["managed_server_command"] = server_config.get("command", "")
1037
+ managed_entries = _managed_mcp_entries_for("codex", server_config)
1038
+ if managed_entries and merge_toml_mcp_servers:
1039
+ payload = merge_toml_mcp_servers(payload, managed_entries)
1040
+ codex_table = payload.setdefault("nexo", {}).setdefault("codex", {})
1041
+ codex_table["managed_default_mcp_count"] = len(managed_entries)
1004
1042
 
1005
1043
  # Ensure Codex headless crons (followup-runner, email-monitor, deep-sleep,
1006
1044
  # etc.) do not stall on approval prompts. Only set defaults when the user
@@ -1018,6 +1056,7 @@ def _sync_codex_managed_config(
1018
1056
  "hooks_enabled": True,
1019
1057
  "model": runtime_profile.get("model", ""),
1020
1058
  "reasoning_effort": runtime_profile.get("reasoning_effort", "") or "",
1059
+ "managed_default_mcp_count": len(_managed_mcp_entries_for("codex", server_config)) if server_config else 0,
1021
1060
  }
1022
1061
 
1023
1062
 
@@ -1408,12 +1447,16 @@ def _sync_json_client(path: Path, server_config: dict, label: str, *, managed_me
1408
1447
  nexo_meta = {}
1409
1448
  payload["nexo"] = nexo_meta
1410
1449
  nexo_meta.update(managed_metadata)
1450
+ managed_entries = _managed_mcp_entries_for(label, server_config)
1451
+ if managed_entries and merge_json_mcp_servers:
1452
+ payload = merge_json_mcp_servers(payload, managed_entries)
1411
1453
  _write_json_object(path, payload)
1412
1454
  return {
1413
1455
  "ok": True,
1414
1456
  "client": label,
1415
1457
  "action": action,
1416
1458
  "path": str(path),
1459
+ "managed_default_mcp_count": len(managed_entries),
1417
1460
  }
1418
1461
 
1419
1462
 
@@ -1491,6 +1534,9 @@ def _sync_claude_code_settings(path: Path, server_config: dict) -> dict:
1491
1534
  runtime_root=runtime_root,
1492
1535
  nexo_home=nexo_home,
1493
1536
  )
1537
+ managed_entries = _managed_mcp_entries_for("claude_code", server_config)
1538
+ if managed_entries and merge_json_mcp_servers:
1539
+ payload = merge_json_mcp_servers(payload, managed_entries)
1494
1540
  _ensure_headless_permissions(payload)
1495
1541
  _write_json_object(path, payload)
1496
1542
  return {
@@ -1499,6 +1545,7 @@ def _sync_claude_code_settings(path: Path, server_config: dict) -> dict:
1499
1545
  "action": action,
1500
1546
  "path": str(path),
1501
1547
  "managed_hook_count": managed_hook_count,
1548
+ "managed_default_mcp_count": len(managed_entries),
1502
1549
  }
1503
1550
 
1504
1551