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,253 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- NEXO Synthesis Engine v2 — Daily intelligence brief.
4
-
5
- Before: ~400 lines of Python concatenating SQL results into markdown sections.
6
- Now: Collects raw data, passes to Claude CLI (sonnet) which synthesizes
7
- with real understanding of what matters for tomorrow.
8
-
9
- Runs every 2 hours via LaunchAgent. Executes ONCE per day (internal gate).
10
- """
11
-
12
- import fcntl
13
- import json
14
- import os
15
- import sqlite3
16
- import subprocess
17
- import sys
18
- from datetime import datetime, date, timedelta
19
- from pathlib import Path
20
-
21
- HOME = Path.home()
22
- NEXO_HOME = Path(os.environ.get("NEXO_HOME", str(Path.home() / ".nexo")))
23
- CLAUDE_DIR = NEXO_HOME
24
- COORD_DIR = CLAUDE_DIR / "coordination"
25
- NEXO_DB = NEXO_HOME / "data" / "nexo.db"
26
- OUTPUT_FILE = COORD_DIR / "daily-synthesis.md"
27
- LAST_RUN_FILE = COORD_DIR / "synthesis-last-run"
28
- LOCK_FILE = COORD_DIR / "synthesis.lock"
29
- CLAUDE_CLI = HOME / ".local" / "bin" / "claude"
30
-
31
- TODAY = date.today()
32
- TODAY_STR = TODAY.isoformat()
33
-
34
-
35
- def log(msg: str):
36
- ts = datetime.now().strftime("%H:%M:%S")
37
- print(f"[{ts}] {msg}", flush=True)
38
-
39
-
40
- def should_run() -> bool:
41
- if LAST_RUN_FILE.exists():
42
- return LAST_RUN_FILE.read_text().strip() != TODAY_STR
43
- return True
44
-
45
-
46
- def mark_done():
47
- LAST_RUN_FILE.write_text(TODAY_STR)
48
-
49
-
50
- def acquire_lock():
51
- lock_fd = open(LOCK_FILE, "w")
52
- try:
53
- fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
54
- return lock_fd
55
- except BlockingIOError:
56
- log("Another instance running. Exiting.")
57
- sys.exit(0)
58
-
59
-
60
- def release_lock(lock_fd):
61
- fcntl.flock(lock_fd, fcntl.LOCK_UN)
62
- lock_fd.close()
63
- LOCK_FILE.unlink(missing_ok=True)
64
-
65
-
66
- def safe_query(sql: str, params=()) -> list:
67
- if not NEXO_DB.exists():
68
- return []
69
- try:
70
- conn = sqlite3.connect(str(NEXO_DB))
71
- conn.row_factory = sqlite3.Row
72
- rows = [dict(r) for r in conn.execute(sql, params).fetchall()]
73
- conn.close()
74
- return rows
75
- except Exception as e:
76
- log(f"Query error: {e}")
77
- return []
78
-
79
-
80
- def collect_data() -> dict:
81
- """Collect all raw data for synthesis."""
82
- data = {"date": TODAY_STR}
83
-
84
- # Today's learnings
85
- data["learnings"] = safe_query(
86
- "SELECT category, title, content, reasoning FROM learnings "
87
- "WHERE date(created_at, 'unixepoch') = ? ORDER BY created_at DESC",
88
- (TODAY_STR,)
89
- )
90
-
91
- # Today's decisions
92
- data["decisions"] = safe_query(
93
- "SELECT domain, decision, alternatives, based_on, outcome FROM decisions "
94
- "WHERE date(created_at) = ? ORDER BY created_at DESC",
95
- (TODAY_STR,)
96
- )
97
-
98
- # Today's changes
99
- data["changes"] = safe_query(
100
- "SELECT files, what_changed, why, affects, risks FROM change_log "
101
- "WHERE date(created_at) = ? ORDER BY created_at DESC",
102
- (TODAY_STR,)
103
- )
104
-
105
- # Session diaries (summaries + mental_state)
106
- data["diaries"] = safe_query(
107
- "SELECT summary, self_critique, mental_state, user_signals FROM session_diary "
108
- "WHERE date(created_at) = ? ORDER BY created_at DESC",
109
- (TODAY_STR,)
110
- )
111
-
112
- # Overdue reminders
113
- data["overdue_reminders"] = safe_query(
114
- "SELECT id, title, due_date FROM reminders "
115
- "WHERE status='PENDING' AND due_date <= ? ORDER BY due_date",
116
- (TODAY_STR,)
117
- )
118
-
119
- # Pending followups
120
- data["pending_followups"] = safe_query(
121
- "SELECT id, title, description, due_date FROM followups "
122
- "WHERE status='pending' ORDER BY due_date"
123
- )
124
-
125
- # Guard stats
126
- data["guard_stats"] = safe_query(
127
- "SELECT category, COUNT(*) as cnt FROM learnings WHERE status='active' "
128
- "GROUP BY category ORDER BY cnt DESC LIMIT 10"
129
- )
130
-
131
- # Postmortem daily (if exists)
132
- pm_file = COORD_DIR / "postmortem-daily.md"
133
- if pm_file.exists():
134
- data["postmortem_summary"] = pm_file.read_text()[:2000]
135
-
136
- return data
137
-
138
-
139
- def synthesize(data: dict) -> bool:
140
- """CLI synthesizes the daily brief."""
141
-
142
- data_json = json.dumps(data, ensure_ascii=False, indent=1)
143
- if len(data_json) > 15000:
144
- data_json = data_json[:15000] + "\n... (truncated)"
145
-
146
- prompt = f"""FIRST: Call nexo_startup(task='daily synthesis') to register this session.
147
-
148
- You are NEXO's synthesis engine. Write the daily intelligence brief for tomorrow's
149
- startup. This file is read by NEXO at the beginning of each session to understand
150
- what happened today and what to focus on tomorrow. Use nexo_learning_add and nexo_followup_create if you discover actionable items.
151
-
152
- TODAY'S RAW DATA:
153
- {data_json}
154
-
155
- Write the synthesis to {OUTPUT_FILE} with this structure:
156
-
157
- # NEXO Daily Synthesis — {TODAY_STR}
158
-
159
- ## Errors & Learnings
160
- [New learnings from today — what went wrong, what was learned]
161
-
162
- ## Decisions Made
163
- [Key decisions and their reasoning]
164
-
165
- ## Changes Deployed
166
- [What was changed in production today]
167
-
168
- ## the user — Observations
169
- [Patterns in the user's behavior: frustrations, pending decisions, ideas without
170
- deadlines, topics he started but didn't close. This is NEXO's peripheral vision.]
171
-
172
- ## Weak Points (self-assessment)
173
- [Where NEXO failed or could have done better today — from session diaries]
174
-
175
- ## Tomorrow's Context
176
- [What the next session needs to know: pending followups, overdue reminders,
177
- in-progress tasks, things to verify]
178
-
179
- ## Guard Status
180
- [Areas with most learnings — where errors concentrate]
181
-
182
- Be concise. Each section 3-8 bullet points max. Focus on what CHANGES BEHAVIOR,
183
- not what merely happened. If a section has nothing, write "Nothing notable."
184
-
185
- Execute without asking."""
186
-
187
- log("Invoking Claude CLI (opus) for synthesis...")
188
- env = os.environ.copy()
189
- env["NEXO_HEADLESS"] = "1" # Skip stop hook post-mortem
190
- env.pop("CLAUDECODE", None)
191
- env.pop("CLAUDE_CODE", None)
192
-
193
- try:
194
- result = subprocess.run(
195
- [str(CLAUDE_CLI), "-p", prompt, "--model", "opus",
196
- "--output-format", "text",
197
- "--allowedTools", "Read,Write,Edit,Glob,Grep,Bash,mcp__nexo__*"],
198
- capture_output=True, text=True, timeout=21600, env=env
199
- )
200
-
201
- if result.returncode != 0:
202
- log(f"CLI error ({result.returncode}): {(result.stderr or '')[:300]}")
203
- return False
204
-
205
- log(f"Synthesis complete. Output: {len(result.stdout or '')} chars")
206
- return True
207
-
208
- except subprocess.TimeoutExpired:
209
- log("CLI timed out (180s)")
210
- return False
211
- except Exception as e:
212
- log(f"Exception: {e}")
213
- return False
214
-
215
-
216
- def main():
217
- if not should_run():
218
- log(f"Already ran today ({TODAY_STR}). Skipping.")
219
- return
220
-
221
- lock_fd = acquire_lock()
222
- try:
223
- log(f"=== NEXO Synthesis v2 — {TODAY_STR} ===")
224
-
225
- data = collect_data()
226
- log(f"Collected: {len(data.get('learnings', []))} learnings, "
227
- f"{len(data.get('decisions', []))} decisions, "
228
- f"{len(data.get('changes', []))} changes, "
229
- f"{len(data.get('diaries', []))} diaries")
230
-
231
- success = synthesize(data)
232
-
233
- if success:
234
- mark_done()
235
- log("Synthesis v2 complete.")
236
- else:
237
- log("Synthesis failed — will retry next trigger.")
238
-
239
- # Register for catch-up
240
- try:
241
- state_file = NEXO_HOME / "operations" / ".catchup-state.json"
242
- st = json.loads(state_file.read_text()) if state_file.exists() else {}
243
- st["synthesis"] = datetime.now().isoformat()
244
- state_file.write_text(json.dumps(st, indent=2))
245
- except Exception:
246
- pass
247
-
248
- finally:
249
- release_lock(lock_fd)
250
-
251
-
252
- if __name__ == "__main__":
253
- main()
@@ -1,79 +0,0 @@
1
- #!/bin/bash
2
- # NEXO TCC Auto-Approve — grants macOS permissions to new Claude Code versions.
3
- #
4
- # macOS only. On Linux this is a no-op (Linux doesn't have TCC).
5
- # Runs at load to approve any new Claude versions that appeared.
6
- #
7
- # What it does:
8
- # 1. Scans ~/.local/share/claude/versions/ for Claude binaries
9
- # 2. For each new version, grants TCC access to Documents, Desktop, Downloads, etc.
10
- # 3. Also approves the Python binary used by NEXO's venv
11
- # 4. Tracks which versions have been approved to avoid re-processing
12
- #
13
- # Why: Claude Code updates frequently. Each new binary needs macOS permission
14
- # grants or the user gets popup dialogs interrupting their work.
15
-
16
- set -euo pipefail
17
-
18
- # Linux: nothing to do
19
- if [ "$(uname -s)" != "Darwin" ]; then
20
- exit 0
21
- fi
22
-
23
- NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
24
- TCC_DB="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
25
- VERSIONS_DIR="$HOME/.local/share/claude/versions"
26
- MARKER_DIR="$NEXO_HOME/data/.tcc-approved"
27
- LOG="$NEXO_HOME/logs/tcc-auto-approve.log"
28
-
29
- mkdir -p "$MARKER_DIR" "$(dirname "$LOG")"
30
-
31
- # TCC services Claude Code needs
32
- SERVICES=(
33
- kTCCServiceSystemPolicyDocumentsFolder
34
- kTCCServiceSystemPolicyDesktopFolder
35
- kTCCServiceSystemPolicyDownloadsFolder
36
- kTCCServiceMediaLibrary
37
- kTCCServiceSystemPolicyNetworkVolumes
38
- kTCCServiceSystemPolicyAppData
39
- kTCCServiceFileProviderDomain
40
- )
41
-
42
- # Approve Claude versions
43
- if [ -d "$VERSIONS_DIR" ]; then
44
- for bin_path in "$VERSIONS_DIR"/*; do
45
- [ ! -e "$bin_path" ] && continue
46
- version=$(basename "$bin_path")
47
- marker="$MARKER_DIR/$version"
48
-
49
- # Skip if already approved
50
- [ -f "$marker" ] && continue
51
-
52
- echo "$(date '+%Y-%m-%d %H:%M:%S') Approving Claude $version" >> "$LOG"
53
-
54
- for svc in "${SERVICES[@]}"; do
55
- sqlite3 "$TCC_DB" "
56
- INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version)
57
- VALUES ('$svc', '$bin_path', 1, 2, 4, 1);
58
- " 2>/dev/null
59
- done
60
-
61
- touch "$marker"
62
- echo "$(date '+%Y-%m-%d %H:%M:%S') Done: Claude $version — ${#SERVICES[@]} services approved" >> "$LOG"
63
- done
64
- fi
65
-
66
- # Also approve Python from NEXO's venv (if it exists)
67
- NEXO_CODE="${NEXO_CODE:-}"
68
- if [ -n "$NEXO_CODE" ]; then
69
- PYTHON_BIN="$(dirname "$NEXO_CODE")/.venv/bin/python"
70
- if [ -e "$PYTHON_BIN" ]; then
71
- PYTHON_REAL=$(readlink -f "$PYTHON_BIN" 2>/dev/null || echo "$PYTHON_BIN")
72
- for svc in "${SERVICES[@]}"; do
73
- sqlite3 "$TCC_DB" "
74
- INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version)
75
- VALUES ('$svc', '$PYTHON_REAL', 1, 2, 4, 1);
76
- " 2>/dev/null
77
- done
78
- fi
79
- fi
@@ -1,161 +0,0 @@
1
- #!/usr/bin/env bash
2
- # nexo-update.sh — Standalone NEXO update script
3
- # Same logic as the MCP tool but usable when the server itself needs updating.
4
- #
5
- # Usage:
6
- # nexo-update.sh # pull from origin main
7
- # nexo-update.sh origin beta # pull from origin beta
8
- # NEXO_HOME=/path nexo-update.sh # custom NEXO_HOME
9
-
10
- set -euo pipefail
11
-
12
- # --- Configuration ---
13
- REMOTE="${1:-origin}"
14
- BRANCH="${2:-main}"
15
- NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
16
-
17
- # Determine repo directory: script is at src/scripts/, repo root is ../../
18
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
19
- REPO_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
20
- SRC_DIR="$REPO_DIR/src"
21
- PACKAGE_JSON="$REPO_DIR/package.json"
22
-
23
- # --- Helpers ---
24
- RED='\033[0;31m'
25
- GREEN='\033[0;32m'
26
- YELLOW='\033[1;33m'
27
- NC='\033[0m'
28
-
29
- log() { echo -e "${GREEN}[nexo-update]${NC} $*"; }
30
- warn() { echo -e "${YELLOW}[nexo-update]${NC} $*"; }
31
- err() { echo -e "${RED}[nexo-update]${NC} $*" >&2; }
32
-
33
- read_version() {
34
- python3 -c "import json; print(json.load(open('$PACKAGE_JSON')).get('version','unknown'))" 2>/dev/null || echo "unknown"
35
- }
36
-
37
- # --- Step 1: Check for uncommitted changes in src/ ---
38
- log "Checking for uncommitted changes in src/..."
39
- cd "$REPO_DIR"
40
-
41
- if [ -n "$(git status --porcelain -- src/ 2>/dev/null)" ]; then
42
- err "ABORTED: Uncommitted changes in src/"
43
- git status --short -- src/
44
- exit 1
45
- fi
46
- log "Working tree clean."
47
-
48
- # Record current state
49
- OLD_VERSION="$(read_version)"
50
- OLD_COMMIT="$(git rev-parse HEAD)"
51
- log "Current: v${OLD_VERSION} (${OLD_COMMIT:0:8})"
52
-
53
- # --- Step 2: Backup databases ---
54
- TIMESTAMP="$(date +%Y-%m-%d-%H%M)"
55
- BACKUP_DIR="$NEXO_HOME/backups/pre-update-$TIMESTAMP"
56
-
57
- backup_dbs() {
58
- local found=0
59
- # Check data/, NEXO_HOME root, and src/ for .db files
60
- for dir in "$NEXO_HOME/data" "$NEXO_HOME" "$SRC_DIR"; do
61
- if [ -d "$dir" ]; then
62
- for db in "$dir"/*.db; do
63
- [ -f "$db" ] || continue
64
- found=1
65
- mkdir -p "$BACKUP_DIR"
66
- cp "$db" "$BACKUP_DIR/$(basename "$db")"
67
- log " Backed up: $(basename "$db")"
68
- done
69
- fi
70
- done
71
- if [ "$found" -eq 0 ]; then
72
- log " No databases found to backup."
73
- fi
74
- }
75
-
76
- log "Backing up databases..."
77
- backup_dbs
78
-
79
- # --- Step 3: git pull ---
80
- log "Pulling from ${REMOTE}/${BRANCH}..."
81
- PULL_OUTPUT="$(git pull "$REMOTE" "$BRANCH" 2>&1)" || {
82
- err "git pull failed:"
83
- err "$PULL_OUTPUT"
84
- exit 1
85
- }
86
- log "$PULL_OUTPUT"
87
-
88
- if echo "$PULL_OUTPUT" | grep -q "Already up to date"; then
89
- log "Already up to date (v${OLD_VERSION}). Done."
90
- exit 0
91
- fi
92
-
93
- # --- Step 4: Check version ---
94
- NEW_VERSION="$(read_version)"
95
- log "New version: v${NEW_VERSION}"
96
-
97
- # --- Step 5: Run migrations if version changed ---
98
- if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
99
- log "Version changed: ${OLD_VERSION} -> ${NEW_VERSION}"
100
- log "Running migrations..."
101
- if ! (cd "$SRC_DIR" && python3 -c "import db; db.init_db()" 2>&1); then
102
- err "Migration failed! Rolling back..."
103
- git reset --hard "$OLD_COMMIT"
104
- # Restore DB backups
105
- if [ -d "$BACKUP_DIR" ]; then
106
- for db in "$BACKUP_DIR"/*.db; do
107
- [ -f "$db" ] || continue
108
- BASENAME="$(basename "$db")"
109
- for candidate in "$NEXO_HOME/data/$BASENAME" "$NEXO_HOME/$BASENAME" "$SRC_DIR/$BASENAME"; do
110
- if [ -f "$candidate" ]; then
111
- cp "$db" "$candidate"
112
- warn " Restored: $BASENAME"
113
- break
114
- fi
115
- done
116
- done
117
- fi
118
- err "Rolled back to ${OLD_COMMIT:0:8}. Databases restored."
119
- exit 1
120
- fi
121
- log "Migrations applied."
122
- else
123
- log "Version unchanged (${OLD_VERSION}), skipping migrations."
124
- fi
125
-
126
- # --- Step 6: Verify import ---
127
- log "Verifying server.py import..."
128
- if ! (cd "$SRC_DIR" && python3 -c "import server" 2>&1); then
129
- err "Import verification failed! Rolling back..."
130
- git reset --hard "$OLD_COMMIT"
131
- if [ -d "$BACKUP_DIR" ]; then
132
- for db in "$BACKUP_DIR"/*.db; do
133
- [ -f "$db" ] || continue
134
- BASENAME="$(basename "$db")"
135
- for candidate in "$NEXO_HOME/data/$BASENAME" "$NEXO_HOME/$BASENAME" "$SRC_DIR/$BASENAME"; do
136
- if [ -f "$candidate" ]; then
137
- cp "$db" "$candidate"
138
- warn " Restored: $BASENAME"
139
- break
140
- fi
141
- done
142
- done
143
- fi
144
- err "Rolled back to ${OLD_COMMIT:0:8}. Databases restored."
145
- exit 1
146
- fi
147
-
148
- # --- Done ---
149
- echo ""
150
- log "========================================="
151
- log " UPDATE SUCCESSFUL"
152
- if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
153
- log " Version: ${OLD_VERSION} -> ${NEW_VERSION}"
154
- else
155
- log " Version: ${OLD_VERSION} (unchanged)"
156
- fi
157
- log " Branch: ${REMOTE}/${BRANCH}"
158
- log " Backup: ${BACKUP_DIR}"
159
- log "========================================="
160
- echo ""
161
- warn "MCP server restart needed to load new code."