superlocalmemory 2.8.5 → 3.0.0

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 (434) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -1
  3. package/NOTICE +63 -0
  4. package/README.md +165 -480
  5. package/bin/slm +17 -449
  6. package/bin/slm-npm +2 -2
  7. package/bin/slm.bat +4 -2
  8. package/conftest.py +5 -0
  9. package/docs/api-reference.md +284 -0
  10. package/docs/architecture.md +149 -0
  11. package/docs/auto-memory.md +150 -0
  12. package/docs/cli-reference.md +276 -0
  13. package/docs/compliance.md +191 -0
  14. package/docs/configuration.md +182 -0
  15. package/docs/getting-started.md +102 -0
  16. package/docs/ide-setup.md +261 -0
  17. package/docs/mcp-tools.md +220 -0
  18. package/docs/migration-from-v2.md +170 -0
  19. package/docs/profiles.md +173 -0
  20. package/docs/troubleshooting.md +310 -0
  21. package/{configs → ide/configs}/antigravity-mcp.json +3 -3
  22. package/ide/configs/chatgpt-desktop-mcp.json +16 -0
  23. package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
  24. package/{configs → ide/configs}/codex-mcp.toml +4 -4
  25. package/{configs → ide/configs}/continue-mcp.yaml +4 -3
  26. package/{configs → ide/configs}/continue-skills.yaml +6 -6
  27. package/ide/configs/cursor-mcp.json +15 -0
  28. package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
  29. package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
  30. package/{configs → ide/configs}/opencode-mcp.json +2 -2
  31. package/{configs → ide/configs}/perplexity-mcp.json +2 -2
  32. package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
  33. package/{configs → ide/configs}/windsurf-mcp.json +3 -3
  34. package/{configs → ide/configs}/zed-mcp.json +2 -2
  35. package/{hooks → ide/hooks}/context-hook.js +9 -20
  36. package/ide/hooks/memory-list-skill.js +70 -0
  37. package/ide/hooks/memory-profile-skill.js +101 -0
  38. package/ide/hooks/memory-recall-skill.js +62 -0
  39. package/ide/hooks/memory-remember-skill.js +68 -0
  40. package/ide/hooks/memory-reset-skill.js +160 -0
  41. package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
  42. package/ide/integrations/langchain/README.md +106 -0
  43. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
  44. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
  45. package/ide/integrations/langchain/pyproject.toml +38 -0
  46. package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
  47. package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
  48. package/ide/integrations/langchain/tests/test_security.py +117 -0
  49. package/ide/integrations/llamaindex/README.md +81 -0
  50. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
  51. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
  52. package/ide/integrations/llamaindex/pyproject.toml +43 -0
  53. package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
  54. package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
  55. package/ide/integrations/llamaindex/tests/test_security.py +241 -0
  56. package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
  57. package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
  58. package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
  59. package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
  60. package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
  61. package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
  62. package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
  63. package/package.json +13 -22
  64. package/pyproject.toml +85 -0
  65. package/scripts/build-dmg.sh +417 -0
  66. package/scripts/install-skills.ps1 +334 -0
  67. package/{install.ps1 → scripts/install.ps1} +36 -4
  68. package/{install.sh → scripts/install.sh} +14 -13
  69. package/scripts/postinstall.js +2 -2
  70. package/scripts/start-dashboard.ps1 +52 -0
  71. package/scripts/start-dashboard.sh +41 -0
  72. package/scripts/sync-wiki.ps1 +127 -0
  73. package/scripts/sync-wiki.sh +82 -0
  74. package/scripts/test-dmg.sh +161 -0
  75. package/scripts/test-npm-package.ps1 +252 -0
  76. package/scripts/test-npm-package.sh +207 -0
  77. package/scripts/verify-install.ps1 +294 -0
  78. package/scripts/verify-install.sh +266 -0
  79. package/src/superlocalmemory/__init__.py +0 -0
  80. package/src/superlocalmemory/attribution/__init__.py +9 -0
  81. package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
  82. package/src/superlocalmemory/attribution/signer.py +153 -0
  83. package/src/superlocalmemory/attribution/watermark.py +189 -0
  84. package/src/superlocalmemory/cli/__init__.py +5 -0
  85. package/src/superlocalmemory/cli/commands.py +245 -0
  86. package/src/superlocalmemory/cli/main.py +89 -0
  87. package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
  88. package/src/superlocalmemory/cli/post_install.py +99 -0
  89. package/src/superlocalmemory/cli/setup_wizard.py +129 -0
  90. package/src/superlocalmemory/compliance/__init__.py +0 -0
  91. package/src/superlocalmemory/compliance/abac.py +204 -0
  92. package/src/superlocalmemory/compliance/audit.py +314 -0
  93. package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
  94. package/src/superlocalmemory/compliance/gdpr.py +294 -0
  95. package/src/superlocalmemory/compliance/lifecycle.py +158 -0
  96. package/src/superlocalmemory/compliance/retention.py +232 -0
  97. package/src/superlocalmemory/compliance/scheduler.py +148 -0
  98. package/src/superlocalmemory/core/__init__.py +0 -0
  99. package/src/superlocalmemory/core/config.py +391 -0
  100. package/src/superlocalmemory/core/embeddings.py +293 -0
  101. package/src/superlocalmemory/core/engine.py +701 -0
  102. package/src/superlocalmemory/core/hooks.py +65 -0
  103. package/src/superlocalmemory/core/maintenance.py +172 -0
  104. package/src/superlocalmemory/core/modes.py +140 -0
  105. package/src/superlocalmemory/core/profiles.py +234 -0
  106. package/src/superlocalmemory/core/registry.py +117 -0
  107. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  108. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
  109. package/src/superlocalmemory/encoding/__init__.py +0 -0
  110. package/src/superlocalmemory/encoding/consolidator.py +485 -0
  111. package/src/superlocalmemory/encoding/emotional.py +125 -0
  112. package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
  113. package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
  114. package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
  115. package/src/superlocalmemory/encoding/foresight.py +91 -0
  116. package/src/superlocalmemory/encoding/graph_builder.py +302 -0
  117. package/src/superlocalmemory/encoding/observation_builder.py +160 -0
  118. package/src/superlocalmemory/encoding/scene_builder.py +183 -0
  119. package/src/superlocalmemory/encoding/signal_inference.py +90 -0
  120. package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
  121. package/src/superlocalmemory/encoding/type_router.py +235 -0
  122. package/src/superlocalmemory/hooks/__init__.py +3 -0
  123. package/src/superlocalmemory/hooks/auto_capture.py +111 -0
  124. package/src/superlocalmemory/hooks/auto_recall.py +93 -0
  125. package/src/superlocalmemory/hooks/ide_connector.py +204 -0
  126. package/src/superlocalmemory/hooks/rules_engine.py +99 -0
  127. package/src/superlocalmemory/infra/__init__.py +3 -0
  128. package/src/superlocalmemory/infra/auth_middleware.py +82 -0
  129. package/src/superlocalmemory/infra/backup.py +317 -0
  130. package/src/superlocalmemory/infra/cache_manager.py +267 -0
  131. package/src/superlocalmemory/infra/event_bus.py +381 -0
  132. package/src/superlocalmemory/infra/rate_limiter.py +135 -0
  133. package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
  134. package/src/superlocalmemory/learning/__init__.py +0 -0
  135. package/src/superlocalmemory/learning/adaptive.py +172 -0
  136. package/src/superlocalmemory/learning/behavioral.py +490 -0
  137. package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
  138. package/src/superlocalmemory/learning/bootstrap.py +298 -0
  139. package/src/superlocalmemory/learning/cross_project.py +399 -0
  140. package/src/superlocalmemory/learning/database.py +376 -0
  141. package/src/superlocalmemory/learning/engagement.py +323 -0
  142. package/src/superlocalmemory/learning/features.py +138 -0
  143. package/src/superlocalmemory/learning/feedback.py +316 -0
  144. package/src/superlocalmemory/learning/outcomes.py +255 -0
  145. package/src/superlocalmemory/learning/project_context.py +366 -0
  146. package/src/superlocalmemory/learning/ranker.py +155 -0
  147. package/src/superlocalmemory/learning/source_quality.py +303 -0
  148. package/src/superlocalmemory/learning/workflows.py +309 -0
  149. package/src/superlocalmemory/llm/__init__.py +0 -0
  150. package/src/superlocalmemory/llm/backbone.py +316 -0
  151. package/src/superlocalmemory/math/__init__.py +0 -0
  152. package/src/superlocalmemory/math/fisher.py +356 -0
  153. package/src/superlocalmemory/math/langevin.py +398 -0
  154. package/src/superlocalmemory/math/sheaf.py +257 -0
  155. package/src/superlocalmemory/mcp/__init__.py +0 -0
  156. package/src/superlocalmemory/mcp/resources.py +245 -0
  157. package/src/superlocalmemory/mcp/server.py +61 -0
  158. package/src/superlocalmemory/mcp/tools.py +18 -0
  159. package/src/superlocalmemory/mcp/tools_core.py +305 -0
  160. package/src/superlocalmemory/mcp/tools_v28.py +223 -0
  161. package/src/superlocalmemory/mcp/tools_v3.py +286 -0
  162. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  163. package/src/superlocalmemory/retrieval/agentic.py +295 -0
  164. package/src/superlocalmemory/retrieval/ann_index.py +223 -0
  165. package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
  166. package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
  167. package/src/superlocalmemory/retrieval/engine.py +390 -0
  168. package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
  169. package/src/superlocalmemory/retrieval/fusion.py +78 -0
  170. package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
  171. package/src/superlocalmemory/retrieval/reranker.py +154 -0
  172. package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
  173. package/src/superlocalmemory/retrieval/strategy.py +96 -0
  174. package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
  175. package/src/superlocalmemory/server/__init__.py +1 -0
  176. package/src/superlocalmemory/server/api.py +248 -0
  177. package/src/superlocalmemory/server/routes/__init__.py +4 -0
  178. package/src/superlocalmemory/server/routes/agents.py +107 -0
  179. package/src/superlocalmemory/server/routes/backup.py +91 -0
  180. package/src/superlocalmemory/server/routes/behavioral.py +127 -0
  181. package/src/superlocalmemory/server/routes/compliance.py +160 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +188 -0
  183. package/src/superlocalmemory/server/routes/events.py +183 -0
  184. package/src/superlocalmemory/server/routes/helpers.py +85 -0
  185. package/src/superlocalmemory/server/routes/learning.py +273 -0
  186. package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
  187. package/src/superlocalmemory/server/routes/memories.py +399 -0
  188. package/src/superlocalmemory/server/routes/profiles.py +219 -0
  189. package/src/superlocalmemory/server/routes/stats.py +346 -0
  190. package/src/superlocalmemory/server/routes/v3_api.py +365 -0
  191. package/src/superlocalmemory/server/routes/ws.py +82 -0
  192. package/src/superlocalmemory/server/security_middleware.py +57 -0
  193. package/src/superlocalmemory/server/ui.py +245 -0
  194. package/src/superlocalmemory/storage/__init__.py +0 -0
  195. package/src/superlocalmemory/storage/access_control.py +182 -0
  196. package/src/superlocalmemory/storage/database.py +594 -0
  197. package/src/superlocalmemory/storage/migrations.py +303 -0
  198. package/src/superlocalmemory/storage/models.py +406 -0
  199. package/src/superlocalmemory/storage/schema.py +726 -0
  200. package/src/superlocalmemory/storage/v2_migrator.py +317 -0
  201. package/src/superlocalmemory/trust/__init__.py +0 -0
  202. package/src/superlocalmemory/trust/gate.py +130 -0
  203. package/src/superlocalmemory/trust/provenance.py +124 -0
  204. package/src/superlocalmemory/trust/scorer.py +347 -0
  205. package/src/superlocalmemory/trust/signals.py +153 -0
  206. package/ui/index.html +278 -5
  207. package/ui/js/auto-settings.js +70 -0
  208. package/ui/js/dashboard.js +90 -0
  209. package/ui/js/fact-detail.js +92 -0
  210. package/ui/js/feedback.js +2 -2
  211. package/ui/js/ide-status.js +102 -0
  212. package/ui/js/math-health.js +98 -0
  213. package/ui/js/recall-lab.js +127 -0
  214. package/ui/js/settings.js +2 -2
  215. package/ui/js/trust-dashboard.js +73 -0
  216. package/api_server.py +0 -724
  217. package/bin/aider-smart +0 -72
  218. package/bin/superlocalmemoryv2-learning +0 -4
  219. package/bin/superlocalmemoryv2-list +0 -3
  220. package/bin/superlocalmemoryv2-patterns +0 -4
  221. package/bin/superlocalmemoryv2-profile +0 -3
  222. package/bin/superlocalmemoryv2-recall +0 -3
  223. package/bin/superlocalmemoryv2-remember +0 -3
  224. package/bin/superlocalmemoryv2-reset +0 -3
  225. package/bin/superlocalmemoryv2-status +0 -3
  226. package/configs/chatgpt-desktop-mcp.json +0 -16
  227. package/configs/cursor-mcp.json +0 -15
  228. package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
  229. package/hooks/memory-list-skill.js +0 -139
  230. package/hooks/memory-profile-skill.js +0 -273
  231. package/hooks/memory-recall-skill.js +0 -114
  232. package/hooks/memory-remember-skill.js +0 -127
  233. package/hooks/memory-reset-skill.js +0 -274
  234. package/mcp_server.py +0 -1800
  235. package/requirements-core.txt +0 -22
  236. package/requirements-learning.txt +0 -12
  237. package/requirements.txt +0 -12
  238. package/src/agent_registry.py +0 -411
  239. package/src/auth_middleware.py +0 -61
  240. package/src/auto_backup.py +0 -459
  241. package/src/behavioral/__init__.py +0 -49
  242. package/src/behavioral/behavioral_listener.py +0 -203
  243. package/src/behavioral/behavioral_patterns.py +0 -275
  244. package/src/behavioral/cross_project_transfer.py +0 -206
  245. package/src/behavioral/outcome_inference.py +0 -194
  246. package/src/behavioral/outcome_tracker.py +0 -193
  247. package/src/behavioral/tests/__init__.py +0 -4
  248. package/src/behavioral/tests/test_behavioral_integration.py +0 -108
  249. package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
  250. package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
  251. package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
  252. package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
  253. package/src/behavioral/tests/test_outcome_inference.py +0 -107
  254. package/src/behavioral/tests/test_outcome_tracker.py +0 -96
  255. package/src/cache_manager.py +0 -518
  256. package/src/compliance/__init__.py +0 -48
  257. package/src/compliance/abac_engine.py +0 -149
  258. package/src/compliance/abac_middleware.py +0 -116
  259. package/src/compliance/audit_db.py +0 -215
  260. package/src/compliance/audit_logger.py +0 -148
  261. package/src/compliance/retention_manager.py +0 -289
  262. package/src/compliance/retention_scheduler.py +0 -186
  263. package/src/compliance/tests/__init__.py +0 -4
  264. package/src/compliance/tests/test_abac_enforcement.py +0 -95
  265. package/src/compliance/tests/test_abac_engine.py +0 -124
  266. package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
  267. package/src/compliance/tests/test_audit_db.py +0 -123
  268. package/src/compliance/tests/test_audit_logger.py +0 -98
  269. package/src/compliance/tests/test_mcp_audit.py +0 -128
  270. package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
  271. package/src/compliance/tests/test_retention_manager.py +0 -131
  272. package/src/compliance/tests/test_retention_scheduler.py +0 -99
  273. package/src/compression/__init__.py +0 -25
  274. package/src/compression/cli.py +0 -150
  275. package/src/compression/cold_storage.py +0 -217
  276. package/src/compression/config.py +0 -72
  277. package/src/compression/orchestrator.py +0 -133
  278. package/src/compression/tier2_compressor.py +0 -228
  279. package/src/compression/tier3_compressor.py +0 -153
  280. package/src/compression/tier_classifier.py +0 -148
  281. package/src/db_connection_manager.py +0 -536
  282. package/src/embedding_engine.py +0 -63
  283. package/src/embeddings/__init__.py +0 -47
  284. package/src/embeddings/cache.py +0 -70
  285. package/src/embeddings/cli.py +0 -113
  286. package/src/embeddings/constants.py +0 -47
  287. package/src/embeddings/database.py +0 -91
  288. package/src/embeddings/engine.py +0 -247
  289. package/src/embeddings/model_loader.py +0 -145
  290. package/src/event_bus.py +0 -562
  291. package/src/graph/__init__.py +0 -36
  292. package/src/graph/build_helpers.py +0 -74
  293. package/src/graph/cli.py +0 -87
  294. package/src/graph/cluster_builder.py +0 -188
  295. package/src/graph/cluster_summary.py +0 -148
  296. package/src/graph/constants.py +0 -47
  297. package/src/graph/edge_builder.py +0 -162
  298. package/src/graph/entity_extractor.py +0 -95
  299. package/src/graph/graph_core.py +0 -226
  300. package/src/graph/graph_search.py +0 -231
  301. package/src/graph/hierarchical.py +0 -207
  302. package/src/graph/schema.py +0 -99
  303. package/src/graph_engine.py +0 -52
  304. package/src/hnsw_index.py +0 -628
  305. package/src/hybrid_search.py +0 -46
  306. package/src/learning/__init__.py +0 -217
  307. package/src/learning/adaptive_ranker.py +0 -682
  308. package/src/learning/bootstrap/__init__.py +0 -69
  309. package/src/learning/bootstrap/constants.py +0 -93
  310. package/src/learning/bootstrap/db_queries.py +0 -316
  311. package/src/learning/bootstrap/sampling.py +0 -82
  312. package/src/learning/bootstrap/text_utils.py +0 -71
  313. package/src/learning/cross_project_aggregator.py +0 -857
  314. package/src/learning/db/__init__.py +0 -40
  315. package/src/learning/db/constants.py +0 -44
  316. package/src/learning/db/schema.py +0 -279
  317. package/src/learning/engagement_tracker.py +0 -628
  318. package/src/learning/feature_extractor.py +0 -708
  319. package/src/learning/feedback_collector.py +0 -806
  320. package/src/learning/learning_db.py +0 -915
  321. package/src/learning/project_context_manager.py +0 -572
  322. package/src/learning/ranking/__init__.py +0 -33
  323. package/src/learning/ranking/constants.py +0 -84
  324. package/src/learning/ranking/helpers.py +0 -278
  325. package/src/learning/source_quality_scorer.py +0 -676
  326. package/src/learning/synthetic_bootstrap.py +0 -755
  327. package/src/learning/tests/test_adaptive_ranker.py +0 -325
  328. package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
  329. package/src/learning/tests/test_aggregator.py +0 -306
  330. package/src/learning/tests/test_auto_retrain_v28.py +0 -35
  331. package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
  332. package/src/learning/tests/test_feature_extractor_v28.py +0 -93
  333. package/src/learning/tests/test_feedback_collector.py +0 -294
  334. package/src/learning/tests/test_learning_db.py +0 -602
  335. package/src/learning/tests/test_learning_db_v28.py +0 -110
  336. package/src/learning/tests/test_learning_init_v28.py +0 -48
  337. package/src/learning/tests/test_outcome_signals.py +0 -48
  338. package/src/learning/tests/test_project_context.py +0 -292
  339. package/src/learning/tests/test_schema_migration.py +0 -319
  340. package/src/learning/tests/test_signal_inference.py +0 -397
  341. package/src/learning/tests/test_source_quality.py +0 -351
  342. package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
  343. package/src/learning/tests/test_workflow_miner.py +0 -318
  344. package/src/learning/workflow_pattern_miner.py +0 -655
  345. package/src/lifecycle/__init__.py +0 -54
  346. package/src/lifecycle/bounded_growth.py +0 -239
  347. package/src/lifecycle/compaction_engine.py +0 -226
  348. package/src/lifecycle/lifecycle_engine.py +0 -355
  349. package/src/lifecycle/lifecycle_evaluator.py +0 -257
  350. package/src/lifecycle/lifecycle_scheduler.py +0 -130
  351. package/src/lifecycle/retention_policy.py +0 -285
  352. package/src/lifecycle/tests/test_bounded_growth.py +0 -193
  353. package/src/lifecycle/tests/test_compaction.py +0 -179
  354. package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
  355. package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
  356. package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
  357. package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
  358. package/src/lifecycle/tests/test_mcp_compact.py +0 -149
  359. package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
  360. package/src/lifecycle/tests/test_retention_policy.py +0 -162
  361. package/src/mcp_tools_v28.py +0 -281
  362. package/src/memory/__init__.py +0 -36
  363. package/src/memory/cli.py +0 -205
  364. package/src/memory/constants.py +0 -39
  365. package/src/memory/helpers.py +0 -28
  366. package/src/memory/schema.py +0 -166
  367. package/src/memory-profiles.py +0 -595
  368. package/src/memory-reset.py +0 -491
  369. package/src/memory_compression.py +0 -989
  370. package/src/memory_store_v2.py +0 -1155
  371. package/src/migrate_v1_to_v2.py +0 -629
  372. package/src/pattern_learner.py +0 -34
  373. package/src/patterns/__init__.py +0 -24
  374. package/src/patterns/analyzers.py +0 -251
  375. package/src/patterns/learner.py +0 -271
  376. package/src/patterns/scoring.py +0 -171
  377. package/src/patterns/store.py +0 -225
  378. package/src/patterns/terminology.py +0 -140
  379. package/src/provenance_tracker.py +0 -312
  380. package/src/qualixar_attribution.py +0 -139
  381. package/src/qualixar_watermark.py +0 -78
  382. package/src/query_optimizer.py +0 -511
  383. package/src/rate_limiter.py +0 -83
  384. package/src/search/__init__.py +0 -20
  385. package/src/search/cli.py +0 -77
  386. package/src/search/constants.py +0 -26
  387. package/src/search/engine.py +0 -241
  388. package/src/search/fusion.py +0 -122
  389. package/src/search/index_loader.py +0 -114
  390. package/src/search/methods.py +0 -162
  391. package/src/search_engine_v2.py +0 -401
  392. package/src/setup_validator.py +0 -482
  393. package/src/subscription_manager.py +0 -391
  394. package/src/tree/__init__.py +0 -59
  395. package/src/tree/builder.py +0 -185
  396. package/src/tree/nodes.py +0 -202
  397. package/src/tree/queries.py +0 -257
  398. package/src/tree/schema.py +0 -80
  399. package/src/tree_manager.py +0 -19
  400. package/src/trust/__init__.py +0 -45
  401. package/src/trust/constants.py +0 -66
  402. package/src/trust/queries.py +0 -157
  403. package/src/trust/schema.py +0 -95
  404. package/src/trust/scorer.py +0 -299
  405. package/src/trust/signals.py +0 -95
  406. package/src/trust_scorer.py +0 -44
  407. package/ui/app.js +0 -1588
  408. package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
  409. package/ui/js/graph-cytoscape.js +0 -1168
  410. package/ui/js/graph-d3-backup.js +0 -32
  411. package/ui/js/graph.js +0 -32
  412. package/ui_server.py +0 -266
  413. /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
  414. /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
  415. /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
  416. /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
  417. /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
  418. /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
  419. /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
  420. /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
  421. /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
  422. /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
  423. /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
  424. /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
  425. /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
  426. /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
  427. /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
  428. /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
  429. /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
  430. /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
  431. /package/{completions → ide/completions}/slm.bash +0 -0
  432. /package/{completions → ide/completions}/slm.zsh +0 -0
  433. /package/{configs → ide/configs}/cody-commands.json +0 -0
  434. /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
@@ -1,124 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for ABAC policy engine.
4
- """
5
- import tempfile
6
- import os
7
- import sys
8
- import json
9
- from pathlib import Path
10
-
11
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
12
-
13
-
14
- class TestABACEngine:
15
- def setup_method(self):
16
- self.tmp_dir = tempfile.mkdtemp()
17
- self.policy_path = os.path.join(self.tmp_dir, "abac_policies.json")
18
-
19
- def teardown_method(self):
20
- import shutil
21
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
22
-
23
- def _write_policies(self, policies):
24
- with open(self.policy_path, "w") as f:
25
- json.dump(policies, f)
26
-
27
- def test_creation_no_policy_file(self):
28
- """Engine works with no policy file — allow all."""
29
- from compliance.abac_engine import ABACEngine
30
- engine = ABACEngine(config_path="/nonexistent/path.json")
31
- assert engine is not None
32
-
33
- def test_missing_policy_allows_all(self):
34
- """No policy file → all access allowed (backward compat)."""
35
- from compliance.abac_engine import ABACEngine
36
- engine = ABACEngine(config_path="/nonexistent/path.json")
37
- result = engine.evaluate(subject={"agent_id": "user"}, resource={"access_level": "public"}, action="read")
38
- assert result["allowed"] is True
39
-
40
- def test_load_policies_from_json(self):
41
- """Can load policies from JSON file."""
42
- from compliance.abac_engine import ABACEngine
43
- self._write_policies([
44
- {"name": "deny-private", "effect": "deny", "subjects": {"agent_id": "*"}, "resources": {"access_level": "private"}, "actions": ["read"]}
45
- ])
46
- engine = ABACEngine(config_path=self.policy_path)
47
- assert len(engine.policies) == 1
48
-
49
- def test_deny_policy_blocks_access(self):
50
- """Deny policy prevents access to matching resources."""
51
- from compliance.abac_engine import ABACEngine
52
- self._write_policies([
53
- {"name": "deny-private", "effect": "deny", "subjects": {"agent_id": "*"}, "resources": {"access_level": "private"}, "actions": ["read"]}
54
- ])
55
- engine = ABACEngine(config_path=self.policy_path)
56
- result = engine.evaluate(subject={"agent_id": "agent_a"}, resource={"access_level": "private"}, action="read")
57
- assert result["allowed"] is False
58
- assert result["policy_name"] == "deny-private"
59
-
60
- def test_allow_policy_grants_access(self):
61
- """Allow policy explicitly permits access."""
62
- from compliance.abac_engine import ABACEngine
63
- self._write_policies([
64
- {"name": "allow-admin", "effect": "allow", "subjects": {"agent_id": "admin"}, "resources": {"access_level": "*"}, "actions": ["read", "write", "delete"]}
65
- ])
66
- engine = ABACEngine(config_path=self.policy_path)
67
- result = engine.evaluate(subject={"agent_id": "admin"}, resource={"access_level": "private"}, action="write")
68
- assert result["allowed"] is True
69
-
70
- def test_subject_matching_specific_agent(self):
71
- """Policy matches specific agent_id."""
72
- from compliance.abac_engine import ABACEngine
73
- self._write_policies([
74
- {"name": "deny-untrusted", "effect": "deny", "subjects": {"agent_id": "untrusted_bot"}, "resources": {"access_level": "*"}, "actions": ["read"]}
75
- ])
76
- engine = ABACEngine(config_path=self.policy_path)
77
- # untrusted_bot denied
78
- r1 = engine.evaluate(subject={"agent_id": "untrusted_bot"}, resource={"access_level": "public"}, action="read")
79
- assert r1["allowed"] is False
80
- # trusted_agent allowed (no matching deny policy)
81
- r2 = engine.evaluate(subject={"agent_id": "trusted_agent"}, resource={"access_level": "public"}, action="read")
82
- assert r2["allowed"] is True
83
-
84
- def test_resource_matching_by_project(self):
85
- """Policy matches by project name."""
86
- from compliance.abac_engine import ABACEngine
87
- self._write_policies([
88
- {"name": "deny-secret-project", "effect": "deny", "subjects": {"agent_id": "*"}, "resources": {"project": "secret_project"}, "actions": ["read"]}
89
- ])
90
- engine = ABACEngine(config_path=self.policy_path)
91
- r1 = engine.evaluate(subject={"agent_id": "user"}, resource={"project": "secret_project"}, action="read")
92
- assert r1["allowed"] is False
93
- r2 = engine.evaluate(subject={"agent_id": "user"}, resource={"project": "public_project"}, action="read")
94
- assert r2["allowed"] is True
95
-
96
- def test_action_matching(self):
97
- """Policy only applies to specified actions."""
98
- from compliance.abac_engine import ABACEngine
99
- self._write_policies([
100
- {"name": "deny-delete", "effect": "deny", "subjects": {"agent_id": "*"}, "resources": {"access_level": "*"}, "actions": ["delete"]}
101
- ])
102
- engine = ABACEngine(config_path=self.policy_path)
103
- r1 = engine.evaluate(subject={"agent_id": "user"}, resource={"access_level": "public"}, action="delete")
104
- assert r1["allowed"] is False
105
- r2 = engine.evaluate(subject={"agent_id": "user"}, resource={"access_level": "public"}, action="read")
106
- assert r2["allowed"] is True
107
-
108
- def test_deny_takes_precedence(self):
109
- """When both allow and deny match, deny wins."""
110
- from compliance.abac_engine import ABACEngine
111
- self._write_policies([
112
- {"name": "allow-all", "effect": "allow", "subjects": {"agent_id": "*"}, "resources": {"access_level": "*"}, "actions": ["read"]},
113
- {"name": "deny-private", "effect": "deny", "subjects": {"agent_id": "*"}, "resources": {"access_level": "private"}, "actions": ["read"]}
114
- ])
115
- engine = ABACEngine(config_path=self.policy_path)
116
- result = engine.evaluate(subject={"agent_id": "user"}, resource={"access_level": "private"}, action="read")
117
- assert result["allowed"] is False
118
-
119
- def test_evaluate_returns_reason(self):
120
- """Evaluation result includes reason."""
121
- from compliance.abac_engine import ABACEngine
122
- engine = ABACEngine(config_path="/nonexistent/path.json")
123
- result = engine.evaluate(subject={"agent_id": "user"}, resource={}, action="read")
124
- assert "reason" in result
@@ -1,118 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for ABAC enforcement via MCP tool integration.
4
- """
5
- import tempfile
6
- import os
7
- import sys
8
- import json
9
- from pathlib import Path
10
-
11
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
12
-
13
-
14
- class TestABACMCPIntegration:
15
- def setup_method(self):
16
- self.tmp_dir = tempfile.mkdtemp()
17
- self.db_path = os.path.join(self.tmp_dir, "memory.db")
18
-
19
- def teardown_method(self):
20
- import shutil
21
-
22
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
23
-
24
- def test_middleware_creation(self):
25
- from compliance.abac_middleware import ABACMiddleware
26
-
27
- mw = ABACMiddleware(self.db_path)
28
- assert mw is not None
29
-
30
- def test_check_read_access_default_allow(self):
31
- """Default (no policies) allows all reads."""
32
- from compliance.abac_middleware import ABACMiddleware
33
-
34
- mw = ABACMiddleware(self.db_path)
35
- result = mw.check_access(
36
- agent_id="any_agent",
37
- action="read",
38
- resource={"access_level": "public"},
39
- )
40
- assert result["allowed"] is True
41
-
42
- def test_check_write_access_default_allow(self):
43
- from compliance.abac_middleware import ABACMiddleware
44
-
45
- mw = ABACMiddleware(self.db_path)
46
- result = mw.check_access(
47
- agent_id="any_agent", action="write", resource={}
48
- )
49
- assert result["allowed"] is True
50
-
51
- def test_check_access_with_deny_policy(self):
52
- """Deny policy blocks access when enforced."""
53
- from compliance.abac_middleware import ABACMiddleware
54
-
55
- policy_path = os.path.join(self.tmp_dir, "abac_policies.json")
56
- with open(policy_path, "w") as f:
57
- json.dump(
58
- [
59
- {
60
- "name": "deny-bots",
61
- "effect": "deny",
62
- "subjects": {"agent_id": "untrusted_bot"},
63
- "resources": {"access_level": "*"},
64
- "actions": ["read", "write"],
65
- }
66
- ],
67
- f,
68
- )
69
- mw = ABACMiddleware(self.db_path, policy_path=policy_path)
70
- result = mw.check_access(
71
- agent_id="untrusted_bot",
72
- action="read",
73
- resource={"access_level": "public"},
74
- )
75
- assert result["allowed"] is False
76
-
77
- def test_denied_access_logged(self):
78
- """Denied access is recorded for audit trail."""
79
- from compliance.abac_middleware import ABACMiddleware
80
-
81
- policy_path = os.path.join(self.tmp_dir, "abac_policies.json")
82
- with open(policy_path, "w") as f:
83
- json.dump(
84
- [
85
- {
86
- "name": "deny-all-write",
87
- "effect": "deny",
88
- "subjects": {"agent_id": "*"},
89
- "resources": {"access_level": "*"},
90
- "actions": ["write"],
91
- }
92
- ],
93
- f,
94
- )
95
- mw = ABACMiddleware(self.db_path, policy_path=policy_path)
96
- mw.check_access(agent_id="user", action="write", resource={})
97
- assert mw.denied_count >= 1
98
-
99
- def test_build_agent_context(self):
100
- """build_agent_context creates proper context dict for store."""
101
- from compliance.abac_middleware import ABACMiddleware
102
-
103
- mw = ABACMiddleware(self.db_path)
104
- ctx = mw.build_agent_context(agent_id="claude_agent", protocol="mcp")
105
- assert ctx["agent_id"] == "claude_agent"
106
- assert ctx["protocol"] == "mcp"
107
-
108
- def test_graceful_when_compliance_unavailable(self):
109
- """Middleware works even if ABACEngine import fails."""
110
- from compliance.abac_middleware import ABACMiddleware
111
-
112
- mw = ABACMiddleware(
113
- self.db_path, policy_path="/nonexistent/path.json"
114
- )
115
- result = mw.check_access(
116
- agent_id="user", action="read", resource={}
117
- )
118
- assert result["allowed"] is True
@@ -1,123 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for audit database with hash chain tamper detection.
4
- """
5
- import sqlite3
6
- import tempfile
7
- import os
8
- import sys
9
- import hashlib
10
- import json
11
- from pathlib import Path
12
-
13
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
14
-
15
-
16
- class TestAuditDB:
17
- def setup_method(self):
18
- self.tmp_dir = tempfile.mkdtemp()
19
- self.db_path = os.path.join(self.tmp_dir, "audit.db")
20
-
21
- def teardown_method(self):
22
- import shutil
23
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
24
-
25
- def test_creation(self):
26
- from compliance.audit_db import AuditDB
27
- db = AuditDB(self.db_path)
28
- assert db is not None
29
-
30
- def test_schema_created(self):
31
- from compliance.audit_db import AuditDB
32
- db = AuditDB(self.db_path)
33
- conn = sqlite3.connect(self.db_path)
34
- tables = {r[0] for r in conn.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()}
35
- conn.close()
36
- assert "audit_events" in tables
37
-
38
- def test_log_event(self):
39
- from compliance.audit_db import AuditDB
40
- db = AuditDB(self.db_path)
41
- eid = db.log_event(event_type="memory.created", actor="user", resource_id=1, details={"action": "create"})
42
- assert isinstance(eid, int)
43
- assert eid > 0
44
-
45
- def test_hash_chain_first_entry(self):
46
- """First entry's prev_hash should be a known genesis value."""
47
- from compliance.audit_db import AuditDB
48
- db = AuditDB(self.db_path)
49
- db.log_event("memory.created", actor="user", resource_id=1)
50
- conn = sqlite3.connect(self.db_path)
51
- row = conn.execute("SELECT prev_hash, entry_hash FROM audit_events WHERE id=1").fetchone()
52
- conn.close()
53
- assert row[0] == "genesis"
54
- assert row[1] is not None and len(row[1]) == 64 # SHA-256 hex
55
-
56
- def test_hash_chain_links(self):
57
- """Each entry's prev_hash should equal the previous entry's entry_hash."""
58
- from compliance.audit_db import AuditDB
59
- db = AuditDB(self.db_path)
60
- db.log_event("memory.created", actor="user", resource_id=1)
61
- db.log_event("memory.recalled", actor="agent_a", resource_id=2)
62
- db.log_event("memory.deleted", actor="user", resource_id=1)
63
- conn = sqlite3.connect(self.db_path)
64
- rows = conn.execute("SELECT id, prev_hash, entry_hash FROM audit_events ORDER BY id").fetchall()
65
- conn.close()
66
- assert rows[1][1] == rows[0][2] # Entry 2's prev = Entry 1's hash
67
- assert rows[2][1] == rows[1][2] # Entry 3's prev = Entry 2's hash
68
-
69
- def test_verify_chain_valid(self):
70
- """verify_chain returns True for untampered chain."""
71
- from compliance.audit_db import AuditDB
72
- db = AuditDB(self.db_path)
73
- db.log_event("memory.created", actor="user", resource_id=1)
74
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
75
- result = db.verify_chain()
76
- assert result["valid"] is True
77
- assert result["entries_checked"] == 2
78
-
79
- def test_verify_chain_detects_tampering(self):
80
- """verify_chain returns False if an entry was modified."""
81
- from compliance.audit_db import AuditDB
82
- db = AuditDB(self.db_path)
83
- db.log_event("memory.created", actor="user", resource_id=1)
84
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
85
- # Tamper with the first entry
86
- conn = sqlite3.connect(self.db_path)
87
- conn.execute("UPDATE audit_events SET actor='hacker' WHERE id=1")
88
- conn.commit()
89
- conn.close()
90
- result = db.verify_chain()
91
- assert result["valid"] is False
92
-
93
- def test_query_by_type(self):
94
- from compliance.audit_db import AuditDB
95
- db = AuditDB(self.db_path)
96
- db.log_event("memory.created", actor="user", resource_id=1)
97
- db.log_event("memory.recalled", actor="user", resource_id=1)
98
- db.log_event("memory.created", actor="user", resource_id=2)
99
- results = db.query_events(event_type="memory.created")
100
- assert len(results) == 2
101
-
102
- def test_query_by_actor(self):
103
- from compliance.audit_db import AuditDB
104
- db = AuditDB(self.db_path)
105
- db.log_event("memory.created", actor="user", resource_id=1)
106
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
107
- results = db.query_events(actor="agent_a")
108
- assert len(results) == 1
109
-
110
- def test_query_by_time_range(self):
111
- from compliance.audit_db import AuditDB
112
- db = AuditDB(self.db_path)
113
- db.log_event("memory.created", actor="user", resource_id=1)
114
- results = db.query_events(limit=10)
115
- assert len(results) >= 1
116
- assert "created_at" in results[0]
117
-
118
- def test_empty_chain_is_valid(self):
119
- from compliance.audit_db import AuditDB
120
- db = AuditDB(self.db_path)
121
- result = db.verify_chain()
122
- assert result["valid"] is True
123
- assert result["entries_checked"] == 0
@@ -1,98 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for audit logger EventBus listener.
4
- """
5
- import tempfile, os, sys, sqlite3
6
- from datetime import datetime
7
- from pathlib import Path
8
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
9
-
10
- class TestAuditLogger:
11
- def setup_method(self):
12
- self.tmp_dir = tempfile.mkdtemp()
13
- self.audit_db_path = os.path.join(self.tmp_dir, "audit.db")
14
-
15
- def teardown_method(self):
16
- import shutil
17
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
18
-
19
- def test_creation(self):
20
- from compliance.audit_logger import AuditLogger
21
- logger = AuditLogger(self.audit_db_path)
22
- assert logger is not None
23
-
24
- def test_logs_memory_created(self):
25
- from compliance.audit_logger import AuditLogger
26
- logger = AuditLogger(self.audit_db_path)
27
- logger.handle_event({"event_type": "memory.created", "memory_id": 1, "payload": {}, "timestamp": datetime.now().isoformat(), "source_agent": "user"})
28
- conn = sqlite3.connect(self.audit_db_path)
29
- rows = conn.execute("SELECT * FROM audit_events WHERE event_type='memory.created'").fetchall()
30
- conn.close()
31
- assert len(rows) == 1
32
-
33
- def test_logs_memory_recalled(self):
34
- from compliance.audit_logger import AuditLogger
35
- logger = AuditLogger(self.audit_db_path)
36
- logger.handle_event({"event_type": "memory.recalled", "memory_id": 2, "payload": {"query": "test"}, "timestamp": datetime.now().isoformat(), "source_agent": "agent_a"})
37
- conn = sqlite3.connect(self.audit_db_path)
38
- rows = conn.execute("SELECT * FROM audit_events WHERE event_type='memory.recalled'").fetchall()
39
- conn.close()
40
- assert len(rows) == 1
41
-
42
- def test_logs_memory_deleted(self):
43
- from compliance.audit_logger import AuditLogger
44
- logger = AuditLogger(self.audit_db_path)
45
- logger.handle_event({"event_type": "memory.deleted", "memory_id": 3, "payload": {}, "timestamp": datetime.now().isoformat(), "source_agent": "user"})
46
- conn = sqlite3.connect(self.audit_db_path)
47
- rows = conn.execute("SELECT * FROM audit_events WHERE event_type='memory.deleted'").fetchall()
48
- conn.close()
49
- assert len(rows) == 1
50
-
51
- def test_hash_chain_maintained(self):
52
- """Multiple events maintain hash chain integrity."""
53
- from compliance.audit_logger import AuditLogger
54
- logger = AuditLogger(self.audit_db_path)
55
- for i in range(5):
56
- logger.handle_event({"event_type": "memory.created", "memory_id": i, "payload": {}, "timestamp": datetime.now().isoformat(), "source_agent": "user"})
57
- from compliance.audit_db import AuditDB
58
- db = AuditDB(self.audit_db_path)
59
- result = db.verify_chain()
60
- assert result["valid"] is True
61
- assert result["entries_checked"] == 5
62
-
63
- def test_logs_lifecycle_transitions(self):
64
- from compliance.audit_logger import AuditLogger
65
- logger = AuditLogger(self.audit_db_path)
66
- logger.handle_event({"event_type": "lifecycle.transitioned", "memory_id": 1, "payload": {"from_state": "active", "to_state": "warm"}, "timestamp": datetime.now().isoformat(), "source_agent": "scheduler"})
67
- conn = sqlite3.connect(self.audit_db_path)
68
- rows = conn.execute("SELECT * FROM audit_events").fetchall()
69
- conn.close()
70
- assert len(rows) == 1
71
-
72
- def test_ignores_unknown_gracefully(self):
73
- """Unknown event types logged without error."""
74
- from compliance.audit_logger import AuditLogger
75
- logger = AuditLogger(self.audit_db_path)
76
- logger.handle_event({"event_type": "unknown.event", "payload": {}, "timestamp": datetime.now().isoformat(), "source_agent": "test"})
77
- assert logger.events_logged >= 1
78
-
79
- def test_graceful_on_malformed_event(self):
80
- """Malformed events don't crash the logger."""
81
- from compliance.audit_logger import AuditLogger
82
- logger = AuditLogger(self.audit_db_path)
83
- logger.handle_event({}) # Empty event
84
- logger.handle_event({"event_type": "test"}) # Missing fields
85
- # Should not crash
86
-
87
- def test_register_with_eventbus(self):
88
- from compliance.audit_logger import AuditLogger
89
- logger = AuditLogger(self.audit_db_path)
90
- result = logger.register_with_eventbus()
91
- assert isinstance(result, bool)
92
-
93
- def test_get_status(self):
94
- from compliance.audit_logger import AuditLogger
95
- logger = AuditLogger(self.audit_db_path)
96
- status = logger.get_status()
97
- assert "events_logged" in status
98
- assert "registered" in status
@@ -1,128 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for audit_trail MCP tool handler.
4
-
5
- Validates the MCP wrapper around AuditDB — tests empty trail, event logging,
6
- event_type and actor filtering, and hash chain verification.
7
- """
8
- import asyncio
9
- import os
10
- import shutil
11
- import sys
12
- import tempfile
13
- from pathlib import Path
14
-
15
- import pytest
16
-
17
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
18
-
19
-
20
- class TestMCPAuditTrail:
21
- """Tests for the audit_trail tool handler."""
22
-
23
- def setup_method(self):
24
- self.tmp_dir = tempfile.mkdtemp()
25
- self.db_path = os.path.join(self.tmp_dir, "audit.db")
26
-
27
- def teardown_method(self):
28
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
29
-
30
- def _run(self, coro):
31
- return asyncio.get_event_loop().run_until_complete(coro)
32
-
33
- def test_empty_trail(self):
34
- """Fresh audit DB should return count=0."""
35
- import mcp_tools_v28 as tools
36
- tools.DEFAULT_AUDIT_DB = self.db_path
37
-
38
- result = self._run(tools.audit_trail())
39
- assert result["success"] is True
40
- assert result["count"] == 0
41
- assert result["events"] == []
42
-
43
- def test_verify_empty_chain(self):
44
- """Hash chain verification on empty DB should be valid."""
45
- import mcp_tools_v28 as tools
46
- tools.DEFAULT_AUDIT_DB = self.db_path
47
-
48
- result = self._run(tools.audit_trail(verify_chain=True))
49
- assert result["success"] is True
50
- assert result["chain_valid"] is True
51
- assert result["chain_entries"] == 0
52
-
53
- def test_query_with_events(self):
54
- """After logging events, query should return them."""
55
- from compliance.audit_db import AuditDB
56
-
57
- db = AuditDB(self.db_path)
58
- db.log_event("memory.created", actor="user", resource_id=1)
59
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
60
- db.log_event("memory.created", actor="user", resource_id=2)
61
-
62
- import mcp_tools_v28 as tools
63
- tools.DEFAULT_AUDIT_DB = self.db_path
64
-
65
- result = self._run(tools.audit_trail())
66
- assert result["success"] is True
67
- assert result["count"] == 3
68
-
69
- def test_filter_by_event_type(self):
70
- """Filtering by event_type should narrow results."""
71
- from compliance.audit_db import AuditDB
72
-
73
- db = AuditDB(self.db_path)
74
- db.log_event("memory.created", actor="user", resource_id=1)
75
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
76
-
77
- import mcp_tools_v28 as tools
78
- tools.DEFAULT_AUDIT_DB = self.db_path
79
-
80
- result = self._run(tools.audit_trail(event_type="memory.created"))
81
- assert result["count"] == 1
82
- assert result["events"][0]["event_type"] == "memory.created"
83
-
84
- def test_filter_by_actor(self):
85
- """Filtering by actor should narrow results."""
86
- from compliance.audit_db import AuditDB
87
-
88
- db = AuditDB(self.db_path)
89
- db.log_event("memory.created", actor="user", resource_id=1)
90
- db.log_event("memory.recalled", actor="agent_a", resource_id=1)
91
-
92
- import mcp_tools_v28 as tools
93
- tools.DEFAULT_AUDIT_DB = self.db_path
94
-
95
- result = self._run(tools.audit_trail(actor="agent_a"))
96
- assert result["count"] == 1
97
- assert result["events"][0]["actor"] == "agent_a"
98
-
99
- def test_verify_chain_with_events(self):
100
- """Hash chain with events should verify successfully."""
101
- from compliance.audit_db import AuditDB
102
-
103
- db = AuditDB(self.db_path)
104
- db.log_event("memory.created", actor="user", resource_id=1)
105
- db.log_event("memory.recalled", actor="user", resource_id=1)
106
- db.log_event("memory.updated", actor="user", resource_id=1)
107
-
108
- import mcp_tools_v28 as tools
109
- tools.DEFAULT_AUDIT_DB = self.db_path
110
-
111
- result = self._run(tools.audit_trail(verify_chain=True))
112
- assert result["success"] is True
113
- assert result["chain_valid"] is True
114
- assert result["chain_entries"] == 3
115
-
116
- def test_limit_parameter(self):
117
- """Limit parameter should cap returned events."""
118
- from compliance.audit_db import AuditDB
119
-
120
- db = AuditDB(self.db_path)
121
- for i in range(10):
122
- db.log_event("memory.created", actor="user", resource_id=i)
123
-
124
- import mcp_tools_v28 as tools
125
- tools.DEFAULT_AUDIT_DB = self.db_path
126
-
127
- result = self._run(tools.audit_trail(limit=3))
128
- assert result["count"] == 3