nexo-brain 0.8.2 → 0.8.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO — Cognitive co-operator for Claude Code. Atkinson-Shiffrin memory, semantic RAG, trust scoring, and metacognitive error prevention.",
6
6
  "bin": {
package/src/cognitive.py CHANGED
@@ -2737,7 +2737,7 @@ def detect_sentiment(text: str) -> dict:
2737
2737
  elif urgency_hits:
2738
2738
  sentiment = "urgent"
2739
2739
  intensity = 0.8
2740
- guidance = "MODE: Acción inmediata. Sin preámbulos."
2740
+ guidance = "MODE: Immediate action. No preamble."
2741
2741
  else:
2742
2742
  sentiment = "neutral"
2743
2743
  intensity = 0.5
@@ -33,10 +33,10 @@ def handle_backup_now() -> str:
33
33
  def handle_backup_list() -> str:
34
34
  """List available backups with dates and sizes."""
35
35
  if not os.path.isdir(BACKUP_DIR):
36
- return "Sin backups."
36
+ return "No backups found."
37
37
  files = sorted(glob.glob(os.path.join(BACKUP_DIR, "nexo-*.db")), reverse=True)
38
38
  if not files:
39
- return "Sin backups."
39
+ return "No backups found."
40
40
  lines = [f"BACKUPS ({len(files)}):"]
41
41
  total_size = 0
42
42
  for f in files:
@@ -5,7 +5,7 @@ def handle_entity_search(query: str, type: str = "") -> str:
5
5
  """Search entities by name or value. Optional type filter."""
6
6
  results = search_entities(query, type)
7
7
  if not results:
8
- return "Sin resultados."
8
+ return "No results."
9
9
  lines = []
10
10
  for e in results:
11
11
  notes = f" — {e['notes']}" if e.get("notes") else ""
@@ -37,14 +37,14 @@ def handle_entity_update(id: int, name: str = "", type: str = "", value: str = "
37
37
  def handle_entity_delete(id: int) -> str:
38
38
  """Delete an entity."""
39
39
  if not delete_entity(id):
40
- return f"ERROR: Entidad [{id}] no encontrada."
40
+ return f"ERROR: Entity [{id}] not found."
41
41
  return f"Entidad [{id}] eliminada."
42
42
 
43
43
  def handle_entity_list(type: str = "") -> str:
44
44
  """List all entities, optionally filtered by type."""
45
45
  results = list_entities(type)
46
46
  if not results:
47
- return "Sin entidades."
47
+ return "No entities found."
48
48
  grouped = {}
49
49
  for e in results:
50
50
  t = e["type"]
package/src/server.py CHANGED
@@ -395,7 +395,7 @@ def nexo_index_add_dir(path: str, dir_type: str = "code",
395
395
  result = fts_add_dir(path, dir_type, patterns, notes)
396
396
  if "error" in result:
397
397
  return f"ERROR: {result['error']}"
398
- return f"Directorio registrado: {result['path']} ({result['dir_type']}, patterns: {result['patterns']})\nUsa nexo_reindex para indexar ahora."
398
+ return f"Directory registered: {result['path']} ({result['dir_type']}, patterns: {result['patterns']})\nUse nexo_reindex to index now."
399
399
 
400
400
 
401
401
  @mcp.tool
@@ -408,7 +408,7 @@ def nexo_index_remove_dir(path: str) -> str:
408
408
  result = fts_remove_dir(path)
409
409
  if "error" in result:
410
410
  return f"ERROR: {result['error']}"
411
- return f"Directorio eliminado del índice: {result['removed']}"
411
+ return f"Directory removed from index: {result['removed']}"
412
412
 
413
413
 
414
414
  @mcp.tool
@@ -416,7 +416,7 @@ def nexo_index_dirs() -> str:
416
416
  """List all directories being indexed by FTS5 (builtin + dynamic)."""
417
417
  dirs = fts_list_dirs()
418
418
  if not dirs:
419
- return "Sin directorios configurados."
419
+ return "No directories configured."
420
420
  lines = ["DIRECTORIOS INDEXADOS:"]
421
421
  for d in dirs:
422
422
  source_tag = "⚙️" if d["source"] == "builtin" else "➕"
@@ -533,7 +533,7 @@ def nexo_plugin_load(filename: str) -> str:
533
533
  """
534
534
  try:
535
535
  n = load_plugin(mcp, filename)
536
- return f"Plugin {filename}: {n} tools registrados."
536
+ return f"Plugin {filename}: {n} tools registered."
537
537
  except Exception as e:
538
538
  return f"Error cargando plugin {filename}: {e}"
539
539
 
@@ -543,10 +543,10 @@ def nexo_plugin_list() -> str:
543
543
  """List all loaded plugins and their tools."""
544
544
  plugins = list_plugins()
545
545
  if not plugins:
546
- return "Sin plugins cargados."
546
+ return "No plugins loaded."
547
547
  lines = ["PLUGINS CARGADOS:"]
548
548
  for p in plugins:
549
- names = p["tool_names"] or "(sin tools)"
549
+ names = p["tool_names"] or "(no tools)"
550
550
  lines.append(f" {p['filename']} — {p['tools_count']} tools: {names}")
551
551
  return "\n".join(lines)
552
552
 
@@ -561,8 +561,8 @@ def nexo_plugin_remove(filename: str) -> str:
561
561
  try:
562
562
  removed = remove_plugin(mcp, filename)
563
563
  if removed:
564
- return f"Plugin {filename} eliminado. Tools quitados: {', '.join(removed)}"
565
- return f"Plugin {filename} eliminado (no tenía tools registrados)."
564
+ return f"Plugin {filename} removed. Tools unregistered: {', '.join(removed)}"
565
+ return f"Plugin {filename} removed (had no registered tools)."
566
566
  except Exception as e:
567
567
  return f"Error eliminando plugin {filename}: {e}"
568
568
 
@@ -23,7 +23,7 @@ def handle_credential_create(service: str, key: str, value: str, notes: str = ''
23
23
  result = create_credential(service, key, value, notes)
24
24
  if "error" in result:
25
25
  return f"ERROR: {result['error']}"
26
- return f"Credencial {service}/{key} creada."
26
+ return f"Credential {service}/{key} created."
27
27
 
28
28
 
29
29
  def handle_credential_update(service: str, key: str, value: str = '', notes: str = '') -> str:
@@ -36,7 +36,7 @@ def handle_credential_update(service: str, key: str, value: str = '', notes: str
36
36
  )
37
37
  if "error" in result:
38
38
  return f"ERROR: {result['error']}"
39
- return f"Credencial {service}/{key} actualizada."
39
+ return f"Credential {service}/{key} updated."
40
40
 
41
41
 
42
42
  def handle_credential_delete(service: str, key: str = '') -> str:
@@ -46,8 +46,8 @@ def handle_credential_delete(service: str, key: str = '') -> str:
46
46
  target = f"{service}/{key}" if key else service
47
47
  return f"ERROR: No se encontraron credenciales para '{target}'."
48
48
  if key:
49
- return f"Credencial {service}/{key} eliminada."
50
- return f"Todas las credenciales de {service} eliminadas."
49
+ return f"Credential {service}/{key} deleted."
50
+ return f"All credentials for {service} deleted."
51
51
 
52
52
 
53
53
  def handle_credential_list(service: str = '') -> str:
@@ -55,8 +55,8 @@ def handle_credential_list(service: str = '') -> str:
55
55
  results = list_credentials(service if service else None)
56
56
  label = service if service else "TODAS"
57
57
  if not results:
58
- return f"CREDENCIALES {label.upper()}: Sin entradas."
59
- lines = [f"CREDENCIALES {label.upper()} ({len(results)}):"]
58
+ return f"CREDENTIALS {label.upper()}: No entries."
59
+ lines = [f"CREDENTIALS {label.upper()} ({len(results)}):"]
60
60
  for r in results:
61
61
  notes = r.get("notes") or ""
62
62
  suffix = f" — {notes}" if notes else ""
@@ -107,7 +107,7 @@ def handle_learning_search(query: str, category: str = '') -> str:
107
107
  """Search learnings by query string, optionally filtered by category."""
108
108
  results = search_learnings(query, category if category else None)
109
109
  if not results:
110
- return f"Sin resultados para '{query}'."
110
+ return f"No results for '{query}'."
111
111
  lines = [f"RESULTADOS ({len(results)}):"]
112
112
  for r in results:
113
113
  snippet = r["content"][:100] + "..." if len(r["content"]) > 100 else r["content"]
@@ -155,7 +155,7 @@ def handle_learning_update(id: int, title: str = '', content: str = '', category
155
155
  if review_days > 0:
156
156
  kwargs["review_days"] = review_days
157
157
  if not kwargs:
158
- return "ERROR: Nada que actualizar. Proporciona campos nuevos."
158
+ return "ERROR: Nothing to update. Provide new fields."
159
159
  basic_kwargs = {k: v for k, v in kwargs.items() if k in {"title", "content", "category", "reasoning"}}
160
160
  result = update_learning(id, **basic_kwargs)
161
161
  if "error" in result:
@@ -192,7 +192,7 @@ def handle_learning_list(category: str = '') -> str:
192
192
  results = list_learnings(category if category else None)
193
193
  if not results:
194
194
  label = category if category else "TODOS"
195
- return f"LEARNINGS {label} (0): Sin entradas."
195
+ return f"LEARNINGS {label} (0): No entries."
196
196
 
197
197
  if category:
198
198
  label = category.upper()
package/src/tools_menu.py CHANGED
@@ -101,7 +101,7 @@ def handle_menu() -> str:
101
101
  dashboard_alerts = _get_dashboard_alerts()
102
102
  memory_reviews = _get_memory_review_summary()
103
103
  due = handle_reminders("due")
104
- has_alerts = dashboard_alerts or memory_reviews["total"] > 0 or (due and "Sin recordatorios" not in due)
104
+ has_alerts = dashboard_alerts or memory_reviews["total"] > 0 or (due and "No reminders" not in due)
105
105
 
106
106
  if has_alerts:
107
107
  lines.append("║" + " PROACTIVE ALERTS".ljust(W) + "║")
@@ -124,7 +124,7 @@ def handle_menu() -> str:
124
124
  )[:W - 4]
125
125
  lines.append("║" + f" ! {text}".ljust(W) + "║")
126
126
 
127
- if due and "Sin recordatorios" not in due:
127
+ if due and "No reminders" not in due:
128
128
  for reminder_line in due.split("\n"):
129
129
  if reminder_line.strip():
130
130
  truncated = reminder_line[:W - 2]
@@ -190,7 +190,7 @@ def handle_menu() -> str:
190
190
 
191
191
  # Active sessions
192
192
  sessions = handle_status()
193
- if "Sin sesiones" not in sessions:
193
+ if "No sessions" not in sessions:
194
194
  lines.append("║" + " ACTIVE SESSIONS".ljust(W) + "║")
195
195
  lines.append("║" + "─" * W + "║")
196
196
  for s_line in sessions.split("\n"):
@@ -34,7 +34,7 @@ def handle_reminders(filter_type: str = "due") -> str:
34
34
  parts.append(f)
35
35
 
36
36
  result = "\n\n".join(parts)
37
- return result if result else "Sin recordatorios pendientes."
37
+ return result if result else "No pending reminders."
38
38
 
39
39
 
40
40
  def _format_reminders(filter_type: str) -> str:
@@ -47,7 +47,7 @@ def handle_startup(task: str = "Startup") -> str:
47
47
  age = _format_age(s["last_update_epoch"])
48
48
  lines.append(f" {s['sid']} ({age}) — {s['task']}")
49
49
  else:
50
- lines.append("Sin otras sesiones activas.")
50
+ lines.append("No other active sessions.")
51
51
 
52
52
  if inbox:
53
53
  lines.append("")
@@ -272,7 +272,7 @@ def handle_status(keyword: str | None = None) -> str:
272
272
  sessions = get_active_sessions()
273
273
 
274
274
  if not sessions:
275
- return "Sin sesiones activas."
275
+ return "No active sessions."
276
276
 
277
277
  lines = ["SESIONES ACTIVAS:"]
278
278
  for s in sessions:
@@ -21,7 +21,7 @@ def handle_task_log(task_num: str, task_name: str, notes: str = '', reasoning: s
21
21
  result = log_task(task_num, task_name, notes, reasoning)
22
22
  if "error" in result:
23
23
  return f"ERROR: {result['error']}"
24
- return f"Tarea {task_num} ({task_name}) registrada."
24
+ return f"Task {task_num} ({task_name}) logged."
25
25
 
26
26
 
27
27
  def handle_task_list(task_num: str = '', days: int = 30) -> str: