nexo-brain 7.9.7 → 7.9.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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/bin/nexo-brain.js +72 -4
- package/package.json +1 -1
- package/src/auto_update.py +15 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.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,7 @@
|
|
|
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.9.
|
|
21
|
+
Version `7.9.9` is the current packaged-runtime line. Hotfix release over `7.9.8`: after the packaged updater fix, the installer now also repairs installs whose metadata already says the new version but whose active runtime still points to an older `~/.nexo/core/current -> versions/<old>`. Running `nexo-brain --yes` or the postinstall path now recopies the packaged runtime, re-activates `core/current`, and leaves installed users on the real new code instead of a stale snapshot. Coordinated Desktop v0.28.11 bundles the matching quit-path fix.
|
|
22
22
|
|
|
23
23
|
Previously in `7.9.5`: patch release that fixes canonical diary confirmation for Desktop: Brain resolves the Desktop/Claude session UUID through NEXO SID aliases before checking `session_diary`, so archive/delete/app-exit can confirm diaries written by `nexo_session_diary_write` under the active `nexo-...` SID. Verification: `pytest tests/test_lifecycle_events.py` (28 passing) plus coordinated Desktop v0.28.6 shutdown/archive/delete/app-exit checks.
|
|
24
24
|
|
package/bin/nexo-brain.js
CHANGED
|
@@ -684,6 +684,59 @@ function finalizeF06Layout(python, nexoHome = NEXO_HOME) {
|
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
686
|
|
|
687
|
+
function readRuntimeVersionFrom(basePath) {
|
|
688
|
+
if (!basePath) return "";
|
|
689
|
+
for (const candidate of [
|
|
690
|
+
path.join(basePath, "version.json"),
|
|
691
|
+
path.join(basePath, "package.json"),
|
|
692
|
+
]) {
|
|
693
|
+
try {
|
|
694
|
+
if (!fs.existsSync(candidate)) continue;
|
|
695
|
+
const payload = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
696
|
+
const version = String(payload.version || "").trim();
|
|
697
|
+
if (version) return version;
|
|
698
|
+
} catch (_) {}
|
|
699
|
+
}
|
|
700
|
+
return "";
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function readActiveRuntimeSnapshotVersion(nexoHome = NEXO_HOME) {
|
|
704
|
+
return readRuntimeVersionFrom(path.join(nexoHome, "core", "current"));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function activateVersionedRuntimeSnapshot(python, nexoHome = NEXO_HOME, version = "") {
|
|
708
|
+
try {
|
|
709
|
+
const srcDir = path.join(__dirname, "..", "src");
|
|
710
|
+
const inline = [
|
|
711
|
+
"import json, os, pathlib, sys",
|
|
712
|
+
`sys.path.insert(0, ${JSON.stringify(srcDir)})`,
|
|
713
|
+
"from runtime_versioning import activate_versioned_runtime_snapshot",
|
|
714
|
+
"home = pathlib.Path(os.environ['NEXO_HOME'])",
|
|
715
|
+
`result = activate_versioned_runtime_snapshot(source_root=home / 'core', version=${JSON.stringify(version)})`,
|
|
716
|
+
"print(json.dumps(result))",
|
|
717
|
+
].join("; ");
|
|
718
|
+
const result = spawnSync(python, ["-c", inline], {
|
|
719
|
+
cwd: nexoHome,
|
|
720
|
+
env: {
|
|
721
|
+
...process.env,
|
|
722
|
+
NEXO_HOME: nexoHome,
|
|
723
|
+
},
|
|
724
|
+
encoding: "utf8",
|
|
725
|
+
});
|
|
726
|
+
if (result.status !== 0) {
|
|
727
|
+
const detail = (result.stderr || result.stdout || "").trim();
|
|
728
|
+
throw new Error(detail || "activation command failed");
|
|
729
|
+
}
|
|
730
|
+
const payload = JSON.parse(String(result.stdout || "{}").trim() || "{}");
|
|
731
|
+
if (!payload || payload.ok !== true) {
|
|
732
|
+
throw new Error(payload && payload.error ? payload.error : "activation returned not-ok");
|
|
733
|
+
}
|
|
734
|
+
return payload;
|
|
735
|
+
} catch (err) {
|
|
736
|
+
return { ok: false, error: String((err && err.message) || err) };
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
687
740
|
function getCoreRuntimeFlatFiles(srcDir = path.join(__dirname, "..", "src")) {
|
|
688
741
|
const staticFiles = [
|
|
689
742
|
"server.py",
|
|
@@ -2296,10 +2349,17 @@ async function runSetup() {
|
|
|
2296
2349
|
const currentPkg = readPackageJson();
|
|
2297
2350
|
const installedVersion = installed.version || "0.0.0";
|
|
2298
2351
|
const currentVersion = currentPkg.version;
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2352
|
+
const activeRuntimeVersion = readActiveRuntimeSnapshotVersion(NEXO_HOME);
|
|
2353
|
+
const needsRuntimeRepair = activeRuntimeVersion !== currentVersion;
|
|
2354
|
+
|
|
2355
|
+
if (installedVersion !== currentVersion || needsRuntimeRepair) {
|
|
2356
|
+
if (installedVersion !== currentVersion) {
|
|
2357
|
+
log(`Existing installation detected: v${installedVersion} → v${currentVersion}`);
|
|
2358
|
+
log("Running auto-migration...");
|
|
2359
|
+
} else {
|
|
2360
|
+
log(`Existing installation detected: metadata v${installedVersion}, runtime core/current v${activeRuntimeVersion || "missing"}`);
|
|
2361
|
+
log("Repairing active runtime snapshot...");
|
|
2362
|
+
}
|
|
2303
2363
|
|
|
2304
2364
|
// Recursive copy helper (skips __pycache__, .pyc, .db files)
|
|
2305
2365
|
const srcDir = path.join(__dirname, "..", "src");
|
|
@@ -2469,6 +2529,9 @@ async function runSetup() {
|
|
|
2469
2529
|
installed_at: installed.installed_at,
|
|
2470
2530
|
updated_at: new Date().toISOString(),
|
|
2471
2531
|
migrated_from: installedVersion,
|
|
2532
|
+
...(installedVersion === currentVersion && activeRuntimeVersion && activeRuntimeVersion !== currentVersion
|
|
2533
|
+
? { runtime_repaired_from: activeRuntimeVersion }
|
|
2534
|
+
: {}),
|
|
2472
2535
|
}, null, 2));
|
|
2473
2536
|
syncRuntimePackageMetadata(path.join(__dirname, ".."), NEXO_HOME);
|
|
2474
2537
|
log("Finalizing F0.6 runtime layout...");
|
|
@@ -2476,6 +2539,11 @@ async function runSetup() {
|
|
|
2476
2539
|
if (!migLayoutFinalize.ok) {
|
|
2477
2540
|
throw new Error(`F0.6 layout finalization failed: ${migLayoutFinalize.error}`);
|
|
2478
2541
|
}
|
|
2542
|
+
const migActivation = activateVersionedRuntimeSnapshot(migPython, NEXO_HOME, currentVersion);
|
|
2543
|
+
if (!migActivation.ok) {
|
|
2544
|
+
throw new Error(`Runtime activation failed: ${migActivation.error}`);
|
|
2545
|
+
}
|
|
2546
|
+
log(` Runtime activation: core/current -> versions/${currentVersion}`);
|
|
2479
2547
|
|
|
2480
2548
|
// Keep the rendered template in-memory for version tracking, but do
|
|
2481
2549
|
// not drop a loose reference file in NEXO_HOME root.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.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",
|
package/src/auto_update.py
CHANGED
|
@@ -3956,6 +3956,13 @@ UPDATE_HISTORY_FILE = paths.logs_dir() / "update-history.jsonl"
|
|
|
3956
3956
|
def _resolve_sync_source() -> tuple[Path | None, Path | None]:
|
|
3957
3957
|
dest = NEXO_HOME
|
|
3958
3958
|
|
|
3959
|
+
def _is_relative_to(path: Path, parent: Path) -> bool:
|
|
3960
|
+
try:
|
|
3961
|
+
path.relative_to(parent)
|
|
3962
|
+
return True
|
|
3963
|
+
except Exception:
|
|
3964
|
+
return False
|
|
3965
|
+
|
|
3959
3966
|
def _runtime_version_source() -> Path | None:
|
|
3960
3967
|
for version_file in (NEXO_HOME / "version.json", NEXO_HOME / "core" / "version.json"):
|
|
3961
3968
|
if not version_file.is_file():
|
|
@@ -3974,16 +3981,21 @@ def _resolve_sync_source() -> tuple[Path | None, Path | None]:
|
|
|
3974
3981
|
|
|
3975
3982
|
try:
|
|
3976
3983
|
runtime_core = (dest / "core").resolve()
|
|
3984
|
+
runtime_versions = (runtime_core / "versions").resolve(strict=False)
|
|
3977
3985
|
code_resolved = NEXO_CODE.resolve()
|
|
3978
3986
|
except Exception:
|
|
3979
3987
|
runtime_core = dest / "core"
|
|
3988
|
+
runtime_versions = runtime_core / "versions"
|
|
3980
3989
|
code_resolved = NEXO_CODE
|
|
3981
3990
|
|
|
3982
3991
|
# Packaged/runtime-only installs resolve the launcher to ``~/.nexo/core``.
|
|
3983
3992
|
# Those must use the packaged updater path instead of treating the managed
|
|
3984
|
-
# runtime itself as a mutable source repository.
|
|
3985
|
-
#
|
|
3986
|
-
|
|
3993
|
+
# runtime itself as a mutable source repository. That also applies once the
|
|
3994
|
+
# launcher resolves through ``core/current`` into ``core/versions/X.Y.Z``:
|
|
3995
|
+
# the active snapshot is still managed runtime state, not a dev checkout.
|
|
3996
|
+
# Only a recorded external source repo in ``version.json`` should
|
|
3997
|
+
# reactivate source-sync mode.
|
|
3998
|
+
if code_resolved == runtime_core or _is_relative_to(code_resolved, runtime_versions):
|
|
3987
3999
|
version_source = _runtime_version_source()
|
|
3988
4000
|
if version_source:
|
|
3989
4001
|
return version_source / "src", version_source
|