nexo-brain 2.5.1 → 2.6.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/.claude-plugin/plugin.json +33 -0
- package/.mcp.json +12 -0
- package/README.md +38 -26
- package/bin/nexo-brain.js +35 -32
- package/hooks/hooks.json +14 -0
- package/package.json +11 -4
- package/src/auto_update.py +44 -1
- package/src/cli.py +388 -23
- package/src/cron_recovery.py +283 -0
- package/src/crons/manifest.json +79 -21
- package/src/crons/sync.py +132 -27
- package/src/db/__init__.py +11 -0
- package/src/db/_personal_scripts.py +548 -0
- package/src/db/_schema.py +44 -1
- package/src/doctor/providers/runtime.py +272 -75
- package/src/evolution_cycle.py +4 -1
- package/src/nexo.db +0 -0
- package/src/plugins/personal_scripts.py +117 -0
- package/src/plugins/schedule.py +116 -27
- package/src/script_registry.py +877 -28
- package/src/scripts/nexo-catchup.py +74 -109
- package/src/scripts/nexo-evolution-run.py +37 -12
- package/src/scripts/nexo-watchdog.sh +242 -54
- package/src/tools_learnings.py +8 -0
- package/templates/launchagents/com.nexo.catchup.plist +7 -6
- package/templates/script-template.py +3 -0
- package/templates/script-template.sh +13 -0
- package/src/scripts/nexo-day-orchestrator.sh +0 -139
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nexo-brain",
|
|
3
|
+
"version": "2.5.1",
|
|
4
|
+
"description": "Cognitive co-operator — persistent memory, learning, autonomous processes, Deep Sleep overnight analysis, unified diagnostics, executable skills, day orchestrator, and web dashboard for AI agents.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "NEXO Brain",
|
|
7
|
+
"email": "info@nexo-brain.com",
|
|
8
|
+
"url": "https://nexo-brain.com"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://nexo-brain.com",
|
|
11
|
+
"repository": "https://github.com/wazionapps/nexo",
|
|
12
|
+
"license": "AGPL-3.0",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"memory",
|
|
15
|
+
"cognitive",
|
|
16
|
+
"autonomous",
|
|
17
|
+
"deep-sleep",
|
|
18
|
+
"learning",
|
|
19
|
+
"mcp",
|
|
20
|
+
"work-continuity",
|
|
21
|
+
"skills",
|
|
22
|
+
"doctor",
|
|
23
|
+
"dashboard"
|
|
24
|
+
],
|
|
25
|
+
"mcpServers": "./.mcp.json",
|
|
26
|
+
"hooks": "./hooks/hooks.json",
|
|
27
|
+
"userConfig": {
|
|
28
|
+
"operator_name": {
|
|
29
|
+
"description": "What should your AI co-operator call itself? (default: NEXO)",
|
|
30
|
+
"sensitive": false
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/.mcp.json
ADDED
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://github.com/wazionapps/nexo/stargazers)
|
|
7
7
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
8
8
|
|
|
9
|
-
> The first AI memory system with architectural inhibitory control — the agent reasons about whether to act before acting. Cognitive Cortex, Context Continuity via auto-compaction hooks, Smart Startup, Context Packets, Auto-Prime, 30 Core Rules as DNA, auto-update, auto-diary,
|
|
9
|
+
> The first AI memory system with architectural inhibitory control — the agent reasons about whether to act before acting. Cognitive Cortex, Context Continuity via auto-compaction hooks, Smart Startup, Context Packets, Auto-Prime, 30 Core Rules as DNA, auto-update, auto-diary, CLAUDE.md version tracker, personal scripts registry, and Claude Code plugin structure. Battle-tested from 6 months of production use, validated via multi-AI debate.
|
|
10
10
|
|
|
11
11
|
**NEXO Brain transforms any MCP-compatible AI agent from a stateless assistant into a cognitive partner that remembers, learns, forgets, adapts, and builds a relationship with you over time.**
|
|
12
12
|
|
|
@@ -198,7 +198,7 @@ This means long sessions (8+ hours) feel like one continuous conversation instea
|
|
|
198
198
|
|
|
199
199
|
## Cognitive Features
|
|
200
200
|
|
|
201
|
-
NEXO Brain provides **
|
|
201
|
+
NEXO Brain provides **144+ MCP tools** across 20+ categories. These features implement cognitive science concepts that go beyond basic memory:
|
|
202
202
|
|
|
203
203
|
### Input Pipeline
|
|
204
204
|
|
|
@@ -269,7 +269,7 @@ Full results in [`benchmarks/locomo/results/`](benchmarks/locomo/results/).
|
|
|
269
269
|
|
|
270
270
|
## Nervous System (v2.0.0)
|
|
271
271
|
|
|
272
|
-
NEXO Brain doesn't just respond — it runs
|
|
272
|
+
NEXO Brain doesn't just respond — it runs 14 autonomous processes in the background, like a biological nervous system. They handle maintenance, health monitoring, and self-improvement without any user interaction:
|
|
273
273
|
|
|
274
274
|
| Script | Schedule | What It Does |
|
|
275
275
|
|--------|----------|-------------|
|
|
@@ -289,7 +289,7 @@ NEXO Brain doesn't just respond — it runs 15 autonomous processes in the backg
|
|
|
289
289
|
| **watchdog** | Every 30 min | Monitors services, LaunchAgents, and infrastructure health |
|
|
290
290
|
| **auto-close-sessions** | Every 5 min | Cleans stale sessions |
|
|
291
291
|
|
|
292
|
-
Core processes are defined in `src/crons/manifest.json` and auto-synced to your system by `nexo_update`. On macOS they run via LaunchAgents; on Linux via systemd user timers. `tcc-approve`, `prevent-sleep`, and `backup` are platform/personal helpers — not in the manifest but listed above for completeness. Personal
|
|
292
|
+
Core processes are defined in `src/crons/manifest.json` and auto-synced to your system by `nexo_update`. On macOS they run via LaunchAgents; on Linux via systemd user timers. `tcc-approve`, `prevent-sleep`, and `backup` are platform/personal helpers — not in the manifest but listed above for completeness. Personal scripts (your own automations) are tracked separately in the Personal Scripts Registry and never touched by the core sync. If your Mac was asleep during a scheduled process, the catch-up script re-runs everything in order when it wakes.
|
|
293
293
|
|
|
294
294
|
## Deep Sleep v2 — Overnight Learning (v2.1.0)
|
|
295
295
|
|
|
@@ -390,7 +390,7 @@ This opens `localhost:6174` in your browser. Add `--port 8080` to change the por
|
|
|
390
390
|
|
|
391
391
|
## Full Orchestration System
|
|
392
392
|
|
|
393
|
-
Memory alone doesn't make a co-operator. What makes the difference is the **behavioral loop** — the automated discipline that ensures every session starts informed, runs with guardrails, and ends with self-reflection.
|
|
393
|
+
Memory alone doesn't make a co-operator. What makes the difference is the **behavioral loop** — the automated discipline that ensures every session starts informed, runs with guardrails, and ends with self-reflection. The hooks and lifecycle below are built into the core product. The optional Day Orchestrator (autonomous headless cycles) was removed from core in v2.6.0 — power users can set it up as a personal script.
|
|
394
394
|
|
|
395
395
|
### Automated Hooks
|
|
396
396
|
|
|
@@ -501,7 +501,7 @@ The installer handles everything:
|
|
|
501
501
|
- Node.js project detected
|
|
502
502
|
Configuring MCP server...
|
|
503
503
|
Setting up nervous system...
|
|
504
|
-
|
|
504
|
+
14 autonomous processes configured.
|
|
505
505
|
Dashboard configured at localhost:6174.
|
|
506
506
|
Caffeinate enabled.
|
|
507
507
|
Generating operator instructions...
|
|
@@ -532,27 +532,31 @@ That's it. No need to run `claude` manually. Your operator will greet you immedi
|
|
|
532
532
|
| Component | What | Where |
|
|
533
533
|
|-----------|------|-------|
|
|
534
534
|
| Cognitive engine | Python: fastembed, numpy, vector search | pip packages |
|
|
535
|
-
| MCP server |
|
|
535
|
+
| MCP server | 144+ tools for memory, cognition, learning, guard | NEXO_HOME/ |
|
|
536
536
|
| Plugins | Guard, episodic memory, cognitive memory, entities, preferences, update, etc. | Code: src/plugins/, Personal: NEXO_HOME/plugins/ |
|
|
537
537
|
| Hooks (7) | SessionStart, Stop, PostToolUse, PreCompact, PostCompact | NEXO_HOME/hooks/ |
|
|
538
|
-
| Nervous system |
|
|
538
|
+
| Nervous system | 14 autonomous processes (decay, sleep, audit, evolution, watchdog, dashboard, etc.) | NEXO_HOME/scripts/ |
|
|
539
539
|
| Dashboard | Web UI at localhost:6174 (23 modules, dark theme) — opt-in, always-on | NEXO_HOME/dashboard/ |
|
|
540
|
-
| Runtime CLI | `nexo` command: scripts, doctor, skills, update | NEXO_HOME/bin/ |
|
|
540
|
+
| Runtime CLI | `nexo` command: chat, scripts, doctor, skills, update | NEXO_HOME/bin/ |
|
|
541
541
|
| Doctor | Unified diagnostics: boot/runtime/deep tiers, `--fix` mode | src/doctor/ |
|
|
542
542
|
| Skills v2 | Executable skills with guide/execute/hybrid modes, approval levels | NEXO_HOME/skills/ |
|
|
543
|
-
|
|
|
543
|
+
| Personal Scripts Registry | User-defined scripts tracked in SQLite with scheduling, reconciliation, and 9 MCP tools | NEXO_HOME/scripts/ |
|
|
544
544
|
| CLAUDE.md | Complete operator instructions (Codex, hooks, guard, trust, memory) | ~/.claude/CLAUDE.md |
|
|
545
545
|
| Schedule config | schedule.json with customizable process times and timezone | NEXO_HOME/config/ |
|
|
546
546
|
| Auto-update | Non-blocking startup check (5s max), opt-out via schedule.json | Built into server startup |
|
|
547
547
|
| CLAUDE.md tracker | Version-tracked core sections with safe updates preserving customizations | Built into auto-update |
|
|
548
548
|
| Auto-diary | 3-layer system: PostToolUse every 10 calls, PreCompact emergency, heartbeat DIARY_OVERDUE | Built into hooks |
|
|
549
|
-
| Claude Code config | MCP server + 7 hooks +
|
|
549
|
+
| Claude Code config | MCP server + 7 hooks + core processes registered | ~/.claude/settings.json |
|
|
550
550
|
|
|
551
551
|
### Runtime CLI
|
|
552
552
|
|
|
553
553
|
After installation or auto-update, NEXO adds `NEXO_HOME/bin` to your shell `PATH`. Open a new terminal and the `nexo` command provides operational tools:
|
|
554
554
|
|
|
555
555
|
```bash
|
|
556
|
+
# Claude Code
|
|
557
|
+
nexo chat # Launch Claude Code in the current directory
|
|
558
|
+
nexo chat ~/claude # Launch Claude Code in a specific directory
|
|
559
|
+
|
|
556
560
|
# Personal Scripts
|
|
557
561
|
nexo scripts list # List your personal scripts
|
|
558
562
|
nexo scripts run my-script # Run a script with injected NEXO env
|
|
@@ -574,7 +578,7 @@ nexo doctor --tier runtime --json # Machine-readable health report
|
|
|
574
578
|
nexo doctor --fix # Apply deterministic repairs
|
|
575
579
|
```
|
|
576
580
|
|
|
577
|
-
Personal scripts live in `NEXO_HOME/scripts/` with inline metadata. See `docs/writing-scripts.md` for details.
|
|
581
|
+
Personal scripts live in `NEXO_HOME/scripts/` with inline metadata and are tracked in a first-class registry (SQLite). 9 MCP tools manage the full lifecycle: `nexo_personal_scripts_list`, `nexo_personal_script_create`, `nexo_personal_script_remove`, `nexo_personal_scripts_reconcile`, `nexo_personal_scripts_sync`, `nexo_personal_scripts_classify`, `nexo_personal_script_schedules`, `nexo_personal_script_unschedule`, `nexo_personal_scripts_ensure_schedules`. See `docs/writing-scripts.md` for details.
|
|
578
582
|
|
|
579
583
|
Skills v2 combine procedural guides with optional executable scripts. Personal skills live in `NEXO_HOME/skills/`, packaged core skills live in `NEXO_CODE/skills/` during development and `NEXO_HOME/skills-core/` in installed environments, and staged runtime copies live in `NEXO_HOME/skills-runtime/`. Execution is fully autonomous: Deep Sleep can evolve mature guide skills into executable drafts automatically, and runtime execution no longer waits for manual approval. See `docs/skills-v2.md` for the full model.
|
|
580
584
|
|
|
@@ -584,7 +588,7 @@ The Doctor system reads existing health artifacts (immune, watchdog, self-audit)
|
|
|
584
588
|
|
|
585
589
|
- **macOS or Linux** (Windows via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install))
|
|
586
590
|
- **Node.js 18+** (for the installer)
|
|
587
|
-
- **Claude Opus (latest version) strongly recommended.** NEXO Brain provides
|
|
591
|
+
- **Claude Opus (latest version) strongly recommended.** NEXO Brain provides 144+ MCP tools across 20+ categories. This cognitive load requires a top-tier model with large context window. Smaller models (Haiku, Sonnet) may struggle with tool selection and produce inconsistent results. Opus handles all 144+ tools without hesitation.
|
|
588
592
|
- Python 3, Homebrew, and Claude Code are installed automatically if missing.
|
|
589
593
|
|
|
590
594
|
## Architecture
|
|
@@ -603,7 +607,7 @@ NEXO Brain separates **code** (immutable, in the repo or npm package) from **dat
|
|
|
603
607
|
|
|
604
608
|
The plugin loader scans `src/plugins/` first (base), then `NEXO_HOME/plugins/` (personal override by filename). This dual-directory approach lets you extend NEXO without forking the repo.
|
|
605
609
|
|
|
606
|
-
###
|
|
610
|
+
### 144+ MCP Tools across 20+ Categories
|
|
607
611
|
|
|
608
612
|
| Category | Count | Tools | Purpose |
|
|
609
613
|
|----------|-------|-------|---------|
|
|
@@ -628,6 +632,7 @@ The plugin loader scans `src/plugins/` first (base), then `NEXO_HOME/plugins/` (
|
|
|
628
632
|
| Adaptive & Somatic | 4 | adaptive_weights, adaptive_override, somatic_check, somatic_stats | Learned signal weights + pain memory per file |
|
|
629
633
|
| Knowledge Graph | 4 | kg_query, kg_path, kg_neighbors, kg_stats | Bi-temporal entity-relationship graph |
|
|
630
634
|
| Context Continuity | 2 | checkpoint_save, checkpoint_read | Auto-compaction session preservation |
|
|
635
|
+
| Personal Scripts | 9 | personal_scripts_list, personal_script_create, personal_script_remove, personal_scripts_reconcile, personal_scripts_sync, personal_scripts_classify, personal_script_schedules, personal_script_unschedule, personal_scripts_ensure_schedules | First-class script registry with lifecycle, scheduling, and reconciliation |
|
|
631
636
|
| Update | 1 | update | Pull latest code, backup, migrate, verify (with rollback) |
|
|
632
637
|
|
|
633
638
|
### Plugin System
|
|
@@ -686,7 +691,7 @@ NEXO Brain is designed as an MCP server. Claude Code is the primary supported cl
|
|
|
686
691
|
npx nexo-brain
|
|
687
692
|
```
|
|
688
693
|
|
|
689
|
-
All
|
|
694
|
+
All 144+ tools are available immediately after installation. The installer configures Claude Code's `~/.claude/settings.json` automatically.
|
|
690
695
|
|
|
691
696
|
### OpenClaw
|
|
692
697
|
|
|
@@ -782,24 +787,31 @@ If NEXO Brain is useful to you, consider:
|
|
|
782
787
|
|
|
783
788
|
[](https://star-history.com/#wazionapps/nexo&Date)
|
|
784
789
|
|
|
785
|
-
## Known Issues
|
|
790
|
+
## Known Issues
|
|
786
791
|
|
|
787
|
-
| Priority | Issue |
|
|
788
|
-
|
|
789
|
-
|
|
|
790
|
-
|
|
|
791
|
-
| P0 | Dashboard has no authentication (localhost only) | v2.1.0 |
|
|
792
|
-
| P0 | Database migrations are fail-open (errors logged but not blocking) | v2.1.0 |
|
|
792
|
+
| Priority | Issue | Status |
|
|
793
|
+
|----------|-------|--------|
|
|
794
|
+
| P1 | Credentials stored in plaintext SQLite — protect with filesystem permissions | Mitigated: secret redaction in tool logs (v2.4.0) |
|
|
795
|
+
| P2 | Dashboard has no authentication (localhost only) | By design — bind to localhost, no remote access |
|
|
793
796
|
|
|
794
797
|
## Changelog
|
|
795
798
|
|
|
799
|
+
### v2.6.0 — Personal Scripts Registry, Plugin Marketplace, Orchestrator Decoupled (2026-04-03)
|
|
800
|
+
- **Personal Scripts Registry**: First-class script tracking in SQLite with 9 MCP tools for full lifecycle management — create, list, remove, schedule, unschedule, reconcile, sync, classify.
|
|
801
|
+
- **Orchestrator removed from core**: Day Orchestrator decoupled from the product. Power users keep it as a personal script. Reduces complexity for standard installs.
|
|
802
|
+
- **Claude Code plugin structure**: `plugin.json` + entry point for Anthropic marketplace submission.
|
|
803
|
+
- **`nexo chat`**: Official CLI command to launch Claude Code with NEXO as operator.
|
|
804
|
+
- **Managed Evolution hardening**: Can now modify core behavior modules with rollback followups. Fixed false-positive watchdog tamper detection.
|
|
805
|
+
- **Cron reliability**: Hardened recovery, TCC diagnostics, keepalive sync, disabled optional cron respect.
|
|
806
|
+
- **Duplicate learning prevention**: Exact-title guard before insert.
|
|
807
|
+
|
|
796
808
|
### v2.5.0 — Runtime CLI, Doctor, Skills v2, Day Orchestrator (2026-04-03)
|
|
797
809
|
- **Runtime CLI** (`nexo`): New operational CLI separate from installer. `nexo scripts list/run/doctor/call` for personal scripts, `nexo doctor` for diagnostics, `nexo skills apply` for executable skills, `nexo update` for one-step sync.
|
|
798
810
|
- **Unified Doctor**: Modular diagnostic system with boot/runtime/deep tiers. Report-only by default, deterministic `--fix` mode. MCP tool `nexo_doctor`. LaunchAgent schedule drift detection and reconciliation.
|
|
799
811
|
- **Skills v2**: Executable skills with guide/execute/hybrid modes. Security levels (read-only/local/remote) with explicit approval. Core vs personal vs community directories. Deep Sleep auto-evolution integration.
|
|
800
|
-
- **Day Orchestrator**: Autonomous NEXO cycles every 15 min (8:00-23:00).
|
|
812
|
+
- **Day Orchestrator**: Autonomous NEXO cycles every 15 min (8:00-23:00). *(Removed from core in v2.6.0 — available as personal script.)*
|
|
801
813
|
- **Dashboard always-on**: Web UI at localhost:6174 as persistent LaunchAgent. 23 modules, Jinja2 templating, dark theme. Opt-in.
|
|
802
|
-
- **Personal Scripts Framework**: Auto-discovery in NEXO_HOME/scripts/, inline metadata, runtime detection, forbidden-pattern validation
|
|
814
|
+
- **Personal Scripts Framework**: Auto-discovery in NEXO_HOME/scripts/, inline metadata, runtime detection, forbidden-pattern validation. *(Promoted to first-class registry in v2.6.0.)*
|
|
803
815
|
- Configurable operator name (UserContext singleton), watchdog normalized to 30 min, LaunchAgent drift fix.
|
|
804
816
|
|
|
805
817
|
### v2.4.0 — Skills, Cron Scheduler, Security, Full Audit (2026-04-03)
|
|
@@ -824,9 +836,9 @@ If NEXO Brain is useful to you, consider:
|
|
|
824
836
|
- **Auto-diary**: 3-layer system — PostToolUse every 10 calls, PreCompact emergency save, heartbeat DIARY_OVERDUE signal.
|
|
825
837
|
- **CLAUDE.md version tracker**: Section markers enable safe core updates without losing user customizations.
|
|
826
838
|
- **schedule.json**: Customizable process schedules with timezone support and `auto_update` flag.
|
|
827
|
-
- **
|
|
839
|
+
- **14 autonomous processes**: Added auto-close-sessions, synthesis, backup, tcc-approve, prevent-sleep (cross-platform).
|
|
828
840
|
- **7 hooks**: SessionStart (timestamp + briefing), Stop, PostToolUse (capture + inbox), PreCompact, PostCompact.
|
|
829
|
-
- **
|
|
841
|
+
- **144+ MCP tools**: Added `nexo_update` tool for manual updates with rollback.
|
|
830
842
|
- **Lambda fix**: Decay values were 24x too aggressive (STM: 7h to 7d, LTM: 2.4d to 60d).
|
|
831
843
|
- **Guard scoping**: Was returning 35+ irrelevant blocking rules; now scoped to area and gated to high/critical.
|
|
832
844
|
- **12 rounds of external audit**: ~60 findings resolved.
|
package/bin/nexo-brain.js
CHANGED
|
@@ -87,13 +87,40 @@ function syncWatchdogHashRegistry(nexoHome) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function isProtectedMacPath(candidate) {
|
|
91
|
+
if (process.platform !== "darwin" || !candidate) return false;
|
|
92
|
+
const homeDir = require("os").homedir();
|
|
93
|
+
const expanded = candidate.replace(/^~/, homeDir);
|
|
94
|
+
const resolved = path.resolve(expanded);
|
|
95
|
+
const protectedRoots = [
|
|
96
|
+
path.join(homeDir, "Documents"),
|
|
97
|
+
path.join(homeDir, "Desktop"),
|
|
98
|
+
path.join(homeDir, "Downloads"),
|
|
99
|
+
path.join(homeDir, "Library", "Mobile Documents"),
|
|
100
|
+
];
|
|
101
|
+
return protectedRoots.some((root) => resolved === root || resolved.startsWith(`${root}${path.sep}`));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function logMacPermissionsNotice(nexoHome, pythonPath = "") {
|
|
105
|
+
if (!isProtectedMacPath(nexoHome)) return;
|
|
106
|
+
log("macOS protected-folder warning:");
|
|
107
|
+
log(` NEXO_HOME is inside a protected folder: ${nexoHome}`);
|
|
108
|
+
log(" Background jobs may fail with 'Operation not permitted'.");
|
|
109
|
+
log(" Recommended: move NEXO_HOME outside Documents/Desktop/Downloads/iCloud Drive.");
|
|
110
|
+
log(" If you keep it there, grant Full Disk Access to /bin/bash and your Python runtime.");
|
|
111
|
+
if (pythonPath) {
|
|
112
|
+
log(` Python runtime: ${pythonPath}`);
|
|
113
|
+
}
|
|
114
|
+
log(" System Settings → Privacy & Security → Full Disk Access");
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
91
118
|
// CORE PROCESS & HOOK DEFINITIONS
|
|
92
|
-
// All
|
|
119
|
+
// All core nightly/periodic processes and all 8 core hooks that make NEXO functional.
|
|
93
120
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
94
121
|
|
|
95
122
|
/**
|
|
96
|
-
* Complete definition of all
|
|
123
|
+
* Complete definition of all core NEXO automated processes.
|
|
97
124
|
* Each entry specifies the script, its interpreter ("python" or "bash"),
|
|
98
125
|
* the schedule type, and default schedule values.
|
|
99
126
|
*/
|
|
@@ -123,8 +150,6 @@ const ALL_PROCESSES = [
|
|
|
123
150
|
type: "keepAlive", purpose: "Keep machine awake for nocturnal processes" },
|
|
124
151
|
{ name: "dashboard", script: "nexo-dashboard.sh", interpreter: "bash", scriptDir: "scripts",
|
|
125
152
|
type: "keepAlive", optional: "dashboard", purpose: "Web dashboard at localhost:6174" },
|
|
126
|
-
{ name: "day-orchestrator", script: "nexo-day-orchestrator.sh", interpreter: "bash", scriptDir: "scripts",
|
|
127
|
-
type: "keepAlive", optional: "orchestrator", purpose: "Autonomous NEXO cycles every 15 min (8:00-23:00)" },
|
|
128
153
|
// --- Daily (times from schedule.json) ---
|
|
129
154
|
{ name: "cognitive-decay", script: "nexo-cognitive-decay.py", interpreter: "python", scriptDir: "scripts",
|
|
130
155
|
type: "daily", defaultHour: 3, defaultMinute: 0, purpose: "Memory decay" },
|
|
@@ -769,7 +794,7 @@ async function main() {
|
|
|
769
794
|
fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|
|
770
795
|
log(" All 8 core hooks registered in Claude Code settings.");
|
|
771
796
|
|
|
772
|
-
// Regenerate
|
|
797
|
+
// Regenerate all core LaunchAgents / systemd timers
|
|
773
798
|
const migSchedule = loadOrCreateSchedule(NEXO_HOME);
|
|
774
799
|
const migPython = findVenvPython(NEXO_HOME) || "python3";
|
|
775
800
|
let migOptionals = {};
|
|
@@ -893,6 +918,8 @@ async function main() {
|
|
|
893
918
|
});
|
|
894
919
|
}
|
|
895
920
|
|
|
921
|
+
logMacPermissionsNotice(NEXO_HOME, syncPython);
|
|
922
|
+
|
|
896
923
|
log(`Already at v${currentVersion}. No migration needed.`);
|
|
897
924
|
rl.close();
|
|
898
925
|
return;
|
|
@@ -937,6 +964,7 @@ async function main() {
|
|
|
937
964
|
}
|
|
938
965
|
const pyVersion = run(`${python} --version`);
|
|
939
966
|
log(`Found ${pyVersion} at ${python}`);
|
|
967
|
+
logMacPermissionsNotice(NEXO_HOME, python);
|
|
940
968
|
|
|
941
969
|
// Find or install Claude Code
|
|
942
970
|
let claudeInstalled = run("which claude");
|
|
@@ -1000,9 +1028,6 @@ async function main() {
|
|
|
1000
1028
|
dashboardQ: " Enable web dashboard at localhost:6174?\n (Always-on UI to explore memory, sessions, learnings, and system health)\n 1. Yes\n 2. No\n > ",
|
|
1001
1029
|
dashYes: "Dashboard enabled.",
|
|
1002
1030
|
dashNo: "Dashboard disabled. You can start it manually: nexo dashboard",
|
|
1003
|
-
orchestratorQ: " Enable autonomous mode? (I'll work on my own every 15 min: check followups, emails, infra, and report by email)\n 1. Yes\n 2. No\n > ",
|
|
1004
|
-
orchYes: "Autonomous mode enabled. I'll be working for you 8:00-23:00.",
|
|
1005
|
-
orchNo: "Autonomous mode disabled. I'll only work when you open a session.",
|
|
1006
1031
|
autoInstallQ: " Can I install tools automatically if I need them? (brew, pip, npm)\n 1. Yes, install whatever you need\n 2. Ask me before installing anything\n > ",
|
|
1007
1032
|
autoInstallYes: "Auto-install enabled.",
|
|
1008
1033
|
autoInstallNo: "I'll ask before installing.",
|
|
@@ -1035,9 +1060,6 @@ async function main() {
|
|
|
1035
1060
|
dashboardQ: " ¿Activar el dashboard web en localhost:6174?\n (UI siempre activa para explorar memoria, sesiones, learnings y salud del sistema)\n 1. Sí\n 2. No\n > ",
|
|
1036
1061
|
dashYes: "Dashboard activado.",
|
|
1037
1062
|
dashNo: "Dashboard desactivado. Puedes iniciarlo manualmente: nexo dashboard",
|
|
1038
|
-
orchestratorQ: " ¿Activar modo autónomo? (Trabajo solo cada 15 min: reviso followups, emails, infra, y te informo por email)\n 1. Sí\n 2. No\n > ",
|
|
1039
|
-
orchYes: "Modo autónomo activado. Estaré trabajando para ti de 8:00 a 23:00.",
|
|
1040
|
-
orchNo: "Modo autónomo desactivado. Solo trabajo cuando abras sesión.",
|
|
1041
1063
|
autoInstallQ: " ¿Puedo instalar herramientas automáticamente si las necesito? (brew, pip, npm)\n 1. Sí, instala lo que necesites\n 2. Pregúntame antes de instalar algo\n > ",
|
|
1042
1064
|
autoInstallYes: "Auto-instalación activada.",
|
|
1043
1065
|
autoInstallNo: "Te preguntaré antes.",
|
|
@@ -1070,9 +1092,6 @@ async function main() {
|
|
|
1070
1092
|
dashboardQ: " Activer le dashboard web sur localhost:6174 ?\n (UI toujours active pour explorer mémoire, sessions et santé du système)\n 1. Oui\n 2. Non\n > ",
|
|
1071
1093
|
dashYes: "Dashboard activé.",
|
|
1072
1094
|
dashNo: "Dashboard désactivé. Démarrage manuel : nexo dashboard",
|
|
1073
|
-
orchestratorQ: " Activer le mode autonome ? (Je travaille seul toutes les 15 min : followups, emails, infra, rapport par email)\n 1. Oui\n 2. Non\n > ",
|
|
1074
|
-
orchYes: "Mode autonome activé. Je travaille pour vous de 8h à 23h.",
|
|
1075
|
-
orchNo: "Mode autonome désactivé. Je travaille uniquement en session.",
|
|
1076
1095
|
autoInstallQ: " Puis-je installer des outils automatiquement ? (brew, pip, npm)\n 1. Oui\n 2. Demande-moi avant\n > ",
|
|
1077
1096
|
autoInstallYes: "Auto-installation activée.",
|
|
1078
1097
|
autoInstallNo: "Je demanderai avant.",
|
|
@@ -1105,9 +1124,6 @@ async function main() {
|
|
|
1105
1124
|
dashboardQ: " Web-Dashboard auf localhost:6174 aktivieren?\n (Immer aktive UI für Speicher, Sitzungen und Systemgesundheit)\n 1. Ja\n 2. Nein\n > ",
|
|
1106
1125
|
dashYes: "Dashboard aktiviert.",
|
|
1107
1126
|
dashNo: "Dashboard deaktiviert. Manuell starten: nexo dashboard",
|
|
1108
|
-
orchestratorQ: " Autonomen Modus aktivieren? (Ich arbeite alle 15 Min selbstständig: Followups, E-Mails, Infra, Bericht per E-Mail)\n 1. Ja\n 2. Nein\n > ",
|
|
1109
|
-
orchYes: "Autonomer Modus aktiviert. Ich arbeite für dich von 8:00 bis 23:00.",
|
|
1110
|
-
orchNo: "Autonomer Modus deaktiviert. Ich arbeite nur in Sitzungen.",
|
|
1111
1127
|
autoInstallQ: " Darf ich Tools automatisch installieren? (brew, pip, npm)\n 1. Ja\n 2. Frag mich vorher\n > ",
|
|
1112
1128
|
autoInstallYes: "Auto-Installation aktiviert.",
|
|
1113
1129
|
autoInstallNo: "Frage vorher.",
|
|
@@ -1140,9 +1156,6 @@ async function main() {
|
|
|
1140
1156
|
dashboardQ: " Attivare la dashboard web su localhost:6174?\n (UI sempre attiva per esplorare memoria, sessioni e salute del sistema)\n 1. Sì\n 2. No\n > ",
|
|
1141
1157
|
dashYes: "Dashboard attivata.",
|
|
1142
1158
|
dashNo: "Dashboard disattivata. Avvio manuale: nexo dashboard",
|
|
1143
|
-
orchestratorQ: " Attivare la modalità autonoma? (Lavoro da solo ogni 15 min: followup, email, infra, report via email)\n 1. Sì\n 2. No\n > ",
|
|
1144
|
-
orchYes: "Modalità autonoma attivata. Lavoro per te dalle 8:00 alle 23:00.",
|
|
1145
|
-
orchNo: "Modalità autonoma disattivata. Lavoro solo nelle sessioni.",
|
|
1146
1159
|
autoInstallQ: " Posso installare strumenti automaticamente? (brew, pip, npm)\n 1. Sì\n 2. Chiedimi prima\n > ",
|
|
1147
1160
|
autoInstallYes: "Auto-installazione attivata.",
|
|
1148
1161
|
autoInstallNo: "Chiederò prima.",
|
|
@@ -1175,9 +1188,6 @@ async function main() {
|
|
|
1175
1188
|
dashboardQ: " Ativar dashboard web em localhost:6174?\n (UI sempre ativa para explorar memória, sessões e saúde do sistema)\n 1. Sim\n 2. Não\n > ",
|
|
1176
1189
|
dashYes: "Dashboard ativado.",
|
|
1177
1190
|
dashNo: "Dashboard desativado. Iniciar manualmente: nexo dashboard",
|
|
1178
|
-
orchestratorQ: " Ativar modo autônomo? (Trabalho sozinho a cada 15 min: followups, emails, infra, relatório por email)\n 1. Sim\n 2. Não\n > ",
|
|
1179
|
-
orchYes: "Modo autônomo ativado. Trabalho para você das 8:00 às 23:00.",
|
|
1180
|
-
orchNo: "Modo autônomo desativado. Trabalho apenas nas sessões.",
|
|
1181
1191
|
autoInstallQ: " Posso instalar ferramentas automaticamente? (brew, pip, npm)\n 1. Sim\n 2. Pergunta antes\n > ",
|
|
1182
1192
|
autoInstallYes: "Auto-instalação ativada.",
|
|
1183
1193
|
autoInstallNo: "Perguntarei antes.",
|
|
@@ -1297,7 +1307,6 @@ async function main() {
|
|
|
1297
1307
|
let doScan = false;
|
|
1298
1308
|
let doCaffeinate = false;
|
|
1299
1309
|
let doDashboard = false;
|
|
1300
|
-
let doOrchestrator = false;
|
|
1301
1310
|
let autoInstall = "ask";
|
|
1302
1311
|
if (!useDefaults) {
|
|
1303
1312
|
const scanAnswer = await ask(t.scanQ);
|
|
@@ -1318,12 +1327,6 @@ async function main() {
|
|
|
1318
1327
|
log(doDashboard ? `✓ ${t.dashYes}` : t.dashNo);
|
|
1319
1328
|
console.log("");
|
|
1320
1329
|
|
|
1321
|
-
// Step 6c: Day Orchestrator — autonomous NEXO cycles
|
|
1322
|
-
const orchAnswer = await ask(t.orchestratorQ);
|
|
1323
|
-
doOrchestrator = orchAnswer.trim() === "1" || orchAnswer.trim().toLowerCase().startsWith("y") || orchAnswer.trim().toLowerCase().startsWith("s");
|
|
1324
|
-
log(doOrchestrator ? `✓ ${t.orchYes}` : t.orchNo);
|
|
1325
|
-
console.log("");
|
|
1326
|
-
|
|
1327
1330
|
// Step 7: Auto-install permission (P11)
|
|
1328
1331
|
const autoInstallAnswer = await ask(t.autoInstallQ);
|
|
1329
1332
|
autoInstall = (autoInstallAnswer.trim() === "1" || autoInstallAnswer.trim().toLowerCase().startsWith("y") || autoInstallAnswer.trim().toLowerCase().startsWith("s")) ? "auto" : "ask";
|
|
@@ -2062,10 +2065,10 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
2062
2065
|
fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|
|
2063
2066
|
log("MCP server + 8 core hooks configured in Claude Code settings.");
|
|
2064
2067
|
|
|
2065
|
-
// Step 7: Create schedule.json (only on fresh install) and install
|
|
2068
|
+
// Step 7: Create schedule.json (only on fresh install) and install core processes
|
|
2066
2069
|
log("Setting up automated processes...");
|
|
2067
2070
|
const schedule = loadOrCreateSchedule(NEXO_HOME);
|
|
2068
|
-
const enabledOptionals = { dashboard: doDashboard
|
|
2071
|
+
const enabledOptionals = { dashboard: doDashboard };
|
|
2069
2072
|
if (isEphemeralInstall(NEXO_HOME)) {
|
|
2070
2073
|
log("Ephemeral HOME/NEXO_HOME detected — skipping LaunchAgents installation.");
|
|
2071
2074
|
} else {
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/src/requirements.txt\" \"${CLAUDE_PLUGIN_DATA}/requirements.txt\" >/dev/null 2>&1 || (python3 -m venv \"${CLAUDE_PLUGIN_DATA}/.venv\" 2>/dev/null; cp \"${CLAUDE_PLUGIN_ROOT}/src/requirements.txt\" \"${CLAUDE_PLUGIN_DATA}/requirements.txt\"; \"${CLAUDE_PLUGIN_DATA}/.venv/bin/pip\" install --quiet -r \"${CLAUDE_PLUGIN_DATA}/requirements.txt\") || rm -f \"${CLAUDE_PLUGIN_DATA}/requirements.txt\""
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
|
-
"description": "NEXO — Cognitive co-operator for Claude Code. Memory, emotional intelligence, overnight learning (Deep Sleep), cron management, trust scoring, and adaptive calibration.",
|
|
5
|
+
"description": "NEXO — Cognitive co-operator for Claude Code. Memory, emotional intelligence, overnight learning (Deep Sleep), personal scripts registry, cron management, trust scoring, managed evolution, and adaptive calibration.",
|
|
6
6
|
"bin": {
|
|
7
7
|
"nexo-brain": "./bin/nexo-brain.js",
|
|
8
8
|
"nexo": "./bin/nexo.js"
|
|
@@ -43,8 +43,12 @@
|
|
|
43
43
|
"runtime-cli",
|
|
44
44
|
"doctor",
|
|
45
45
|
"executable-skills",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
46
|
+
"work-continuity",
|
|
47
|
+
"personal-scripts",
|
|
48
|
+
"script-registry",
|
|
49
|
+
"claude-code-plugin",
|
|
50
|
+
"managed-evolution",
|
|
51
|
+
"nexo-chat"
|
|
48
52
|
],
|
|
49
53
|
"author": "NEXO Brain <info@nexo-brain.com>",
|
|
50
54
|
"license": "AGPL-3.0",
|
|
@@ -68,6 +72,9 @@
|
|
|
68
72
|
"!src/**/*.pyc",
|
|
69
73
|
"!src/**/*.pyo",
|
|
70
74
|
"templates/",
|
|
75
|
+
".claude-plugin/",
|
|
76
|
+
".mcp.json",
|
|
77
|
+
"hooks/hooks.json",
|
|
71
78
|
"README.md",
|
|
72
79
|
"LICENSE"
|
|
73
80
|
]
|
package/src/auto_update.py
CHANGED
|
@@ -81,6 +81,29 @@ def _sync_watchdog_hash_registry():
|
|
|
81
81
|
_log(f"watchdog hash registry sync error: {e}")
|
|
82
82
|
|
|
83
83
|
|
|
84
|
+
def _warn_protected_runtime_location():
|
|
85
|
+
"""Log a targeted macOS TCC warning for risky NEXO_HOME locations."""
|
|
86
|
+
if sys.platform != "darwin":
|
|
87
|
+
return
|
|
88
|
+
try:
|
|
89
|
+
home = Path.home()
|
|
90
|
+
resolved = NEXO_HOME.resolve(strict=False)
|
|
91
|
+
protected_roots = (
|
|
92
|
+
home / "Documents",
|
|
93
|
+
home / "Desktop",
|
|
94
|
+
home / "Downloads",
|
|
95
|
+
home / "Library" / "Mobile Documents",
|
|
96
|
+
)
|
|
97
|
+
if any(resolved == root or root in resolved.parents for root in protected_roots):
|
|
98
|
+
_log(
|
|
99
|
+
"NEXO_HOME is inside a macOS protected folder. Background jobs may need Full Disk Access "
|
|
100
|
+
"for /bin/bash and the NEXO Python runtime, or NEXO_HOME should be moved outside "
|
|
101
|
+
"Documents/Desktop/Downloads/iCloud Drive."
|
|
102
|
+
)
|
|
103
|
+
except Exception as e:
|
|
104
|
+
_log(f"protected runtime warning skipped: {e}")
|
|
105
|
+
|
|
106
|
+
|
|
84
107
|
def _is_git_repo() -> bool:
|
|
85
108
|
"""Check if REPO_DIR is inside a git repository."""
|
|
86
109
|
try:
|
|
@@ -230,6 +253,24 @@ def _refresh_installed_manifest():
|
|
|
230
253
|
_log(f"Manifest refresh warning: {e}")
|
|
231
254
|
|
|
232
255
|
|
|
256
|
+
def _cleanup_retired_runtime_files():
|
|
257
|
+
"""Remove retired core files that should not survive updates."""
|
|
258
|
+
retired = [
|
|
259
|
+
NEXO_HOME / "scripts" / "nexo-day-orchestrator.sh",
|
|
260
|
+
]
|
|
261
|
+
for target in retired:
|
|
262
|
+
try:
|
|
263
|
+
if target.exists():
|
|
264
|
+
if target.is_dir():
|
|
265
|
+
import shutil
|
|
266
|
+
shutil.rmtree(target)
|
|
267
|
+
else:
|
|
268
|
+
target.unlink()
|
|
269
|
+
_log(f"Removed retired runtime file: {target.name}")
|
|
270
|
+
except Exception as e:
|
|
271
|
+
_log(f"Retired runtime cleanup warning ({target.name}): {e}")
|
|
272
|
+
|
|
273
|
+
|
|
233
274
|
def _sync_crons():
|
|
234
275
|
"""Sync cron definitions with manifest after a git pull."""
|
|
235
276
|
try:
|
|
@@ -244,6 +285,7 @@ def _sync_crons():
|
|
|
244
285
|
_log(f"Cron sync failed (exit {result.returncode}): {result.stderr or result.stdout}")
|
|
245
286
|
return # Don't refresh manifest if timers weren't actually updated
|
|
246
287
|
_log("Synced cron definitions with manifest")
|
|
288
|
+
_cleanup_retired_runtime_files()
|
|
247
289
|
# Refresh the installed manifest only after successful sync
|
|
248
290
|
_refresh_installed_manifest()
|
|
249
291
|
except Exception as e:
|
|
@@ -886,10 +928,11 @@ def auto_update_check() -> dict:
|
|
|
886
928
|
_log(f"scripts backfill error: {e}")
|
|
887
929
|
|
|
888
930
|
_sync_watchdog_hash_registry()
|
|
931
|
+
_warn_protected_runtime_location()
|
|
889
932
|
|
|
890
933
|
# Backfill runtime CLI modules for existing installs
|
|
891
934
|
try:
|
|
892
|
-
for fname in ("cli.py", "script_registry.py", "skills_runtime.py"):
|
|
935
|
+
for fname in ("cli.py", "script_registry.py", "skills_runtime.py", "cron_recovery.py"):
|
|
893
936
|
src_file = SRC_DIR / fname
|
|
894
937
|
dest_file = NEXO_HOME / fname
|
|
895
938
|
if src_file.is_file() and (not dest_file.exists() or src_file.stat().st_mtime > dest_file.stat().st_mtime):
|