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,289 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Compliance retention manager — regulatory retention enforcement.
4
-
5
- Unlike the lifecycle ``retention_policy.py`` (which manages lifecycle-level
6
- policies stored alongside memory.db), this compliance module is the
7
- *regulatory* layer that:
8
-
9
- - Links retention rules to regulatory frameworks (GDPR, EU AI Act, HIPAA).
10
- - Enforces GDPR right-to-erasure (tombstone memory + preserve audit trail).
11
- - Enforces EU AI Act audit retention (10-year minimum for audit records).
12
- - Records every retention action in audit.db for tamper-evident compliance.
13
-
14
- Rules are stored in audit.db (``compliance_retention_rules`` table) so that
15
- the audit database remains the single source of truth for all compliance
16
- configuration and evidence.
17
- """
18
- import hashlib
19
- import json
20
- import logging
21
- import sqlite3
22
- from datetime import datetime, timezone
23
- from typing import Any, Dict, List, Optional
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
- _RULES_TABLE_SQL = """
28
- CREATE TABLE IF NOT EXISTS compliance_retention_rules (
29
- id INTEGER PRIMARY KEY AUTOINCREMENT,
30
- name TEXT NOT NULL,
31
- framework TEXT NOT NULL,
32
- retention_days INTEGER NOT NULL,
33
- action TEXT NOT NULL,
34
- applies_to TEXT NOT NULL,
35
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
36
- )
37
- """
38
-
39
- _AUDIT_EVENTS_TABLE_SQL = """
40
- CREATE TABLE IF NOT EXISTS audit_events (
41
- id INTEGER PRIMARY KEY AUTOINCREMENT,
42
- event_type TEXT NOT NULL,
43
- actor TEXT NOT NULL,
44
- resource_id INTEGER,
45
- details TEXT DEFAULT '{}',
46
- prev_hash TEXT NOT NULL DEFAULT 'genesis',
47
- entry_hash TEXT NOT NULL DEFAULT '',
48
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
49
- )
50
- """
51
-
52
-
53
- def _compute_hash(event_type: str, actor: str, resource_id: Any,
54
- details: str, prev_hash: str, ts: str) -> str:
55
- """Compute a SHA-256 hash for a single audit event."""
56
- payload = f"{event_type}|{actor}|{resource_id}|{details}|{prev_hash}|{ts}"
57
- return hashlib.sha256(payload.encode("utf-8")).hexdigest()
58
-
59
-
60
- class ComplianceRetentionManager:
61
- """Enforces regulatory retention policies across memory and audit DBs.
62
-
63
- Connects to *both* databases:
64
- - ``memory_db_path``: where memories live (tombstoning happens here).
65
- - ``audit_db_path``: where rules and audit events are stored.
66
- """
67
-
68
- def __init__(self, memory_db_path: str, audit_db_path: str):
69
- self._memory_db_path = memory_db_path
70
- self._audit_db_path = audit_db_path
71
- self._ensure_tables()
72
-
73
- # ------------------------------------------------------------------
74
- # Internal helpers
75
- # ------------------------------------------------------------------
76
-
77
- def _connect_audit(self) -> sqlite3.Connection:
78
- conn = sqlite3.connect(self._audit_db_path)
79
- conn.row_factory = sqlite3.Row
80
- return conn
81
-
82
- def _connect_memory(self) -> sqlite3.Connection:
83
- conn = sqlite3.connect(self._memory_db_path)
84
- conn.row_factory = sqlite3.Row
85
- return conn
86
-
87
- def _ensure_tables(self) -> None:
88
- conn = self._connect_audit()
89
- try:
90
- conn.execute(_RULES_TABLE_SQL)
91
- conn.execute(_AUDIT_EVENTS_TABLE_SQL)
92
- conn.commit()
93
- finally:
94
- conn.close()
95
-
96
- def _log_audit_event(self, event_type: str, actor: str,
97
- resource_id: Optional[int],
98
- details: Dict[str, Any]) -> None:
99
- """Append a tamper-evident audit event to audit.db."""
100
- conn = self._connect_audit()
101
- try:
102
- last = conn.execute(
103
- "SELECT entry_hash FROM audit_events ORDER BY id DESC LIMIT 1"
104
- ).fetchone()
105
- prev_hash = last["entry_hash"] if last else "genesis"
106
- ts = datetime.now(timezone.utc).isoformat()
107
- details_json = json.dumps(details, default=str)
108
- entry_hash = _compute_hash(
109
- event_type, actor, resource_id, details_json, prev_hash, ts,
110
- )
111
- conn.execute(
112
- "INSERT INTO audit_events "
113
- "(event_type, actor, resource_id, details, prev_hash, entry_hash, created_at) "
114
- "VALUES (?, ?, ?, ?, ?, ?, ?)",
115
- (event_type, actor, resource_id, details_json, prev_hash,
116
- entry_hash, ts),
117
- )
118
- conn.commit()
119
- finally:
120
- conn.close()
121
-
122
- @staticmethod
123
- def _parse_json(value: Any) -> Any:
124
- if isinstance(value, str):
125
- try:
126
- return json.loads(value)
127
- except (json.JSONDecodeError, TypeError):
128
- return value
129
- return value if value is not None else []
130
-
131
- @staticmethod
132
- def _matches(criteria: Any, mem_tags: Any, mem_project: Optional[str]) -> bool:
133
- """Return True when a rule's ``applies_to`` matches the memory."""
134
- if not isinstance(criteria, dict) or not criteria:
135
- return False
136
- ok = True
137
- if "tags" in criteria:
138
- rule_tags = set(criteria["tags"]) if criteria["tags"] else set()
139
- m_tags = set(mem_tags) if isinstance(mem_tags, list) else set()
140
- if not rule_tags & m_tags:
141
- ok = False
142
- if "project_name" in criteria:
143
- if mem_project != criteria["project_name"]:
144
- ok = False
145
- return ok
146
-
147
- # ------------------------------------------------------------------
148
- # Public API
149
- # ------------------------------------------------------------------
150
-
151
- def create_retention_rule(self, name: str, framework: str,
152
- retention_days: int, action: str,
153
- applies_to: Dict[str, Any]) -> int:
154
- """Create a compliance retention rule in audit.db.
155
-
156
- Returns the auto-generated rule ID.
157
- """
158
- conn = self._connect_audit()
159
- try:
160
- cur = conn.execute(
161
- "INSERT INTO compliance_retention_rules "
162
- "(name, framework, retention_days, action, applies_to) "
163
- "VALUES (?, ?, ?, ?, ?)",
164
- (name, framework, retention_days, action,
165
- json.dumps(applies_to)),
166
- )
167
- conn.commit()
168
- rule_id = cur.lastrowid
169
- finally:
170
- conn.close()
171
-
172
- self._log_audit_event(
173
- "retention.rule_created", "system", rule_id,
174
- {"name": name, "framework": framework},
175
- )
176
- return rule_id
177
-
178
- def list_rules(self) -> List[Dict[str, Any]]:
179
- """Return all compliance retention rules."""
180
- conn = self._connect_audit()
181
- try:
182
- rows = conn.execute(
183
- "SELECT * FROM compliance_retention_rules ORDER BY id"
184
- ).fetchall()
185
- result = []
186
- for r in rows:
187
- d = dict(r)
188
- if isinstance(d.get("applies_to"), str):
189
- d["applies_to"] = self._parse_json(d["applies_to"])
190
- result.append(d)
191
- return result
192
- finally:
193
- conn.close()
194
-
195
- def evaluate_memory(self, memory_id: int) -> Optional[Dict[str, Any]]:
196
- """Check which compliance rule applies to a memory.
197
-
198
- Reads the memory's tags/project from memory.db, then evaluates
199
- all rules from audit.db. The first matching rule (ordered by id)
200
- is returned.
201
-
202
- Returns a dict with ``rule_name``, ``action``, ``retention_days``,
203
- ``framework``; or ``None`` if no rule matches.
204
- """
205
- mem_conn = self._connect_memory()
206
- try:
207
- mem = mem_conn.execute(
208
- "SELECT tags, project_name FROM memories WHERE id = ?",
209
- (memory_id,),
210
- ).fetchone()
211
- if mem is None:
212
- return None
213
- mem_tags = self._parse_json(mem["tags"])
214
- mem_project = mem["project_name"]
215
- finally:
216
- mem_conn.close()
217
-
218
- audit_conn = self._connect_audit()
219
- try:
220
- rules = audit_conn.execute(
221
- "SELECT * FROM compliance_retention_rules ORDER BY id"
222
- ).fetchall()
223
- for rule in rules:
224
- criteria = self._parse_json(rule["applies_to"])
225
- if self._matches(criteria, mem_tags, mem_project):
226
- return {
227
- "rule_name": rule["name"],
228
- "action": rule["action"],
229
- "retention_days": rule["retention_days"],
230
- "framework": rule["framework"],
231
- }
232
- return None
233
- finally:
234
- audit_conn.close()
235
-
236
- def execute_erasure_request(self, memory_id: int, framework: str,
237
- requested_by: str) -> Dict[str, Any]:
238
- """Execute a GDPR (or other framework) right-to-erasure request.
239
-
240
- 1. Tombstones the memory in memory.db.
241
- 2. Logs the erasure event in audit.db (preserving the audit trail).
242
-
243
- Returns a result dict with ``success``, ``action``, and ``memory_id``.
244
- """
245
- mem_conn = self._connect_memory()
246
- try:
247
- row = mem_conn.execute(
248
- "SELECT id FROM memories WHERE id = ?", (memory_id,),
249
- ).fetchone()
250
- if row is None:
251
- return {"success": False, "error": "memory_not_found",
252
- "memory_id": memory_id}
253
-
254
- ts = datetime.now(timezone.utc).isoformat()
255
- mem_conn.execute(
256
- "UPDATE memories SET lifecycle_state = 'tombstoned', "
257
- "lifecycle_updated_at = ? WHERE id = ?",
258
- (ts, memory_id),
259
- )
260
- mem_conn.commit()
261
- finally:
262
- mem_conn.close()
263
-
264
- self._log_audit_event(
265
- "retention.erasure", requested_by, memory_id,
266
- {"framework": framework, "action": "tombstoned"},
267
- )
268
-
269
- return {"success": True, "action": "tombstoned",
270
- "memory_id": memory_id}
271
-
272
- def get_compliance_status(self) -> Dict[str, Any]:
273
- """Return a summary of current compliance retention state."""
274
- conn = self._connect_audit()
275
- try:
276
- rules = conn.execute(
277
- "SELECT * FROM compliance_retention_rules"
278
- ).fetchall()
279
- frameworks = list({r["framework"] for r in rules})
280
- events_count = conn.execute(
281
- "SELECT COUNT(*) AS cnt FROM audit_events"
282
- ).fetchone()["cnt"]
283
- return {
284
- "rules_count": len(rules),
285
- "frameworks": sorted(frameworks),
286
- "audit_events_count": events_count,
287
- }
288
- finally:
289
- conn.close()
@@ -1,186 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Background scheduler for periodic retention policy enforcement.
4
-
5
- Runs on a configurable interval (default: 24 hours) to:
6
- 1. Load compliance retention rules from audit.db
7
- 2. Scan all memories in memory.db against those rules
8
- 3. Tombstone expired memories (age exceeds retention_days)
9
- 4. Log every action to audit.db for tamper-evident compliance
10
-
11
- Uses daemon threading -- does not prevent process exit.
12
- """
13
- import json
14
- import logging
15
- import sqlite3
16
- import threading
17
- from datetime import datetime, timezone
18
- from typing import Any, Dict, List, Optional
19
-
20
- from .retention_manager import ComplianceRetentionManager
21
-
22
- logger = logging.getLogger(__name__)
23
-
24
- # Default interval: 24 hours
25
- DEFAULT_INTERVAL_SECONDS = 86400
26
-
27
-
28
- class RetentionScheduler:
29
- """Background scheduler for periodic retention policy enforcement.
30
-
31
- Orchestrates ComplianceRetentionManager on a configurable timer
32
- interval to automatically enforce retention rules.
33
- """
34
-
35
- def __init__(
36
- self,
37
- memory_db_path: str,
38
- audit_db_path: str,
39
- interval_seconds: int = DEFAULT_INTERVAL_SECONDS,
40
- ):
41
- self._memory_db_path = memory_db_path
42
- self._audit_db_path = audit_db_path
43
- self.interval_seconds = interval_seconds
44
-
45
- self._manager = ComplianceRetentionManager(
46
- memory_db_path, audit_db_path,
47
- )
48
-
49
- self._timer: Optional[threading.Timer] = None
50
- self._running = False
51
- self._lock = threading.Lock()
52
-
53
- @property
54
- def is_running(self) -> bool:
55
- """Whether the scheduler is currently running."""
56
- return self._running
57
-
58
- def start(self) -> None:
59
- """Start the background scheduler."""
60
- with self._lock:
61
- if self._running:
62
- return
63
- self._running = True
64
- self._schedule_next()
65
-
66
- def stop(self) -> None:
67
- """Stop the background scheduler."""
68
- with self._lock:
69
- self._running = False
70
- if self._timer is not None:
71
- self._timer.cancel()
72
- self._timer = None
73
-
74
- def run_now(self) -> Dict[str, Any]:
75
- """Execute a retention enforcement cycle immediately.
76
-
77
- Returns:
78
- Dict with timestamp, actions taken, and rules evaluated.
79
- """
80
- return self._execute_cycle()
81
-
82
- def _schedule_next(self) -> None:
83
- """Schedule the next enforcement cycle."""
84
- self._timer = threading.Timer(self.interval_seconds, self._run_cycle)
85
- self._timer.daemon = True
86
- self._timer.start()
87
-
88
- def _run_cycle(self) -> None:
89
- """Run one enforcement cycle, then schedule the next."""
90
- try:
91
- self._execute_cycle()
92
- except Exception:
93
- pass # Scheduler must not crash
94
- finally:
95
- with self._lock:
96
- if self._running:
97
- self._schedule_next()
98
-
99
- def _execute_cycle(self) -> Dict[str, Any]:
100
- """Core retention enforcement logic.
101
-
102
- 1. Load all retention rules from audit.db
103
- 2. Scan every memory against each rule
104
- 3. Tombstone memories that exceed retention_days
105
- 4. Log actions to audit.db
106
- """
107
- rules = self._manager.list_rules()
108
- actions: List[Dict[str, Any]] = []
109
-
110
- # Scan all memories
111
- memory_ids = self._get_all_memory_ids()
112
-
113
- for mem_id in memory_ids:
114
- mem = self._get_memory(mem_id)
115
- if mem is None:
116
- continue
117
-
118
- # Already tombstoned -- skip
119
- if mem.get("lifecycle_state") == "tombstoned":
120
- continue
121
-
122
- match = self._manager.evaluate_memory(mem_id)
123
- if match is None:
124
- continue
125
-
126
- # Check if memory age exceeds the rule's retention_days
127
- created_at = mem.get("created_at")
128
- if created_at is None:
129
- continue
130
-
131
- age_days = self._age_in_days(created_at)
132
- if age_days > match["retention_days"]:
133
- action = match["action"]
134
- if action == "tombstone":
135
- result = self._manager.execute_erasure_request(
136
- mem_id, match["framework"], "retention_scheduler",
137
- )
138
- actions.append({
139
- "memory_id": mem_id,
140
- "action": action,
141
- "rule_name": match["rule_name"],
142
- "framework": match["framework"],
143
- "age_days": age_days,
144
- "success": result.get("success", False),
145
- })
146
-
147
- return {
148
- "timestamp": datetime.now(timezone.utc).isoformat(),
149
- "actions": actions,
150
- "rules_evaluated": len(rules),
151
- }
152
-
153
- # ------------------------------------------------------------------
154
- # Internal helpers
155
- # ------------------------------------------------------------------
156
-
157
- def _get_all_memory_ids(self) -> List[int]:
158
- """Return all memory IDs from memory.db."""
159
- conn = sqlite3.connect(self._memory_db_path)
160
- try:
161
- rows = conn.execute("SELECT id FROM memories").fetchall()
162
- return [r[0] for r in rows]
163
- finally:
164
- conn.close()
165
-
166
- def _get_memory(self, memory_id: int) -> Optional[Dict[str, Any]]:
167
- """Fetch a single memory row as a dict."""
168
- conn = sqlite3.connect(self._memory_db_path)
169
- conn.row_factory = sqlite3.Row
170
- try:
171
- row = conn.execute(
172
- "SELECT * FROM memories WHERE id = ?", (memory_id,),
173
- ).fetchone()
174
- return dict(row) if row else None
175
- finally:
176
- conn.close()
177
-
178
- @staticmethod
179
- def _age_in_days(created_at_str: str) -> float:
180
- """Calculate age of a memory in days from its created_at."""
181
- try:
182
- created = datetime.fromisoformat(created_at_str)
183
- now = datetime.now(created.tzinfo)
184
- return (now - created).total_seconds() / 86400
185
- except (ValueError, TypeError):
186
- return 0.0
@@ -1,4 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for compliance engine.
4
- """
@@ -1,95 +0,0 @@
1
- # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
3
- """Tests for ABAC enforcement in memory operations.
4
- """
5
- import sqlite3
6
- import tempfile
7
- import os
8
- import sys
9
- import json
10
- import shutil
11
- from pathlib import Path
12
-
13
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
14
-
15
-
16
- class TestABACEnforcement:
17
- def setup_method(self):
18
- self.tmp_dir = tempfile.mkdtemp()
19
- self.db_path = os.path.join(self.tmp_dir, "memory.db")
20
- # Create store with test data
21
- from memory_store_v2 import MemoryStoreV2
22
- self.store = MemoryStoreV2(self.db_path)
23
- self.store.add_memory(
24
- content="public memory about Python",
25
- tags=["python"],
26
- importance=5,
27
- )
28
- self.store.add_memory(
29
- content="private memory about secrets",
30
- tags=["secrets"],
31
- importance=8,
32
- )
33
- # Set access_level for private memory
34
- conn = sqlite3.connect(self.db_path)
35
- conn.execute("UPDATE memories SET access_level='private' WHERE id=2")
36
- conn.commit()
37
- conn.close()
38
- self.store._rebuild_vectors()
39
-
40
- def teardown_method(self):
41
- shutil.rmtree(self.tmp_dir, ignore_errors=True)
42
-
43
- def test_search_without_abac_works(self):
44
- """Search without ABAC context works (backward compat)."""
45
- results = self.store.search("Python", limit=5)
46
- assert len(results) >= 1
47
-
48
- def test_search_with_agent_context(self):
49
- """Search with agent_context parameter works."""
50
- results = self.store.search(
51
- "memory", limit=10, agent_context={"agent_id": "user"}
52
- )
53
- assert isinstance(results, list)
54
-
55
- def test_create_without_abac_works(self):
56
- """Create without ABAC works (backward compat)."""
57
- mem_id = self.store.add_memory(content="new memory", tags=["test"])
58
- assert mem_id is not None
59
-
60
- def test_abac_check_method_exists(self):
61
- """MemoryStoreV2 has _check_abac method."""
62
- assert hasattr(self.store, "_check_abac")
63
-
64
- def test_check_abac_default_allows(self):
65
- """Default ABAC check (no policy file) allows everything."""
66
- result = self.store._check_abac(
67
- subject={"agent_id": "user"},
68
- resource={"access_level": "public"},
69
- action="read",
70
- )
71
- assert result["allowed"] is True
72
-
73
- def test_check_abac_with_policy(self):
74
- """ABAC check with policy file respects deny rules."""
75
- policy_path = os.path.join(self.tmp_dir, "abac_policies.json")
76
- with open(policy_path, "w") as f:
77
- json.dump(
78
- [
79
- {
80
- "name": "deny-private",
81
- "effect": "deny",
82
- "subjects": {"agent_id": "*"},
83
- "resources": {"access_level": "private"},
84
- "actions": ["read"],
85
- }
86
- ],
87
- f,
88
- )
89
- result = self.store._check_abac(
90
- subject={"agent_id": "bot"},
91
- resource={"access_level": "private"},
92
- action="read",
93
- policy_path=policy_path,
94
- )
95
- assert result["allowed"] is False