nexo-brain 7.1.1 → 7.1.2
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 +3 -2
- package/bin/nexo-brain.js +198 -92
- package/package.json +1 -1
- package/src/agent_runner.py +10 -8
- package/src/auto_close_sessions.py +19 -2
- package/src/auto_update.py +232 -28
- package/src/autonomy_mandate.py +260 -0
- package/src/bootstrap_docs.py +22 -1
- package/src/cli.py +181 -1
- package/src/cli_email.py +104 -73
- package/src/client_sync.py +22 -1
- package/src/cognitive/_core.py +5 -3
- package/src/core_prompts.py +50 -0
- package/src/cron_recovery.py +81 -7
- package/src/crons/manifest.json +57 -0
- package/src/crons/sync.py +95 -26
- package/src/dashboard/app.py +59 -0
- package/src/dashboard/templates/base.html +2 -0
- package/src/dashboard/templates/feature-disabled.html +27 -0
- package/src/db/_email_accounts.py +67 -18
- package/src/db/_fts.py +5 -5
- package/src/db/_personal_scripts.py +1 -1
- package/src/db/_skills.py +3 -3
- package/src/doctor/providers/runtime.py +35 -20
- package/src/email_config.py +18 -9
- package/src/enforcement_classifier.py +3 -12
- package/src/evolution_cycle.py +37 -149
- package/src/guardian_telemetry.py +3 -2
- package/src/hook_guardrails.py +61 -0
- package/src/hooks/capture-tool-logs.sh +11 -3
- package/src/hooks/daily-briefing-check.sh +7 -2
- package/src/hooks/heartbeat-enforcement.py +14 -1
- package/src/hooks/heartbeat-posttool.sh +2 -0
- package/src/hooks/heartbeat-user-msg.sh +2 -0
- package/src/hooks/inbox-hook.sh +6 -2
- package/src/hooks/post-compact.sh +12 -4
- package/src/hooks/pre-compact.sh +12 -4
- package/src/migrate_embeddings.py +5 -3
- package/src/nexo_migrate.py +3 -1
- package/src/plugin_loader.py +14 -5
- package/src/plugins/adaptive_mode.py +4 -1
- package/src/plugins/backup.py +32 -20
- package/src/plugins/evolution.py +2 -0
- package/src/plugins/memory_export.py +6 -1
- package/src/plugins/personal_plugins.py +17 -7
- package/src/plugins/personal_scripts.py +64 -3
- package/src/presets/entities_universal.json +67 -4
- package/src/product_mode.py +201 -0
- package/src/r14_correction_learning.py +5 -20
- package/src/r15_project_context.py +4 -10
- package/src/r16_declared_done.py +3 -16
- package/src/r17_promise_debt.py +3 -16
- package/src/r18_followup_autocomplete.py +5 -7
- package/src/r19_project_grep.py +5 -8
- package/src/r20_constant_change.py +5 -15
- package/src/r21_legacy_path.py +5 -7
- package/src/r22_personal_script.py +4 -8
- package/src/r23_ssh_without_atlas.py +4 -11
- package/src/r23b_deploy_vhost.py +7 -6
- package/src/r23c_cwd_mismatch.py +7 -6
- package/src/r23d_chown_chmod_recursive.py +6 -6
- package/src/r23e_force_push_main.py +5 -6
- package/src/r23f_db_no_where.py +5 -6
- package/src/r23g_secrets_in_output.py +5 -5
- package/src/r23h_shebang_mismatch.py +6 -5
- package/src/r23i_auto_deploy_ignored.py +5 -6
- package/src/r23j_global_install.py +5 -6
- package/src/r23k_script_duplicates_skill.py +7 -6
- package/src/r23l_resource_collision.py +7 -6
- package/src/r23m_message_duplicate.py +6 -5
- package/src/r24_stale_memory.py +4 -9
- package/src/r25_nora_maria_read_only.py +5 -10
- package/src/r34_identity_coherence.py +6 -13
- package/src/r_catalog.py +3 -7
- package/src/resonance_map.py +13 -13
- package/src/runtime_power.py +29 -80
- package/src/script_registry.py +236 -6
- package/src/scripts/check-context.py +8 -25
- package/src/scripts/deep-sleep/extract.py +6 -10
- package/src/scripts/nexo-auto-update.py +27 -4
- package/src/scripts/nexo-catchup.py +9 -19
- package/src/scripts/nexo-cognitive-decay.py +26 -3
- package/src/scripts/nexo-daily-self-audit.py +50 -51
- package/src/scripts/nexo-email-migrate-config.py +30 -11
- package/src/scripts/nexo-email-monitor.py +97 -238
- package/src/scripts/nexo-followup-runner.py +70 -133
- package/src/scripts/nexo-hook-record.py +1 -1
- package/src/scripts/nexo-immune.py +6 -31
- package/src/scripts/nexo-impact-scorer.py +27 -4
- package/src/scripts/nexo-learning-housekeep.py +26 -3
- package/src/scripts/nexo-learning-validator.py +34 -32
- package/src/scripts/nexo-migrate.py +28 -12
- package/src/scripts/nexo-morning-agent.py +9 -23
- package/src/scripts/nexo-outcome-checker.py +27 -4
- package/src/scripts/nexo-postmortem-consolidator.py +30 -62
- package/src/scripts/nexo-pre-commit.py +28 -0
- package/src/scripts/nexo-proactive-dashboard.py +27 -0
- package/src/scripts/nexo-reflection.py +33 -3
- package/src/scripts/nexo-runtime-preflight.py +27 -2
- package/src/scripts/nexo-send-reply.py +10 -8
- package/src/scripts/nexo-sleep.py +11 -25
- package/src/scripts/nexo-synthesis.py +7 -40
- package/src/scripts/nexo-watchdog-smoke.py +30 -1
- package/src/scripts/nexo-watchdog.sh +23 -17
- package/src/scripts/phase_guardian_analysis.py +27 -4
- package/src/server.py +14 -3
- package/src/storage_router.py +8 -6
- package/src/tools_drive.py +5 -13
- package/src/tools_guardian.py +3 -4
- package/src/tools_menu.py +2 -2
- package/src/tools_reminders_crud.py +17 -0
- package/src/tools_sessions.py +1 -4
- package/src/user_context.py +3 -6
- package/src/user_data_portability.py +31 -23
- package/templates/CLAUDE.md.template +11 -3
- package/templates/CODEX.AGENTS.md.template +11 -3
- package/templates/core-prompts/catchup-assessment.md +19 -0
- package/templates/core-prompts/check-context.md +24 -0
- package/templates/core-prompts/daily-self-audit.md +42 -0
- package/templates/core-prompts/daily-synthesis.md +40 -0
- package/templates/core-prompts/deep-sleep-extract-json-output.md +8 -0
- package/templates/core-prompts/drive-signal-classifier-system.md +4 -0
- package/templates/core-prompts/drive-signal-classifier-user.md +6 -0
- package/templates/core-prompts/email-monitor.md +202 -0
- package/templates/core-prompts/enforcement-classifier-retry.md +1 -0
- package/templates/core-prompts/enforcement-classifier-strict.md +1 -0
- package/templates/core-prompts/evolution-public-contribution.md +32 -0
- package/templates/core-prompts/evolution-public-pr-review.md +38 -0
- package/templates/core-prompts/evolution-weekly.md +71 -0
- package/templates/core-prompts/followup-runner-operator-attention-context.md +4 -0
- package/templates/core-prompts/followup-runner-operator-attention-question.md +1 -0
- package/templates/core-prompts/followup-runner.md +74 -0
- package/templates/core-prompts/immune-triage.md +31 -0
- package/templates/core-prompts/interactive-startup.md +1 -0
- package/templates/core-prompts/json-object-only.md +1 -0
- package/templates/core-prompts/learning-validator.md +25 -0
- package/templates/core-prompts/morning-agent-json-output.md +1 -0
- package/templates/core-prompts/morning-agent.md +23 -0
- package/templates/core-prompts/postmortem-consolidator.md +60 -0
- package/templates/core-prompts/r-catalog.md +1 -0
- package/templates/core-prompts/r14-correction-learning-injection.md +1 -0
- package/templates/core-prompts/r14-correction-learning-question.md +1 -0
- package/templates/core-prompts/r15-project-context-injection.md +1 -0
- package/templates/core-prompts/r16-declared-done-injection.md +1 -0
- package/templates/core-prompts/r16-declared-done-question.md +1 -0
- package/templates/core-prompts/r17-promise-debt-injection.md +1 -0
- package/templates/core-prompts/r17-promise-debt-question.md +1 -0
- package/templates/core-prompts/r18-followup-autocomplete-injection.md +3 -0
- package/templates/core-prompts/r19-project-grep-injection.md +1 -0
- package/templates/core-prompts/r20-constant-change-injection.md +1 -0
- package/templates/core-prompts/r20-constant-change-question.md +1 -0
- package/templates/core-prompts/r21-legacy-path-injection.md +1 -0
- package/templates/core-prompts/r22-personal-script-injection.md +1 -0
- package/templates/core-prompts/r23-ssh-without-atlas-injection.md +1 -0
- package/templates/core-prompts/r23b-deploy-vhost-injection.md +1 -0
- package/templates/core-prompts/r23c-cwd-mismatch-injection.md +1 -0
- package/templates/core-prompts/r23d-chown-chmod-recursive-injection.md +1 -0
- package/templates/core-prompts/r23e-force-push-main-injection.md +1 -0
- package/templates/core-prompts/r23f-db-no-where-injection.md +1 -0
- package/templates/core-prompts/r23g-secrets-in-output-injection.md +1 -0
- package/templates/core-prompts/r23h-shebang-mismatch-injection.md +1 -0
- package/templates/core-prompts/r23i-auto-deploy-ignored-injection.md +1 -0
- package/templates/core-prompts/r23j-global-install-injection.md +1 -0
- package/templates/core-prompts/r23k-script-duplicates-skill-injection.md +1 -0
- package/templates/core-prompts/r23l-resource-collision-injection.md +1 -0
- package/templates/core-prompts/r23m-message-duplicate-injection.md +1 -0
- package/templates/core-prompts/r24-stale-memory-injection.md +1 -0
- package/templates/core-prompts/r25-read-only-host-injection.md +1 -0
- package/templates/core-prompts/r34-identity-coherence-probe.md +1 -0
- package/templates/core-prompts/r34-identity-coherence-question.md +1 -0
- package/templates/core-prompts/sleep.md +25 -0
- package/templates/email-template.md +55 -0
- package/templates/nexo_helper.py +31 -13
- package/templates/plugin-template.py +3 -3
- package/templates/skill-template.md +2 -1
package/bin/nexo-brain.js
CHANGED
|
@@ -318,6 +318,50 @@ function syncRuntimePackageMetadata(repoRoot = path.join(__dirname, ".."), runti
|
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
function resolveRuntimeConfigDir(nexoHome) {
|
|
322
|
+
const canonical = path.join(nexoHome, "personal", "config");
|
|
323
|
+
const legacy = path.join(nexoHome, "config");
|
|
324
|
+
if (fs.existsSync(canonical)) return canonical;
|
|
325
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
326
|
+
return canonical;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function resolveRuntimeBrainDir(nexoHome) {
|
|
330
|
+
const canonical = path.join(nexoHome, "personal", "brain");
|
|
331
|
+
const legacy = path.join(nexoHome, "brain");
|
|
332
|
+
if (fs.existsSync(canonical)) return canonical;
|
|
333
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
334
|
+
return canonical;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function resolveRuntimeDataDir(nexoHome) {
|
|
338
|
+
const canonical = path.join(nexoHome, "runtime", "data");
|
|
339
|
+
const legacy = path.join(nexoHome, "data");
|
|
340
|
+
if (fs.existsSync(canonical)) return canonical;
|
|
341
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
342
|
+
return canonical;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function resolveRuntimeLogsDir(nexoHome) {
|
|
346
|
+
const canonical = path.join(nexoHome, "runtime", "logs");
|
|
347
|
+
const legacy = path.join(nexoHome, "logs");
|
|
348
|
+
if (fs.existsSync(canonical)) return canonical;
|
|
349
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
350
|
+
return canonical;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function resolveRuntimeCronsDir(nexoHome) {
|
|
354
|
+
const canonical = path.join(nexoHome, "runtime", "crons");
|
|
355
|
+
const legacy = path.join(nexoHome, "crons");
|
|
356
|
+
if (fs.existsSync(canonical)) return canonical;
|
|
357
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
358
|
+
return canonical;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function resolveRuntimeSchedulePath(nexoHome) {
|
|
362
|
+
return path.join(resolveRuntimeConfigDir(nexoHome), "schedule.json");
|
|
363
|
+
}
|
|
364
|
+
|
|
321
365
|
function finalizeF06Layout(python, nexoHome = NEXO_HOME) {
|
|
322
366
|
try {
|
|
323
367
|
const result = spawnSync(
|
|
@@ -327,7 +371,6 @@ function finalizeF06Layout(python, nexoHome = NEXO_HOME) {
|
|
|
327
371
|
[
|
|
328
372
|
"import auto_update",
|
|
329
373
|
"auto_update._maybe_migrate_to_f06_layout()",
|
|
330
|
-
"auto_update._ensure_f06_legacy_shims()",
|
|
331
374
|
"auto_update._rewrite_f06_launch_agents()",
|
|
332
375
|
].join("; "),
|
|
333
376
|
],
|
|
@@ -418,7 +461,7 @@ function getCoreRuntimePackages() {
|
|
|
418
461
|
// getCoreRuntimeFlatFiles for that reason) but data contracts with a stable
|
|
419
462
|
// path that external clients read. Keep in sync with docs/contracts/.
|
|
420
463
|
function publishBrainContracts(srcDir = path.join(__dirname, "..", "src"), nexoHome = NEXO_HOME) {
|
|
421
|
-
const brainDir =
|
|
464
|
+
const brainDir = resolveRuntimeBrainDir(nexoHome);
|
|
422
465
|
fs.mkdirSync(brainDir, { recursive: true });
|
|
423
466
|
const contracts = ["resonance_tiers.json"];
|
|
424
467
|
contracts.forEach((name) => {
|
|
@@ -458,7 +501,7 @@ function resolveLaunchAgentPath(home) {
|
|
|
458
501
|
|
|
459
502
|
function setupKeychainPassFile(nexoHome) {
|
|
460
503
|
if (process.platform !== "darwin") return;
|
|
461
|
-
const configDir =
|
|
504
|
+
const configDir = resolveRuntimeConfigDir(nexoHome);
|
|
462
505
|
const passFile = path.join(configDir, ".keychain-pass");
|
|
463
506
|
if (fs.existsSync(passFile)) return; // already set up
|
|
464
507
|
fs.mkdirSync(configDir, { recursive: true });
|
|
@@ -528,7 +571,7 @@ function detectFullDiskAccessReasons(nexoHome) {
|
|
|
528
571
|
reasons.push(`NEXO_HOME is inside a protected macOS folder: ${nexoHome}`);
|
|
529
572
|
}
|
|
530
573
|
|
|
531
|
-
const logsDir =
|
|
574
|
+
const logsDir = resolveRuntimeLogsDir(nexoHome);
|
|
532
575
|
if (fs.existsSync(logsDir)) {
|
|
533
576
|
const candidates = fs.readdirSync(logsDir).filter((name) => name.endsWith("-stderr.log"));
|
|
534
577
|
for (const name of candidates) {
|
|
@@ -586,25 +629,25 @@ async function maybeConfigureFullDiskAccess(schedule, useDefaults, pythonPath =
|
|
|
586
629
|
schedule.full_disk_access_reasons = reasons;
|
|
587
630
|
|
|
588
631
|
if (process.platform !== "darwin" || !reasons.length) {
|
|
589
|
-
fs.writeFileSync(
|
|
632
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
590
633
|
return schedule;
|
|
591
634
|
}
|
|
592
635
|
|
|
593
636
|
if (current === "granted") {
|
|
594
637
|
const probe = probeFullDiskAccess(NEXO_HOME);
|
|
595
638
|
if (probe.granted) {
|
|
596
|
-
fs.writeFileSync(
|
|
639
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
597
640
|
return schedule;
|
|
598
641
|
}
|
|
599
642
|
schedule.full_disk_access_status = "later";
|
|
600
643
|
} else if (current === "declined") {
|
|
601
|
-
fs.writeFileSync(
|
|
644
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
602
645
|
return schedule;
|
|
603
646
|
}
|
|
604
647
|
|
|
605
648
|
if (useDefaults || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
606
649
|
schedule.full_disk_access_status = current === "granted" ? "later" : current || "unset";
|
|
607
|
-
fs.writeFileSync(
|
|
650
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
608
651
|
return schedule;
|
|
609
652
|
}
|
|
610
653
|
|
|
@@ -640,7 +683,7 @@ async function maybeConfigureFullDiskAccess(schedule, useDefaults, pythonPath =
|
|
|
640
683
|
schedule.full_disk_access_status = "declined";
|
|
641
684
|
}
|
|
642
685
|
|
|
643
|
-
fs.writeFileSync(
|
|
686
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
644
687
|
return schedule;
|
|
645
688
|
}
|
|
646
689
|
|
|
@@ -737,7 +780,7 @@ function _manifestHookEntries() {
|
|
|
737
780
|
|
|
738
781
|
function _hookCommand(hook, hooksDir, nexoHome) {
|
|
739
782
|
// Resolve handler path under the installed runtime. hooksDir points to
|
|
740
|
-
//
|
|
783
|
+
// the canonical installed hook tree (preferably ~/.nexo/core/hooks).
|
|
741
784
|
const handlerFile = path.basename(hook.handler);
|
|
742
785
|
const runtimePath = path.join(hooksDir, handlerFile);
|
|
743
786
|
return `NEXO_HOME=${nexoHome} python3 ${runtimePath}`;
|
|
@@ -795,7 +838,7 @@ function registerAllCoreHooks(settings, hooksDir, nexoHome) {
|
|
|
795
838
|
|
|
796
839
|
// Ensure operations dir exists for any hook that wants to drop a file there
|
|
797
840
|
// (session-start.py writes .session-start-ts here).
|
|
798
|
-
fs.mkdirSync(path.join(nexoHome, "operations"), { recursive: true });
|
|
841
|
+
fs.mkdirSync(path.join(nexoHome, "runtime", "operations"), { recursive: true });
|
|
799
842
|
|
|
800
843
|
const manifestEntries = _manifestHookEntries();
|
|
801
844
|
const registrations = [];
|
|
@@ -909,7 +952,7 @@ function registerAllCoreHooks(settings, hooksDir, nexoHome) {
|
|
|
909
952
|
* NEVER overwrites an existing schedule.json (user customization).
|
|
910
953
|
*/
|
|
911
954
|
function loadOrCreateSchedule(nexoHome) {
|
|
912
|
-
const configDir =
|
|
955
|
+
const configDir = resolveRuntimeConfigDir(nexoHome);
|
|
913
956
|
fs.mkdirSync(configDir, { recursive: true });
|
|
914
957
|
const scheduleFile = path.join(configDir, "schedule.json");
|
|
915
958
|
|
|
@@ -988,6 +1031,71 @@ function getDefaultSchedule(timezone) {
|
|
|
988
1031
|
};
|
|
989
1032
|
}
|
|
990
1033
|
|
|
1034
|
+
function writeDesktopProductMode(nexoHome) {
|
|
1035
|
+
if (String(process.env.NEXO_DESKTOP_MANAGED || "").trim() !== "1") return;
|
|
1036
|
+
const configDir = resolveRuntimeConfigDir(nexoHome);
|
|
1037
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
1038
|
+
const target = path.join(configDir, "product-mode.json");
|
|
1039
|
+
let createdAt = new Date().toISOString();
|
|
1040
|
+
if (fs.existsSync(target)) {
|
|
1041
|
+
try {
|
|
1042
|
+
const existing = JSON.parse(fs.readFileSync(target, "utf8"));
|
|
1043
|
+
if (existing && typeof existing === "object" && existing.created_at) {
|
|
1044
|
+
createdAt = existing.created_at;
|
|
1045
|
+
}
|
|
1046
|
+
} catch (_) {}
|
|
1047
|
+
}
|
|
1048
|
+
fs.writeFileSync(target, JSON.stringify({
|
|
1049
|
+
desktop_managed: true,
|
|
1050
|
+
product_mode: "desktop_closed_product",
|
|
1051
|
+
disabled_features: ["evolution"],
|
|
1052
|
+
source: "desktop",
|
|
1053
|
+
created_at: createdAt,
|
|
1054
|
+
updated_at: new Date().toISOString(),
|
|
1055
|
+
}, null, 2));
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function ensureEvolutionObjectiveForCurrentProductMode(nexoHome) {
|
|
1059
|
+
const brainDir = resolveRuntimeBrainDir(nexoHome);
|
|
1060
|
+
fs.mkdirSync(brainDir, { recursive: true });
|
|
1061
|
+
const evoObjectivePath = path.join(brainDir, "evolution-objective.json");
|
|
1062
|
+
const desktopManaged = String(process.env.NEXO_DESKTOP_MANAGED || "").trim() === "1";
|
|
1063
|
+
let payload = null;
|
|
1064
|
+
if (fs.existsSync(evoObjectivePath)) {
|
|
1065
|
+
try {
|
|
1066
|
+
payload = JSON.parse(fs.readFileSync(evoObjectivePath, "utf8"));
|
|
1067
|
+
} catch (_) {
|
|
1068
|
+
payload = null;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
if (!payload || typeof payload !== "object") {
|
|
1072
|
+
payload = {
|
|
1073
|
+
objective: "Improve operational excellence and reduce repeated errors",
|
|
1074
|
+
focus_areas: ["error_prevention", "proactivity", "memory_quality"],
|
|
1075
|
+
evolution_enabled: true,
|
|
1076
|
+
evolution_mode: "auto",
|
|
1077
|
+
dimensions: {
|
|
1078
|
+
episodic_memory: { current: 0, target: 90 },
|
|
1079
|
+
autonomy: { current: 0, target: 80 },
|
|
1080
|
+
proactivity: { current: 0, target: 70 },
|
|
1081
|
+
self_improvement: { current: 0, target: 60 },
|
|
1082
|
+
agi: { current: 0, target: 20 },
|
|
1083
|
+
},
|
|
1084
|
+
total_evolutions: 0,
|
|
1085
|
+
consecutive_failures: 0,
|
|
1086
|
+
created_at: new Date().toISOString(),
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
if (desktopManaged) {
|
|
1090
|
+
payload.evolution_enabled = false;
|
|
1091
|
+
payload.disabled_reason = "Disabled by NEXO Desktop product contract";
|
|
1092
|
+
payload.disabled_by = "desktop_product";
|
|
1093
|
+
payload.desktop_managed = true;
|
|
1094
|
+
}
|
|
1095
|
+
fs.writeFileSync(evoObjectivePath, JSON.stringify(payload, null, 2));
|
|
1096
|
+
return evoObjectivePath;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
991
1099
|
function normalizePublicContributionConfig(config = {}) {
|
|
992
1100
|
const base = getDefaultSchedule().public_contribution;
|
|
993
1101
|
const merged = { ...base, ...(config || {}) };
|
|
@@ -1448,7 +1556,7 @@ async function maybeConfigurePowerPolicy(schedule, useDefaults) {
|
|
|
1448
1556
|
schedule.power_policy = "disabled";
|
|
1449
1557
|
}
|
|
1450
1558
|
schedule.power_policy_version = 2;
|
|
1451
|
-
fs.writeFileSync(
|
|
1559
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
1452
1560
|
return schedule;
|
|
1453
1561
|
}
|
|
1454
1562
|
|
|
@@ -1471,13 +1579,13 @@ async function maybeConfigurePublicContribution(schedule, useDefaults) {
|
|
|
1471
1579
|
const current = normalizePublicContributionConfig((schedule && schedule.public_contribution) || {});
|
|
1472
1580
|
if (current.mode && current.mode !== "unset") {
|
|
1473
1581
|
schedule.public_contribution = current;
|
|
1474
|
-
fs.writeFileSync(
|
|
1582
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
1475
1583
|
return schedule;
|
|
1476
1584
|
}
|
|
1477
1585
|
|
|
1478
1586
|
if (useDefaults || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
1479
1587
|
schedule.public_contribution = current;
|
|
1480
|
-
fs.writeFileSync(
|
|
1588
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
1481
1589
|
return schedule;
|
|
1482
1590
|
}
|
|
1483
1591
|
|
|
@@ -1526,7 +1634,7 @@ async function maybeConfigurePublicContribution(schedule, useDefaults) {
|
|
|
1526
1634
|
}
|
|
1527
1635
|
|
|
1528
1636
|
schedule.public_contribution = current;
|
|
1529
|
-
fs.writeFileSync(
|
|
1637
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
1530
1638
|
return schedule;
|
|
1531
1639
|
}
|
|
1532
1640
|
|
|
@@ -1561,12 +1669,12 @@ const DAY_MAP = {
|
|
|
1561
1669
|
function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAgentsDir, enabledOptionals = {}) {
|
|
1562
1670
|
const home = require("os").homedir();
|
|
1563
1671
|
const nexoCode = nexoHome;
|
|
1564
|
-
const logsDir = path.join(nexoHome, "logs");
|
|
1672
|
+
const logsDir = path.join(nexoHome, "runtime", "logs");
|
|
1565
1673
|
fs.mkdirSync(logsDir, { recursive: true });
|
|
1566
1674
|
|
|
1567
|
-
// Resolve script path
|
|
1675
|
+
// Resolve script path against the canonical runtime code tree.
|
|
1568
1676
|
function scriptPath(proc) {
|
|
1569
|
-
const dir = proc.scriptDir === "root" ? nexoHome :
|
|
1677
|
+
const dir = proc.scriptDir === "root" ? runtimeCodeDir(nexoHome) : runtimeScriptsDir(nexoHome);
|
|
1570
1678
|
return path.join(dir, proc.script);
|
|
1571
1679
|
}
|
|
1572
1680
|
|
|
@@ -1916,7 +2024,7 @@ async function main() {
|
|
|
1916
2024
|
|
|
1917
2025
|
// Update hooks (entire directory)
|
|
1918
2026
|
const hooksSrc = path.join(srcDir, "hooks");
|
|
1919
|
-
const hooksDest = path.join(NEXO_HOME, "hooks");
|
|
2027
|
+
const hooksDest = path.join(NEXO_HOME, "core", "hooks");
|
|
1920
2028
|
if (fs.existsSync(hooksSrc)) {
|
|
1921
2029
|
copyDirRec(hooksSrc, hooksDest);
|
|
1922
2030
|
// Make .sh files executable
|
|
@@ -1931,14 +2039,16 @@ async function main() {
|
|
|
1931
2039
|
coreFlatFiles.forEach((f) => {
|
|
1932
2040
|
const src = path.join(srcDir, f);
|
|
1933
2041
|
if (fs.existsSync(src)) {
|
|
1934
|
-
|
|
2042
|
+
const dest = path.join(NEXO_HOME, "core", f);
|
|
2043
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
2044
|
+
fs.copyFileSync(src, dest);
|
|
1935
2045
|
}
|
|
1936
2046
|
});
|
|
1937
2047
|
// Update core packages (db/, cognitive/) — full directory copy
|
|
1938
2048
|
getCoreRuntimePackages().forEach(pkg => {
|
|
1939
2049
|
const pkgSrc = path.join(srcDir, pkg);
|
|
1940
2050
|
if (fs.existsSync(pkgSrc)) {
|
|
1941
|
-
copyDirRec(pkgSrc, path.join(NEXO_HOME, pkg));
|
|
2051
|
+
copyDirRec(pkgSrc, path.join(NEXO_HOME, "core", pkg));
|
|
1942
2052
|
}
|
|
1943
2053
|
});
|
|
1944
2054
|
// Publish Brain contracts to ~/.nexo/brain/ (read by NEXO Desktop et al.)
|
|
@@ -1971,7 +2081,7 @@ async function main() {
|
|
|
1971
2081
|
|
|
1972
2082
|
// Update plugins (all .py files in plugins/)
|
|
1973
2083
|
const pluginsSrc = path.join(srcDir, "plugins");
|
|
1974
|
-
const pluginsDest = path.join(NEXO_HOME, "plugins");
|
|
2084
|
+
const pluginsDest = path.join(NEXO_HOME, "core", "plugins");
|
|
1975
2085
|
fs.mkdirSync(pluginsDest, { recursive: true });
|
|
1976
2086
|
if (fs.existsSync(pluginsSrc)) {
|
|
1977
2087
|
fs.readdirSync(pluginsSrc).filter(f => f.endsWith(".py") && !isDuplicateArtifactName(f, pluginsSrc)).forEach((f) => {
|
|
@@ -1982,7 +2092,7 @@ async function main() {
|
|
|
1982
2092
|
|
|
1983
2093
|
// Update dashboard (recursive — includes static/, templates/)
|
|
1984
2094
|
const dashSrc = path.join(srcDir, "dashboard");
|
|
1985
|
-
const dashDest = path.join(NEXO_HOME, "dashboard");
|
|
2095
|
+
const dashDest = path.join(NEXO_HOME, "core", "dashboard");
|
|
1986
2096
|
if (fs.existsSync(dashSrc)) {
|
|
1987
2097
|
copyDirRec(dashSrc, dashDest);
|
|
1988
2098
|
log(" Dashboard updated.");
|
|
@@ -1990,7 +2100,7 @@ async function main() {
|
|
|
1990
2100
|
|
|
1991
2101
|
// Update rules (directory with core-rules.json, __init__.py, migrate.py)
|
|
1992
2102
|
const rulesSrc = path.join(srcDir, "rules");
|
|
1993
|
-
const rulesDest = path.join(NEXO_HOME, "rules");
|
|
2103
|
+
const rulesDest = path.join(NEXO_HOME, "core", "rules");
|
|
1994
2104
|
if (fs.existsSync(rulesSrc)) {
|
|
1995
2105
|
copyDirRec(rulesSrc, rulesDest);
|
|
1996
2106
|
log(" Rules updated.");
|
|
@@ -1998,7 +2108,7 @@ async function main() {
|
|
|
1998
2108
|
|
|
1999
2109
|
// Update crons (manifest.json + sync.py — needed by catchup & watchdog)
|
|
2000
2110
|
const cronsMigSrc = path.join(srcDir, "crons");
|
|
2001
|
-
const cronsMigDest = path.join(NEXO_HOME, "crons");
|
|
2111
|
+
const cronsMigDest = path.join(NEXO_HOME, "runtime", "crons");
|
|
2002
2112
|
if (fs.existsSync(cronsMigSrc)) {
|
|
2003
2113
|
copyDirRec(cronsMigSrc, cronsMigDest);
|
|
2004
2114
|
log(" Crons updated.");
|
|
@@ -2006,7 +2116,7 @@ async function main() {
|
|
|
2006
2116
|
|
|
2007
2117
|
// Update scripts (all .py, .sh files + subdirectories like deep-sleep/)
|
|
2008
2118
|
const scriptsSrc = path.join(srcDir, "scripts");
|
|
2009
|
-
const scriptsDest = path.join(NEXO_HOME, "scripts");
|
|
2119
|
+
const scriptsDest = path.join(NEXO_HOME, "core", "scripts");
|
|
2010
2120
|
if (fs.existsSync(scriptsSrc)) {
|
|
2011
2121
|
copyDirRec(scriptsSrc, scriptsDest);
|
|
2012
2122
|
// Make .sh files executable
|
|
@@ -2023,7 +2133,7 @@ async function main() {
|
|
|
2023
2133
|
try { settings = JSON.parse(fs.readFileSync(CLAUDE_SETTINGS, "utf8")); } catch {}
|
|
2024
2134
|
}
|
|
2025
2135
|
if (!settings.hooks) settings.hooks = {};
|
|
2026
|
-
const migHooksDest = path.join(NEXO_HOME, "hooks");
|
|
2136
|
+
const migHooksDest = path.join(NEXO_HOME, "core", "hooks");
|
|
2027
2137
|
registerAllCoreHooks(settings, migHooksDest, NEXO_HOME);
|
|
2028
2138
|
fs.mkdirSync(path.dirname(CLAUDE_SETTINGS), { recursive: true });
|
|
2029
2139
|
fs.writeFileSync(CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
|
|
@@ -2037,7 +2147,7 @@ async function main() {
|
|
|
2037
2147
|
migSchedule = await maybeConfigureFullDiskAccess(migSchedule, useDefaults, migPython);
|
|
2038
2148
|
let migOptionals = {};
|
|
2039
2149
|
try {
|
|
2040
|
-
const optFile = path.join(NEXO_HOME, "
|
|
2150
|
+
const optFile = path.join(resolveRuntimeConfigDir(NEXO_HOME), "optionals.json");
|
|
2041
2151
|
if (fs.existsSync(optFile)) migOptionals = JSON.parse(fs.readFileSync(optFile, "utf8"));
|
|
2042
2152
|
} catch {}
|
|
2043
2153
|
installAllProcesses(platform, migPython, NEXO_HOME, migSchedule, LAUNCH_AGENTS, migOptionals);
|
|
@@ -2057,20 +2167,19 @@ async function main() {
|
|
|
2057
2167
|
throw new Error(`F0.6 layout finalization failed: ${migLayoutFinalize.error}`);
|
|
2058
2168
|
}
|
|
2059
2169
|
|
|
2060
|
-
//
|
|
2170
|
+
// Keep the rendered template in-memory for version tracking, but do
|
|
2171
|
+
// not drop a loose reference file in NEXO_HOME root.
|
|
2061
2172
|
const templateSrc = path.join(__dirname, "..", "templates", "CLAUDE.md.template");
|
|
2062
2173
|
if (fs.existsSync(templateSrc)) {
|
|
2063
2174
|
const operatorName = installed.operator_name || DEFAULT_ASSISTANT_NAME;
|
|
2064
2175
|
let claudeMd = fs.readFileSync(templateSrc, "utf8")
|
|
2065
2176
|
.replace(/\{\{NAME\}\}/g, operatorName)
|
|
2066
2177
|
.replace(/\{\{NEXO_HOME\}\}/g, NEXO_HOME);
|
|
2067
|
-
fs.writeFileSync(path.join(NEXO_HOME, "CLAUDE.md.updated"), claudeMd);
|
|
2068
|
-
log(` Updated CLAUDE.md template saved to ~/.nexo/CLAUDE.md.updated`);
|
|
2069
2178
|
|
|
2070
2179
|
// Update CLAUDE.md version tracker (auto_update.py will handle section migration on next server start)
|
|
2071
2180
|
const migClaudeMdVerMatch = claudeMd.match(/nexo-claude-md-version:\s*([\d.]+)/);
|
|
2072
2181
|
if (migClaudeMdVerMatch) {
|
|
2073
|
-
const migDataDir =
|
|
2182
|
+
const migDataDir = resolveRuntimeDataDir(NEXO_HOME);
|
|
2074
2183
|
fs.mkdirSync(migDataDir, { recursive: true });
|
|
2075
2184
|
// Don't write the version yet — let auto_update.py detect the diff and migrate sections
|
|
2076
2185
|
// Only write if no version file exists (first time with version tracking)
|
|
@@ -2130,7 +2239,7 @@ async function main() {
|
|
|
2130
2239
|
}
|
|
2131
2240
|
|
|
2132
2241
|
// Same version — backfill crons/ if missing (for installs before crons was shipped)
|
|
2133
|
-
const cronsDest =
|
|
2242
|
+
const cronsDest = resolveRuntimeCronsDir(NEXO_HOME);
|
|
2134
2243
|
const cronsSrc = path.join(__dirname, "..", "src", "crons");
|
|
2135
2244
|
if (fs.existsSync(cronsSrc)) {
|
|
2136
2245
|
const copyDirRec2 = (src, dest) => {
|
|
@@ -2164,7 +2273,7 @@ async function main() {
|
|
|
2164
2273
|
}
|
|
2165
2274
|
|
|
2166
2275
|
// Same version — refresh packaged core skills/templates/runtime helpers too.
|
|
2167
|
-
const skillsCoreDest = path.join(NEXO_HOME, "
|
|
2276
|
+
const skillsCoreDest = path.join(NEXO_HOME, "core", "skills");
|
|
2168
2277
|
const skillsCoreSrc = path.join(__dirname, "..", "src", "skills");
|
|
2169
2278
|
if (fs.existsSync(skillsCoreSrc)) {
|
|
2170
2279
|
const copyDirRec3 = (src, dest) => {
|
|
@@ -2183,8 +2292,9 @@ async function main() {
|
|
|
2183
2292
|
|
|
2184
2293
|
["skills_runtime.py"].forEach((fname) => {
|
|
2185
2294
|
const srcFile = path.join(__dirname, "..", "src", fname);
|
|
2186
|
-
const destFile = path.join(NEXO_HOME, fname);
|
|
2295
|
+
const destFile = path.join(NEXO_HOME, "core", fname);
|
|
2187
2296
|
if (fs.existsSync(srcFile)) {
|
|
2297
|
+
fs.mkdirSync(path.dirname(destFile), { recursive: true });
|
|
2188
2298
|
fs.copyFileSync(srcFile, destFile);
|
|
2189
2299
|
}
|
|
2190
2300
|
});
|
|
@@ -2615,10 +2725,11 @@ async function main() {
|
|
|
2615
2725
|
calibrated_at: new Date().toISOString(),
|
|
2616
2726
|
};
|
|
2617
2727
|
// Ensure NEXO_HOME and brain dir exist before writing calibration
|
|
2728
|
+
const runtimeBrainDir = resolveRuntimeBrainDir(NEXO_HOME);
|
|
2618
2729
|
fs.mkdirSync(NEXO_HOME, { recursive: true });
|
|
2619
|
-
fs.mkdirSync(
|
|
2730
|
+
fs.mkdirSync(runtimeBrainDir, { recursive: true });
|
|
2620
2731
|
fs.writeFileSync(
|
|
2621
|
-
path.join(
|
|
2732
|
+
path.join(runtimeBrainDir, "calibration.json"),
|
|
2622
2733
|
JSON.stringify(calibration, null, 2)
|
|
2623
2734
|
);
|
|
2624
2735
|
|
|
@@ -2672,7 +2783,7 @@ async function main() {
|
|
|
2672
2783
|
// Persist the updated calibration (auto_install may have changed post-write above).
|
|
2673
2784
|
try {
|
|
2674
2785
|
fs.writeFileSync(
|
|
2675
|
-
path.join(
|
|
2786
|
+
path.join(runtimeBrainDir, "calibration.json"),
|
|
2676
2787
|
JSON.stringify(calibration, null, 2)
|
|
2677
2788
|
);
|
|
2678
2789
|
} catch (_) {}
|
|
@@ -2683,10 +2794,9 @@ async function main() {
|
|
|
2683
2794
|
// the heavy bootstrap (client installs, pip, scan, LaunchAgents) so the
|
|
2684
2795
|
// smoke does not sit on long dependency timeouts inside sandboxes.
|
|
2685
2796
|
try {
|
|
2686
|
-
|
|
2687
|
-
fs.mkdirSync(canonicalBrainDir, { recursive: true });
|
|
2797
|
+
fs.mkdirSync(runtimeBrainDir, { recursive: true });
|
|
2688
2798
|
fs.writeFileSync(
|
|
2689
|
-
path.join(
|
|
2799
|
+
path.join(runtimeBrainDir, "calibration.json"),
|
|
2690
2800
|
JSON.stringify(calibration, null, 2)
|
|
2691
2801
|
);
|
|
2692
2802
|
} catch (_) {}
|
|
@@ -2746,40 +2856,33 @@ async function main() {
|
|
|
2746
2856
|
const dirs = [
|
|
2747
2857
|
NEXO_HOME,
|
|
2748
2858
|
path.join(NEXO_HOME, "bin"),
|
|
2749
|
-
path.join(NEXO_HOME, "
|
|
2750
|
-
path.join(NEXO_HOME, "
|
|
2751
|
-
path.join(NEXO_HOME, "
|
|
2752
|
-
path.join(NEXO_HOME, "
|
|
2753
|
-
path.join(NEXO_HOME, "
|
|
2754
|
-
path.join(NEXO_HOME, "
|
|
2755
|
-
path.join(NEXO_HOME, "
|
|
2756
|
-
path.join(NEXO_HOME, "
|
|
2757
|
-
path.join(NEXO_HOME, "brain"),
|
|
2758
|
-
path.join(NEXO_HOME, "config"),
|
|
2759
|
-
path.join(NEXO_HOME, "
|
|
2859
|
+
path.join(NEXO_HOME, "core"),
|
|
2860
|
+
path.join(NEXO_HOME, "core", "plugins"),
|
|
2861
|
+
path.join(NEXO_HOME, "core", "scripts"),
|
|
2862
|
+
path.join(NEXO_HOME, "core", "skills"),
|
|
2863
|
+
path.join(NEXO_HOME, "core", "hooks"),
|
|
2864
|
+
path.join(NEXO_HOME, "core", "rules"),
|
|
2865
|
+
path.join(NEXO_HOME, "core", "dashboard"),
|
|
2866
|
+
path.join(NEXO_HOME, "personal"),
|
|
2867
|
+
path.join(NEXO_HOME, "personal", "brain"),
|
|
2868
|
+
path.join(NEXO_HOME, "personal", "config"),
|
|
2869
|
+
path.join(NEXO_HOME, "personal", "skills"),
|
|
2870
|
+
path.join(NEXO_HOME, "runtime"),
|
|
2871
|
+
path.join(NEXO_HOME, "runtime", "data"),
|
|
2872
|
+
path.join(NEXO_HOME, "runtime", "logs"),
|
|
2873
|
+
path.join(NEXO_HOME, "runtime", "backups"),
|
|
2874
|
+
path.join(NEXO_HOME, "runtime", "coordination"),
|
|
2875
|
+
path.join(NEXO_HOME, "runtime", "operations"),
|
|
2876
|
+
path.join(NEXO_HOME, "runtime", "crons"),
|
|
2760
2877
|
];
|
|
2761
2878
|
dirs.forEach((d) => fs.mkdirSync(d, { recursive: true }));
|
|
2762
2879
|
|
|
2763
|
-
|
|
2764
|
-
const evoObjectivePath =
|
|
2765
|
-
if (
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
evolution_enabled: true,
|
|
2770
|
-
evolution_mode: "auto",
|
|
2771
|
-
dimensions: {
|
|
2772
|
-
episodic_memory: { current: 0, target: 90 },
|
|
2773
|
-
autonomy: { current: 0, target: 80 },
|
|
2774
|
-
proactivity: { current: 0, target: 70 },
|
|
2775
|
-
self_improvement: { current: 0, target: 60 },
|
|
2776
|
-
agi: { current: 0, target: 20 },
|
|
2777
|
-
},
|
|
2778
|
-
total_evolutions: 0,
|
|
2779
|
-
consecutive_failures: 0,
|
|
2780
|
-
created_at: new Date().toISOString(),
|
|
2781
|
-
}, null, 2));
|
|
2782
|
-
log(" Created default evolution-objective.json in brain/");
|
|
2880
|
+
writeDesktopProductMode(NEXO_HOME);
|
|
2881
|
+
const evoObjectivePath = ensureEvolutionObjectiveForCurrentProductMode(NEXO_HOME);
|
|
2882
|
+
if (String(process.env.NEXO_DESKTOP_MANAGED || "").trim() === "1") {
|
|
2883
|
+
log(" Desktop product contract detected — evolution disabled.");
|
|
2884
|
+
} else if (fs.existsSync(evoObjectivePath)) {
|
|
2885
|
+
log(" Ensured evolution-objective.json in brain/");
|
|
2783
2886
|
}
|
|
2784
2887
|
|
|
2785
2888
|
// Write version file for auto-update tracking
|
|
@@ -2825,7 +2928,9 @@ async function main() {
|
|
|
2825
2928
|
coreFiles.forEach((f) => {
|
|
2826
2929
|
const src = path.join(srcDir, f);
|
|
2827
2930
|
if (fs.existsSync(src)) {
|
|
2828
|
-
|
|
2931
|
+
const dest = path.join(NEXO_HOME, "core", f);
|
|
2932
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
2933
|
+
fs.copyFileSync(src, dest);
|
|
2829
2934
|
}
|
|
2830
2935
|
});
|
|
2831
2936
|
|
|
@@ -2840,6 +2945,7 @@ async function main() {
|
|
|
2840
2945
|
`RUNTIME_HOME="${NEXO_HOME}"`,
|
|
2841
2946
|
'NEXO_HOME="$RUNTIME_HOME"',
|
|
2842
2947
|
'export NEXO_HOME',
|
|
2948
|
+
'export PYTHONDONTWRITEBYTECODE=1',
|
|
2843
2949
|
'resolve_code_dir() {',
|
|
2844
2950
|
' if [ -n "${NEXO_CODE:-}" ] && [ -f "${NEXO_CODE%/}/cli.py" ]; then',
|
|
2845
2951
|
' printf \'%s\\n\' "${NEXO_CODE%/}"',
|
|
@@ -2924,24 +3030,24 @@ async function main() {
|
|
|
2924
3030
|
getCoreRuntimePackages().forEach(pkg => {
|
|
2925
3031
|
const pkgSrc = path.join(srcDir, pkg);
|
|
2926
3032
|
if (fs.existsSync(pkgSrc)) {
|
|
2927
|
-
copyDirRecursive(pkgSrc, path.join(NEXO_HOME, pkg));
|
|
3033
|
+
copyDirRecursive(pkgSrc, path.join(NEXO_HOME, "core", pkg));
|
|
2928
3034
|
}
|
|
2929
3035
|
});
|
|
2930
3036
|
|
|
2931
3037
|
log("Copying plugins, scripts, and templates...");
|
|
2932
3038
|
// Plugins (all .py files in plugins/)
|
|
2933
|
-
fs.mkdirSync(path.join(NEXO_HOME, "plugins"), { recursive: true });
|
|
3039
|
+
fs.mkdirSync(path.join(NEXO_HOME, "core", "plugins"), { recursive: true });
|
|
2934
3040
|
if (fs.existsSync(pluginsSrcDir)) {
|
|
2935
3041
|
fs.readdirSync(pluginsSrcDir).filter(f => f.endsWith(".py") && !isDuplicateArtifactName(f, pluginsSrcDir)).forEach((f) => {
|
|
2936
|
-
fs.copyFileSync(path.join(pluginsSrcDir, f), path.join(NEXO_HOME, "plugins", f));
|
|
3042
|
+
fs.copyFileSync(path.join(pluginsSrcDir, f), path.join(NEXO_HOME, "core", "plugins", f));
|
|
2937
3043
|
});
|
|
2938
3044
|
}
|
|
2939
3045
|
|
|
2940
3046
|
// Scripts (all files + subdirectories like deep-sleep/)
|
|
2941
3047
|
if (fs.existsSync(scriptsSrcDir)) {
|
|
2942
|
-
copyDirRecursive(scriptsSrcDir, path.join(NEXO_HOME, "scripts"));
|
|
3048
|
+
copyDirRecursive(scriptsSrcDir, path.join(NEXO_HOME, "core", "scripts"));
|
|
2943
3049
|
// Make .sh files executable
|
|
2944
|
-
const scriptsDest = path.join(NEXO_HOME, "scripts");
|
|
3050
|
+
const scriptsDest = path.join(NEXO_HOME, "core", "scripts");
|
|
2945
3051
|
fs.readdirSync(scriptsDest).filter(f => f.endsWith(".sh")).forEach(f => {
|
|
2946
3052
|
fs.chmodSync(path.join(scriptsDest, f), "755");
|
|
2947
3053
|
});
|
|
@@ -2950,28 +3056,28 @@ async function main() {
|
|
|
2950
3056
|
|
|
2951
3057
|
// Core skills are shipped separately from personal skills.
|
|
2952
3058
|
if (fs.existsSync(skillsSrcDir)) {
|
|
2953
|
-
copyDirRecursive(skillsSrcDir, path.join(NEXO_HOME, "
|
|
3059
|
+
copyDirRecursive(skillsSrcDir, path.join(NEXO_HOME, "core", "skills"));
|
|
2954
3060
|
log(" Core skills installed.");
|
|
2955
3061
|
}
|
|
2956
3062
|
|
|
2957
3063
|
// Dashboard (recursive — includes static/, templates/)
|
|
2958
3064
|
const dashSrcDir = path.join(srcDir, "dashboard");
|
|
2959
3065
|
if (fs.existsSync(dashSrcDir)) {
|
|
2960
|
-
copyDirRecursive(dashSrcDir, path.join(NEXO_HOME, "dashboard"));
|
|
3066
|
+
copyDirRecursive(dashSrcDir, path.join(NEXO_HOME, "core", "dashboard"));
|
|
2961
3067
|
log(" Dashboard installed.");
|
|
2962
3068
|
}
|
|
2963
3069
|
|
|
2964
3070
|
// Rules directory
|
|
2965
3071
|
const rulesSrcDir = path.join(srcDir, "rules");
|
|
2966
3072
|
if (fs.existsSync(rulesSrcDir)) {
|
|
2967
|
-
copyDirRecursive(rulesSrcDir, path.join(NEXO_HOME, "rules"));
|
|
3073
|
+
copyDirRecursive(rulesSrcDir, path.join(NEXO_HOME, "core", "rules"));
|
|
2968
3074
|
log(" Rules installed.");
|
|
2969
3075
|
}
|
|
2970
3076
|
|
|
2971
3077
|
// Crons directory (manifest.json + sync.py — needed by catchup & watchdog)
|
|
2972
3078
|
const cronsSrcDir = path.join(srcDir, "crons");
|
|
2973
3079
|
if (fs.existsSync(cronsSrcDir)) {
|
|
2974
|
-
copyDirRecursive(cronsSrcDir, path.join(NEXO_HOME, "crons"));
|
|
3080
|
+
copyDirRecursive(cronsSrcDir, path.join(NEXO_HOME, "runtime", "crons"));
|
|
2975
3081
|
log(" Crons installed.");
|
|
2976
3082
|
}
|
|
2977
3083
|
|
|
@@ -3001,7 +3107,7 @@ async function main() {
|
|
|
3001
3107
|
// Hooks directory
|
|
3002
3108
|
const hooksSrcDir = path.join(srcDir, "hooks");
|
|
3003
3109
|
if (fs.existsSync(hooksSrcDir)) {
|
|
3004
|
-
const hooksDest = path.join(NEXO_HOME, "hooks");
|
|
3110
|
+
const hooksDest = path.join(NEXO_HOME, "core", "hooks");
|
|
3005
3111
|
copyDirRecursive(hooksSrcDir, hooksDest);
|
|
3006
3112
|
// Make .sh files executable
|
|
3007
3113
|
fs.readdirSync(hooksDest).filter(f => f.endsWith(".sh")).forEach(f => {
|
|
@@ -3028,7 +3134,7 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
|
|
|
3028
3134
|
- Give long explanations when a short answer suffices
|
|
3029
3135
|
- Repeat mistakes I've already logged
|
|
3030
3136
|
`;
|
|
3031
|
-
fs.writeFileSync(path.join(NEXO_HOME, "
|
|
3137
|
+
fs.writeFileSync(path.join(resolveRuntimeBrainDir(NEXO_HOME), "personality.md"), personality);
|
|
3032
3138
|
|
|
3033
3139
|
// Deep scan (P9) — comprehensive environment analysis
|
|
3034
3140
|
const profileData = {
|
|
@@ -3517,15 +3623,15 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
|
|
|
3517
3623
|
|
|
3518
3624
|
// Save full profile
|
|
3519
3625
|
fs.writeFileSync(
|
|
3520
|
-
path.join(NEXO_HOME, "
|
|
3626
|
+
path.join(resolveRuntimeBrainDir(NEXO_HOME), "profile.json"),
|
|
3521
3627
|
JSON.stringify(profileData, null, 2)
|
|
3522
3628
|
);
|
|
3523
|
-
log(`Saved to
|
|
3629
|
+
log(`Saved to ${path.join(resolveRuntimeBrainDir(NEXO_HOME), "profile.json")}`);
|
|
3524
3630
|
|
|
3525
3631
|
} else {
|
|
3526
3632
|
// No scan — save minimal profile
|
|
3527
3633
|
fs.writeFileSync(
|
|
3528
|
-
path.join(NEXO_HOME, "
|
|
3634
|
+
path.join(resolveRuntimeBrainDir(NEXO_HOME), "profile.json"),
|
|
3529
3635
|
JSON.stringify(profileData, null, 2)
|
|
3530
3636
|
);
|
|
3531
3637
|
log(lang === "es" ? "Sin problema. Iré aprendiéndote sobre la marcha." : "No problem. I'll learn about you as we go.");
|
|
@@ -3552,7 +3658,7 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
3552
3658
|
## Work patterns
|
|
3553
3659
|
(${operatorName} will observe and record these)
|
|
3554
3660
|
`;
|
|
3555
|
-
fs.writeFileSync(path.join(NEXO_HOME, "
|
|
3661
|
+
fs.writeFileSync(path.join(resolveRuntimeBrainDir(NEXO_HOME), "user-profile.md"), profileMd);
|
|
3556
3662
|
|
|
3557
3663
|
console.log("");
|
|
3558
3664
|
|
|
@@ -3647,7 +3753,7 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
3647
3753
|
log("Setting up automated processes...");
|
|
3648
3754
|
let schedule = loadOrCreateSchedule(NEXO_HOME);
|
|
3649
3755
|
schedule = applyClientSetupToSchedule(schedule, clientSetup);
|
|
3650
|
-
fs.writeFileSync(
|
|
3756
|
+
fs.writeFileSync(resolveRuntimeSchedulePath(NEXO_HOME), JSON.stringify(schedule, null, 2));
|
|
3651
3757
|
schedule = await maybeConfigurePowerPolicy(schedule, useDefaults);
|
|
3652
3758
|
schedule = await maybeConfigurePublicContribution(schedule, useDefaults);
|
|
3653
3759
|
schedule = await maybeConfigureFullDiskAccess(schedule, useDefaults, python);
|
|
@@ -3662,7 +3768,7 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
3662
3768
|
|
|
3663
3769
|
// Persist optional process preferences for auto-update
|
|
3664
3770
|
try {
|
|
3665
|
-
const configDir =
|
|
3771
|
+
const configDir = resolveRuntimeConfigDir(NEXO_HOME);
|
|
3666
3772
|
fs.mkdirSync(configDir, { recursive: true });
|
|
3667
3773
|
const optFile = path.join(configDir, "optionals.json");
|
|
3668
3774
|
fs.writeFileSync(optFile, JSON.stringify(enabledOptionals, null, 2));
|
|
@@ -3769,7 +3875,7 @@ See ~/.nexo/ for configuration.
|
|
|
3769
3875
|
// Write initial CLAUDE.md version tracker
|
|
3770
3876
|
const claudeMdVersionMatch = claudeMd.match(/nexo-claude-md-version:\s*([\d.]+)/);
|
|
3771
3877
|
if (claudeMdVersionMatch) {
|
|
3772
|
-
const dataDir =
|
|
3878
|
+
const dataDir = resolveRuntimeDataDir(NEXO_HOME);
|
|
3773
3879
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
3774
3880
|
fs.writeFileSync(path.join(dataDir, "claude_md_version.txt"), claudeMdVersionMatch[1]);
|
|
3775
3881
|
log(`CLAUDE.md version tracker initialized: v${claudeMdVersionMatch[1]}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.2",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain \u2014 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",
|