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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +5 -1
- package/bin/nexo-brain.js +55 -0
- package/bin/postinstall.js +33 -1
- package/package.json +1 -1
- package/src/plugins/update.py +38 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.30.
|
|
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.
|
|
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);
|
package/bin/postinstall.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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",
|
package/src/plugins/update.py
CHANGED
|
@@ -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"):
|