superlocalmemory 3.6.22 → 3.7.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 +52 -0
- package/README.md +275 -72
- package/bin/slm-npm +43 -89
- package/docs/pi-dev-integration.md +43 -0
- package/ide/configs/antigravity-mcp.json +2 -2
- package/ide/configs/chatgpt-desktop-mcp.json +1 -1
- package/ide/configs/claude-desktop-mcp.json +2 -2
- package/ide/configs/windsurf-mcp.json +2 -2
- package/ide/hooks/context-hook.js +6 -2
- package/ide/hooks/post-recall-hook.js +7 -3
- package/ide/hooks/tool-event-hook.sh +2 -1
- package/package.json +19 -10
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/_GENERATED.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/pyproject.toml +40 -8
- package/scripts/postinstall-interactive.js +17 -94
- package/scripts/postinstall.js +185 -258
- package/scripts/preuninstall.js +9 -50
- package/src/superlocalmemory/__init__.py +2 -2
- package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
- package/src/superlocalmemory/attribution/signer.py +34 -19
- package/src/superlocalmemory/attribution/watermark.py +1 -1
- package/src/superlocalmemory/cli/_lazy_init.py +3 -5
- package/src/superlocalmemory/cli/commands.py +490 -195
- package/src/superlocalmemory/cli/context_commands.py +5 -4
- package/src/superlocalmemory/cli/daemon.py +282 -187
- package/src/superlocalmemory/cli/db_migrate.py +3 -1
- package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
- package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
- package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
- package/src/superlocalmemory/cli/main.py +128 -31
- package/src/superlocalmemory/cli/pending_store.py +54 -38
- package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
- package/src/superlocalmemory/cli/service_installer.py +57 -52
- package/src/superlocalmemory/cli/setup_wizard.py +142 -88
- package/src/superlocalmemory/cli/version_banner.py +2 -1
- package/src/superlocalmemory/code_graph/config.py +3 -1
- package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
- package/src/superlocalmemory/core/config.py +65 -20
- package/src/superlocalmemory/core/consolidation_engine.py +9 -7
- package/src/superlocalmemory/core/context_cache.py +56 -8
- package/src/superlocalmemory/core/derivation_lineage.py +246 -0
- package/src/superlocalmemory/core/embedding_worker.py +32 -20
- package/src/superlocalmemory/core/embeddings.py +54 -18
- package/src/superlocalmemory/core/engine.py +150 -104
- package/src/superlocalmemory/core/engine_ingestion.py +513 -0
- package/src/superlocalmemory/core/engine_wiring.py +2 -0
- package/src/superlocalmemory/core/evidence_bundle.py +526 -0
- package/src/superlocalmemory/core/fact_consolidator.py +5 -11
- package/src/superlocalmemory/core/graph_analyzer.py +2 -2
- package/src/superlocalmemory/core/health_monitor.py +4 -2
- package/src/superlocalmemory/core/ingestion_command.py +636 -0
- package/src/superlocalmemory/core/injection.py +69 -18
- package/src/superlocalmemory/core/lifecycle_state.py +153 -0
- package/src/superlocalmemory/core/maintenance.py +23 -22
- package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
- package/src/superlocalmemory/core/mutations.py +143 -0
- package/src/superlocalmemory/core/platform_utils.py +7 -4
- package/src/superlocalmemory/core/ram_lock.py +16 -5
- package/src/superlocalmemory/core/rate_limit.py +1 -1
- package/src/superlocalmemory/core/recall_pipeline.py +60 -101
- package/src/superlocalmemory/core/recall_worker.py +76 -59
- package/src/superlocalmemory/core/registry.py +1 -1
- package/src/superlocalmemory/core/scale_engine.py +293 -0
- package/src/superlocalmemory/core/score_contract.py +62 -0
- package/src/superlocalmemory/core/security_primitives.py +3 -1
- package/src/superlocalmemory/core/slm_disabled.py +3 -5
- package/src/superlocalmemory/core/store_pipeline.py +172 -40
- package/src/superlocalmemory/core/tier_manager.py +32 -20
- package/src/superlocalmemory/core/worker_pool.py +13 -4
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
- package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
- package/src/superlocalmemory/encoding/auto_linker.py +1 -1
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
- package/src/superlocalmemory/encoding/consolidator.py +22 -5
- package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
- package/src/superlocalmemory/encoding/foresight.py +2 -0
- package/src/superlocalmemory/encoding/graph_builder.py +1 -1
- package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
- package/src/superlocalmemory/evaluation/__init__.py +13 -0
- package/src/superlocalmemory/evaluation/calibration.py +308 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
- package/src/superlocalmemory/graph/cozo_backend.py +256 -23
- package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
- package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
- package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
- package/src/superlocalmemory/hooks/auto_recall.py +31 -6
- package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
- package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
- package/src/superlocalmemory/hooks/claude_code_hooks.py +126 -39
- package/src/superlocalmemory/hooks/codex_assets.py +59 -0
- package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
- package/src/superlocalmemory/hooks/context_payload.py +1 -1
- package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
- package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
- package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
- package/src/superlocalmemory/hooks/hook_handlers.py +241 -55
- package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
- package/src/superlocalmemory/hooks/session_registry.py +15 -8
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
- package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
- package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
- package/src/superlocalmemory/infra/auth_middleware.py +38 -5
- package/src/superlocalmemory/infra/backup.py +7 -5
- package/src/superlocalmemory/infra/cloud_backup.py +18 -8
- package/src/superlocalmemory/infra/daemon_identity.py +248 -0
- package/src/superlocalmemory/infra/data_root.py +199 -0
- package/src/superlocalmemory/infra/event_bus.py +3 -1
- package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
- package/src/superlocalmemory/infra/process_reaper.py +23 -0
- package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
- package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
- package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/credentials.py +14 -7
- package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
- package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
- package/src/superlocalmemory/learning/ensemble.py +11 -0
- package/src/superlocalmemory/learning/entity_compiler.py +1 -1
- package/src/superlocalmemory/learning/feedback.py +1 -1
- package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
- package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
- package/src/superlocalmemory/learning/ranker.py +4 -1
- package/src/superlocalmemory/learning/source_quality.py +1 -1
- package/src/superlocalmemory/learning/trigram_index.py +3 -2
- package/src/superlocalmemory/llm/backbone.py +13 -8
- package/src/superlocalmemory/math/ebbinghaus.py +1 -1
- package/src/superlocalmemory/math/fisher.py +1 -1
- package/src/superlocalmemory/math/fisher_quantized.py +1 -1
- package/src/superlocalmemory/math/hopfield.py +1 -1
- package/src/superlocalmemory/math/langevin.py +1 -1
- package/src/superlocalmemory/math/polar_quant.py +3 -4
- package/src/superlocalmemory/math/qjl.py +1 -1
- package/src/superlocalmemory/math/sheaf.py +1 -1
- package/src/superlocalmemory/math/turbo_quant.py +3 -2
- package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
- package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
- package/src/superlocalmemory/mcp/http_transport.py +53 -0
- package/src/superlocalmemory/mcp/server.py +39 -13
- package/src/superlocalmemory/mcp/shared.py +69 -3
- package/src/superlocalmemory/mcp/tools_active.py +141 -31
- package/src/superlocalmemory/mcp/tools_core.py +128 -29
- package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
- package/src/superlocalmemory/mcp/tools_learning.py +42 -2
- package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
- package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
- package/src/superlocalmemory/mcp/tools_v28.py +23 -2
- package/src/superlocalmemory/mcp/tools_v3.py +26 -1
- package/src/superlocalmemory/mcp/tools_v33.py +56 -17
- package/src/superlocalmemory/mesh/broker.py +2 -0
- package/src/superlocalmemory/mesh/remote_sync.py +50 -12
- package/src/superlocalmemory/optimize/cache/manager.py +77 -1
- package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
- package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
- package/src/superlocalmemory/optimize/compress/router.py +6 -1
- package/src/superlocalmemory/optimize/config/__init__.py +5 -0
- package/src/superlocalmemory/optimize/config/store.py +6 -4
- package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
- package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
- package/src/superlocalmemory/optimize/proxy/server.py +2 -2
- package/src/superlocalmemory/optimize/storage/db.py +14 -13
- package/src/superlocalmemory/retrieval/agentic.py +1 -1
- package/src/superlocalmemory/retrieval/ann_index.py +1 -1
- package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
- package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
- package/src/superlocalmemory/retrieval/engine.py +169 -79
- package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
- package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
- package/src/superlocalmemory/retrieval/fusion.py +1 -1
- package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
- package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
- package/src/superlocalmemory/retrieval/reranker.py +56 -20
- package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
- package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
- package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
- package/src/superlocalmemory/retrieval/strategy.py +1 -1
- package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
- package/src/superlocalmemory/retrieval/vector_store.py +1 -1
- package/src/superlocalmemory/server/api.py +10 -7
- package/src/superlocalmemory/server/bandit_loops.py +4 -2
- package/src/superlocalmemory/server/recall_serializer.py +24 -0
- package/src/superlocalmemory/server/route_mutations.py +84 -0
- package/src/superlocalmemory/server/routes/agents.py +8 -6
- package/src/superlocalmemory/server/routes/brain.py +14 -12
- package/src/superlocalmemory/server/routes/chat.py +29 -12
- package/src/superlocalmemory/server/routes/data_io.py +55 -24
- package/src/superlocalmemory/server/routes/helpers.py +29 -4
- package/src/superlocalmemory/server/routes/ingest.py +53 -36
- package/src/superlocalmemory/server/routes/memories.py +104 -43
- package/src/superlocalmemory/server/routes/mesh.py +31 -0
- package/src/superlocalmemory/server/routes/profiles.py +26 -4
- package/src/superlocalmemory/server/routes/tiers.py +43 -11
- package/src/superlocalmemory/server/routes/timeline.py +5 -1
- package/src/superlocalmemory/server/routes/v3_api.py +76 -21
- package/src/superlocalmemory/server/security_middleware.py +1 -1
- package/src/superlocalmemory/server/ui.py +6 -3
- package/src/superlocalmemory/server/unified_daemon.py +680 -293
- package/src/superlocalmemory/server/write_identity.py +147 -0
- package/src/superlocalmemory/storage/access_log.py +4 -3
- package/src/superlocalmemory/storage/database.py +118 -25
- package/src/superlocalmemory/storage/migration_runner.py +84 -1
- package/src/superlocalmemory/storage/migration_v33.py +1 -1
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
- package/src/superlocalmemory/storage/models.py +16 -0
- package/src/superlocalmemory/storage/quantized_store.py +20 -3
- package/src/superlocalmemory/storage/v2_migrator.py +5 -3
- package/src/superlocalmemory/ui/favicon.svg +5 -0
- package/src/superlocalmemory/ui/index.html +1 -0
- package/src/superlocalmemory/ui/js/compliance.js +1 -1
- package/src/superlocalmemory/ui/js/core.js +49 -8
- package/src/superlocalmemory/ui/js/dashboard.js +23 -2
- package/src/superlocalmemory/ui/js/feedback.js +1 -1
- package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
- package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
- package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
- package/src/superlocalmemory/ui/js/settings.js +4 -2
- package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
- package/bin/slm +0 -59
- package/bin/slm.bat +0 -77
- package/bin/slm.cmd +0 -5
- package/ide/integrations/langchain/README.md +0 -106
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
- package/ide/integrations/langchain/pyproject.toml +0 -38
- package/ide/integrations/langchain/tests/__init__.py +0 -3
- package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
- package/ide/integrations/langchain/tests/test_security.py +0 -117
- package/ide/integrations/llamaindex/README.md +0 -81
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
- package/ide/integrations/llamaindex/pyproject.toml +0 -43
- package/ide/integrations/llamaindex/tests/__init__.py +0 -3
- package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
- package/ide/integrations/llamaindex/tests/test_security.py +0 -241
- package/plugin-src/.mcp.json +0 -12
- package/plugin-src/agents/slm-memory-advisor.md +0 -44
- package/plugin-src/agents/slm-optimize-advisor.md +0 -38
- package/plugin-src/hooks/.gitkeep +0 -0
- package/plugin-src/hooks/hooks.json +0 -23
- package/plugin-src/manifest.json +0 -25
- package/plugin-src/requirements.txt +0 -1
- package/plugin-src/rules/CLAUDE.md.fragment +0 -44
- package/plugin-src/scripts/ensure-venv.bat +0 -122
- package/plugin-src/scripts/ensure-venv.sh +0 -105
- package/plugin-src/scripts/slm-launch +0 -15
- package/plugin-src/scripts/slm-launch.bat +0 -17
- package/plugin-src/settings.json +0 -16
- package/plugin-src/skills/slm-cache/SKILL.md +0 -140
- package/plugin-src/skills/slm-compress/SKILL.md +0 -143
- package/plugin-src/skills/slm-graph/SKILL.md +0 -300
- package/plugin-src/skills/slm-recall/SKILL.md +0 -204
- package/plugin-src/skills/slm-remember/SKILL.md +0 -194
- package/plugin-src/skills/slm-session/SKILL.md +0 -207
- package/plugin-src/skills/slm-status/SKILL.md +0 -149
- package/scripts/__tests__/build-plugin.test.mjs +0 -613
- package/scripts/_savings_math.py +0 -270
- package/scripts/build-dmg.sh +0 -417
- package/scripts/build-plugin.js +0 -742
- package/scripts/build-slm-hook.ps1 +0 -40
- package/scripts/build-slm-hook.sh +0 -45
- package/scripts/build_entry.py +0 -452
- package/scripts/ci/stage5b_gate.sh +0 -50
- package/scripts/dogfood_savings.py +0 -490
- package/scripts/generate-thumbnails.py +0 -218
- package/scripts/install-skills.ps1 +0 -4
- package/scripts/install-skills.sh +0 -5
- package/scripts/install.ps1 +0 -701
- package/scripts/install.sh +0 -1015
- package/scripts/postinstall_binary.js +0 -287
- package/scripts/prepack.js +0 -33
- package/scripts/release_manifest.py +0 -273
- package/scripts/slm-hook.spec +0 -56
- package/scripts/start-dashboard.ps1 +0 -52
- package/scripts/start-dashboard.sh +0 -41
- package/scripts/sync-wiki.ps1 +0 -127
- package/scripts/sync-wiki.sh +0 -82
- package/scripts/test-dmg.sh +0 -161
- package/scripts/test-npm-package.ps1 +0 -252
- package/scripts/test-npm-package.sh +0 -207
- package/scripts/verify-install.ps1 +0 -294
- package/scripts/verify-install.sh +0 -266
- package/scripts/verify-v27.ps1 +0 -301
- package/scripts/verify-v27.sh +0 -233
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -513
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -71
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3
|
|
4
|
+
|
|
5
|
+
"""M018 — durable canonical-ingestion operation records.
|
|
6
|
+
|
|
7
|
+
This is the EXPAND phase of the V3.7 ingestion migration. It is additive:
|
|
8
|
+
legacy ``pending_memories`` and ``ingestion_log`` remain untouched until the
|
|
9
|
+
backfill and dual-write comparison prove the new contract.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import sqlite3
|
|
15
|
+
|
|
16
|
+
NAME = "M018_ingestion_operations"
|
|
17
|
+
DB_TARGET = "memory"
|
|
18
|
+
|
|
19
|
+
DDL = """
|
|
20
|
+
CREATE TABLE IF NOT EXISTS ingestion_operations (
|
|
21
|
+
operation_id TEXT PRIMARY KEY,
|
|
22
|
+
profile_id TEXT NOT NULL,
|
|
23
|
+
source_type TEXT NOT NULL,
|
|
24
|
+
idempotency_key TEXT NOT NULL,
|
|
25
|
+
source_hash TEXT NOT NULL,
|
|
26
|
+
raw_content TEXT NOT NULL,
|
|
27
|
+
raw_metadata_json TEXT NOT NULL DEFAULT '{}',
|
|
28
|
+
scope TEXT NOT NULL DEFAULT 'personal'
|
|
29
|
+
CHECK (scope IN ('personal', 'project', 'shared', 'global')),
|
|
30
|
+
shared_with_json TEXT NOT NULL DEFAULT '[]',
|
|
31
|
+
trusted_actor_id TEXT NOT NULL DEFAULT '',
|
|
32
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
33
|
+
session_date TEXT NOT NULL DEFAULT '',
|
|
34
|
+
speaker TEXT NOT NULL DEFAULT '',
|
|
35
|
+
role TEXT NOT NULL DEFAULT 'user',
|
|
36
|
+
state TEXT NOT NULL DEFAULT 'raw'
|
|
37
|
+
CHECK (state IN ('raw', 'queryable', 'enriching', 'complete', 'failed')),
|
|
38
|
+
queryable_fact_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
39
|
+
final_fact_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
40
|
+
derivation_version TEXT NOT NULL DEFAULT '',
|
|
41
|
+
derivation_state_json TEXT NOT NULL DEFAULT '{}',
|
|
42
|
+
lease_owner TEXT NOT NULL DEFAULT '',
|
|
43
|
+
lease_expires_at REAL NOT NULL DEFAULT 0,
|
|
44
|
+
next_retry_at REAL NOT NULL DEFAULT 0,
|
|
45
|
+
attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
|
|
46
|
+
last_error TEXT NOT NULL DEFAULT '',
|
|
47
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
48
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
49
|
+
UNIQUE(profile_id, source_type, idempotency_key)
|
|
50
|
+
);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_ingestion_operations_state
|
|
52
|
+
ON ingestion_operations(state, updated_at);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_ingestion_operations_source_hash
|
|
54
|
+
ON ingestion_operations(profile_id, source_hash);
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def apply(conn: sqlite3.Connection) -> None:
|
|
59
|
+
"""Create the additive operation table and indexes idempotently."""
|
|
60
|
+
conn.executescript(DDL)
|
|
61
|
+
columns = {
|
|
62
|
+
row[1]
|
|
63
|
+
for row in conn.execute("PRAGMA table_info(ingestion_operations)").fetchall()
|
|
64
|
+
}
|
|
65
|
+
additive_columns = {
|
|
66
|
+
"derivation_state_json": "TEXT NOT NULL DEFAULT '{}'",
|
|
67
|
+
"session_date": "TEXT NOT NULL DEFAULT ''",
|
|
68
|
+
"speaker": "TEXT NOT NULL DEFAULT ''",
|
|
69
|
+
"role": "TEXT NOT NULL DEFAULT 'user'",
|
|
70
|
+
"lease_owner": "TEXT NOT NULL DEFAULT ''",
|
|
71
|
+
"lease_expires_at": "REAL NOT NULL DEFAULT 0",
|
|
72
|
+
"next_retry_at": "REAL NOT NULL DEFAULT 0",
|
|
73
|
+
}
|
|
74
|
+
for name, declaration in additive_columns.items():
|
|
75
|
+
if name not in columns:
|
|
76
|
+
conn.execute(
|
|
77
|
+
f"ALTER TABLE ingestion_operations ADD COLUMN {name} {declaration}"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def verify(conn: sqlite3.Connection) -> bool:
|
|
82
|
+
"""Return true only when the complete M018 contract is present."""
|
|
83
|
+
table = conn.execute(
|
|
84
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' "
|
|
85
|
+
"AND name='ingestion_operations'"
|
|
86
|
+
).fetchone()
|
|
87
|
+
if table is None:
|
|
88
|
+
return False
|
|
89
|
+
columns = {
|
|
90
|
+
row[1]
|
|
91
|
+
for row in conn.execute("PRAGMA table_info(ingestion_operations)").fetchall()
|
|
92
|
+
}
|
|
93
|
+
required = {
|
|
94
|
+
"operation_id",
|
|
95
|
+
"profile_id",
|
|
96
|
+
"source_type",
|
|
97
|
+
"idempotency_key",
|
|
98
|
+
"source_hash",
|
|
99
|
+
"raw_content",
|
|
100
|
+
"state",
|
|
101
|
+
"queryable_fact_ids_json",
|
|
102
|
+
"final_fact_ids_json",
|
|
103
|
+
"derivation_version",
|
|
104
|
+
"derivation_state_json",
|
|
105
|
+
"session_date",
|
|
106
|
+
"speaker",
|
|
107
|
+
"role",
|
|
108
|
+
"lease_owner",
|
|
109
|
+
"lease_expires_at",
|
|
110
|
+
"next_retry_at",
|
|
111
|
+
"attempt_count",
|
|
112
|
+
"last_error",
|
|
113
|
+
}
|
|
114
|
+
if not required <= columns:
|
|
115
|
+
return False
|
|
116
|
+
indexes = {
|
|
117
|
+
row[1]
|
|
118
|
+
for row in conn.execute("PRAGMA index_list(ingestion_operations)").fetchall()
|
|
119
|
+
}
|
|
120
|
+
return "idx_ingestion_operations_state" in indexes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
|
|
4
|
+
"""M019 — durable, non-fabricated derivation lineage."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import sqlite3
|
|
9
|
+
|
|
10
|
+
NAME = "M019_derivation_lineage"
|
|
11
|
+
DB_TARGET = "memory"
|
|
12
|
+
|
|
13
|
+
DDL = """
|
|
14
|
+
CREATE TABLE IF NOT EXISTS derivation_lineage (
|
|
15
|
+
lineage_id TEXT PRIMARY KEY,
|
|
16
|
+
profile_id TEXT NOT NULL,
|
|
17
|
+
object_type TEXT NOT NULL,
|
|
18
|
+
object_id TEXT NOT NULL,
|
|
19
|
+
operation_id TEXT NOT NULL DEFAULT '',
|
|
20
|
+
derivation_version TEXT NOT NULL DEFAULT '',
|
|
21
|
+
source_status TEXT NOT NULL
|
|
22
|
+
CHECK (source_status IN ('exact', 'derived_from_facts', 'unresolved', 'not_applicable')),
|
|
23
|
+
source_start INTEGER,
|
|
24
|
+
source_end INTEGER,
|
|
25
|
+
source_text_sha256 TEXT NOT NULL DEFAULT '',
|
|
26
|
+
source_fact_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
27
|
+
unresolved_reason TEXT NOT NULL DEFAULT '',
|
|
28
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
29
|
+
UNIQUE(profile_id, object_type, object_id, operation_id)
|
|
30
|
+
);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_derivation_lineage_profile
|
|
32
|
+
ON derivation_lineage(profile_id, object_type, object_id);
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_derivation_lineage_operation
|
|
34
|
+
ON derivation_lineage(operation_id);
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def apply(conn: sqlite3.Connection) -> None:
|
|
39
|
+
conn.executescript(DDL)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def verify(conn: sqlite3.Connection) -> bool:
|
|
43
|
+
table = conn.execute(
|
|
44
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='derivation_lineage'"
|
|
45
|
+
).fetchone()
|
|
46
|
+
if table is None:
|
|
47
|
+
return False
|
|
48
|
+
columns = {row[1] for row in conn.execute("PRAGMA table_info(derivation_lineage)")}
|
|
49
|
+
return {
|
|
50
|
+
"lineage_id", "profile_id", "object_type", "object_id",
|
|
51
|
+
"operation_id", "derivation_version", "source_status",
|
|
52
|
+
"source_start", "source_end", "source_text_sha256",
|
|
53
|
+
"source_fact_ids_json", "unresolved_reason",
|
|
54
|
+
} <= columns
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
|
|
4
|
+
"""M020 — forward-only integrity repair for learned model state.
|
|
5
|
+
|
|
6
|
+
M002's DDL shipped before model-state SHA values were backfilled. Do not
|
|
7
|
+
modify M002: its stored hash is part of every existing user's upgrade record.
|
|
8
|
+
This migration deterministically fills only missing digests and never changes
|
|
9
|
+
the model payload or ranking metadata.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import hashlib
|
|
15
|
+
import sqlite3
|
|
16
|
+
|
|
17
|
+
NAME = "M020_model_state_integrity"
|
|
18
|
+
DB_TARGET = "learning"
|
|
19
|
+
|
|
20
|
+
# The runner records a stable fingerprint even though this migration uses a
|
|
21
|
+
# Python apply function for binary-safe SHA computation.
|
|
22
|
+
DDL = "-- M020: backfill missing learning_model_state.bytes_sha256\n"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def verify(conn: sqlite3.Connection) -> bool:
|
|
26
|
+
"""Return True only when every persisted model has an integrity digest."""
|
|
27
|
+
try:
|
|
28
|
+
missing = conn.execute(
|
|
29
|
+
"SELECT 1 FROM learning_model_state "
|
|
30
|
+
"WHERE bytes_sha256 = '' OR bytes_sha256 IS NULL LIMIT 1"
|
|
31
|
+
).fetchone()
|
|
32
|
+
except sqlite3.Error:
|
|
33
|
+
return False
|
|
34
|
+
return missing is None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def apply(conn: sqlite3.Connection) -> None:
|
|
38
|
+
"""Backfill SHA-256 values without modifying model bytes or metadata."""
|
|
39
|
+
rows = conn.execute(
|
|
40
|
+
"SELECT id, state_bytes FROM learning_model_state "
|
|
41
|
+
"WHERE bytes_sha256 = '' OR bytes_sha256 IS NULL"
|
|
42
|
+
).fetchall()
|
|
43
|
+
updates = [
|
|
44
|
+
(hashlib.sha256(state_bytes).hexdigest(), row_id)
|
|
45
|
+
for row_id, state_bytes in rows
|
|
46
|
+
if state_bytes is not None
|
|
47
|
+
]
|
|
48
|
+
if updates:
|
|
49
|
+
conn.executemany(
|
|
50
|
+
"UPDATE learning_model_state SET bytes_sha256 = ? WHERE id = ?",
|
|
51
|
+
updates,
|
|
52
|
+
)
|
|
@@ -24,6 +24,8 @@ from . import (
|
|
|
24
24
|
M004_cross_platform_sync_log,
|
|
25
25
|
M005_bandit_tables,
|
|
26
26
|
M015_add_pinned_column,
|
|
27
|
+
M019_derivation_lineage,
|
|
28
|
+
M020_model_state_integrity,
|
|
27
29
|
)
|
|
28
30
|
|
|
29
31
|
# ---------------------------------------------------------------------------
|
|
@@ -72,6 +74,9 @@ __all__ = (
|
|
|
72
74
|
"M003_migration_log",
|
|
73
75
|
"M004_cross_platform_sync_log",
|
|
74
76
|
"M005_bandit_tables",
|
|
77
|
+
"M015_add_pinned_column",
|
|
78
|
+
"M019_derivation_lineage",
|
|
79
|
+
"M020_model_state_integrity",
|
|
75
80
|
# Legacy re-exports (backward compat):
|
|
76
81
|
"CURRENT_SCHEMA_VERSION",
|
|
77
82
|
"get_schema_version",
|
|
@@ -402,6 +402,12 @@ class RetrievalResult:
|
|
|
402
402
|
score: float = 0.0
|
|
403
403
|
channel_scores: dict[str, float] = field(default_factory=dict)
|
|
404
404
|
confidence: float = 0.0
|
|
405
|
+
# Score Contract v2. Legacy ``score`` and ``confidence`` remain one-release
|
|
406
|
+
# aliases of relevance_score and memory_confidence respectively.
|
|
407
|
+
relevance_score: float | None = None
|
|
408
|
+
ranking_score: float | None = None
|
|
409
|
+
memory_confidence: float | None = None
|
|
410
|
+
rank_position: int = 0
|
|
405
411
|
evidence_chain: list[str] = field(default_factory=list)
|
|
406
412
|
trust_score: float = 0.5
|
|
407
413
|
# LLD-00 §3 + P0.4: HMAC marker emitted during recall so post-tool hooks
|
|
@@ -424,3 +430,13 @@ class RecallResponse:
|
|
|
424
430
|
# v3.6.6: Evidence floor. True when floor gates out ALL results.
|
|
425
431
|
# Additive field — backward compatible (defaults to False).
|
|
426
432
|
no_confident_match: bool = False
|
|
433
|
+
score_contract_version: str = "2"
|
|
434
|
+
calibration_status: str = "uncalibrated"
|
|
435
|
+
calibration_id: str | None = None
|
|
436
|
+
answer_confidence: float | None = None
|
|
437
|
+
abstained: bool = False
|
|
438
|
+
abstention_reason: str | None = None
|
|
439
|
+
# Cross-encoder execution is observable; cold/busy/error fallback must not
|
|
440
|
+
# be mistaken for a reranked response.
|
|
441
|
+
reranker_applied: bool = False
|
|
442
|
+
reranker_status: str = "not_configured"
|
|
@@ -12,7 +12,7 @@ HR-06: BLOB columns use Python bytes, not base64.
|
|
|
12
12
|
HR-07: QJL is optional -- system works without it.
|
|
13
13
|
|
|
14
14
|
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
15
|
-
License:
|
|
15
|
+
License: AGPL-3.0-or-later
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
@@ -150,13 +150,29 @@ class QuantizedEmbeddingStore:
|
|
|
150
150
|
query_embedding: NDArray,
|
|
151
151
|
profile_id: str,
|
|
152
152
|
top_k: int = 50,
|
|
153
|
+
*,
|
|
154
|
+
bit_widths: tuple[int, ...] | None = None,
|
|
153
155
|
) -> list[tuple[str, float]]:
|
|
154
156
|
"""Search polar embeddings for a profile.
|
|
155
157
|
|
|
156
158
|
Pre-filters by lifecycle_zone (excludes 'forgotten').
|
|
159
|
+
``bit_widths`` selects a persisted precision tier; ``None`` preserves
|
|
160
|
+
the legacy all-quantized-row behavior.
|
|
157
161
|
Returns [(fact_id, similarity)] sorted descending.
|
|
158
162
|
"""
|
|
163
|
+
if bit_widths is not None and not bit_widths:
|
|
164
|
+
return []
|
|
159
165
|
try:
|
|
166
|
+
width_clause = ""
|
|
167
|
+
params: list[object] = [profile_id]
|
|
168
|
+
if bit_widths is not None:
|
|
169
|
+
widths = tuple(int(width) for width in bit_widths)
|
|
170
|
+
width_clause = (
|
|
171
|
+
" AND pe.bit_width IN ("
|
|
172
|
+
+ ",".join("?" for _ in widths)
|
|
173
|
+
+ ")"
|
|
174
|
+
)
|
|
175
|
+
params.extend(widths)
|
|
160
176
|
rows = self._db.execute(
|
|
161
177
|
"SELECT pe.fact_id, pe.radius, pe.angle_indices, "
|
|
162
178
|
" pe.qjl_bits, pe.bit_width "
|
|
@@ -164,8 +180,9 @@ class QuantizedEmbeddingStore:
|
|
|
164
180
|
"JOIN fact_retention fr "
|
|
165
181
|
" ON pe.fact_id = fr.fact_id AND fr.profile_id = pe.profile_id "
|
|
166
182
|
"WHERE pe.profile_id = ? "
|
|
167
|
-
" AND fr.lifecycle_zone NOT IN ('forgotten')"
|
|
168
|
-
|
|
183
|
+
" AND fr.lifecycle_zone NOT IN ('forgotten')"
|
|
184
|
+
+ width_clause,
|
|
185
|
+
tuple(params),
|
|
169
186
|
)
|
|
170
187
|
except Exception as exc:
|
|
171
188
|
logger.error("search query failed: %s", exc)
|
|
@@ -17,10 +17,12 @@ import sys
|
|
|
17
17
|
from datetime import datetime, UTC
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
|
|
20
|
+
from superlocalmemory.infra.data_root import DynamicStatePath, canonical_data_root
|
|
21
|
+
|
|
20
22
|
logger = logging.getLogger(__name__)
|
|
21
23
|
|
|
22
24
|
V2_BASE = Path.home() / ".claude-memory"
|
|
23
|
-
V3_BASE =
|
|
25
|
+
V3_BASE = DynamicStatePath()
|
|
24
26
|
V2_DB_NAME = "memory.db"
|
|
25
27
|
BACKUP_NAME = "memory-v2-backup.db"
|
|
26
28
|
|
|
@@ -143,10 +145,10 @@ V3_INDEXES_SQL = [
|
|
|
143
145
|
class V2Migrator:
|
|
144
146
|
"""Migrate V2 database to V3 schema."""
|
|
145
147
|
|
|
146
|
-
def __init__(self, home: Path | None = None):
|
|
148
|
+
def __init__(self, home: Path | None = None, v3_base: Path | None = None):
|
|
147
149
|
self._home = home or Path.home()
|
|
148
150
|
self._v2_base = self._home / ".claude-memory"
|
|
149
|
-
self._v3_base =
|
|
151
|
+
self._v3_base = Path(v3_base) if v3_base is not None else canonical_data_root()
|
|
150
152
|
self._v2_db = self._v2_base / V2_DB_NAME
|
|
151
153
|
self._v3_db = self._v3_base / V2_DB_NAME
|
|
152
154
|
self._backup_db = self._v3_base / BACKUP_NAME
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#0a0e1a"/>
|
|
3
|
+
<path d="M16 32h12l8-14 12 14" fill="none" stroke="#45e0a8" stroke-linecap="round" stroke-linejoin="round" stroke-width="5"/>
|
|
4
|
+
<circle cx="16" cy="32" r="5" fill="#45e0a8"/><circle cx="36" cy="18" r="5" fill="#45e0a8"/><circle cx="48" cy="32" r="5" fill="#45e0a8"/>
|
|
5
|
+
</svg>
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
on mismatch, so the browser cannot show stale UI after an upgrade. -->
|
|
9
9
|
<meta name="slm-version" content="__SLM_VERSION__">
|
|
10
10
|
<title>SuperLocalMemory V3 — Dashboard</title>
|
|
11
|
+
<link rel="icon" type="image/svg+xml" href="static/favicon.svg">
|
|
11
12
|
|
|
12
13
|
<!-- Bootstrap CSS (vendored locally v3.4.21 — no CDN calls, works offline) -->
|
|
13
14
|
<link href="static/vendor/bootstrap.min.css" rel="stylesheet">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
2
|
// Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
3
3
|
// Compliance tab — audit trail, retention policies, ABAC (v2.8)
|
|
4
4
|
// NOTE: All dynamic values use textContent or escapeHtml() from core.js before DOM insertion.
|
|
@@ -14,6 +14,23 @@
|
|
|
14
14
|
// ============================================================================
|
|
15
15
|
|
|
16
16
|
window.SLM_FETCH_TIMEOUT_MS = 15000;
|
|
17
|
+
window.SLM_INSTALL_TOKEN_KEY = 'slm_install_token';
|
|
18
|
+
|
|
19
|
+
window.slmInstallToken = async function (forceRefresh) {
|
|
20
|
+
if (!forceRefresh) {
|
|
21
|
+
var cached = sessionStorage.getItem(window.SLM_INSTALL_TOKEN_KEY);
|
|
22
|
+
if (cached) return cached;
|
|
23
|
+
}
|
|
24
|
+
var response = await window.__slmOriginalFetch(
|
|
25
|
+
'/internal/token',
|
|
26
|
+
{credentials: 'same-origin'}
|
|
27
|
+
);
|
|
28
|
+
if (!response.ok) return '';
|
|
29
|
+
var payload = await response.json();
|
|
30
|
+
var token = payload && payload.token ? payload.token : '';
|
|
31
|
+
if (token) sessionStorage.setItem(window.SLM_INSTALL_TOKEN_KEY, token);
|
|
32
|
+
return token;
|
|
33
|
+
};
|
|
17
34
|
|
|
18
35
|
// Global fetch patch: apply the abort timeout to every relative-URL request
|
|
19
36
|
// automatically. 17 UI modules call bare fetch() — patching here avoids
|
|
@@ -26,18 +43,42 @@ window.SLM_FETCH_TIMEOUT_MS = 15000;
|
|
|
26
43
|
if (window.__slmFetchPatched) return;
|
|
27
44
|
window.__slmFetchPatched = true;
|
|
28
45
|
var _origFetch = window.fetch.bind(window);
|
|
46
|
+
window.__slmOriginalFetch = _origFetch;
|
|
29
47
|
window.fetch = function (input, init) {
|
|
30
|
-
init = init || {};
|
|
48
|
+
init = Object.assign({}, init || {});
|
|
31
49
|
var urlStr = typeof input === 'string' ? input : (input && input.url) || '';
|
|
32
50
|
var isRelative = !(/^https?:\/\//i.test(urlStr));
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
var method = String(
|
|
52
|
+
init.method || (input && input.method) || 'GET'
|
|
53
|
+
).toUpperCase();
|
|
54
|
+
var mutating = ['POST', 'PUT', 'PATCH', 'DELETE'].indexOf(method) !== -1;
|
|
55
|
+
|
|
56
|
+
function send() {
|
|
57
|
+
if (!isRelative || init.signal) {
|
|
58
|
+
return _origFetch(input, init);
|
|
59
|
+
}
|
|
60
|
+
var controller = new AbortController();
|
|
61
|
+
var timeoutMs = init.timeoutMs || window.SLM_FETCH_TIMEOUT_MS;
|
|
62
|
+
var timer = setTimeout(function () { controller.abort(); }, timeoutMs);
|
|
63
|
+
init.signal = controller.signal;
|
|
64
|
+
return _origFetch(input, init).finally(function () { clearTimeout(timer); });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (isRelative && mutating && urlStr !== '/internal/token') {
|
|
68
|
+
return window.slmInstallToken(false).then(function (token) {
|
|
69
|
+
if (!token) throw new Error('local write credential unavailable');
|
|
70
|
+
var headers = new Headers(
|
|
71
|
+
init.headers || (input && input.headers) || {}
|
|
72
|
+
);
|
|
73
|
+
if (!headers.has('X-Install-Token')) {
|
|
74
|
+
headers.set('X-Install-Token', token);
|
|
75
|
+
}
|
|
76
|
+
init.headers = headers;
|
|
77
|
+
init.credentials = init.credentials || 'same-origin';
|
|
78
|
+
return send();
|
|
79
|
+
});
|
|
35
80
|
}
|
|
36
|
-
|
|
37
|
-
var timeoutMs = init.timeoutMs || window.SLM_FETCH_TIMEOUT_MS;
|
|
38
|
-
var timer = setTimeout(function () { controller.abort(); }, timeoutMs);
|
|
39
|
-
init.signal = controller.signal;
|
|
40
|
-
return _origFetch(input, init).finally(function () { clearTimeout(timer); });
|
|
81
|
+
return send();
|
|
41
82
|
};
|
|
42
83
|
})();
|
|
43
84
|
|
|
@@ -72,14 +72,35 @@ document.addEventListener('click', function(e) {
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
async function dashboardInstallToken() {
|
|
76
|
+
var key = 'slm_install_token';
|
|
77
|
+
var cached = sessionStorage.getItem(key);
|
|
78
|
+
if (cached) return cached;
|
|
79
|
+
var response = await fetch('/internal/token', {credentials: 'same-origin'});
|
|
80
|
+
if (!response.ok) return '';
|
|
81
|
+
var payload = await response.json();
|
|
82
|
+
var token = payload && payload.token ? payload.token : '';
|
|
83
|
+
if (token) sessionStorage.setItem(key, token);
|
|
84
|
+
return token;
|
|
85
|
+
}
|
|
86
|
+
|
|
75
87
|
// Quick store
|
|
76
|
-
document.getElementById('quick-store-btn')?.addEventListener('click', function() {
|
|
88
|
+
document.getElementById('quick-store-btn')?.addEventListener('click', async function() {
|
|
77
89
|
var input = document.getElementById('quick-store-input');
|
|
78
90
|
var content = input.value.trim();
|
|
79
91
|
if (!content) return;
|
|
92
|
+
var token = await dashboardInstallToken();
|
|
93
|
+
if (!token) {
|
|
94
|
+
showToast('Store failed: local write credential unavailable', 'error');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
80
97
|
fetch('/remember', {
|
|
81
98
|
method: 'POST',
|
|
82
|
-
|
|
99
|
+
credentials: 'same-origin',
|
|
100
|
+
headers: {
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
'X-Install-Token': token
|
|
103
|
+
},
|
|
83
104
|
body: JSON.stringify({content: content})
|
|
84
105
|
}).then(function(r) {
|
|
85
106
|
if (!r.ok) return r.json().catch(function() { return {}; }).then(function(d) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SuperLocalMemory V2 - Feedback Module (v2.7.4)
|
|
3
3
|
* Copyright (c) 2026 Varun Pratap Bhardwaj
|
|
4
|
-
* Licensed under
|
|
4
|
+
* Licensed under GNU Affero General Public License v3.0 or later
|
|
5
5
|
*
|
|
6
6
|
* Collects implicit and explicit feedback signals from dashboard
|
|
7
7
|
* interactions. All data stays 100% local.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SuperLocalMemory V2.6.5 - Interactive Knowledge Graph - Filtering Module
|
|
2
|
-
// Copyright (c) 2026 Varun Pratap Bhardwaj —
|
|
2
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj — GNU Affero General Public License v3.0 or later
|
|
3
3
|
// Part of modular graph visualization system (split from monolithic graph-cytoscape.js)
|
|
4
4
|
|
|
5
5
|
// ============================================================================
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SuperLocalMemory V2.6.5 - Interactive Knowledge Graph - UI Elements Module
|
|
2
|
-
// Copyright (c) 2026 Varun Pratap Bhardwaj —
|
|
2
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj — GNU Affero General Public License v3.0 or later
|
|
3
3
|
// Part of modular graph visualization system (split from monolithic graph-cytoscape.js)
|
|
4
4
|
|
|
5
5
|
// ============================================================================
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
2
|
// Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
3
3
|
// Lifecycle tab — state distribution, compaction, transitions (v2.8)
|
|
4
4
|
// NOTE: All dynamic values pass through escapeHtml() or textContent for DOM insertion.
|
|
@@ -84,50 +84,26 @@
|
|
|
84
84
|
}, REFRESH_INTERVAL);
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
// Try BOTH brokers: daemon (port 8765 /mesh/*) AND standalone slm-mesh (port 7899 /*)
|
|
88
|
-
var STANDALONE_PORT = null;
|
|
89
|
-
|
|
90
|
-
function fetchStandaloneBroker(path) {
|
|
91
|
-
var ports = [7899];
|
|
92
|
-
return fetch('http://127.0.0.1:' + ports[0] + path, { signal: AbortSignal.timeout(2000) })
|
|
93
|
-
.then(function(r) {
|
|
94
|
-
if (r.ok) { STANDALONE_PORT = ports[0]; return r.json(); }
|
|
95
|
-
STANDALONE_PORT = null;
|
|
96
|
-
return null;
|
|
97
|
-
})
|
|
98
|
-
.catch(function() { STANDALONE_PORT = null; return null; });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
87
|
function fetchMeshStatus() {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}).catch(function() { return null; }),
|
|
107
|
-
fetchStandaloneBroker('/health')
|
|
108
|
-
]).then(function(results) {
|
|
109
|
-
var daemon = results[0];
|
|
88
|
+
meshFetch('/mesh/status').then(function(r) {
|
|
89
|
+
if (!r.ok) return r.status === 401 ? { _auth_error: true } : null;
|
|
90
|
+
return r.json();
|
|
91
|
+
}).catch(function() { return null; }).then(function(daemon) {
|
|
110
92
|
if (daemon && daemon._auth_error) { renderMeshStatusAuthError(); return; }
|
|
111
|
-
renderMeshStatus(daemon,
|
|
93
|
+
renderMeshStatus(daemon, null);
|
|
112
94
|
});
|
|
113
95
|
}
|
|
114
96
|
|
|
115
97
|
function fetchMeshPeers() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}).catch(function() { return { peers: [] }; }),
|
|
121
|
-
fetchStandaloneBroker('/peers')
|
|
122
|
-
]).then(function(results) {
|
|
123
|
-
var daemonResult = results[0];
|
|
98
|
+
meshFetch('/mesh/peers').then(function(r) {
|
|
99
|
+
if (!r.ok) return r.status === 401 ? { _auth_error: true } : { peers: [] };
|
|
100
|
+
return r.json();
|
|
101
|
+
}).catch(function() { return { peers: [] }; }).then(function(daemonResult) {
|
|
124
102
|
if (daemonResult && daemonResult._auth_error) { renderMeshPeersAuthError(); return; }
|
|
125
103
|
var daemonPeers = (daemonResult && daemonResult.peers) || [];
|
|
126
|
-
var standalonePeers = (results[1] && (results[1].peers || results[1])) || [];
|
|
127
|
-
if (!Array.isArray(standalonePeers)) standalonePeers = [];
|
|
128
104
|
var seen = {};
|
|
129
105
|
var allPeers = [];
|
|
130
|
-
daemonPeers.
|
|
106
|
+
daemonPeers.forEach(function(p) {
|
|
131
107
|
var id = p.peer_id || p.id || JSON.stringify(p);
|
|
132
108
|
if (!seen[id]) { seen[id] = true; allPeers.push(p); }
|
|
133
109
|
});
|
|
@@ -200,28 +176,18 @@
|
|
|
200
176
|
// Standalone broker (TypeScript, slm-mesh npm)
|
|
201
177
|
var standaloneUp = standaloneData && standaloneData.status === 'ok';
|
|
202
178
|
var standaloneUptime = standaloneData ? (standaloneData.uptime || 0) : 0;
|
|
203
|
-
var
|
|
204
|
-
|
|
205
|
-
var anyUp = daemonUp || standaloneUp;
|
|
206
|
-
var statusText = anyUp ? 'Active' : 'Offline';
|
|
207
|
-
var statusKey = anyUp ? 'active' : 'dead';
|
|
208
|
-
var bestUptime = Math.max(daemonUptime, standaloneUptime);
|
|
209
|
-
|
|
210
|
-
// Combined info
|
|
211
|
-
var brokerInfo = [];
|
|
212
|
-
if (daemonUp) brokerInfo.push('Daemon (Python)');
|
|
213
|
-
if (standaloneUp) brokerInfo.push('slm-mesh ' + standaloneVersion);
|
|
179
|
+
var statusText = daemonUp ? 'Active' : 'Offline';
|
|
180
|
+
var statusKey = daemonUp ? 'active' : 'dead';
|
|
214
181
|
|
|
215
182
|
el.innerHTML =
|
|
216
183
|
'<div class="row g-3">' +
|
|
217
184
|
statusCard('Broker', statusDot(statusKey) + ' ' + statusText, 'bi-wifi') +
|
|
218
185
|
statusCard('Peers', daemonPeers, 'bi-people') +
|
|
219
|
-
statusCard('Uptime', formatUptime(
|
|
220
|
-
statusCard('
|
|
186
|
+
statusCard('Uptime', formatUptime(daemonUptime), 'bi-clock') +
|
|
187
|
+
statusCard('Broker', daemonUp ? 1 : 0, 'bi-hdd-stack') +
|
|
221
188
|
'</div>' +
|
|
222
189
|
'<div style="font-size:0.75rem;color:var(--ng-text-quaternary);margin-top:8px;text-align:center">' +
|
|
223
|
-
(
|
|
224
|
-
(standaloneUp ? ' (port 7899)' : '') +
|
|
190
|
+
(daemonUp ? 'Running: integrated SLM daemon' : 'No broker detected') +
|
|
225
191
|
' · Peers register via <code>mesh_summary</code> MCP tool and expire after 60s without heartbeat' +
|
|
226
192
|
'</div>';
|
|
227
193
|
}
|
|
@@ -272,12 +272,14 @@ function _updateSidebarWidget(destinations) {
|
|
|
272
272
|
|
|
273
273
|
if (primary.destination_type === 'google_drive') {
|
|
274
274
|
var email = config.email || 'Google Drive';
|
|
275
|
-
|
|
275
|
+
// Keep the dashboard fully local. CSP deliberately forbids remote
|
|
276
|
+
// avatar requests, and a provider icon conveys the same state.
|
|
277
|
+
avatar.innerHTML = '<i class="bi bi-google" style="font-size:14px;color:#4285f4;"></i>';
|
|
276
278
|
name.textContent = email.split('@')[0];
|
|
277
279
|
name.title = email;
|
|
278
280
|
} else if (primary.destination_type === 'github') {
|
|
279
281
|
var username = config.username || 'GitHub';
|
|
280
|
-
avatar.innerHTML = '<
|
|
282
|
+
avatar.innerHTML = '<i class="bi bi-github" style="font-size:14px;"></i>';
|
|
281
283
|
name.textContent = username;
|
|
282
284
|
}
|
|
283
285
|
|