nexo-brain 2.4.0 → 2.5.0
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/README.md +65 -2
- package/bin/nexo-brain.js +208 -11
- package/bin/nexo.js +55 -0
- package/community/skills/.gitkeep +1 -0
- package/package.json +5 -2
- package/src/auto_update.py +158 -8
- package/src/cli.py +605 -0
- package/src/cognitive/_ingest.py +1 -1
- package/src/cognitive/_memory.py +4 -4
- package/src/crons/manifest.json +8 -0
- package/src/dashboard/app.py +700 -35
- package/src/dashboard/templates/adaptive.html +112 -218
- package/src/dashboard/templates/artifacts.html +133 -0
- package/src/dashboard/templates/backups.html +136 -0
- package/src/dashboard/templates/base.html +413 -0
- package/src/dashboard/templates/calendar.html +523 -654
- package/src/dashboard/templates/chat.html +356 -0
- package/src/dashboard/templates/claims.html +259 -0
- package/src/dashboard/templates/cortex.html +262 -0
- package/src/dashboard/templates/credentials.html +128 -0
- package/src/dashboard/templates/crons.html +370 -0
- package/src/dashboard/templates/dashboard.html +383 -578
- package/src/dashboard/templates/dreams.html +252 -0
- package/src/dashboard/templates/email.html +160 -0
- package/src/dashboard/templates/evolution.html +189 -0
- package/src/dashboard/templates/feed.html +249 -0
- package/src/dashboard/templates/followup_health.html +170 -0
- package/src/dashboard/templates/graph.html +191 -269
- package/src/dashboard/templates/guard.html +259 -0
- package/src/dashboard/templates/inbox.html +220 -346
- package/src/dashboard/templates/memory.html +317 -197
- package/src/dashboard/templates/operations.html +521 -698
- package/src/dashboard/templates/plugins.html +185 -0
- package/src/dashboard/templates/rules.html +246 -0
- package/src/dashboard/templates/sentiment.html +247 -0
- package/src/dashboard/templates/sessions.html +215 -182
- package/src/dashboard/templates/skills.html +329 -0
- package/src/dashboard/templates/somatic.html +68 -172
- package/src/dashboard/templates/triggers.html +133 -0
- package/src/dashboard/templates/trust.html +360 -0
- package/src/db/__init__.py +5 -0
- package/src/db/_schema.py +16 -1
- package/src/db/_sessions.py +22 -0
- package/src/db/_skills.py +980 -274
- package/src/doctor/__init__.py +1 -0
- package/src/doctor/formatters.py +52 -0
- package/src/doctor/models.py +44 -0
- package/src/doctor/orchestrator.py +42 -0
- package/src/doctor/providers/__init__.py +1 -0
- package/src/doctor/providers/boot.py +206 -0
- package/src/doctor/providers/deep.py +292 -0
- package/src/doctor/providers/runtime.py +686 -0
- package/src/hooks/post-compact.sh +5 -1
- package/src/hooks/pre-compact.sh +1 -1
- package/src/plugins/doctor.py +36 -0
- package/src/plugins/evolution.py +2 -1
- package/src/plugins/skills.py +135 -175
- package/src/requirements.txt +1 -0
- package/src/script_registry.py +322 -0
- package/src/scripts/deep-sleep/apply_findings.py +63 -48
- package/src/scripts/deep-sleep/extract-prompt.md +14 -0
- package/src/scripts/deep-sleep/synthesize-prompt.md +36 -0
- package/src/scripts/deep-sleep/synthesize.py +37 -1
- package/src/scripts/nexo-dashboard.sh +29 -0
- package/src/scripts/nexo-day-orchestrator.sh +139 -0
- package/src/scripts/nexo-evolution-run.py +2 -1
- package/src/scripts/nexo-learning-housekeep.py +1 -1
- package/src/scripts/nexo-watchdog.sh +1 -1
- package/src/server.py +9 -5
- package/src/skills/run-runtime-doctor/guide.md +12 -0
- package/src/skills/run-runtime-doctor/script.py +21 -0
- package/src/skills/run-runtime-doctor/skill.json +25 -0
- package/src/skills_runtime.py +347 -0
- package/src/tools_menu.py +3 -2
- package/src/tools_sessions.py +126 -0
- package/src/user_context.py +46 -0
- package/templates/nexo_helper.py +45 -0
- package/templates/script-template.py +44 -0
- package/templates/skill-script-template.py +39 -0
- package/templates/skill-template.md +33 -0
package/src/auto_update.py
CHANGED
|
@@ -94,6 +94,61 @@ def _read_package_version() -> str:
|
|
|
94
94
|
return "unknown"
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
def _runtime_cli_wrapper_text() -> str:
|
|
98
|
+
return (
|
|
99
|
+
"#!/usr/bin/env bash\n"
|
|
100
|
+
"set -euo pipefail\n\n"
|
|
101
|
+
f'NEXO_HOME="{NEXO_HOME}"\n'
|
|
102
|
+
'PYTHON="$NEXO_HOME/.venv/bin/python3"\n'
|
|
103
|
+
'if [ ! -x "$PYTHON" ]; then\n'
|
|
104
|
+
' if command -v python3 >/dev/null 2>&1; then\n'
|
|
105
|
+
' PYTHON="python3"\n'
|
|
106
|
+
" else\n"
|
|
107
|
+
' PYTHON="python"\n'
|
|
108
|
+
" fi\n"
|
|
109
|
+
"fi\n"
|
|
110
|
+
'export NEXO_HOME\n'
|
|
111
|
+
'export NEXO_CODE="$NEXO_HOME"\n'
|
|
112
|
+
'exec "$PYTHON" "$NEXO_HOME/cli.py" "$@"\n'
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _shell_rc_files() -> list[Path]:
|
|
117
|
+
shell = os.environ.get("SHELL", "/bin/bash")
|
|
118
|
+
home_dir = Path.home()
|
|
119
|
+
if "zsh" in shell:
|
|
120
|
+
return [home_dir / ".zshrc"]
|
|
121
|
+
return [home_dir / ".bash_profile", home_dir / ".bashrc"]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _ensure_runtime_cli_in_shell():
|
|
125
|
+
path_line = f'export PATH="{NEXO_HOME / "bin"}:$PATH"'
|
|
126
|
+
comment = "# NEXO runtime CLI"
|
|
127
|
+
for rc_file in _shell_rc_files():
|
|
128
|
+
try:
|
|
129
|
+
content = rc_file.read_text() if rc_file.exists() else ""
|
|
130
|
+
if path_line not in content:
|
|
131
|
+
with rc_file.open("a") as fh:
|
|
132
|
+
fh.write(f"\n{comment}\n{path_line}\n")
|
|
133
|
+
_log(f"Backfilled runtime CLI PATH in {rc_file.name}")
|
|
134
|
+
except Exception as e:
|
|
135
|
+
_log(f"Shell PATH backfill error for {rc_file.name}: {e}")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _ensure_runtime_cli_wrapper():
|
|
139
|
+
try:
|
|
140
|
+
bin_dir = NEXO_HOME / "bin"
|
|
141
|
+
bin_dir.mkdir(parents=True, exist_ok=True)
|
|
142
|
+
wrapper = bin_dir / "nexo"
|
|
143
|
+
content = _runtime_cli_wrapper_text()
|
|
144
|
+
if not wrapper.exists() or wrapper.read_text() != content:
|
|
145
|
+
wrapper.write_text(content)
|
|
146
|
+
wrapper.chmod(0o755)
|
|
147
|
+
_log("Backfilled runtime CLI wrapper")
|
|
148
|
+
except Exception as e:
|
|
149
|
+
_log(f"Runtime CLI wrapper backfill error: {e}")
|
|
150
|
+
|
|
151
|
+
|
|
97
152
|
# ── Hook sync ────────────────────────────────────────────────────────
|
|
98
153
|
|
|
99
154
|
def _requirements_hash() -> str:
|
|
@@ -402,7 +457,12 @@ def _check_npm_version() -> str | None:
|
|
|
402
457
|
if not latest:
|
|
403
458
|
return None
|
|
404
459
|
if latest != current and not current.endswith(latest):
|
|
405
|
-
|
|
460
|
+
try:
|
|
461
|
+
from user_context import get_context
|
|
462
|
+
_name = get_context().assistant_name
|
|
463
|
+
except Exception:
|
|
464
|
+
_name = "NEXO"
|
|
465
|
+
return f"{_name} update available: {current} -> {latest}. Run: npm update -g {pkg_name}"
|
|
406
466
|
except Exception:
|
|
407
467
|
pass
|
|
408
468
|
return None
|
|
@@ -577,15 +637,12 @@ def _find_user_claude_md() -> Path | None:
|
|
|
577
637
|
|
|
578
638
|
def _resolve_placeholders(template_text: str) -> str:
|
|
579
639
|
"""Fill {{NAME}} and {{NEXO_HOME}} from the user's existing CLAUDE.md or config."""
|
|
580
|
-
#
|
|
581
|
-
name = "NEXO"
|
|
640
|
+
# Read operator name from calibration/version
|
|
582
641
|
try:
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
data = json.loads(vf.read_text())
|
|
586
|
-
name = data.get("operator_name", name)
|
|
642
|
+
from user_context import get_context
|
|
643
|
+
name = get_context().assistant_name
|
|
587
644
|
except Exception:
|
|
588
|
-
|
|
645
|
+
name = "NEXO"
|
|
589
646
|
|
|
590
647
|
return (
|
|
591
648
|
template_text
|
|
@@ -796,6 +853,99 @@ def auto_update_check() -> dict:
|
|
|
796
853
|
except Exception as e:
|
|
797
854
|
_log(f"scripts backfill error: {e}")
|
|
798
855
|
|
|
856
|
+
# Backfill runtime CLI modules for existing installs
|
|
857
|
+
try:
|
|
858
|
+
for fname in ("cli.py", "script_registry.py", "skills_runtime.py"):
|
|
859
|
+
src_file = SRC_DIR / fname
|
|
860
|
+
dest_file = NEXO_HOME / fname
|
|
861
|
+
if src_file.is_file() and (not dest_file.exists() or src_file.stat().st_mtime > dest_file.stat().st_mtime):
|
|
862
|
+
import shutil
|
|
863
|
+
shutil.copy2(str(src_file), str(dest_file))
|
|
864
|
+
_log(f"Backfilled {fname}")
|
|
865
|
+
except Exception as e:
|
|
866
|
+
_log(f"CLI backfill error: {e}")
|
|
867
|
+
|
|
868
|
+
_ensure_runtime_cli_wrapper()
|
|
869
|
+
_ensure_runtime_cli_in_shell()
|
|
870
|
+
|
|
871
|
+
# Backfill doctor package for existing installs
|
|
872
|
+
try:
|
|
873
|
+
doctor_src = SRC_DIR / "doctor"
|
|
874
|
+
doctor_dest = NEXO_HOME / "doctor"
|
|
875
|
+
if doctor_src.is_dir():
|
|
876
|
+
import shutil
|
|
877
|
+
if not doctor_dest.is_dir():
|
|
878
|
+
shutil.copytree(str(doctor_src), str(doctor_dest), ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
|
879
|
+
_log("Backfilled doctor package")
|
|
880
|
+
else:
|
|
881
|
+
# Update existing files
|
|
882
|
+
for root, dirs, files in os.walk(str(doctor_src)):
|
|
883
|
+
dirs[:] = [d for d in dirs if d != "__pycache__"]
|
|
884
|
+
rel = os.path.relpath(root, str(doctor_src))
|
|
885
|
+
dest_dir = doctor_dest / rel
|
|
886
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
887
|
+
for f in files:
|
|
888
|
+
if f.endswith(".pyc"):
|
|
889
|
+
continue
|
|
890
|
+
src_f = Path(root) / f
|
|
891
|
+
dst_f = dest_dir / f
|
|
892
|
+
if not dst_f.exists() or src_f.stat().st_mtime > dst_f.stat().st_mtime:
|
|
893
|
+
shutil.copy2(str(src_f), str(dst_f))
|
|
894
|
+
except Exception as e:
|
|
895
|
+
_log(f"Doctor backfill error: {e}")
|
|
896
|
+
|
|
897
|
+
# Backfill packaged core skills to a dedicated directory.
|
|
898
|
+
try:
|
|
899
|
+
skills_src = SRC_DIR / "skills"
|
|
900
|
+
skills_dest = NEXO_HOME / "skills-core"
|
|
901
|
+
if skills_src.is_dir():
|
|
902
|
+
import shutil
|
|
903
|
+
if not skills_dest.is_dir():
|
|
904
|
+
shutil.copytree(str(skills_src), str(skills_dest), ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
|
905
|
+
_log("Backfilled skills-core")
|
|
906
|
+
else:
|
|
907
|
+
for root, dirs, files in os.walk(str(skills_src)):
|
|
908
|
+
dirs[:] = [d for d in dirs if d != "__pycache__"]
|
|
909
|
+
rel = os.path.relpath(root, str(skills_src))
|
|
910
|
+
dest_dir = skills_dest / rel
|
|
911
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
912
|
+
for f in files:
|
|
913
|
+
if f.endswith(".pyc"):
|
|
914
|
+
continue
|
|
915
|
+
src_f = Path(root) / f
|
|
916
|
+
dst_f = dest_dir / f
|
|
917
|
+
if not dst_f.exists() or src_f.stat().st_mtime > dst_f.stat().st_mtime:
|
|
918
|
+
shutil.copy2(str(src_f), str(dst_f))
|
|
919
|
+
except Exception as e:
|
|
920
|
+
_log(f"Skills backfill error: {e}")
|
|
921
|
+
|
|
922
|
+
# Backfill MCP doctor plugin so existing installs expose nexo_doctor.
|
|
923
|
+
try:
|
|
924
|
+
plugin_src = SRC_DIR / "plugins" / "doctor.py"
|
|
925
|
+
plugin_dest = NEXO_HOME / "plugins" / "doctor.py"
|
|
926
|
+
plugin_dest.parent.mkdir(parents=True, exist_ok=True)
|
|
927
|
+
if plugin_src.is_file() and (not plugin_dest.exists() or plugin_src.stat().st_mtime > plugin_dest.stat().st_mtime):
|
|
928
|
+
import shutil
|
|
929
|
+
shutil.copy2(str(plugin_src), str(plugin_dest))
|
|
930
|
+
_log("Backfilled doctor plugin")
|
|
931
|
+
except Exception as e:
|
|
932
|
+
_log(f"Doctor plugin backfill error: {e}")
|
|
933
|
+
|
|
934
|
+
# Backfill script/skill templates for existing installs
|
|
935
|
+
try:
|
|
936
|
+
templates_src = REPO_DIR / "templates"
|
|
937
|
+
templates_dest = NEXO_HOME / "templates"
|
|
938
|
+
templates_dest.mkdir(parents=True, exist_ok=True)
|
|
939
|
+
for fname in ("script-template.py", "nexo_helper.py", "skill-template.md", "skill-script-template.py"):
|
|
940
|
+
src_file = templates_src / fname
|
|
941
|
+
dest_file = templates_dest / fname
|
|
942
|
+
if src_file.is_file() and (not dest_file.exists() or src_file.stat().st_mtime > dest_file.stat().st_mtime):
|
|
943
|
+
import shutil
|
|
944
|
+
shutil.copy2(str(src_file), str(dest_file))
|
|
945
|
+
_log(f"Backfilled template {fname}")
|
|
946
|
+
except Exception as e:
|
|
947
|
+
_log(f"Template backfill error: {e}")
|
|
948
|
+
|
|
799
949
|
# CLAUDE.md version migration
|
|
800
950
|
try:
|
|
801
951
|
result["claude_md_update"] = _migrate_claude_md()
|