nexo-brain 7.20.10 → 7.20.12

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.20.10",
3
+ "version": "7.20.12",
4
4
  "description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
5
5
  "author": {
6
6
  "name": "NEXO Brain",
package/README.md CHANGED
@@ -18,7 +18,11 @@
18
18
 
19
19
  [Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
20
20
 
21
- Version `7.20.10` is the current packaged-runtime line. Patch release over v7.20.9 — Local Context manual refreshes now reconcile automatic roots every time, so newly mounted disks and upgraded default roots are picked up immediately from Desktop's "comprobar cambios" path.
21
+ Version `7.20.12` is the current packaged-runtime line. Patch release over v7.20.11 — Local Context now keeps the first index pass separate from live change tracking, persists the current indexing start time, caps compact context payloads for agents, and installs the Windows host scheduler needed to keep WSL indexing alive after reboots.
22
+
23
+ Previously in `7.20.11`: patch release over v7.20.10 — Local Context now starts from real system volume roots plus mounted/removable/network volumes, filters system/cache/app/product artifacts, and injects relevant local evidence automatically into heartbeat, task-open and pre-action context.
24
+
25
+ Previously in `7.20.10`: patch release over v7.20.9 — Local Context manual refreshes now reconcile automatic roots every time, so newly mounted disks and upgraded default roots are picked up immediately from Desktop's "comprobar cambios" path.
22
26
 
23
27
  Previously in `7.20.9`: patch release over v7.20.8 — Local Context scans automatic roots at full operational depth, falls back to crontab when Linux/WSL systemd user timers fail, passes Windows AppData email roots into WSL, and blocks Google API keys before HTML cleaning.
24
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.20.10",
3
+ "version": "7.20.12",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO Brain — 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",
package/src/cli.py CHANGED
@@ -1361,6 +1361,10 @@ def _local_context_query(args) -> int:
1361
1361
  limit=int(getattr(args, "limit", 12) or 12),
1362
1362
  evidence_required=not bool(getattr(args, "no_evidence_required", False)),
1363
1363
  current_context=getattr(args, "current_context", "") or "",
1364
+ mode=getattr(args, "mode", "compact") or "compact",
1365
+ max_chars=int(getattr(args, "max_chars", 20000) or 0),
1366
+ include_entities=bool(getattr(args, "include_entities", False)),
1367
+ include_relations=bool(getattr(args, "include_relations", False)),
1364
1368
  ),
1365
1369
  args,
1366
1370
  )
@@ -3211,6 +3215,10 @@ def main():
3211
3215
  local_context_query_p.add_argument("--intent", default="answer", help="Intent label stored with the query audit row")
3212
3216
  local_context_query_p.add_argument("--limit", type=int, default=12, help="Maximum evidence rows")
3213
3217
  local_context_query_p.add_argument("--current-context", default="", help="Optional current conversation/task context")
3218
+ local_context_query_p.add_argument("--mode", choices=["compact", "full"], default="compact", help="Payload shape. Compact is safe for chat clients; full is for debugging.")
3219
+ local_context_query_p.add_argument("--max-chars", type=int, default=20000, help="Maximum JSON payload size before truncation. Use 0 to disable.")
3220
+ local_context_query_p.add_argument("--include-entities", action="store_true", help="Include matched entities in the JSON payload.")
3221
+ local_context_query_p.add_argument("--include-relations", action="store_true", help="Include graph relations in the JSON payload.")
3214
3222
  local_context_query_p.add_argument("--no-evidence-required", action="store_true", help="Allow empty evidence results")
3215
3223
  local_context_query_p.add_argument("--json", action="store_true", help="JSON output")
3216
3224
 
package/src/crons/sync.py CHANGED
@@ -35,6 +35,14 @@ if str(_runtime_root) not in sys.path:
35
35
 
36
36
  import paths
37
37
  from cron_recovery import is_cron_enabled, resolve_declared_schedule, should_run_at_load
38
+ try:
39
+ from windows_runtime import resolve_windows_host_binary, running_inside_wsl
40
+ except ImportError:
41
+ def resolve_windows_host_binary(command: str) -> str:
42
+ return ""
43
+
44
+ def running_inside_wsl() -> bool:
45
+ return False
38
46
  try:
39
47
  from runtime_power import (
40
48
  launchctl_side_effects_allowed,
@@ -548,6 +556,65 @@ def _install_linux_crontab_fallback(entries: list[str]) -> dict:
548
556
  return {"ok": True, "entries": len(entries)}
549
557
 
550
558
 
559
+ def _powershell_single_quote(value: str | os.PathLike[str]) -> str:
560
+ return "'" + str(value).replace("'", "''") + "'"
561
+
562
+
563
+ def _windows_argument_quote(value: str | os.PathLike[str]) -> str:
564
+ text = str(value)
565
+ return '"' + text.replace("\\", "\\\\").replace('"', '\\"') + '"'
566
+
567
+
568
+ def _sync_wsl_windows_host_local_index_task(dry_run: bool = False) -> dict:
569
+ if not running_inside_wsl():
570
+ return {"ok": True, "skipped": True, "reason": "not_wsl"}
571
+ powershell = resolve_windows_host_binary("powershell.exe")
572
+ if not powershell:
573
+ log("WARNING: Windows host PowerShell not available; local-index host task not installed.")
574
+ return {"ok": False, "skipped": True, "reason": "powershell_missing"}
575
+
576
+ distro = str(os.environ.get("WSL_DISTRO_NAME", "")).strip()
577
+ if not distro:
578
+ log("WARNING: WSL_DISTRO_NAME missing; local-index host task not installed.")
579
+ return {"ok": False, "skipped": True, "reason": "wsl_distro_missing"}
580
+
581
+ python_bin = "/usr/bin/python3" if Path("/usr/bin/python3").exists() else "python3"
582
+ script_path = _runtime_code_dir() / "scripts" / "nexo-local-index.py"
583
+ command = (
584
+ f"cd {shlex.quote(str(Path.home()))} && "
585
+ f"NEXO_HOME={shlex.quote(str(NEXO_HOME))} "
586
+ f"NEXO_CODE={shlex.quote(str(_runtime_code_dir()))} "
587
+ f"{shlex.quote(python_bin)} {shlex.quote(str(script_path))}"
588
+ )
589
+ wsl_args = " ".join(
590
+ _windows_argument_quote(arg)
591
+ for arg in ("-d", distro, "--exec", "/bin/bash", "-lc", command)
592
+ )
593
+ task_name = "NEXO Local Memory"
594
+ ps_script = (
595
+ f"$action = New-ScheduledTaskAction -Execute 'wsl.exe' -Argument {_powershell_single_quote(wsl_args)}; "
596
+ "$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) "
597
+ "-RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration (New-TimeSpan -Days 3650); "
598
+ "$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries "
599
+ "-StartWhenAvailable -MultipleInstances IgnoreNew; "
600
+ f"Register-ScheduledTask -TaskName {_powershell_single_quote(task_name)} -Action $action -Trigger $trigger "
601
+ "-Settings $settings -Description 'NEXO Local Memory background indexing' -Force | Out-Null; "
602
+ f"Start-ScheduledTask -TaskName {_powershell_single_quote(task_name)}"
603
+ )
604
+
605
+ if dry_run:
606
+ log(f" DRY-RUN: would install Windows host task: {task_name}")
607
+ return {"ok": True, "dry_run": True, "task_name": task_name, "argument": wsl_args}
608
+
609
+ result = subprocess.run([powershell, "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps_script], capture_output=True, text=True, timeout=45)
610
+ if result.returncode != 0:
611
+ error = (result.stderr or result.stdout or "windows_host_task_install_failed").strip()
612
+ log(f"WARNING: Windows host local-index task install failed: {error}")
613
+ return {"ok": False, "task_name": task_name, "error": error}
614
+ log(f"Windows host task installed: {task_name}")
615
+ return {"ok": True, "task_name": task_name, "argument": wsl_args}
616
+
617
+
551
618
  def _enable_systemd_user_units(units: list[str]) -> dict:
552
619
  errors: list[str] = []
553
620
  daemon = subprocess.run(["systemctl", "--user", "daemon-reload"], capture_output=True, text=True)
@@ -699,6 +766,7 @@ def sync(dry_run: bool = False):
699
766
  system = platform.system()
700
767
  if system == "Linux":
701
768
  sync_linux(dry_run)
769
+ _sync_wsl_windows_host_local_index_task(dry_run)
702
770
  return
703
771
  if system != "Darwin":
704
772
  log(f"Unsupported platform: {system}. Skipping.")
@@ -9,6 +9,7 @@ from .api import (
9
9
  add_exclusion,
10
10
  add_root,
11
11
  clear_index,
12
+ context_router,
12
13
  context_query,
13
14
  diagnostics_tail,
14
15
  ensure_default_roots,
@@ -33,6 +34,7 @@ __all__ = [
33
34
  "add_exclusion",
34
35
  "add_root",
35
36
  "clear_index",
37
+ "context_router",
36
38
  "context_query",
37
39
  "diagnostics_tail",
38
40
  "ensure_default_roots",