nexo-brain 5.10.1 → 5.10.2

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.10.1",
3
+ "version": "5.10.2",
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 `5.10.1` is the current packaged-runtime line: silent, one-shot migration that recovers legacy `reasoning_effort="max"` (written by `nexo preferences --reasoning-effort max` before v5.9.0) into the new `preferences.default_resonance` map any user who had configured `max` before v5.9.0 and never touched the new selector was silently falling back to `DEFAULT_RESONANCE="alto"` on interactive calls since the v5.10.0 update. Now `_run_runtime_post_sync()` runs `_migrate_effort_to_resonance()` exactly once: `max→maximo`, `xhigh→alto`, `high→medio`, `medium→bajo`. No-op when calibration or schedule already declares an explicit `default_resonance`; idempotent; conservative; never raises.
21
+ Version `5.10.2` is the current packaged-runtime line: auto-bootstraps `brain/profile.json` from `brain/calibration.json` on `nexo update` when the profile file is missing, empty, or corrupt AND calibration carries at least one of `meta.role`, `meta.technical_level`, `name`, `language`. NEXO Desktop's *Preferencias Avanzado* tab used to render an empty `{}` for that block when the onboarding flow had been interrupted; now it either shows the seeded profile or a friendly explanation of what each file is for, paired with Desktop `v0.11.2` which adds header descriptions to both JSON blocks. Never overwrites a populated profile, never raises, idempotent. Also fixes a latent host-filesystem leak in `test_user_facing_caller_with_no_user_default_uses_alto` exposed by the v5.10.1 migration.
22
+
23
+ Previously in `5.10.1`: silent, one-shot migration that recovers legacy `reasoning_effort="max"` (written by `nexo preferences --reasoning-effort max` before v5.9.0) into the new `preferences.default_resonance` map — any user who had configured `max` before v5.9.0 and never touched the new selector was silently falling back to `DEFAULT_RESONANCE="alto"` on interactive calls since the v5.10.0 update. `_run_runtime_post_sync()` runs `_migrate_effort_to_resonance()` exactly once: `max→maximo`, `xhigh→alto`, `high→medio`, `medium→bajo`. No-op when calibration or schedule already declares an explicit `default_resonance`; idempotent; conservative; never raises.
22
24
 
23
25
  Previously in `5.10.0`: fixes the deep-sleep extract bloat that made Session 1 take ~57 minutes on some installs (new `bare_mode` on `run_automation_prompt` wires `claude --bare` for JSON-only extractor callers — ~4.3× faster per child, sourced from `ANTHROPIC_API_KEY` env or `~/.claude/anthropic-api-key.txt`). `caller=` is now **mandatory** on `run_automation_prompt` — no silent fallback; every automation subprocess traces back to a registered caller with a deliberate tier. Five personal scripts (`personal/email-monitor`, `personal/github-monitor`, `personal/post-x`, `personal/followup-runner`, `personal/orchestrator-v2`) joined the resonance map with tiers picked per caller based on what each one does. gbp/* marketing posts bumped from `medio` to `alto` (public-facing copy, quality first over speed). 65 legacy protocol debts bulk-resolved as part of the audit — the patterns that generated them are structurally closed by mandatory `caller=` + unified session log + bare_mode.
24
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "5.10.1",
3
+ "version": "5.10.2",
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",
@@ -973,6 +973,84 @@ def _migrate_effort_to_resonance(dest: Path = NEXO_HOME) -> list[str]:
973
973
  return actions
974
974
 
975
975
 
976
+ def _bootstrap_profile_from_calibration_meta(dest: Path = NEXO_HOME) -> list[str]:
977
+ """Create ``brain/profile.json`` from ``calibration.json`` fields when the
978
+ profile file does not exist yet.
979
+
980
+ Context: the onboarding flow documented in CLAUDE.md writes ``role`` and
981
+ ``technical_level`` to ``brain/profile.json``. Users who went through the
982
+ 2025/early-2026 flow (or whose onboarding was interrupted) ended up with
983
+ those values living under ``calibration.json → meta.role`` and
984
+ ``meta.technical_level`` only, with no ``profile.json`` file at all.
985
+ NEXO Desktop's "Preferencias → Avanzado" tab then shows an empty
986
+ ``{}`` for ``profile.json`` with no context — confusing for the operator.
987
+
988
+ This migration is conservative and idempotent:
989
+ - Only runs when ``profile.json`` does not exist (or is empty/invalid).
990
+ - Only writes when ``calibration.json`` has at least one of
991
+ ``meta.role`` / ``meta.technical_level`` / ``name`` / ``language``.
992
+ - Never overwrites an existing profile.
993
+ - Errors are swallowed into a ``profile-bootstrap-warning:*`` action
994
+ line; the update path never raises.
995
+ """
996
+ import json as _json
997
+
998
+ actions: list[str] = []
999
+
1000
+ cal_path = dest / "brain" / "calibration.json"
1001
+ profile_path = dest / "brain" / "profile.json"
1002
+
1003
+ if profile_path.exists():
1004
+ try:
1005
+ existing = _json.loads(profile_path.read_text())
1006
+ if isinstance(existing, dict) and existing:
1007
+ return actions # profile already populated, keep untouched
1008
+ except Exception:
1009
+ # Corrupt / empty file — fall through and rewrite below.
1010
+ pass
1011
+
1012
+ if not cal_path.exists():
1013
+ return actions
1014
+
1015
+ try:
1016
+ cal = _json.loads(cal_path.read_text())
1017
+ if not isinstance(cal, dict):
1018
+ return actions
1019
+ except Exception:
1020
+ return actions
1021
+
1022
+ meta = cal.get("meta") if isinstance(cal.get("meta"), dict) else {}
1023
+ payload: dict = {}
1024
+
1025
+ role = str(meta.get("role") or "").strip()
1026
+ tech = str(meta.get("technical_level") or "").strip()
1027
+ name = str(cal.get("name") or "").strip()
1028
+ lang = str(cal.get("language") or "").strip()
1029
+
1030
+ if role:
1031
+ payload["role"] = role
1032
+ if tech:
1033
+ payload["technical_level"] = tech
1034
+ if name:
1035
+ payload["name"] = name
1036
+ if lang:
1037
+ payload["language"] = lang
1038
+
1039
+ if not payload:
1040
+ return actions # nothing to seed the profile with
1041
+
1042
+ payload["source"] = "auto_update._bootstrap_profile_from_calibration_meta"
1043
+
1044
+ try:
1045
+ profile_path.parent.mkdir(parents=True, exist_ok=True)
1046
+ profile_path.write_text(_json.dumps(payload, indent=2, ensure_ascii=False) + "\n")
1047
+ actions.append(f"profile-bootstrap:{len(payload)-1}-fields")
1048
+ except Exception as exc:
1049
+ actions.append(f"profile-bootstrap-warning:{exc.__class__.__name__}")
1050
+
1051
+ return actions
1052
+
1053
+
976
1054
  def _heal_deep_sleep_runtime(dest: Path = NEXO_HOME) -> list[str]:
977
1055
  """Repair deep-sleep state that older runtimes left in a bad shape.
978
1056
 
@@ -2808,6 +2886,14 @@ def _run_runtime_post_sync(dest: Path = NEXO_HOME, progress_fn=None) -> tuple[bo
2808
2886
  except Exception as exc:
2809
2887
  actions.append(f"resonance-migration-warning:{exc.__class__.__name__}")
2810
2888
 
2889
+ try:
2890
+ _emit_progress(progress_fn, "Bootstrapping profile.json from calibration...")
2891
+ boot_actions = _bootstrap_profile_from_calibration_meta(dest)
2892
+ for action in boot_actions:
2893
+ actions.append(action)
2894
+ except Exception as exc:
2895
+ actions.append(f"profile-bootstrap-warning:{exc.__class__.__name__}")
2896
+
2811
2897
  _emit_progress(progress_fn, "Verifying runtime imports...")
2812
2898
  verify = subprocess.run(
2813
2899
  [sys.executable, "-c", "import server"],