nexo-brain 2.3.0 → 2.3.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/README.md +1 -1
- package/bin/nexo-brain.js +92 -9
- package/bin/postinstall.js +22 -15
- package/package.json +7 -4
- package/src/auto_update.py +194 -5
- package/src/crons/sync.py +6 -2
- package/src/db/_core.py +1 -0
- package/src/db/_entities.py +1 -0
- package/src/db/_episodic.py +1 -0
- package/src/db/_learnings.py +1 -0
- package/src/db/_reminders.py +1 -0
- package/src/db/_schema.py +11 -1
- package/src/db/_sessions.py +1 -0
- package/src/db/_skills.py +1 -0
- package/src/hooks/capture-tool-logs.sh +23 -6
- package/src/hooks/session-start.sh +4 -3
- package/src/plugin_loader.py +1 -0
- package/src/plugins/update.py +377 -26
- package/src/scripts/deep-sleep/apply_findings.py +1 -0
- package/src/scripts/deep-sleep/collect.py +1 -0
- package/src/scripts/deep-sleep/extract.py +1 -0
- package/src/scripts/deep-sleep/synthesize.py +1 -0
- package/src/scripts/nexo-catchup.py +29 -4
- package/src/scripts/nexo-daily-self-audit.py +21 -1
- package/src/scripts/nexo-evolution-run.py +21 -1
- package/src/scripts/nexo-learning-housekeep.py +1 -0
- package/src/scripts/nexo-postmortem-consolidator.py +34 -9
- package/src/scripts/nexo-sleep.py +32 -10
- package/src/scripts/nexo-synthesis.py +29 -9
- package/src/scripts/nexo-update.sh +109 -7
- package/src/scripts/nexo-watchdog.sh +122 -58
- package/src/server.py +66 -1
- package/src/tools_coordination.py +1 -0
- package/src/tools_sessions.py +1 -0
- package/scripts/migrate-to-unified 2.sh +0 -813
- package/scripts/migrate-to-unified.sh +0 -813
- package/scripts/migrate-v1.5-to-v1.6 2.py +0 -778
- package/scripts/migrate-v1.5-to-v1.6.py +0 -778
- package/scripts/migrate-v1.7-to-v1.8 2.py +0 -214
- package/scripts/migrate-v1.7-to-v1.8.py +0 -214
- package/scripts/nexo-preflight.sh +0 -236
- package/scripts/pre-commit-check 2.sh +0 -55
- package/scripts/pre-commit-check.sh +0 -55
- package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
- package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
- package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
- package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
- package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
- package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
- package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
- package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
- package/src/auto_close_sessions 2.py +0 -159
- package/src/auto_update 2.py +0 -634
- package/src/claim_graph 2.py +0 -323
- package/src/cognitive/__init__ 2.py +0 -62
- package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_core.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_decay.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_ingest.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_memory.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_search.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_trust.cpython-312.pyc +0 -0
- package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
- package/src/cognitive/_core 2.py +0 -567
- package/src/cognitive/_decay 2.py +0 -382
- package/src/cognitive/_ingest 2.py +0 -892
- package/src/cognitive/_memory 2.py +0 -912
- package/src/cognitive/_search 2.py +0 -949
- package/src/cognitive/_trust 2.py +0 -464
- package/src/crons/__pycache__/sync.cpython-314.pyc +0 -0
- package/src/crons/manifest 2.json +0 -106
- package/src/crons/sync 2.py +0 -217
- package/src/dashboard/__init__ 2.py +0 -0
- package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
- package/src/dashboard/app 2.py +0 -789
- package/src/db/__init__ 2.py +0 -89
- package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_cron_runs.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_cron_runs.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_skills.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_skills.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_skills.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
- package/src/db/_core 2.py +0 -417
- package/src/db/_credentials 2.py +0 -124
- package/src/db/_entities 2.py +0 -178
- package/src/db/_episodic 2.py +0 -738
- package/src/db/_evolution 2.py +0 -54
- package/src/db/_fts 2.py +0 -406
- package/src/db/_learnings 2.py +0 -168
- package/src/db/_reminders 2.py +0 -338
- package/src/db/_schema 2.py +0 -364
- package/src/db/_sessions 2.py +0 -300
- package/src/db/_tasks 2.py +0 -91
- package/src/evolution_cycle 2.py +0 -266
- package/src/hnsw_index 2.py +0 -254
- package/src/hooks/auto_capture 2.py +0 -208
- package/src/hooks/caffeinate-guard 2.sh +0 -8
- package/src/hooks/capture-session 2.sh +0 -21
- package/src/hooks/capture-tool-logs 2.sh +0 -127
- package/src/hooks/daily-briefing-check 2.sh +0 -33
- package/src/hooks/inbox-hook 2.sh +0 -76
- package/src/hooks/post-compact 2.sh +0 -148
- package/src/hooks/pre-compact 2.sh +0 -151
- package/src/hooks/session-start 2.sh +0 -268
- package/src/hooks/session-stop 2.sh +0 -140
- package/src/kg_populate 2.py +0 -290
- package/src/knowledge_graph 2.py +0 -257
- package/src/maintenance 2.py +0 -59
- package/src/migrate_embeddings 2.py +0 -122
- package/src/plugin_loader 2.py +0 -202
- package/src/plugins/__init__ 2.py +0 -0
- package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/schedule.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/schedule.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/skills.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/skills.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
- package/src/plugins/adaptive_mode 2.py +0 -805
- package/src/plugins/agents 2.py +0 -52
- package/src/plugins/artifact_registry 2.py +0 -450
- package/src/plugins/backup 2.py +0 -104
- package/src/plugins/cognitive_memory 2.py +0 -564
- package/src/plugins/core_rules 2.py +0 -252
- package/src/plugins/cortex 2.py +0 -299
- package/src/plugins/entities 2.py +0 -67
- package/src/plugins/episodic_memory 2.py +0 -533
- package/src/plugins/evolution 2.py +0 -115
- package/src/plugins/guard 2.py +0 -746
- package/src/plugins/knowledge_graph_tools 2.py +0 -105
- package/src/plugins/preferences 2.py +0 -47
- package/src/plugins/update 2.py +0 -256
- package/src/requirements 2.txt +0 -12
- package/src/rules/__init__ 2.py +0 -0
- package/src/rules/core-rules 2.json +0 -331
- package/src/rules/migrate 2.py +0 -207
- package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
- package/src/scripts/check-context 2.py +0 -264
- package/src/scripts/nexo-auto-update 2.py +0 -6
- package/src/scripts/nexo-backup 2.sh +0 -25
- package/src/scripts/nexo-brain-activation 2.sh +0 -140
- package/src/scripts/nexo-catchup 2.py +0 -242
- package/src/scripts/nexo-cognitive-decay 2.py +0 -182
- package/src/scripts/nexo-daily-self-audit 2.py +0 -552
- package/src/scripts/nexo-deep-sleep 2.sh +0 -97
- package/src/scripts/nexo-evolution-run 2.py +0 -597
- package/src/scripts/nexo-followup-hygiene 2.py +0 -112
- package/src/scripts/nexo-github-monitor 2.py +0 -256
- package/src/scripts/nexo-immune 2.py +0 -927
- package/src/scripts/nexo-inbox-hook 2.sh +0 -74
- package/src/scripts/nexo-install 2.py +0 -6
- package/src/scripts/nexo-learning-housekeep 2.py +0 -245
- package/src/scripts/nexo-learning-validator 2.py +0 -207
- package/src/scripts/nexo-migrate 2.py +0 -232
- package/src/scripts/nexo-postmortem-consolidator 2.py +0 -421
- package/src/scripts/nexo-pre-commit 2.py +0 -120
- package/src/scripts/nexo-prevent-sleep 2.sh +0 -29
- package/src/scripts/nexo-proactive-dashboard 2.py +0 -345
- package/src/scripts/nexo-reflection 2.py +0 -253
- package/src/scripts/nexo-runtime-preflight 2.py +0 -274
- package/src/scripts/nexo-send-email 2.py +0 -25
- package/src/scripts/nexo-send-email.py +0 -25
- package/src/scripts/nexo-send-reply 2.py +0 -178
- package/src/scripts/nexo-send-reply.py +0 -178
- package/src/scripts/nexo-sleep 2.py +0 -592
- package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
- package/src/scripts/nexo-synthesis 2.py +0 -253
- package/src/scripts/nexo-tcc-approve 2.sh +0 -79
- package/src/scripts/nexo-update 2.sh +0 -161
- package/src/scripts/nexo-watchdog 2.sh +0 -878
- package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
- package/src/server 2.py +0 -733
- package/src/storage_router 2.py +0 -32
- package/src/tools_coordination 2.py +0 -102
- package/src/tools_credentials 2.py +0 -68
- package/src/tools_learnings 2.py +0 -220
- package/src/tools_menu 2.py +0 -227
- package/src/tools_reminders 2.py +0 -86
- package/src/tools_reminders_crud 2.py +0 -159
- package/src/tools_sessions 2.py +0 -476
- package/src/tools_task_history 2.py +0 -57
- package/templates/CLAUDE.md 2.template +0 -63
- package/templates/openclaw 2.json +0 -13
- package/tests/__init__ 2.py +0 -0
- package/tests/__init__.py +0 -0
- package/tests/conftest 2.py +0 -71
- package/tests/conftest.py +0 -71
- package/tests/test_cognitive 2.py +0 -205
- package/tests/test_cognitive.py +0 -205
- package/tests/test_knowledge_graph 2.py +0 -140
- package/tests/test_knowledge_graph.py +0 -140
- package/tests/test_migrations 2.py +0 -137
- package/tests/test_migrations.py +0 -137
package/src/tools_reminders 2.py
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"""Reminders and followups reader — reads from SQLite database."""
|
|
2
|
-
|
|
3
|
-
from db import get_reminders, get_followups
|
|
4
|
-
from datetime import date
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def _is_due(date_str: str) -> bool:
|
|
8
|
-
"""Check if a date string is today or in the past."""
|
|
9
|
-
if not date_str:
|
|
10
|
-
return False
|
|
11
|
-
try:
|
|
12
|
-
d = date.fromisoformat(date_str.strip()[:10])
|
|
13
|
-
return d <= date.today()
|
|
14
|
-
except (ValueError, IndexError):
|
|
15
|
-
return False
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def handle_reminders(filter_type: str = "due") -> str:
|
|
19
|
-
"""Read reminders and followups from SQLite, return relevant ones.
|
|
20
|
-
|
|
21
|
-
Args:
|
|
22
|
-
filter_type: 'due' (vencidos/hoy), 'all' (todos activos), 'followups' (solo followups)
|
|
23
|
-
"""
|
|
24
|
-
parts = []
|
|
25
|
-
|
|
26
|
-
if filter_type in ("due", "all"):
|
|
27
|
-
r = _format_reminders(filter_type)
|
|
28
|
-
if r:
|
|
29
|
-
parts.append(r)
|
|
30
|
-
|
|
31
|
-
if filter_type in ("due", "all", "followups"):
|
|
32
|
-
f = _format_followups(filter_type)
|
|
33
|
-
if f:
|
|
34
|
-
parts.append(f)
|
|
35
|
-
|
|
36
|
-
result = "\n\n".join(parts)
|
|
37
|
-
return result if result else "No pending reminders."
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def _format_reminders(filter_type: str) -> str:
|
|
41
|
-
"""Format reminders from database."""
|
|
42
|
-
rows = get_reminders(filter_type)
|
|
43
|
-
if not rows:
|
|
44
|
-
return ""
|
|
45
|
-
|
|
46
|
-
lines = ["REMINDERS:"]
|
|
47
|
-
for r in rows:
|
|
48
|
-
rid = r.get("id", "?")
|
|
49
|
-
fecha = r.get("date") or ""
|
|
50
|
-
desc = r.get("description", "")
|
|
51
|
-
status = r.get("status", "")
|
|
52
|
-
desc = desc.replace("**", "")
|
|
53
|
-
due_marker = " [DUE]" if _is_due(fecha) else ""
|
|
54
|
-
fecha_display = f"({fecha})" if fecha else "(—)"
|
|
55
|
-
lines.append(f" {rid} {fecha_display}{due_marker} — {desc[:120]}")
|
|
56
|
-
if "RECURRENTE" in status.upper():
|
|
57
|
-
lines.append(f" Status: {status}")
|
|
58
|
-
|
|
59
|
-
return "\n".join(lines)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def _format_followups(filter_type: str) -> str:
|
|
63
|
-
"""Format followups from database."""
|
|
64
|
-
rows = get_followups(filter_type)
|
|
65
|
-
if not rows:
|
|
66
|
-
return ""
|
|
67
|
-
|
|
68
|
-
lines = ["FOLLOWUPS NEXO:"]
|
|
69
|
-
# Sort by priority: critical first, then high, medium, low
|
|
70
|
-
pri_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
|
|
71
|
-
rows = sorted(rows, key=lambda r: pri_order.get(r.get("priority") or "medium", 2))
|
|
72
|
-
for r in rows:
|
|
73
|
-
nfid = r.get("id", "?")
|
|
74
|
-
fecha = r.get("date") or ""
|
|
75
|
-
desc = r.get("description", "")
|
|
76
|
-
desc = desc.replace("**", "")
|
|
77
|
-
due_marker = " [DUE]" if _is_due(fecha) else ""
|
|
78
|
-
fecha_display = f"({fecha})" if fecha else "(—)"
|
|
79
|
-
rec = r.get("recurrence") or ""
|
|
80
|
-
rec_tag = f" [♻️ {rec}]" if rec else ""
|
|
81
|
-
pri = r.get("priority") or "medium"
|
|
82
|
-
pri_icon = {"critical": "🔴", "high": "🟠", "medium": "", "low": "⚪"}.get(pri, "")
|
|
83
|
-
pri_tag = f" {pri_icon}" if pri_icon else ""
|
|
84
|
-
lines.append(f" {nfid} {fecha_display}{due_marker}{pri_tag}{rec_tag} — {desc[:120]}")
|
|
85
|
-
|
|
86
|
-
return "\n".join(lines)
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
"""CRUD handlers for reminders and followups — operates on SQLite via db.py."""
|
|
2
|
-
|
|
3
|
-
from db import (
|
|
4
|
-
create_reminder, update_reminder, complete_reminder, delete_reminder,
|
|
5
|
-
get_reminders, get_reminder,
|
|
6
|
-
create_followup, update_followup, complete_followup, delete_followup,
|
|
7
|
-
get_followups, get_followup,
|
|
8
|
-
find_decisions_by_context_ref, update_decision_outcome,
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# ── Reminders ──────────────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
def handle_reminder_create(id: str, description: str, date: str = '', category: str = 'general') -> str:
|
|
15
|
-
"""Create a new reminder. id must start with 'R'."""
|
|
16
|
-
if not id.startswith('R'):
|
|
17
|
-
return f"ERROR: Reminder ID must start with 'R' (received: '{id}')."
|
|
18
|
-
|
|
19
|
-
result = create_reminder(id=id, description=description, date=date or None, category=category)
|
|
20
|
-
if not result or "error" in result:
|
|
21
|
-
error_msg = result.get("error", "unknown") if isinstance(result, dict) else "unknown"
|
|
22
|
-
return f"ERROR: {error_msg}"
|
|
23
|
-
|
|
24
|
-
date_str = date if date else 'no date'
|
|
25
|
-
return f"Reminder created. Date: {date_str}. Category: {category}."
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def handle_reminder_update(id: str, description: str = '', date: str = '', status: str = '', category: str = '') -> str:
|
|
29
|
-
"""Update one or more fields of an existing reminder."""
|
|
30
|
-
fields: dict = {}
|
|
31
|
-
if description:
|
|
32
|
-
fields['description'] = description
|
|
33
|
-
if date:
|
|
34
|
-
fields['date'] = date
|
|
35
|
-
if status:
|
|
36
|
-
fields['status'] = status
|
|
37
|
-
if category:
|
|
38
|
-
fields['category'] = category
|
|
39
|
-
|
|
40
|
-
if not fields:
|
|
41
|
-
return f"ERROR: No fields specified to update for {id}."
|
|
42
|
-
|
|
43
|
-
result = update_reminder(id=id, **fields)
|
|
44
|
-
if not result:
|
|
45
|
-
return f"ERROR: Reminder {id} not found."
|
|
46
|
-
|
|
47
|
-
changed = ', '.join(fields.keys())
|
|
48
|
-
return f"Reminder {id} updated: {changed}."
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def handle_reminder_complete(id: str) -> str:
|
|
52
|
-
"""Mark a reminder as completed."""
|
|
53
|
-
result = complete_reminder(id=id)
|
|
54
|
-
if not result or "error" in result:
|
|
55
|
-
return f"ERROR: Reminder {id} not found."
|
|
56
|
-
|
|
57
|
-
return f"Reminder {id} marked COMPLETED."
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def handle_reminder_delete(id: str) -> str:
|
|
61
|
-
"""Delete a reminder permanently."""
|
|
62
|
-
result = delete_reminder(id=id)
|
|
63
|
-
if not result:
|
|
64
|
-
return f"ERROR: Reminder {id} not found."
|
|
65
|
-
|
|
66
|
-
return f"Reminder {id} deleted."
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# ── Followups ──────────────────────────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
def handle_followup_create(id: str, description: str, date: str = '', verification: str = '', reasoning: str = '', recurrence: str = '') -> str:
|
|
72
|
-
"""Create a new NEXO followup. id must start with 'NF'.
|
|
73
|
-
|
|
74
|
-
Args:
|
|
75
|
-
id: Unique ID starting with 'NF'
|
|
76
|
-
description: What to verify/do
|
|
77
|
-
date: Target date YYYY-MM-DD (optional)
|
|
78
|
-
verification: How to verify completion (optional)
|
|
79
|
-
reasoning: WHY this followup exists — what decision/context led to it
|
|
80
|
-
recurrence: Recurrence pattern (optional). Formats: 'weekly:monday', 'monthly:1', 'quarterly'.
|
|
81
|
-
When completed, auto-creates the next occurrence.
|
|
82
|
-
"""
|
|
83
|
-
if not id.startswith('NF'):
|
|
84
|
-
return f"ERROR: Followup ID must start with 'NF' (received: '{id}')."
|
|
85
|
-
|
|
86
|
-
result = create_followup(id=id, description=description, date=date or None, verification=verification, reasoning=reasoning, recurrence=recurrence or None)
|
|
87
|
-
if not result or "error" in result:
|
|
88
|
-
error_msg = result.get("error", "unknown") if isinstance(result, dict) else "unknown"
|
|
89
|
-
return f"ERROR: {error_msg}"
|
|
90
|
-
|
|
91
|
-
date_str = date if date else 'no date'
|
|
92
|
-
rec_str = f" Recurrence: {recurrence}." if recurrence else ""
|
|
93
|
-
warning = result.get("warning", "")
|
|
94
|
-
warn_str = f"\n{warning}" if warning else ""
|
|
95
|
-
return f"Followup created. Date: {date_str}.{rec_str}{warn_str}"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def handle_followup_update(id: str, description: str = '', date: str = '', verification: str = '', status: str = '') -> str:
|
|
99
|
-
"""Update one or more fields of an existing followup."""
|
|
100
|
-
fields: dict = {}
|
|
101
|
-
if description:
|
|
102
|
-
fields['description'] = description
|
|
103
|
-
if date:
|
|
104
|
-
fields['date'] = date
|
|
105
|
-
if verification:
|
|
106
|
-
fields['verification'] = verification
|
|
107
|
-
if status:
|
|
108
|
-
fields['status'] = status
|
|
109
|
-
|
|
110
|
-
if not fields:
|
|
111
|
-
return f"ERROR: No fields specified to update for {id}."
|
|
112
|
-
|
|
113
|
-
result = update_followup(id=id, **fields)
|
|
114
|
-
if not result:
|
|
115
|
-
return f"ERROR: Followup {id} not found."
|
|
116
|
-
|
|
117
|
-
changed = ', '.join(fields.keys())
|
|
118
|
-
return f"Followup updated: {changed}."
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def handle_followup_complete(id: str, result: str = '') -> str:
|
|
122
|
-
"""Mark a followup as completed, optionally recording the result.
|
|
123
|
-
Also auto-updates any decision that references this followup in context_ref.
|
|
124
|
-
If the followup is recurring, auto-creates the next occurrence."""
|
|
125
|
-
from db import get_db
|
|
126
|
-
# Check recurrence before completing (complete may rename the ID)
|
|
127
|
-
conn = get_db()
|
|
128
|
-
row = conn.execute("SELECT recurrence FROM followups WHERE id = ?", (id,)).fetchone()
|
|
129
|
-
has_recurrence = row and row["recurrence"]
|
|
130
|
-
|
|
131
|
-
db_result = complete_followup(id=id, result=result)
|
|
132
|
-
if not db_result or "error" in db_result:
|
|
133
|
-
return f"ERROR: Followup {id} not found."
|
|
134
|
-
|
|
135
|
-
# Auto-link: find decisions whose context_ref matches this followup ID
|
|
136
|
-
msg = f"Followup {id} marked COMPLETED."
|
|
137
|
-
if has_recurrence:
|
|
138
|
-
# The new one was auto-created by complete_followup
|
|
139
|
-
new_row = conn.execute("SELECT date FROM followups WHERE id = ?", (id,)).fetchone()
|
|
140
|
-
if new_row:
|
|
141
|
-
msg += f" ♻️ Next auto-created for {new_row['date']}."
|
|
142
|
-
linked_decisions = find_decisions_by_context_ref(id)
|
|
143
|
-
if linked_decisions:
|
|
144
|
-
outcome_text = result if result else f"Followup {id} completed"
|
|
145
|
-
for dec in linked_decisions:
|
|
146
|
-
update_decision_outcome(dec['id'], outcome_text)
|
|
147
|
-
dec_ids = ', '.join(f"#{d['id']}" for d in linked_decisions)
|
|
148
|
-
msg += f" Decision(s) {dec_ids} updated with automatic outcome."
|
|
149
|
-
|
|
150
|
-
return msg
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def handle_followup_delete(id: str) -> str:
|
|
154
|
-
"""Delete a followup permanently."""
|
|
155
|
-
result = delete_followup(id=id)
|
|
156
|
-
if not result:
|
|
157
|
-
return f"ERROR: Followup {id} not found."
|
|
158
|
-
|
|
159
|
-
return f"Followup deleted."
|