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,89 +0,0 @@
1
- """NEXO DB — Modular SQLite database layer.
2
-
3
- This package replaces the monolithic db.py. All public functions are
4
- re-exported here for full backwards compatibility:
5
- from db import get_db, create_learning, ...
6
- """
7
-
8
- # Core: connection, constants, init, utils
9
- from db._core import (
10
- DB_PATH, SESSION_STALE_SECONDS, MESSAGE_TTL_SECONDS, QUESTION_TTL_SECONDS,
11
- get_db, close_db, _get_raw_conn, _SerializedConnection,
12
- _shared_conn, _write_lock,
13
- init_db, _gen_id, now_epoch, local_time_str, _multi_word_like,
14
- )
15
-
16
- # FTS5 search
17
- from db._fts import (
18
- fts_add_dir, fts_remove_dir, fts_list_dirs,
19
- rebuild_fts_index, fts_search, fts_upsert,
20
- )
21
-
22
- # Schema migrations
23
- from db._schema import (
24
- run_migrations, get_schema_version,
25
- )
26
-
27
- # Sessions, file tracking, messages, questions
28
- from db._sessions import (
29
- register_session, update_session, complete_session,
30
- get_active_sessions, clean_stale_sessions, search_sessions,
31
- track_files, untrack_files, get_all_tracked_files,
32
- send_message, get_inbox,
33
- ask_question, answer_question, get_pending_questions, check_answer,
34
- )
35
-
36
- # Reminders and followups
37
- from db._reminders import (
38
- create_reminder, update_reminder, complete_reminder, delete_reminder,
39
- get_reminders, get_reminder,
40
- create_followup, update_followup, complete_followup, delete_followup,
41
- get_followups, get_followup,
42
- find_similar_followups,
43
- )
44
-
45
- # Learnings
46
- from db._learnings import (
47
- create_learning, update_learning, delete_learning,
48
- search_learnings, list_learnings,
49
- extract_keywords, find_similar_learnings,
50
- )
51
-
52
- # Credentials
53
- from db._credentials import (
54
- create_credential, update_credential, delete_credential,
55
- get_credential, list_credentials,
56
- )
57
-
58
- # Task history
59
- from db._tasks import (
60
- log_task, list_task_history, set_task_frequency,
61
- get_overdue_tasks, get_task_frequencies,
62
- )
63
-
64
- # Entities, preferences, agents
65
- from db._entities import (
66
- create_entity, search_entities, list_entities, update_entity, delete_entity,
67
- set_preference, get_preference, list_preferences, delete_preference,
68
- create_agent, get_agent, list_agents, update_agent, delete_agent,
69
- )
70
-
71
- # Episodic memory
72
- from db._episodic import (
73
- cleanup_old_changes, log_change, search_changes, update_change_commit, auto_resolve_followups,
74
- cleanup_old_decisions, log_decision, update_decision_outcome,
75
- get_memory_review_queue, find_decisions_by_context_ref, search_decisions,
76
- cleanup_old_diaries, write_session_diary,
77
- diary_archive_search, diary_archive_read, diary_archive_stats,
78
- check_session_has_diary,
79
- upsert_diary_draft, get_diary_draft, delete_diary_draft,
80
- save_checkpoint, read_checkpoint, increment_compaction_count,
81
- get_orphan_sessions, read_session_diary,
82
- recall,
83
- )
84
-
85
- # Evolution
86
- from db._evolution import (
87
- insert_evolution_metric, get_latest_metrics,
88
- insert_evolution_log, get_evolution_history, update_evolution_log_status,
89
- )
@@ -1,417 +0,0 @@
1
- """SQLite database for NEXO session coordination."""
2
-
3
- import sqlite3
4
- import time
5
- import os
6
- import secrets
7
- import string
8
- import datetime
9
- import pathlib
10
- import threading
11
-
12
- NEXO_HOME = os.environ.get("NEXO_HOME", os.path.expanduser("~/.nexo"))
13
- _data_dir = os.path.join(NEXO_HOME, "data")
14
- os.makedirs(_data_dir, exist_ok=True)
15
-
16
- DB_PATH = os.environ.get(
17
- "NEXO_TEST_DB",
18
- os.environ.get(
19
- "NEXO_DB",
20
- os.path.join(_data_dir, "nexo.db"),
21
- ),
22
- )
23
-
24
- # TTLs in seconds (match session-coord.sh behavior)
25
- SESSION_STALE_SECONDS = 900 # 15 min (documented TTL)
26
- MESSAGE_TTL_SECONDS = 3600 # 1 hour
27
- QUESTION_TTL_SECONDS = 600 # 10 min
28
-
29
- # Single shared connection per process with write serialization.
30
- # SQLite allows only one writer at a time. Using a shared connection with
31
- # check_same_thread=False and a write lock ensures:
32
- # - No FTS5 corruption from concurrent write connections
33
- # - Reads can happen freely (WAL allows concurrent readers)
34
- # - Writes are serialized via _write_lock to prevent 'database is locked' errors
35
- _shared_conn: sqlite3.Connection | None = None
36
- _write_lock = threading.RLock() # RLock allows re-entrant locking (function A calls B, both serialize)
37
-
38
-
39
- def get_db() -> sqlite3.Connection:
40
- """Get shared database connection with WAL mode.
41
-
42
- Returns a _SerializedConnection wrapper that serializes all execute
43
- calls via _write_lock, preventing race conditions and FTS5 corruption
44
- under concurrent thread access.
45
- """
46
- global _shared_conn
47
- if _shared_conn is None:
48
- raw = sqlite3.connect(
49
- DB_PATH, timeout=30, check_same_thread=False,
50
- isolation_level=None, # autocommit — no implicit BEGIN holding locks
51
- )
52
- raw.execute("PRAGMA journal_mode=WAL")
53
- raw.execute("PRAGMA busy_timeout=30000")
54
- raw.execute("PRAGMA foreign_keys=ON")
55
- raw.execute("PRAGMA wal_autocheckpoint=100")
56
- raw.row_factory = sqlite3.Row
57
- _shared_conn = _SerializedConnection(raw)
58
- return _shared_conn
59
-
60
-
61
- def close_db():
62
- """Close the shared database connection. Called on shutdown signals."""
63
- global _shared_conn
64
- if _shared_conn is not None:
65
- try:
66
- _shared_conn.close()
67
- except Exception:
68
- pass
69
- _shared_conn = None
70
-
71
-
72
- def _get_raw_conn() -> sqlite3.Connection:
73
- """Get the raw unwrapped connection (for PRAGMA queries that need direct access)."""
74
- conn = get_db()
75
- if isinstance(conn, _SerializedConnection):
76
- return conn._conn
77
- return conn
78
-
79
-
80
- class _SerializedConnection:
81
- """Wrapper around sqlite3.Connection that serializes all execute calls.
82
-
83
- SQLite with a single shared connection and check_same_thread=False needs
84
- serialization to prevent:
85
- - Stale lastrowid when concurrent INSERTs happen
86
- - FTS5 index corruption from concurrent writes
87
- - 'NoneType' errors from interleaved INSERT+SELECT sequences
88
-
89
- All execute/executemany/executescript calls go through _write_lock.
90
- Property access (row_factory etc.) passes through directly.
91
- """
92
- def __init__(self, conn: sqlite3.Connection):
93
- self._conn = conn
94
-
95
- def execute(self, *args, **kwargs):
96
- with _write_lock:
97
- return self._conn.execute(*args, **kwargs)
98
-
99
- def executemany(self, *args, **kwargs):
100
- with _write_lock:
101
- return self._conn.executemany(*args, **kwargs)
102
-
103
- def executescript(self, *args, **kwargs):
104
- with _write_lock:
105
- return self._conn.executescript(*args, **kwargs)
106
-
107
- def commit(self):
108
- with _write_lock:
109
- return self._conn.commit()
110
-
111
- def close(self):
112
- return self._conn.close()
113
-
114
- def __getattr__(self, name):
115
- return getattr(self._conn, name)
116
-
117
- def __setattr__(self, name, value):
118
- if name == '_conn':
119
- super().__setattr__(name, value)
120
- else:
121
- setattr(self._conn, name, value)
122
-
123
-
124
- def init_db():
125
- """Create tables if they don't exist."""
126
- conn = get_db()
127
- conn.executescript("""
128
- CREATE TABLE IF NOT EXISTS sessions (
129
- sid TEXT PRIMARY KEY,
130
- task TEXT NOT NULL DEFAULT '',
131
- started_epoch REAL NOT NULL,
132
- last_update_epoch REAL NOT NULL,
133
- local_time TEXT NOT NULL DEFAULT ''
134
- );
135
-
136
- CREATE TABLE IF NOT EXISTS tracked_files (
137
- sid TEXT NOT NULL,
138
- path TEXT NOT NULL,
139
- tracked_at REAL NOT NULL,
140
- PRIMARY KEY (sid, path),
141
- FOREIGN KEY (sid) REFERENCES sessions(sid) ON DELETE CASCADE
142
- );
143
-
144
- CREATE TABLE IF NOT EXISTS messages (
145
- id TEXT PRIMARY KEY,
146
- from_sid TEXT NOT NULL,
147
- to_sid TEXT NOT NULL,
148
- text TEXT NOT NULL,
149
- created_epoch REAL NOT NULL
150
- );
151
-
152
- CREATE TABLE IF NOT EXISTS message_reads (
153
- message_id TEXT NOT NULL,
154
- sid TEXT NOT NULL,
155
- PRIMARY KEY (message_id, sid),
156
- FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE
157
- );
158
-
159
- CREATE TABLE IF NOT EXISTS questions (
160
- qid TEXT PRIMARY KEY,
161
- from_sid TEXT NOT NULL,
162
- to_sid TEXT NOT NULL,
163
- question TEXT NOT NULL,
164
- answer TEXT,
165
- status TEXT NOT NULL DEFAULT 'pending',
166
- created_epoch REAL NOT NULL,
167
- answered_epoch REAL
168
- );
169
-
170
-
171
- CREATE TABLE IF NOT EXISTS reminders (
172
- id TEXT PRIMARY KEY,
173
- date TEXT,
174
- description TEXT NOT NULL,
175
- status TEXT NOT NULL DEFAULT 'PENDING',
176
- category TEXT DEFAULT 'general',
177
- created_at REAL NOT NULL,
178
- updated_at REAL NOT NULL
179
- );
180
-
181
- CREATE TABLE IF NOT EXISTS followups (
182
- id TEXT PRIMARY KEY,
183
- date TEXT,
184
- description TEXT NOT NULL,
185
- verification TEXT DEFAULT '',
186
- status TEXT NOT NULL DEFAULT 'PENDING',
187
- recurrence TEXT DEFAULT NULL,
188
- created_at REAL NOT NULL,
189
- updated_at REAL NOT NULL
190
- );
191
-
192
- CREATE TABLE IF NOT EXISTS learnings (
193
- id INTEGER PRIMARY KEY AUTOINCREMENT,
194
- category TEXT NOT NULL,
195
- title TEXT NOT NULL,
196
- content TEXT NOT NULL,
197
- created_at REAL NOT NULL,
198
- updated_at REAL NOT NULL
199
- );
200
-
201
- CREATE TABLE IF NOT EXISTS credentials (
202
- id INTEGER PRIMARY KEY AUTOINCREMENT,
203
- service TEXT NOT NULL,
204
- key TEXT NOT NULL,
205
- value TEXT NOT NULL,
206
- notes TEXT DEFAULT '',
207
- created_at REAL NOT NULL,
208
- updated_at REAL NOT NULL,
209
- UNIQUE(service, key)
210
- );
211
-
212
- CREATE TABLE IF NOT EXISTS task_history (
213
- id INTEGER PRIMARY KEY AUTOINCREMENT,
214
- task_num TEXT NOT NULL,
215
- task_name TEXT NOT NULL,
216
- executed_at REAL NOT NULL,
217
- notes TEXT DEFAULT ''
218
- );
219
-
220
- CREATE TABLE IF NOT EXISTS task_frequencies (
221
- task_num TEXT PRIMARY KEY,
222
- task_name TEXT NOT NULL,
223
- frequency_days INTEGER NOT NULL,
224
- description TEXT DEFAULT ''
225
- );
226
-
227
- CREATE TABLE IF NOT EXISTS plugins (
228
- filename TEXT PRIMARY KEY,
229
- tools_count INTEGER DEFAULT 0,
230
- tool_names TEXT DEFAULT '',
231
- loaded_at REAL,
232
- created_by TEXT DEFAULT 'manual'
233
- );
234
-
235
- CREATE TABLE IF NOT EXISTS entities (
236
- id INTEGER PRIMARY KEY AUTOINCREMENT,
237
- name TEXT NOT NULL,
238
- type TEXT NOT NULL DEFAULT 'general',
239
- value TEXT NOT NULL,
240
- notes TEXT DEFAULT '',
241
- created_at REAL NOT NULL,
242
- updated_at REAL NOT NULL
243
- );
244
-
245
- CREATE TABLE IF NOT EXISTS preferences (
246
- key TEXT PRIMARY KEY,
247
- value TEXT NOT NULL,
248
- category TEXT DEFAULT 'general',
249
- updated_at REAL NOT NULL
250
- );
251
-
252
- CREATE TABLE IF NOT EXISTS agents (
253
- id TEXT PRIMARY KEY,
254
- name TEXT NOT NULL,
255
- specialization TEXT NOT NULL,
256
- model TEXT DEFAULT 'sonnet',
257
- tools TEXT DEFAULT '',
258
- context_files TEXT DEFAULT '',
259
- rules TEXT DEFAULT '',
260
- created_at REAL NOT NULL,
261
- updated_at REAL NOT NULL
262
- );
263
-
264
- CREATE TABLE IF NOT EXISTS change_log (
265
- id INTEGER PRIMARY KEY AUTOINCREMENT,
266
- session_id TEXT NOT NULL,
267
- created_at TEXT DEFAULT (datetime('now')),
268
- files TEXT NOT NULL,
269
- what_changed TEXT NOT NULL,
270
- why TEXT NOT NULL,
271
- triggered_by TEXT DEFAULT '',
272
- affects TEXT DEFAULT '',
273
- risks TEXT DEFAULT '',
274
- verify TEXT DEFAULT '',
275
- commit_ref TEXT DEFAULT ''
276
- );
277
-
278
- CREATE TABLE IF NOT EXISTS decisions (
279
- id INTEGER PRIMARY KEY AUTOINCREMENT,
280
- session_id TEXT NOT NULL,
281
- created_at TEXT DEFAULT (datetime('now')),
282
- domain TEXT NOT NULL,
283
- decision TEXT NOT NULL,
284
- alternatives TEXT,
285
- based_on TEXT,
286
- confidence TEXT DEFAULT 'medium',
287
- context_ref TEXT,
288
- outcome TEXT,
289
- outcome_at TEXT
290
- );
291
-
292
- CREATE TABLE IF NOT EXISTS session_diary (
293
- id INTEGER PRIMARY KEY AUTOINCREMENT,
294
- session_id TEXT NOT NULL,
295
- created_at TEXT DEFAULT (datetime('now')),
296
- decisions TEXT NOT NULL,
297
- discarded TEXT,
298
- pending TEXT,
299
- context_next TEXT,
300
- mental_state TEXT,
301
- domain TEXT,
302
- user_signals TEXT,
303
- summary TEXT NOT NULL
304
- );
305
-
306
- CREATE TABLE IF NOT EXISTS evolution_metrics (
307
- id INTEGER PRIMARY KEY AUTOINCREMENT,
308
- dimension TEXT NOT NULL,
309
- score INTEGER NOT NULL CHECK(score >= 0 AND score <= 100),
310
- measured_at TEXT DEFAULT (datetime('now')),
311
- evidence TEXT NOT NULL,
312
- delta INTEGER DEFAULT 0
313
- );
314
-
315
- CREATE TABLE IF NOT EXISTS evolution_log (
316
- id INTEGER PRIMARY KEY AUTOINCREMENT,
317
- created_at TEXT DEFAULT (datetime('now')),
318
- cycle_number INTEGER NOT NULL,
319
- dimension TEXT NOT NULL,
320
- proposal TEXT NOT NULL,
321
- classification TEXT NOT NULL DEFAULT 'auto',
322
- status TEXT DEFAULT 'pending',
323
- files_changed TEXT,
324
- snapshot_ref TEXT,
325
- test_result TEXT,
326
- impact INTEGER DEFAULT 0,
327
- reasoning TEXT NOT NULL
328
- );
329
- """)
330
- # foreign_keys=ON is set in get_db() per-connection
331
-
332
- # ── Run formal migrations ────────────────────────────────────
333
- from db._schema import run_migrations
334
- run_migrations(conn)
335
-
336
- # ── FTS5 unified search index ────────────────────────────────
337
- conn.execute("""
338
- CREATE VIRTUAL TABLE IF NOT EXISTS unified_search USING fts5(
339
- source,
340
- source_id,
341
- title,
342
- body,
343
- category,
344
- updated_at UNINDEXED,
345
- tokenize='unicode61 remove_diacritics 2'
346
- )
347
- """)
348
-
349
- # Dynamic directory registry for FTS indexing
350
- conn.execute("""
351
- CREATE TABLE IF NOT EXISTS fts_dirs (
352
- id INTEGER PRIMARY KEY AUTOINCREMENT,
353
- path TEXT NOT NULL UNIQUE,
354
- dir_type TEXT NOT NULL DEFAULT 'code',
355
- patterns TEXT NOT NULL DEFAULT '*.php,*.js,*.json,*.py,*.ts,*.tsx',
356
- added_at REAL NOT NULL,
357
- notes TEXT DEFAULT ''
358
- )
359
- """)
360
- conn.commit()
361
-
362
- if os.environ.get("NEXO_SKIP_FS_INDEX", "0") != "1":
363
- # FTS refresh in background thread — never block server startup
364
- import threading
365
-
366
- def _bg_fts():
367
- try:
368
- bg_conn = sqlite3.connect(DB_PATH, timeout=30)
369
- bg_conn.execute("PRAGMA journal_mode=WAL")
370
- bg_conn.execute("PRAGMA busy_timeout=30000")
371
- bg_conn.row_factory = sqlite3.Row
372
- row = bg_conn.execute("SELECT COUNT(*) FROM unified_search").fetchone()
373
- from db._fts import rebuild_fts_index, _refresh_fts_files
374
- if row[0] == 0:
375
- rebuild_fts_index(bg_conn)
376
- else:
377
- _refresh_fts_files(bg_conn)
378
- bg_conn.close()
379
- except Exception:
380
- pass
381
-
382
- threading.Thread(target=_bg_fts, daemon=True).start()
383
-
384
-
385
-
386
- def _gen_id(prefix: str, length: int = 8) -> str:
387
- """Generate a random ID like 'msg-a1b2c3' or 'q-x9y8z7w6'."""
388
- chars = string.ascii_lowercase + string.digits
389
- suffix = ''.join(secrets.choice(chars) for _ in range(length))
390
- return f"{prefix}-{suffix}"
391
-
392
-
393
- # ── Session operations ──────────────────────────────────────────────
394
-
395
- def now_epoch() -> float:
396
- return time.time()
397
-
398
-
399
- def local_time_str() -> str:
400
- from datetime import datetime
401
- return datetime.now().strftime("%H:%M")
402
-
403
-
404
- def _multi_word_like(query: str, columns: list[str]) -> tuple[str, list]:
405
- """Build AND-ed LIKE conditions: every word must appear in at least one column."""
406
- words = query.strip().split()
407
- if not words:
408
- return "1=1", []
409
- word_conditions = []
410
- params = []
411
- for word in words:
412
- pattern = f"%{word}%"
413
- col_or = " OR ".join(f"{c} LIKE ?" for c in columns)
414
- word_conditions.append(f"({col_or})")
415
- params.extend([pattern] * len(columns))
416
- return " AND ".join(word_conditions), params
417
-