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/README.md
CHANGED
|
@@ -341,7 +341,7 @@ Deep Sleep generates a `session-tone.json` that tells NEXO how to behave next mo
|
|
|
341
341
|
|
|
342
342
|
This is read by `nexo_smart_startup` and injected into every session's context. NEXO adapts its personality based on real behavioral data, not just configuration.
|
|
343
343
|
|
|
344
|
-
## Cron Manifest (v2.
|
|
344
|
+
## Cron Manifest & Scheduler (v2.4.0)
|
|
345
345
|
|
|
346
346
|
All core crons are defined in `src/crons/manifest.json`. When you run `nexo_update`, the sync script:
|
|
347
347
|
- **Installs** new crons from the manifest
|
|
@@ -349,7 +349,23 @@ All core crons are defined in `src/crons/manifest.json`. When you run `nexo_upda
|
|
|
349
349
|
- **Removes** crons no longer in the manifest (only core ones)
|
|
350
350
|
- **Never touches** personal crons you created yourself
|
|
351
351
|
|
|
352
|
-
|
|
352
|
+
Every cron execution is tracked in the `cron_runs` table via a universal wrapper. Use `nexo_schedule_status` to see what ran overnight:
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
✅ deep-sleep: 1/1 OK, 4523s avg — 37 sessions, 259 findings
|
|
356
|
+
✅ immune: 48/48 OK, 2s avg
|
|
357
|
+
❌ evolution: 0/1 OK — CLI timeout
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Add personal crons from conversation with `nexo_schedule_add` — generates LaunchAgent (macOS) or systemd timer (Linux) automatically.
|
|
361
|
+
|
|
362
|
+
## Skill Auto-Creation (v2.4.0)
|
|
363
|
+
|
|
364
|
+
Deep Sleep automatically extracts reusable procedures from successful multi-step tasks and stores them as skills with full procedural content (steps, gotchas, markdown).
|
|
365
|
+
|
|
366
|
+
Pipeline: `trace → draft → published → archived`. Trust rises with successful use, decays without it. No human approval gates.
|
|
367
|
+
|
|
368
|
+
7 MCP tools: `nexo_skill_create`, `nexo_skill_match`, `nexo_skill_get`, `nexo_skill_result`, `nexo_skill_list`, `nexo_skill_merge`, `nexo_skill_stats`.
|
|
353
369
|
|
|
354
370
|
## Dashboard (v1.6.0)
|
|
355
371
|
|
|
@@ -528,6 +544,38 @@ That's it. No need to run `claude` manually. Your operator will greet you immedi
|
|
|
528
544
|
| Auto-diary | 3-layer system: PostToolUse every 10 calls, PreCompact emergency, heartbeat DIARY_OVERDUE | Built into hooks |
|
|
529
545
|
| Claude Code config | MCP server + 7 hooks + 15 processes registered | ~/.claude/settings.json |
|
|
530
546
|
|
|
547
|
+
### Runtime CLI
|
|
548
|
+
|
|
549
|
+
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:
|
|
550
|
+
|
|
551
|
+
```bash
|
|
552
|
+
# Personal Scripts
|
|
553
|
+
nexo scripts list # List your personal scripts
|
|
554
|
+
nexo scripts run my-script # Run a script with injected NEXO env
|
|
555
|
+
nexo scripts doctor # Validate all personal scripts
|
|
556
|
+
nexo scripts call nexo_learning_search --input '{"query":"cron"}' # Call any MCP tool
|
|
557
|
+
|
|
558
|
+
# Skills v2
|
|
559
|
+
nexo skills sync # Sync filesystem skill definitions into SQLite
|
|
560
|
+
nexo skills list # List published/stable skills
|
|
561
|
+
nexo skills get SK-... # Inspect a skill definition
|
|
562
|
+
nexo skills apply SK-... --dry-run --json # Resolve guide/execute/hybrid without running it
|
|
563
|
+
nexo skills approve SK-... --execution-level local --approved-by Francisco # Optional metadata override
|
|
564
|
+
nexo skills evolution # Show text→script and improvement candidates
|
|
565
|
+
|
|
566
|
+
# Unified Doctor
|
|
567
|
+
nexo doctor # Quick boot diagnostics
|
|
568
|
+
nexo doctor --tier all # Full system check (boot + runtime + deep)
|
|
569
|
+
nexo doctor --tier runtime --json # Machine-readable health report
|
|
570
|
+
nexo doctor --fix # Apply deterministic repairs
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Personal scripts live in `NEXO_HOME/scripts/` with inline metadata. See `docs/writing-scripts.md` for details.
|
|
574
|
+
|
|
575
|
+
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.
|
|
576
|
+
|
|
577
|
+
The Doctor system reads existing health artifacts (immune, watchdog, self-audit) without triggering repairs in default mode.
|
|
578
|
+
|
|
531
579
|
### Requirements
|
|
532
580
|
|
|
533
581
|
- **macOS or Linux** (Windows via [WSL](https://learn.microsoft.com/en-us/windows/wsl/install))
|
|
@@ -741,6 +789,21 @@ If NEXO Brain is useful to you, consider:
|
|
|
741
789
|
|
|
742
790
|
## Changelog
|
|
743
791
|
|
|
792
|
+
### v2.4.0 — Skills, Cron Scheduler, Security, Full Audit (2026-04-03)
|
|
793
|
+
- **Skill Auto-Creation**: Deep Sleep extracts reusable procedures from sessions. Content stored as markdown with steps and gotchas. Trust pipeline with autonomous quality control.
|
|
794
|
+
- **Cron Scheduler**: execution tracking (`cron_runs` table), `nexo_schedule_status` and `nexo_schedule_add` MCP tools, universal cron wrapper for all processes.
|
|
795
|
+
- **Deep Sleep v2.4**: watermark-based collection (late-night sessions included), per-session checkpointing (crash-safe), retry x3, JSON parsing fix, auto-calibration of personality settings.
|
|
796
|
+
- **Security**: credential redaction in tool logs, transcript sanitization, command injection fix in dashboard, path traversal protection in plugin loader.
|
|
797
|
+
- **Diary filter**: startup only shows human sessions, auto-closed cron sessions filtered out. Email sessions preserved as real interactions.
|
|
798
|
+
- **Preflight CI**: 66 automated checks (py_compile, bash -n, manifest consistency, npm artifact, forbidden markers).
|
|
799
|
+
- **Python 3.9 compat**: `from __future__ import annotations` across 18 files.
|
|
800
|
+
- **Linux**: full systemd timer support, .bashrc alias for interactive shells.
|
|
801
|
+
- Passed 5-phase automated audit: Product, Failure, Security, Packaging, UX.
|
|
802
|
+
|
|
803
|
+
### v2.2.0 — Trust Score v2 (2026-04-01)
|
|
804
|
+
- **Trust Score**: fair daily calibration from Deep Sleep analysis. Score 0-100 based on corrections, autonomy, proactivity.
|
|
805
|
+
- **Cognitive Quarantine**: new memories go through quarantine before promotion to LTM.
|
|
806
|
+
|
|
744
807
|
### v2.0.0 — Unified Architecture (2026-03-31)
|
|
745
808
|
- **Code/data separation**: Code in repo (`src/`), personal data in `NEXO_HOME` (default `~/.nexo/`). `NEXO_HOME` env var required.
|
|
746
809
|
- **Plugin loader dual-directory**: Scans `src/plugins/` (base) then `NEXO_HOME/plugins/` (personal override by filename).
|
package/bin/nexo-brain.js
CHANGED
|
@@ -31,6 +31,13 @@ const LAUNCH_AGENTS = path.join(
|
|
|
31
31
|
"LaunchAgents"
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
function isEphemeralInstall(nexoHome) {
|
|
35
|
+
const homeDir = require("os").homedir();
|
|
36
|
+
const allowEphemeral = process.env.NEXO_ALLOW_EPHEMERAL_INSTALL === "1";
|
|
37
|
+
if (allowEphemeral) return false;
|
|
38
|
+
return nexoHome.startsWith("/tmp/") || homeDir.startsWith("/tmp/");
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
const rl = readline.createInterface({
|
|
35
42
|
input: process.stdin,
|
|
36
43
|
output: process.stdout,
|
|
@@ -66,9 +73,9 @@ const ALL_PROCESSES = [
|
|
|
66
73
|
// --- Every 5 minutes ---
|
|
67
74
|
{ name: "auto-close-sessions", script: "auto_close_sessions.py", interpreter: "python", scriptDir: "root",
|
|
68
75
|
type: "interval", intervalMinutes: 5, purpose: "Clean stale sessions" },
|
|
69
|
-
{ name: "watchdog", script: "nexo-watchdog.sh", interpreter: "bash", scriptDir: "scripts",
|
|
70
|
-
type: "interval", intervalMinutes: 5, purpose: "Health monitoring" },
|
|
71
76
|
// --- Every 30 minutes ---
|
|
77
|
+
{ name: "watchdog", script: "nexo-watchdog.sh", interpreter: "bash", scriptDir: "scripts",
|
|
78
|
+
type: "interval", intervalMinutes: 30, purpose: "Health monitoring" },
|
|
72
79
|
{ name: "immune", script: "nexo-immune.py", interpreter: "python", scriptDir: "scripts",
|
|
73
80
|
type: "interval", intervalMinutes: 30, purpose: "System immunity checks" },
|
|
74
81
|
// --- Every 2 hours ---
|
|
@@ -86,6 +93,10 @@ const ALL_PROCESSES = [
|
|
|
86
93
|
// --- KeepAlive (persistent daemon) ---
|
|
87
94
|
{ name: "prevent-sleep", script: "nexo-prevent-sleep.sh", interpreter: "bash", scriptDir: "scripts",
|
|
88
95
|
type: "keepAlive", purpose: "Keep machine awake for nocturnal processes" },
|
|
96
|
+
{ name: "dashboard", script: "nexo-dashboard.sh", interpreter: "bash", scriptDir: "scripts",
|
|
97
|
+
type: "keepAlive", optional: "dashboard", purpose: "Web dashboard at localhost:6174" },
|
|
98
|
+
{ name: "day-orchestrator", script: "nexo-day-orchestrator.sh", interpreter: "bash", scriptDir: "scripts",
|
|
99
|
+
type: "keepAlive", optional: "orchestrator", purpose: "Autonomous NEXO cycles every 15 min (8:00-23:00)" },
|
|
89
100
|
// --- Daily (times from schedule.json) ---
|
|
90
101
|
{ name: "cognitive-decay", script: "nexo-cognitive-decay.py", interpreter: "python", scriptDir: "scripts",
|
|
91
102
|
type: "daily", defaultHour: 3, defaultMinute: 0, purpose: "Memory decay" },
|
|
@@ -262,7 +273,7 @@ const DAY_MAP = {
|
|
|
262
273
|
* Linux+systemd: .service + .timer files
|
|
263
274
|
* Linux fallback: crontab entries
|
|
264
275
|
*/
|
|
265
|
-
function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAgentsDir) {
|
|
276
|
+
function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAgentsDir, enabledOptionals = {}) {
|
|
266
277
|
const home = require("os").homedir();
|
|
267
278
|
const nexoCode = nexoHome;
|
|
268
279
|
const logsDir = path.join(nexoHome, "logs");
|
|
@@ -298,6 +309,8 @@ function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAge
|
|
|
298
309
|
for (const proc of ALL_PROCESSES) {
|
|
299
310
|
// Skip macOnly processes on Linux
|
|
300
311
|
if (proc.macOnly && platform !== "darwin") continue;
|
|
312
|
+
// Skip optional processes that weren't enabled
|
|
313
|
+
if (proc.optional && !enabledOptionals[proc.optional]) continue;
|
|
301
314
|
|
|
302
315
|
const plistName = `com.nexo.${proc.name}.plist`;
|
|
303
316
|
const plistPath = path.join(launchAgentsDir, plistName);
|
|
@@ -404,6 +417,7 @@ function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAge
|
|
|
404
417
|
|
|
405
418
|
for (const proc of ALL_PROCESSES) {
|
|
406
419
|
if (proc.macOnly) continue; // tcc-approve is macOS only
|
|
420
|
+
if (proc.optional && !enabledOptionals[proc.optional]) continue;
|
|
407
421
|
const serviceName = `nexo-${proc.name}`;
|
|
408
422
|
const serviceFile = path.join(systemdDir, `${serviceName}.service`);
|
|
409
423
|
const timerFile = path.join(systemdDir, `${serviceName}.timer`);
|
|
@@ -481,6 +495,7 @@ WantedBy=timers.target
|
|
|
481
495
|
const envLine2 = `NEXO_CODE=${nexoCode}`;
|
|
482
496
|
|
|
483
497
|
for (const proc of ALL_PROCESSES) {
|
|
498
|
+
if (proc.optional && !enabledOptionals[proc.optional]) continue;
|
|
484
499
|
const sPath = scriptPath(proc);
|
|
485
500
|
const interp = interpreterPath(proc);
|
|
486
501
|
const s = getSchedule(proc);
|
|
@@ -729,8 +744,13 @@ async function main() {
|
|
|
729
744
|
// Regenerate ALL 13 LaunchAgents / systemd timers
|
|
730
745
|
const migSchedule = loadOrCreateSchedule(NEXO_HOME);
|
|
731
746
|
const migPython = findVenvPython(NEXO_HOME) || "python3";
|
|
732
|
-
|
|
733
|
-
|
|
747
|
+
let migOptionals = {};
|
|
748
|
+
try {
|
|
749
|
+
const optFile = path.join(NEXO_HOME, "config", "optionals.json");
|
|
750
|
+
if (fs.existsSync(optFile)) migOptionals = JSON.parse(fs.readFileSync(optFile, "utf8"));
|
|
751
|
+
} catch {}
|
|
752
|
+
installAllProcesses(platform, migPython, NEXO_HOME, migSchedule, LAUNCH_AGENTS, migOptionals);
|
|
753
|
+
log(" All automated processes updated.");
|
|
734
754
|
|
|
735
755
|
// Update version file
|
|
736
756
|
fs.writeFileSync(versionFile, JSON.stringify({
|
|
@@ -776,7 +796,7 @@ async function main() {
|
|
|
776
796
|
// Same version — backfill crons/ if missing (for installs before crons was shipped)
|
|
777
797
|
const cronsDest = path.join(NEXO_HOME, "crons");
|
|
778
798
|
const cronsSrc = path.join(__dirname, "..", "src", "crons");
|
|
779
|
-
if (
|
|
799
|
+
if (fs.existsSync(cronsSrc)) {
|
|
780
800
|
const copyDirRec2 = (src, dest) => {
|
|
781
801
|
fs.mkdirSync(dest, { recursive: true });
|
|
782
802
|
fs.readdirSync(src).forEach(item => {
|
|
@@ -788,7 +808,61 @@ async function main() {
|
|
|
788
808
|
});
|
|
789
809
|
};
|
|
790
810
|
copyDirRec2(cronsSrc, cronsDest);
|
|
791
|
-
log("
|
|
811
|
+
log("Refreshed crons/ directory.");
|
|
812
|
+
|
|
813
|
+
const cronSyncPath = path.join(cronsSrc, "sync.py");
|
|
814
|
+
const syncPython = findVenvPython(NEXO_HOME) || run("which python3") || "python3";
|
|
815
|
+
if (fs.existsSync(cronSyncPath)) {
|
|
816
|
+
const syncResult = spawnSync(syncPython, [cronSyncPath], {
|
|
817
|
+
env: { ...process.env, NEXO_HOME, NEXO_CODE: path.join(__dirname, "..", "src") },
|
|
818
|
+
stdio: "pipe",
|
|
819
|
+
encoding: "utf8",
|
|
820
|
+
});
|
|
821
|
+
if (syncResult.status === 0) {
|
|
822
|
+
log("Core crons reconciled with manifest.");
|
|
823
|
+
} else {
|
|
824
|
+
const syncErr = (syncResult.stderr || syncResult.stdout || "").trim();
|
|
825
|
+
log(`Cron sync warning: ${syncErr || `exit ${syncResult.status}`}`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Same version — refresh packaged core skills/templates/runtime helpers too.
|
|
831
|
+
const skillsCoreDest = path.join(NEXO_HOME, "skills-core");
|
|
832
|
+
const skillsCoreSrc = path.join(__dirname, "..", "src", "skills");
|
|
833
|
+
if (fs.existsSync(skillsCoreSrc)) {
|
|
834
|
+
const copyDirRec3 = (src, dest) => {
|
|
835
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
836
|
+
fs.readdirSync(src).forEach(item => {
|
|
837
|
+
if (item === "__pycache__" || item.endsWith(".pyc")) return;
|
|
838
|
+
const srcP = path.join(src, item);
|
|
839
|
+
const destP = path.join(dest, item);
|
|
840
|
+
if (fs.statSync(srcP).isDirectory()) copyDirRec3(srcP, destP);
|
|
841
|
+
else fs.copyFileSync(srcP, destP);
|
|
842
|
+
});
|
|
843
|
+
};
|
|
844
|
+
copyDirRec3(skillsCoreSrc, skillsCoreDest);
|
|
845
|
+
log("Refreshed skills-core/ directory.");
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
["skills_runtime.py"].forEach((fname) => {
|
|
849
|
+
const srcFile = path.join(__dirname, "..", "src", fname);
|
|
850
|
+
const destFile = path.join(NEXO_HOME, fname);
|
|
851
|
+
if (fs.existsSync(srcFile)) {
|
|
852
|
+
fs.copyFileSync(srcFile, destFile);
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
const templatesSrc = path.join(__dirname, "..", "templates");
|
|
857
|
+
const templatesDest = path.join(NEXO_HOME, "templates");
|
|
858
|
+
if (fs.existsSync(templatesSrc)) {
|
|
859
|
+
fs.mkdirSync(templatesDest, { recursive: true });
|
|
860
|
+
["script-template.py", "nexo_helper.py", "skill-template.md", "skill-script-template.py"].forEach((f) => {
|
|
861
|
+
const src = path.join(templatesSrc, f);
|
|
862
|
+
if (fs.existsSync(src)) {
|
|
863
|
+
fs.copyFileSync(src, path.join(templatesDest, f));
|
|
864
|
+
}
|
|
865
|
+
});
|
|
792
866
|
}
|
|
793
867
|
|
|
794
868
|
log(`Already at v${currentVersion}. No migration needed.`);
|
|
@@ -895,6 +969,12 @@ async function main() {
|
|
|
895
969
|
caffeinateQ: " Keep Mac awake for my cognitive processes at night?\n (I consolidate memory, clean duplicates, and discover connections while you sleep)\n 1. Yes\n 2. No\n > ",
|
|
896
970
|
caffYes: "Nocturnal processes scheduled.",
|
|
897
971
|
caffNo: "Ok, I'll run them when I can.",
|
|
972
|
+
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 > ",
|
|
973
|
+
dashYes: "Dashboard enabled.",
|
|
974
|
+
dashNo: "Dashboard disabled. You can start it manually: nexo dashboard",
|
|
975
|
+
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 > ",
|
|
976
|
+
orchYes: "Autonomous mode enabled. I'll be working for you 8:00-23:00.",
|
|
977
|
+
orchNo: "Autonomous mode disabled. I'll only work when you open a session.",
|
|
898
978
|
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 > ",
|
|
899
979
|
autoInstallYes: "Auto-install enabled.",
|
|
900
980
|
autoInstallNo: "I'll ask before installing.",
|
|
@@ -924,6 +1004,12 @@ async function main() {
|
|
|
924
1004
|
caffeinateQ: " ¿Mantengo el Mac despierto para mis procesos cognitivos nocturnos?\n (Consolido memoria, limpio duplicados y descubro conexiones mientras duermes)\n 1. Sí\n 2. No\n > ",
|
|
925
1005
|
caffYes: "Procesos nocturnos programados.",
|
|
926
1006
|
caffNo: "Ok, los ejecutaré cuando pueda.",
|
|
1007
|
+
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 > ",
|
|
1008
|
+
dashYes: "Dashboard activado.",
|
|
1009
|
+
dashNo: "Dashboard desactivado. Puedes iniciarlo manualmente: nexo dashboard",
|
|
1010
|
+
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 > ",
|
|
1011
|
+
orchYes: "Modo autónomo activado. Estaré trabajando para ti de 8:00 a 23:00.",
|
|
1012
|
+
orchNo: "Modo autónomo desactivado. Solo trabajo cuando abras sesión.",
|
|
927
1013
|
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 > ",
|
|
928
1014
|
autoInstallYes: "Auto-instalación activada.",
|
|
929
1015
|
autoInstallNo: "Te preguntaré antes.",
|
|
@@ -953,6 +1039,12 @@ async function main() {
|
|
|
953
1039
|
caffeinateQ: " Garder le Mac éveillé pour mes processus nocturnes ?\n 1. Oui\n 2. Non\n > ",
|
|
954
1040
|
caffYes: "Processus nocturnes programmés.",
|
|
955
1041
|
caffNo: "Ok, je les exécuterai quand possible.",
|
|
1042
|
+
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 > ",
|
|
1043
|
+
dashYes: "Dashboard activé.",
|
|
1044
|
+
dashNo: "Dashboard désactivé. Démarrage manuel : nexo dashboard",
|
|
1045
|
+
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 > ",
|
|
1046
|
+
orchYes: "Mode autonome activé. Je travaille pour vous de 8h à 23h.",
|
|
1047
|
+
orchNo: "Mode autonome désactivé. Je travaille uniquement en session.",
|
|
956
1048
|
autoInstallQ: " Puis-je installer des outils automatiquement ? (brew, pip, npm)\n 1. Oui\n 2. Demande-moi avant\n > ",
|
|
957
1049
|
autoInstallYes: "Auto-installation activée.",
|
|
958
1050
|
autoInstallNo: "Je demanderai avant.",
|
|
@@ -982,6 +1074,12 @@ async function main() {
|
|
|
982
1074
|
caffeinateQ: " Mac wach halten für nächtliche Prozesse?\n 1. Ja\n 2. Nein\n > ",
|
|
983
1075
|
caffYes: "Nachtprozesse geplant.",
|
|
984
1076
|
caffNo: "Ok, führe sie aus wenn möglich.",
|
|
1077
|
+
dashboardQ: " Web-Dashboard auf localhost:6174 aktivieren?\n (Immer aktive UI für Speicher, Sitzungen und Systemgesundheit)\n 1. Ja\n 2. Nein\n > ",
|
|
1078
|
+
dashYes: "Dashboard aktiviert.",
|
|
1079
|
+
dashNo: "Dashboard deaktiviert. Manuell starten: nexo dashboard",
|
|
1080
|
+
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 > ",
|
|
1081
|
+
orchYes: "Autonomer Modus aktiviert. Ich arbeite für dich von 8:00 bis 23:00.",
|
|
1082
|
+
orchNo: "Autonomer Modus deaktiviert. Ich arbeite nur in Sitzungen.",
|
|
985
1083
|
autoInstallQ: " Darf ich Tools automatisch installieren? (brew, pip, npm)\n 1. Ja\n 2. Frag mich vorher\n > ",
|
|
986
1084
|
autoInstallYes: "Auto-Installation aktiviert.",
|
|
987
1085
|
autoInstallNo: "Frage vorher.",
|
|
@@ -1011,6 +1109,12 @@ async function main() {
|
|
|
1011
1109
|
caffeinateQ: " Tenere il Mac sveglio per i processi notturni?\n 1. Sì\n 2. No\n > ",
|
|
1012
1110
|
caffYes: "Processi notturni programmati.",
|
|
1013
1111
|
caffNo: "Ok, li eseguirò quando possibile.",
|
|
1112
|
+
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 > ",
|
|
1113
|
+
dashYes: "Dashboard attivata.",
|
|
1114
|
+
dashNo: "Dashboard disattivata. Avvio manuale: nexo dashboard",
|
|
1115
|
+
orchestratorQ: " Attivare la modalità autonoma? (Lavoro da solo ogni 15 min: followup, email, infra, report via email)\n 1. Sì\n 2. No\n > ",
|
|
1116
|
+
orchYes: "Modalità autonoma attivata. Lavoro per te dalle 8:00 alle 23:00.",
|
|
1117
|
+
orchNo: "Modalità autonoma disattivata. Lavoro solo nelle sessioni.",
|
|
1014
1118
|
autoInstallQ: " Posso installare strumenti automaticamente? (brew, pip, npm)\n 1. Sì\n 2. Chiedimi prima\n > ",
|
|
1015
1119
|
autoInstallYes: "Auto-installazione attivata.",
|
|
1016
1120
|
autoInstallNo: "Chiederò prima.",
|
|
@@ -1040,6 +1144,12 @@ async function main() {
|
|
|
1040
1144
|
caffeinateQ: " Manter o Mac acordado para processos noturnos?\n 1. Sim\n 2. Não\n > ",
|
|
1041
1145
|
caffYes: "Processos noturnos agendados.",
|
|
1042
1146
|
caffNo: "Ok, executo quando possível.",
|
|
1147
|
+
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 > ",
|
|
1148
|
+
dashYes: "Dashboard ativado.",
|
|
1149
|
+
dashNo: "Dashboard desativado. Iniciar manualmente: nexo dashboard",
|
|
1150
|
+
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 > ",
|
|
1151
|
+
orchYes: "Modo autônomo ativado. Trabalho para você das 8:00 às 23:00.",
|
|
1152
|
+
orchNo: "Modo autônomo desativado. Trabalho apenas nas sessões.",
|
|
1043
1153
|
autoInstallQ: " Posso instalar ferramentas automaticamente? (brew, pip, npm)\n 1. Sim\n 2. Pergunta antes\n > ",
|
|
1044
1154
|
autoInstallYes: "Auto-instalação ativada.",
|
|
1045
1155
|
autoInstallNo: "Perguntarei antes.",
|
|
@@ -1158,6 +1268,8 @@ async function main() {
|
|
|
1158
1268
|
// Step 5: Deep scan (P9)
|
|
1159
1269
|
let doScan = false;
|
|
1160
1270
|
let doCaffeinate = false;
|
|
1271
|
+
let doDashboard = false;
|
|
1272
|
+
let doOrchestrator = false;
|
|
1161
1273
|
let autoInstall = "ask";
|
|
1162
1274
|
if (!useDefaults) {
|
|
1163
1275
|
const scanAnswer = await ask(t.scanQ);
|
|
@@ -1172,6 +1284,18 @@ async function main() {
|
|
|
1172
1284
|
console.log("");
|
|
1173
1285
|
}
|
|
1174
1286
|
|
|
1287
|
+
// Step 6b: Dashboard — always-on web UI
|
|
1288
|
+
const dashAnswer = await ask(t.dashboardQ);
|
|
1289
|
+
doDashboard = dashAnswer.trim() === "1" || dashAnswer.trim().toLowerCase().startsWith("y") || dashAnswer.trim().toLowerCase().startsWith("s");
|
|
1290
|
+
log(doDashboard ? `✓ ${t.dashYes}` : t.dashNo);
|
|
1291
|
+
console.log("");
|
|
1292
|
+
|
|
1293
|
+
// Step 6c: Day Orchestrator — autonomous NEXO cycles
|
|
1294
|
+
const orchAnswer = await ask(t.orchestratorQ);
|
|
1295
|
+
doOrchestrator = orchAnswer.trim() === "1" || orchAnswer.trim().toLowerCase().startsWith("y") || orchAnswer.trim().toLowerCase().startsWith("s");
|
|
1296
|
+
log(doOrchestrator ? `✓ ${t.orchYes}` : t.orchNo);
|
|
1297
|
+
console.log("");
|
|
1298
|
+
|
|
1175
1299
|
// Step 7: Auto-install permission (P11)
|
|
1176
1300
|
const autoInstallAnswer = await ask(t.autoInstallQ);
|
|
1177
1301
|
autoInstall = (autoInstallAnswer.trim() === "1" || autoInstallAnswer.trim().toLowerCase().startsWith("y") || autoInstallAnswer.trim().toLowerCase().startsWith("s")) ? "auto" : "ask";
|
|
@@ -1224,8 +1348,12 @@ async function main() {
|
|
|
1224
1348
|
log("Setting up NEXO home...");
|
|
1225
1349
|
const dirs = [
|
|
1226
1350
|
NEXO_HOME,
|
|
1351
|
+
path.join(NEXO_HOME, "bin"),
|
|
1227
1352
|
path.join(NEXO_HOME, "plugins"),
|
|
1228
1353
|
path.join(NEXO_HOME, "scripts"),
|
|
1354
|
+
path.join(NEXO_HOME, "skills"),
|
|
1355
|
+
path.join(NEXO_HOME, "skills-core"),
|
|
1356
|
+
path.join(NEXO_HOME, "skills-runtime"),
|
|
1229
1357
|
path.join(NEXO_HOME, "logs"),
|
|
1230
1358
|
path.join(NEXO_HOME, "backups"),
|
|
1231
1359
|
path.join(NEXO_HOME, "coordination"),
|
|
@@ -1275,6 +1403,7 @@ async function main() {
|
|
|
1275
1403
|
const srcDir = path.join(__dirname, "..", "src");
|
|
1276
1404
|
const pluginsSrcDir = path.join(srcDir, "plugins");
|
|
1277
1405
|
const scriptsSrcDir = path.join(srcDir, "scripts");
|
|
1406
|
+
const skillsSrcDir = path.join(srcDir, "skills");
|
|
1278
1407
|
const templateDir = path.join(__dirname, "..", "templates");
|
|
1279
1408
|
|
|
1280
1409
|
// Recursive copy helper (skips __pycache__, .pyc, .db files)
|
|
@@ -1315,6 +1444,9 @@ async function main() {
|
|
|
1315
1444
|
"tools_task_history.py",
|
|
1316
1445
|
"tools_menu.py",
|
|
1317
1446
|
"requirements.txt",
|
|
1447
|
+
"cli.py",
|
|
1448
|
+
"script_registry.py",
|
|
1449
|
+
"skills_runtime.py",
|
|
1318
1450
|
];
|
|
1319
1451
|
coreFiles.forEach((f) => {
|
|
1320
1452
|
const src = path.join(srcDir, f);
|
|
@@ -1323,8 +1455,31 @@ async function main() {
|
|
|
1323
1455
|
}
|
|
1324
1456
|
});
|
|
1325
1457
|
|
|
1458
|
+
// Runtime CLI wrapper lives in NEXO_HOME/bin so it survives npx installs.
|
|
1459
|
+
const runtimeCli = [
|
|
1460
|
+
"#!/usr/bin/env bash",
|
|
1461
|
+
"set -euo pipefail",
|
|
1462
|
+
"",
|
|
1463
|
+
`NEXO_HOME="${NEXO_HOME}"`,
|
|
1464
|
+
'PYTHON="$NEXO_HOME/.venv/bin/python3"',
|
|
1465
|
+
'if [ ! -x "$PYTHON" ]; then',
|
|
1466
|
+
' if command -v python3 >/dev/null 2>&1; then',
|
|
1467
|
+
' PYTHON="python3"',
|
|
1468
|
+
" else",
|
|
1469
|
+
' PYTHON="python"',
|
|
1470
|
+
" fi",
|
|
1471
|
+
"fi",
|
|
1472
|
+
'export NEXO_HOME',
|
|
1473
|
+
'export NEXO_CODE="$NEXO_HOME"',
|
|
1474
|
+
'exec "$PYTHON" "$NEXO_HOME/cli.py" "$@"',
|
|
1475
|
+
"",
|
|
1476
|
+
].join("\n");
|
|
1477
|
+
const runtimeCliPath = path.join(NEXO_HOME, "bin", "nexo");
|
|
1478
|
+
fs.writeFileSync(runtimeCliPath, runtimeCli);
|
|
1479
|
+
fs.chmodSync(runtimeCliPath, 0o755);
|
|
1480
|
+
|
|
1326
1481
|
// Core packages (directories with __init__.py)
|
|
1327
|
-
["db", "cognitive"].forEach(pkg => {
|
|
1482
|
+
["db", "cognitive", "doctor"].forEach(pkg => {
|
|
1328
1483
|
const pkgSrc = path.join(srcDir, pkg);
|
|
1329
1484
|
if (fs.existsSync(pkgSrc)) {
|
|
1330
1485
|
copyDirRecursive(pkgSrc, path.join(NEXO_HOME, pkg));
|
|
@@ -1349,6 +1504,12 @@ async function main() {
|
|
|
1349
1504
|
});
|
|
1350
1505
|
}
|
|
1351
1506
|
|
|
1507
|
+
// Core skills are shipped separately from personal skills.
|
|
1508
|
+
if (fs.existsSync(skillsSrcDir)) {
|
|
1509
|
+
copyDirRecursive(skillsSrcDir, path.join(NEXO_HOME, "skills-core"));
|
|
1510
|
+
log(" Core skills installed.");
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1352
1513
|
// Dashboard (recursive — includes static/, templates/)
|
|
1353
1514
|
const dashSrcDir = path.join(srcDir, "dashboard");
|
|
1354
1515
|
if (fs.existsSync(dashSrcDir)) {
|
|
@@ -1370,6 +1531,19 @@ async function main() {
|
|
|
1370
1531
|
log(" Crons installed.");
|
|
1371
1532
|
}
|
|
1372
1533
|
|
|
1534
|
+
// Templates directory (scripts + skills scaffolds)
|
|
1535
|
+
const templatesDest = path.join(NEXO_HOME, "templates");
|
|
1536
|
+
fs.mkdirSync(templatesDest, { recursive: true });
|
|
1537
|
+
if (fs.existsSync(templateDir)) {
|
|
1538
|
+
["script-template.py", "nexo_helper.py", "skill-template.md", "skill-script-template.py"].forEach(f => {
|
|
1539
|
+
const src = path.join(templateDir, f);
|
|
1540
|
+
if (fs.existsSync(src)) {
|
|
1541
|
+
fs.copyFileSync(src, path.join(templatesDest, f));
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
log(" Script and skill templates installed.");
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1373
1547
|
// Hooks directory
|
|
1374
1548
|
const hooksSrcDir = path.join(srcDir, "hooks");
|
|
1375
1549
|
if (fs.existsSync(hooksSrcDir)) {
|
|
@@ -1862,12 +2036,25 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
1862
2036
|
// Step 7: Create schedule.json (only on fresh install) and install ALL 13 processes
|
|
1863
2037
|
log("Setting up automated processes...");
|
|
1864
2038
|
const schedule = loadOrCreateSchedule(NEXO_HOME);
|
|
1865
|
-
|
|
2039
|
+
const enabledOptionals = { dashboard: doDashboard, orchestrator: doOrchestrator };
|
|
2040
|
+
if (isEphemeralInstall(NEXO_HOME)) {
|
|
2041
|
+
log("Ephemeral HOME/NEXO_HOME detected — skipping LaunchAgents installation.");
|
|
2042
|
+
} else {
|
|
2043
|
+
installAllProcesses(platform, python, NEXO_HOME, schedule, LAUNCH_AGENTS, enabledOptionals);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// Persist optional process preferences for auto-update
|
|
2047
|
+
try {
|
|
2048
|
+
const configDir = path.join(NEXO_HOME, "config");
|
|
2049
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
2050
|
+
const optFile = path.join(configDir, "optionals.json");
|
|
2051
|
+
fs.writeFileSync(optFile, JSON.stringify(enabledOptionals, null, 2));
|
|
2052
|
+
} catch {}
|
|
1866
2053
|
|
|
1867
2054
|
// Note: prevent-sleep and tcc-approve are now part of ALL_PROCESSES
|
|
1868
2055
|
// and installed by installAllProcesses() above. No separate caffeinate block needed.
|
|
1869
2056
|
|
|
1870
|
-
// Step 8: Create shell alias
|
|
2057
|
+
// Step 8: Create shell alias and add runtime CLI to PATH
|
|
1871
2058
|
log("Creating shell alias...");
|
|
1872
2059
|
const aliasName = operatorName.toLowerCase();
|
|
1873
2060
|
const savedCliPath = (() => {
|
|
@@ -1877,6 +2064,8 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
1877
2064
|
const claudeBin = savedCliPath || run("which claude") || "claude";
|
|
1878
2065
|
const aliasLine = `alias ${aliasName}='${claudeBin} --dangerously-skip-permissions "."'`;
|
|
1879
2066
|
const aliasComment = `# ${operatorName} — start Claude Code with ${operatorName} speaking first`;
|
|
2067
|
+
const nexoPathLine = `export PATH="${path.join(NEXO_HOME, "bin")}:$PATH"`;
|
|
2068
|
+
const nexoPathComment = "# NEXO runtime CLI";
|
|
1880
2069
|
|
|
1881
2070
|
// Detect shell and add alias
|
|
1882
2071
|
const userShell = process.env.SHELL || "/bin/bash";
|
|
@@ -1899,6 +2088,14 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
1899
2088
|
rcContent = fs.readFileSync(rcFile, "utf8");
|
|
1900
2089
|
}
|
|
1901
2090
|
|
|
2091
|
+
if (!rcContent.includes(nexoPathLine)) {
|
|
2092
|
+
fs.appendFileSync(rcFile, `\n${nexoPathComment}\n${nexoPathLine}\n`);
|
|
2093
|
+
log(`Added NEXO runtime CLI to ${path.basename(rcFile)}`);
|
|
2094
|
+
rcContent += `\n${nexoPathComment}\n${nexoPathLine}\n`;
|
|
2095
|
+
} else {
|
|
2096
|
+
log(`Runtime CLI already present in ${path.basename(rcFile)}`);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
1902
2099
|
if (!rcContent.includes(`alias ${aliasName}=`)) {
|
|
1903
2100
|
fs.appendFileSync(rcFile, `\n${aliasComment}\n${aliasLine}\n`);
|
|
1904
2101
|
log(`Added '${aliasName}' alias to ${path.basename(rcFile)}`);
|
|
@@ -1906,7 +2103,7 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
1906
2103
|
log(`Alias '${aliasName}' already exists in ${path.basename(rcFile)}`);
|
|
1907
2104
|
}
|
|
1908
2105
|
}
|
|
1909
|
-
log(`After setup, open a new terminal and type: ${aliasName}`);
|
|
2106
|
+
log(`After setup, open a new terminal and type: ${aliasName} or nexo`);
|
|
1910
2107
|
console.log("");
|
|
1911
2108
|
|
|
1912
2109
|
// Step 9: Generate CLAUDE.md template
|
package/bin/nexo.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nexo — Runtime operational CLI for NEXO.
|
|
4
|
+
*
|
|
5
|
+
* Thin Node launcher that resolves NEXO_HOME, finds Python,
|
|
6
|
+
* and delegates to src/cli.py (repo mode) or NEXO_HOME/cli.py (installed mode).
|
|
7
|
+
*
|
|
8
|
+
* Business logic lives in Python, not here.
|
|
9
|
+
*/
|
|
10
|
+
const { spawnSync } = require("child_process");
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
|
|
15
|
+
const NEXO_HOME = process.env.NEXO_HOME || path.join(os.homedir(), ".nexo");
|
|
16
|
+
|
|
17
|
+
function findPython() {
|
|
18
|
+
const candidates = [
|
|
19
|
+
path.join(NEXO_HOME, ".venv", "bin", "python3"),
|
|
20
|
+
path.join(NEXO_HOME, ".venv", "bin", "python"),
|
|
21
|
+
"python3",
|
|
22
|
+
"python",
|
|
23
|
+
];
|
|
24
|
+
for (const c of candidates) {
|
|
25
|
+
if (c.includes("/") ? fs.existsSync(c) : true) return c;
|
|
26
|
+
}
|
|
27
|
+
return "python3";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findCliPy() {
|
|
31
|
+
const repoCandidate = path.join(__dirname, "..", "src", "cli.py");
|
|
32
|
+
const installedCandidate = path.join(NEXO_HOME, "cli.py");
|
|
33
|
+
if (fs.existsSync(repoCandidate)) return repoCandidate;
|
|
34
|
+
return installedCandidate;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const python = findPython();
|
|
38
|
+
const cliPy = findCliPy();
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(cliPy)) {
|
|
41
|
+
console.error(`NEXO CLI not found at ${cliPy}`);
|
|
42
|
+
console.error("Run 'nexo-brain' first to complete installation.");
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = spawnSync(python, [cliPy, ...process.argv.slice(2)], {
|
|
47
|
+
stdio: "inherit",
|
|
48
|
+
env: {
|
|
49
|
+
...process.env,
|
|
50
|
+
NEXO_HOME,
|
|
51
|
+
NEXO_CODE: path.join(__dirname, "..", "src"),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO — Cognitive co-operator for Claude Code. Memory, emotional intelligence, overnight learning (Deep Sleep), cron management, trust scoring, and adaptive calibration.",
|
|
6
6
|
"bin": {
|
|
7
|
-
"nexo-brain": "./bin/nexo-brain.js"
|
|
7
|
+
"nexo-brain": "./bin/nexo-brain.js",
|
|
8
|
+
"nexo": "./bin/nexo.js"
|
|
8
9
|
},
|
|
9
10
|
"keywords": [
|
|
10
11
|
"claude-code",
|
|
@@ -54,8 +55,10 @@
|
|
|
54
55
|
},
|
|
55
56
|
"files": [
|
|
56
57
|
"bin/nexo-brain.js",
|
|
58
|
+
"bin/nexo.js",
|
|
57
59
|
"bin/postinstall.js",
|
|
58
60
|
"src/",
|
|
61
|
+
"community/",
|
|
59
62
|
"!src/**/__pycache__",
|
|
60
63
|
"!src/**/*.pyc",
|
|
61
64
|
"!src/**/*.pyo",
|