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.
Files changed (299) hide show
  1. package/README.md +1 -1
  2. package/bin/nexo-brain.js +92 -9
  3. package/bin/postinstall.js +22 -15
  4. package/package.json +7 -4
  5. package/src/auto_update.py +194 -5
  6. package/src/crons/sync.py +6 -2
  7. package/src/db/_core.py +1 -0
  8. package/src/db/_entities.py +1 -0
  9. package/src/db/_episodic.py +1 -0
  10. package/src/db/_learnings.py +1 -0
  11. package/src/db/_reminders.py +1 -0
  12. package/src/db/_schema.py +11 -1
  13. package/src/db/_sessions.py +1 -0
  14. package/src/db/_skills.py +1 -0
  15. package/src/hooks/capture-tool-logs.sh +23 -6
  16. package/src/hooks/session-start.sh +4 -3
  17. package/src/plugin_loader.py +1 -0
  18. package/src/plugins/update.py +377 -26
  19. package/src/scripts/deep-sleep/apply_findings.py +1 -0
  20. package/src/scripts/deep-sleep/collect.py +1 -0
  21. package/src/scripts/deep-sleep/extract.py +1 -0
  22. package/src/scripts/deep-sleep/synthesize.py +1 -0
  23. package/src/scripts/nexo-catchup.py +29 -4
  24. package/src/scripts/nexo-daily-self-audit.py +21 -1
  25. package/src/scripts/nexo-evolution-run.py +21 -1
  26. package/src/scripts/nexo-learning-housekeep.py +1 -0
  27. package/src/scripts/nexo-postmortem-consolidator.py +34 -9
  28. package/src/scripts/nexo-sleep.py +32 -10
  29. package/src/scripts/nexo-synthesis.py +29 -9
  30. package/src/scripts/nexo-update.sh +109 -7
  31. package/src/scripts/nexo-watchdog.sh +122 -58
  32. package/src/server.py +66 -1
  33. package/src/tools_coordination.py +1 -0
  34. package/src/tools_sessions.py +1 -0
  35. package/scripts/migrate-to-unified 2.sh +0 -813
  36. package/scripts/migrate-to-unified.sh +0 -813
  37. package/scripts/migrate-v1.5-to-v1.6 2.py +0 -778
  38. package/scripts/migrate-v1.5-to-v1.6.py +0 -778
  39. package/scripts/migrate-v1.7-to-v1.8 2.py +0 -214
  40. package/scripts/migrate-v1.7-to-v1.8.py +0 -214
  41. package/scripts/nexo-preflight.sh +0 -236
  42. package/scripts/pre-commit-check 2.sh +0 -55
  43. package/scripts/pre-commit-check.sh +0 -55
  44. package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
  45. package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
  46. package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
  47. package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
  48. package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
  49. package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
  50. package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
  51. package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
  52. package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
  53. package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
  54. package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
  55. package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
  56. package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
  57. package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
  58. package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
  59. package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
  60. package/src/auto_close_sessions 2.py +0 -159
  61. package/src/auto_update 2.py +0 -634
  62. package/src/claim_graph 2.py +0 -323
  63. package/src/cognitive/__init__ 2.py +0 -62
  64. package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
  65. package/src/cognitive/__pycache__/__init__.cpython-312.pyc +0 -0
  66. package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
  67. package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
  68. package/src/cognitive/__pycache__/_core.cpython-312.pyc +0 -0
  69. package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
  70. package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
  71. package/src/cognitive/__pycache__/_decay.cpython-312.pyc +0 -0
  72. package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
  73. package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
  74. package/src/cognitive/__pycache__/_ingest.cpython-312.pyc +0 -0
  75. package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
  76. package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
  77. package/src/cognitive/__pycache__/_memory.cpython-312.pyc +0 -0
  78. package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
  79. package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
  80. package/src/cognitive/__pycache__/_search.cpython-312.pyc +0 -0
  81. package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
  82. package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
  83. package/src/cognitive/__pycache__/_trust.cpython-312.pyc +0 -0
  84. package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
  85. package/src/cognitive/_core 2.py +0 -567
  86. package/src/cognitive/_decay 2.py +0 -382
  87. package/src/cognitive/_ingest 2.py +0 -892
  88. package/src/cognitive/_memory 2.py +0 -912
  89. package/src/cognitive/_search 2.py +0 -949
  90. package/src/cognitive/_trust 2.py +0 -464
  91. package/src/crons/__pycache__/sync.cpython-314.pyc +0 -0
  92. package/src/crons/manifest 2.json +0 -106
  93. package/src/crons/sync 2.py +0 -217
  94. package/src/dashboard/__init__ 2.py +0 -0
  95. package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
  96. package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
  97. package/src/dashboard/app 2.py +0 -789
  98. package/src/db/__init__ 2.py +0 -89
  99. package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
  100. package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
  101. package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
  102. package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
  103. package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
  104. package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
  105. package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
  106. package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
  107. package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
  108. package/src/db/__pycache__/_cron_runs.cpython-310.pyc +0 -0
  109. package/src/db/__pycache__/_cron_runs.cpython-314.pyc +0 -0
  110. package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
  111. package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
  112. package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
  113. package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
  114. package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
  115. package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
  116. package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
  117. package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
  118. package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
  119. package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
  120. package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
  121. package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
  122. package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
  123. package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
  124. package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
  125. package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
  126. package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
  127. package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
  128. package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
  129. package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
  130. package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
  131. package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
  132. package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
  133. package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
  134. package/src/db/__pycache__/_skills.cpython-310.pyc +0 -0
  135. package/src/db/__pycache__/_skills.cpython-312.pyc +0 -0
  136. package/src/db/__pycache__/_skills.cpython-314.pyc +0 -0
  137. package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
  138. package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
  139. package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
  140. package/src/db/_core 2.py +0 -417
  141. package/src/db/_credentials 2.py +0 -124
  142. package/src/db/_entities 2.py +0 -178
  143. package/src/db/_episodic 2.py +0 -738
  144. package/src/db/_evolution 2.py +0 -54
  145. package/src/db/_fts 2.py +0 -406
  146. package/src/db/_learnings 2.py +0 -168
  147. package/src/db/_reminders 2.py +0 -338
  148. package/src/db/_schema 2.py +0 -364
  149. package/src/db/_sessions 2.py +0 -300
  150. package/src/db/_tasks 2.py +0 -91
  151. package/src/evolution_cycle 2.py +0 -266
  152. package/src/hnsw_index 2.py +0 -254
  153. package/src/hooks/auto_capture 2.py +0 -208
  154. package/src/hooks/caffeinate-guard 2.sh +0 -8
  155. package/src/hooks/capture-session 2.sh +0 -21
  156. package/src/hooks/capture-tool-logs 2.sh +0 -127
  157. package/src/hooks/daily-briefing-check 2.sh +0 -33
  158. package/src/hooks/inbox-hook 2.sh +0 -76
  159. package/src/hooks/post-compact 2.sh +0 -148
  160. package/src/hooks/pre-compact 2.sh +0 -151
  161. package/src/hooks/session-start 2.sh +0 -268
  162. package/src/hooks/session-stop 2.sh +0 -140
  163. package/src/kg_populate 2.py +0 -290
  164. package/src/knowledge_graph 2.py +0 -257
  165. package/src/maintenance 2.py +0 -59
  166. package/src/migrate_embeddings 2.py +0 -122
  167. package/src/plugin_loader 2.py +0 -202
  168. package/src/plugins/__init__ 2.py +0 -0
  169. package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
  170. package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
  171. package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
  172. package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
  173. package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
  174. package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
  175. package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
  176. package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
  177. package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
  178. package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
  179. package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
  180. package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
  181. package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
  182. package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
  183. package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
  184. package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
  185. package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
  186. package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
  187. package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
  188. package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
  189. package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
  190. package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
  191. package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
  192. package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
  193. package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
  194. package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
  195. package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
  196. package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
  197. package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
  198. package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
  199. package/src/plugins/__pycache__/schedule.cpython-310.pyc +0 -0
  200. package/src/plugins/__pycache__/schedule.cpython-314.pyc +0 -0
  201. package/src/plugins/__pycache__/skills.cpython-310.pyc +0 -0
  202. package/src/plugins/__pycache__/skills.cpython-314.pyc +0 -0
  203. package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
  204. package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
  205. package/src/plugins/adaptive_mode 2.py +0 -805
  206. package/src/plugins/agents 2.py +0 -52
  207. package/src/plugins/artifact_registry 2.py +0 -450
  208. package/src/plugins/backup 2.py +0 -104
  209. package/src/plugins/cognitive_memory 2.py +0 -564
  210. package/src/plugins/core_rules 2.py +0 -252
  211. package/src/plugins/cortex 2.py +0 -299
  212. package/src/plugins/entities 2.py +0 -67
  213. package/src/plugins/episodic_memory 2.py +0 -533
  214. package/src/plugins/evolution 2.py +0 -115
  215. package/src/plugins/guard 2.py +0 -746
  216. package/src/plugins/knowledge_graph_tools 2.py +0 -105
  217. package/src/plugins/preferences 2.py +0 -47
  218. package/src/plugins/update 2.py +0 -256
  219. package/src/requirements 2.txt +0 -12
  220. package/src/rules/__init__ 2.py +0 -0
  221. package/src/rules/core-rules 2.json +0 -331
  222. package/src/rules/migrate 2.py +0 -207
  223. package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
  224. package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
  225. package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
  226. package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
  227. package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
  228. package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
  229. package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
  230. package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
  231. package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
  232. package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
  233. package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
  234. package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
  235. package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
  236. package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
  237. package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
  238. package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
  239. package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
  240. package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
  241. package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
  242. package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
  243. package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
  244. package/src/scripts/check-context 2.py +0 -264
  245. package/src/scripts/nexo-auto-update 2.py +0 -6
  246. package/src/scripts/nexo-backup 2.sh +0 -25
  247. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  248. package/src/scripts/nexo-catchup 2.py +0 -242
  249. package/src/scripts/nexo-cognitive-decay 2.py +0 -182
  250. package/src/scripts/nexo-daily-self-audit 2.py +0 -552
  251. package/src/scripts/nexo-deep-sleep 2.sh +0 -97
  252. package/src/scripts/nexo-evolution-run 2.py +0 -597
  253. package/src/scripts/nexo-followup-hygiene 2.py +0 -112
  254. package/src/scripts/nexo-github-monitor 2.py +0 -256
  255. package/src/scripts/nexo-immune 2.py +0 -927
  256. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  257. package/src/scripts/nexo-install 2.py +0 -6
  258. package/src/scripts/nexo-learning-housekeep 2.py +0 -245
  259. package/src/scripts/nexo-learning-validator 2.py +0 -207
  260. package/src/scripts/nexo-migrate 2.py +0 -232
  261. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -421
  262. package/src/scripts/nexo-pre-commit 2.py +0 -120
  263. package/src/scripts/nexo-prevent-sleep 2.sh +0 -29
  264. package/src/scripts/nexo-proactive-dashboard 2.py +0 -345
  265. package/src/scripts/nexo-reflection 2.py +0 -253
  266. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  267. package/src/scripts/nexo-send-email 2.py +0 -25
  268. package/src/scripts/nexo-send-email.py +0 -25
  269. package/src/scripts/nexo-send-reply 2.py +0 -178
  270. package/src/scripts/nexo-send-reply.py +0 -178
  271. package/src/scripts/nexo-sleep 2.py +0 -592
  272. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  273. package/src/scripts/nexo-synthesis 2.py +0 -253
  274. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  275. package/src/scripts/nexo-update 2.sh +0 -161
  276. package/src/scripts/nexo-watchdog 2.sh +0 -878
  277. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  278. package/src/server 2.py +0 -733
  279. package/src/storage_router 2.py +0 -32
  280. package/src/tools_coordination 2.py +0 -102
  281. package/src/tools_credentials 2.py +0 -68
  282. package/src/tools_learnings 2.py +0 -220
  283. package/src/tools_menu 2.py +0 -227
  284. package/src/tools_reminders 2.py +0 -86
  285. package/src/tools_reminders_crud 2.py +0 -159
  286. package/src/tools_sessions 2.py +0 -476
  287. package/src/tools_task_history 2.py +0 -57
  288. package/templates/CLAUDE.md 2.template +0 -63
  289. package/templates/openclaw 2.json +0 -13
  290. package/tests/__init__ 2.py +0 -0
  291. package/tests/__init__.py +0 -0
  292. package/tests/conftest 2.py +0 -71
  293. package/tests/conftest.py +0 -71
  294. package/tests/test_cognitive 2.py +0 -205
  295. package/tests/test_cognitive.py +0 -205
  296. package/tests/test_knowledge_graph 2.py +0 -140
  297. package/tests/test_knowledge_graph.py +0 -140
  298. package/tests/test_migrations 2.py +0 -137
  299. package/tests/test_migrations.py +0 -137
@@ -1,214 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- NEXO Migration Script: v1.7.x -> v1.8.0 (Hybrid Architecture)
4
-
5
- Migrates CLAUDE.md to the new hybrid architecture where:
6
- - CLAUDE.md = bootstrap (identity, profile, format, autonomy, project atlas)
7
- - MCP instructions field = tool-coupled behavioral rules
8
- - nexo_context_packet = on-demand area-specific context
9
-
10
- The MCP server now carries all tool-coupled rules in its `instructions` field,
11
- so CLAUDE.md no longer needs to duplicate them. This reduces CLAUDE.md from
12
- ~130 lines to ~50 lines, saving ~3K context tokens per session.
13
-
14
- Safe to run multiple times (idempotent). Creates a backup before modifying.
15
-
16
- Usage:
17
- python3 migrate-v1.7-to-v1.8.py [--dry-run] [--nexo-home /path/to/nexo]
18
- """
19
-
20
- import argparse
21
- import os
22
- import re
23
- import shutil
24
- import sys
25
- from datetime import datetime
26
-
27
-
28
- # Sections that are now in the MCP instructions field and should be REMOVED from CLAUDE.md
29
- MCP_OWNED_SECTIONS = [
30
- "Heartbeat",
31
- "Guard",
32
- "Delegation",
33
- "Reminders & Followups",
34
- "Reminders y Followups",
35
- "Memory",
36
- "Memoria",
37
- "Trust Score",
38
- "Adaptive Mode",
39
- "Dissonance",
40
- "Disonancia",
41
- "Observe the User",
42
- "Observar a Francisco", # legacy personal CLAUDE.md files
43
- "Observar al Usuario",
44
- "Change Log",
45
- "Session Diary",
46
- "Cortex",
47
- "Operational Codex",
48
- ]
49
-
50
- # Sections that STAY in CLAUDE.md (bootstrap layer)
51
- BOOTSTRAP_SECTIONS = [
52
- "Startup",
53
- "User Profile",
54
- "Francisco", # legacy personal CLAUDE.md files
55
- "Formato",
56
- "Format",
57
- "Autonomy",
58
- "Autonomía",
59
- "Project Atlas",
60
- "Atlas de Proyectos",
61
- "Hooks",
62
- "Menu",
63
- "Platforms",
64
- "Plataformas",
65
- "Repo",
66
- ]
67
-
68
-
69
- def find_nexo_home(override=None):
70
- if override:
71
- return override
72
- candidates = [
73
- os.path.expanduser("~/nexo"),
74
- os.path.expanduser("~/.nexo"),
75
- os.path.expanduser("~/claude/nexo-mcp"),
76
- ]
77
- for c in candidates:
78
- if os.path.isdir(c):
79
- return c
80
- return None
81
-
82
-
83
- def find_claude_md():
84
- """Find the CLAUDE.md file that contains NEXO instructions."""
85
- candidates = [
86
- os.path.expanduser("~/.claude/CLAUDE.md"),
87
- os.path.expanduser("~/CLAUDE.md"),
88
- ]
89
- for c in candidates:
90
- if os.path.isfile(c):
91
- return c
92
- return None
93
-
94
-
95
- def parse_sections(content):
96
- """Parse markdown into sections by ## headers."""
97
- sections = []
98
- current_header = None
99
- current_lines = []
100
-
101
- for line in content.split("\n"):
102
- if line.startswith("## "):
103
- if current_header is not None:
104
- sections.append((current_header, "\n".join(current_lines)))
105
- current_header = line[3:].strip()
106
- current_lines = [line]
107
- else:
108
- current_lines.append(line)
109
-
110
- if current_header is not None:
111
- sections.append((current_header, "\n".join(current_lines)))
112
- elif current_lines:
113
- sections.append(("_preamble", "\n".join(current_lines)))
114
-
115
- return sections
116
-
117
-
118
- def is_mcp_owned(header):
119
- """Check if a section header matches an MCP-owned section."""
120
- header_lower = header.lower()
121
- for section in MCP_OWNED_SECTIONS:
122
- if section.lower() in header_lower:
123
- return True
124
- return False
125
-
126
-
127
- def migrate_claude_md(path, dry_run=False):
128
- """Slim down CLAUDE.md by removing MCP-owned sections."""
129
- with open(path, "r") as f:
130
- content = f.read()
131
-
132
- original_lines = len(content.strip().split("\n"))
133
- sections = parse_sections(content)
134
-
135
- # Separate preamble, bootstrap, and MCP-owned sections
136
- preamble = ""
137
- kept = []
138
- removed = []
139
-
140
- for header, body in sections:
141
- if header == "_preamble":
142
- preamble = body
143
- elif is_mcp_owned(header):
144
- removed.append(header)
145
- else:
146
- kept.append((header, body))
147
-
148
- if not removed:
149
- print(" CLAUDE.md already migrated (no MCP-owned sections found).")
150
- return False
151
-
152
- # Add hybrid architecture note to preamble
153
- if "MCP instructions" not in preamble and "instructions" not in preamble:
154
- preamble = preamble.rstrip() + (
155
- "\nTool-coupled behavioral rules (heartbeat, guard, trust, memory, diary) "
156
- "now live in the MCP server instructions field and are injected automatically.\n"
157
- )
158
-
159
- # Reconstruct
160
- new_content = preamble + "\n"
161
- for header, body in kept:
162
- new_content += "\n" + body + "\n"
163
-
164
- new_lines = len(new_content.strip().split("\n"))
165
-
166
- print(f" Sections removed (now in MCP): {', '.join(removed)}")
167
- print(f" Lines: {original_lines} → {new_lines} (saved {original_lines - new_lines})")
168
-
169
- if dry_run:
170
- print(" [DRY RUN] No changes written.")
171
- return True
172
-
173
- # Backup
174
- backup = path + f".backup-{datetime.now().strftime(\"%Y%m%d-%H%M%S\")}"
175
- shutil.copy2(path, backup)
176
- print(f" Backup: {backup}")
177
-
178
- with open(path, "w") as f:
179
- f.write(new_content)
180
- print(" CLAUDE.md updated.")
181
- return True
182
-
183
-
184
- def main():
185
- parser = argparse.ArgumentParser(description="Migrate NEXO to v1.8 hybrid architecture")
186
- parser.add_argument("--dry-run", action="store_true", help="Show what would change without modifying files")
187
- parser.add_argument("--nexo-home", help="Override NEXO home directory")
188
- args = parser.parse_args()
189
-
190
- print("NEXO v1.7 → v1.8 Migration (Hybrid Architecture)")
191
- print("=" * 50)
192
- print()
193
-
194
- # Step 1: Find and migrate CLAUDE.md
195
- claude_md = find_claude_md()
196
- if claude_md:
197
- print(f"Found CLAUDE.md: {claude_md}")
198
- migrate_claude_md(claude_md, dry_run=args.dry_run)
199
- else:
200
- print("No CLAUDE.md found (skipping).")
201
-
202
- print()
203
- print("Migration complete.")
204
- print()
205
- print("What changed:")
206
- print(" - CLAUDE.md now contains only bootstrap (identity, format, autonomy)")
207
- print(" - Tool-coupled rules are in the MCP server instructions field")
208
- print(" - Context-specific rules load on-demand via nexo_context_packet")
209
- print()
210
- print("The MCP server must be restarted for instructions to take effect.")
211
-
212
-
213
- if __name__ == "__main__":
214
- main()
@@ -1,214 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- NEXO Migration Script: v1.7.x -> v1.8.0 (Hybrid Architecture)
4
-
5
- Migrates CLAUDE.md to the new hybrid architecture where:
6
- - CLAUDE.md = bootstrap (identity, profile, format, autonomy, project atlas)
7
- - MCP instructions field = tool-coupled behavioral rules
8
- - nexo_context_packet = on-demand area-specific context
9
-
10
- The MCP server now carries all tool-coupled rules in its `instructions` field,
11
- so CLAUDE.md no longer needs to duplicate them. This reduces CLAUDE.md from
12
- ~130 lines to ~50 lines, saving ~3K context tokens per session.
13
-
14
- Safe to run multiple times (idempotent). Creates a backup before modifying.
15
-
16
- Usage:
17
- python3 migrate-v1.7-to-v1.8.py [--dry-run] [--nexo-home /path/to/nexo]
18
- """
19
-
20
- import argparse
21
- import os
22
- import re
23
- import shutil
24
- import sys
25
- from datetime import datetime
26
-
27
-
28
- # Sections that are now in the MCP instructions field and should be REMOVED from CLAUDE.md
29
- MCP_OWNED_SECTIONS = [
30
- "Heartbeat",
31
- "Guard",
32
- "Delegation",
33
- "Reminders & Followups",
34
- "Reminders y Followups",
35
- "Memory",
36
- "Memoria",
37
- "Trust Score",
38
- "Adaptive Mode",
39
- "Dissonance",
40
- "Disonancia",
41
- "Observe the User",
42
- "Observar a {{user}}", # legacy personal CLAUDE.md files
43
- "Observar al Usuario",
44
- "Change Log",
45
- "Session Diary",
46
- "Cortex",
47
- "Operational Codex",
48
- ]
49
-
50
- # Sections that STAY in CLAUDE.md (bootstrap layer)
51
- BOOTSTRAP_SECTIONS = [
52
- "Startup",
53
- "User Profile",
54
- "{{user_name}}", # legacy personal CLAUDE.md files
55
- "Formato",
56
- "Format",
57
- "Autonomy",
58
- "Autonomía",
59
- "Project Atlas",
60
- "Atlas de Proyectos",
61
- "Hooks",
62
- "Menu",
63
- "Platforms",
64
- "Plataformas",
65
- "Repo",
66
- ]
67
-
68
-
69
- def find_nexo_home(override=None):
70
- if override:
71
- return override
72
- candidates = [
73
- os.path.expanduser("~/nexo"),
74
- os.path.expanduser("~/.nexo"),
75
- os.path.expanduser("~/claude/nexo-mcp"),
76
- ]
77
- for c in candidates:
78
- if os.path.isdir(c):
79
- return c
80
- return None
81
-
82
-
83
- def find_claude_md():
84
- """Find the CLAUDE.md file that contains NEXO instructions."""
85
- candidates = [
86
- os.path.expanduser("~/.claude/CLAUDE.md"),
87
- os.path.expanduser("~/CLAUDE.md"),
88
- ]
89
- for c in candidates:
90
- if os.path.isfile(c):
91
- return c
92
- return None
93
-
94
-
95
- def parse_sections(content):
96
- """Parse markdown into sections by ## headers."""
97
- sections = []
98
- current_header = None
99
- current_lines = []
100
-
101
- for line in content.split("\n"):
102
- if line.startswith("## "):
103
- if current_header is not None:
104
- sections.append((current_header, "\n".join(current_lines)))
105
- current_header = line[3:].strip()
106
- current_lines = [line]
107
- else:
108
- current_lines.append(line)
109
-
110
- if current_header is not None:
111
- sections.append((current_header, "\n".join(current_lines)))
112
- elif current_lines:
113
- sections.append(("_preamble", "\n".join(current_lines)))
114
-
115
- return sections
116
-
117
-
118
- def is_mcp_owned(header):
119
- """Check if a section header matches an MCP-owned section."""
120
- header_lower = header.lower()
121
- for section in MCP_OWNED_SECTIONS:
122
- if section.lower() in header_lower:
123
- return True
124
- return False
125
-
126
-
127
- def migrate_claude_md(path, dry_run=False):
128
- """Slim down CLAUDE.md by removing MCP-owned sections."""
129
- with open(path, "r") as f:
130
- content = f.read()
131
-
132
- original_lines = len(content.strip().split("\n"))
133
- sections = parse_sections(content)
134
-
135
- # Separate preamble, bootstrap, and MCP-owned sections
136
- preamble = ""
137
- kept = []
138
- removed = []
139
-
140
- for header, body in sections:
141
- if header == "_preamble":
142
- preamble = body
143
- elif is_mcp_owned(header):
144
- removed.append(header)
145
- else:
146
- kept.append((header, body))
147
-
148
- if not removed:
149
- print(" CLAUDE.md already migrated (no MCP-owned sections found).")
150
- return False
151
-
152
- # Add hybrid architecture note to preamble
153
- if "MCP instructions" not in preamble and "instructions" not in preamble:
154
- preamble = preamble.rstrip() + (
155
- "\nTool-coupled behavioral rules (heartbeat, guard, trust, memory, diary) "
156
- "now live in the MCP server instructions field and are injected automatically.\n"
157
- )
158
-
159
- # Reconstruct
160
- new_content = preamble + "\n"
161
- for header, body in kept:
162
- new_content += "\n" + body + "\n"
163
-
164
- new_lines = len(new_content.strip().split("\n"))
165
-
166
- print(f" Sections removed (now in MCP): {', '.join(removed)}")
167
- print(f" Lines: {original_lines} → {new_lines} (saved {original_lines - new_lines})")
168
-
169
- if dry_run:
170
- print(" [DRY RUN] No changes written.")
171
- return True
172
-
173
- # Backup
174
- backup = path + f".backup-{datetime.now().strftime(\"%Y%m%d-%H%M%S\")}"
175
- shutil.copy2(path, backup)
176
- print(f" Backup: {backup}")
177
-
178
- with open(path, "w") as f:
179
- f.write(new_content)
180
- print(" CLAUDE.md updated.")
181
- return True
182
-
183
-
184
- def main():
185
- parser = argparse.ArgumentParser(description="Migrate NEXO to v1.8 hybrid architecture")
186
- parser.add_argument("--dry-run", action="store_true", help="Show what would change without modifying files")
187
- parser.add_argument("--nexo-home", help="Override NEXO home directory")
188
- args = parser.parse_args()
189
-
190
- print("NEXO v1.7 → v1.8 Migration (Hybrid Architecture)")
191
- print("=" * 50)
192
- print()
193
-
194
- # Step 1: Find and migrate CLAUDE.md
195
- claude_md = find_claude_md()
196
- if claude_md:
197
- print(f"Found CLAUDE.md: {claude_md}")
198
- migrate_claude_md(claude_md, dry_run=args.dry_run)
199
- else:
200
- print("No CLAUDE.md found (skipping).")
201
-
202
- print()
203
- print("Migration complete.")
204
- print()
205
- print("What changed:")
206
- print(" - CLAUDE.md now contains only bootstrap (identity, format, autonomy)")
207
- print(" - Tool-coupled rules are in the MCP server instructions field")
208
- print(" - Context-specific rules load on-demand via nexo_context_packet")
209
- print()
210
- print("The MCP server must be restarted for instructions to take effect.")
211
-
212
-
213
- if __name__ == "__main__":
214
- main()
@@ -1,236 +0,0 @@
1
- #!/bin/bash
2
- # ============================================================================
3
- # NEXO Preflight — CI / manual verification script
4
- # Checks: Python syntax, shell syntax, manifest<->file consistency,
5
- # manifest<->watchdog consistency
6
- # Exit code: 0 if all PASS, 1 if any FAIL
7
- # Usage: bash scripts/nexo-preflight.sh
8
- # ============================================================================
9
- set -uo pipefail
10
-
11
- REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
12
- SRC="$REPO_ROOT/src"
13
- MANIFEST="$SRC/crons/manifest.json"
14
- WATCHDOG="$SRC/scripts/nexo-watchdog.sh"
15
-
16
- PASS=0
17
- FAIL=0
18
- WARN=0
19
-
20
- pass() { echo " PASS $1"; ((PASS++)); }
21
- fail() { echo " FAIL $1"; ((FAIL++)); }
22
- warn() { echo " WARN $1"; ((WARN++)); }
23
-
24
- echo "============================================================"
25
- echo "NEXO Preflight — $(date '+%Y-%m-%d %H:%M:%S')"
26
- echo "============================================================"
27
-
28
- # ── 1. py_compile for all Python scripts in src/scripts/ ──────────────────
29
- echo ""
30
- # Non-core scripts to exclude from compilation checks
31
- NON_CORE="check-context.py"
32
-
33
- echo "--- Check 1: Python syntax (src/scripts/*.py) ---"
34
- for pyfile in "$SRC"/scripts/*.py; do
35
- # Skip " 2" duplicate files (backup copies)
36
- [[ "$pyfile" == *" 2"* ]] && continue
37
- [ -f "$pyfile" ] || continue
38
- name=$(basename "$pyfile")
39
- # Skip non-core scripts
40
- for skip in $NON_CORE; do
41
- [[ "$name" == "$skip" ]] && continue 2
42
- done
43
- if python3 -m py_compile "$pyfile" 2>/dev/null; then
44
- pass "$name"
45
- else
46
- fail "$name — py_compile error"
47
- fi
48
- done
49
-
50
- # ── 2. py_compile for auto_close_sessions.py ──────────────────────────────
51
- echo ""
52
- echo "--- Check 2: Python syntax (auto_close_sessions.py) ---"
53
- ACS="$SRC/auto_close_sessions.py"
54
- if [ -f "$ACS" ]; then
55
- if python3 -m py_compile "$ACS" 2>/dev/null; then
56
- pass "auto_close_sessions.py"
57
- else
58
- fail "auto_close_sessions.py — py_compile error"
59
- fi
60
- else
61
- fail "auto_close_sessions.py — file not found"
62
- fi
63
-
64
- # ── 3. bash -n for all shell scripts in src/scripts/ ─────────────────────
65
- echo ""
66
- echo "--- Check 3: Shell syntax (src/scripts/*.sh) ---"
67
- for shfile in "$SRC"/scripts/*.sh; do
68
- # Skip " 2" duplicate files (backup copies)
69
- [[ "$shfile" == *" 2"* ]] && continue
70
- [ -f "$shfile" ] || continue
71
- name=$(basename "$shfile")
72
- if bash -n "$shfile" 2>/dev/null; then
73
- pass "$name"
74
- else
75
- fail "$name — bash -n syntax error"
76
- fi
77
- done
78
-
79
- # ── 4. Manifest<->file consistency ────────────────────────────────────────
80
- echo ""
81
- echo "--- Check 4: Manifest crons have existing script files ---"
82
- if [ ! -f "$MANIFEST" ]; then
83
- fail "manifest.json not found at $MANIFEST"
84
- else
85
- # Extract script paths from manifest crons
86
- cron_scripts=$(python3 -c "
87
- import json, sys
88
- try:
89
- m = json.load(open('$MANIFEST'))
90
- for c in m.get('crons', []):
91
- print(c.get('id', '?') + '|' + c.get('script', ''))
92
- except Exception as e:
93
- print(f'ERROR|{e}', file=sys.stderr)
94
- sys.exit(1)
95
- " 2>/dev/null)
96
-
97
- if [ $? -ne 0 ]; then
98
- fail "manifest.json — cannot parse JSON"
99
- else
100
- while IFS='|' read -r cron_id script_path; do
101
- [ -z "$script_path" ] && continue
102
- full_path="$SRC/$script_path"
103
- if [ -f "$full_path" ]; then
104
- pass "cron '$cron_id' -> $script_path exists"
105
- else
106
- fail "cron '$cron_id' -> $script_path NOT FOUND"
107
- fi
108
- done <<< "$cron_scripts"
109
- fi
110
- fi
111
-
112
- # ── 5. Manifest<->watchdog MONITORS consistency ──────────────────────────
113
- echo ""
114
- echo "--- Check 5: Manifest crons present in watchdog MONITORS ---"
115
- if [ ! -f "$WATCHDOG" ]; then
116
- fail "nexo-watchdog.sh not found at $WATCHDOG"
117
- else
118
- # The watchdog dynamically builds MONITORS from manifest.json via
119
- # _build_monitors_from_manifest(). Verify that function exists and
120
- # references the manifest, plus check that any hardcoded PERSONAL_MONITORS
121
- # use valid com.nexo.* plist IDs.
122
-
123
- if grep -q "_build_monitors_from_manifest" "$WATCHDOG"; then
124
- pass "watchdog dynamically loads MONITORS from manifest.json"
125
- else
126
- fail "watchdog does NOT reference _build_monitors_from_manifest"
127
- fi
128
-
129
- if grep -q 'MANIFEST_FILE' "$WATCHDOG"; then
130
- pass "watchdog references MANIFEST_FILE"
131
- else
132
- fail "watchdog does NOT reference MANIFEST_FILE for dynamic loading"
133
- fi
134
-
135
- # Check that any hardcoded personal monitors have valid format
136
- personal_count=$(grep -c '|com\.nexo\.' "$WATCHDOG" 2>/dev/null || echo 0)
137
- if [ "$personal_count" -gt 0 ]; then
138
- pass "watchdog has $personal_count personal monitor entries"
139
- else
140
- pass "watchdog has no hardcoded personal monitors (all from manifest)"
141
- fi
142
- fi
143
-
144
- # ── 6. Manifest<->README consistency ─────────────────────────────────────
145
- echo ""
146
- echo "--- Check 6: Manifest crons mentioned in README ---"
147
- README="$REPO_ROOT/README.md"
148
- if [ -f "$README" ] && [ -f "$MANIFEST" ]; then
149
- manifest_ids=$(python3 -c "
150
- import json
151
- m = json.load(open('$MANIFEST'))
152
- for c in m.get('crons', []):
153
- print(c['id'])
154
- " 2>/dev/null)
155
-
156
- for cid in $manifest_ids; do
157
- if grep -qE "\*\*${cid}\*\*|${cid}" "$README" 2>/dev/null; then
158
- pass "cron '$cid' documented in README"
159
- else
160
- fail "cron '$cid' NOT in README"
161
- fi
162
- done
163
- else
164
- warn "README.md or manifest.json not found, skipping"
165
- fi
166
-
167
- # ── 7. Smoke tests ──────────────────────────────────────────────────────
168
- echo ""
169
- echo "--- Check 7: Smoke tests ---"
170
-
171
- # 7a: catchup weekday conversion (manifest 0=Sunday -> python 6)
172
- WEEKDAY_TEST=$(python3 -c "
173
- # Simulate the conversion from catchup.py
174
- manifest_weekday = 0 # Sunday in cron/launchd
175
- py_weekday = (manifest_weekday - 1) % 7 # Should be 6 (Sunday in Python)
176
- assert py_weekday == 6, f'Expected 6 (Sunday), got {py_weekday}'
177
- # Also test Monday
178
- assert (1 - 1) % 7 == 0, 'Monday should be 0'
179
- # Saturday
180
- assert (6 - 1) % 7 == 5, 'Saturday should be 5'
181
- print('OK')
182
- " 2>&1)
183
- if [ "$WEEKDAY_TEST" = "OK" ]; then
184
- pass "catchup weekday conversion (manifest 0=Sun -> python 6)"
185
- else
186
- fail "catchup weekday conversion: $WEEKDAY_TEST"
187
- fi
188
-
189
- # 7b: change_log schema uses what_changed (not description)
190
- SCHEMA_TEST=$(python3 -c "
191
- import sys
192
- sys.path.insert(0, '$SRC')
193
- # Verify change_log columns match what learning-housekeep uses
194
- with open('$SRC/db/_core.py') as f:
195
- core = f.read()
196
- if 'what_changed' in core:
197
- print('OK')
198
- else:
199
- print('FAIL: what_changed not found in _core.py')
200
- " 2>&1)
201
- if [ "$SCHEMA_TEST" = "OK" ]; then
202
- pass "change_log schema uses what_changed (matches reconciler)"
203
- else
204
- fail "change_log schema: $SCHEMA_TEST"
205
- fi
206
-
207
- # 7c: reconciler queries use correct columns for change_log
208
- RECONCILER_TEST=$(python3 -c "
209
- with open('$SRC/scripts/nexo-learning-housekeep.py') as f:
210
- code = f.read()
211
- # Find the change_log section of _reconcile_decision_outcome
212
- cl_section = code[code.index('# Check change_log'):code.index('return None', code.index('# Check change_log'))]
213
- if 'what_changed LIKE' in cl_section:
214
- print('OK')
215
- else:
216
- print('FAIL: change_log section does not use what_changed')
217
- " 2>&1)
218
- if [ "$RECONCILER_TEST" = "OK" ]; then
219
- pass "reconciler uses correct change_log columns"
220
- else
221
- fail "reconciler columns: $RECONCILER_TEST"
222
- fi
223
-
224
- # ── Summary ───────────────────────────────────────────────────────────────
225
- echo ""
226
- echo "============================================================"
227
- echo "Results: $PASS PASS, $FAIL FAIL, $WARN WARN"
228
- echo "============================================================"
229
-
230
- if [ "$FAIL" -gt 0 ]; then
231
- echo "PREFLIGHT FAILED"
232
- exit 1
233
- else
234
- echo "PREFLIGHT OK"
235
- exit 0
236
- fi