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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +9 -1
- package/NOTICE +63 -0
- package/README.md +165 -480
- package/bin/slm +17 -449
- package/bin/slm-npm +2 -2
- package/bin/slm.bat +4 -2
- package/conftest.py +5 -0
- package/docs/api-reference.md +284 -0
- package/docs/architecture.md +149 -0
- package/docs/auto-memory.md +150 -0
- package/docs/cli-reference.md +276 -0
- package/docs/compliance.md +191 -0
- package/docs/configuration.md +182 -0
- package/docs/getting-started.md +102 -0
- package/docs/ide-setup.md +261 -0
- package/docs/mcp-tools.md +220 -0
- package/docs/migration-from-v2.md +170 -0
- package/docs/profiles.md +173 -0
- package/docs/troubleshooting.md +310 -0
- package/{configs → ide/configs}/antigravity-mcp.json +3 -3
- package/ide/configs/chatgpt-desktop-mcp.json +16 -0
- package/{configs → ide/configs}/claude-desktop-mcp.json +3 -3
- package/{configs → ide/configs}/codex-mcp.toml +4 -4
- package/{configs → ide/configs}/continue-mcp.yaml +4 -3
- package/{configs → ide/configs}/continue-skills.yaml +6 -6
- package/ide/configs/cursor-mcp.json +15 -0
- package/{configs → ide/configs}/gemini-cli-mcp.json +2 -2
- package/{configs → ide/configs}/jetbrains-mcp.json +2 -2
- package/{configs → ide/configs}/opencode-mcp.json +2 -2
- package/{configs → ide/configs}/perplexity-mcp.json +2 -2
- package/{configs → ide/configs}/vscode-copilot-mcp.json +2 -2
- package/{configs → ide/configs}/windsurf-mcp.json +3 -3
- package/{configs → ide/configs}/zed-mcp.json +2 -2
- package/{hooks → ide/hooks}/context-hook.js +9 -20
- package/ide/hooks/memory-list-skill.js +70 -0
- package/ide/hooks/memory-profile-skill.js +101 -0
- package/ide/hooks/memory-recall-skill.js +62 -0
- package/ide/hooks/memory-remember-skill.js +68 -0
- package/ide/hooks/memory-reset-skill.js +160 -0
- package/{hooks → ide/hooks}/post-recall-hook.js +2 -2
- package/ide/integrations/langchain/README.md +106 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +9 -0
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +201 -0
- package/ide/integrations/langchain/pyproject.toml +38 -0
- package/{src/learning → ide/integrations/langchain}/tests/__init__.py +1 -0
- package/ide/integrations/langchain/tests/test_chat_message_history.py +215 -0
- package/ide/integrations/langchain/tests/test_security.py +117 -0
- package/ide/integrations/llamaindex/README.md +81 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +9 -0
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +316 -0
- package/ide/integrations/llamaindex/pyproject.toml +43 -0
- package/{src/lifecycle → ide/integrations/llamaindex}/tests/__init__.py +1 -2
- package/ide/integrations/llamaindex/tests/test_chat_store.py +294 -0
- package/ide/integrations/llamaindex/tests/test_security.py +241 -0
- package/{skills → ide/skills}/slm-build-graph/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-list-recent/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-recall/SKILL.md +5 -5
- package/{skills → ide/skills}/slm-remember/SKILL.md +6 -6
- package/{skills → ide/skills}/slm-show-patterns/SKILL.md +7 -7
- package/{skills → ide/skills}/slm-status/SKILL.md +9 -9
- package/{skills → ide/skills}/slm-switch-profile/SKILL.md +9 -9
- package/package.json +13 -22
- package/pyproject.toml +85 -0
- package/scripts/build-dmg.sh +417 -0
- package/scripts/install-skills.ps1 +334 -0
- package/{install.ps1 → scripts/install.ps1} +36 -4
- package/{install.sh → scripts/install.sh} +14 -13
- package/scripts/postinstall.js +2 -2
- package/scripts/start-dashboard.ps1 +52 -0
- package/scripts/start-dashboard.sh +41 -0
- package/scripts/sync-wiki.ps1 +127 -0
- package/scripts/sync-wiki.sh +82 -0
- package/scripts/test-dmg.sh +161 -0
- package/scripts/test-npm-package.ps1 +252 -0
- package/scripts/test-npm-package.sh +207 -0
- package/scripts/verify-install.ps1 +294 -0
- package/scripts/verify-install.sh +266 -0
- package/src/superlocalmemory/__init__.py +0 -0
- package/src/superlocalmemory/attribution/__init__.py +9 -0
- package/src/superlocalmemory/attribution/mathematical_dna.py +235 -0
- package/src/superlocalmemory/attribution/signer.py +153 -0
- package/src/superlocalmemory/attribution/watermark.py +189 -0
- package/src/superlocalmemory/cli/__init__.py +5 -0
- package/src/superlocalmemory/cli/commands.py +245 -0
- package/src/superlocalmemory/cli/main.py +89 -0
- package/src/superlocalmemory/cli/migrate_cmd.py +55 -0
- package/src/superlocalmemory/cli/post_install.py +99 -0
- package/src/superlocalmemory/cli/setup_wizard.py +129 -0
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +204 -0
- package/src/superlocalmemory/compliance/audit.py +314 -0
- package/src/superlocalmemory/compliance/eu_ai_act.py +131 -0
- package/src/superlocalmemory/compliance/gdpr.py +294 -0
- package/src/superlocalmemory/compliance/lifecycle.py +158 -0
- package/src/superlocalmemory/compliance/retention.py +232 -0
- package/src/superlocalmemory/compliance/scheduler.py +148 -0
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/config.py +391 -0
- package/src/superlocalmemory/core/embeddings.py +293 -0
- package/src/superlocalmemory/core/engine.py +701 -0
- package/src/superlocalmemory/core/hooks.py +65 -0
- package/src/superlocalmemory/core/maintenance.py +172 -0
- package/src/superlocalmemory/core/modes.py +140 -0
- package/src/superlocalmemory/core/profiles.py +234 -0
- package/src/superlocalmemory/core/registry.py +117 -0
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +223 -0
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/consolidator.py +485 -0
- package/src/superlocalmemory/encoding/emotional.py +125 -0
- package/src/superlocalmemory/encoding/entity_resolver.py +525 -0
- package/src/superlocalmemory/encoding/entropy_gate.py +104 -0
- package/src/superlocalmemory/encoding/fact_extractor.py +775 -0
- package/src/superlocalmemory/encoding/foresight.py +91 -0
- package/src/superlocalmemory/encoding/graph_builder.py +302 -0
- package/src/superlocalmemory/encoding/observation_builder.py +160 -0
- package/src/superlocalmemory/encoding/scene_builder.py +183 -0
- package/src/superlocalmemory/encoding/signal_inference.py +90 -0
- package/src/superlocalmemory/encoding/temporal_parser.py +426 -0
- package/src/superlocalmemory/encoding/type_router.py +235 -0
- package/src/superlocalmemory/hooks/__init__.py +3 -0
- package/src/superlocalmemory/hooks/auto_capture.py +111 -0
- package/src/superlocalmemory/hooks/auto_recall.py +93 -0
- package/src/superlocalmemory/hooks/ide_connector.py +204 -0
- package/src/superlocalmemory/hooks/rules_engine.py +99 -0
- package/src/superlocalmemory/infra/__init__.py +3 -0
- package/src/superlocalmemory/infra/auth_middleware.py +82 -0
- package/src/superlocalmemory/infra/backup.py +317 -0
- package/src/superlocalmemory/infra/cache_manager.py +267 -0
- package/src/superlocalmemory/infra/event_bus.py +381 -0
- package/src/superlocalmemory/infra/rate_limiter.py +135 -0
- package/src/{webhook_dispatcher.py → superlocalmemory/infra/webhook_dispatcher.py} +104 -101
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +172 -0
- package/src/superlocalmemory/learning/behavioral.py +490 -0
- package/src/superlocalmemory/learning/behavioral_listener.py +94 -0
- package/src/superlocalmemory/learning/bootstrap.py +298 -0
- package/src/superlocalmemory/learning/cross_project.py +399 -0
- package/src/superlocalmemory/learning/database.py +376 -0
- package/src/superlocalmemory/learning/engagement.py +323 -0
- package/src/superlocalmemory/learning/features.py +138 -0
- package/src/superlocalmemory/learning/feedback.py +316 -0
- package/src/superlocalmemory/learning/outcomes.py +255 -0
- package/src/superlocalmemory/learning/project_context.py +366 -0
- package/src/superlocalmemory/learning/ranker.py +155 -0
- package/src/superlocalmemory/learning/source_quality.py +303 -0
- package/src/superlocalmemory/learning/workflows.py +309 -0
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +316 -0
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/fisher.py +356 -0
- package/src/superlocalmemory/math/langevin.py +398 -0
- package/src/superlocalmemory/math/sheaf.py +257 -0
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/resources.py +245 -0
- package/src/superlocalmemory/mcp/server.py +61 -0
- package/src/superlocalmemory/mcp/tools.py +18 -0
- package/src/superlocalmemory/mcp/tools_core.py +305 -0
- package/src/superlocalmemory/mcp/tools_v28.py +223 -0
- package/src/superlocalmemory/mcp/tools_v3.py +286 -0
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +295 -0
- package/src/superlocalmemory/retrieval/ann_index.py +223 -0
- package/src/superlocalmemory/retrieval/bm25_channel.py +185 -0
- package/src/superlocalmemory/retrieval/bridge_discovery.py +170 -0
- package/src/superlocalmemory/retrieval/engine.py +390 -0
- package/src/superlocalmemory/retrieval/entity_channel.py +179 -0
- package/src/superlocalmemory/retrieval/fusion.py +78 -0
- package/src/superlocalmemory/retrieval/profile_channel.py +105 -0
- package/src/superlocalmemory/retrieval/reranker.py +154 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +232 -0
- package/src/superlocalmemory/retrieval/strategy.py +96 -0
- package/src/superlocalmemory/retrieval/temporal_channel.py +175 -0
- package/src/superlocalmemory/server/__init__.py +1 -0
- package/src/superlocalmemory/server/api.py +248 -0
- package/src/superlocalmemory/server/routes/__init__.py +4 -0
- package/src/superlocalmemory/server/routes/agents.py +107 -0
- package/src/superlocalmemory/server/routes/backup.py +91 -0
- package/src/superlocalmemory/server/routes/behavioral.py +127 -0
- package/src/superlocalmemory/server/routes/compliance.py +160 -0
- package/src/superlocalmemory/server/routes/data_io.py +188 -0
- package/src/superlocalmemory/server/routes/events.py +183 -0
- package/src/superlocalmemory/server/routes/helpers.py +85 -0
- package/src/superlocalmemory/server/routes/learning.py +273 -0
- package/src/superlocalmemory/server/routes/lifecycle.py +116 -0
- package/src/superlocalmemory/server/routes/memories.py +399 -0
- package/src/superlocalmemory/server/routes/profiles.py +219 -0
- package/src/superlocalmemory/server/routes/stats.py +346 -0
- package/src/superlocalmemory/server/routes/v3_api.py +365 -0
- package/src/superlocalmemory/server/routes/ws.py +82 -0
- package/src/superlocalmemory/server/security_middleware.py +57 -0
- package/src/superlocalmemory/server/ui.py +245 -0
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/access_control.py +182 -0
- package/src/superlocalmemory/storage/database.py +594 -0
- package/src/superlocalmemory/storage/migrations.py +303 -0
- package/src/superlocalmemory/storage/models.py +406 -0
- package/src/superlocalmemory/storage/schema.py +726 -0
- package/src/superlocalmemory/storage/v2_migrator.py +317 -0
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +130 -0
- package/src/superlocalmemory/trust/provenance.py +124 -0
- package/src/superlocalmemory/trust/scorer.py +347 -0
- package/src/superlocalmemory/trust/signals.py +153 -0
- package/ui/index.html +278 -5
- package/ui/js/auto-settings.js +70 -0
- package/ui/js/dashboard.js +90 -0
- package/ui/js/fact-detail.js +92 -0
- package/ui/js/feedback.js +2 -2
- package/ui/js/ide-status.js +102 -0
- package/ui/js/math-health.js +98 -0
- package/ui/js/recall-lab.js +127 -0
- package/ui/js/settings.js +2 -2
- package/ui/js/trust-dashboard.js +73 -0
- package/api_server.py +0 -724
- package/bin/aider-smart +0 -72
- package/bin/superlocalmemoryv2-learning +0 -4
- package/bin/superlocalmemoryv2-list +0 -3
- package/bin/superlocalmemoryv2-patterns +0 -4
- package/bin/superlocalmemoryv2-profile +0 -3
- package/bin/superlocalmemoryv2-recall +0 -3
- package/bin/superlocalmemoryv2-remember +0 -3
- package/bin/superlocalmemoryv2-reset +0 -3
- package/bin/superlocalmemoryv2-status +0 -3
- package/configs/chatgpt-desktop-mcp.json +0 -16
- package/configs/cursor-mcp.json +0 -15
- package/docs/SECURITY-QUICK-REFERENCE.md +0 -214
- package/hooks/memory-list-skill.js +0 -139
- package/hooks/memory-profile-skill.js +0 -273
- package/hooks/memory-recall-skill.js +0 -114
- package/hooks/memory-remember-skill.js +0 -127
- package/hooks/memory-reset-skill.js +0 -274
- package/mcp_server.py +0 -1800
- package/requirements-core.txt +0 -22
- package/requirements-learning.txt +0 -12
- package/requirements.txt +0 -12
- package/src/agent_registry.py +0 -411
- package/src/auth_middleware.py +0 -61
- package/src/auto_backup.py +0 -459
- package/src/behavioral/__init__.py +0 -49
- package/src/behavioral/behavioral_listener.py +0 -203
- package/src/behavioral/behavioral_patterns.py +0 -275
- package/src/behavioral/cross_project_transfer.py +0 -206
- package/src/behavioral/outcome_inference.py +0 -194
- package/src/behavioral/outcome_tracker.py +0 -193
- package/src/behavioral/tests/__init__.py +0 -4
- package/src/behavioral/tests/test_behavioral_integration.py +0 -108
- package/src/behavioral/tests/test_behavioral_patterns.py +0 -150
- package/src/behavioral/tests/test_cross_project_transfer.py +0 -142
- package/src/behavioral/tests/test_mcp_behavioral.py +0 -139
- package/src/behavioral/tests/test_mcp_report_outcome.py +0 -117
- package/src/behavioral/tests/test_outcome_inference.py +0 -107
- package/src/behavioral/tests/test_outcome_tracker.py +0 -96
- package/src/cache_manager.py +0 -518
- package/src/compliance/__init__.py +0 -48
- package/src/compliance/abac_engine.py +0 -149
- package/src/compliance/abac_middleware.py +0 -116
- package/src/compliance/audit_db.py +0 -215
- package/src/compliance/audit_logger.py +0 -148
- package/src/compliance/retention_manager.py +0 -289
- package/src/compliance/retention_scheduler.py +0 -186
- package/src/compliance/tests/__init__.py +0 -4
- package/src/compliance/tests/test_abac_enforcement.py +0 -95
- package/src/compliance/tests/test_abac_engine.py +0 -124
- package/src/compliance/tests/test_abac_mcp_integration.py +0 -118
- package/src/compliance/tests/test_audit_db.py +0 -123
- package/src/compliance/tests/test_audit_logger.py +0 -98
- package/src/compliance/tests/test_mcp_audit.py +0 -128
- package/src/compliance/tests/test_mcp_retention_policy.py +0 -125
- package/src/compliance/tests/test_retention_manager.py +0 -131
- package/src/compliance/tests/test_retention_scheduler.py +0 -99
- package/src/compression/__init__.py +0 -25
- package/src/compression/cli.py +0 -150
- package/src/compression/cold_storage.py +0 -217
- package/src/compression/config.py +0 -72
- package/src/compression/orchestrator.py +0 -133
- package/src/compression/tier2_compressor.py +0 -228
- package/src/compression/tier3_compressor.py +0 -153
- package/src/compression/tier_classifier.py +0 -148
- package/src/db_connection_manager.py +0 -536
- package/src/embedding_engine.py +0 -63
- package/src/embeddings/__init__.py +0 -47
- package/src/embeddings/cache.py +0 -70
- package/src/embeddings/cli.py +0 -113
- package/src/embeddings/constants.py +0 -47
- package/src/embeddings/database.py +0 -91
- package/src/embeddings/engine.py +0 -247
- package/src/embeddings/model_loader.py +0 -145
- package/src/event_bus.py +0 -562
- package/src/graph/__init__.py +0 -36
- package/src/graph/build_helpers.py +0 -74
- package/src/graph/cli.py +0 -87
- package/src/graph/cluster_builder.py +0 -188
- package/src/graph/cluster_summary.py +0 -148
- package/src/graph/constants.py +0 -47
- package/src/graph/edge_builder.py +0 -162
- package/src/graph/entity_extractor.py +0 -95
- package/src/graph/graph_core.py +0 -226
- package/src/graph/graph_search.py +0 -231
- package/src/graph/hierarchical.py +0 -207
- package/src/graph/schema.py +0 -99
- package/src/graph_engine.py +0 -52
- package/src/hnsw_index.py +0 -628
- package/src/hybrid_search.py +0 -46
- package/src/learning/__init__.py +0 -217
- package/src/learning/adaptive_ranker.py +0 -682
- package/src/learning/bootstrap/__init__.py +0 -69
- package/src/learning/bootstrap/constants.py +0 -93
- package/src/learning/bootstrap/db_queries.py +0 -316
- package/src/learning/bootstrap/sampling.py +0 -82
- package/src/learning/bootstrap/text_utils.py +0 -71
- package/src/learning/cross_project_aggregator.py +0 -857
- package/src/learning/db/__init__.py +0 -40
- package/src/learning/db/constants.py +0 -44
- package/src/learning/db/schema.py +0 -279
- package/src/learning/engagement_tracker.py +0 -628
- package/src/learning/feature_extractor.py +0 -708
- package/src/learning/feedback_collector.py +0 -806
- package/src/learning/learning_db.py +0 -915
- package/src/learning/project_context_manager.py +0 -572
- package/src/learning/ranking/__init__.py +0 -33
- package/src/learning/ranking/constants.py +0 -84
- package/src/learning/ranking/helpers.py +0 -278
- package/src/learning/source_quality_scorer.py +0 -676
- package/src/learning/synthetic_bootstrap.py +0 -755
- package/src/learning/tests/test_adaptive_ranker.py +0 -325
- package/src/learning/tests/test_adaptive_ranker_v28.py +0 -60
- package/src/learning/tests/test_aggregator.py +0 -306
- package/src/learning/tests/test_auto_retrain_v28.py +0 -35
- package/src/learning/tests/test_e2e_ranking_v28.py +0 -82
- package/src/learning/tests/test_feature_extractor_v28.py +0 -93
- package/src/learning/tests/test_feedback_collector.py +0 -294
- package/src/learning/tests/test_learning_db.py +0 -602
- package/src/learning/tests/test_learning_db_v28.py +0 -110
- package/src/learning/tests/test_learning_init_v28.py +0 -48
- package/src/learning/tests/test_outcome_signals.py +0 -48
- package/src/learning/tests/test_project_context.py +0 -292
- package/src/learning/tests/test_schema_migration.py +0 -319
- package/src/learning/tests/test_signal_inference.py +0 -397
- package/src/learning/tests/test_source_quality.py +0 -351
- package/src/learning/tests/test_synthetic_bootstrap.py +0 -429
- package/src/learning/tests/test_workflow_miner.py +0 -318
- package/src/learning/workflow_pattern_miner.py +0 -655
- package/src/lifecycle/__init__.py +0 -54
- package/src/lifecycle/bounded_growth.py +0 -239
- package/src/lifecycle/compaction_engine.py +0 -226
- package/src/lifecycle/lifecycle_engine.py +0 -355
- package/src/lifecycle/lifecycle_evaluator.py +0 -257
- package/src/lifecycle/lifecycle_scheduler.py +0 -130
- package/src/lifecycle/retention_policy.py +0 -285
- package/src/lifecycle/tests/test_bounded_growth.py +0 -193
- package/src/lifecycle/tests/test_compaction.py +0 -179
- package/src/lifecycle/tests/test_lifecycle_engine.py +0 -137
- package/src/lifecycle/tests/test_lifecycle_evaluation.py +0 -177
- package/src/lifecycle/tests/test_lifecycle_scheduler.py +0 -127
- package/src/lifecycle/tests/test_lifecycle_search.py +0 -109
- package/src/lifecycle/tests/test_mcp_compact.py +0 -149
- package/src/lifecycle/tests/test_mcp_lifecycle_status.py +0 -114
- package/src/lifecycle/tests/test_retention_policy.py +0 -162
- package/src/mcp_tools_v28.py +0 -281
- package/src/memory/__init__.py +0 -36
- package/src/memory/cli.py +0 -205
- package/src/memory/constants.py +0 -39
- package/src/memory/helpers.py +0 -28
- package/src/memory/schema.py +0 -166
- package/src/memory-profiles.py +0 -595
- package/src/memory-reset.py +0 -491
- package/src/memory_compression.py +0 -989
- package/src/memory_store_v2.py +0 -1155
- package/src/migrate_v1_to_v2.py +0 -629
- package/src/pattern_learner.py +0 -34
- package/src/patterns/__init__.py +0 -24
- package/src/patterns/analyzers.py +0 -251
- package/src/patterns/learner.py +0 -271
- package/src/patterns/scoring.py +0 -171
- package/src/patterns/store.py +0 -225
- package/src/patterns/terminology.py +0 -140
- package/src/provenance_tracker.py +0 -312
- package/src/qualixar_attribution.py +0 -139
- package/src/qualixar_watermark.py +0 -78
- package/src/query_optimizer.py +0 -511
- package/src/rate_limiter.py +0 -83
- package/src/search/__init__.py +0 -20
- package/src/search/cli.py +0 -77
- package/src/search/constants.py +0 -26
- package/src/search/engine.py +0 -241
- package/src/search/fusion.py +0 -122
- package/src/search/index_loader.py +0 -114
- package/src/search/methods.py +0 -162
- package/src/search_engine_v2.py +0 -401
- package/src/setup_validator.py +0 -482
- package/src/subscription_manager.py +0 -391
- package/src/tree/__init__.py +0 -59
- package/src/tree/builder.py +0 -185
- package/src/tree/nodes.py +0 -202
- package/src/tree/queries.py +0 -257
- package/src/tree/schema.py +0 -80
- package/src/tree_manager.py +0 -19
- package/src/trust/__init__.py +0 -45
- package/src/trust/constants.py +0 -66
- package/src/trust/queries.py +0 -157
- package/src/trust/schema.py +0 -95
- package/src/trust/scorer.py +0 -299
- package/src/trust/signals.py +0 -95
- package/src/trust_scorer.py +0 -44
- package/ui/app.js +0 -1588
- package/ui/js/graph-cytoscape-monolithic-backup.js +0 -1168
- package/ui/js/graph-cytoscape.js +0 -1168
- package/ui/js/graph-d3-backup.js +0 -32
- package/ui/js/graph.js +0 -32
- package/ui_server.py +0 -266
- /package/docs/{ACCESSIBILITY.md → v2-archive/ACCESSIBILITY.md} +0 -0
- /package/docs/{ARCHITECTURE.md → v2-archive/ARCHITECTURE.md} +0 -0
- /package/docs/{CLI-COMMANDS-REFERENCE.md → v2-archive/CLI-COMMANDS-REFERENCE.md} +0 -0
- /package/docs/{COMPRESSION-README.md → v2-archive/COMPRESSION-README.md} +0 -0
- /package/docs/{FRAMEWORK-INTEGRATIONS.md → v2-archive/FRAMEWORK-INTEGRATIONS.md} +0 -0
- /package/docs/{MCP-MANUAL-SETUP.md → v2-archive/MCP-MANUAL-SETUP.md} +0 -0
- /package/docs/{MCP-TROUBLESHOOTING.md → v2-archive/MCP-TROUBLESHOOTING.md} +0 -0
- /package/docs/{PATTERN-LEARNING.md → v2-archive/PATTERN-LEARNING.md} +0 -0
- /package/docs/{PROFILES-GUIDE.md → v2-archive/PROFILES-GUIDE.md} +0 -0
- /package/docs/{RESET-GUIDE.md → v2-archive/RESET-GUIDE.md} +0 -0
- /package/docs/{SEARCH-ENGINE-V2.2.0.md → v2-archive/SEARCH-ENGINE-V2.2.0.md} +0 -0
- /package/docs/{SEARCH-INTEGRATION-GUIDE.md → v2-archive/SEARCH-INTEGRATION-GUIDE.md} +0 -0
- /package/docs/{UI-SERVER.md → v2-archive/UI-SERVER.md} +0 -0
- /package/docs/{UNIVERSAL-INTEGRATION.md → v2-archive/UNIVERSAL-INTEGRATION.md} +0 -0
- /package/docs/{V2.2.0-OPTIONAL-SEARCH.md → v2-archive/V2.2.0-OPTIONAL-SEARCH.md} +0 -0
- /package/docs/{WINDOWS-INSTALL-README.txt → v2-archive/WINDOWS-INSTALL-README.txt} +0 -0
- /package/docs/{WINDOWS-POST-INSTALL.txt → v2-archive/WINDOWS-POST-INSTALL.txt} +0 -0
- /package/docs/{example_graph_usage.py → v2-archive/example_graph_usage.py} +0 -0
- /package/{completions → ide/completions}/slm.bash +0 -0
- /package/{completions → ide/completions}/slm.zsh +0 -0
- /package/{configs → ide/configs}/cody-commands.json +0 -0
- /package/{install-skills.sh → scripts/install-skills.sh} +0 -0
package/src/graph/__init__.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: MIT
|
|
2
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
3
|
-
"""graph package - Knowledge Graph Clustering for SuperLocalMemory V2
|
|
4
|
-
|
|
5
|
-
Re-exports all public classes, constants, and functions so that
|
|
6
|
-
``from graph import GraphEngine`` (or any other symbol) works.
|
|
7
|
-
"""
|
|
8
|
-
from graph.constants import (
|
|
9
|
-
MAX_MEMORIES_FOR_GRAPH,
|
|
10
|
-
SKLEARN_AVAILABLE,
|
|
11
|
-
IGRAPH_AVAILABLE,
|
|
12
|
-
MEMORY_DIR,
|
|
13
|
-
DB_PATH,
|
|
14
|
-
)
|
|
15
|
-
from graph.entity_extractor import EntityExtractor, ClusterNamer
|
|
16
|
-
from graph.edge_builder import EdgeBuilder
|
|
17
|
-
from graph.cluster_builder import ClusterBuilder
|
|
18
|
-
from graph.graph_core import GraphEngine
|
|
19
|
-
from graph.cli import main
|
|
20
|
-
|
|
21
|
-
__all__ = [
|
|
22
|
-
# Constants
|
|
23
|
-
"MAX_MEMORIES_FOR_GRAPH",
|
|
24
|
-
"SKLEARN_AVAILABLE",
|
|
25
|
-
"IGRAPH_AVAILABLE",
|
|
26
|
-
"MEMORY_DIR",
|
|
27
|
-
"DB_PATH",
|
|
28
|
-
# Classes
|
|
29
|
-
"EntityExtractor",
|
|
30
|
-
"ClusterNamer",
|
|
31
|
-
"EdgeBuilder",
|
|
32
|
-
"ClusterBuilder",
|
|
33
|
-
"GraphEngine",
|
|
34
|
-
# Functions
|
|
35
|
-
"main",
|
|
36
|
-
]
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Helper functions for the graph build process.
|
|
5
|
-
|
|
6
|
-
Provides sampling and cleanup utilities used during full graph builds.
|
|
7
|
-
"""
|
|
8
|
-
from graph.constants import logger, MAX_MEMORIES_FOR_GRAPH
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def apply_sampling(cursor, memories, active_profile):
|
|
12
|
-
"""Apply intelligent sampling if memory count exceeds cap.
|
|
13
|
-
|
|
14
|
-
Returns a (possibly truncated) list of memory tuples.
|
|
15
|
-
"""
|
|
16
|
-
if len(memories) > MAX_MEMORIES_FOR_GRAPH:
|
|
17
|
-
logger.warning(
|
|
18
|
-
"Memory count (%d) exceeds graph cap (%d). Using intelligent sampling.",
|
|
19
|
-
len(memories), MAX_MEMORIES_FOR_GRAPH
|
|
20
|
-
)
|
|
21
|
-
recent_count = int(MAX_MEMORIES_FOR_GRAPH * 0.6)
|
|
22
|
-
important_count = int(MAX_MEMORIES_FOR_GRAPH * 0.4)
|
|
23
|
-
|
|
24
|
-
recent_memories = cursor.execute('''
|
|
25
|
-
SELECT id, content, summary FROM memories
|
|
26
|
-
WHERE profile = ? ORDER BY created_at DESC LIMIT ?
|
|
27
|
-
''', (active_profile, recent_count)).fetchall()
|
|
28
|
-
|
|
29
|
-
important_memories = cursor.execute('''
|
|
30
|
-
SELECT id, content, summary FROM memories
|
|
31
|
-
WHERE profile = ? ORDER BY importance DESC, access_count DESC LIMIT ?
|
|
32
|
-
''', (active_profile, important_count)).fetchall()
|
|
33
|
-
|
|
34
|
-
seen_ids = set()
|
|
35
|
-
sampled = []
|
|
36
|
-
for m in recent_memories + important_memories:
|
|
37
|
-
if m[0] not in seen_ids:
|
|
38
|
-
seen_ids.add(m[0])
|
|
39
|
-
sampled.append(m)
|
|
40
|
-
memories = sampled[:MAX_MEMORIES_FOR_GRAPH]
|
|
41
|
-
logger.info("Sampled %d memories for graph build", len(memories))
|
|
42
|
-
|
|
43
|
-
elif len(memories) > MAX_MEMORIES_FOR_GRAPH * 0.8:
|
|
44
|
-
logger.warning(
|
|
45
|
-
"Approaching graph cap: %d/%d memories (%.0f%%). "
|
|
46
|
-
"Consider running memory compression.",
|
|
47
|
-
len(memories), MAX_MEMORIES_FOR_GRAPH,
|
|
48
|
-
len(memories) / MAX_MEMORIES_FOR_GRAPH * 100
|
|
49
|
-
)
|
|
50
|
-
return memories
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def clear_profile_graph_data(cursor, conn, memories, active_profile):
|
|
54
|
-
"""Clear existing graph data for a profile's memories."""
|
|
55
|
-
profile_memory_ids = [m[0] for m in memories]
|
|
56
|
-
if profile_memory_ids:
|
|
57
|
-
placeholders = ','.join('?' * len(profile_memory_ids))
|
|
58
|
-
cursor.execute(f'''
|
|
59
|
-
DELETE FROM graph_edges
|
|
60
|
-
WHERE source_memory_id IN ({placeholders})
|
|
61
|
-
OR target_memory_id IN ({placeholders})
|
|
62
|
-
''', profile_memory_ids + profile_memory_ids)
|
|
63
|
-
cursor.execute(f'''
|
|
64
|
-
DELETE FROM graph_nodes WHERE memory_id IN ({placeholders})
|
|
65
|
-
''', profile_memory_ids)
|
|
66
|
-
cursor.execute('''
|
|
67
|
-
DELETE FROM graph_clusters
|
|
68
|
-
WHERE id NOT IN (
|
|
69
|
-
SELECT DISTINCT cluster_id FROM memories WHERE cluster_id IS NOT NULL
|
|
70
|
-
)
|
|
71
|
-
''')
|
|
72
|
-
cursor.execute('UPDATE memories SET cluster_id = NULL WHERE profile = ?',
|
|
73
|
-
(active_profile,))
|
|
74
|
-
conn.commit()
|
package/src/graph/cli.py
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""CLI interface for manual graph operations.
|
|
5
|
-
|
|
6
|
-
Provides a command-line interface for building graphs, viewing stats,
|
|
7
|
-
finding related memories, inspecting clusters, and generating summaries.
|
|
8
|
-
"""
|
|
9
|
-
import json
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def main():
|
|
13
|
-
"""CLI interface for manual graph operations."""
|
|
14
|
-
import argparse
|
|
15
|
-
from graph.graph_core import GraphEngine
|
|
16
|
-
from graph.cluster_builder import ClusterBuilder
|
|
17
|
-
|
|
18
|
-
parser = argparse.ArgumentParser(description='GraphEngine - Knowledge Graph Management')
|
|
19
|
-
parser.add_argument('command', choices=['build', 'stats', 'related', 'cluster', 'hierarchical', 'summaries'],
|
|
20
|
-
help='Command to execute')
|
|
21
|
-
parser.add_argument('--memory-id', type=int, help='Memory ID for related/add commands')
|
|
22
|
-
parser.add_argument('--cluster-id', type=int, help='Cluster ID for cluster command')
|
|
23
|
-
parser.add_argument('--min-similarity', type=float, default=0.3,
|
|
24
|
-
help='Minimum similarity for edges (default: 0.3)')
|
|
25
|
-
parser.add_argument('--hops', type=int, default=2, help='Max hops for related (default: 2)')
|
|
26
|
-
|
|
27
|
-
args = parser.parse_args()
|
|
28
|
-
|
|
29
|
-
engine = GraphEngine()
|
|
30
|
-
|
|
31
|
-
if args.command == 'build':
|
|
32
|
-
print("Building knowledge graph...")
|
|
33
|
-
stats = engine.build_graph(min_similarity=args.min_similarity)
|
|
34
|
-
print(json.dumps(stats, indent=2))
|
|
35
|
-
|
|
36
|
-
elif args.command == 'stats':
|
|
37
|
-
print("Graph Statistics:")
|
|
38
|
-
stats = engine.get_stats()
|
|
39
|
-
print(json.dumps(stats, indent=2))
|
|
40
|
-
|
|
41
|
-
elif args.command == 'related':
|
|
42
|
-
if not args.memory_id:
|
|
43
|
-
print("Error: --memory-id required for 'related' command")
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
print(f"Finding memories related to #{args.memory_id}...")
|
|
47
|
-
related = engine.get_related(args.memory_id, max_hops=args.hops)
|
|
48
|
-
|
|
49
|
-
if not related:
|
|
50
|
-
print("No related memories found")
|
|
51
|
-
else:
|
|
52
|
-
for idx, mem in enumerate(related, 1):
|
|
53
|
-
print(f"\n{idx}. Memory #{mem['id']} ({mem['hops']}-hop, weight={mem['weight']:.3f})")
|
|
54
|
-
print(f" Relationship: {mem['relationship']}")
|
|
55
|
-
summary = mem['summary'] or '[No summary]'
|
|
56
|
-
print(f" Summary: {summary[:100]}...")
|
|
57
|
-
if mem['shared_entities']:
|
|
58
|
-
print(f" Shared: {', '.join(mem['shared_entities'][:5])}")
|
|
59
|
-
|
|
60
|
-
elif args.command == 'cluster':
|
|
61
|
-
if not args.cluster_id:
|
|
62
|
-
print("Error: --cluster-id required for 'cluster' command")
|
|
63
|
-
return
|
|
64
|
-
|
|
65
|
-
print(f"Cluster #{args.cluster_id} members:")
|
|
66
|
-
members = engine.get_cluster_members(args.cluster_id)
|
|
67
|
-
|
|
68
|
-
for idx, mem in enumerate(members, 1):
|
|
69
|
-
print(f"\n{idx}. Memory #{mem['id']} (importance={mem['importance']})")
|
|
70
|
-
summary = mem['summary'] or '[No summary]'
|
|
71
|
-
print(f" {summary[:100]}...")
|
|
72
|
-
|
|
73
|
-
elif args.command == 'hierarchical':
|
|
74
|
-
print("Running hierarchical sub-clustering...")
|
|
75
|
-
cluster_builder = ClusterBuilder(engine.db_path)
|
|
76
|
-
stats = cluster_builder.hierarchical_cluster()
|
|
77
|
-
print(json.dumps(stats, indent=2))
|
|
78
|
-
|
|
79
|
-
elif args.command == 'summaries':
|
|
80
|
-
print("Generating cluster summaries...")
|
|
81
|
-
cluster_builder = ClusterBuilder(engine.db_path)
|
|
82
|
-
count = cluster_builder.generate_cluster_summaries()
|
|
83
|
-
print(f"Generated summaries for {count} clusters")
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if __name__ == '__main__':
|
|
87
|
-
main()
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Community detection and cluster management for the graph engine.
|
|
5
|
-
|
|
6
|
-
Implements Leiden algorithm based community detection. Hierarchical
|
|
7
|
-
sub-clustering is delegated to the ``hierarchical`` module.
|
|
8
|
-
"""
|
|
9
|
-
import sqlite3
|
|
10
|
-
import json
|
|
11
|
-
from typing import List, Dict
|
|
12
|
-
from collections import Counter
|
|
13
|
-
|
|
14
|
-
from graph.constants import logger, IGRAPH_AVAILABLE, MEMORY_DIR
|
|
15
|
-
from graph.cluster_summary import generate_cluster_summaries as _generate_summaries
|
|
16
|
-
from graph.hierarchical import hierarchical_cluster as _hierarchical_cluster
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ClusterBuilder:
|
|
20
|
-
"""Detect memory communities using Leiden algorithm."""
|
|
21
|
-
|
|
22
|
-
def __init__(self, db_path):
|
|
23
|
-
"""Initialize cluster builder."""
|
|
24
|
-
self.db_path = db_path
|
|
25
|
-
|
|
26
|
-
def _get_active_profile(self) -> str:
|
|
27
|
-
"""Get the currently active profile name from config."""
|
|
28
|
-
config_file = MEMORY_DIR / "profiles.json"
|
|
29
|
-
if config_file.exists():
|
|
30
|
-
try:
|
|
31
|
-
with open(config_file, 'r') as f:
|
|
32
|
-
config = json.load(f)
|
|
33
|
-
return config.get('active_profile', 'default')
|
|
34
|
-
except (json.JSONDecodeError, IOError):
|
|
35
|
-
pass
|
|
36
|
-
return 'default'
|
|
37
|
-
|
|
38
|
-
def detect_communities(self) -> int:
|
|
39
|
-
"""
|
|
40
|
-
Run Leiden algorithm to find memory clusters (active profile only).
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
Number of clusters created
|
|
44
|
-
"""
|
|
45
|
-
if not IGRAPH_AVAILABLE:
|
|
46
|
-
logger.warning("igraph/leidenalg not installed. Graph clustering disabled. Install with: pip3 install python-igraph leidenalg")
|
|
47
|
-
return 0
|
|
48
|
-
import igraph as ig
|
|
49
|
-
import leidenalg
|
|
50
|
-
|
|
51
|
-
conn = sqlite3.connect(self.db_path)
|
|
52
|
-
cursor = conn.cursor()
|
|
53
|
-
active_profile = self._get_active_profile()
|
|
54
|
-
|
|
55
|
-
try:
|
|
56
|
-
# Load edges for active profile's memories only
|
|
57
|
-
edges = cursor.execute('''
|
|
58
|
-
SELECT ge.source_memory_id, ge.target_memory_id, ge.weight
|
|
59
|
-
FROM graph_edges ge
|
|
60
|
-
WHERE ge.source_memory_id IN (SELECT id FROM memories WHERE profile = ?)
|
|
61
|
-
AND ge.target_memory_id IN (SELECT id FROM memories WHERE profile = ?)
|
|
62
|
-
''', (active_profile, active_profile)).fetchall()
|
|
63
|
-
|
|
64
|
-
if not edges:
|
|
65
|
-
logger.warning("No edges found - cannot build clusters")
|
|
66
|
-
return 0
|
|
67
|
-
|
|
68
|
-
# Build memory ID mapping
|
|
69
|
-
memory_ids = set()
|
|
70
|
-
for source, target, _ in edges:
|
|
71
|
-
memory_ids.add(source)
|
|
72
|
-
memory_ids.add(target)
|
|
73
|
-
|
|
74
|
-
memory_ids = sorted(list(memory_ids))
|
|
75
|
-
memory_id_to_vertex = {mid: idx for idx, mid in enumerate(memory_ids)}
|
|
76
|
-
vertex_to_memory_id = {idx: mid for mid, idx in memory_id_to_vertex.items()}
|
|
77
|
-
|
|
78
|
-
# Create igraph graph
|
|
79
|
-
g = ig.Graph()
|
|
80
|
-
g.add_vertices(len(memory_ids))
|
|
81
|
-
|
|
82
|
-
edge_list = []
|
|
83
|
-
edge_weights = []
|
|
84
|
-
for source, target, weight in edges:
|
|
85
|
-
edge_list.append((memory_id_to_vertex[source], memory_id_to_vertex[target]))
|
|
86
|
-
edge_weights.append(weight)
|
|
87
|
-
|
|
88
|
-
g.add_edges(edge_list)
|
|
89
|
-
|
|
90
|
-
# Run Leiden algorithm
|
|
91
|
-
logger.info(f"Running Leiden on {len(memory_ids)} nodes, {len(edges)} edges")
|
|
92
|
-
partition = leidenalg.find_partition(
|
|
93
|
-
g, leidenalg.ModularityVertexPartition,
|
|
94
|
-
weights=edge_weights, n_iterations=100, seed=42
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
clusters_created = 0
|
|
98
|
-
for cluster_idx, community in enumerate(partition):
|
|
99
|
-
if len(community) < 2:
|
|
100
|
-
continue
|
|
101
|
-
|
|
102
|
-
cluster_memory_ids = [vertex_to_memory_id[v] for v in community]
|
|
103
|
-
avg_importance = self._get_avg_importance(cursor, cluster_memory_ids)
|
|
104
|
-
cluster_name = self._generate_cluster_name(cursor, cluster_memory_ids)
|
|
105
|
-
|
|
106
|
-
result = cursor.execute('''
|
|
107
|
-
INSERT INTO graph_clusters (name, member_count, avg_importance)
|
|
108
|
-
VALUES (?, ?, ?)
|
|
109
|
-
''', (cluster_name, len(cluster_memory_ids), avg_importance))
|
|
110
|
-
|
|
111
|
-
cluster_id = result.lastrowid
|
|
112
|
-
cursor.executemany('''
|
|
113
|
-
UPDATE memories SET cluster_id = ? WHERE id = ?
|
|
114
|
-
''', [(cluster_id, mid) for mid in cluster_memory_ids])
|
|
115
|
-
|
|
116
|
-
clusters_created += 1
|
|
117
|
-
logger.info(f"Cluster {cluster_id}: '{cluster_name}' ({len(cluster_memory_ids)} members)")
|
|
118
|
-
|
|
119
|
-
conn.commit()
|
|
120
|
-
logger.info(f"Created {clusters_created} clusters")
|
|
121
|
-
return clusters_created
|
|
122
|
-
|
|
123
|
-
except Exception as e:
|
|
124
|
-
logger.error(f"Community detection failed: {e}")
|
|
125
|
-
conn.rollback()
|
|
126
|
-
return 0
|
|
127
|
-
finally:
|
|
128
|
-
conn.close()
|
|
129
|
-
|
|
130
|
-
def _get_avg_importance(self, cursor, memory_ids: List[int]) -> float:
|
|
131
|
-
"""Calculate average importance for cluster."""
|
|
132
|
-
placeholders = ','.join('?' * len(memory_ids))
|
|
133
|
-
result = cursor.execute(f'''
|
|
134
|
-
SELECT AVG(importance) FROM memories WHERE id IN ({placeholders})
|
|
135
|
-
''', memory_ids).fetchone()
|
|
136
|
-
return result[0] if result and result[0] else 5.0
|
|
137
|
-
|
|
138
|
-
def _generate_cluster_name(self, cursor, memory_ids: List[int]) -> str:
|
|
139
|
-
"""Generate cluster name from member entities (TF-IDF approach)."""
|
|
140
|
-
placeholders = ','.join('?' * len(memory_ids))
|
|
141
|
-
nodes = cursor.execute(f'''
|
|
142
|
-
SELECT entities FROM graph_nodes WHERE memory_id IN ({placeholders})
|
|
143
|
-
''', memory_ids).fetchall()
|
|
144
|
-
|
|
145
|
-
all_entities = []
|
|
146
|
-
for node in nodes:
|
|
147
|
-
if node[0]:
|
|
148
|
-
all_entities.extend(json.loads(node[0]))
|
|
149
|
-
|
|
150
|
-
if not all_entities:
|
|
151
|
-
return f"Cluster (ID auto-assigned)"
|
|
152
|
-
|
|
153
|
-
entity_counts = Counter(all_entities)
|
|
154
|
-
top_entities = [e for e, _ in entity_counts.most_common(3)]
|
|
155
|
-
|
|
156
|
-
if len(top_entities) >= 2:
|
|
157
|
-
name = f"{top_entities[0].title()} & {top_entities[1].title()}"
|
|
158
|
-
elif len(top_entities) == 1:
|
|
159
|
-
name = f"{top_entities[0].title()} Contexts"
|
|
160
|
-
else:
|
|
161
|
-
name = "Mixed Contexts"
|
|
162
|
-
|
|
163
|
-
return name[:100]
|
|
164
|
-
|
|
165
|
-
def hierarchical_cluster(self, min_subcluster_size: int = 5, max_depth: int = 3) -> Dict[str, any]:
|
|
166
|
-
"""
|
|
167
|
-
Run recursive Leiden clustering -- cluster the clusters.
|
|
168
|
-
|
|
169
|
-
Delegates to the hierarchical module.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
min_subcluster_size: Minimum members to attempt sub-clustering (default 5)
|
|
173
|
-
max_depth: Maximum recursion depth (default 3)
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
Dictionary with hierarchical clustering statistics
|
|
177
|
-
"""
|
|
178
|
-
return _hierarchical_cluster(
|
|
179
|
-
self.db_path,
|
|
180
|
-
get_avg_importance_fn=self._get_avg_importance,
|
|
181
|
-
generate_cluster_name_fn=self._generate_cluster_name,
|
|
182
|
-
min_subcluster_size=min_subcluster_size,
|
|
183
|
-
max_depth=max_depth,
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
def generate_cluster_summaries(self) -> int:
|
|
187
|
-
"""Generate TF-IDF structured summaries for all clusters."""
|
|
188
|
-
return _generate_summaries(self.db_path)
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Cluster summary generation for the graph engine.
|
|
5
|
-
|
|
6
|
-
Generates TF-IDF structured summaries for graph clusters,
|
|
7
|
-
analyzing member content to produce human-readable descriptions
|
|
8
|
-
of each cluster's theme, key topics, and scope.
|
|
9
|
-
"""
|
|
10
|
-
import sqlite3
|
|
11
|
-
import json
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from collections import Counter
|
|
14
|
-
|
|
15
|
-
from graph.constants import logger, MEMORY_DIR
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _get_active_profile() -> str:
|
|
19
|
-
"""Get the currently active profile name from config."""
|
|
20
|
-
config_file = MEMORY_DIR / "profiles.json"
|
|
21
|
-
if config_file.exists():
|
|
22
|
-
try:
|
|
23
|
-
with open(config_file, 'r') as f:
|
|
24
|
-
config = json.load(f)
|
|
25
|
-
return config.get('active_profile', 'default')
|
|
26
|
-
except (json.JSONDecodeError, IOError):
|
|
27
|
-
pass
|
|
28
|
-
return 'default'
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def generate_cluster_summaries(db_path: Path) -> int:
|
|
32
|
-
"""
|
|
33
|
-
Generate TF-IDF structured summaries for all clusters.
|
|
34
|
-
|
|
35
|
-
For each cluster, analyzes member content to produce a human-readable
|
|
36
|
-
summary describing the cluster's theme, key topics, and scope.
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
Number of clusters with summaries generated
|
|
40
|
-
"""
|
|
41
|
-
conn = sqlite3.connect(db_path)
|
|
42
|
-
cursor = conn.cursor()
|
|
43
|
-
active_profile = _get_active_profile()
|
|
44
|
-
|
|
45
|
-
try:
|
|
46
|
-
# Get all clusters for this profile
|
|
47
|
-
cursor.execute('''
|
|
48
|
-
SELECT DISTINCT gc.id, gc.name, gc.member_count
|
|
49
|
-
FROM graph_clusters gc
|
|
50
|
-
JOIN memories m ON m.cluster_id = gc.id
|
|
51
|
-
WHERE m.profile = ?
|
|
52
|
-
''', (active_profile,))
|
|
53
|
-
clusters = cursor.fetchall()
|
|
54
|
-
|
|
55
|
-
if not clusters:
|
|
56
|
-
return 0
|
|
57
|
-
|
|
58
|
-
summaries_generated = 0
|
|
59
|
-
|
|
60
|
-
for cluster_id, cluster_name, member_count in clusters:
|
|
61
|
-
summary = _build_cluster_summary(cursor, cluster_id, active_profile)
|
|
62
|
-
if summary:
|
|
63
|
-
cursor.execute('''
|
|
64
|
-
UPDATE graph_clusters SET summary = ?, updated_at = CURRENT_TIMESTAMP
|
|
65
|
-
WHERE id = ?
|
|
66
|
-
''', (summary, cluster_id))
|
|
67
|
-
summaries_generated += 1
|
|
68
|
-
logger.info(f"Summary for cluster {cluster_id} ({cluster_name}): {summary[:80]}...")
|
|
69
|
-
|
|
70
|
-
conn.commit()
|
|
71
|
-
logger.info(f"Generated {summaries_generated} cluster summaries")
|
|
72
|
-
return summaries_generated
|
|
73
|
-
|
|
74
|
-
except Exception as e:
|
|
75
|
-
logger.error(f"Summary generation failed: {e}")
|
|
76
|
-
conn.rollback()
|
|
77
|
-
return 0
|
|
78
|
-
finally:
|
|
79
|
-
conn.close()
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _build_cluster_summary(cursor, cluster_id: int, profile: str) -> str:
|
|
83
|
-
"""Build a TF-IDF structured summary for a single cluster."""
|
|
84
|
-
# Get member content
|
|
85
|
-
cursor.execute('''
|
|
86
|
-
SELECT m.content, m.summary, m.tags, m.category, m.project_name
|
|
87
|
-
FROM memories m
|
|
88
|
-
WHERE m.cluster_id = ? AND m.profile = ?
|
|
89
|
-
''', (cluster_id, profile))
|
|
90
|
-
members = cursor.fetchall()
|
|
91
|
-
|
|
92
|
-
if not members:
|
|
93
|
-
return ""
|
|
94
|
-
|
|
95
|
-
# Collect entities from graph nodes
|
|
96
|
-
cursor.execute('''
|
|
97
|
-
SELECT gn.entities
|
|
98
|
-
FROM graph_nodes gn
|
|
99
|
-
JOIN memories m ON gn.memory_id = m.id
|
|
100
|
-
WHERE m.cluster_id = ? AND m.profile = ?
|
|
101
|
-
''', (cluster_id, profile))
|
|
102
|
-
all_entities = []
|
|
103
|
-
for row in cursor.fetchall():
|
|
104
|
-
if row[0]:
|
|
105
|
-
try:
|
|
106
|
-
all_entities.extend(json.loads(row[0]))
|
|
107
|
-
except (json.JSONDecodeError, TypeError):
|
|
108
|
-
pass
|
|
109
|
-
|
|
110
|
-
# Top entities by frequency (TF-IDF already extracted these)
|
|
111
|
-
entity_counts = Counter(all_entities)
|
|
112
|
-
top_entities = [e for e, _ in entity_counts.most_common(5)]
|
|
113
|
-
|
|
114
|
-
# Collect unique projects and categories
|
|
115
|
-
projects = set()
|
|
116
|
-
categories = set()
|
|
117
|
-
for m in members:
|
|
118
|
-
if m[3]: # category
|
|
119
|
-
categories.add(m[3])
|
|
120
|
-
if m[4]: # project_name
|
|
121
|
-
projects.add(m[4])
|
|
122
|
-
|
|
123
|
-
# Build structured summary
|
|
124
|
-
parts = []
|
|
125
|
-
|
|
126
|
-
# Theme from top entities
|
|
127
|
-
if top_entities:
|
|
128
|
-
parts.append(f"Key topics: {', '.join(top_entities[:5])}")
|
|
129
|
-
|
|
130
|
-
# Scope
|
|
131
|
-
if projects:
|
|
132
|
-
parts.append(f"Projects: {', '.join(sorted(projects)[:3])}")
|
|
133
|
-
if categories:
|
|
134
|
-
parts.append(f"Categories: {', '.join(sorted(categories)[:3])}")
|
|
135
|
-
|
|
136
|
-
# Size context
|
|
137
|
-
parts.append(f"{len(members)} memories")
|
|
138
|
-
|
|
139
|
-
# Check for hierarchical context
|
|
140
|
-
cursor.execute('SELECT parent_cluster_id FROM graph_clusters WHERE id = ?', (cluster_id,))
|
|
141
|
-
parent_row = cursor.fetchone()
|
|
142
|
-
if parent_row and parent_row[0]:
|
|
143
|
-
cursor.execute('SELECT name FROM graph_clusters WHERE id = ?', (parent_row[0],))
|
|
144
|
-
parent_name_row = cursor.fetchone()
|
|
145
|
-
if parent_name_row:
|
|
146
|
-
parts.append(f"Sub-cluster of: {parent_name_row[0]}")
|
|
147
|
-
|
|
148
|
-
return " | ".join(parts)
|
package/src/graph/constants.py
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
4
|
-
"""Shared constants, imports, and configuration for the graph engine modules.
|
|
5
|
-
"""
|
|
6
|
-
# SECURITY: Graph build limits to prevent resource exhaustion
|
|
7
|
-
MAX_MEMORIES_FOR_GRAPH = 10000
|
|
8
|
-
|
|
9
|
-
import sqlite3
|
|
10
|
-
import json
|
|
11
|
-
import time
|
|
12
|
-
import logging
|
|
13
|
-
from datetime import datetime
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
from typing import List, Dict, Optional, Tuple, Set
|
|
16
|
-
from collections import Counter
|
|
17
|
-
|
|
18
|
-
# Core dependencies
|
|
19
|
-
try:
|
|
20
|
-
from sklearn.feature_extraction.text import TfidfVectorizer
|
|
21
|
-
from sklearn.metrics.pairwise import cosine_similarity
|
|
22
|
-
import numpy as np
|
|
23
|
-
SKLEARN_AVAILABLE = True
|
|
24
|
-
except ImportError:
|
|
25
|
-
SKLEARN_AVAILABLE = False
|
|
26
|
-
raise ImportError("scikit-learn is required. Install: pip install scikit-learn")
|
|
27
|
-
|
|
28
|
-
# Graph dependencies - lazy import to avoid conflicts with compression module
|
|
29
|
-
IGRAPH_AVAILABLE = False
|
|
30
|
-
try:
|
|
31
|
-
# Import only when needed to avoid module conflicts
|
|
32
|
-
import importlib
|
|
33
|
-
ig_module = importlib.import_module('igraph')
|
|
34
|
-
leiden_module = importlib.import_module('leidenalg')
|
|
35
|
-
IGRAPH_AVAILABLE = True
|
|
36
|
-
except ImportError:
|
|
37
|
-
pass # Will raise error when building clusters if not available
|
|
38
|
-
|
|
39
|
-
# Setup logging
|
|
40
|
-
logging.basicConfig(
|
|
41
|
-
level=logging.INFO,
|
|
42
|
-
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
43
|
-
)
|
|
44
|
-
logger = logging.getLogger('graph_engine')
|
|
45
|
-
|
|
46
|
-
MEMORY_DIR = Path.home() / ".claude-memory"
|
|
47
|
-
DB_PATH = MEMORY_DIR / "memory.db"
|