superlocalmemory 4.1.13 → 4.1.14

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 (740) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +48 -0
  3. package/README.md +3 -3
  4. package/package.json +1 -8
  5. package/plugin/.claude-plugin/plugin.json +1 -1
  6. package/plugin/CLAUDE.md +3 -3
  7. package/plugin/agents/slm-governance-advisor.md +1 -1
  8. package/plugin/agents/slm-loop-runner.md +1 -1
  9. package/plugin/agents/slm-memory-advisor.md +1 -1
  10. package/plugin/agents/slm-optimize-advisor.md +1 -1
  11. package/plugin/requirements.txt +1 -1
  12. package/plugin/skills/slm-cache/SKILL.md +1 -1
  13. package/plugin/skills/slm-compress/SKILL.md +1 -1
  14. package/plugin/skills/slm-governance/SKILL.md +1 -1
  15. package/plugin/skills/slm-graph/SKILL.md +1 -1
  16. package/plugin/skills/slm-loop/SKILL.md +1 -1
  17. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  18. package/plugin/skills/slm-profile/SKILL.md +1 -1
  19. package/plugin/skills/slm-recall/SKILL.md +1 -1
  20. package/plugin/skills/slm-remember/SKILL.md +1 -1
  21. package/plugin/skills/slm-scope/SKILL.md +1 -1
  22. package/plugin/skills/slm-session/SKILL.md +1 -1
  23. package/plugin/skills/slm-status/SKILL.md +1 -1
  24. package/plugin-src/agents/slm-memory-advisor.md +1 -1
  25. package/plugin-src/agents/slm-optimize-advisor.md +1 -1
  26. package/plugin-src/rules/AGENTS.md +1 -1
  27. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  29. package/plugin-src/skills/slm-governance/SKILL.md +1 -1
  30. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  31. package/plugin-src/skills/slm-loop/SKILL.md +1 -1
  32. package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
  33. package/plugin-src/skills/slm-profile/SKILL.md +1 -1
  34. package/plugin-src/skills/slm-recall/SKILL.md +1 -1
  35. package/plugin-src/skills/slm-remember/SKILL.md +1 -1
  36. package/plugin-src/skills/slm-scope/SKILL.md +1 -1
  37. package/plugin-src/skills/slm-session/SKILL.md +1 -1
  38. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  39. package/scripts/postinstall.js +71 -2
  40. package/pyproject.toml +0 -250
  41. package/src/superlocalmemory/__init__.py +0 -82
  42. package/src/superlocalmemory/access/__init__.py +0 -3
  43. package/src/superlocalmemory/access/rbac.py +0 -575
  44. package/src/superlocalmemory/attribution/__init__.py +0 -9
  45. package/src/superlocalmemory/attribution/signer.py +0 -173
  46. package/src/superlocalmemory/attribution/watermark.py +0 -189
  47. package/src/superlocalmemory/brain/__init__.py +0 -5
  48. package/src/superlocalmemory/brain/truth.py +0 -418
  49. package/src/superlocalmemory/cli/__init__.py +0 -5
  50. package/src/superlocalmemory/cli/__main__.py +0 -17
  51. package/src/superlocalmemory/cli/_lazy_init.py +0 -115
  52. package/src/superlocalmemory/cli/cache_cmd.py +0 -198
  53. package/src/superlocalmemory/cli/commands.py +0 -4710
  54. package/src/superlocalmemory/cli/compress_cmd.py +0 -151
  55. package/src/superlocalmemory/cli/context_commands.py +0 -193
  56. package/src/superlocalmemory/cli/daemon.py +0 -909
  57. package/src/superlocalmemory/cli/db_migrate.py +0 -150
  58. package/src/superlocalmemory/cli/diagnostics_cmd.py +0 -101
  59. package/src/superlocalmemory/cli/escape_hatch.py +0 -220
  60. package/src/superlocalmemory/cli/evidence_cmd.py +0 -103
  61. package/src/superlocalmemory/cli/gdpr_cmd.py +0 -792
  62. package/src/superlocalmemory/cli/gdpr_io.py +0 -109
  63. package/src/superlocalmemory/cli/help_cmd.py +0 -197
  64. package/src/superlocalmemory/cli/host_upgrades.py +0 -189
  65. package/src/superlocalmemory/cli/ingest_cmd.py +0 -327
  66. package/src/superlocalmemory/cli/json_output.py +0 -81
  67. package/src/superlocalmemory/cli/loop_cmd.py +0 -187
  68. package/src/superlocalmemory/cli/main.py +0 -1145
  69. package/src/superlocalmemory/cli/mesh_cmd.py +0 -38
  70. package/src/superlocalmemory/cli/migrate_cmd.py +0 -55
  71. package/src/superlocalmemory/cli/ops_cmd.py +0 -281
  72. package/src/superlocalmemory/cli/optimize_cmd.py +0 -179
  73. package/src/superlocalmemory/cli/optimize_constants.py +0 -31
  74. package/src/superlocalmemory/cli/pending_store.py +0 -296
  75. package/src/superlocalmemory/cli/proxy_cmd.py +0 -108
  76. package/src/superlocalmemory/cli/scale_engine_cmd.py +0 -56
  77. package/src/superlocalmemory/cli/service_installer.py +0 -373
  78. package/src/superlocalmemory/cli/setup_wizard.py +0 -1162
  79. package/src/superlocalmemory/cli/summary_cmd.py +0 -215
  80. package/src/superlocalmemory/cli/version_banner.py +0 -202
  81. package/src/superlocalmemory/cli/wizard_v3426_options.py +0 -129
  82. package/src/superlocalmemory/code_graph/__init__.py +0 -46
  83. package/src/superlocalmemory/code_graph/blast_radius.py +0 -177
  84. package/src/superlocalmemory/code_graph/bridge/__init__.py +0 -36
  85. package/src/superlocalmemory/code_graph/bridge/entity_resolver.py +0 -490
  86. package/src/superlocalmemory/code_graph/bridge/event_listeners.py +0 -206
  87. package/src/superlocalmemory/code_graph/bridge/fact_enricher.py +0 -159
  88. package/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +0 -170
  89. package/src/superlocalmemory/code_graph/bridge/maintenance.py +0 -220
  90. package/src/superlocalmemory/code_graph/bridge/temporal_checker.py +0 -152
  91. package/src/superlocalmemory/code_graph/changes.py +0 -363
  92. package/src/superlocalmemory/code_graph/communities.py +0 -299
  93. package/src/superlocalmemory/code_graph/config.py +0 -154
  94. package/src/superlocalmemory/code_graph/database.py +0 -526
  95. package/src/superlocalmemory/code_graph/extractors/__init__.py +0 -95
  96. package/src/superlocalmemory/code_graph/extractors/python.py +0 -413
  97. package/src/superlocalmemory/code_graph/extractors/typescript.py +0 -556
  98. package/src/superlocalmemory/code_graph/flows.py +0 -350
  99. package/src/superlocalmemory/code_graph/git_hooks.py +0 -226
  100. package/src/superlocalmemory/code_graph/graph_engine.py +0 -295
  101. package/src/superlocalmemory/code_graph/graph_store.py +0 -335
  102. package/src/superlocalmemory/code_graph/incremental.py +0 -200
  103. package/src/superlocalmemory/code_graph/models.py +0 -130
  104. package/src/superlocalmemory/code_graph/parser.py +0 -687
  105. package/src/superlocalmemory/code_graph/resolver.py +0 -321
  106. package/src/superlocalmemory/code_graph/search.py +0 -460
  107. package/src/superlocalmemory/code_graph/service.py +0 -95
  108. package/src/superlocalmemory/code_graph/watcher.py +0 -207
  109. package/src/superlocalmemory/compliance/__init__.py +0 -0
  110. package/src/superlocalmemory/compliance/abac.py +0 -204
  111. package/src/superlocalmemory/compliance/audit.py +0 -385
  112. package/src/superlocalmemory/compliance/eu_ai_act.py +0 -101
  113. package/src/superlocalmemory/compliance/gdpr.py +0 -1479
  114. package/src/superlocalmemory/compliance/lifecycle.py +0 -158
  115. package/src/superlocalmemory/compliance/retention.py +0 -415
  116. package/src/superlocalmemory/compliance/scheduler.py +0 -217
  117. package/src/superlocalmemory/contracts/__init__.py +0 -1
  118. package/src/superlocalmemory/contracts/schemas/agent-experience-v1.schema.json +0 -92
  119. package/src/superlocalmemory/contracts/schemas/agent-integration-contract-v2.schema.json +0 -46
  120. package/src/superlocalmemory/contracts/schemas/cognitive-turn-receipt-v1.schema.json +0 -59
  121. package/src/superlocalmemory/contracts/v402.py +0 -62
  122. package/src/superlocalmemory/core/__init__.py +0 -0
  123. package/src/superlocalmemory/core/actor_context.py +0 -166
  124. package/src/superlocalmemory/core/admission.py +0 -769
  125. package/src/superlocalmemory/core/backend_orchestrator.py +0 -637
  126. package/src/superlocalmemory/core/block_hygiene.py +0 -147
  127. package/src/superlocalmemory/core/community_summary.py +0 -267
  128. package/src/superlocalmemory/core/component_healer.py +0 -144
  129. package/src/superlocalmemory/core/component_registry.py +0 -514
  130. package/src/superlocalmemory/core/config.py +0 -2204
  131. package/src/superlocalmemory/core/consolidation_engine.py +0 -983
  132. package/src/superlocalmemory/core/context_cache.py +0 -574
  133. package/src/superlocalmemory/core/derivation_lineage.py +0 -246
  134. package/src/superlocalmemory/core/embedding_worker.py +0 -208
  135. package/src/superlocalmemory/core/embeddings.py +0 -1052
  136. package/src/superlocalmemory/core/engine.py +0 -1395
  137. package/src/superlocalmemory/core/engine_capabilities.py +0 -24
  138. package/src/superlocalmemory/core/engine_ingestion.py +0 -983
  139. package/src/superlocalmemory/core/engine_lock.py +0 -75
  140. package/src/superlocalmemory/core/engine_wiring.py +0 -776
  141. package/src/superlocalmemory/core/entity_community.py +0 -178
  142. package/src/superlocalmemory/core/error_envelope.py +0 -60
  143. package/src/superlocalmemory/core/evidence_bundle.py +0 -528
  144. package/src/superlocalmemory/core/fact_consolidator.py +0 -812
  145. package/src/superlocalmemory/core/file_lock.py +0 -92
  146. package/src/superlocalmemory/core/graph_analyzer.py +0 -456
  147. package/src/superlocalmemory/core/graph_metrics.py +0 -597
  148. package/src/superlocalmemory/core/graph_pruner.py +0 -939
  149. package/src/superlocalmemory/core/health_monitor.py +0 -338
  150. package/src/superlocalmemory/core/hooks.py +0 -65
  151. package/src/superlocalmemory/core/ingest_gate.py +0 -133
  152. package/src/superlocalmemory/core/ingest_policy.py +0 -38
  153. package/src/superlocalmemory/core/ingestion_command.py +0 -1042
  154. package/src/superlocalmemory/core/injection.py +0 -434
  155. package/src/superlocalmemory/core/install_detector.py +0 -131
  156. package/src/superlocalmemory/core/key_expander.py +0 -138
  157. package/src/superlocalmemory/core/lifecycle_state.py +0 -153
  158. package/src/superlocalmemory/core/maintenance.py +0 -777
  159. package/src/superlocalmemory/core/maintenance_scheduler.py +0 -507
  160. package/src/superlocalmemory/core/materialization_control.py +0 -20
  161. package/src/superlocalmemory/core/mcp_embedder_proxy.py +0 -89
  162. package/src/superlocalmemory/core/memory_health.py +0 -266
  163. package/src/superlocalmemory/core/mode_capability.py +0 -111
  164. package/src/superlocalmemory/core/modes.py +0 -168
  165. package/src/superlocalmemory/core/mutations.py +0 -688
  166. package/src/superlocalmemory/core/ollama_embedder.py +0 -266
  167. package/src/superlocalmemory/core/ollama_validator.py +0 -315
  168. package/src/superlocalmemory/core/operation_policy.py +0 -92
  169. package/src/superlocalmemory/core/operation_policy_registry.py +0 -542
  170. package/src/superlocalmemory/core/operation_request.py +0 -127
  171. package/src/superlocalmemory/core/ops_remediation.py +0 -542
  172. package/src/superlocalmemory/core/pii.py +0 -105
  173. package/src/superlocalmemory/core/platform_utils.py +0 -138
  174. package/src/superlocalmemory/core/profiles.py +0 -234
  175. package/src/superlocalmemory/core/progressive_abstraction.py +0 -208
  176. package/src/superlocalmemory/core/projection_drain.py +0 -380
  177. package/src/superlocalmemory/core/queue_consumer.py +0 -168
  178. package/src/superlocalmemory/core/ram_lock.py +0 -160
  179. package/src/superlocalmemory/core/rate_limit.py +0 -151
  180. package/src/superlocalmemory/core/recall_gate.py +0 -95
  181. package/src/superlocalmemory/core/recall_pipeline.py +0 -1337
  182. package/src/superlocalmemory/core/recall_queue.py +0 -377
  183. package/src/superlocalmemory/core/recall_worker.py +0 -414
  184. package/src/superlocalmemory/core/registry.py +0 -121
  185. package/src/superlocalmemory/core/remember_admission.py +0 -161
  186. package/src/superlocalmemory/core/remember_runtime.py +0 -1190
  187. package/src/superlocalmemory/core/remote_mode.py +0 -214
  188. package/src/superlocalmemory/core/reranker_worker.py +0 -338
  189. package/src/superlocalmemory/core/safe_fs.py +0 -108
  190. package/src/superlocalmemory/core/scale_autopromote.py +0 -196
  191. package/src/superlocalmemory/core/scale_engine.py +0 -915
  192. package/src/superlocalmemory/core/score_contract.py +0 -82
  193. package/src/superlocalmemory/core/security_primitives.py +0 -672
  194. package/src/superlocalmemory/core/session_identity.py +0 -98
  195. package/src/superlocalmemory/core/shadow_router.py +0 -319
  196. package/src/superlocalmemory/core/slm_disabled.py +0 -85
  197. package/src/superlocalmemory/core/status_contract.py +0 -108
  198. package/src/superlocalmemory/core/store_pipeline.py +0 -1404
  199. package/src/superlocalmemory/core/summarizer.py +0 -200
  200. package/src/superlocalmemory/core/tier_manager.py +0 -461
  201. package/src/superlocalmemory/core/topic_signature.py +0 -156
  202. package/src/superlocalmemory/core/transactions/__init__.py +0 -78
  203. package/src/superlocalmemory/core/transactions/concrete_owners.py +0 -604
  204. package/src/superlocalmemory/core/transactions/erasure.py +0 -825
  205. package/src/superlocalmemory/core/transactions/manifest.py +0 -255
  206. package/src/superlocalmemory/core/transactions/manifest_key.py +0 -155
  207. package/src/superlocalmemory/core/transactions/obligations.py +0 -272
  208. package/src/superlocalmemory/core/transactions/owners.py +0 -114
  209. package/src/superlocalmemory/core/transactions/reconciler.py +0 -285
  210. package/src/superlocalmemory/core/transactions/service.py +0 -330
  211. package/src/superlocalmemory/core/worker_pool.py +0 -377
  212. package/src/superlocalmemory/core/working_memory.py +0 -288
  213. package/src/superlocalmemory/dynamics/__init__.py +0 -0
  214. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +0 -374
  215. package/src/superlocalmemory/dynamics/eap_scheduler.py +0 -294
  216. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +0 -171
  217. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +0 -227
  218. package/src/superlocalmemory/encoding/__init__.py +0 -0
  219. package/src/superlocalmemory/encoding/auto_linker.py +0 -308
  220. package/src/superlocalmemory/encoding/cognitive_consolidator.py +0 -899
  221. package/src/superlocalmemory/encoding/consolidator.py +0 -472
  222. package/src/superlocalmemory/encoding/context_generator.py +0 -175
  223. package/src/superlocalmemory/encoding/emotional.py +0 -189
  224. package/src/superlocalmemory/encoding/entity_reflexion.py +0 -200
  225. package/src/superlocalmemory/encoding/entity_resolver.py +0 -687
  226. package/src/superlocalmemory/encoding/entropy_gate.py +0 -101
  227. package/src/superlocalmemory/encoding/fact_extractor.py +0 -877
  228. package/src/superlocalmemory/encoding/foresight.py +0 -93
  229. package/src/superlocalmemory/encoding/graph_builder.py +0 -346
  230. package/src/superlocalmemory/encoding/observation_builder.py +0 -177
  231. package/src/superlocalmemory/encoding/prospective_markers.py +0 -262
  232. package/src/superlocalmemory/encoding/scene_builder.py +0 -410
  233. package/src/superlocalmemory/encoding/signal_inference.py +0 -90
  234. package/src/superlocalmemory/encoding/temporal_parser.py +0 -432
  235. package/src/superlocalmemory/encoding/temporal_validator.py +0 -572
  236. package/src/superlocalmemory/encoding/type_router.py +0 -237
  237. package/src/superlocalmemory/evaluation/__init__.py +0 -13
  238. package/src/superlocalmemory/evaluation/calibration.py +0 -308
  239. package/src/superlocalmemory/evolution/__init__.py +0 -29
  240. package/src/superlocalmemory/evolution/blind_verifier.py +0 -122
  241. package/src/superlocalmemory/evolution/budget.py +0 -356
  242. package/src/superlocalmemory/evolution/evolution_store.py +0 -619
  243. package/src/superlocalmemory/evolution/llm_dispatch.py +0 -559
  244. package/src/superlocalmemory/evolution/model_selection.py +0 -175
  245. package/src/superlocalmemory/evolution/mutation_generator.py +0 -226
  246. package/src/superlocalmemory/evolution/skill_activator.py +0 -270
  247. package/src/superlocalmemory/evolution/skill_evolver.py +0 -928
  248. package/src/superlocalmemory/evolution/triggers.py +0 -376
  249. package/src/superlocalmemory/evolution/types.py +0 -114
  250. package/src/superlocalmemory/graph/__init__.py +0 -9
  251. package/src/superlocalmemory/graph/cozo_adjacency.py +0 -122
  252. package/src/superlocalmemory/graph/cozo_backend.py +0 -751
  253. package/src/superlocalmemory/hooks/__init__.py +0 -3
  254. package/src/superlocalmemory/hooks/_outcome_common.py +0 -523
  255. package/src/superlocalmemory/hooks/adapter_base.py +0 -347
  256. package/src/superlocalmemory/hooks/antigravity_adapter.py +0 -171
  257. package/src/superlocalmemory/hooks/auto_capture.py +0 -133
  258. package/src/superlocalmemory/hooks/auto_invoker.py +0 -521
  259. package/src/superlocalmemory/hooks/auto_parameterize.py +0 -147
  260. package/src/superlocalmemory/hooks/auto_recall.py +0 -191
  261. package/src/superlocalmemory/hooks/auto_recall_hook.py +0 -251
  262. package/src/superlocalmemory/hooks/before_web_hook.py +0 -131
  263. package/src/superlocalmemory/hooks/claude_code_hooks.py +0 -637
  264. package/src/superlocalmemory/hooks/codex_assets.py +0 -251
  265. package/src/superlocalmemory/hooks/codex_hooks.py +0 -186
  266. package/src/superlocalmemory/hooks/context_payload.py +0 -311
  267. package/src/superlocalmemory/hooks/copilot_adapter.py +0 -208
  268. package/src/superlocalmemory/hooks/cross_platform_connector.py +0 -90
  269. package/src/superlocalmemory/hooks/cursor_adapter.py +0 -173
  270. package/src/superlocalmemory/hooks/hook_daemon.py +0 -295
  271. package/src/superlocalmemory/hooks/hook_handlers.py +0 -822
  272. package/src/superlocalmemory/hooks/ide_connector.py +0 -246
  273. package/src/superlocalmemory/hooks/memory_protocol.py +0 -158
  274. package/src/superlocalmemory/hooks/portable_kit.py +0 -755
  275. package/src/superlocalmemory/hooks/post_tool_async_hook.py +0 -183
  276. package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +0 -351
  277. package/src/superlocalmemory/hooks/prewarm_auth.py +0 -187
  278. package/src/superlocalmemory/hooks/rules_engine.py +0 -99
  279. package/src/superlocalmemory/hooks/session_registry.py +0 -330
  280. package/src/superlocalmemory/hooks/stop_outcome_hook.py +0 -138
  281. package/src/superlocalmemory/hooks/sync_loop.py +0 -114
  282. package/src/superlocalmemory/hooks/topic_shift_hook.py +0 -302
  283. package/src/superlocalmemory/hooks/user_prompt_hook.py +0 -131
  284. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +0 -210
  285. package/src/superlocalmemory/infra/__init__.py +0 -3
  286. package/src/superlocalmemory/infra/auth_middleware.py +0 -145
  287. package/src/superlocalmemory/infra/backup.py +0 -974
  288. package/src/superlocalmemory/infra/backup_obligations.py +0 -423
  289. package/src/superlocalmemory/infra/cache_manager.py +0 -267
  290. package/src/superlocalmemory/infra/cloud_backup.py +0 -788
  291. package/src/superlocalmemory/infra/daemon_identity.py +0 -300
  292. package/src/superlocalmemory/infra/data_root.py +0 -238
  293. package/src/superlocalmemory/infra/event_bus.py +0 -637
  294. package/src/superlocalmemory/infra/local_diagnostics.py +0 -327
  295. package/src/superlocalmemory/infra/pid_manager.py +0 -193
  296. package/src/superlocalmemory/infra/process_identity.py +0 -180
  297. package/src/superlocalmemory/infra/process_reaper.py +0 -624
  298. package/src/superlocalmemory/infra/rate_limiter.py +0 -228
  299. package/src/superlocalmemory/infra/self_heal.py +0 -401
  300. package/src/superlocalmemory/infra/version_integrity.py +0 -229
  301. package/src/superlocalmemory/ingestion/__init__.py +0 -13
  302. package/src/superlocalmemory/ingestion/adapter_manager.py +0 -255
  303. package/src/superlocalmemory/ingestion/base_adapter.py +0 -171
  304. package/src/superlocalmemory/ingestion/calendar_adapter.py +0 -349
  305. package/src/superlocalmemory/ingestion/credentials.py +0 -125
  306. package/src/superlocalmemory/ingestion/gmail_adapter.py +0 -378
  307. package/src/superlocalmemory/ingestion/parsers.py +0 -100
  308. package/src/superlocalmemory/ingestion/transcript_adapter.py +0 -161
  309. package/src/superlocalmemory/integrations/__init__.py +0 -1
  310. package/src/superlocalmemory/integrations/bounded_loops_mcp.py +0 -431
  311. package/src/superlocalmemory/integrations/bounded_loops_v051.py +0 -236
  312. package/src/superlocalmemory/learning/__init__.py +0 -0
  313. package/src/superlocalmemory/learning/adaptive.py +0 -172
  314. package/src/superlocalmemory/learning/arm_catalog.py +0 -97
  315. package/src/superlocalmemory/learning/assertion_miner.py +0 -403
  316. package/src/superlocalmemory/learning/bandit.py +0 -654
  317. package/src/superlocalmemory/learning/bandit_cache.py +0 -131
  318. package/src/superlocalmemory/learning/behavioral.py +0 -542
  319. package/src/superlocalmemory/learning/bootstrap.py +0 -298
  320. package/src/superlocalmemory/learning/consolidation_cycle.py +0 -398
  321. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +0 -115
  322. package/src/superlocalmemory/learning/consolidation_worker.py +0 -261
  323. package/src/superlocalmemory/learning/cross_project.py +0 -408
  324. package/src/superlocalmemory/learning/database.py +0 -698
  325. package/src/superlocalmemory/learning/dedup_hnsw.py +0 -413
  326. package/src/superlocalmemory/learning/engagement.py +0 -487
  327. package/src/superlocalmemory/learning/engagement_features.py +0 -279
  328. package/src/superlocalmemory/learning/ensemble.py +0 -309
  329. package/src/superlocalmemory/learning/entity_compiler.py +0 -356
  330. package/src/superlocalmemory/learning/fact_outcome_joins.py +0 -207
  331. package/src/superlocalmemory/learning/features.py +0 -138
  332. package/src/superlocalmemory/learning/feedback.py +0 -724
  333. package/src/superlocalmemory/learning/forgetting_scheduler.py +0 -375
  334. package/src/superlocalmemory/learning/hnsw_dedup.py +0 -69
  335. package/src/superlocalmemory/learning/labeler.py +0 -85
  336. package/src/superlocalmemory/learning/legacy_migration.py +0 -316
  337. package/src/superlocalmemory/learning/lightgbm_subprocess.py +0 -236
  338. package/src/superlocalmemory/learning/memory_merge.py +0 -175
  339. package/src/superlocalmemory/learning/model_cache.py +0 -267
  340. package/src/superlocalmemory/learning/model_rollback.py +0 -281
  341. package/src/superlocalmemory/learning/outcome_queue.py +0 -306
  342. package/src/superlocalmemory/learning/outcomes.py +0 -286
  343. package/src/superlocalmemory/learning/pattern_miner.py +0 -465
  344. package/src/superlocalmemory/learning/pattern_miner_constants.py +0 -90
  345. package/src/superlocalmemory/learning/pcos.py +0 -291
  346. package/src/superlocalmemory/learning/project_context.py +0 -366
  347. package/src/superlocalmemory/learning/propensity.py +0 -131
  348. package/src/superlocalmemory/learning/ranker.py +0 -300
  349. package/src/superlocalmemory/learning/ranker_common.py +0 -163
  350. package/src/superlocalmemory/learning/ranker_retrain_legacy.py +0 -210
  351. package/src/superlocalmemory/learning/ranker_retrain_online.py +0 -423
  352. package/src/superlocalmemory/learning/reward.py +0 -888
  353. package/src/superlocalmemory/learning/reward_archive.py +0 -223
  354. package/src/superlocalmemory/learning/reward_boost.py +0 -211
  355. package/src/superlocalmemory/learning/reward_from_outcomes.py +0 -365
  356. package/src/superlocalmemory/learning/reward_model.py +0 -144
  357. package/src/superlocalmemory/learning/reward_proxy.py +0 -578
  358. package/src/superlocalmemory/learning/shadow_test.py +0 -524
  359. package/src/superlocalmemory/learning/signal_kinds.py +0 -79
  360. package/src/superlocalmemory/learning/signal_worker.py +0 -268
  361. package/src/superlocalmemory/learning/signals.py +0 -646
  362. package/src/superlocalmemory/learning/skill_performance_miner.py +0 -422
  363. package/src/superlocalmemory/learning/source_quality.py +0 -828
  364. package/src/superlocalmemory/learning/trigram_index.py +0 -548
  365. package/src/superlocalmemory/learning/workflows.py +0 -309
  366. package/src/superlocalmemory/llm/__init__.py +0 -0
  367. package/src/superlocalmemory/llm/backbone.py +0 -364
  368. package/src/superlocalmemory/loops/__init__.py +0 -58
  369. package/src/superlocalmemory/loops/budget.py +0 -58
  370. package/src/superlocalmemory/loops/engine.py +0 -174
  371. package/src/superlocalmemory/loops/ledger.py +0 -298
  372. package/src/superlocalmemory/loops/models.py +0 -152
  373. package/src/superlocalmemory/loops/rules.py +0 -52
  374. package/src/superlocalmemory/math/__init__.py +0 -0
  375. package/src/superlocalmemory/math/ebbinghaus.py +0 -352
  376. package/src/superlocalmemory/math/fisher.py +0 -356
  377. package/src/superlocalmemory/math/fisher_quantized.py +0 -255
  378. package/src/superlocalmemory/math/hopfield.py +0 -282
  379. package/src/superlocalmemory/math/langevin.py +0 -411
  380. package/src/superlocalmemory/math/polar_quant.py +0 -414
  381. package/src/superlocalmemory/math/qjl.py +0 -115
  382. package/src/superlocalmemory/math/sheaf.py +0 -261
  383. package/src/superlocalmemory/math/turbo_quant.py +0 -318
  384. package/src/superlocalmemory/mcp/__init__.py +0 -0
  385. package/src/superlocalmemory/mcp/_daemon_proxy.py +0 -203
  386. package/src/superlocalmemory/mcp/_pool_adapter.py +0 -181
  387. package/src/superlocalmemory/mcp/_stdin_guard.py +0 -60
  388. package/src/superlocalmemory/mcp/agent_context.py +0 -115
  389. package/src/superlocalmemory/mcp/cli_fallback.py +0 -602
  390. package/src/superlocalmemory/mcp/http_transport.py +0 -85
  391. package/src/superlocalmemory/mcp/profiles.py +0 -154
  392. package/src/superlocalmemory/mcp/resources.py +0 -281
  393. package/src/superlocalmemory/mcp/server.py +0 -480
  394. package/src/superlocalmemory/mcp/session_binding.py +0 -98
  395. package/src/superlocalmemory/mcp/shared.py +0 -112
  396. package/src/superlocalmemory/mcp/tools.py +0 -18
  397. package/src/superlocalmemory/mcp/tools_active.py +0 -958
  398. package/src/superlocalmemory/mcp/tools_brain.py +0 -298
  399. package/src/superlocalmemory/mcp/tools_code_graph.py +0 -1717
  400. package/src/superlocalmemory/mcp/tools_context.py +0 -239
  401. package/src/superlocalmemory/mcp/tools_core.py +0 -1112
  402. package/src/superlocalmemory/mcp/tools_evolution.py +0 -343
  403. package/src/superlocalmemory/mcp/tools_learning.py +0 -393
  404. package/src/superlocalmemory/mcp/tools_loops.py +0 -345
  405. package/src/superlocalmemory/mcp/tools_mesh.py +0 -429
  406. package/src/superlocalmemory/mcp/tools_ops.py +0 -115
  407. package/src/superlocalmemory/mcp/tools_optimize.py +0 -322
  408. package/src/superlocalmemory/mcp/tools_summaries.py +0 -147
  409. package/src/superlocalmemory/mcp/tools_v28.py +0 -292
  410. package/src/superlocalmemory/mcp/tools_v3.py +0 -398
  411. package/src/superlocalmemory/mcp/tools_v33.py +0 -507
  412. package/src/superlocalmemory/mesh/__init__.py +0 -12
  413. package/src/superlocalmemory/mesh/broker.py +0 -812
  414. package/src/superlocalmemory/mesh/broker_security.py +0 -470
  415. package/src/superlocalmemory/mesh/discovery.py +0 -365
  416. package/src/superlocalmemory/mesh/lock_protocol.py +0 -313
  417. package/src/superlocalmemory/mesh/node_identity.py +0 -97
  418. package/src/superlocalmemory/mesh/outbox_remote.py +0 -429
  419. package/src/superlocalmemory/mesh/remote_sync.py +0 -829
  420. package/src/superlocalmemory/mesh/state_sync.py +0 -286
  421. package/src/superlocalmemory/migrations/__init__.py +0 -5
  422. package/src/superlocalmemory/migrations/v3_4_25_to_v3_4_26.py +0 -144
  423. package/src/superlocalmemory/optimize/NOTICE +0 -6
  424. package/src/superlocalmemory/optimize/__init__.py +0 -0
  425. package/src/superlocalmemory/optimize/adapters/__init__.py +0 -68
  426. package/src/superlocalmemory/optimize/adapters/_agent_registry.py +0 -120
  427. package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +0 -112
  428. package/src/superlocalmemory/optimize/adapters/openai_adapter.py +0 -122
  429. package/src/superlocalmemory/optimize/adapters/wrap.py +0 -228
  430. package/src/superlocalmemory/optimize/cache/__init__.py +0 -31
  431. package/src/superlocalmemory/optimize/cache/boundary_store.py +0 -488
  432. package/src/superlocalmemory/optimize/cache/centroid_store.py +0 -199
  433. package/src/superlocalmemory/optimize/cache/context_key.py +0 -67
  434. package/src/superlocalmemory/optimize/cache/exact.py +0 -88
  435. package/src/superlocalmemory/optimize/cache/invalidation.py +0 -36
  436. package/src/superlocalmemory/optimize/cache/key_builder.py +0 -111
  437. package/src/superlocalmemory/optimize/cache/manager.py +0 -737
  438. package/src/superlocalmemory/optimize/cache/semantic.py +0 -637
  439. package/src/superlocalmemory/optimize/cache/stampede.py +0 -50
  440. package/src/superlocalmemory/optimize/compress/__init__.py +0 -17
  441. package/src/superlocalmemory/optimize/compress/align.py +0 -159
  442. package/src/superlocalmemory/optimize/compress/ccr.py +0 -116
  443. package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +0 -71
  444. package/src/superlocalmemory/optimize/compress/router.py +0 -667
  445. package/src/superlocalmemory/optimize/config/__init__.py +0 -56
  446. package/src/superlocalmemory/optimize/config/defaults.py +0 -43
  447. package/src/superlocalmemory/optimize/config/schema.py +0 -327
  448. package/src/superlocalmemory/optimize/config/store.py +0 -270
  449. package/src/superlocalmemory/optimize/metrics/__init__.py +0 -8
  450. package/src/superlocalmemory/optimize/metrics/counters.py +0 -155
  451. package/src/superlocalmemory/optimize/metrics/estimator.py +0 -87
  452. package/src/superlocalmemory/optimize/metrics/exporters.py +0 -77
  453. package/src/superlocalmemory/optimize/metrics/persistence.py +0 -115
  454. package/src/superlocalmemory/optimize/proxy/__init__.py +0 -28
  455. package/src/superlocalmemory/optimize/proxy/_helpers.py +0 -730
  456. package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +0 -375
  457. package/src/superlocalmemory/optimize/proxy/capture.py +0 -550
  458. package/src/superlocalmemory/optimize/proxy/gemini_surface.py +0 -528
  459. package/src/superlocalmemory/optimize/proxy/lifecycle.py +0 -126
  460. package/src/superlocalmemory/optimize/proxy/openai_surface.py +0 -465
  461. package/src/superlocalmemory/optimize/proxy/server.py +0 -199
  462. package/src/superlocalmemory/optimize/proxy/vertex_surface.py +0 -246
  463. package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
  464. package/src/superlocalmemory/optimize/storage/db.py +0 -1185
  465. package/src/superlocalmemory/optimize/storage/schema.py +0 -205
  466. package/src/superlocalmemory/parameterization/__init__.py +0 -47
  467. package/src/superlocalmemory/parameterization/cross_project.py +0 -12
  468. package/src/superlocalmemory/parameterization/pattern_extractor.py +0 -584
  469. package/src/superlocalmemory/parameterization/pii_filter.py +0 -106
  470. package/src/superlocalmemory/parameterization/prompt_injector.py +0 -219
  471. package/src/superlocalmemory/parameterization/prompt_lifecycle.py +0 -281
  472. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +0 -542
  473. package/src/superlocalmemory/parameterization/workflow_miner.py +0 -17
  474. package/src/superlocalmemory/reliability/__init__.py +0 -45
  475. package/src/superlocalmemory/reliability/join_liveness.py +0 -301
  476. package/src/superlocalmemory/reliability/prior_distance.py +0 -243
  477. package/src/superlocalmemory/retrieval/__init__.py +0 -0
  478. package/src/superlocalmemory/retrieval/agentic.py +0 -367
  479. package/src/superlocalmemory/retrieval/ann_index.py +0 -235
  480. package/src/superlocalmemory/retrieval/bm25_channel.py +0 -451
  481. package/src/superlocalmemory/retrieval/bridge_discovery.py +0 -253
  482. package/src/superlocalmemory/retrieval/channel_registry.py +0 -154
  483. package/src/superlocalmemory/retrieval/channel_status.py +0 -117
  484. package/src/superlocalmemory/retrieval/engine.py +0 -1615
  485. package/src/superlocalmemory/retrieval/entity_channel.py +0 -994
  486. package/src/superlocalmemory/retrieval/forgetting_filter.py +0 -160
  487. package/src/superlocalmemory/retrieval/fusion.py +0 -81
  488. package/src/superlocalmemory/retrieval/graph_adjacency.py +0 -219
  489. package/src/superlocalmemory/retrieval/hopfield_channel.py +0 -465
  490. package/src/superlocalmemory/retrieval/profile_channel.py +0 -105
  491. package/src/superlocalmemory/retrieval/quantization_aware_search.py +0 -147
  492. package/src/superlocalmemory/retrieval/remote_reranker.py +0 -758
  493. package/src/superlocalmemory/retrieval/reranker.py +0 -674
  494. package/src/superlocalmemory/retrieval/scope_policy.py +0 -126
  495. package/src/superlocalmemory/retrieval/semantic_channel.py +0 -638
  496. package/src/superlocalmemory/retrieval/spreading.py +0 -288
  497. package/src/superlocalmemory/retrieval/spreading_activation.py +0 -616
  498. package/src/superlocalmemory/retrieval/strategy.py +0 -248
  499. package/src/superlocalmemory/retrieval/temporal_channel.py +0 -433
  500. package/src/superlocalmemory/retrieval/temporal_frame.py +0 -102
  501. package/src/superlocalmemory/retrieval/temporal_utils.py +0 -122
  502. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +0 -499
  503. package/src/superlocalmemory/retrieval/time_window.py +0 -181
  504. package/src/superlocalmemory/retrieval/vector_store.py +0 -863
  505. package/src/superlocalmemory/server/__init__.py +0 -1
  506. package/src/superlocalmemory/server/api.py +0 -310
  507. package/src/superlocalmemory/server/asset_versions.py +0 -171
  508. package/src/superlocalmemory/server/bandit_loops.py +0 -158
  509. package/src/superlocalmemory/server/config_file.py +0 -90
  510. package/src/superlocalmemory/server/consolidation_runner.py +0 -140
  511. package/src/superlocalmemory/server/egress_policy.py +0 -258
  512. package/src/superlocalmemory/server/loopback.py +0 -85
  513. package/src/superlocalmemory/server/middleware/__init__.py +0 -11
  514. package/src/superlocalmemory/server/middleware/security_headers.py +0 -144
  515. package/src/superlocalmemory/server/origin.py +0 -55
  516. package/src/superlocalmemory/server/profile_runtime.py +0 -515
  517. package/src/superlocalmemory/server/rbac_enforce.py +0 -194
  518. package/src/superlocalmemory/server/recall_health.py +0 -343
  519. package/src/superlocalmemory/server/recall_serializer.py +0 -320
  520. package/src/superlocalmemory/server/route_mutations.py +0 -104
  521. package/src/superlocalmemory/server/routes/__init__.py +0 -4
  522. package/src/superlocalmemory/server/routes/abstraction.py +0 -314
  523. package/src/superlocalmemory/server/routes/adapters.py +0 -63
  524. package/src/superlocalmemory/server/routes/agents.py +0 -303
  525. package/src/superlocalmemory/server/routes/backup.py +0 -869
  526. package/src/superlocalmemory/server/routes/behavioral.py +0 -659
  527. package/src/superlocalmemory/server/routes/brain.py +0 -1892
  528. package/src/superlocalmemory/server/routes/chat.py +0 -393
  529. package/src/superlocalmemory/server/routes/compliance.py +0 -533
  530. package/src/superlocalmemory/server/routes/config_api.py +0 -703
  531. package/src/superlocalmemory/server/routes/data_io.py +0 -329
  532. package/src/superlocalmemory/server/routes/entity.py +0 -237
  533. package/src/superlocalmemory/server/routes/events.py +0 -214
  534. package/src/superlocalmemory/server/routes/evolution.py +0 -510
  535. package/src/superlocalmemory/server/routes/helpers.py +0 -499
  536. package/src/superlocalmemory/server/routes/ingest.py +0 -137
  537. package/src/superlocalmemory/server/routes/insights.py +0 -366
  538. package/src/superlocalmemory/server/routes/learning.py +0 -834
  539. package/src/superlocalmemory/server/routes/learning_telemetry.py +0 -154
  540. package/src/superlocalmemory/server/routes/lifecycle.py +0 -184
  541. package/src/superlocalmemory/server/routes/memories.py +0 -1661
  542. package/src/superlocalmemory/server/routes/mesh.py +0 -517
  543. package/src/superlocalmemory/server/routes/mesh_lock.py +0 -54
  544. package/src/superlocalmemory/server/routes/mesh_state.py +0 -63
  545. package/src/superlocalmemory/server/routes/optimize.py +0 -197
  546. package/src/superlocalmemory/server/routes/prewarm.py +0 -173
  547. package/src/superlocalmemory/server/routes/profiles.py +0 -292
  548. package/src/superlocalmemory/server/routes/ratelimit.py +0 -132
  549. package/src/superlocalmemory/server/routes/rbac.py +0 -366
  550. package/src/superlocalmemory/server/routes/stats.py +0 -385
  551. package/src/superlocalmemory/server/routes/tiers.py +0 -222
  552. package/src/superlocalmemory/server/routes/timeline.py +0 -258
  553. package/src/superlocalmemory/server/routes/token.py +0 -90
  554. package/src/superlocalmemory/server/routes/v3_api.py +0 -3023
  555. package/src/superlocalmemory/server/routes/ws.py +0 -171
  556. package/src/superlocalmemory/server/security_middleware.py +0 -89
  557. package/src/superlocalmemory/server/ui.py +0 -354
  558. package/src/superlocalmemory/server/unified_daemon.py +0 -6326
  559. package/src/superlocalmemory/server/write_identity.py +0 -195
  560. package/src/superlocalmemory/storage/__init__.py +0 -0
  561. package/src/superlocalmemory/storage/_migration_internals.py +0 -638
  562. package/src/superlocalmemory/storage/_schema_version.py +0 -174
  563. package/src/superlocalmemory/storage/access_log.py +0 -170
  564. package/src/superlocalmemory/storage/admission_codec.py +0 -129
  565. package/src/superlocalmemory/storage/admission_journal.py +0 -843
  566. package/src/superlocalmemory/storage/agent_experience.py +0 -546
  567. package/src/superlocalmemory/storage/backup.py +0 -531
  568. package/src/superlocalmemory/storage/correction_cases.py +0 -670
  569. package/src/superlocalmemory/storage/database.py +0 -3180
  570. package/src/superlocalmemory/storage/deferred_writes.py +0 -209
  571. package/src/superlocalmemory/storage/embedding_codec.py +0 -200
  572. package/src/superlocalmemory/storage/embedding_migrator.py +0 -672
  573. package/src/superlocalmemory/storage/erasure_fence.py +0 -45
  574. package/src/superlocalmemory/storage/execution_learning.py +0 -285
  575. package/src/superlocalmemory/storage/external_evidence.py +0 -359
  576. package/src/superlocalmemory/storage/generation_fence.py +0 -63
  577. package/src/superlocalmemory/storage/lineage_retention.py +0 -236
  578. package/src/superlocalmemory/storage/logical_edges.py +0 -86
  579. package/src/superlocalmemory/storage/memory_write.py +0 -115
  580. package/src/superlocalmemory/storage/migration_runner.py +0 -895
  581. package/src/superlocalmemory/storage/migration_v33.py +0 -140
  582. package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +0 -67
  583. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +0 -107
  584. package/src/superlocalmemory/storage/migrations/M003_migration_log.py +0 -38
  585. package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +0 -46
  586. package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +0 -75
  587. package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +0 -75
  588. package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +0 -63
  589. package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +0 -94
  590. package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +0 -80
  591. package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +0 -87
  592. package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +0 -72
  593. package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +0 -55
  594. package/src/superlocalmemory/storage/migrations/M014_v345_scale_ready.py +0 -45
  595. package/src/superlocalmemory/storage/migrations/M015_add_pinned_column.py +0 -58
  596. package/src/superlocalmemory/storage/migrations/M016_add_scope_support.py +0 -120
  597. package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +0 -79
  598. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +0 -120
  599. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +0 -54
  600. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +0 -52
  601. package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +0 -108
  602. package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +0 -86
  603. package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +0 -194
  604. package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +0 -87
  605. package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +0 -90
  606. package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +0 -136
  607. package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +0 -163
  608. package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +0 -305
  609. package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +0 -137
  610. package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +0 -93
  611. package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +0 -80
  612. package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +0 -188
  613. package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +0 -148
  614. package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +0 -58
  615. package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +0 -113
  616. package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +0 -107
  617. package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +0 -162
  618. package/src/superlocalmemory/storage/migrations/M038_learning_feedback_channel.py +0 -77
  619. package/src/superlocalmemory/storage/migrations/M039_scene_fact_members.py +0 -137
  620. package/src/superlocalmemory/storage/migrations/M040_agent_experience_receipts.py +0 -254
  621. package/src/superlocalmemory/storage/migrations/M041_external_evidence_receipts.py +0 -189
  622. package/src/superlocalmemory/storage/migrations/M042_correction_case_ledger.py +0 -245
  623. package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +0 -512
  624. package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +0 -127
  625. package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +0 -158
  626. package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +0 -620
  627. package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +0 -306
  628. package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +0 -229
  629. package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +0 -201
  630. package/src/superlocalmemory/storage/migrations/M050_execution_learning_v2.py +0 -70
  631. package/src/superlocalmemory/storage/migrations/__init__.py +0 -103
  632. package/src/superlocalmemory/storage/migrations.py +0 -333
  633. package/src/superlocalmemory/storage/models.py +0 -500
  634. package/src/superlocalmemory/storage/projection_outbox.py +0 -346
  635. package/src/superlocalmemory/storage/quantized_store.py +0 -280
  636. package/src/superlocalmemory/storage/read_connection.py +0 -115
  637. package/src/superlocalmemory/storage/retention_policy.py +0 -860
  638. package/src/superlocalmemory/storage/schema.py +0 -1108
  639. package/src/superlocalmemory/storage/schema_code_graph.py +0 -282
  640. package/src/superlocalmemory/storage/schema_v32.py +0 -382
  641. package/src/superlocalmemory/storage/schema_v3410.py +0 -159
  642. package/src/superlocalmemory/storage/schema_v3411.py +0 -149
  643. package/src/superlocalmemory/storage/schema_v343.py +0 -315
  644. package/src/superlocalmemory/storage/schema_v345.py +0 -109
  645. package/src/superlocalmemory/storage/schema_v347.py +0 -140
  646. package/src/superlocalmemory/storage/sqlite_vectors.py +0 -169
  647. package/src/superlocalmemory/storage/v2_migrator.py +0 -466
  648. package/src/superlocalmemory/storage/write_coordinator.py +0 -949
  649. package/src/superlocalmemory/storage/write_lock.py +0 -88
  650. package/src/superlocalmemory/summaries/__init__.py +0 -37
  651. package/src/superlocalmemory/summaries/base.py +0 -267
  652. package/src/superlocalmemory/summaries/daily_reflection.py +0 -340
  653. package/src/superlocalmemory/summaries/non_answer.py +0 -223
  654. package/src/superlocalmemory/summaries/project_work_log.py +0 -440
  655. package/src/superlocalmemory/summaries/session_summary.py +0 -311
  656. package/src/superlocalmemory/trust/__init__.py +0 -0
  657. package/src/superlocalmemory/trust/gate.py +0 -171
  658. package/src/superlocalmemory/trust/provenance.py +0 -124
  659. package/src/superlocalmemory/trust/scorer.py +0 -413
  660. package/src/superlocalmemory/trust/signals.py +0 -153
  661. package/src/superlocalmemory/ui/assets/slm-icon-white.svg +0 -64
  662. package/src/superlocalmemory/ui/assets/slm-icon.svg +0 -36
  663. package/src/superlocalmemory/ui/css/brain.css +0 -409
  664. package/src/superlocalmemory/ui/css/design-system.css +0 -696
  665. package/src/superlocalmemory/ui/css/legacy-dashboard.css +0 -663
  666. package/src/superlocalmemory/ui/css/neural-glass.css +0 -1599
  667. package/src/superlocalmemory/ui/css/od-bridge.css +0 -158
  668. package/src/superlocalmemory/ui/favicon.svg +0 -36
  669. package/src/superlocalmemory/ui/index.html +0 -1638
  670. package/src/superlocalmemory/ui/js/agents.js +0 -192
  671. package/src/superlocalmemory/ui/js/auto-settings.js +0 -624
  672. package/src/superlocalmemory/ui/js/brain.js +0 -1400
  673. package/src/superlocalmemory/ui/js/clusters.js +0 -326
  674. package/src/superlocalmemory/ui/js/compliance.js +0 -307
  675. package/src/superlocalmemory/ui/js/core.js +0 -566
  676. package/src/superlocalmemory/ui/js/dashboard.js +0 -503
  677. package/src/superlocalmemory/ui/js/event-delegation.js +0 -113
  678. package/src/superlocalmemory/ui/js/events.js +0 -178
  679. package/src/superlocalmemory/ui/js/fact-detail.js +0 -142
  680. package/src/superlocalmemory/ui/js/feedback.js +0 -339
  681. package/src/superlocalmemory/ui/js/graph-event-bus.js +0 -83
  682. package/src/superlocalmemory/ui/js/graph-filters.js +0 -220
  683. package/src/superlocalmemory/ui/js/graph-ui.js +0 -214
  684. package/src/superlocalmemory/ui/js/ide-status.js +0 -115
  685. package/src/superlocalmemory/ui/js/init.js +0 -54
  686. package/src/superlocalmemory/ui/js/knowledge-graph.js +0 -945
  687. package/src/superlocalmemory/ui/js/lifecycle.js +0 -387
  688. package/src/superlocalmemory/ui/js/math-health.js +0 -114
  689. package/src/superlocalmemory/ui/js/memories.js +0 -394
  690. package/src/superlocalmemory/ui/js/memory-chat.js +0 -371
  691. package/src/superlocalmemory/ui/js/memory-timeline.js +0 -265
  692. package/src/superlocalmemory/ui/js/modal.js +0 -733
  693. package/src/superlocalmemory/ui/js/ng-entities.js +0 -298
  694. package/src/superlocalmemory/ui/js/ng-health.js +0 -208
  695. package/src/superlocalmemory/ui/js/ng-ingestion.js +0 -203
  696. package/src/superlocalmemory/ui/js/ng-mesh.js +0 -374
  697. package/src/superlocalmemory/ui/js/ng-shell.js +0 -524
  698. package/src/superlocalmemory/ui/js/ng-skills.js +0 -663
  699. package/src/superlocalmemory/ui/js/od-agents.js +0 -588
  700. package/src/superlocalmemory/ui/js/od-auth-gate.js +0 -257
  701. package/src/superlocalmemory/ui/js/od-backup.js +0 -878
  702. package/src/superlocalmemory/ui/js/od-boundedloops.js +0 -324
  703. package/src/superlocalmemory/ui/js/od-brain.js +0 -1095
  704. package/src/superlocalmemory/ui/js/od-compliance-ext.js +0 -301
  705. package/src/superlocalmemory/ui/js/od-components.js +0 -147
  706. package/src/superlocalmemory/ui/js/od-entities.js +0 -622
  707. package/src/superlocalmemory/ui/js/od-graph.js +0 -776
  708. package/src/superlocalmemory/ui/js/od-health.js +0 -579
  709. package/src/superlocalmemory/ui/js/od-mcp.js +0 -508
  710. package/src/superlocalmemory/ui/js/od-memories.js +0 -1499
  711. package/src/superlocalmemory/ui/js/od-mesh.js +0 -645
  712. package/src/superlocalmemory/ui/js/od-operations.js +0 -1268
  713. package/src/superlocalmemory/ui/js/od-ops-health.js +0 -417
  714. package/src/superlocalmemory/ui/js/od-optimize.js +0 -828
  715. package/src/superlocalmemory/ui/js/od-settings.js +0 -1275
  716. package/src/superlocalmemory/ui/js/od-shell.js +0 -819
  717. package/src/superlocalmemory/ui/js/od-skills.js +0 -600
  718. package/src/superlocalmemory/ui/js/od-team.js +0 -265
  719. package/src/superlocalmemory/ui/js/optimize.js +0 -191
  720. package/src/superlocalmemory/ui/js/profiles.js +0 -362
  721. package/src/superlocalmemory/ui/js/quick-actions.js +0 -334
  722. package/src/superlocalmemory/ui/js/recall-lab.js +0 -373
  723. package/src/superlocalmemory/ui/js/search.js +0 -86
  724. package/src/superlocalmemory/ui/js/settings.js +0 -556
  725. package/src/superlocalmemory/ui/js/timeline.js +0 -62
  726. package/src/superlocalmemory/ui/js/trust-dashboard.js +0 -225
  727. package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +0 -2018
  728. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  729. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  730. package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +0 -7
  731. package/src/superlocalmemory/ui/vendor/bootstrap.min.css +0 -6
  732. package/src/superlocalmemory/ui/vendor/d3.v7.min.js +0 -2
  733. package/src/superlocalmemory/ui/vendor/graphology-library.min.js +0 -2
  734. package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +0 -2
  735. package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +0 -8
  736. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
  737. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
  738. package/src/superlocalmemory/ui/vendor/sigma.min.js +0 -1
  739. package/src/superlocalmemory/vector/__init__.py +0 -9
  740. package/src/superlocalmemory/vector/lancedb_backend.py +0 -366
@@ -1,909 +0,0 @@
1
- # Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
2
- # Licensed under AGPL-3.0-or-later - see LICENSE file
3
- # Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
4
-
5
- """SLM Daemon — client functions for communicating with the unified daemon.
6
-
7
- The unified daemon (server/unified_daemon.py) runs as a single FastAPI/uvicorn
8
- process on port 8765, with port 8767 as a backward-compat TCP redirect.
9
-
10
- This module contains CLIENT functions used by CLI commands:
11
- - is_daemon_running(): check if daemon is alive
12
- - ensure_daemon(): start daemon if not running
13
- - stop_daemon(): gracefully stop the daemon
14
- - daemon_request(): send HTTP request to daemon
15
-
16
- The actual daemon server code is in server/unified_daemon.py.
17
-
18
- Part of Qualixar | Author: Varun Pratap Bhardwaj
19
- License: AGPL-3.0-or-later
20
- """
21
-
22
- from __future__ import annotations
23
-
24
- import json
25
- import logging
26
- import os
27
- import socket
28
- import sys
29
- import time
30
- from dataclasses import replace
31
-
32
- from superlocalmemory.infra.daemon_identity import (
33
- build_descriptor,
34
- descriptor_matches_health,
35
- descriptor_path,
36
- process_create_time_for,
37
- read_descriptor,
38
- write_descriptor,
39
- )
40
- from superlocalmemory.infra.data_root import (
41
- assert_no_durable_root_conflict,
42
- state_path,
43
- )
44
- from superlocalmemory.infra.process_identity import (
45
- compare_start_tokens,
46
- process_start_token_for,
47
- )
48
-
49
- logger = logging.getLogger(__name__)
50
-
51
- try:
52
- _DEFAULT_PORT = int(os.environ.get("SLM_DAEMON_PORT", "") or 8765)
53
- except ValueError:
54
- _DEFAULT_PORT = 8765
55
- _LEGACY_PORT = 8767 # backward-compat redirect
56
- _DEFAULT_IDLE_TIMEOUT = 0 # v3.4.3: 24/7 default (was 1800)
57
- _PID_FILE = None # test-only override; runtime resolution stays dynamic
58
- _PORT_FILE = None # test-only override; runtime resolution stays dynamic
59
- _EXPECTED_DESCRIPTOR_UNSET = object()
60
-
61
-
62
- # ---------------------------------------------------------------------------
63
- # Client: check if daemon running + send requests
64
- # ---------------------------------------------------------------------------
65
-
66
- def _is_pid_alive(pid: int) -> bool:
67
- """Cross-platform check if a process with given PID exists."""
68
- try:
69
- import psutil
70
- return psutil.pid_exists(pid)
71
- except ImportError:
72
- try:
73
- os.kill(pid, 0)
74
- return True
75
- except (ProcessLookupError, PermissionError):
76
- return False
77
-
78
-
79
- _CREATE_TIME_TOLERANCE_SECONDS = 1.0
80
-
81
-
82
- def _health_proves_descriptor_ownership(descriptor) -> bool:
83
- """Return whether the live health endpoint proves this exact daemon.
84
-
85
- This is a *stronger* ownership proof than any process-table comparison. To
86
- pass, a process listening on the descriptor's port must echo the random
87
- 128-bit ``instance_id`` and the SHA-256 fingerprint of the 256-bit
88
- capability token -- both of which exist only inside the mode-0600
89
- ``daemon.json`` -- alongside its own PID, namespace, owner and port. A
90
- process that merely inherited a recycled PID cannot produce any of that.
91
- """
92
- health = _fetch_health(descriptor.port)
93
- if health is None:
94
- return False
95
- return descriptor_matches_health(descriptor, health)
96
-
97
-
98
- def _resolve_descriptor_liveness(descriptor) -> tuple[bool, str]:
99
- """Return ``(is_alive, evidence)`` for the descriptor's recorded process.
100
-
101
- Ownership is decided by the strongest available evidence, never by the
102
- wall clock alone:
103
-
104
- 1. The PID must exist and must not be a zombie.
105
- 2. A clock-independent start token settles it exactly, with no tolerance.
106
- This is the path that fixes issue #104: under WSL2 the boot time behind
107
- ``psutil.create_time`` drifts against the wall clock during a session,
108
- so a recorded creation time stops matching the *same* live process
109
- (~35s after ~4 minutes). A start token cannot drift, so no tolerance
110
- constant is needed and none can silently expire.
111
- 3. Otherwise fall back to comparing creation times, for descriptors written
112
- by an older release and for platforms with no token (Windows, where the
113
- kernel creation time is already immune to clock adjustment).
114
- 4. A creation-time mismatch is *not* proof of PID reuse -- it is exactly
115
- what a stepped clock looks like -- so before condemning a running
116
- daemon, ask the daemon to prove its identity over loopback. Only if that
117
- cryptographic proof also fails is the process declared foreign.
118
- """
119
- if not _is_pid_alive(descriptor.pid):
120
- return False, "process_exited"
121
- try:
122
- import psutil
123
- except ImportError:
124
- # Without psutil, PID existence is the only signal there is.
125
- return True, "pid_exists_without_psutil"
126
- try:
127
- process = psutil.Process(descriptor.pid)
128
- # A terminated daemon can remain in the process table briefly as a
129
- # zombie while its parent reaps it. PID existence is therefore not
130
- # liveness and must not block a namespace-owned restart.
131
- if not process.is_running() or process.status() == psutil.STATUS_ZOMBIE:
132
- return False, "process_zombie"
133
- actual_create_time = float(process.create_time())
134
- except Exception:
135
- return False, "process_unreadable"
136
-
137
- recorded_token = getattr(descriptor, "process_start_token", None)
138
- if recorded_token:
139
- verdict = compare_start_tokens(
140
- recorded_token, process_start_token_for(descriptor.pid),
141
- )
142
- if verdict is True:
143
- return True, "start_token_match"
144
- if verdict is False:
145
- return False, "start_token_mismatch"
146
-
147
- drift = abs(actual_create_time - float(descriptor.process_create_time))
148
- if drift <= _CREATE_TIME_TOLERANCE_SECONDS:
149
- return True, "create_time_match"
150
-
151
- if _health_proves_descriptor_ownership(descriptor):
152
- logger.debug(
153
- "descriptor creation time drifted by %.3fs for pid %s; owned "
154
- "daemon confirmed by health identity instead",
155
- drift, descriptor.pid,
156
- )
157
- return True, "health_identity_match"
158
- return False, "identity_mismatch"
159
-
160
-
161
- def _descriptor_process_is_alive(descriptor) -> bool:
162
- """Reject stale descriptors when a PID has been reused by another process."""
163
- return _resolve_descriptor_liveness(descriptor)[0]
164
-
165
-
166
- def _is_port_available(port: int) -> bool:
167
- """Return whether the daemon port can be exclusively bound right now."""
168
- try:
169
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as candidate:
170
- if sys.platform == "win32":
171
- # Winsock SO_REUSEADDR can bind an address that is still
172
- # occupied, so it cannot prove shutdown completion. Request
173
- # exclusive ownership where available and otherwise use the
174
- # default non-reuse bind contract.
175
- exclusive = getattr(socket, "SO_EXCLUSIVEADDRUSE", None)
176
- if exclusive is not None:
177
- candidate.setsockopt(socket.SOL_SOCKET, exclusive, 1)
178
- else:
179
- # On POSIX, mirror Uvicorn's reuse contract so a closed
180
- # listener's TIME_WAIT sockets do not block a safe restart.
181
- candidate.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
182
- candidate.bind(("127.0.0.1", port))
183
- return True
184
- except OSError:
185
- return False
186
-
187
-
188
- def _has_tcp_listener(port: int) -> bool:
189
- """Return whether a process is actively accepting on the daemon port."""
190
- try:
191
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as candidate:
192
- candidate.settimeout(0.5)
193
- return candidate.connect_ex(("127.0.0.1", port)) == 0
194
- except OSError:
195
- return False
196
-
197
-
198
- def wait_for_owned_daemon_shutdown(
199
- descriptor,
200
- timeout: float = 25.0,
201
- *,
202
- legacy_pid: int | None = None,
203
- legacy_port: int | None = None,
204
- ) -> bool:
205
- """Wait for the stopped instance *and* its TCP listener to be gone.
206
-
207
- Restart must never spawn a replacement just because the descriptor was
208
- removed: a graceful shutdown can remove it before Uvicorn releases the
209
- port. The 25-second budget covers Uvicorn's 10-second graceful drain plus
210
- SLM worker cleanup. A descriptor carries process creation time, so PID
211
- reuse cannot make this wait target an unrelated process.
212
- """
213
- port = (
214
- descriptor.port
215
- if descriptor is not None
216
- else legacy_port if legacy_port is not None else _DEFAULT_PORT
217
- )
218
- deadline = time.monotonic() + timeout
219
- while time.monotonic() < deadline:
220
- process_alive = bool(
221
- _descriptor_process_is_alive(descriptor)
222
- if descriptor is not None
223
- else legacy_pid is not None and _is_verified_legacy_process(legacy_pid)
224
- )
225
- if not process_alive and _is_port_available(port):
226
- return True
227
- time.sleep(0.1)
228
- return False
229
-
230
-
231
- def is_daemon_running() -> bool:
232
- """Return True only for a daemon owned by this canonical data namespace.
233
-
234
- A PID or an HTTP 200 proves liveness, not ownership. V3.7 requires the
235
- private local descriptor and the health endpoint to agree on namespace,
236
- process instance, capability fingerprint, owner, PID, protocol, and port.
237
- """
238
- local_descriptor_path = descriptor_path()
239
- descriptor = read_descriptor()
240
- if descriptor is not None:
241
- if not _descriptor_process_is_alive(descriptor):
242
- return False
243
- if descriptor.state == "starting":
244
- return True
245
- health = _fetch_health(descriptor.port)
246
- return health is not None and descriptor_matches_health(descriptor, health)
247
-
248
- # A malformed or foreign descriptor must fail closed; never fall through
249
- # to legacy PID/port adoption in the same namespace.
250
- if local_descriptor_path.exists():
251
- return False
252
-
253
- legacy = _verified_legacy_health()
254
- return legacy is not None
255
-
256
-
257
- def owned_daemon_process_alive() -> bool:
258
- """Return whether an owned daemon *process* is alive, HTTP aside.
259
-
260
- ``is_daemon_running()`` additionally requires a live, matching
261
- ``/health`` response, which conflates two different questions: "is there
262
- a process I need to stop" and "is it ready to serve requests right now."
263
- A daemon whose event loop is synchronously blocked by a long-running
264
- handler (``/maintenance/run``, ``/consolidate/cognitive``) cannot answer
265
- the second for the duration of that call, but the answer to the first is
266
- still yes. Callers that only need to decide whether a stop is owed
267
- (``slm restart`` Step 1) should use this instead, so a transiently busy
268
- daemon is not skipped as "already stopped" while it keeps running and
269
- holding the port — which then made Step 3 refuse to start a second
270
- daemon on the still-occupied port and fail the whole restart.
271
- """
272
- descriptor = read_descriptor()
273
- if descriptor is not None:
274
- return _descriptor_process_is_alive(descriptor)
275
- if descriptor_path().exists():
276
- return False
277
- return _verified_legacy_health() is not None
278
-
279
-
280
- def _fetch_health(port: int) -> dict | None:
281
- """Fetch loopback health without following cross-namespace discovery."""
282
- try:
283
- import urllib.request
284
-
285
- expected_url = f"http://127.0.0.1:{port}/health"
286
- response = urllib.request.urlopen(
287
- expected_url, timeout=2,
288
- )
289
- if response.status != 200:
290
- return None
291
- geturl = getattr(response, "geturl", None)
292
- final_url = geturl() if callable(geturl) else None
293
- if final_url is not None and final_url != expected_url:
294
- return None
295
- payload = json.loads(response.read().decode())
296
- return payload if isinstance(payload, dict) else None
297
- except Exception:
298
- return None
299
-
300
-
301
- def _is_verified_legacy_process(pid: int) -> bool:
302
- """One-release bridge for a same-root V3.6 unified-daemon process."""
303
- if not _is_pid_alive(pid):
304
- return False
305
- try:
306
- import psutil
307
-
308
- process = psutil.Process(pid)
309
- command = " ".join(process.cmdline())
310
- return "superlocalmemory.server.unified_daemon" in command
311
- except Exception:
312
- return False
313
-
314
-
315
- def _verified_legacy_health() -> dict | None:
316
- """Accept legacy health only with a verified same-root daemon PID file."""
317
- pid_file = descriptor_path().with_name("daemon.pid")
318
- port_file = descriptor_path().with_name("daemon.port")
319
- try:
320
- pid = int(pid_file.read_text().strip())
321
- port = int(port_file.read_text().strip()) if port_file.exists() else _DEFAULT_PORT
322
- except (OSError, ValueError):
323
- return None
324
- if not _is_verified_legacy_process(pid):
325
- return None
326
- health = _fetch_health(port)
327
- if health is None or int(health.get("pid", -1)) != pid:
328
- return None
329
- # Identity-bearing health without a descriptor is not legacy and cannot
330
- # be adopted. It belongs to another namespace or stale state.
331
- if health.get("daemon_protocol") is not None:
332
- return None
333
- return {**health, "_legacy_port": port}
334
-
335
-
336
- def _get_port() -> int:
337
- descriptor = read_descriptor()
338
- if descriptor is not None:
339
- return descriptor.port
340
- if descriptor_path().exists():
341
- return _DEFAULT_PORT
342
- legacy = _verified_legacy_health()
343
- if legacy is not None:
344
- return int(legacy["_legacy_port"])
345
- return _DEFAULT_PORT
346
-
347
-
348
- class DaemonRefused(RuntimeError):
349
- """The daemon answered, and the answer was no.
350
-
351
- Raised for HTTP 401 and 403 only. Distinct from ``daemon_request``
352
- returning ``None``, which means the daemon could not be reached or did not
353
- answer usefully. Callers that fall back to a direct engine write MUST let
354
- this propagate or exit on it: falling back after a refusal performs, as the
355
- machine owner, exactly the write the workspace just declined.
356
- """
357
-
358
- def __init__(self, status: int, path: str = "") -> None:
359
- self.status = int(status)
360
- self.path = path
361
- super().__init__(
362
- f"the daemon refused this request (HTTP {status})"
363
- + (f" for {path}" if path else "")
364
- )
365
-
366
-
367
- class DaemonConflict(RuntimeError):
368
- """A deterministic daemon conflict that the caller must resolve."""
369
-
370
- def __init__(self, detail: str) -> None:
371
- self.detail = detail or "daemon request conflicted with current state"
372
- super().__init__(self.detail)
373
-
374
-
375
- def daemon_request(
376
- method: str,
377
- path: str,
378
- body: dict | None = None,
379
- *,
380
- timeout_seconds: float = 30.0,
381
- expected_descriptor=_EXPECTED_DESCRIPTOR_UNSET,
382
- expected_legacy: dict | None = None,
383
- verify_health: bool = True,
384
- preserve_conflict: bool = False,
385
- ) -> dict | None:
386
- """Send a request only after validating the owned daemon identity.
387
-
388
- ``verify_health`` — when True (the default), a ``GET /health`` preflight
389
- must succeed and match the descriptor before the real request is sent.
390
- That preflight needs the daemon's event loop to be free to answer HTTP,
391
- which is a *readiness* question, not a *liveness* one: a daemon whose
392
- loop is synchronously blocked by a long-running handler (e.g.
393
- ``/maintenance/run``, ``/consolidate/cognitive``, neither of which is
394
- offloaded to a thread the way ``/recall`` was for exactly this reason in
395
- v3.4.52) cannot answer /health for the duration of that call even though
396
- the process is fully alive and listening. Callers that have already
397
- proven process-level ownership some other way (e.g. ``stop_daemon()`` via
398
- ``_descriptor_process_is_alive``) should pass ``verify_health=False`` so a
399
- busy-but-alive daemon does not get misreported as not running. Only
400
- meaningful for the descriptor path — the legacy bridge has no capability
401
- header and still needs health to identify its target.
402
- """
403
- legacy = None
404
- if expected_legacy is not None:
405
- # Legacy daemons have no capability header. Bind the compatibility
406
- # request to the captured PID+port and refuse to adopt a replacement
407
- # descriptor or a different legacy process during this stop.
408
- if read_descriptor() is not None:
409
- return None
410
- current_legacy = _verified_legacy_health()
411
- if current_legacy is None or (
412
- int(current_legacy.get("pid", -1))
413
- != int(expected_legacy.get("pid", -2))
414
- or int(current_legacy.get("_legacy_port", -1))
415
- != int(expected_legacy.get("_legacy_port", -2))
416
- ):
417
- return None
418
- descriptor = None
419
- legacy = current_legacy
420
- else:
421
- descriptor = (
422
- read_descriptor()
423
- if expected_descriptor is _EXPECTED_DESCRIPTOR_UNSET
424
- else expected_descriptor
425
- )
426
- capability: str | None = None
427
- target_instance: str | None = None
428
- if descriptor is not None:
429
- if verify_health:
430
- health = _fetch_health(descriptor.port)
431
- if health is None or not descriptor_matches_health(descriptor, health):
432
- return None
433
- if method.upper() == "GET" and path == "/health":
434
- return health
435
- port = descriptor.port
436
- capability = descriptor.capability
437
- target_instance = descriptor.instance_id
438
- elif descriptor_path().exists():
439
- return None
440
- else:
441
- legacy = legacy or _verified_legacy_health()
442
- if legacy is None:
443
- return None
444
- if method.upper() == "GET" and path == "/health":
445
- return {key: value for key, value in legacy.items() if key != "_legacy_port"}
446
- port = int(legacy["_legacy_port"])
447
- try:
448
- import urllib.error
449
- import urllib.request
450
- url = f"http://127.0.0.1:{port}{path}"
451
- data = json.dumps(body).encode() if body else None
452
- headers = {"Content-Type": "application/json"} if data else {}
453
- if capability is not None and target_instance is not None:
454
- headers["X-SLM-Daemon-Capability"] = capability
455
- headers["X-SLM-Target-Instance"] = target_instance
456
- # Daemon ownership proves that this CLI targets the local instance; it
457
- # does not replace a dashboard user's profile-scoped authorization in
458
- # governed workspaces. The user opts in by supplying an explicit
459
- # session through the process environment (never logged or persisted).
460
- user_session = os.environ.get("SLM_USER_SESSION", "").strip()
461
- if user_session:
462
- headers["X-SLM-User-Session"] = user_session
463
- req = urllib.request.Request(url, data=data, headers=headers, method=method)
464
- resp = urllib.request.urlopen(req, timeout=timeout_seconds)
465
- return json.loads(resp.read().decode())
466
- except urllib.error.HTTPError as exc:
467
- # A refusal is an answer, not a failure to get one. Returning None here
468
- # made "you are not allowed to do this" indistinguishable from "the
469
- # daemon is not running", and every caller that falls back to a local
470
- # engine write treated the first as the second -- so a workspace that
471
- # required a login refused the write over HTTP and then performed it
472
- # locally as the machine owner.
473
- if exc.code in (401, 403):
474
- raise DaemonRefused(exc.code, path) from exc
475
- if exc.code == 409 and preserve_conflict:
476
- detail = "daemon request conflicted with current state"
477
- try:
478
- payload = json.loads(exc.read().decode())
479
- if isinstance(payload, dict) and payload.get("detail"):
480
- detail = str(payload["detail"])
481
- except Exception:
482
- pass
483
- raise DaemonConflict(detail) from exc
484
- return None
485
- except Exception:
486
- return None
487
-
488
-
489
- _LOCK_FILE = None # test-only override; runtime resolution stays dynamic
490
-
491
-
492
- def _pid_file_path():
493
- return _PID_FILE or state_path("daemon.pid")
494
-
495
-
496
- def _port_file_path():
497
- return _PORT_FILE or state_path("daemon.port")
498
-
499
-
500
- def _lock_file_path():
501
- return _LOCK_FILE or state_path("daemon.lock")
502
-
503
-
504
- def _start_daemon_subprocess() -> bool:
505
- """Spawn the unified daemon subprocess and wait for readiness.
506
-
507
- v3.4.42: Extracted from ensure_daemon() so callers that already hold
508
- daemon.lock (e.g. cmd_restart Step 2) can start the daemon WITHOUT
509
- triggering a second flock acquisition. BSD-style flock blocks per-fd
510
- even within the same process, so the previous code path produced a
511
- self-deadlock when called from Step 3 of `slm restart`: the lock held
512
- by Step 2 caused ensure_daemon's own flock to fail with EWOULDBLOCK,
513
- falling into the wait-for-someone-else branch and timing out at 60s
514
- even though the daemon would have started cleanly.
515
-
516
- PRECONDITION: caller has either acquired daemon.lock OR is certain no
517
- other CLI/MCP process is racing to start a daemon (e.g. we just killed
518
- everything in `slm restart` Step 1).
519
-
520
- Returns True if daemon is reachable on the health endpoint within
521
- 60 seconds, False otherwise.
522
- """
523
- if is_daemon_running():
524
- return True
525
- # Never create a descriptor for a child that cannot own the listener.
526
- # A closed connection in TIME_WAIT is not a listener and is safe: the
527
- # server reserves its socket with SO_REUSEADDR during bootstrap.
528
- if _has_tcp_listener(_DEFAULT_PORT):
529
- logger.warning("daemon port %d is already owned; refusing a second start", _DEFAULT_PORT)
530
- return False
531
- assert_no_durable_root_conflict()
532
-
533
- import subprocess
534
-
535
- from superlocalmemory import __version__ as _slm_version
536
- # v3.6.9 (#33): pass SLM_DAEMON_PORT as explicit --port= so the daemon
537
- # binds the right port even when the env var reaches the subprocess.
538
- _target_port = _DEFAULT_PORT
539
- cmd = [
540
- sys.executable, "-m", "superlocalmemory.server.unified_daemon",
541
- "--start", f"--port={_target_port}",
542
- ]
543
- log_dir = state_path("logs")
544
- log_dir.mkdir(parents=True, exist_ok=True)
545
- log_file = log_dir / "daemon.log"
546
-
547
- kwargs: dict = {}
548
- if sys.platform == "win32":
549
- kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
550
- else:
551
- kwargs["start_new_session"] = True
552
-
553
- # v3.4.60: Force OMP_NUM_THREADS=1 in daemon env BEFORE Python imports
554
- # numpy/torch/lightgbm. Setting it in __init__.py is too late on M5 Pro —
555
- # by the time superlocalmemory.__init__ runs, libomp has already been
556
- # initialized by an earlier import, causing the SIGSEGV at
557
- # __kmp_suspend_initialize_thread when lightgbm forks its worker pool.
558
- # Forcing serial OpenMP eliminates the parallel barrier race entirely.
559
- daemon_env = os.environ.copy()
560
- daemon_env["OMP_NUM_THREADS"] = "1"
561
- daemon_env["KMP_DUPLICATE_LIB_OK"] = "TRUE"
562
- bootstrap_descriptor = build_descriptor(
563
- port=_target_port,
564
- version=_slm_version,
565
- pid=os.getpid(),
566
- state="starting",
567
- )
568
- daemon_env["SLM_DAEMON_INSTANCE_ID"] = bootstrap_descriptor.instance_id
569
- daemon_env["SLM_DAEMON_CAPABILITY"] = bootstrap_descriptor.capability
570
- kwargs["env"] = daemon_env
571
-
572
- with open(log_file, "a") as lf:
573
- proc = subprocess.Popen(cmd, stdout=lf, stderr=lf, **kwargs)
574
-
575
- # Publish the exact child identity immediately so concurrent callers know
576
- # this namespace is warming up. If the child won the race and already
577
- # published the same instance as ready, never overwrite it with starting.
578
- child_descriptor = replace(
579
- bootstrap_descriptor,
580
- pid=proc.pid,
581
- process_create_time=process_create_time_for(proc.pid),
582
- process_start_token=process_start_token_for(proc.pid),
583
- )
584
- current = read_descriptor()
585
- if not (
586
- current is not None
587
- and current.instance_id == child_descriptor.instance_id
588
- and current.pid == child_descriptor.pid
589
- and current.state == "ready"
590
- ):
591
- write_descriptor(child_descriptor)
592
-
593
- # One-release compatibility mirrors; never sufficient for ownership.
594
- _pid_file_path().write_text(str(proc.pid))
595
- _port_file_path().write_text(str(_target_port))
596
-
597
- return _wait_for_daemon(timeout=60)
598
-
599
-
600
- def ensure_daemon(*, port: int | None = None) -> bool:
601
- """Start daemon if not running. Returns True if daemon is ready.
602
-
603
- ``port`` — when supplied, the daemon is started (or verified) on this port
604
- instead of the configured default. The dashboard passes its own ``--port``
605
- here so the bind authority matches the URL shown to the user.
606
-
607
- v3.4.4 BULLETPROOF:
608
- 1. If PID alive → return True immediately (even if warming up)
609
- 2. File lock prevents two callers from starting concurrent daemons
610
- 3. After starting, waits for PID file (not health check) — fast detection
611
- 4. Cross-platform: macOS + Windows + Linux
612
-
613
- v3.4.42: Refactored to delegate the actual subprocess start to
614
- `_start_daemon_subprocess()`. Callers that already hold daemon.lock
615
- (e.g. `slm restart` Step 3) should call that helper directly to avoid
616
- the same-process flock self-deadlock that returned a false-negative
617
- "failed to start" while the daemon was actually starting cleanly.
618
- """
619
- if is_daemon_running():
620
- return True
621
- if (
622
- os.environ.get("SLM_TEST_ISOLATION") == "1"
623
- and os.environ.get("SLM_TEST_ALLOW_DAEMON_SPAWN") != "1"
624
- ):
625
- logger.debug(
626
- "pytest isolation blocked daemon spawn; use an owned daemon fixture",
627
- )
628
- return False
629
-
630
- # File lock — prevent concurrent starts from multiple CLI/MCP calls
631
- lock_fd = None
632
- try:
633
- lock_file = _lock_file_path()
634
- lock_file.parent.mkdir(parents=True, exist_ok=True)
635
- lock_fd = open(lock_file, "w")
636
-
637
- # Cross-platform file locking
638
- if sys.platform == "win32":
639
- import msvcrt
640
- try:
641
- msvcrt.locking(lock_fd.fileno(), msvcrt.LK_NBLCK, 1)
642
- except (IOError, OSError):
643
- # Another process is starting the daemon — just wait for it
644
- lock_fd.close()
645
- return _wait_for_daemon(timeout=60)
646
- else:
647
- import fcntl
648
- try:
649
- fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
650
- except (IOError, OSError):
651
- lock_fd.close()
652
- return _wait_for_daemon(timeout=60)
653
-
654
- # Re-check after acquiring lock (another process may have started it)
655
- if is_daemon_running():
656
- return True
657
-
658
- # v3.6.9 (#36): TCP-level check catches a systemd-started daemon that
659
- # has bound the port but hasn't written a PID file yet (e.g. different
660
- # HOME for the service user vs. the SSH user). If the port is already
661
- # bound, don't start a second daemon — wait for HTTP readiness instead.
662
- try:
663
- import socket as _socket
664
- with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as _s:
665
- _s.settimeout(1)
666
- if _s.connect_ex(("127.0.0.1", _DEFAULT_PORT)) == 0:
667
- return _wait_for_daemon(timeout=30)
668
- except Exception:
669
- pass
670
-
671
- # Start unified daemon in background — delegated to helper so the
672
- # same logic can be reused by callers that already hold the lock.
673
- return _start_daemon_subprocess()
674
-
675
- except Exception as exc:
676
- # Daemon auto-start is the entry point for dashboard / mesh /
677
- # health features; failure here silently disables all of them.
678
- # Log at WARNING so operators can see it in production logs.
679
- logger.warning("ensure_daemon error: %s (run `slm doctor`)", exc)
680
- return False
681
- finally:
682
- if lock_fd:
683
- try:
684
- lock_fd.close()
685
- except Exception:
686
- pass
687
- try:
688
- _lock_file_path().unlink(missing_ok=True)
689
- except Exception:
690
- pass
691
-
692
-
693
- def _wait_for_daemon(timeout: int = 60) -> bool:
694
- """Wait for matching owned health; liveness alone is never readiness."""
695
- for _ in range(timeout * 2): # check every 0.5s
696
- time.sleep(0.5)
697
- descriptor = read_descriptor()
698
- if descriptor is not None:
699
- if not _descriptor_process_is_alive(descriptor):
700
- continue
701
- health = _fetch_health(descriptor.port)
702
- if health is not None and descriptor_matches_health(descriptor, health):
703
- return True
704
- continue
705
- if descriptor_path().exists():
706
- continue
707
- if _verified_legacy_health() is not None:
708
- return True
709
- return False
710
-
711
-
712
- _GENERIC_UNAVAILABLE = {
713
- "reason": "unknown",
714
- "message": "Owned daemon is unavailable; retry later.",
715
- "hint": "Run `slm doctor`, then `slm restart` if it stays down.",
716
- }
717
-
718
- _LIVENESS_DIAGNOSIS = {
719
- "process_exited": (
720
- "daemon_process_exited",
721
- "the recorded daemon process (pid {pid}) is no longer running",
722
- "Start it again with `slm start`.",
723
- ),
724
- "process_zombie": (
725
- "daemon_process_exited",
726
- "the recorded daemon process (pid {pid}) has exited and is awaiting "
727
- "reaping by its parent",
728
- "Start it again with `slm start`.",
729
- ),
730
- "process_unreadable": (
731
- "daemon_process_unreadable",
732
- "the recorded daemon process (pid {pid}) could not be inspected; it "
733
- "may belong to another user",
734
- "Run `slm restart` to publish a fresh descriptor.",
735
- ),
736
- "start_token_mismatch": (
737
- "pid_reused_by_another_process",
738
- "pid {pid} is alive but is a different process than the daemon that "
739
- "wrote {path}; the daemon exited and its pid was recycled",
740
- "Run `slm restart` to publish a fresh descriptor.",
741
- ),
742
- "identity_mismatch": (
743
- "daemon_identity_mismatch",
744
- "pid {pid} did not match the process identity recorded in {path} and "
745
- "the process on port {port} did not prove it owns that identity; the "
746
- "recorded creation time can also diverge on its own if this machine's "
747
- "clock is stepped (common under WSL2)",
748
- "Run `slm restart` to publish a fresh descriptor.",
749
- ),
750
- }
751
-
752
-
753
- def describe_daemon_unavailability() -> dict[str, str]:
754
- """Explain *why* the owned daemon cannot be used, in actionable terms.
755
-
756
- "Owned daemon is unavailable" is true of a stopped daemon, a recycled PID,
757
- an unreachable port and an identity mismatch alike, which left issue #104's
758
- reporter with nothing to act on. This names the specific evidence instead.
759
- Diagnosis is best-effort and never raises: a broken diagnosis must not
760
- replace the caller's real error.
761
- """
762
- try:
763
- return _describe_daemon_unavailability()
764
- except Exception: # noqa: BLE001 - diagnosis is advisory only
765
- return dict(_GENERIC_UNAVAILABLE)
766
-
767
-
768
- def _describe_daemon_unavailability() -> dict[str, str]:
769
- path = descriptor_path()
770
- descriptor = read_descriptor()
771
- if descriptor is None:
772
- if path.exists():
773
- return {
774
- "reason": "descriptor_unusable",
775
- "message": (
776
- f"{path} is unreadable, malformed, or belongs to another "
777
- f"data root or user."
778
- ),
779
- "hint": "Run `slm restart` to publish a fresh descriptor.",
780
- }
781
- if _verified_legacy_health() is not None:
782
- return {
783
- "reason": "legacy_daemon_request_failed",
784
- "message": (
785
- "a pre-descriptor daemon answered health but rejected or "
786
- "dropped the request."
787
- ),
788
- "hint": "Run `slm restart` to upgrade it to an owned daemon.",
789
- }
790
- return {
791
- "reason": "no_daemon",
792
- "message": f"no daemon is registered for this data root ({path} is absent).",
793
- "hint": "Run `slm start`.",
794
- }
795
-
796
- alive, evidence = _resolve_descriptor_liveness(descriptor)
797
- if not alive:
798
- reason, template, hint = _LIVENESS_DIAGNOSIS.get(
799
- evidence,
800
- (
801
- "daemon_identity_mismatch",
802
- "pid {pid} did not match the identity recorded in {path}",
803
- "Run `slm restart` to publish a fresh descriptor.",
804
- ),
805
- )
806
- return {
807
- "reason": reason,
808
- "message": template.format(
809
- pid=descriptor.pid, port=descriptor.port, path=path,
810
- ) + ".",
811
- "hint": hint,
812
- }
813
-
814
- health = _fetch_health(descriptor.port)
815
- if health is None:
816
- return {
817
- "reason": "daemon_unreachable",
818
- "message": (
819
- f"the owned daemon (pid {descriptor.pid}) is running but did "
820
- f"not answer http://127.0.0.1:{descriptor.port}/health within "
821
- f"2s."
822
- ),
823
- "hint": (
824
- "Check `slm logs` for a stalled request, or `slm restart` if "
825
- "it stays unresponsive."
826
- ),
827
- }
828
- if not descriptor_matches_health(descriptor, health):
829
- return {
830
- "reason": "port_owned_by_another_daemon",
831
- "message": (
832
- f"port {descriptor.port} answered health but with a different "
833
- f"daemon identity than {path} records."
834
- ),
835
- "hint": (
836
- "Another SuperLocalMemory instance holds that port. Stop it, "
837
- "or set SLM_DAEMON_PORT to a free port."
838
- ),
839
- }
840
- return {
841
- "reason": "request_rejected",
842
- "message": (
843
- f"the owned daemon (pid {descriptor.pid}) is healthy but rejected "
844
- f"or dropped this request."
845
- ),
846
- "hint": "Check `slm logs` for the failing request.",
847
- }
848
-
849
-
850
- def stop_daemon() -> bool:
851
- """Stop only the daemon proven to belong to this data namespace.
852
-
853
- Machine-wide process-name scans are forbidden: they can kill another SLM
854
- installation or a user's live workers during tests. V3.7 uses the owned
855
- HTTP capability; the daemon itself terminates its child process tree.
856
- Success means the owned process exited and released its listener, not just
857
- that the asynchronous stop request was accepted.
858
-
859
- A busy daemon is not a dead daemon. ``daemon_request()`` normally
860
- preflights every call with ``GET /health`` before sending it, but that
861
- preflight needs the daemon's single-threaded event loop to be free to
862
- answer HTTP. ``/maintenance/run`` and ``/consolidate/cognitive`` run
863
- multi-second (sometimes multi-minute) synchronous work directly inline in
864
- their handlers with no thread offload, which blocks *every* request on
865
- that loop, health included, for as long as they run. Reproduced live: a
866
- genuine ``/maintenance/run`` call held the loop long enough that 15/15
867
- health polls during the window timed out at exactly the 2s cap while
868
- ``ps``/``lsof`` proved the process never stopped listening — which is
869
- exactly the "Daemon was not running" false report this fixes. Process
870
- liveness (PID + clock-independent start token, proven below via
871
- ``_descriptor_process_is_alive``) is the fact that actually matters for
872
- "should I try to stop this," so it is checked directly and the mutating
873
- ``/stop`` POST is sent with ``verify_health=False`` once that is proven —
874
- the daemon still authenticates the request by its capability header on
875
- arrival, so this loses no ownership guarantee, only the redundant,
876
- stall-prone preflight round trip.
877
- """
878
- descriptor = read_descriptor()
879
- legacy = _verified_legacy_health() if descriptor is None else None
880
- if descriptor is None and legacy is None:
881
- return False
882
- if descriptor is not None:
883
- if not _descriptor_process_is_alive(descriptor):
884
- return False
885
- response = daemon_request(
886
- "POST",
887
- "/stop",
888
- expected_descriptor=descriptor,
889
- verify_health=False,
890
- )
891
- else:
892
- if legacy is None:
893
- return False
894
- response = daemon_request(
895
- "POST",
896
- "/stop",
897
- expected_legacy=legacy,
898
- )
899
- if not response or response.get("status") != "stopping":
900
- return False
901
- if descriptor is not None:
902
- return wait_for_owned_daemon_shutdown(descriptor)
903
- if legacy is None:
904
- return False
905
- return wait_for_owned_daemon_shutdown(
906
- None,
907
- legacy_pid=int(legacy["pid"]),
908
- legacy_port=int(legacy["_legacy_port"]),
909
- )