nexo-brain 2.6.1 → 2.6.3
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 +2 -2
- package/bin/nexo-brain.js +53 -10
- package/package.json +1 -1
- package/src/auto_update.py +534 -0
- package/src/cli.py +46 -186
- package/src/cron_recovery.py +86 -6
- package/src/crons/sync.py +11 -3
- package/src/nexo.db +0 -0
- package/src/plugins/schedule.py +20 -4
- package/src/plugins/update.py +26 -14
- package/src/runtime_power.py +284 -0
- package/src/script_registry.py +66 -0
- package/src/scripts/nexo-catchup.py +10 -5
- package/src/server.py +6 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.3",
|
|
4
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
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/README.md
CHANGED
|
@@ -280,7 +280,7 @@ NEXO Brain doesn't just respond — it runs 14 autonomous processes in the backg
|
|
|
280
280
|
| **postmortem** | 23:30 daily | Session consolidation, extract patterns from day's events |
|
|
281
281
|
| **catchup** | On boot | Runs any missed scheduled processes (Mac was off/asleep) |
|
|
282
282
|
| **tcc-approve** | On boot (macOS) | Auto-approve macOS permissions for Claude Code updates |
|
|
283
|
-
| **prevent-sleep** |
|
|
283
|
+
| **prevent-sleep** | Optional opt-in daemon | Keeps machine awake for nocturnal processes when `power_policy=always_on` (caffeinate/systemd-inhibit) |
|
|
284
284
|
| **evolution** | Weekly (Sun) | Self-improvement proposals — NEXO suggests and applies enhancements |
|
|
285
285
|
| **followup-hygiene** | Weekly (Sun) | Normalizes statuses, flags stale followups, cleans orphans |
|
|
286
286
|
| **learning-housekeep** | 03:15 daily | Dedup learnings, adjust weights by usage, process overdue reviews, reconcile decision outcomes |
|
|
@@ -289,7 +289,7 @@ NEXO Brain doesn't just respond — it runs 14 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 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
|
|
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. `prevent-sleep` is opt-in via the persisted power policy (`always_on` / `disabled` / `unset`). Personal scripts (your own automations) are tracked separately in the Personal Scripts Registry, can declare their own recovery policy inline, and are never touched by the core sync. If your Mac was asleep during a scheduled process, the catch-up system can now recover both core crons and managed personal schedules according to their recovery contract.
|
|
293
293
|
|
|
294
294
|
## Deep Sleep v2 — Overnight Learning (v2.1.0)
|
|
295
295
|
|
package/bin/nexo-brain.js
CHANGED
|
@@ -226,9 +226,11 @@ function registerAllCoreHooks(settings, hooksDir, nexoHome) {
|
|
|
226
226
|
// We need to search and update in both formats.
|
|
227
227
|
let found = false;
|
|
228
228
|
|
|
229
|
-
for (
|
|
229
|
+
for (let idx = 0; idx < settings.hooks[hook.event].length; idx++) {
|
|
230
|
+
const entry = settings.hooks[hook.event][idx];
|
|
230
231
|
if (entry.hooks && Array.isArray(entry.hooks)) {
|
|
231
232
|
// Nested format: {matcher, hooks: [...]}
|
|
233
|
+
if (!entry.matcher) entry.matcher = "*";
|
|
232
234
|
const subIdx = entry.hooks.findIndex(
|
|
233
235
|
(h) => h.command && h.command.includes(hook.key)
|
|
234
236
|
);
|
|
@@ -240,19 +242,25 @@ function registerAllCoreHooks(settings, hooksDir, nexoHome) {
|
|
|
240
242
|
break;
|
|
241
243
|
}
|
|
242
244
|
} else if (entry.command && entry.command.includes(hook.key)) {
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
if (hook.timeout
|
|
245
|
+
// Legacy flat format: migrate to nested matcher+hooks.
|
|
246
|
+
const migrated = { type: "command", command };
|
|
247
|
+
if (hook.timeout) migrated.timeout = hook.timeout;
|
|
248
|
+
settings.hooks[hook.event][idx] = {
|
|
249
|
+
matcher: "*",
|
|
250
|
+
hooks: [migrated],
|
|
251
|
+
};
|
|
246
252
|
found = true;
|
|
247
253
|
break;
|
|
248
254
|
}
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
if (!found) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
258
|
+
const newHook = { type: "command", command };
|
|
259
|
+
if (hook.timeout) newHook.timeout = hook.timeout;
|
|
260
|
+
settings.hooks[hook.event].push({
|
|
261
|
+
matcher: "*",
|
|
262
|
+
hooks: [newHook],
|
|
263
|
+
});
|
|
256
264
|
}
|
|
257
265
|
}
|
|
258
266
|
}
|
|
@@ -286,6 +294,8 @@ function getDefaultSchedule(timezone) {
|
|
|
286
294
|
return {
|
|
287
295
|
timezone: timezone || "UTC",
|
|
288
296
|
auto_update: true,
|
|
297
|
+
power_policy: "unset",
|
|
298
|
+
power_policy_version: 1,
|
|
289
299
|
processes: {
|
|
290
300
|
"cognitive-decay": { hour: 3, minute: 0 },
|
|
291
301
|
"postmortem": { hour: 23, minute: 30 },
|
|
@@ -298,6 +308,33 @@ function getDefaultSchedule(timezone) {
|
|
|
298
308
|
};
|
|
299
309
|
}
|
|
300
310
|
|
|
311
|
+
async function maybeConfigurePowerPolicy(schedule, useDefaults) {
|
|
312
|
+
const current = String((schedule && schedule.power_policy) || "unset").toLowerCase();
|
|
313
|
+
if (current && current !== "unset") {
|
|
314
|
+
return schedule;
|
|
315
|
+
}
|
|
316
|
+
if (useDefaults || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
317
|
+
schedule.power_policy = "unset";
|
|
318
|
+
schedule.power_policy_version = 1;
|
|
319
|
+
return schedule;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
console.log("");
|
|
323
|
+
log("Optional power policy:");
|
|
324
|
+
log("If enabled, NEXO will try to keep the machine awake for background work.");
|
|
325
|
+
const answer = (await ask(" Keep this machine awake for background work? [y/N/later]: ")).trim().toLowerCase();
|
|
326
|
+
if (answer === "y" || answer === "yes") {
|
|
327
|
+
schedule.power_policy = "always_on";
|
|
328
|
+
} else if (answer === "later" || answer === "l") {
|
|
329
|
+
schedule.power_policy = "unset";
|
|
330
|
+
} else {
|
|
331
|
+
schedule.power_policy = "disabled";
|
|
332
|
+
}
|
|
333
|
+
schedule.power_policy_version = 1;
|
|
334
|
+
fs.writeFileSync(path.join(NEXO_HOME, "config", "schedule.json"), JSON.stringify(schedule, null, 2));
|
|
335
|
+
return schedule;
|
|
336
|
+
}
|
|
337
|
+
|
|
301
338
|
/**
|
|
302
339
|
* Resolve the venv python path for an existing NEXO_HOME installation.
|
|
303
340
|
*/
|
|
@@ -370,6 +407,9 @@ function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAge
|
|
|
370
407
|
const sPath = scriptPath(proc);
|
|
371
408
|
const interp = interpreterPath(proc);
|
|
372
409
|
const s = getSchedule(proc);
|
|
410
|
+
if (proc.name === "prevent-sleep" && (schedule.power_policy || "unset") !== "always_on") {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
373
413
|
|
|
374
414
|
let scheduleBlock = "";
|
|
375
415
|
if (proc.type === "keepAlive") {
|
|
@@ -477,6 +517,7 @@ function installAllProcesses(platform, pythonPath, nexoHome, schedule, launchAge
|
|
|
477
517
|
const sPath = scriptPath(proc);
|
|
478
518
|
const interp = interpreterPath(proc);
|
|
479
519
|
const s = getSchedule(proc);
|
|
520
|
+
if (proc.name === "prevent-sleep" && (schedule.power_policy || "unset") !== "always_on") continue;
|
|
480
521
|
|
|
481
522
|
const serviceType = proc.type === "keepAlive" ? "simple" : "oneshot";
|
|
482
523
|
const restartPolicy = proc.type === "keepAlive" ? "Restart=always\nRestartSec=5" : "";
|
|
@@ -795,7 +836,8 @@ async function main() {
|
|
|
795
836
|
log(" All 8 core hooks registered in Claude Code settings.");
|
|
796
837
|
|
|
797
838
|
// Regenerate all core LaunchAgents / systemd timers
|
|
798
|
-
|
|
839
|
+
let migSchedule = loadOrCreateSchedule(NEXO_HOME);
|
|
840
|
+
migSchedule = await maybeConfigurePowerPolicy(migSchedule, useDefaults);
|
|
799
841
|
const migPython = findVenvPython(NEXO_HOME) || "python3";
|
|
800
842
|
let migOptionals = {};
|
|
801
843
|
try {
|
|
@@ -2067,7 +2109,8 @@ ${doScan ? `- Stack: ${Object.keys(profileData.code.languages || {}).slice(0, 5)
|
|
|
2067
2109
|
|
|
2068
2110
|
// Step 7: Create schedule.json (only on fresh install) and install core processes
|
|
2069
2111
|
log("Setting up automated processes...");
|
|
2070
|
-
|
|
2112
|
+
let schedule = loadOrCreateSchedule(NEXO_HOME);
|
|
2113
|
+
schedule = await maybeConfigurePowerPolicy(schedule, useDefaults);
|
|
2071
2114
|
const enabledOptionals = { dashboard: doDashboard };
|
|
2072
2115
|
if (isEphemeralInstall(NEXO_HOME)) {
|
|
2073
2116
|
log("Ephemeral HOME/NEXO_HOME detected — skipping LaunchAgents installation.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.3",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
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": {
|