nexo-brain 7.23.12 → 7.24.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.
Files changed (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +15 -11
  3. package/bin/nexo-brain.js +42 -235
  4. package/package.json +1 -1
  5. package/src/automation_supervisor.py +1 -1
  6. package/src/cli.py +255 -9
  7. package/src/cognitive_control_observatory.py +224 -0
  8. package/src/dashboard/app.py +26 -9
  9. package/src/db/__init__.py +2 -0
  10. package/src/db/_learnings.py +1 -1
  11. package/src/db/_memory_v2.py +107 -1
  12. package/src/db/_protocol.py +2 -2
  13. package/src/db/_reminders.py +132 -4
  14. package/src/db/_schema.py +2 -2
  15. package/src/events_bus.py +4 -5
  16. package/src/guardrails/__init__.py +0 -0
  17. package/src/guardrails/minimal_delta.py +267 -0
  18. package/src/learning_resolver.py +419 -0
  19. package/src/lifecycle_events.py +9 -9
  20. package/src/local_context/api.py +67 -5
  21. package/src/local_context/usage_events.py +24 -0
  22. package/src/memory_observation_processor.py +28 -0
  23. package/src/memory_retrieval.py +5 -5
  24. package/src/operator_language.py +2 -0
  25. package/src/plugins/backup.py +1 -1
  26. package/src/plugins/cortex.py +21 -21
  27. package/src/plugins/episodic_memory.py +11 -11
  28. package/src/plugins/goal_engine.py +3 -3
  29. package/src/plugins/personal_scripts.py +75 -0
  30. package/src/plugins/protocol.py +10 -1
  31. package/src/pre_answer_router.py +116 -0
  32. package/src/r_catalog.py +4 -5
  33. package/src/saved_not_used_audit.py +31 -31
  34. package/src/script_registry.py +444 -1
  35. package/src/scripts/deep-sleep/apply_findings.py +79 -17
  36. package/src/scripts/nexo-daily-self-audit.py +46 -13
  37. package/src/scripts/nexo-email-migrate-config.py +2 -2
  38. package/src/scripts/nexo-email-monitor.py +19 -19
  39. package/src/scripts/nexo-followup-hygiene.py +40 -8
  40. package/src/scripts/nexo-followup-runner.py +31 -31
  41. package/src/scripts/nexo-inbox-hook.sh +1 -1
  42. package/src/scripts/nexo-learning-validator.py +24 -3
  43. package/src/server.py +73 -1
  44. package/src/system_catalog.py +31 -31
  45. package/src/tools_learnings.py +96 -65
  46. package/src/tools_memory_v2.py +2 -2
  47. package/src/tools_sessions.py +25 -7
  48. package/templates/core-prompts/postmortem-consolidator.md +3 -3
  49. package/templates/core-prompts/r17-promise-debt-injection.md +1 -1
  50. package/templates/core-prompts/server-mcp-instructions.md +6 -6
  51. package/tool-enforcement-map.json +143 -13
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.23.12",
3
+ "version": "7.24.0",
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.23.12` is the current packaged-runtime line. Patch over v7.23.11 - protected database recovery now repairs degraded Brain tables from backup without rolling back newer rows.
21
+ Version `7.24.0` is the current packaged-runtime line. Minor release over v7.23.13 - Home Agents, cognitive quality controls, English operational copy, and non-blocking task-open context are integrated into main.
22
+
23
+ Previously in `7.23.13`: patch over v7.23.12 - release guardrails now audit publish workflows for masked failures and add minimal-delta coverage for punctual UI edits.
24
+
25
+ Previously in `7.23.12`: patch over v7.23.11 - protected database recovery now repairs degraded Brain tables from backup without rolling back newer rows.
22
26
 
23
27
  Previously in `7.23.11`: patch over v7.23.10 - older installed runtimes can update safely even when `cognitive_paths.py` has not been synced yet.
24
28
 
@@ -202,24 +206,24 @@ Previously in `7.4.1`: patch release correcting the over-promise in v7.4.0's rel
202
206
 
203
207
  Previously in `7.2.0`: minor release consolidating three parallel workstreams into a single Guardian-active-by-default train. Block K roadmap closure (G1 enforcer active, G3 SSH remote-write detector, `src/guardian_runtime_config.py` resolver, `_persist_guardian_hard_defaults` during `nexo update`). F0.6 hardening wave (`nexo rollback f06` CLI, `src/scripts/prune_runtime_backups.py` promoted to core, `docs/f06-layout-contract.md`, three new doctor boot-tier checks, `scripts/nexo-migrate-nora.sh` + `scripts/f0-safe-apply-remote.sh` idempotent migration). Adaptive weights flipped from "14-day calendar wait" to "14 days OR (≥200 samples AND ≥2 days)" with auto-promotion during `nexo update`. Small-fixes batch: R34 `bool("unknown")==True` fix, `classify_scripts_dir` dedup, B10 module-level path constants lazy-evaluated, schedule override audit log, `scripts/pre-release-verify.sh` + `docs/release-discipline.md`, pre-commit hook that blocks commits when `tool-enforcement-map.json` drifts from `src/plugins/`.
204
208
 
205
- Previously in `7.1.10`: follow-up over v7.1.8 that shipped two rescue batches of WIP stashed aside during the v7.1.8 release window. First rescue: `src/autonomy_mandate.py` expanded the mandate-detection vocabulary (hazlo todo / no pares / estás al mando / te dejo al mando / sigue sin parar / haz el plan completo), added three honest flags on `MandateState` (`execute_until_blocker`, `suppress_mid_task_menus`, `revalidate_after_compaction`) with session filtering, wired post/pre-compact hooks that read those flags, surfaced them through protocol/workflow handlers and session payload, and introduced the new `src/checkpoint_policy.py` module with tests. Second rescue: `scripts/verify_release_readiness.py` gained a smoke-artifact contract pass that validates `release-contracts/smoke/v<version>.json` before any tag push, the release-final audit skill references the new contract, `src/hook_guardrails.py` + `src/hooks/post_tool_use.py` refine the post-tool protocol reminder path with a new contract test, and a couple of core prompts (task-close evidence, r14 correction learning) got wording polish.
209
+ Previously in `7.1.10`: follow-up over v7.1.8 that shipped two rescue batches of WIP stashed aside during the v7.1.8 release window. First rescue: `src/autonomy_mandate.py` expanded the Spanish-language mandate-detection phrase set (do everything / do not stop / you are in charge / I leave you in charge / keep going / do the full plan), added three honest flags on `MandateState` (`execute_until_blocker`, `suppress_mid_task_menus`, `revalidate_after_compaction`) with session filtering, wired post/pre-compact hooks that read those flags, surfaced them through protocol/workflow handlers and session payload, and introduced the new `src/checkpoint_policy.py` module with tests. Second rescue: `scripts/verify_release_readiness.py` gained a smoke-artifact contract pass that validates `release-contracts/smoke/v<version>.json` before any tag push, the release-final audit skill references the new contract, `src/hook_guardrails.py` + `src/hooks/post_tool_use.py` refine the post-tool protocol reminder path with a new contract test, and a couple of core prompts (task-close evidence, r14 correction learning) got wording polish.
206
210
 
207
211
  Previously in `7.1.8`: batch release over v7.1.7 consolidating the Block K Guardian/Enforcer roadmap (auto-drain of stale `protocol_debt` rows, destructive-command pre-tool gate, `guard_check`-required gate, inline guard ack on `nexo_task_open`, Guardian Health in the morning briefing) with Block D hardcode cleanup (classifier-backed `backfill_task_owner`, migration v50 supersedes the duplicate NEXO-product learning pair, new semantic-hardcodes audit) and Block E product guards (LaunchAgent plist protection, agent-name fallbacks no longer leak the product identity, `francisco_emails` removed from the email-config dict export, `runner-health-check.py` + `nexo_personal_automation.py` promoted from personal to core).
208
212
 
209
- Previously in `7.0.1`: hotfix over v7.0.0 (db._core.DB_PATH was only caller still hardcoded to legacy ~/.nexo/data/nexo.db; every shared-DB command silently returned empty results post-migration). Previously in `7.0.0`: **BREAKING — Plan Consolidado fase F0.6**: physical separation of the runtime tree into `~/.nexo/{core,personal,runtime}/`. The flat layout (`~/.nexo/scripts/`, `brain/`, `data/`, `operations/`, ...) is gone. Operators on v6.x are auto-migrated on first `nexo update`; fresh installs land directly in the new tree. New `paths.py` helpers are transition-aware.
213
+ Previously in `7.0.1`: hotfix over v7.0.0 (db._core.DB_PATH was only caller still hardcoded to legacy ~/.nexo/data/nexo.db; every shared-DB command silently returned empty results post-migration). Previously in `7.0.0`: **BREAKING — Consolidated Plan Phase F0.6**: physical separation of the runtime tree into `~/.nexo/{core,personal,runtime}/`. The flat layout (`~/.nexo/scripts/`, `brain/`, `data/`, `operations/`, ...) is gone. Operators on v6.x are auto-migrated on first `nexo update`; fresh installs land directly in the new tree. New `paths.py` helpers are transition-aware.
210
214
 
211
- Previously in `6.5.0`: Plan Consolidado fase F0.2: operators can now `nexo scripts enable|disable|status <name>` any personal automation. The cron wrapper honours the flag at every tick (`exit 0` with `summary='[disabled]'` while the LaunchAgent stays loaded). The companion NEXO Desktop client (a closed-source product, distributed separately) wires the same toggle into its Automatizaciones panel. See [CHANGELOG](CHANGELOG.md) for the full diff.
215
+ Previously in `6.5.0`: Consolidated Plan Phase F0.2: operators can now `nexo scripts enable|disable|status <name>` any personal automation. The cron wrapper honours the flag at every tick (`exit 0` with `summary='[disabled]'` while the LaunchAgent stays loaded). The companion NEXO Desktop client (a closed-source product, distributed separately) wires the same toggle into its Automations panel. See [CHANGELOG](CHANGELOG.md) for the full diff.
212
216
 
213
217
  > **About NEXO Desktop.** NEXO Desktop is a separate closed-source companion app distributed at [nexo-desktop.com](https://nexo-desktop.com/) — its source does not live in this repo. When release notes mention Desktop they describe a coordinated client release that consumes the Brain's CLI / MCP contract; the Brain itself is fully usable on its own (terminal, Codex, Claude Code, or any MCP client). If you want the product edition rather than the open-source Brain alone, contact `info@wazion.com` and ask about NEXO Desktop.
214
218
 
215
219
 
216
- Previously in `6.4.0`: Plan Consolidado fase F1 — multi-tenant email accounts (`email_accounts` table, `nexo email setup` interactive wizard, `nexo email add --password-stdin --json` for machine consumers, idempotent migrator from legacy `~/.nexo/nexo-email/config.json`). On post-F0.6 installs that legacy-looking path is only a compatibility alias/shim into `~/.nexo/runtime/nexo-email/config.json`; it should never be treated as a second source of truth.
220
+ Previously in `6.4.0`: Consolidated Plan Phase F1 — multi-tenant email accounts (`email_accounts` table, `nexo email setup` interactive wizard, `nexo email add --password-stdin --json` for machine consumers, idempotent migrator from legacy `~/.nexo/nexo-email/config.json`). On post-F0.6 installs that legacy-looking path is only a compatibility alias/shim into `~/.nexo/runtime/nexo-email/config.json`; it should never be treated as a second source of truth.
217
221
 
218
222
  Previously in `6.3.1`: privacy hotfix over v6.3.0. The nightly auditor caught that `src/presets/entities_universal.json` in v6.3.0 shipped operator-specific `vhost_mapping` entries (private IPs, hostnames, tenant names). v6.3.1 pulls those out into `src/presets/entities_local.sample.json` (template) + `.gitignore`'d `~/.nexo/brain/presets/entities_local.json` (operator copy), and the installer drops the sample at `nexo init`. No behaviour change on the Guardian side.
219
223
 
220
- Previously in `6.3.0` — Plan Consolidado wave 2, coordinated with NEXO Desktop v0.18.0. Closes the remaining Guardian roadmap items that do not require an invasive structure migration: extended `cognitive_sentiment` shape (is_correction/valence/intent), extended `entities` schema, 21 labelled rule fixtures with R13 spike gates, Fase F telemetry loops + Deep Sleep phase, pinned local zero-shot classifier skeleton (mDeBERTa), hook respects `NEXO_MIGRATING=1`, `origin` column on `personal_scripts`, and the T4 LLM gate wrapping R15/R23e/R23f/R23h (byte-parity Py ↔ JS). Two pre-release auditors flagged a CRITICAL in the first JS wire (method-name + async mismatch) and a HIGH (classifier bool conflated "no" with "unparseable"); both corrected with regression tests before merge.
224
+ Previously in `6.3.0` — Consolidated Plan wave 2, coordinated with NEXO Desktop v0.18.0. Closes the remaining Guardian roadmap items that do not require an invasive structure migration: extended `cognitive_sentiment` shape (is_correction/valence/intent), extended `entities` schema, 21 labelled rule fixtures with R13 spike gates, Phase F telemetry loops + Deep Sleep phase, pinned local zero-shot classifier skeleton (mDeBERTa), hook respects `NEXO_MIGRATING=1`, `origin` column on `personal_scripts`, and the T4 LLM gate wrapping R15/R23e/R23f/R23h (byte-parity Py ↔ JS). Two pre-release auditors flagged a CRITICAL in the first JS wire (method-name + async mismatch) and a HIGH (classifier bool conflated "no" with "unparseable"); both corrected with regression tests before merge.
221
225
 
222
- Previously in `6.1.1`: small fix to `nexo --help` so the `Latest: vX` line reliably appears when NEXO Desktop invokes the CLI via subprocess — unblocks the Desktop Brain auto-update banner that previously couldn't parse the version delta. No behaviour change for interactive terminal users; the 6-hour registry cache still rate-limits network calls. Bundles all v6.1.0 Protocol Enforcer Fase 2 + multi-claude-sid hotfix content.
226
+ Previously in `6.1.1`: small fix to `nexo --help` so the `Latest: vX` line reliably appears when NEXO Desktop invokes the CLI via subprocess — unblocks the Desktop Brain auto-update banner that previously couldn't parse the version delta. No behaviour change for interactive terminal users; the 6-hour registry cache still rate-limits network calls. Bundles all v6.1.0 Protocol Enforcer Phase 2 + multi-claude-sid hotfix content.
223
227
 
224
228
  Previously in `6.0.2`: adds the reserved caller prefix `personal/*` so scripts living in `~/.nexo/scripts/` can invoke the automation backend with their own caller id without editing `src/resonance_map.py`. New kwarg `tier` (`"maximo"` / `"alto"` / `"medio"` / `"bajo"`) on `run_automation_prompt`, `run_automation_interactive`, `nexo_helper.run_automation_text`, `nexo_helper.run_automation_json`, and `nexo-agent-run.py --tier`. Precedence for `personal/*` callers: explicit `tier=` → explicit `reasoning_effort=` → `calibration.preferences.default_resonance` → `DEFAULT_RESONANCE` (`alto`). Registered callers keep their behaviour unchanged. New guide: [`docs/personal-scripts-guide.md`](docs/personal-scripts-guide.md).
225
229
 
@@ -233,11 +237,11 @@ Previously in `5.10.1`: silent, one-shot migration that recovers legacy `reasoni
233
237
 
234
238
  Previously in `5.10.0`: fixes the deep-sleep extract bloat that made Session 1 take ~57 minutes on some installs (new `bare_mode` on `run_automation_prompt` wires `claude --bare` for JSON-only extractor callers — ~4.3× faster per child, sourced from `ANTHROPIC_API_KEY` env or `~/.claude/anthropic-api-key.txt`). `caller=` is now **mandatory** on `run_automation_prompt` — no silent fallback; every automation subprocess traces back to a registered caller with a deliberate tier. Five personal scripts (`personal/email-monitor`, `personal/github-monitor`, `personal/post-x`, `personal/followup-runner`, `personal/orchestrator-v2`) joined the resonance map with tiers picked per caller based on what each one does. gbp/* marketing posts bumped from `medio` to `alto` (public-facing copy, quality first over speed). 65 legacy protocol debts bulk-resolved as part of the audit — the patterns that generated them are structurally closed by mandatory `caller=` + unified session log + bare_mode.
235
239
 
236
- Previously in `5.9.1`: adds `default_resonance` to `brain/calibration.json` via the Desktop-facing schema (`nexo schema --json`), so NEXO Desktop's Preferences dialog renders a select with `Máximo` / `Alto (recomendado)` / `Medio` / `Bajo` automatically — no Desktop release needed. `resolve_tier_for_caller` reads calibration first and falls back to the legacy `schedule.json` location. `nexo preferences --resonance` writes both. The UI control only affects interactive sessions (`nexo chat`, Desktop new conversation, interactive `nexo update`); crons and background processes stay pinned per caller in `resonance_map.py`.
240
+ Previously in `5.9.1`: adds `default_resonance` to `brain/calibration.json` via the Desktop-facing schema (`nexo schema --json`), so NEXO Desktop's Preferences dialog renders a localized resonance selector automatically — no Desktop release needed. `resolve_tier_for_caller` reads calibration first and falls back to the legacy `schedule.json` location. `nexo preferences --resonance` writes both. The UI control only affects interactive sessions (`nexo chat`, Desktop new conversation, interactive `nexo update`); crons and background processes stay pinned per caller in `resonance_map.py`.
237
241
 
238
242
  Previously in `5.9.0`: every Claude/Codex invocation now flows through a central **resonance map** and a **unified session log**. Four tiers (`MAXIMO` / `ALTO` / `MEDIO` / `BAJO`) each resolve to a concrete `(model, reasoning_effort)` pair per backend. User-facing callers (`nexo chat`, Desktop new conversation, interactive `nexo update`) honour the user's `default_resonance` preference; system-owned callers (deep-sleep, evolution, catchup, GBP posts, …) run at a fixed tier chosen per caller in `src/resonance_map.py` — the user's preference never downgrades a cron we decided needs `MAXIMO`. Unknown callers raise `UnregisteredCallerError`. Migration #41 adds `caller`, `session_type`, `started_at`, `ended_at`, `pid`, `resonance_tier` to `automation_runs`; interactive sessions record a row at spawn (with `ended_at=NULL`) and update it on close, so the Brain now has a single source of truth for every Claude/Codex call regardless of origin. New `nexo preferences --resonance` CLI. New MCP tools `nexo_session_log_create` / `nexo_session_log_close` let NEXO Desktop (which spawns `claude` directly from its TypeScript process) feed the same log.
239
243
 
240
- Previously in `5.8.2`: the Brain core no longer auto-classifies `followups` and `reminders` on behalf of agents. v5.8.0's `classify_task()` heuristic (NEXO-specific ID prefixes `NF-PROTOCOL-*` / `NF-DS-*` / `NF-AUDIT-*`, Spanish user-verbs `debes` / `revisar` / `firmar`, agent keywords `monitor` / `auditoría diaria` / `checkpoint`) was fine for NEXO's own DB but bled convention into every third-party agent plugged into the shared Brain. The core now persists `internal=0` and `owner=NULL` when the caller omits them, and clients that want automatic classification (NEXO Desktop does, via its `_legacyClassifyOwner` helpers) compute it themselves and pass the result. Migration #40 keeps the columns + indexes; rows already backfilled by v5.8.0 keep their values. `normalise_owner` still explicitly rejects the string `"nexo"` so legacy hardcoding cannot sneak back in.
244
+ Previously in `5.8.2`: the Brain core no longer auto-classifies `followups` and `reminders` on behalf of agents. v5.8.0's `classify_task()` heuristic (NEXO-specific ID prefixes `NF-PROTOCOL-*` / `NF-DS-*` / `NF-AUDIT-*`, Spanish user-verb patterns, and agent keywords such as monitor or daily audit) was fine for NEXO's own DB but bled convention into every third-party agent plugged into the shared Brain. The core now persists `internal=0` and `owner=NULL` when the caller omits them, and clients that want automatic classification (NEXO Desktop does, via its `_legacyClassifyOwner` helpers) compute it themselves and pass the result. Migration #40 keeps the columns + indexes; rows already backfilled by v5.8.0 keep their values. `normalise_owner` still explicitly rejects the string `"nexo"` so legacy hardcoding cannot sneak back in.
241
245
 
242
246
  Previously in `5.8.1`: closes a self-reinforcing `launchctl kickstart -k` loop in the watchdog that wedged deep-sleep Phase 2 between 2026-04-14 and 2026-04-17. The cron wrapper now INSERTs an in-flight row (`ended_at=NULL`) at start and traps SIGTERM/INT/HUP to close it with `exit_code=143` instead of vanishing from `cron_runs`. The watchdog interprets in-flight rows as "currently running" and only re-executes after verifying the worker process is dead. `extract.py` classifies CLI failures into transient (`overloaded_error`, rate-limit, timeout, signal — retried next run) and deterministic (skipped after `MAX_POISON_ATTEMPTS`), and passes a slim shared-context (200 head lines + metadata) instead of the full 400+ KB dump. A new `auto_update._heal_deep_sleep_runtime()` repairs existing installs silently on the next `nexo update`: poisoned checkpoints, stale locks, dangling `cron_runs` rows, and bloated `.watchdog-fails` counters.
243
247
 
@@ -336,8 +340,8 @@ Version `5.2.1` fixes the Deep Sleep datetime regression and closes the decision
336
340
 
337
341
  Version `5.2.0` closes two focused gaps in the Cortex layer that were left open by the v5.1 audit — the high-stakes response-contract detector was English-only, and the `nexo-cortex-cycle` cron was writing a quality snapshot that no reader ever consumed:
338
342
 
339
- - `HIGH_STAKES_KEYWORDS_ES` adds ~45 Spanish keywords to the high-stakes detector with accented and unaccented variants, so a goal written in Spanish (`migrar la base de datos de producción`) trips the same gate as its English twin.
340
- - `NEGATION_PATTERNS` suppresses false positives when the user explicitly disclaims touching the sensitive area (`sin afectar producción`, `no tocar prod`, `without touching production`, `don't modify`). The raw keyword being present is no longer enough to flag the task.
343
+ - `HIGH_STAKES_KEYWORDS_ES` adds ~45 Spanish-language keywords to the high-stakes detector with accented and unaccented variants, so a goal written in Spanish trips the same gate as its English twin.
344
+ - `NEGATION_PATTERNS` suppresses false positives when the user explicitly disclaims touching the sensitive area, including both Spanish and English boundary statements. The raw keyword being present is no longer enough to flag the task.
341
345
  - `evaluate_response_confidence` accepts two new optional kwargs, `pre_action_context_hits` (+up to 10) and `area_has_atlas_entry` (+5), so the score can finally reward tasks that loaded real context instead of only punishing unprepared ones. Both signals are capped and cannot override a real risk penalty.
342
346
  - A monotonic numeric safeguard layers on top of the boolean decision tree: `answer` downgrades to `verify` when `final_score < 50`, and `verify` downgrades to `defer` when `high_stakes` and `final_score < 30`. The safeguard can only make response discipline stricter, never looser.
343
347
  - `handle_cortex_quality` in `src/plugins/cortex.py` now reads `$NEXO_HOME/operations/cortex-quality-latest.json` when the requested window (7 or 1 days) is fresh (<6h 30m) and the schema matches — silent fallback to the live SQL computation on any failure. The handler's JSON response now includes `"source": "cache" | "live"` for observability.
package/bin/nexo-brain.js CHANGED
@@ -535,7 +535,7 @@ function isOnboardingComplete(calibration) {
535
535
  if (meta.onboarding_completed === true) {
536
536
  // v7.12.11 — bug surfaced on Inma's smoke install 2026-05-03: Desktop
537
537
  // bootstrap runs nexo-brain in --yes/--skip mode, which used to write
538
- // `onboarding_completed: true` alongside the placeholder "Usuario"/"en"
538
+ // `onboarding_completed: true` alongside the placeholder "User"/"en"
539
539
  // defaults. The Desktop wizard then never fired because this returned
540
540
  // true on the very first launch. Treat a placeholder name as "marker is
541
541
  // a lie, real onboarding never happened" so the renderer can still
@@ -1918,29 +1918,6 @@ function persistClaudeCliPath(claudePath) {
1918
1918
  }
1919
1919
 
1920
1920
  function clientSetupStrings(lang) {
1921
- if (lang === "es") {
1922
- return {
1923
- title: "Shared brain siempre activo. Ahora elige clientes y backend de automatización.",
1924
- detected: "Clientes detectados",
1925
- yes: "sí",
1926
- no: "no",
1927
- useClaudeCodeQ: " ¿Quieres usar Claude Code como cliente interactivo? (recomendado)",
1928
- useCodexQ: " ¿Quieres usar Codex como cliente interactivo?",
1929
- useDesktopQ: " ¿Quieres conectar Claude Desktop al mismo brain?",
1930
- defaultTerminalQ: " ¿Qué cliente debe abrir `nexo chat` por defecto?",
1931
- automationQ: " ¿Quieres automatización en background? (sleep, deep-sleep, synthesis, self-audit, evolution, postmortem)",
1932
- automationBackendQ: " ¿Qué backend debe ejecutar esa automatización?",
1933
- installClaudeQ: " Claude Code no está instalado. ¿Quieres instalarlo ahora?",
1934
- installCodexQ: " Codex no está instalado. ¿Quieres instalarlo ahora?",
1935
- installingClaude: "Instalando Claude Code...",
1936
- installingCodex: "Instalando Codex...",
1937
- desktopManual: "Claude Desktop no se instala desde NEXO. Cuando exista, se conectará con la sync de clientes.",
1938
- terminalFallback: (label) => `El cliente terminal elegido no está disponible. \`nexo chat\` quedará pendiente hasta instalar ${label}.`,
1939
- automationDisabled: (label) => `El backend ${label} sigue sin estar disponible. Se desactiva la automatización por ahora.`,
1940
- summary: (defaultClient, defaultProfile, backend, backendProfile, automationEnabled) =>
1941
- `Configuración clientes: chat=${defaultClient}(${defaultProfile}), automation=${automationEnabled ? `${backend}(${backendProfile})` : "none"}`,
1942
- };
1943
- }
1944
1921
  return {
1945
1922
  title: "Shared brain is always on. Now choose your clients and automation backend.",
1946
1923
  detected: "Detected clients",
@@ -2021,15 +1998,13 @@ function formatRuntimeProfile(profile = {}) {
2021
1998
  // tier (maximo / alto / medio / bajo) and that choice drives every backend
2022
1999
  // via src/resonance_tiers.json. No more model or effort questions.
2023
2000
  async function askResonanceTier(lang, currentTier) {
2024
- const recommended = lang === "es" ? " (recomendado)" : " (recommended)";
2025
- const question = lang === "es"
2026
- ? " ¿Qué nivel de potencia quieres por defecto para tus conversaciones?"
2027
- : " Which default power level do you want for your conversations?";
2001
+ const recommended = " (recommended)";
2002
+ const question = " Which default power level do you want for your conversations?";
2028
2003
  const options = [
2029
- { value: "maximo", label: lang === "es" ? "máximo" : "maximum" },
2030
- { value: "alto", label: (lang === "es" ? "alto" : "high") + recommended },
2031
- { value: "medio", label: lang === "es" ? "medio" : "medium" },
2032
- { value: "bajo", label: lang === "es" ? "bajo" : "low" },
2004
+ { value: "maximo", label: "maximum" },
2005
+ { value: "alto", label: "high" + recommended },
2006
+ { value: "medio", label: "medium" },
2007
+ { value: "bajo", label: "low" },
2033
2008
  ];
2034
2009
  const fallback = RESONANCE_TIER_NAMES.includes(currentTier) ? currentTier : DEFAULT_RESONANCE_TIER;
2035
2010
  const chosen = await askChoice(question, options, fallback);
@@ -2101,20 +2076,20 @@ function installClaudeCodeCli(platform) {
2101
2076
  // OFFLINE-FIRST v0.32.4: install claude-code wrapper + ALL its native packs
2102
2077
  // from bundled tarballs. Path: resources/brain-bundle/claude-code/*.tgz.
2103
2078
  //
2104
- // Bug que arregla este fix (encontrado 2026-05-02):
2105
- // claude-code 2.1.x ships como wrapper + 4 native packs por arquitectura
2079
+ // Bug fixed here (found 2026-05-02):
2080
+ // claude-code 2.1.x ships as a wrapper + 4 native packs per architecture
2106
2081
  // (@anthropic-ai/claude-code-linux-x64, -darwin-arm64, -darwin-x64,
2107
- // -linux-arm64). Antes solo bundeaba el wrapper (.tgz 13 KB) y pasaba SOLO
2108
- // ese al npm install. npm intentaba resolver los `optionalDependencies` del
2109
- // registry online fallo offline wrapper instala SIN binario claude
2082
+ // -linux-arm64). Previously only the wrapper was bundled (.tgz 13 KB) and
2083
+ // passed to npm install. npm tried to resolve `optionalDependencies` from the
2084
+ // online registry -> offline failure -> wrapper installs WITHOUT claude binary ->
2110
2085
  // `command -v claude` exit 127 → bootstrap "claude-runtime-missing-soft".
2111
- // Ahora bundeamos los 5 .tgz (wrapper + 4 native) y se los pasamos TODOS
2112
- // a npm en un solo install. npm los ve como dependencias pre-resueltas
2113
- // y skip el registry lookup. claude binary ejecutable resultante.
2086
+ // Now the 5 .tgz files (wrapper + 4 native packs) are bundled and passed to
2087
+ // npm in a single install. npm sees them as pre-resolved dependencies and
2088
+ // skips registry lookup, leaving an executable claude binary.
2114
2089
  const bundledClaudeDir = path.join(__dirname, "..", "claude-code");
2115
2090
  if (fs.existsSync(bundledClaudeDir)) {
2116
2091
  const allTgz = fs.readdirSync(bundledClaudeDir).filter((f) => f.endsWith(".tgz"));
2117
- // Ordenar: el wrapper primero (sin sufijo de plataforma), después los packs.
2092
+ // Order wrapper first (without platform suffix), then native packs.
2118
2093
  const wrapper = allTgz.find((f) => /^anthropic-ai-claude-code-\d/.test(f));
2119
2094
  // v7.12.6 — Filter native packs to ONLY the current platform/arch.
2120
2095
  // Bug: passing all 4 native packs to `npm install` triggers EBADPLATFORM
@@ -2154,7 +2129,7 @@ function installClaudeCodeCli(platform) {
2154
2129
  return { installed: true, path: claudeInstalled };
2155
2130
  }
2156
2131
  } else if (wrapper) {
2157
- // Fallback: solo wrapper (legacy bundle 0.32.3 y anteriores).
2132
+ // Fallback: wrapper only (legacy bundle 0.32.3 and older).
2158
2133
  const tgzPath = path.join(bundledClaudeDir, wrapper);
2159
2134
  log(" Installing claude-code from bundled wrapper only (legacy bundle, may need network for native pack)...");
2160
2135
  spawnSync(
@@ -2255,7 +2230,7 @@ async function configureClientSetup({ lang, useDefaults, autoInstall, detected }
2255
2230
  setup.interactive_clients.claude_desktop = await askYesNo(strings.useDesktopQ, detected.claude_desktop.installed);
2256
2231
 
2257
2232
  const defaultTerminalChoices = [
2258
- { value: "claude_code", label: lang === "es" ? "Claude Code (recomendado)" : "Claude Code (recommended)" },
2233
+ { value: "claude_code", label: "Claude Code (recommended)" },
2259
2234
  { value: "codex", label: "Codex" },
2260
2235
  ].filter((item) => setup.interactive_clients[item.value]);
2261
2236
 
@@ -2275,7 +2250,7 @@ async function configureClientSetup({ lang, useDefaults, autoInstall, detected }
2275
2250
  setup.automation_backend = await askChoice(
2276
2251
  strings.automationBackendQ,
2277
2252
  [
2278
- { value: "claude_code", label: lang === "es" ? "Claude Code (recomendado)" : "Claude Code (recommended)" },
2253
+ { value: "claude_code", label: "Claude Code (recommended)" },
2279
2254
  { value: "codex", label: "Codex" },
2280
2255
  ],
2281
2256
  backendDefault,
@@ -2834,10 +2809,10 @@ async function runSetup() {
2834
2809
  " ║ ║"
2835
2810
  );
2836
2811
  console.log(
2837
- " ║ Hello! / ¡Hola! / Bonjour! / Hallo! ║"
2812
+ " ║ Hello! ║"
2838
2813
  );
2839
2814
  console.log(
2840
- " ║ Ciao! / Olá! / こんにちは! / 你好! ║"
2815
+ " ║ Interactive installer ║"
2841
2816
  );
2842
2817
  console.log(
2843
2818
  " ╚══════════════════════════════════════════════════════════╝"
@@ -3274,14 +3249,13 @@ async function runSetup() {
3274
3249
  let python = resolveInstallerPython();
3275
3250
  if (!python) {
3276
3251
  if (platform === "darwin") {
3277
- // v0.32.5 — Mac vanilla NO trae python3. La auto-instalación de
3278
- // Homebrew vía `curl install.sh` requiere TTY interactivo + sudo +
3279
- // user accept license. Cuando este script se invoca desde Electron
3280
- // sandbox, NO hay TTY curl pipe cuelga sin progreso → bootstrap
3281
- // se queda silencioso. Mejor: detectar la ausencia de Python y
3282
- // surface un error CLARO al user con instrucciones manuales que
3283
- // funcionan siempre. Si hay TTY (corriendo desde terminal), seguimos
3284
- // con el path automático.
3252
+ // v0.32.5 — stock macOS does not include python3. Homebrew
3253
+ // auto-installation via `curl install.sh` requires an interactive TTY,
3254
+ // sudo, and license acceptance. When Electron invokes this script from
3255
+ // the sandbox there is NO TTY, so the curl pipe can hang with no
3256
+ // progress and leave bootstrap silent. Better: detect missing Python
3257
+ // and surface a clear user-facing error with manual instructions that
3258
+ // always work. If a TTY exists (terminal run), keep the automatic path.
3285
3259
  const isTty = !!(process.stdin && process.stdin.isTTY);
3286
3260
  let hasBrew = run("which brew");
3287
3261
  if (!hasBrew && !isTty) {
@@ -3305,11 +3279,11 @@ async function runSetup() {
3305
3279
  hasBrew = run("which brew") || run("eval $(/opt/homebrew/bin/brew shellenv) && which brew");
3306
3280
  }
3307
3281
  if (hasBrew) {
3308
- // v0.32.5 — explicit @3.12 pin: el Brain `requirements.txt` y los
3309
- // wheels manylinux están compilados contra cp312. `brew install
3310
- // python3` instala el `python3` formula que actualmente apunta a
3311
- // 3.13 wheels rechazados numpy/cffi/cryptography/onnxruntime
3312
- // fallan al import. Pinning a `python@3.12` evita el drift.
3282
+ // v0.32.5 — explicit @3.12 pin: Brain `requirements.txt` and the
3283
+ // manylinux wheels are compiled against cp312. `brew install python3`
3284
+ // installs the `python3` formula, which currently points to 3.13:
3285
+ // wheels are rejected and numpy/cffi/cryptography/onnxruntime imports
3286
+ // fail. Pinning `python@3.12` avoids that drift.
3313
3287
  log("Python 3.12 not found. Installing via Homebrew...");
3314
3288
  spawnSync("brew", ["install", "python@3.12"], { stdio: "inherit" });
3315
3289
  python = resolveInstallerPython() || run("which python3.12") || run("which python3");
@@ -3383,172 +3357,7 @@ async function runSetup() {
3383
3357
  ready: (name, alias) => `${name} is ready. Open a new terminal and type: ${alias}`,
3384
3358
  readySubtext: "First time we talk, I'll finish getting to know you\nwith a couple of questions I can't figure out on my own.",
3385
3359
  profileTitle: "PROFILE",
3386
- },
3387
- es: {
3388
- langConfirm: "Español, perfecto.",
3389
- askDataDir: ` ¿Dónde quieres que guarde mis datos? (bases de datos, backups, plugins personales)\n Por defecto: ~/.nexo/\n > `,
3390
- dataDirConfirm: (p) => `Directorio de datos: ${p}`,
3391
- askUserName: " ¿Cómo te llamas? > ",
3392
- userGreet: (n) => `Encantado, ${n}.`,
3393
- askAgentName: ` ¿Cómo quieres que me llame? (default: ${DEFAULT_ASSISTANT_NAME}) > `,
3394
- agentConfirm: (n) => `Perfecto, soy ${n}.`,
3395
- agentNameReserved: "Ese nombre está reservado para el producto. Elige otro nombre para el asistente.",
3396
- calibTitle: "Vamos a calibrar mi personalidad para trabajar mejor contigo.",
3397
- calibNote: "(Puedes cambiar esto en cualquier momento con nexo_preference_set)",
3398
- autonomyQ: " ¿Cuánta autonomía me das?\n 1. Conservador — pregunto antes de casi todo\n 2. Equilibrado — actúo en lo rutinario, pregunto en lo importante\n 3. Total — actúo primero, informo después, solo pregunto si hay duda real\n > ",
3399
- commQ: "\n ¿Cómo prefieres que me comunique?\n 1. Conciso — solo resultados, cero relleno\n 2. Equilibrado — explicaciones breves cuando aporten\n 3. Detallado — razonamiento y trade-offs incluidos\n > ",
3400
- honestyQ: "\n Cuando no esté de acuerdo con tu enfoque:\n 1. Te lo digo claro y explico por qué\n 2. Lo menciono brevemente pero sigo tu criterio\n 3. Ejecuto lo que pides sin más\n > ",
3401
- proactiveQ: "\n ¿Qué tan proactivo quieres que sea?\n 1. Solo hago lo que me pidas\n 2. Sugiero mejoras cuando las detecto\n 3. Arreglo lo que veo sin preguntar y propongo optimizaciones\n > ",
3402
- errorQ: "\n Cuando me equivoque:\n 1. Corrijo rápido y sigo\n 2. Explico qué falló y qué aprendí\n > ",
3403
- scanQ: " ¿Quieres que analice tu entorno para conocerte a fondo?\n Todo queda en local, nada sale de tu máquina.\n\n 1. Sí, analiza todo\n 2. No, ya te iré contando\n > ",
3404
- scanStart: "Conociéndote... esto toma 1-2 minutos.",
3405
- scanDone: "Listo.",
3406
- caffeinateQ: " ¿Activo el helper de energía del Mac para mis procesos en segundo plano?\n (Usa caffeinate. Con la tapa cerrada depende de tu setup; la recuperación al despertar sigue activa.)\n 1. Sí\n 2. No\n > ",
3407
- caffYes: "Helper de energía activado.",
3408
- caffNo: "Ok, la recuperación al despertar cubrirá las ventanas perdidas.",
3409
- 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 > ",
3410
- dashYes: "Dashboard activado.",
3411
- dashNo: "Dashboard desactivado. Puedes iniciarlo manualmente: nexo dashboard",
3412
- 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 > ",
3413
- autoInstallYes: "Auto-instalación activada.",
3414
- autoInstallNo: "Te preguntaré antes.",
3415
- installing: "Configurando...",
3416
- ready: (name, alias) => `${name} está listo. Abre una terminal nueva y escribe: ${alias}`,
3417
- readySubtext: "La primera vez que hablemos, terminaré de conocerte\ncon un par de preguntas que no puedo resolver solo.",
3418
- profileTitle: "PERFIL",
3419
- },
3420
- fr: {
3421
- langConfirm: "Français, parfait.",
3422
- askDataDir: ` Où stocker mes données ? (bases de données, sauvegardes, plugins)\n Par défaut : ~/.nexo/\n > `,
3423
- dataDirConfirm: (p) => `Répertoire de données : ${p}`,
3424
- askUserName: " Comment tu t'appelles ? > ",
3425
- userGreet: (n) => `Enchanté, ${n}.`,
3426
- askAgentName: ` Comment veux-tu m'appeler ? (défaut : ${DEFAULT_ASSISTANT_NAME}) > `,
3427
- agentConfirm: (n) => `C'est noté. Je suis ${n}.`,
3428
- agentNameReserved: "Ce nom est réservé au produit. Choisis un autre nom pour l'assistant.",
3429
- calibTitle: "Calibrons ma personnalité pour mieux travailler ensemble.",
3430
- calibNote: "(Tu peux changer ça à tout moment avec nexo_preference_set)",
3431
- autonomyQ: " Quel niveau d'autonomie me donnes-tu ?\n 1. Conservateur — je demande avant presque tout\n 2. Équilibré — j'agis en routine, je demande pour l'important\n 3. Total — j'agis d'abord, j'informe après\n > ",
3432
- commQ: "\n Comment préfères-tu que je communique ?\n 1. Concis — résultats seulement\n 2. Équilibré — brèves explications quand c'est utile\n 3. Détaillé — raisonnement et compromis inclus\n > ",
3433
- honestyQ: "\n Quand je ne suis pas d'accord :\n 1. Je te le dis clairement\n 2. Je le mentionne brièvement\n 3. J'exécute sans commenter\n > ",
3434
- proactiveQ: "\n Quel niveau de proactivité ?\n 1. Seulement ce qui est demandé\n 2. Je suggère des améliorations\n 3. Je corrige ce que je vois et propose des optimisations\n > ",
3435
- errorQ: "\n Quand je me trompe :\n 1. Correction rapide\n 2. J'explique ce qui s'est passé\n > ",
3436
- scanQ: " Veux-tu que j'analyse ton environnement pour te connaître en profondeur ?\n Tout reste local.\n\n 1. Oui, analyse tout\n 2. Non, je te raconterai\n > ",
3437
- scanStart: "Je fais connaissance... ça prend 1-2 minutes.",
3438
- scanDone: "Terminé.",
3439
- caffeinateQ: " Activer l'aide énergie du Mac pour mes processus en arrière-plan ?\n (Utilise caffeinate. Avec le capot fermé, cela dépend de votre configuration ; la reprise au réveil reste active.)\n 1. Oui\n 2. Non\n > ",
3440
- caffYes: "Aide énergie activée.",
3441
- caffNo: "D'accord, la reprise au réveil couvrira les fenêtres manquées.",
3442
- 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 > ",
3443
- dashYes: "Dashboard activé.",
3444
- dashNo: "Dashboard désactivé. Démarrage manuel : nexo dashboard",
3445
- autoInstallQ: " Puis-je installer des outils automatiquement ? (brew, pip, npm)\n 1. Oui\n 2. Demande-moi avant\n > ",
3446
- autoInstallYes: "Auto-installation activée.",
3447
- autoInstallNo: "Je demanderai avant.",
3448
- installing: "Configuration...",
3449
- ready: (name, alias) => `${name} est prêt. Ouvre un nouveau terminal et tape : ${alias}`,
3450
- readySubtext: "La première fois qu'on se parle, je finirai de te connaître\navec quelques questions que je ne peux pas résoudre seul.",
3451
- profileTitle: "PROFIL",
3452
- },
3453
- de: {
3454
- langConfirm: "Deutsch, perfekt.",
3455
- askDataDir: ` Wo sollen meine Daten gespeichert werden? (Datenbanken, Backups, Plugins)\n Standard: ~/.nexo/\n > `,
3456
- dataDirConfirm: (p) => `Datenverzeichnis: ${p}`,
3457
- askUserName: " Wie heißt du? > ",
3458
- userGreet: (n) => `Freut mich, ${n}.`,
3459
- askAgentName: ` Wie soll ich heißen? (Standard: ${DEFAULT_ASSISTANT_NAME}) > `,
3460
- agentConfirm: (n) => `Alles klar. Ich bin ${n}.`,
3461
- agentNameReserved: "Dieser Name ist für das Produkt reserviert. Bitte wähle einen anderen Assistentennamen.",
3462
- calibTitle: "Kalibrieren wir meine Persönlichkeit für die Zusammenarbeit.",
3463
- calibNote: "(Jederzeit änderbar mit nexo_preference_set)",
3464
- autonomyQ: " Wie viel Autonomie gibst du mir?\n 1. Konservativ — frage vor fast allem\n 2. Ausgewogen — handle bei Routine, frage bei Wichtigem\n 3. Voll — handle zuerst, informiere danach\n > ",
3465
- commQ: "\n Wie soll ich kommunizieren?\n 1. Knapp — nur Ergebnisse\n 2. Ausgewogen — kurze Erklärungen wenn nützlich\n 3. Detailliert — Begründungen und Abwägungen\n > ",
3466
- honestyQ: "\n Wenn ich nicht einverstanden bin:\n 1. Sage es klar\n 2. Erwähne es kurz\n 3. Führe einfach aus\n > ",
3467
- proactiveQ: "\n Wie proaktiv soll ich sein?\n 1. Nur was gefragt wird\n 2. Verbesserungen vorschlagen\n 3. Selbst korrigieren und optimieren\n > ",
3468
- errorQ: "\n Wenn ich einen Fehler mache:\n 1. Schnell korrigieren\n 2. Erklären was schiefging\n > ",
3469
- scanQ: " Soll ich deine Umgebung analysieren um dich kennenzulernen?\n Alles bleibt lokal.\n\n 1. Ja, analysiere alles\n 2. Nein, ich erzähle dir mit der Zeit\n > ",
3470
- scanStart: "Lerne dich kennen... dauert 1-2 Minuten.",
3471
- scanDone: "Fertig.",
3472
- caffeinateQ: " Den Mac-Energiehelfer für meine Hintergrundprozesse aktivieren?\n (Nutzt caffeinate. Bei geschlossenem Deckel hängt das vom Setup ab; Wiederaufnahme beim Aufwachen bleibt aktiv.)\n 1. Ja\n 2. Nein\n > ",
3473
- caffYes: "Energiehelfer aktiviert.",
3474
- caffNo: "Okay, die Wiederaufnahme beim Aufwachen deckt verpasste Fenster ab.",
3475
- dashboardQ: " Web-Dashboard auf localhost:6174 aktivieren?\n (Immer aktive UI für Speicher, Sitzungen und Systemgesundheit)\n 1. Ja\n 2. Nein\n > ",
3476
- dashYes: "Dashboard aktiviert.",
3477
- dashNo: "Dashboard deaktiviert. Manuell starten: nexo dashboard",
3478
- autoInstallQ: " Darf ich Tools automatisch installieren? (brew, pip, npm)\n 1. Ja\n 2. Frag mich vorher\n > ",
3479
- autoInstallYes: "Auto-Installation aktiviert.",
3480
- autoInstallNo: "Frage vorher.",
3481
- installing: "Konfiguriere...",
3482
- ready: (name, alias) => `${name} ist bereit. Öffne ein neues Terminal und tippe: ${alias}`,
3483
- readySubtext: "Beim ersten Gespräch stelle ich noch ein paar Fragen\ndie ich nicht alleine beantworten kann.",
3484
- profileTitle: "PROFIL",
3485
- },
3486
- it: {
3487
- langConfirm: "Italiano, perfetto.",
3488
- askDataDir: ` Dove salvare i miei dati? (database, backup, plugin)\n Default: ~/.nexo/\n > `,
3489
- dataDirConfirm: (p) => `Directory dati: ${p}`,
3490
- askUserName: " Come ti chiami? > ",
3491
- userGreet: (n) => `Piacere, ${n}.`,
3492
- askAgentName: ` Come vuoi chiamarmi? (default: ${DEFAULT_ASSISTANT_NAME}) > `,
3493
- agentConfirm: (n) => `Perfetto, sono ${n}.`,
3494
- agentNameReserved: "Quel nome è riservato al prodotto. Scegli un altro nome per l'assistente.",
3495
- calibTitle: "Calibriamo la mia personalità per lavorare meglio insieme.",
3496
- calibNote: "(Puoi cambiare in qualsiasi momento con nexo_preference_set)",
3497
- autonomyQ: " Quanta autonomia mi dai?\n 1. Conservatore — chiedo prima di quasi tutto\n 2. Equilibrato — agisco nella routine, chiedo per le cose importanti\n 3. Totale — agisco prima, informo dopo\n > ",
3498
- commQ: "\n Come preferisci che comunichi?\n 1. Conciso — solo risultati\n 2. Equilibrato — brevi spiegazioni quando utili\n 3. Dettagliato — ragionamento e compromessi\n > ",
3499
- honestyQ: "\n Quando non sono d'accordo:\n 1. Te lo dico chiaramente\n 2. Lo accenno brevemente\n 3. Eseguo senza commentare\n > ",
3500
- proactiveQ: "\n Quanto proattivo vuoi che sia?\n 1. Solo quello che chiedi\n 2. Suggerisco miglioramenti\n 3. Correggo quello che vedo e propongo ottimizzazioni\n > ",
3501
- errorQ: "\n Quando sbaglio:\n 1. Correggo veloce e vado avanti\n 2. Spiego cosa è andato storto\n > ",
3502
- scanQ: " Vuoi che analizzi il tuo ambiente per conoscerti a fondo?\n Tutto resta locale.\n\n 1. Sì, analizza tutto\n 2. No, ti racconterò col tempo\n > ",
3503
- scanStart: "Ti conosco... ci vogliono 1-2 minuti.",
3504
- scanDone: "Fatto.",
3505
- caffeinateQ: " Attivare l'helper energetico del Mac per i processi in background?\n (Usa caffeinate. Con il coperchio chiuso dipende dal setup; il recupero al risveglio resta attivo.)\n 1. Sì\n 2. No\n > ",
3506
- caffYes: "Helper energetico attivato.",
3507
- caffNo: "Ok, il recupero al risveglio coprirà le finestre perse.",
3508
- 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 > ",
3509
- dashYes: "Dashboard attivata.",
3510
- dashNo: "Dashboard disattivata. Avvio manuale: nexo dashboard",
3511
- autoInstallQ: " Posso installare strumenti automaticamente? (brew, pip, npm)\n 1. Sì\n 2. Chiedimi prima\n > ",
3512
- autoInstallYes: "Auto-installazione attivata.",
3513
- autoInstallNo: "Chiederò prima.",
3514
- installing: "Configurazione...",
3515
- ready: (name, alias) => `${name} è pronto. Apri un nuovo terminale e scrivi: ${alias}`,
3516
- readySubtext: "La prima volta che parliamo, finirò di conoscerti\ncon un paio di domande che non posso risolvere da solo.",
3517
- profileTitle: "PROFILO",
3518
- },
3519
- pt: {
3520
- langConfirm: "Português, perfeito.",
3521
- askDataDir: ` Onde guardar os meus dados? (bases de dados, backups, plugins)\n Padrão: ~/.nexo/\n > `,
3522
- dataDirConfirm: (p) => `Diretório de dados: ${p}`,
3523
- askUserName: " Como te chamas? > ",
3524
- userGreet: (n) => `Prazer, ${n}.`,
3525
- askAgentName: ` Como queres que eu me chame? (padrão: ${DEFAULT_ASSISTANT_NAME}) > `,
3526
- agentConfirm: (n) => `Perfeito, sou ${n}.`,
3527
- agentNameReserved: "Esse nome está reservado para o produto. Escolhe outro nome para o assistente.",
3528
- calibTitle: "Vamos calibrar a minha personalidade para trabalhar melhor contigo.",
3529
- calibNote: "(Podes mudar a qualquer momento com nexo_preference_set)",
3530
- autonomyQ: " Quanta autonomia me dás?\n 1. Conservador — pergunto antes de quase tudo\n 2. Equilibrado — ajo na rotina, pergunto no importante\n 3. Total — ajo primeiro, informo depois\n > ",
3531
- commQ: "\n Como preferes que eu comunique?\n 1. Conciso — só resultados\n 2. Equilibrado — explicações breves quando úteis\n 3. Detalhado — raciocínio e trade-offs\n > ",
3532
- honestyQ: "\n Quando não concordo:\n 1. Digo claramente\n 2. Menciono brevemente\n 3. Executo sem comentar\n > ",
3533
- proactiveQ: "\n Quão proativo queres que eu seja?\n 1. Só o que pedes\n 2. Sugiro melhorias\n 3. Corrijo o que vejo e proponho otimizações\n > ",
3534
- errorQ: "\n Quando erro:\n 1. Corrijo rápido\n 2. Explico o que correu mal\n > ",
3535
- scanQ: " Queres que analise o teu ambiente para te conhecer a fundo?\n Tudo fica local.\n\n 1. Sim, analisa tudo\n 2. Não, vou-te contando\n > ",
3536
- scanStart: "A conhecer-te... demora 1-2 minutos.",
3537
- scanDone: "Pronto.",
3538
- caffeinateQ: " Ativar o helper de energia do Mac para processos em segundo plano?\n (Usa caffeinate. Com a tampa fechada depende do teu setup; a recuperação ao despertar continua ativa.)\n 1. Sim\n 2. Não\n > ",
3539
- caffYes: "Helper de energia ativado.",
3540
- caffNo: "Ok, a recuperação ao despertar cobrirá janelas perdidas.",
3541
- 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 > ",
3542
- dashYes: "Dashboard ativado.",
3543
- dashNo: "Dashboard desativado. Iniciar manualmente: nexo dashboard",
3544
- autoInstallQ: " Posso instalar ferramentas automaticamente? (brew, pip, npm)\n 1. Sim\n 2. Pergunta antes\n > ",
3545
- autoInstallYes: "Auto-instalação ativada.",
3546
- autoInstallNo: "Perguntarei antes.",
3547
- installing: "A configurar...",
3548
- ready: (name, alias) => `${name} está pronto. Abre um novo terminal e escreve: ${alias}`,
3549
- readySubtext: "Na primeira vez que falarmos, termino de te conhecer\ncom umas perguntas que não consigo resolver sozinho.",
3550
- profileTitle: "PERFIL",
3551
- },
3360
+ }
3552
3361
  };
3553
3362
 
3554
3363
  const existingCalibrationRecord = readRuntimeCalibration(NEXO_HOME);
@@ -3564,7 +3373,7 @@ async function runSetup() {
3564
3373
  let lang = existingIdentity.language || "en";
3565
3374
  let t = i18n[lang] || i18n.en;
3566
3375
  if (!useDefaults) {
3567
- const langInput = await ask(" What's your preferred language? / ¿En qué idioma prefieres hablar?\n > ");
3376
+ const langInput = await ask(" What's your preferred language?\n > ");
3568
3377
  const langLower = langInput.trim().toLowerCase();
3569
3378
  // Detect language from common responses
3570
3379
  if (/^(es|español|spanish|castellano)/.test(langLower)) lang = "es";
@@ -3600,14 +3409,14 @@ async function runSetup() {
3600
3409
  console.log("");
3601
3410
  }
3602
3411
 
3603
- // Step 2: User's name (P2) — v6.0.0 empty input falls through to "Usuario"
3412
+ // Step 2: User's name (P2) — v6.0.0 empty input falls through to "User"
3604
3413
  // instead of keeping an empty string. The calibration file always ships
3605
3414
  // with a concrete user.name so downstream tooling does not need guards.
3606
- let userName = existingIdentity.userName || "Usuario";
3415
+ let userName = existingIdentity.userName || "User";
3607
3416
  if (!useDefaults) {
3608
3417
  const nameInput = await ask(t.askUserName);
3609
3418
  const trimmedName = nameInput.trim();
3610
- userName = trimmedName || "Usuario";
3419
+ userName = trimmedName || "User";
3611
3420
  if (trimmedName) {
3612
3421
  log(t.userGreet(trimmedName));
3613
3422
  console.log("");
@@ -3636,9 +3445,7 @@ async function runSetup() {
3636
3445
  let resonanceTier = DEFAULT_RESONANCE_TIER;
3637
3446
  if (!useDefaults) {
3638
3447
  resonanceTier = await askResonanceTier(lang, DEFAULT_RESONANCE_TIER);
3639
- log(lang === "es"
3640
- ? `Potencia por defecto: ${resonanceTier}.`
3641
- : `Default power: ${resonanceTier}.`);
3448
+ log(`Default power: ${resonanceTier}.`);
3642
3449
  console.log("");
3643
3450
  }
3644
3451
 
@@ -3698,7 +3505,7 @@ async function runSetup() {
3698
3505
  // answered the prompts (interactive run, !useDefaults). The
3699
3506
  // Desktop bootstrap calls nexo-brain with `--yes/--skip` to set up
3700
3507
  // the runtime non-interactively; in that path the values are
3701
- // placeholders ("Usuario" / "en" / "Nova") and the real wizard
3508
+ // placeholders ("User" / "en" / "Nova") and the real wizard
3702
3509
  // lives in the renderer. Marking it complete here used to short-
3703
3510
  // circuit that wizard and leave new users staring at an empty chat
3704
3511
  // (Inma 2026-05-03 smoke install).
@@ -4722,7 +4529,7 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
4722
4529
  if (profileData.calendar.events) line(`Calendar: ${profileData.calendar.events} events`);
4723
4530
  line(`Timezone: ${profileData.system.timezone}`);
4724
4531
  line("");
4725
- line(lang === "es" ? "Ya te conozco. Vamos a trabajar." : lang === "fr" ? "Je te connais. Au travail." : lang === "de" ? "Ich kenne dich. Los geht's." : lang === "it" ? "Ti conosco. Al lavoro." : lang === "pt" ? "J\u00E1 te conhe\u00E7o. Ao trabalho." : "I know you now. Let's work.");
4532
+ line("I know you now. Let's work.");
4726
4533
  console.log(` \u255A${"═".repeat(boxW - 2)}\u255D`);
4727
4534
  console.log("");
4728
4535
 
@@ -4739,7 +4546,7 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
4739
4546
  path.join(resolveRuntimeBrainDir(NEXO_HOME), "profile.json"),
4740
4547
  JSON.stringify(profileData, null, 2)
4741
4548
  );
4742
- log(lang === "es" ? "Sin problema. Iré aprendiéndote sobre la marcha." : "No problem. I'll learn about you as we go.");
4549
+ log("No problem. I'll learn about you as we go.");
4743
4550
  }
4744
4551
 
4745
4552
  // Generate user profile markdown (from scan or minimal)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.23.12",
3
+ "version": "7.24.0",
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",
@@ -467,7 +467,7 @@ def format_markdown(report: Mapping[str, Any]) -> str:
467
467
  )
468
468
  )
469
469
  if not findings:
470
- lines.append("| ninguno | OK | Sin open rows/spool/LaunchAgents pendientes en fixtures |")
470
+ lines.append("| none | OK | No pending open rows/spool/LaunchAgents in fixtures |")
471
471
  return "\n".join(lines)
472
472
 
473
473