nexo-brain 7.30.9 → 7.30.11

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.9",
3
+ "version": "7.30.11",
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,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.9` is the current packaged-runtime line. Patch release over v7.30.8 - post-update self-heal now stamps a verified repair baseline, and doctor release gates distinguish current installation failures from historical operator/session drift.
21
+ Version `7.30.11` is the current packaged-runtime line. Patch release over v7.30.10 - the installer and npm postinstall path now stamp the verified repair baseline too, so the first update from older packaged installs is covered without a manual second run.
22
+
23
+ Previously in `7.30.10`: patch release over v7.30.9 - packaged `nexo update` now stamps the verified repair baseline after import verification, including same-version maintenance runs.
24
+
25
+ Previously in `7.30.9`: patch release over v7.30.8 - post-update self-heal now stamps a verified repair baseline, and doctor release gates distinguish current installation failures from historical operator/session drift.
22
26
 
23
27
  Previously in `7.30.8`: patch release over v7.30.7 - Deep Sleep now folds parallel Codex sub-agents into their parent thread and Local Context stops the `entity_facts` cartesian blow-up that created runaway sidecar databases.
24
28
 
package/bin/nexo-brain.js CHANGED
@@ -949,6 +949,52 @@ function syncRuntimePackageMetadata(repoRoot = path.join(__dirname, ".."), runti
949
949
  }
950
950
  }
951
951
 
952
+ const REPAIR_BASELINE_FILE = "last-repair-baseline.json";
953
+
954
+ function _runtimeRepairBaselineDir(nexoHome = NEXO_HOME) {
955
+ const canonical = path.join(nexoHome, "runtime", "operations");
956
+ const legacy = path.join(nexoHome, "operations");
957
+ if (!fs.existsSync(path.join(nexoHome, "runtime")) && fs.existsSync(legacy)) {
958
+ return legacy;
959
+ }
960
+ return canonical;
961
+ }
962
+
963
+ function stampRuntimeRepairBaseline(nexoHome = NEXO_HOME, source = "bin.nexo-brain") {
964
+ try {
965
+ const operationsDir = _runtimeRepairBaselineDir(nexoHome);
966
+ fs.mkdirSync(operationsDir, { recursive: true });
967
+ const now = new Date();
968
+ const body = JSON.stringify({
969
+ last_repair_epoch: now.getTime() / 1000,
970
+ last_repair_at: now.toISOString().replace(/\.\d{3}Z$/, "Z"),
971
+ source,
972
+ reason: "verified runtime repair baseline after installer/postinstall repair",
973
+ }, null, 2) + "\n";
974
+ const baselinePath = path.join(operationsDir, REPAIR_BASELINE_FILE);
975
+ fs.writeFileSync(baselinePath, body);
976
+
977
+ const legacyDir = path.join(nexoHome, "operations");
978
+ const legacyPath = path.join(legacyDir, REPAIR_BASELINE_FILE);
979
+ if (legacyPath !== baselinePath && fs.existsSync(legacyDir)) {
980
+ try {
981
+ fs.writeFileSync(legacyPath, body);
982
+ } catch (_) {}
983
+ }
984
+ return { ok: true, path: baselinePath };
985
+ } catch (err) {
986
+ return { ok: false, error: String((err && err.message) || err) };
987
+ }
988
+ }
989
+
990
+ function logRepairBaselineStatus(result) {
991
+ if (result && result.ok) {
992
+ log(" Repair baseline: updated.");
993
+ } else {
994
+ log(` Repair baseline warning: ${(result && result.error) || "unknown error"}`);
995
+ }
996
+ }
997
+
952
998
  function resolveRuntimeConfigDir(nexoHome) {
953
999
  const canonical = path.join(nexoHome, "personal", "config");
954
1000
  const legacy = path.join(nexoHome, "config");
@@ -3286,6 +3332,9 @@ async function runSetup() {
3286
3332
  throw new Error(`Runtime activation failed: ${migActivation.error}`);
3287
3333
  }
3288
3334
  log(` Runtime activation: core/current -> versions/${currentVersion}`);
3335
+ logRepairBaselineStatus(
3336
+ stampRuntimeRepairBaseline(NEXO_HOME, "bin.nexo-brain.migration")
3337
+ );
3289
3338
 
3290
3339
  // Keep the rendered template in-memory for version tracking, but do
3291
3340
  // not drop a loose reference file in NEXO_HOME root.
@@ -3439,6 +3488,9 @@ async function runSetup() {
3439
3488
  if (!syncLayoutFinalize.ok) {
3440
3489
  throw new Error(`F0.6 layout finalization failed: ${syncLayoutFinalize.error}`);
3441
3490
  }
3491
+ logRepairBaselineStatus(
3492
+ stampRuntimeRepairBaseline(NEXO_HOME, "bin.nexo-brain.same-version-repair")
3493
+ );
3442
3494
 
3443
3495
  runDesktopAwareModelWarmup(syncPython, NEXO_HOME, { reason: "repair" });
3444
3496
  logMacPermissionsNotice(NEXO_HOME, syncPython);
@@ -5029,6 +5081,9 @@ See ~/.nexo/ for configuration.
5029
5081
  if (!layoutFinalize.ok) {
5030
5082
  throw new Error(`F0.6 layout finalization failed: ${layoutFinalize.error}`);
5031
5083
  }
5084
+ logRepairBaselineStatus(
5085
+ stampRuntimeRepairBaseline(NEXO_HOME, "bin.nexo-brain.install")
5086
+ );
5032
5087
 
5033
5088
  console.log("");
5034
5089
  const readyMsg = t.ready(operatorName, aliasName);
@@ -13,6 +13,7 @@ const { execFileSync } = require("child_process");
13
13
  const NEXO_HOME = process.env.NEXO_HOME || path.join(require("os").homedir(), ".nexo");
14
14
  const VERSION_FILE = path.join(NEXO_HOME, "version.json");
15
15
  const INSTALLER = path.join(__dirname, "nexo-brain.js");
16
+ const REPAIR_BASELINE_FILE = "last-repair-baseline.json";
16
17
 
17
18
  if (process.env.NEXO_SKIP_POSTINSTALL === "1") {
18
19
  // Called during rollback — skip migration to avoid loops
@@ -31,13 +32,44 @@ function runModelWarmup(reason) {
31
32
  });
32
33
  }
33
34
 
35
+ function runtimeRepairBaselineDir(nexoHome = NEXO_HOME) {
36
+ const canonical = path.join(nexoHome, "runtime", "operations");
37
+ const legacy = path.join(nexoHome, "operations");
38
+ if (!fs.existsSync(path.join(nexoHome, "runtime")) && fs.existsSync(legacy)) {
39
+ return legacy;
40
+ }
41
+ return canonical;
42
+ }
43
+
44
+ function stampRuntimeRepairBaseline(source = "bin.postinstall") {
45
+ const operationsDir = runtimeRepairBaselineDir(NEXO_HOME);
46
+ fs.mkdirSync(operationsDir, { recursive: true });
47
+ const now = new Date();
48
+ const body = JSON.stringify({
49
+ last_repair_epoch: now.getTime() / 1000,
50
+ last_repair_at: now.toISOString().replace(/\.\d{3}Z$/, "Z"),
51
+ source,
52
+ reason: "verified runtime repair baseline after installer/postinstall repair",
53
+ }, null, 2) + "\n";
54
+ const baselinePath = path.join(operationsDir, REPAIR_BASELINE_FILE);
55
+ fs.writeFileSync(baselinePath, body);
56
+
57
+ const legacyDir = path.join(NEXO_HOME, "operations");
58
+ const legacyPath = path.join(legacyDir, REPAIR_BASELINE_FILE);
59
+ if (legacyPath !== baselinePath && fs.existsSync(legacyDir)) {
60
+ try {
61
+ fs.writeFileSync(legacyPath, body);
62
+ } catch (_) {}
63
+ }
64
+ }
65
+
34
66
  if (fs.existsSync(VERSION_FILE)) {
35
67
  // Existing installation — run auto-migration silently
36
68
  const installed = JSON.parse(fs.readFileSync(VERSION_FILE, "utf8"));
37
69
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
38
70
 
39
71
  if (installed.version === pkg.version) {
40
- // Same version, nothing to do
72
+ stampRuntimeRepairBaseline("bin.postinstall.same-version");
41
73
  process.exit(0);
42
74
  }
43
75
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.30.9",
3
+ "version": "7.30.11",
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",
@@ -152,6 +152,23 @@ NEXO_HOME = export_resolved_nexo_home()
152
152
  DATA_DIR = paths.data_dir()
153
153
  BACKUP_BASE = paths.backups_dir()
154
154
  TECHNICAL_BACKUP_KEEP = 5
155
+ REPAIR_BASELINE_FILE = "last-repair-baseline.json"
156
+
157
+
158
+ def _stamp_runtime_repair_baseline(source: str = "plugins.update") -> str:
159
+ operations_dir = NEXO_HOME / "operations"
160
+ operations_dir.mkdir(parents=True, exist_ok=True)
161
+ now = time.time()
162
+ payload = {
163
+ "last_repair_epoch": now,
164
+ "last_repair_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(now)),
165
+ "source": source,
166
+ "reason": "verified runtime repair baseline after update/post-sync",
167
+ }
168
+ (operations_dir / REPAIR_BASELINE_FILE).write_text(
169
+ json.dumps(payload, indent=2, ensure_ascii=False) + "\n"
170
+ )
171
+ return "runtime-repair-baseline"
155
172
 
156
173
 
157
174
  def _env_int(name: str, default: int) -> int:
@@ -1454,6 +1471,13 @@ def _handle_packaged_update(progress_fn=None, *, include_clis: bool = True) -> s
1454
1471
  verify_err = _verify_import()
1455
1472
  if verify_err:
1456
1473
  errors.append(f"verification: {verify_err}")
1474
+ repair_baseline_warning = None
1475
+ if not verify_err:
1476
+ try:
1477
+ _emit_progress(progress_fn, "Stamping runtime repair baseline...")
1478
+ _stamp_runtime_repair_baseline("plugins.update._handle_packaged_update")
1479
+ except Exception as exc:
1480
+ repair_baseline_warning = f"{exc.__class__.__name__}: {exc}"
1457
1481
 
1458
1482
  hook_sync_warning = None
1459
1483
  cron_sync_warning = None
@@ -1616,6 +1640,10 @@ def _handle_packaged_update(progress_fn=None, *, include_clis: bool = True) -> s
1616
1640
  lines.append(" Clients: configured client targets synced")
1617
1641
  else:
1618
1642
  lines.append(f" WARNING: client sync: {client_sync_warning}")
1643
+ if not repair_baseline_warning:
1644
+ lines.append(" Repair baseline: updated")
1645
+ else:
1646
+ lines.append(f" WARNING: repair baseline: {repair_baseline_warning}")
1619
1647
  if launchagent_reload_summary and launchagent_reload_summary.get("scanned"):
1620
1648
  if not launchagent_reload_warning:
1621
1649
  lines.append(
@@ -1765,6 +1793,12 @@ def handle_update(
1765
1793
  if verify_err:
1766
1794
  raise RuntimeError(f"Verification failed: {verify_err}")
1767
1795
  steps_done.append("verify")
1796
+ try:
1797
+ _emit_progress(progress_fn, "Stamping runtime repair baseline...")
1798
+ _stamp_runtime_repair_baseline("plugins.update.handle_update")
1799
+ steps_done.append("runtime-repair-baseline")
1800
+ except Exception as e:
1801
+ steps_done.append(f"runtime-repair-baseline-warning:{e.__class__.__name__}")
1768
1802
 
1769
1803
  # Step 8: Sync crons with manifest
1770
1804
  cron_sync_result = ""
@@ -1929,6 +1963,8 @@ def handle_update(
1929
1963
  trailing.insert(2 if len(trailing) >= 2 else len(trailing), " Crons: synced with manifest")
1930
1964
  if "client-sync" in steps_done:
1931
1965
  trailing.append(" Clients: configured client targets synced")
1966
+ if "runtime-repair-baseline" in steps_done:
1967
+ trailing.append(" Repair baseline: updated")
1932
1968
  if trailing:
1933
1969
  msg += "\n" + "\n".join(trailing)
1934
1970
  return msg
@@ -1954,6 +1990,8 @@ def handle_update(
1954
1990
  lines.extend(external_cli_lines)
1955
1991
  if "client-sync" in steps_done:
1956
1992
  lines.append(" Clients: configured client targets synced")
1993
+ if "runtime-repair-baseline" in steps_done:
1994
+ lines.append(" Repair baseline: updated")
1957
1995
  if versioned_runtime_summary and versioned_runtime_summary.get("ok"):
1958
1996
  lines.append(f" Runtime activation: core/current -> versions/{new_version}")
1959
1997
  if version_prune_summary and version_prune_summary.get("pruned"):