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.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +48 -0
- package/README.md +3 -3
- package/package.json +1 -8
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/agents/slm-memory-advisor.md +1 -1
- package/plugin-src/agents/slm-optimize-advisor.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-governance/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +1 -1
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-scope/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/scripts/postinstall.js +71 -2
- package/pyproject.toml +0 -250
- package/src/superlocalmemory/__init__.py +0 -82
- package/src/superlocalmemory/access/__init__.py +0 -3
- package/src/superlocalmemory/access/rbac.py +0 -575
- package/src/superlocalmemory/attribution/__init__.py +0 -9
- package/src/superlocalmemory/attribution/signer.py +0 -173
- package/src/superlocalmemory/attribution/watermark.py +0 -189
- package/src/superlocalmemory/brain/__init__.py +0 -5
- package/src/superlocalmemory/brain/truth.py +0 -418
- package/src/superlocalmemory/cli/__init__.py +0 -5
- package/src/superlocalmemory/cli/__main__.py +0 -17
- package/src/superlocalmemory/cli/_lazy_init.py +0 -115
- package/src/superlocalmemory/cli/cache_cmd.py +0 -198
- package/src/superlocalmemory/cli/commands.py +0 -4710
- package/src/superlocalmemory/cli/compress_cmd.py +0 -151
- package/src/superlocalmemory/cli/context_commands.py +0 -193
- package/src/superlocalmemory/cli/daemon.py +0 -909
- package/src/superlocalmemory/cli/db_migrate.py +0 -150
- package/src/superlocalmemory/cli/diagnostics_cmd.py +0 -101
- package/src/superlocalmemory/cli/escape_hatch.py +0 -220
- package/src/superlocalmemory/cli/evidence_cmd.py +0 -103
- package/src/superlocalmemory/cli/gdpr_cmd.py +0 -792
- package/src/superlocalmemory/cli/gdpr_io.py +0 -109
- package/src/superlocalmemory/cli/help_cmd.py +0 -197
- package/src/superlocalmemory/cli/host_upgrades.py +0 -189
- package/src/superlocalmemory/cli/ingest_cmd.py +0 -327
- package/src/superlocalmemory/cli/json_output.py +0 -81
- package/src/superlocalmemory/cli/loop_cmd.py +0 -187
- package/src/superlocalmemory/cli/main.py +0 -1145
- package/src/superlocalmemory/cli/mesh_cmd.py +0 -38
- package/src/superlocalmemory/cli/migrate_cmd.py +0 -55
- package/src/superlocalmemory/cli/ops_cmd.py +0 -281
- package/src/superlocalmemory/cli/optimize_cmd.py +0 -179
- package/src/superlocalmemory/cli/optimize_constants.py +0 -31
- package/src/superlocalmemory/cli/pending_store.py +0 -296
- package/src/superlocalmemory/cli/proxy_cmd.py +0 -108
- package/src/superlocalmemory/cli/scale_engine_cmd.py +0 -56
- package/src/superlocalmemory/cli/service_installer.py +0 -373
- package/src/superlocalmemory/cli/setup_wizard.py +0 -1162
- package/src/superlocalmemory/cli/summary_cmd.py +0 -215
- package/src/superlocalmemory/cli/version_banner.py +0 -202
- package/src/superlocalmemory/cli/wizard_v3426_options.py +0 -129
- package/src/superlocalmemory/code_graph/__init__.py +0 -46
- package/src/superlocalmemory/code_graph/blast_radius.py +0 -177
- package/src/superlocalmemory/code_graph/bridge/__init__.py +0 -36
- package/src/superlocalmemory/code_graph/bridge/entity_resolver.py +0 -490
- package/src/superlocalmemory/code_graph/bridge/event_listeners.py +0 -206
- package/src/superlocalmemory/code_graph/bridge/fact_enricher.py +0 -159
- package/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +0 -170
- package/src/superlocalmemory/code_graph/bridge/maintenance.py +0 -220
- package/src/superlocalmemory/code_graph/bridge/temporal_checker.py +0 -152
- package/src/superlocalmemory/code_graph/changes.py +0 -363
- package/src/superlocalmemory/code_graph/communities.py +0 -299
- package/src/superlocalmemory/code_graph/config.py +0 -154
- package/src/superlocalmemory/code_graph/database.py +0 -526
- package/src/superlocalmemory/code_graph/extractors/__init__.py +0 -95
- package/src/superlocalmemory/code_graph/extractors/python.py +0 -413
- package/src/superlocalmemory/code_graph/extractors/typescript.py +0 -556
- package/src/superlocalmemory/code_graph/flows.py +0 -350
- package/src/superlocalmemory/code_graph/git_hooks.py +0 -226
- package/src/superlocalmemory/code_graph/graph_engine.py +0 -295
- package/src/superlocalmemory/code_graph/graph_store.py +0 -335
- package/src/superlocalmemory/code_graph/incremental.py +0 -200
- package/src/superlocalmemory/code_graph/models.py +0 -130
- package/src/superlocalmemory/code_graph/parser.py +0 -687
- package/src/superlocalmemory/code_graph/resolver.py +0 -321
- package/src/superlocalmemory/code_graph/search.py +0 -460
- package/src/superlocalmemory/code_graph/service.py +0 -95
- package/src/superlocalmemory/code_graph/watcher.py +0 -207
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +0 -204
- package/src/superlocalmemory/compliance/audit.py +0 -385
- package/src/superlocalmemory/compliance/eu_ai_act.py +0 -101
- package/src/superlocalmemory/compliance/gdpr.py +0 -1479
- package/src/superlocalmemory/compliance/lifecycle.py +0 -158
- package/src/superlocalmemory/compliance/retention.py +0 -415
- package/src/superlocalmemory/compliance/scheduler.py +0 -217
- package/src/superlocalmemory/contracts/__init__.py +0 -1
- package/src/superlocalmemory/contracts/schemas/agent-experience-v1.schema.json +0 -92
- package/src/superlocalmemory/contracts/schemas/agent-integration-contract-v2.schema.json +0 -46
- package/src/superlocalmemory/contracts/schemas/cognitive-turn-receipt-v1.schema.json +0 -59
- package/src/superlocalmemory/contracts/v402.py +0 -62
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/actor_context.py +0 -166
- package/src/superlocalmemory/core/admission.py +0 -769
- package/src/superlocalmemory/core/backend_orchestrator.py +0 -637
- package/src/superlocalmemory/core/block_hygiene.py +0 -147
- package/src/superlocalmemory/core/community_summary.py +0 -267
- package/src/superlocalmemory/core/component_healer.py +0 -144
- package/src/superlocalmemory/core/component_registry.py +0 -514
- package/src/superlocalmemory/core/config.py +0 -2204
- package/src/superlocalmemory/core/consolidation_engine.py +0 -983
- package/src/superlocalmemory/core/context_cache.py +0 -574
- package/src/superlocalmemory/core/derivation_lineage.py +0 -246
- package/src/superlocalmemory/core/embedding_worker.py +0 -208
- package/src/superlocalmemory/core/embeddings.py +0 -1052
- package/src/superlocalmemory/core/engine.py +0 -1395
- package/src/superlocalmemory/core/engine_capabilities.py +0 -24
- package/src/superlocalmemory/core/engine_ingestion.py +0 -983
- package/src/superlocalmemory/core/engine_lock.py +0 -75
- package/src/superlocalmemory/core/engine_wiring.py +0 -776
- package/src/superlocalmemory/core/entity_community.py +0 -178
- package/src/superlocalmemory/core/error_envelope.py +0 -60
- package/src/superlocalmemory/core/evidence_bundle.py +0 -528
- package/src/superlocalmemory/core/fact_consolidator.py +0 -812
- package/src/superlocalmemory/core/file_lock.py +0 -92
- package/src/superlocalmemory/core/graph_analyzer.py +0 -456
- package/src/superlocalmemory/core/graph_metrics.py +0 -597
- package/src/superlocalmemory/core/graph_pruner.py +0 -939
- package/src/superlocalmemory/core/health_monitor.py +0 -338
- package/src/superlocalmemory/core/hooks.py +0 -65
- package/src/superlocalmemory/core/ingest_gate.py +0 -133
- package/src/superlocalmemory/core/ingest_policy.py +0 -38
- package/src/superlocalmemory/core/ingestion_command.py +0 -1042
- package/src/superlocalmemory/core/injection.py +0 -434
- package/src/superlocalmemory/core/install_detector.py +0 -131
- package/src/superlocalmemory/core/key_expander.py +0 -138
- package/src/superlocalmemory/core/lifecycle_state.py +0 -153
- package/src/superlocalmemory/core/maintenance.py +0 -777
- package/src/superlocalmemory/core/maintenance_scheduler.py +0 -507
- package/src/superlocalmemory/core/materialization_control.py +0 -20
- package/src/superlocalmemory/core/mcp_embedder_proxy.py +0 -89
- package/src/superlocalmemory/core/memory_health.py +0 -266
- package/src/superlocalmemory/core/mode_capability.py +0 -111
- package/src/superlocalmemory/core/modes.py +0 -168
- package/src/superlocalmemory/core/mutations.py +0 -688
- package/src/superlocalmemory/core/ollama_embedder.py +0 -266
- package/src/superlocalmemory/core/ollama_validator.py +0 -315
- package/src/superlocalmemory/core/operation_policy.py +0 -92
- package/src/superlocalmemory/core/operation_policy_registry.py +0 -542
- package/src/superlocalmemory/core/operation_request.py +0 -127
- package/src/superlocalmemory/core/ops_remediation.py +0 -542
- package/src/superlocalmemory/core/pii.py +0 -105
- package/src/superlocalmemory/core/platform_utils.py +0 -138
- package/src/superlocalmemory/core/profiles.py +0 -234
- package/src/superlocalmemory/core/progressive_abstraction.py +0 -208
- package/src/superlocalmemory/core/projection_drain.py +0 -380
- package/src/superlocalmemory/core/queue_consumer.py +0 -168
- package/src/superlocalmemory/core/ram_lock.py +0 -160
- package/src/superlocalmemory/core/rate_limit.py +0 -151
- package/src/superlocalmemory/core/recall_gate.py +0 -95
- package/src/superlocalmemory/core/recall_pipeline.py +0 -1337
- package/src/superlocalmemory/core/recall_queue.py +0 -377
- package/src/superlocalmemory/core/recall_worker.py +0 -414
- package/src/superlocalmemory/core/registry.py +0 -121
- package/src/superlocalmemory/core/remember_admission.py +0 -161
- package/src/superlocalmemory/core/remember_runtime.py +0 -1190
- package/src/superlocalmemory/core/remote_mode.py +0 -214
- package/src/superlocalmemory/core/reranker_worker.py +0 -338
- package/src/superlocalmemory/core/safe_fs.py +0 -108
- package/src/superlocalmemory/core/scale_autopromote.py +0 -196
- package/src/superlocalmemory/core/scale_engine.py +0 -915
- package/src/superlocalmemory/core/score_contract.py +0 -82
- package/src/superlocalmemory/core/security_primitives.py +0 -672
- package/src/superlocalmemory/core/session_identity.py +0 -98
- package/src/superlocalmemory/core/shadow_router.py +0 -319
- package/src/superlocalmemory/core/slm_disabled.py +0 -85
- package/src/superlocalmemory/core/status_contract.py +0 -108
- package/src/superlocalmemory/core/store_pipeline.py +0 -1404
- package/src/superlocalmemory/core/summarizer.py +0 -200
- package/src/superlocalmemory/core/tier_manager.py +0 -461
- package/src/superlocalmemory/core/topic_signature.py +0 -156
- package/src/superlocalmemory/core/transactions/__init__.py +0 -78
- package/src/superlocalmemory/core/transactions/concrete_owners.py +0 -604
- package/src/superlocalmemory/core/transactions/erasure.py +0 -825
- package/src/superlocalmemory/core/transactions/manifest.py +0 -255
- package/src/superlocalmemory/core/transactions/manifest_key.py +0 -155
- package/src/superlocalmemory/core/transactions/obligations.py +0 -272
- package/src/superlocalmemory/core/transactions/owners.py +0 -114
- package/src/superlocalmemory/core/transactions/reconciler.py +0 -285
- package/src/superlocalmemory/core/transactions/service.py +0 -330
- package/src/superlocalmemory/core/worker_pool.py +0 -377
- package/src/superlocalmemory/core/working_memory.py +0 -288
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +0 -374
- package/src/superlocalmemory/dynamics/eap_scheduler.py +0 -294
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +0 -171
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +0 -227
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/auto_linker.py +0 -308
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +0 -899
- package/src/superlocalmemory/encoding/consolidator.py +0 -472
- package/src/superlocalmemory/encoding/context_generator.py +0 -175
- package/src/superlocalmemory/encoding/emotional.py +0 -189
- package/src/superlocalmemory/encoding/entity_reflexion.py +0 -200
- package/src/superlocalmemory/encoding/entity_resolver.py +0 -687
- package/src/superlocalmemory/encoding/entropy_gate.py +0 -101
- package/src/superlocalmemory/encoding/fact_extractor.py +0 -877
- package/src/superlocalmemory/encoding/foresight.py +0 -93
- package/src/superlocalmemory/encoding/graph_builder.py +0 -346
- package/src/superlocalmemory/encoding/observation_builder.py +0 -177
- package/src/superlocalmemory/encoding/prospective_markers.py +0 -262
- package/src/superlocalmemory/encoding/scene_builder.py +0 -410
- package/src/superlocalmemory/encoding/signal_inference.py +0 -90
- package/src/superlocalmemory/encoding/temporal_parser.py +0 -432
- package/src/superlocalmemory/encoding/temporal_validator.py +0 -572
- package/src/superlocalmemory/encoding/type_router.py +0 -237
- package/src/superlocalmemory/evaluation/__init__.py +0 -13
- package/src/superlocalmemory/evaluation/calibration.py +0 -308
- package/src/superlocalmemory/evolution/__init__.py +0 -29
- package/src/superlocalmemory/evolution/blind_verifier.py +0 -122
- package/src/superlocalmemory/evolution/budget.py +0 -356
- package/src/superlocalmemory/evolution/evolution_store.py +0 -619
- package/src/superlocalmemory/evolution/llm_dispatch.py +0 -559
- package/src/superlocalmemory/evolution/model_selection.py +0 -175
- package/src/superlocalmemory/evolution/mutation_generator.py +0 -226
- package/src/superlocalmemory/evolution/skill_activator.py +0 -270
- package/src/superlocalmemory/evolution/skill_evolver.py +0 -928
- package/src/superlocalmemory/evolution/triggers.py +0 -376
- package/src/superlocalmemory/evolution/types.py +0 -114
- package/src/superlocalmemory/graph/__init__.py +0 -9
- package/src/superlocalmemory/graph/cozo_adjacency.py +0 -122
- package/src/superlocalmemory/graph/cozo_backend.py +0 -751
- package/src/superlocalmemory/hooks/__init__.py +0 -3
- package/src/superlocalmemory/hooks/_outcome_common.py +0 -523
- package/src/superlocalmemory/hooks/adapter_base.py +0 -347
- package/src/superlocalmemory/hooks/antigravity_adapter.py +0 -171
- package/src/superlocalmemory/hooks/auto_capture.py +0 -133
- package/src/superlocalmemory/hooks/auto_invoker.py +0 -521
- package/src/superlocalmemory/hooks/auto_parameterize.py +0 -147
- package/src/superlocalmemory/hooks/auto_recall.py +0 -191
- package/src/superlocalmemory/hooks/auto_recall_hook.py +0 -251
- package/src/superlocalmemory/hooks/before_web_hook.py +0 -131
- package/src/superlocalmemory/hooks/claude_code_hooks.py +0 -637
- package/src/superlocalmemory/hooks/codex_assets.py +0 -251
- package/src/superlocalmemory/hooks/codex_hooks.py +0 -186
- package/src/superlocalmemory/hooks/context_payload.py +0 -311
- package/src/superlocalmemory/hooks/copilot_adapter.py +0 -208
- package/src/superlocalmemory/hooks/cross_platform_connector.py +0 -90
- package/src/superlocalmemory/hooks/cursor_adapter.py +0 -173
- package/src/superlocalmemory/hooks/hook_daemon.py +0 -295
- package/src/superlocalmemory/hooks/hook_handlers.py +0 -822
- package/src/superlocalmemory/hooks/ide_connector.py +0 -246
- package/src/superlocalmemory/hooks/memory_protocol.py +0 -158
- package/src/superlocalmemory/hooks/portable_kit.py +0 -755
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +0 -183
- package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +0 -351
- package/src/superlocalmemory/hooks/prewarm_auth.py +0 -187
- package/src/superlocalmemory/hooks/rules_engine.py +0 -99
- package/src/superlocalmemory/hooks/session_registry.py +0 -330
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +0 -138
- package/src/superlocalmemory/hooks/sync_loop.py +0 -114
- package/src/superlocalmemory/hooks/topic_shift_hook.py +0 -302
- package/src/superlocalmemory/hooks/user_prompt_hook.py +0 -131
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +0 -210
- package/src/superlocalmemory/infra/__init__.py +0 -3
- package/src/superlocalmemory/infra/auth_middleware.py +0 -145
- package/src/superlocalmemory/infra/backup.py +0 -974
- package/src/superlocalmemory/infra/backup_obligations.py +0 -423
- package/src/superlocalmemory/infra/cache_manager.py +0 -267
- package/src/superlocalmemory/infra/cloud_backup.py +0 -788
- package/src/superlocalmemory/infra/daemon_identity.py +0 -300
- package/src/superlocalmemory/infra/data_root.py +0 -238
- package/src/superlocalmemory/infra/event_bus.py +0 -637
- package/src/superlocalmemory/infra/local_diagnostics.py +0 -327
- package/src/superlocalmemory/infra/pid_manager.py +0 -193
- package/src/superlocalmemory/infra/process_identity.py +0 -180
- package/src/superlocalmemory/infra/process_reaper.py +0 -624
- package/src/superlocalmemory/infra/rate_limiter.py +0 -228
- package/src/superlocalmemory/infra/self_heal.py +0 -401
- package/src/superlocalmemory/infra/version_integrity.py +0 -229
- package/src/superlocalmemory/ingestion/__init__.py +0 -13
- package/src/superlocalmemory/ingestion/adapter_manager.py +0 -255
- package/src/superlocalmemory/ingestion/base_adapter.py +0 -171
- package/src/superlocalmemory/ingestion/calendar_adapter.py +0 -349
- package/src/superlocalmemory/ingestion/credentials.py +0 -125
- package/src/superlocalmemory/ingestion/gmail_adapter.py +0 -378
- package/src/superlocalmemory/ingestion/parsers.py +0 -100
- package/src/superlocalmemory/ingestion/transcript_adapter.py +0 -161
- package/src/superlocalmemory/integrations/__init__.py +0 -1
- package/src/superlocalmemory/integrations/bounded_loops_mcp.py +0 -431
- package/src/superlocalmemory/integrations/bounded_loops_v051.py +0 -236
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +0 -172
- package/src/superlocalmemory/learning/arm_catalog.py +0 -97
- package/src/superlocalmemory/learning/assertion_miner.py +0 -403
- package/src/superlocalmemory/learning/bandit.py +0 -654
- package/src/superlocalmemory/learning/bandit_cache.py +0 -131
- package/src/superlocalmemory/learning/behavioral.py +0 -542
- package/src/superlocalmemory/learning/bootstrap.py +0 -298
- package/src/superlocalmemory/learning/consolidation_cycle.py +0 -398
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +0 -115
- package/src/superlocalmemory/learning/consolidation_worker.py +0 -261
- package/src/superlocalmemory/learning/cross_project.py +0 -408
- package/src/superlocalmemory/learning/database.py +0 -698
- package/src/superlocalmemory/learning/dedup_hnsw.py +0 -413
- package/src/superlocalmemory/learning/engagement.py +0 -487
- package/src/superlocalmemory/learning/engagement_features.py +0 -279
- package/src/superlocalmemory/learning/ensemble.py +0 -309
- package/src/superlocalmemory/learning/entity_compiler.py +0 -356
- package/src/superlocalmemory/learning/fact_outcome_joins.py +0 -207
- package/src/superlocalmemory/learning/features.py +0 -138
- package/src/superlocalmemory/learning/feedback.py +0 -724
- package/src/superlocalmemory/learning/forgetting_scheduler.py +0 -375
- package/src/superlocalmemory/learning/hnsw_dedup.py +0 -69
- package/src/superlocalmemory/learning/labeler.py +0 -85
- package/src/superlocalmemory/learning/legacy_migration.py +0 -316
- package/src/superlocalmemory/learning/lightgbm_subprocess.py +0 -236
- package/src/superlocalmemory/learning/memory_merge.py +0 -175
- package/src/superlocalmemory/learning/model_cache.py +0 -267
- package/src/superlocalmemory/learning/model_rollback.py +0 -281
- package/src/superlocalmemory/learning/outcome_queue.py +0 -306
- package/src/superlocalmemory/learning/outcomes.py +0 -286
- package/src/superlocalmemory/learning/pattern_miner.py +0 -465
- package/src/superlocalmemory/learning/pattern_miner_constants.py +0 -90
- package/src/superlocalmemory/learning/pcos.py +0 -291
- package/src/superlocalmemory/learning/project_context.py +0 -366
- package/src/superlocalmemory/learning/propensity.py +0 -131
- package/src/superlocalmemory/learning/ranker.py +0 -300
- package/src/superlocalmemory/learning/ranker_common.py +0 -163
- package/src/superlocalmemory/learning/ranker_retrain_legacy.py +0 -210
- package/src/superlocalmemory/learning/ranker_retrain_online.py +0 -423
- package/src/superlocalmemory/learning/reward.py +0 -888
- package/src/superlocalmemory/learning/reward_archive.py +0 -223
- package/src/superlocalmemory/learning/reward_boost.py +0 -211
- package/src/superlocalmemory/learning/reward_from_outcomes.py +0 -365
- package/src/superlocalmemory/learning/reward_model.py +0 -144
- package/src/superlocalmemory/learning/reward_proxy.py +0 -578
- package/src/superlocalmemory/learning/shadow_test.py +0 -524
- package/src/superlocalmemory/learning/signal_kinds.py +0 -79
- package/src/superlocalmemory/learning/signal_worker.py +0 -268
- package/src/superlocalmemory/learning/signals.py +0 -646
- package/src/superlocalmemory/learning/skill_performance_miner.py +0 -422
- package/src/superlocalmemory/learning/source_quality.py +0 -828
- package/src/superlocalmemory/learning/trigram_index.py +0 -548
- package/src/superlocalmemory/learning/workflows.py +0 -309
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +0 -364
- package/src/superlocalmemory/loops/__init__.py +0 -58
- package/src/superlocalmemory/loops/budget.py +0 -58
- package/src/superlocalmemory/loops/engine.py +0 -174
- package/src/superlocalmemory/loops/ledger.py +0 -298
- package/src/superlocalmemory/loops/models.py +0 -152
- package/src/superlocalmemory/loops/rules.py +0 -52
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/ebbinghaus.py +0 -352
- package/src/superlocalmemory/math/fisher.py +0 -356
- package/src/superlocalmemory/math/fisher_quantized.py +0 -255
- package/src/superlocalmemory/math/hopfield.py +0 -282
- package/src/superlocalmemory/math/langevin.py +0 -411
- package/src/superlocalmemory/math/polar_quant.py +0 -414
- package/src/superlocalmemory/math/qjl.py +0 -115
- package/src/superlocalmemory/math/sheaf.py +0 -261
- package/src/superlocalmemory/math/turbo_quant.py +0 -318
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +0 -203
- package/src/superlocalmemory/mcp/_pool_adapter.py +0 -181
- package/src/superlocalmemory/mcp/_stdin_guard.py +0 -60
- package/src/superlocalmemory/mcp/agent_context.py +0 -115
- package/src/superlocalmemory/mcp/cli_fallback.py +0 -602
- package/src/superlocalmemory/mcp/http_transport.py +0 -85
- package/src/superlocalmemory/mcp/profiles.py +0 -154
- package/src/superlocalmemory/mcp/resources.py +0 -281
- package/src/superlocalmemory/mcp/server.py +0 -480
- package/src/superlocalmemory/mcp/session_binding.py +0 -98
- package/src/superlocalmemory/mcp/shared.py +0 -112
- package/src/superlocalmemory/mcp/tools.py +0 -18
- package/src/superlocalmemory/mcp/tools_active.py +0 -958
- package/src/superlocalmemory/mcp/tools_brain.py +0 -298
- package/src/superlocalmemory/mcp/tools_code_graph.py +0 -1717
- package/src/superlocalmemory/mcp/tools_context.py +0 -239
- package/src/superlocalmemory/mcp/tools_core.py +0 -1112
- package/src/superlocalmemory/mcp/tools_evolution.py +0 -343
- package/src/superlocalmemory/mcp/tools_learning.py +0 -393
- package/src/superlocalmemory/mcp/tools_loops.py +0 -345
- package/src/superlocalmemory/mcp/tools_mesh.py +0 -429
- package/src/superlocalmemory/mcp/tools_ops.py +0 -115
- package/src/superlocalmemory/mcp/tools_optimize.py +0 -322
- package/src/superlocalmemory/mcp/tools_summaries.py +0 -147
- package/src/superlocalmemory/mcp/tools_v28.py +0 -292
- package/src/superlocalmemory/mcp/tools_v3.py +0 -398
- package/src/superlocalmemory/mcp/tools_v33.py +0 -507
- package/src/superlocalmemory/mesh/__init__.py +0 -12
- package/src/superlocalmemory/mesh/broker.py +0 -812
- package/src/superlocalmemory/mesh/broker_security.py +0 -470
- package/src/superlocalmemory/mesh/discovery.py +0 -365
- package/src/superlocalmemory/mesh/lock_protocol.py +0 -313
- package/src/superlocalmemory/mesh/node_identity.py +0 -97
- package/src/superlocalmemory/mesh/outbox_remote.py +0 -429
- package/src/superlocalmemory/mesh/remote_sync.py +0 -829
- package/src/superlocalmemory/mesh/state_sync.py +0 -286
- package/src/superlocalmemory/migrations/__init__.py +0 -5
- package/src/superlocalmemory/migrations/v3_4_25_to_v3_4_26.py +0 -144
- package/src/superlocalmemory/optimize/NOTICE +0 -6
- package/src/superlocalmemory/optimize/__init__.py +0 -0
- package/src/superlocalmemory/optimize/adapters/__init__.py +0 -68
- package/src/superlocalmemory/optimize/adapters/_agent_registry.py +0 -120
- package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +0 -112
- package/src/superlocalmemory/optimize/adapters/openai_adapter.py +0 -122
- package/src/superlocalmemory/optimize/adapters/wrap.py +0 -228
- package/src/superlocalmemory/optimize/cache/__init__.py +0 -31
- package/src/superlocalmemory/optimize/cache/boundary_store.py +0 -488
- package/src/superlocalmemory/optimize/cache/centroid_store.py +0 -199
- package/src/superlocalmemory/optimize/cache/context_key.py +0 -67
- package/src/superlocalmemory/optimize/cache/exact.py +0 -88
- package/src/superlocalmemory/optimize/cache/invalidation.py +0 -36
- package/src/superlocalmemory/optimize/cache/key_builder.py +0 -111
- package/src/superlocalmemory/optimize/cache/manager.py +0 -737
- package/src/superlocalmemory/optimize/cache/semantic.py +0 -637
- package/src/superlocalmemory/optimize/cache/stampede.py +0 -50
- package/src/superlocalmemory/optimize/compress/__init__.py +0 -17
- package/src/superlocalmemory/optimize/compress/align.py +0 -159
- package/src/superlocalmemory/optimize/compress/ccr.py +0 -116
- package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +0 -71
- package/src/superlocalmemory/optimize/compress/router.py +0 -667
- package/src/superlocalmemory/optimize/config/__init__.py +0 -56
- package/src/superlocalmemory/optimize/config/defaults.py +0 -43
- package/src/superlocalmemory/optimize/config/schema.py +0 -327
- package/src/superlocalmemory/optimize/config/store.py +0 -270
- package/src/superlocalmemory/optimize/metrics/__init__.py +0 -8
- package/src/superlocalmemory/optimize/metrics/counters.py +0 -155
- package/src/superlocalmemory/optimize/metrics/estimator.py +0 -87
- package/src/superlocalmemory/optimize/metrics/exporters.py +0 -77
- package/src/superlocalmemory/optimize/metrics/persistence.py +0 -115
- package/src/superlocalmemory/optimize/proxy/__init__.py +0 -28
- package/src/superlocalmemory/optimize/proxy/_helpers.py +0 -730
- package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +0 -375
- package/src/superlocalmemory/optimize/proxy/capture.py +0 -550
- package/src/superlocalmemory/optimize/proxy/gemini_surface.py +0 -528
- package/src/superlocalmemory/optimize/proxy/lifecycle.py +0 -126
- package/src/superlocalmemory/optimize/proxy/openai_surface.py +0 -465
- package/src/superlocalmemory/optimize/proxy/server.py +0 -199
- package/src/superlocalmemory/optimize/proxy/vertex_surface.py +0 -246
- package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
- package/src/superlocalmemory/optimize/storage/db.py +0 -1185
- package/src/superlocalmemory/optimize/storage/schema.py +0 -205
- package/src/superlocalmemory/parameterization/__init__.py +0 -47
- package/src/superlocalmemory/parameterization/cross_project.py +0 -12
- package/src/superlocalmemory/parameterization/pattern_extractor.py +0 -584
- package/src/superlocalmemory/parameterization/pii_filter.py +0 -106
- package/src/superlocalmemory/parameterization/prompt_injector.py +0 -219
- package/src/superlocalmemory/parameterization/prompt_lifecycle.py +0 -281
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +0 -542
- package/src/superlocalmemory/parameterization/workflow_miner.py +0 -17
- package/src/superlocalmemory/reliability/__init__.py +0 -45
- package/src/superlocalmemory/reliability/join_liveness.py +0 -301
- package/src/superlocalmemory/reliability/prior_distance.py +0 -243
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +0 -367
- package/src/superlocalmemory/retrieval/ann_index.py +0 -235
- package/src/superlocalmemory/retrieval/bm25_channel.py +0 -451
- package/src/superlocalmemory/retrieval/bridge_discovery.py +0 -253
- package/src/superlocalmemory/retrieval/channel_registry.py +0 -154
- package/src/superlocalmemory/retrieval/channel_status.py +0 -117
- package/src/superlocalmemory/retrieval/engine.py +0 -1615
- package/src/superlocalmemory/retrieval/entity_channel.py +0 -994
- package/src/superlocalmemory/retrieval/forgetting_filter.py +0 -160
- package/src/superlocalmemory/retrieval/fusion.py +0 -81
- package/src/superlocalmemory/retrieval/graph_adjacency.py +0 -219
- package/src/superlocalmemory/retrieval/hopfield_channel.py +0 -465
- package/src/superlocalmemory/retrieval/profile_channel.py +0 -105
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +0 -147
- package/src/superlocalmemory/retrieval/remote_reranker.py +0 -758
- package/src/superlocalmemory/retrieval/reranker.py +0 -674
- package/src/superlocalmemory/retrieval/scope_policy.py +0 -126
- package/src/superlocalmemory/retrieval/semantic_channel.py +0 -638
- package/src/superlocalmemory/retrieval/spreading.py +0 -288
- package/src/superlocalmemory/retrieval/spreading_activation.py +0 -616
- package/src/superlocalmemory/retrieval/strategy.py +0 -248
- package/src/superlocalmemory/retrieval/temporal_channel.py +0 -433
- package/src/superlocalmemory/retrieval/temporal_frame.py +0 -102
- package/src/superlocalmemory/retrieval/temporal_utils.py +0 -122
- package/src/superlocalmemory/retrieval/temporal_validity_filter.py +0 -499
- package/src/superlocalmemory/retrieval/time_window.py +0 -181
- package/src/superlocalmemory/retrieval/vector_store.py +0 -863
- package/src/superlocalmemory/server/__init__.py +0 -1
- package/src/superlocalmemory/server/api.py +0 -310
- package/src/superlocalmemory/server/asset_versions.py +0 -171
- package/src/superlocalmemory/server/bandit_loops.py +0 -158
- package/src/superlocalmemory/server/config_file.py +0 -90
- package/src/superlocalmemory/server/consolidation_runner.py +0 -140
- package/src/superlocalmemory/server/egress_policy.py +0 -258
- package/src/superlocalmemory/server/loopback.py +0 -85
- package/src/superlocalmemory/server/middleware/__init__.py +0 -11
- package/src/superlocalmemory/server/middleware/security_headers.py +0 -144
- package/src/superlocalmemory/server/origin.py +0 -55
- package/src/superlocalmemory/server/profile_runtime.py +0 -515
- package/src/superlocalmemory/server/rbac_enforce.py +0 -194
- package/src/superlocalmemory/server/recall_health.py +0 -343
- package/src/superlocalmemory/server/recall_serializer.py +0 -320
- package/src/superlocalmemory/server/route_mutations.py +0 -104
- package/src/superlocalmemory/server/routes/__init__.py +0 -4
- package/src/superlocalmemory/server/routes/abstraction.py +0 -314
- package/src/superlocalmemory/server/routes/adapters.py +0 -63
- package/src/superlocalmemory/server/routes/agents.py +0 -303
- package/src/superlocalmemory/server/routes/backup.py +0 -869
- package/src/superlocalmemory/server/routes/behavioral.py +0 -659
- package/src/superlocalmemory/server/routes/brain.py +0 -1892
- package/src/superlocalmemory/server/routes/chat.py +0 -393
- package/src/superlocalmemory/server/routes/compliance.py +0 -533
- package/src/superlocalmemory/server/routes/config_api.py +0 -703
- package/src/superlocalmemory/server/routes/data_io.py +0 -329
- package/src/superlocalmemory/server/routes/entity.py +0 -237
- package/src/superlocalmemory/server/routes/events.py +0 -214
- package/src/superlocalmemory/server/routes/evolution.py +0 -510
- package/src/superlocalmemory/server/routes/helpers.py +0 -499
- package/src/superlocalmemory/server/routes/ingest.py +0 -137
- package/src/superlocalmemory/server/routes/insights.py +0 -366
- package/src/superlocalmemory/server/routes/learning.py +0 -834
- package/src/superlocalmemory/server/routes/learning_telemetry.py +0 -154
- package/src/superlocalmemory/server/routes/lifecycle.py +0 -184
- package/src/superlocalmemory/server/routes/memories.py +0 -1661
- package/src/superlocalmemory/server/routes/mesh.py +0 -517
- package/src/superlocalmemory/server/routes/mesh_lock.py +0 -54
- package/src/superlocalmemory/server/routes/mesh_state.py +0 -63
- package/src/superlocalmemory/server/routes/optimize.py +0 -197
- package/src/superlocalmemory/server/routes/prewarm.py +0 -173
- package/src/superlocalmemory/server/routes/profiles.py +0 -292
- package/src/superlocalmemory/server/routes/ratelimit.py +0 -132
- package/src/superlocalmemory/server/routes/rbac.py +0 -366
- package/src/superlocalmemory/server/routes/stats.py +0 -385
- package/src/superlocalmemory/server/routes/tiers.py +0 -222
- package/src/superlocalmemory/server/routes/timeline.py +0 -258
- package/src/superlocalmemory/server/routes/token.py +0 -90
- package/src/superlocalmemory/server/routes/v3_api.py +0 -3023
- package/src/superlocalmemory/server/routes/ws.py +0 -171
- package/src/superlocalmemory/server/security_middleware.py +0 -89
- package/src/superlocalmemory/server/ui.py +0 -354
- package/src/superlocalmemory/server/unified_daemon.py +0 -6326
- package/src/superlocalmemory/server/write_identity.py +0 -195
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/_migration_internals.py +0 -638
- package/src/superlocalmemory/storage/_schema_version.py +0 -174
- package/src/superlocalmemory/storage/access_log.py +0 -170
- package/src/superlocalmemory/storage/admission_codec.py +0 -129
- package/src/superlocalmemory/storage/admission_journal.py +0 -843
- package/src/superlocalmemory/storage/agent_experience.py +0 -546
- package/src/superlocalmemory/storage/backup.py +0 -531
- package/src/superlocalmemory/storage/correction_cases.py +0 -670
- package/src/superlocalmemory/storage/database.py +0 -3180
- package/src/superlocalmemory/storage/deferred_writes.py +0 -209
- package/src/superlocalmemory/storage/embedding_codec.py +0 -200
- package/src/superlocalmemory/storage/embedding_migrator.py +0 -672
- package/src/superlocalmemory/storage/erasure_fence.py +0 -45
- package/src/superlocalmemory/storage/execution_learning.py +0 -285
- package/src/superlocalmemory/storage/external_evidence.py +0 -359
- package/src/superlocalmemory/storage/generation_fence.py +0 -63
- package/src/superlocalmemory/storage/lineage_retention.py +0 -236
- package/src/superlocalmemory/storage/logical_edges.py +0 -86
- package/src/superlocalmemory/storage/memory_write.py +0 -115
- package/src/superlocalmemory/storage/migration_runner.py +0 -895
- package/src/superlocalmemory/storage/migration_v33.py +0 -140
- package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +0 -67
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +0 -107
- package/src/superlocalmemory/storage/migrations/M003_migration_log.py +0 -38
- package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +0 -46
- package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +0 -75
- package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +0 -75
- package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +0 -63
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +0 -94
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +0 -80
- package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +0 -87
- package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +0 -72
- package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +0 -55
- package/src/superlocalmemory/storage/migrations/M014_v345_scale_ready.py +0 -45
- package/src/superlocalmemory/storage/migrations/M015_add_pinned_column.py +0 -58
- package/src/superlocalmemory/storage/migrations/M016_add_scope_support.py +0 -120
- package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +0 -79
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +0 -120
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +0 -54
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +0 -52
- package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +0 -108
- package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +0 -86
- package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +0 -194
- package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +0 -87
- package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +0 -90
- package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +0 -136
- package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +0 -163
- package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +0 -305
- package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +0 -137
- package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +0 -93
- package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +0 -80
- package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +0 -188
- package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +0 -148
- package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +0 -58
- package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +0 -113
- package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +0 -107
- package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +0 -162
- package/src/superlocalmemory/storage/migrations/M038_learning_feedback_channel.py +0 -77
- package/src/superlocalmemory/storage/migrations/M039_scene_fact_members.py +0 -137
- package/src/superlocalmemory/storage/migrations/M040_agent_experience_receipts.py +0 -254
- package/src/superlocalmemory/storage/migrations/M041_external_evidence_receipts.py +0 -189
- package/src/superlocalmemory/storage/migrations/M042_correction_case_ledger.py +0 -245
- package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +0 -512
- package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +0 -127
- package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +0 -158
- package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +0 -620
- package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +0 -306
- package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +0 -229
- package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +0 -201
- package/src/superlocalmemory/storage/migrations/M050_execution_learning_v2.py +0 -70
- package/src/superlocalmemory/storage/migrations/__init__.py +0 -103
- package/src/superlocalmemory/storage/migrations.py +0 -333
- package/src/superlocalmemory/storage/models.py +0 -500
- package/src/superlocalmemory/storage/projection_outbox.py +0 -346
- package/src/superlocalmemory/storage/quantized_store.py +0 -280
- package/src/superlocalmemory/storage/read_connection.py +0 -115
- package/src/superlocalmemory/storage/retention_policy.py +0 -860
- package/src/superlocalmemory/storage/schema.py +0 -1108
- package/src/superlocalmemory/storage/schema_code_graph.py +0 -282
- package/src/superlocalmemory/storage/schema_v32.py +0 -382
- package/src/superlocalmemory/storage/schema_v3410.py +0 -159
- package/src/superlocalmemory/storage/schema_v3411.py +0 -149
- package/src/superlocalmemory/storage/schema_v343.py +0 -315
- package/src/superlocalmemory/storage/schema_v345.py +0 -109
- package/src/superlocalmemory/storage/schema_v347.py +0 -140
- package/src/superlocalmemory/storage/sqlite_vectors.py +0 -169
- package/src/superlocalmemory/storage/v2_migrator.py +0 -466
- package/src/superlocalmemory/storage/write_coordinator.py +0 -949
- package/src/superlocalmemory/storage/write_lock.py +0 -88
- package/src/superlocalmemory/summaries/__init__.py +0 -37
- package/src/superlocalmemory/summaries/base.py +0 -267
- package/src/superlocalmemory/summaries/daily_reflection.py +0 -340
- package/src/superlocalmemory/summaries/non_answer.py +0 -223
- package/src/superlocalmemory/summaries/project_work_log.py +0 -440
- package/src/superlocalmemory/summaries/session_summary.py +0 -311
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +0 -171
- package/src/superlocalmemory/trust/provenance.py +0 -124
- package/src/superlocalmemory/trust/scorer.py +0 -413
- package/src/superlocalmemory/trust/signals.py +0 -153
- package/src/superlocalmemory/ui/assets/slm-icon-white.svg +0 -64
- package/src/superlocalmemory/ui/assets/slm-icon.svg +0 -36
- package/src/superlocalmemory/ui/css/brain.css +0 -409
- package/src/superlocalmemory/ui/css/design-system.css +0 -696
- package/src/superlocalmemory/ui/css/legacy-dashboard.css +0 -663
- package/src/superlocalmemory/ui/css/neural-glass.css +0 -1599
- package/src/superlocalmemory/ui/css/od-bridge.css +0 -158
- package/src/superlocalmemory/ui/favicon.svg +0 -36
- package/src/superlocalmemory/ui/index.html +0 -1638
- package/src/superlocalmemory/ui/js/agents.js +0 -192
- package/src/superlocalmemory/ui/js/auto-settings.js +0 -624
- package/src/superlocalmemory/ui/js/brain.js +0 -1400
- package/src/superlocalmemory/ui/js/clusters.js +0 -326
- package/src/superlocalmemory/ui/js/compliance.js +0 -307
- package/src/superlocalmemory/ui/js/core.js +0 -566
- package/src/superlocalmemory/ui/js/dashboard.js +0 -503
- package/src/superlocalmemory/ui/js/event-delegation.js +0 -113
- package/src/superlocalmemory/ui/js/events.js +0 -178
- package/src/superlocalmemory/ui/js/fact-detail.js +0 -142
- package/src/superlocalmemory/ui/js/feedback.js +0 -339
- package/src/superlocalmemory/ui/js/graph-event-bus.js +0 -83
- package/src/superlocalmemory/ui/js/graph-filters.js +0 -220
- package/src/superlocalmemory/ui/js/graph-ui.js +0 -214
- package/src/superlocalmemory/ui/js/ide-status.js +0 -115
- package/src/superlocalmemory/ui/js/init.js +0 -54
- package/src/superlocalmemory/ui/js/knowledge-graph.js +0 -945
- package/src/superlocalmemory/ui/js/lifecycle.js +0 -387
- package/src/superlocalmemory/ui/js/math-health.js +0 -114
- package/src/superlocalmemory/ui/js/memories.js +0 -394
- package/src/superlocalmemory/ui/js/memory-chat.js +0 -371
- package/src/superlocalmemory/ui/js/memory-timeline.js +0 -265
- package/src/superlocalmemory/ui/js/modal.js +0 -733
- package/src/superlocalmemory/ui/js/ng-entities.js +0 -298
- package/src/superlocalmemory/ui/js/ng-health.js +0 -208
- package/src/superlocalmemory/ui/js/ng-ingestion.js +0 -203
- package/src/superlocalmemory/ui/js/ng-mesh.js +0 -374
- package/src/superlocalmemory/ui/js/ng-shell.js +0 -524
- package/src/superlocalmemory/ui/js/ng-skills.js +0 -663
- package/src/superlocalmemory/ui/js/od-agents.js +0 -588
- package/src/superlocalmemory/ui/js/od-auth-gate.js +0 -257
- package/src/superlocalmemory/ui/js/od-backup.js +0 -878
- package/src/superlocalmemory/ui/js/od-boundedloops.js +0 -324
- package/src/superlocalmemory/ui/js/od-brain.js +0 -1095
- package/src/superlocalmemory/ui/js/od-compliance-ext.js +0 -301
- package/src/superlocalmemory/ui/js/od-components.js +0 -147
- package/src/superlocalmemory/ui/js/od-entities.js +0 -622
- package/src/superlocalmemory/ui/js/od-graph.js +0 -776
- package/src/superlocalmemory/ui/js/od-health.js +0 -579
- package/src/superlocalmemory/ui/js/od-mcp.js +0 -508
- package/src/superlocalmemory/ui/js/od-memories.js +0 -1499
- package/src/superlocalmemory/ui/js/od-mesh.js +0 -645
- package/src/superlocalmemory/ui/js/od-operations.js +0 -1268
- package/src/superlocalmemory/ui/js/od-ops-health.js +0 -417
- package/src/superlocalmemory/ui/js/od-optimize.js +0 -828
- package/src/superlocalmemory/ui/js/od-settings.js +0 -1275
- package/src/superlocalmemory/ui/js/od-shell.js +0 -819
- package/src/superlocalmemory/ui/js/od-skills.js +0 -600
- package/src/superlocalmemory/ui/js/od-team.js +0 -265
- package/src/superlocalmemory/ui/js/optimize.js +0 -191
- package/src/superlocalmemory/ui/js/profiles.js +0 -362
- package/src/superlocalmemory/ui/js/quick-actions.js +0 -334
- package/src/superlocalmemory/ui/js/recall-lab.js +0 -373
- package/src/superlocalmemory/ui/js/search.js +0 -86
- package/src/superlocalmemory/ui/js/settings.js +0 -556
- package/src/superlocalmemory/ui/js/timeline.js +0 -62
- package/src/superlocalmemory/ui/js/trust-dashboard.js +0 -225
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +0 -2018
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +0 -7
- package/src/superlocalmemory/ui/vendor/bootstrap.min.css +0 -6
- package/src/superlocalmemory/ui/vendor/d3.v7.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology-library.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +0 -8
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/sigma.min.js +0 -1
- package/src/superlocalmemory/vector/__init__.py +0 -9
- package/src/superlocalmemory/vector/lancedb_backend.py +0 -366
|
@@ -1,1499 +0,0 @@
|
|
|
1
|
-
// od-memories.js — Memories · Timeline · Knowledge Clusters (OD design port)
|
|
2
|
-
// Render: #memories-pane | Public: window.odRenderMemories(container)
|
|
3
|
-
// CSP-safe: data-od-act event delegation. XSS-safe: _esc() on all API values.
|
|
4
|
-
// nosemgrep: innerHTML — all dynamic values escaped via _esc()
|
|
5
|
-
//
|
|
6
|
-
// Endpoints (live daemon 127.0.0.1:8765):
|
|
7
|
-
// GET /api/memories?limit=N&offset=N[&category=X]
|
|
8
|
-
// → { memories[{id,memory_id,content,category,importance(0-1),
|
|
9
|
-
// access_count,created_at,project_name}], total }
|
|
10
|
-
// GET /api/memories/{id}/facts → { facts[{fact_type,content}] }
|
|
11
|
-
// GET /api/v3/timeline/?range=Xd&group_by=category&limit=N
|
|
12
|
-
// → { events[{id,timestamp,category}] }
|
|
13
|
-
// GET /api/clusters → { clusters[{cluster_id,member_count,categories,summary}] }
|
|
14
|
-
// GET /api/clusters/{id}?limit=N → { members[], summary }
|
|
15
|
-
// TODO: /api/memories/{id}/score-breakdown — Semantic/BM25/Entity/Temporal not yet exposed.
|
|
16
|
-
(function () {
|
|
17
|
-
'use strict';
|
|
18
|
-
|
|
19
|
-
// ── Utilities ───────────────────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
function _esc(s) {
|
|
22
|
-
if (typeof escapeHtml === 'function') return escapeHtml(s);
|
|
23
|
-
var d = document.createElement('div');
|
|
24
|
-
d.textContent = String(s == null ? '' : s);
|
|
25
|
-
return d.innerHTML;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function _fmt(iso) {
|
|
29
|
-
if (!iso) return '—';
|
|
30
|
-
var d = new Date(iso);
|
|
31
|
-
return isNaN(d.getTime()) ? String(iso) : d.toLocaleDateString();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function _ago(iso) {
|
|
35
|
-
if (!iso) return '';
|
|
36
|
-
var s = (Date.now() - new Date(iso).getTime()) / 1000;
|
|
37
|
-
if (s < 0) s = 0;
|
|
38
|
-
if (s < 60) return Math.floor(s) + 's ago';
|
|
39
|
-
if (s < 3600) return Math.floor(s / 60) + 'm ago';
|
|
40
|
-
if (s < 86400) return Math.floor(s / 3600) + 'h ago';
|
|
41
|
-
return Math.floor(s / 86400) + 'd ago';
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// importance arrives as 0–1 float; display as X/10 integer
|
|
45
|
-
function _imp(raw) { return Math.round((parseFloat(raw) || 0) * 10); }
|
|
46
|
-
|
|
47
|
-
// importance (0–1) → badge class for Score column
|
|
48
|
-
function _scoreCls(raw) {
|
|
49
|
-
var v = parseFloat(raw) || 0;
|
|
50
|
-
return v >= 0.7 ? 'ok' : v >= 0.4 ? 'warn' : 'danger';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// API category → badge class
|
|
54
|
-
function _catCls(cat) {
|
|
55
|
-
var MAP = { semantic: 'violet', episodic: 'cyan', opinion: 'warn',
|
|
56
|
-
temporal: 'ok', consolidation: 'danger' };
|
|
57
|
-
return MAP[String(cat).toLowerCase()] || 'neutral';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Normalize /api/search result → memory shape (fact_id→id, score→importance)
|
|
61
|
-
function _normSearch(r) { return {id:r.fact_id||r.memory_id||'',content:r.content||'',category:r.category||'semantic',project_name:r.project_name||'',importance:r.score||r.confidence||0,created_at:r.created_at||'',access_count:r.access_count||0}; }
|
|
62
|
-
// shared_with is stored as a JSON array string; show it comma-separated.
|
|
63
|
-
function _sharedToStr(v) {
|
|
64
|
-
if (!v) return '';
|
|
65
|
-
if (Array.isArray(v)) return v.join(', ');
|
|
66
|
-
try { var a = JSON.parse(v); return Array.isArray(a) ? a.join(', ') : ''; }
|
|
67
|
-
catch (e) { return ''; }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Write-auth token: reuses dashboard.js closure when available, else fails gracefully
|
|
71
|
-
function _getMutToken() { return typeof window.dashboardInstallToken==='function'?window.dashboardInstallToken():Promise.resolve(''); }
|
|
72
|
-
|
|
73
|
-
// ── CSS (injected once) ─────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
var _cssInjected = false;
|
|
76
|
-
function _injectCSS() {
|
|
77
|
-
if (_cssInjected) return;
|
|
78
|
-
_cssInjected = true;
|
|
79
|
-
var s = document.createElement('style');
|
|
80
|
-
s.dataset.odModule = 'memories';
|
|
81
|
-
s.textContent =
|
|
82
|
-
'.od-drawer{position:fixed;top:0;right:0;height:100vh;width:420px;max-width:92vw;' +
|
|
83
|
-
'background:var(--card);border-left:1px solid var(--border);box-shadow:var(--sh-lg);' +
|
|
84
|
-
'transform:translateX(100%);transition:transform .28s cubic-bezier(.22,1,.36,1);' +
|
|
85
|
-
'z-index:60;overflow-y:auto;padding:24px;}' +
|
|
86
|
-
'.od-drawer.open{transform:none;}' +
|
|
87
|
-
'.od-drawer-scrim{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:59;' +
|
|
88
|
-
'opacity:0;pointer-events:none;transition:opacity .25s;}' +
|
|
89
|
-
'.od-drawer-scrim.on{opacity:1;pointer-events:auto;}' +
|
|
90
|
-
'.od-prov{padding:14px;border-radius:var(--r-md);background:var(--card-2);' +
|
|
91
|
-
'border:1px solid var(--border);margin-top:12px;}';
|
|
92
|
-
document.head.appendChild(s);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ── Module state ────────────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
var _st = {
|
|
98
|
-
rootId: null,
|
|
99
|
-
// Must match the pane carrying `active` in _scaffold(). Recall Lab leads.
|
|
100
|
-
activeTab: 'recall',
|
|
101
|
-
category: null, // null = all; string = filtered category
|
|
102
|
-
sort: 'created',
|
|
103
|
-
page: 0,
|
|
104
|
-
pageSize: 50,
|
|
105
|
-
total: 0,
|
|
106
|
-
memories: [],
|
|
107
|
-
catCounts: {}, // pre-fetched per-category totals
|
|
108
|
-
tlRange: '30d',
|
|
109
|
-
cluLoaded: false, // reset in render() to avoid stale state on re-entry
|
|
110
|
-
searchQ: null,
|
|
111
|
-
requestSeq: 0,
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Known categories from the daemon (pre-fetched at render time)
|
|
115
|
-
var KNOWN_CATS = ['semantic', 'episodic', 'opinion', 'temporal', 'consolidation'];
|
|
116
|
-
|
|
117
|
-
// ── Main entry ──────────────────────────────────────────────────────────────
|
|
118
|
-
|
|
119
|
-
function render(container) {
|
|
120
|
-
if (!container) return;
|
|
121
|
-
_injectCSS();
|
|
122
|
-
var id = 'od-mem-' + Math.random().toString(36).slice(2, 8);
|
|
123
|
-
// activeTab is reset explicitly: _scaffold always emits the Recall pane as the
|
|
124
|
-
// active one, so leaving a stale value here (from a tab click before the user
|
|
125
|
-
// navigated away and back) would desync state from what is actually on screen.
|
|
126
|
-
_st = Object.assign({}, _st, {
|
|
127
|
-
rootId: id, page: 0, category: null, sort: 'created', activeTab: 'recall',
|
|
128
|
-
memories: [], catCounts: {}, cluLoaded: false, searchQ: null, requestSeq: 0,
|
|
129
|
-
});
|
|
130
|
-
// Clear per-id timeline cache for this render instance
|
|
131
|
-
_tlLoaded = {};
|
|
132
|
-
container.innerHTML = _scaffold(id);
|
|
133
|
-
_wire(container, id);
|
|
134
|
-
// Fire initial loads in parallel
|
|
135
|
-
_loadMem(id);
|
|
136
|
-
_loadCatCounts(id);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// ── Scaffold HTML ────────────────────────────────────────────────────────────
|
|
140
|
-
|
|
141
|
-
function _scaffold(id) {
|
|
142
|
-
return (
|
|
143
|
-
'<div id="' + id + '">' +
|
|
144
|
-
'<div class="page-head">' +
|
|
145
|
-
'<h2>Everything you\'ve remembered</h2>' +
|
|
146
|
-
'<p id="' + id + '-sub" style="color:var(--fg-2);margin-top:5px">Loading…</p>' +
|
|
147
|
-
'</div>' +
|
|
148
|
-
// Tab order is deliberate (owner request, 4.0.8): the two tabs that ANSWER
|
|
149
|
-
// a question come first, the three that BROWSE data come after. Someone who
|
|
150
|
-
// opens this page usually wants "what do you know about X" or "what did I do
|
|
151
|
-
// today" — not a 3,600-row table sorted by insert time.
|
|
152
|
-
'<div class="tabs" id="' + id + '-tabs">' +
|
|
153
|
-
// Recall Lab — recall-lab.js is loaded in index.html and uses document-level
|
|
154
|
-
// click/keydown delegation keyed on the IDs below, so it survives re-renders.
|
|
155
|
-
'<button class="tab active" data-od-act="tab" data-tab="recall">Recall Lab</button>' +
|
|
156
|
-
'<button class="tab" data-od-act="tab" data-tab="summary">Summaries</button>' +
|
|
157
|
-
'<button class="tab" data-od-act="tab" data-tab="all">' +
|
|
158
|
-
'All memories <span class="cnt" id="' + id + '-cnt-all">…</span></button>' +
|
|
159
|
-
'<button class="tab" data-od-act="tab" data-tab="timeline">Creation timeline</button>' +
|
|
160
|
-
'<button class="tab" data-od-act="tab" data-tab="clusters">' +
|
|
161
|
-
'Knowledge clusters <span class="cnt" id="' + id + '-cnt-clusters">…</span></button>' +
|
|
162
|
-
'</div>' +
|
|
163
|
-
'<div class="tabpane" id="' + id + '-pane-all">' + _allScaffold(id) + '</div>' +
|
|
164
|
-
'<div class="tabpane" id="' + id + '-pane-timeline">' + _tlScaffold(id) + '</div>' +
|
|
165
|
-
'<div class="tabpane" id="' + id + '-pane-clusters">' +
|
|
166
|
-
'<div class="launch-grid" id="' + id + '-clu-grid">' +
|
|
167
|
-
_loading('Loading clusters…') +
|
|
168
|
-
'</div>' +
|
|
169
|
-
'</div>' +
|
|
170
|
-
'<div class="tabpane" id="' + id + '-pane-summary" style="padding-top:12px">' +
|
|
171
|
-
'<p style="font-size:13px;color:var(--fg-2);margin-bottom:12px">'+
|
|
172
|
-
'A readable view of what you recorded. Every summary states how much '+
|
|
173
|
-
'of the underlying data it could actually cover.' +
|
|
174
|
-
'</p>' +
|
|
175
|
-
// "This project" used to be a button sending an empty target, which the
|
|
176
|
-
// API rejected every single time with "project requires target". It could
|
|
177
|
-
// not have worked: SLM runs as one global daemon and this is a browser
|
|
178
|
-
// tab — there is no current working directory to mean "this". The server
|
|
179
|
-
// lists the projects it has actually seen and the user picks one.
|
|
180
|
-
'<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:14px">' +
|
|
181
|
-
'<button class="tab" data-od-act="sum" data-kind="day" data-target="today">Today</button>' +
|
|
182
|
-
'<button class="tab" data-od-act="sum" data-kind="day" data-target="yesterday">Yesterday</button>' +
|
|
183
|
-
'<select id="' + id + '-sum-proj" data-od-act="sum-proj" ' +
|
|
184
|
-
'title="Projects SuperLocalMemory has recorded activity in" ' +
|
|
185
|
-
'style="padding:7px 10px;border:1px solid var(--border);' +
|
|
186
|
-
'border-radius:var(--r-md);background:var(--card-2);color:var(--fg);' +
|
|
187
|
-
'font-size:13px;max-width:340px">' +
|
|
188
|
-
'<option value="">Loading projects…</option>' +
|
|
189
|
-
'</select>' +
|
|
190
|
-
'</div>' +
|
|
191
|
-
'<div id="' + id + '-sum-out" style="font-size:13px;color:var(--fg-2)">Pick a summary above.</div>' +
|
|
192
|
-
// Knowledge Overview.
|
|
193
|
-
//
|
|
194
|
-
// The Today/Yesterday buttons above are a date filter over
|
|
195
|
-
// atomic_facts and have never had any link to a cluster, so the
|
|
196
|
-
// Summaries tab could not show what the store actually knows ABOUT
|
|
197
|
-
// anything. This card fills that: cluster summaries, read from the
|
|
198
|
-
// display-only table, which is where they belong now that they are
|
|
199
|
-
// out of the retrieval corpus.
|
|
200
|
-
'<div id="' + id + '-kover" style="margin-top:26px;' +
|
|
201
|
-
'border-top:1px solid var(--border);padding-top:20px">' +
|
|
202
|
-
_loading('Loading what your memory knows…') +
|
|
203
|
-
'</div>' +
|
|
204
|
-
'</div>' +
|
|
205
|
-
// Recall Lab pane — exact IDs required by recall-lab.js:
|
|
206
|
-
// #recall-lab-query (input), #recall-lab-search (button — click check),
|
|
207
|
-
// #recall-lab-per-page (select, optional), #recall-lab-meta, #recall-lab-results.
|
|
208
|
-
// Backend: POST /api/v3/recall/trace
|
|
209
|
-
//
|
|
210
|
-
// This is now the landing pane, so it has to explain itself to someone who
|
|
211
|
-
// has never heard the word "recall" in this sense. An empty search box as a
|
|
212
|
-
// first impression tells a non-technical user nothing about what SLM does.
|
|
213
|
-
'<div class="tabpane active" id="' + id + '-pane-recall" style="padding-top:12px">' +
|
|
214
|
-
'<div style="margin-bottom:14px">' +
|
|
215
|
-
'<p style="font-size:13px;color:var(--fg-2);margin-bottom:10px">' +
|
|
216
|
-
'Ask your memory a question and watch it answer. This shows you the ' +
|
|
217
|
-
'same result an AI assistant gets — plus <em>why</em> each memory was ' +
|
|
218
|
-
'chosen, how strongly it matched, and how long the lookup took.' +
|
|
219
|
-
'</p>' +
|
|
220
|
-
'<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">' +
|
|
221
|
-
'<input id="recall-lab-query" placeholder="Enter recall query…" autocomplete="off" ' +
|
|
222
|
-
'style="flex:1;min-width:200px;padding:8px 12px;' +
|
|
223
|
-
'border:1px solid var(--border);border-radius:6px;font-size:13px;' +
|
|
224
|
-
'background:var(--bg-2);color:var(--fg)">' +
|
|
225
|
-
'<select id="recall-lab-per-page" ' +
|
|
226
|
-
'style="padding:7px 10px;border:1px solid var(--border);border-radius:6px;' +
|
|
227
|
-
'font-size:13px;background:var(--bg-2);color:var(--fg)">' +
|
|
228
|
-
'<option value="5">5</option>' +
|
|
229
|
-
'<option value="10" selected>10</option>' +
|
|
230
|
-
'<option value="20">20</option>' +
|
|
231
|
-
'<option value="50">50</option>' +
|
|
232
|
-
'</select>' +
|
|
233
|
-
'<button id="recall-lab-search" ' +
|
|
234
|
-
'style="padding:8px 18px;background:var(--accent);color:#fff;' +
|
|
235
|
-
'border:none;border-radius:6px;font-size:13px;cursor:pointer;' +
|
|
236
|
-
'white-space:nowrap">Run Trace</button>' +
|
|
237
|
-
'</div>' +
|
|
238
|
-
'</div>' +
|
|
239
|
-
// #recall-lab-meta — written by recall-lab.js before results (timing, count, etc.)
|
|
240
|
-
'<div id="recall-lab-meta" ' +
|
|
241
|
-
'style="font-size:12px;color:var(--fg-2);margin-bottom:8px"></div>' +
|
|
242
|
-
// #recall-lab-results — written by recall-lab.js (result cards, pagination).
|
|
243
|
-
// Seeded with a starter state because this pane loads first: a bare box
|
|
244
|
-
// gives a first-time user no idea what to type. recall-lab.js replaces
|
|
245
|
-
// the whole node on the first search, so this costs nothing afterwards.
|
|
246
|
-
'<div id="recall-lab-results">' + _recallStarter() + '</div>' +
|
|
247
|
-
'</div>' +
|
|
248
|
-
'</div>'
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function _allScaffold(id) {
|
|
253
|
-
return (
|
|
254
|
-
'<div style="margin-bottom:16px;display:flex;gap:8px;align-items:center">' +
|
|
255
|
-
'<input data-od-act="search" placeholder="Search all memories…" autocomplete="off" ' +
|
|
256
|
-
'style="flex:1;padding:8px 12px;border:1px solid var(--border);' +
|
|
257
|
-
'border-radius:var(--r-md);background:var(--card-2);color:var(--fg);' +
|
|
258
|
-
'font-size:13.5px;outline:none">' +
|
|
259
|
-
'<select data-od-act="window" title="Limit search to a time window" ' +
|
|
260
|
-
'style="padding:8px 10px;border:1px solid var(--border);border-radius:var(--r-md);' +
|
|
261
|
-
'background:var(--card-2);color:var(--fg);font-size:13px;outline:none">' +
|
|
262
|
-
'<option value="">Any time</option>' +
|
|
263
|
-
'<option value="24h">Last 24h</option>' +
|
|
264
|
-
'<option value="7d">Last 7 days</option>' +
|
|
265
|
-
'<option value="30d">Last 30 days</option>' +
|
|
266
|
-
'<option value="90d">Last 90 days</option>' +
|
|
267
|
-
'<option value="1y">Last year</option>' +
|
|
268
|
-
'</select>' +
|
|
269
|
-
'</div>' +
|
|
270
|
-
// Filter bar: category chips (populated after cat-count fetch) + sort seg
|
|
271
|
-
'<div id="' + id + '-cats" ' +
|
|
272
|
-
'style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px;align-items:center">' +
|
|
273
|
-
'<div class="chip on" data-od-act="cat" data-cat="">All categories</div>' +
|
|
274
|
-
'<div style="flex:1"></div>' +
|
|
275
|
-
// Scope view: Mine (this profile) / Shared with me / Global / Everything
|
|
276
|
-
'<div class="seg" title="Which memories to show">' +
|
|
277
|
-
'<button class="active" data-od-act="scope-view" data-scope="mine">Mine</button>' +
|
|
278
|
-
'<button data-od-act="scope-view" data-scope="shared">Shared</button>' +
|
|
279
|
-
'<button data-od-act="scope-view" data-scope="global">Global</button>' +
|
|
280
|
-
'<button data-od-act="scope-view" data-scope="all">All</button>' +
|
|
281
|
-
'</div>' +
|
|
282
|
-
'<div class="seg">' +
|
|
283
|
-
'<button class="active" data-od-act="sort" data-sort="created">Newest</button>' +
|
|
284
|
-
'<button data-od-act="sort" data-sort="score">Score</button>' +
|
|
285
|
-
'<button data-od-act="sort" data-sort="importance">Importance</button>' +
|
|
286
|
-
'</div>' +
|
|
287
|
-
'</div>' +
|
|
288
|
-
'<div class="card" id="' + id + '-tbl-wrap">' + _loading('Loading memories…') + '</div>' +
|
|
289
|
-
'<div id="' + id + '-pg" style="margin-top:10px"></div>'
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function _tlScaffold(id) {
|
|
294
|
-
return (
|
|
295
|
-
'<div class="card">' +
|
|
296
|
-
'<div class="card-head">' +
|
|
297
|
-
'<h3>Memory creation timeline</h3>' +
|
|
298
|
-
'<span class="sub" id="' + id + '-tl-sub">facts stored per day</span>' +
|
|
299
|
-
'<div style="flex:1"></div>' +
|
|
300
|
-
'<div class="seg">' +
|
|
301
|
-
'<button data-od-act="tl-range" data-range="7d">7d</button>' +
|
|
302
|
-
'<button class="active" data-od-act="tl-range" data-range="30d">30d</button>' +
|
|
303
|
-
'</div>' +
|
|
304
|
-
'</div>' +
|
|
305
|
-
'<div class="card-pad">' +
|
|
306
|
-
'<div class="bars" id="' + id + '-bars" style="height:120px">' +
|
|
307
|
-
_loading('Loading timeline…') +
|
|
308
|
-
'</div>' +
|
|
309
|
-
'<div style="display:flex;justify-content:space-between;margin-top:10px;' +
|
|
310
|
-
'font-size:11.5px;color:var(--fg-3)">' +
|
|
311
|
-
'<span id="' + id + '-tl-start"></span><span>today</span>' +
|
|
312
|
-
'</div>' +
|
|
313
|
-
'</div>' +
|
|
314
|
-
'</div>' +
|
|
315
|
-
'<div class="card" style="margin-top:16px">' +
|
|
316
|
-
'<div class="card-head"><h3>By fact type</h3></div>' +
|
|
317
|
-
'<div class="card-pad" id="' + id + '-ftypes">' + _loading('Loading breakdown…') + '</div>' +
|
|
318
|
-
'</div>'
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function _loading(msg) {
|
|
323
|
-
return '<div style="padding:40px;text-align:center;color:var(--fg-2);font-size:13px">' +
|
|
324
|
-
_esc(msg) + '</div>';
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/* Starter state for Recall Lab.
|
|
328
|
-
*
|
|
329
|
-
* Recall Lab is the landing pane, so this is the first thing most people see in
|
|
330
|
-
* the dashboard. It has to answer "what is this and what do I type" without
|
|
331
|
-
* assuming the reader knows what a recall trace is.
|
|
332
|
-
*
|
|
333
|
-
* The examples are deliberately static. Seeding them from real memories was the
|
|
334
|
-
* first idea and it is worse: stored content is things like
|
|
335
|
-
* "[claude][SLM 4.0.8 CHECKPOINT] RELEASE STATE: local", which teaches exactly
|
|
336
|
-
* the wrong query shape. These teach the shape; the store answers.
|
|
337
|
-
*/
|
|
338
|
-
var RECALL_EGS = [
|
|
339
|
-
'what did I decide about the database',
|
|
340
|
-
'what am I working on',
|
|
341
|
-
'what problems have I hit before',
|
|
342
|
-
];
|
|
343
|
-
|
|
344
|
-
function _recallStarter() {
|
|
345
|
-
var chips = RECALL_EGS.map(function (q) {
|
|
346
|
-
return '<button class="tab" data-od-act="recall-eg" data-q="' + _esc(q) + '">' +
|
|
347
|
-
_esc(q) + '</button>';
|
|
348
|
-
}).join('');
|
|
349
|
-
return (
|
|
350
|
-
'<div id="od-recall-starter" style="border:1px dashed var(--border);' +
|
|
351
|
-
'border-radius:var(--r-md);padding:22px;color:var(--fg-2);font-size:13px">' +
|
|
352
|
-
'<div style="font-weight:600;color:var(--fg);margin-bottom:6px">' +
|
|
353
|
-
'Ask a question above to search your memory</div>' +
|
|
354
|
-
'<p style="margin:0 0 14px;line-height:1.55">' +
|
|
355
|
-
'It searches by meaning, not keywords — asking “what database are we using” ' +
|
|
356
|
-
'can surface a memory that says “switched to Postgres”, even though the two ' +
|
|
357
|
-
'share no words. Try one:' +
|
|
358
|
-
'</p>' +
|
|
359
|
-
'<div style="display:flex;gap:8px;flex-wrap:wrap">' + chips + '</div>' +
|
|
360
|
-
'</div>'
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// ── Tab switching ────────────────────────────────────────────────────────────
|
|
365
|
-
|
|
366
|
-
function _switchTab(id, tab) {
|
|
367
|
-
_st = Object.assign({}, _st, { activeTab: tab });
|
|
368
|
-
var root = document.getElementById(id);
|
|
369
|
-
if (!root) return;
|
|
370
|
-
root.querySelectorAll('#' + id + '-tabs .tab').forEach(function (b) {
|
|
371
|
-
b.classList.toggle('active', b.dataset.tab === tab);
|
|
372
|
-
});
|
|
373
|
-
root.querySelectorAll('.tabpane').forEach(function (p) { p.classList.remove('active'); });
|
|
374
|
-
var pane = document.getElementById(id + '-pane-' + tab);
|
|
375
|
-
if (pane) pane.classList.add('active');
|
|
376
|
-
if (tab === 'timeline') _loadTimeline(id);
|
|
377
|
-
if (tab === 'clusters') _loadClusters(id);
|
|
378
|
-
if (tab === 'summary') { _loadProjectOptions(id); _loadKnowledgeOverview(id); }
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/* Populate the project picker from projects SLM has actually recorded.
|
|
382
|
-
*
|
|
383
|
-
* Loaded lazily on first visit to Summaries rather than at render time — the
|
|
384
|
-
* Memories page opens on Recall Lab, and most visits never reach this tab.
|
|
385
|
-
*/
|
|
386
|
-
function _loadProjectOptions(id) {
|
|
387
|
-
var sel = document.getElementById(id + '-sum-proj');
|
|
388
|
-
if (!sel) return;
|
|
389
|
-
// Guard on the element, not a module flag. A module-level "already loaded"
|
|
390
|
-
// boolean outlives the DOM it described: navigate away and back, the pane
|
|
391
|
-
// re-renders with a fresh <select> still reading "Loading projects…", and the
|
|
392
|
-
// stale flag suppresses the fetch that would fill it. Caught in review by
|
|
393
|
-
// exactly that sequence.
|
|
394
|
-
if (sel.dataset.loaded === '1' || sel.dataset.loading === '1') return;
|
|
395
|
-
sel.dataset.loading = '1';
|
|
396
|
-
fetch('/api/summary/projects')
|
|
397
|
-
.then(function (r) { return r.json(); })
|
|
398
|
-
.then(function (d) {
|
|
399
|
-
var list = (d && d.projects) || [];
|
|
400
|
-
sel.dataset.loaded = '1';
|
|
401
|
-
delete sel.dataset.loading;
|
|
402
|
-
if (!list.length) {
|
|
403
|
-
sel.innerHTML = '<option value="">No projects recorded yet</option>';
|
|
404
|
-
sel.disabled = true;
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
sel.innerHTML =
|
|
408
|
-
'<option value="">Summarise a project…</option>' +
|
|
409
|
-
list.map(function (p) {
|
|
410
|
-
return '<option value="' + _esc(p.path) + '" title="' + _esc(p.path) + '">' +
|
|
411
|
-
_esc(p.label) + ' (' + p.events + ')</option>';
|
|
412
|
-
}).join('');
|
|
413
|
-
})
|
|
414
|
-
.catch(function () {
|
|
415
|
-
// Fail visibly but harmlessly: a silent empty dropdown reads as "you have
|
|
416
|
-
// no projects", which is a different and wrong statement. Clearing the
|
|
417
|
-
// in-flight marker leaves the next tab visit free to retry.
|
|
418
|
-
delete sel.dataset.loading;
|
|
419
|
-
sel.innerHTML = '<option value="">Could not load projects — retry</option>';
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/* Summaries pane (4.0.8, issue #113).
|
|
424
|
-
*
|
|
425
|
-
* Reads GET /api/summary. The generators shipped in 4.0.6 with no caller at
|
|
426
|
-
* all; 4.0.7 added the CLI; this is the surface for someone who is already
|
|
427
|
-
* looking at the dashboard rather than a terminal.
|
|
428
|
-
*
|
|
429
|
-
* Coverage is rendered on every result, never only on bad ones — a summary
|
|
430
|
-
* that hides how much of the data it saw is the failure mode #113 named.
|
|
431
|
-
*/
|
|
432
|
-
function _loadSummary(id, kind, target) {
|
|
433
|
-
var out = document.getElementById(id + '-sum-out');
|
|
434
|
-
if (!out) return;
|
|
435
|
-
out.textContent = 'Building summary…';
|
|
436
|
-
|
|
437
|
-
var q = '/api/summary?kind=' + encodeURIComponent(kind);
|
|
438
|
-
// The daemon resolves an empty target for "day" (defaults to today) but not
|
|
439
|
-
// for project or session, which need an explicit one from the picker.
|
|
440
|
-
if (target) q += '&target=' + encodeURIComponent(target);
|
|
441
|
-
|
|
442
|
-
fetch(q)
|
|
443
|
-
.then(function (r) {
|
|
444
|
-
if (!r.ok) return r.json().then(function (e) { throw new Error(e.detail || r.status); });
|
|
445
|
-
return r.json();
|
|
446
|
-
})
|
|
447
|
-
.then(function (d) {
|
|
448
|
-
out.textContent = '';
|
|
449
|
-
|
|
450
|
-
var body = document.createElement('pre');
|
|
451
|
-
body.style.cssText = 'white-space:pre-wrap;font-family:inherit;font-size:13px;' +
|
|
452
|
-
'line-height:1.65;color:var(--fg);background:var(--card-2);border:1px solid var(--border);' +
|
|
453
|
-
'border-radius:var(--r-md);padding:14px;margin:0';
|
|
454
|
-
body.textContent = d.summary || '(nothing recorded)';
|
|
455
|
-
out.appendChild(body);
|
|
456
|
-
|
|
457
|
-
var meta = document.createElement('div');
|
|
458
|
-
meta.style.cssText = 'margin-top:10px;font-size:12px;color:var(--fg-3);line-height:1.6';
|
|
459
|
-
meta.textContent = _summaryProvenance(d);
|
|
460
|
-
out.appendChild(meta);
|
|
461
|
-
|
|
462
|
-
/* Why it came out this way, and what to do about it.
|
|
463
|
-
*
|
|
464
|
-
* The provenance line above says a summary was assembled from the
|
|
465
|
-
* user's own notes rather than written. It never said why. Someone in
|
|
466
|
-
* Mode A — which has no language model by design — saw a plainer
|
|
467
|
-
* result than they expected with no way to learn that a written one
|
|
468
|
-
* needs a model, and would reasonably read the feature as broken.
|
|
469
|
-
*/
|
|
470
|
-
var cap = d.capability;
|
|
471
|
-
if (cap && cap.message) {
|
|
472
|
-
var hint = document.createElement('div');
|
|
473
|
-
hint.style.cssText = 'margin-top:10px;font-size:12px;line-height:1.6;' +
|
|
474
|
-
'color:var(--fg-2);background:var(--card-2);border:1px solid var(--border);' +
|
|
475
|
-
'border-left:3px solid var(--accent, var(--border));' +
|
|
476
|
-
'border-radius:var(--r-md);padding:10px 12px';
|
|
477
|
-
hint.textContent = cap.message;
|
|
478
|
-
out.appendChild(hint);
|
|
479
|
-
}
|
|
480
|
-
})
|
|
481
|
-
.catch(function (e) {
|
|
482
|
-
out.textContent = 'Could not build summary: ' + (e && e.message ? e.message : 'error');
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
/* Plain-English provenance line under a summary.
|
|
487
|
-
*
|
|
488
|
-
* The old line read "Built from 0 memories · coverage: full · method: llm_b".
|
|
489
|
-
* Three problems in one string: it contradicted itself (nothing, covered
|
|
490
|
-
* fully), and "coverage" and "llm_b" are internal vocabulary. Someone who has
|
|
491
|
-
* not read the source cannot tell whether that summary is trustworthy — which
|
|
492
|
-
* is the entire job of a provenance line.
|
|
493
|
-
*/
|
|
494
|
-
var _COVERAGE_TEXT = {
|
|
495
|
-
full: 'Covers everything recorded for this period.',
|
|
496
|
-
partial: 'Partial view — some of what was recorded is not reflected here.',
|
|
497
|
-
insufficient: 'Too little was recorded to summarise properly.',
|
|
498
|
-
no_session: 'That session has no memories attached to it.',
|
|
499
|
-
unavailable: 'The underlying data could not be read.',
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
var _METHOD_TEXT = {
|
|
503
|
-
extractive: 'Assembled directly from your own notes — no AI involved.',
|
|
504
|
-
llm_b: 'Written by the AI model running locally on this machine.',
|
|
505
|
-
llm_c: 'Written by your configured cloud AI model.',
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
function _summaryProvenance(d) {
|
|
509
|
-
var n = d.source_count || 0;
|
|
510
|
-
var md = d.metadata || {};
|
|
511
|
-
var parts = [];
|
|
512
|
-
|
|
513
|
-
if (n > 0) {
|
|
514
|
-
parts.push('Based on ' + n + ' memor' + (n === 1 ? 'y' : 'ies') + '.');
|
|
515
|
-
} else if (md.event_count) {
|
|
516
|
-
// A project can have plenty of recorded activity and no stored facts. Saying
|
|
517
|
-
// "0 memories" and stopping makes that look like an error rather than a
|
|
518
|
-
// description of what actually happened.
|
|
519
|
-
parts.push('Based on ' + md.event_count + ' recorded actions; no facts were ' +
|
|
520
|
-
'saved for this project.');
|
|
521
|
-
} else {
|
|
522
|
-
parts.push('No stored memories matched.');
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
parts.push(_COVERAGE_TEXT[d.coverage] || 'Coverage unknown.');
|
|
526
|
-
if (d.generated_by && _METHOD_TEXT[d.generated_by]) {
|
|
527
|
-
parts.push(_METHOD_TEXT[d.generated_by]);
|
|
528
|
-
}
|
|
529
|
-
return parts.join(' ');
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// ── Category counts (pre-fetch real totals) ──────────────────────────────────
|
|
533
|
-
|
|
534
|
-
function _loadCatCounts(id) {
|
|
535
|
-
Promise.all(KNOWN_CATS.map(function (cat) {
|
|
536
|
-
return fetch('/api/memories?limit=1&category=' + encodeURIComponent(cat))
|
|
537
|
-
.then(function (r) { return r.json(); })
|
|
538
|
-
.then(function (d) { return { cat: cat, total: d.total || 0 }; })
|
|
539
|
-
.catch(function () { return { cat: cat, total: 0 }; });
|
|
540
|
-
})).then(function (results) {
|
|
541
|
-
var counts = {};
|
|
542
|
-
results.forEach(function (r) { if (r.total > 0) counts[r.cat] = r.total; });
|
|
543
|
-
_st = Object.assign({}, _st, { catCounts: counts });
|
|
544
|
-
_rebuildCatBar(id);
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Rebuild the full filter bar (chips + sort) from current _st
|
|
549
|
-
function _rebuildCatBar(id) {
|
|
550
|
-
var bar = document.getElementById(id + '-cats');
|
|
551
|
-
if (!bar) return;
|
|
552
|
-
var active = _st.category || '';
|
|
553
|
-
var html = '<div class="chip' + (!active ? ' on' : '') +
|
|
554
|
-
'" data-od-act="cat" data-cat="">All categories</div>';
|
|
555
|
-
Object.keys(_st.catCounts).forEach(function (cat) {
|
|
556
|
-
html += '<div class="chip' + (_st.category === cat ? ' on' : '') +
|
|
557
|
-
'" data-od-act="cat" data-cat="' + _esc(cat) + '">' +
|
|
558
|
-
_esc(cat) + ' <span class="cnt">' +
|
|
559
|
-
_st.catCounts[cat].toLocaleString() + '</span></div>';
|
|
560
|
-
});
|
|
561
|
-
var sv = _st.scopeView || 'mine';
|
|
562
|
-
html += '<div style="flex:1"></div>' +
|
|
563
|
-
'<div class="seg" title="Which memories to show">' +
|
|
564
|
-
['mine', 'shared', 'global', 'all'].map(function (s) {
|
|
565
|
-
var label = { mine: 'Mine', shared: 'Shared', global: 'Global', all: 'All' }[s];
|
|
566
|
-
return '<button class="' + (sv === s ? 'active' : '') +
|
|
567
|
-
'" data-od-act="scope-view" data-scope="' + s + '">' + label + '</button>';
|
|
568
|
-
}).join('') +
|
|
569
|
-
'</div>' +
|
|
570
|
-
'<div class="seg">' +
|
|
571
|
-
'<button class="' + (_st.sort === 'created' ? 'active' : '') +
|
|
572
|
-
'" data-od-act="sort" data-sort="created">Newest</button>' +
|
|
573
|
-
'<button class="' + (_st.sort === 'score' ? 'active' : '') +
|
|
574
|
-
'" data-od-act="sort" data-sort="score">Score</button>' +
|
|
575
|
-
'<button class="' + (_st.sort === 'importance' ? 'active' : '') +
|
|
576
|
-
'" data-od-act="sort" data-sort="importance">Importance</button>' +
|
|
577
|
-
'</div>';
|
|
578
|
-
bar.innerHTML = html;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// ── Memories fetch & render ──────────────────────────────────────────────────
|
|
582
|
-
|
|
583
|
-
function _loadMem(id) {
|
|
584
|
-
var url = '/api/memories?limit=' + _st.pageSize +
|
|
585
|
-
'&offset=' + (_st.page * _st.pageSize);
|
|
586
|
-
if (_st.category) url += '&category=' + encodeURIComponent(_st.category);
|
|
587
|
-
if (_st.scopeView && _st.scopeView !== 'mine') {
|
|
588
|
-
url += '&scope=' + encodeURIComponent(_st.scopeView);
|
|
589
|
-
}
|
|
590
|
-
var requestSeq = _st.requestSeq + 1;
|
|
591
|
-
_st = Object.assign({}, _st, { requestSeq: requestSeq });
|
|
592
|
-
var wrap = document.getElementById(id + '-tbl-wrap');
|
|
593
|
-
if (wrap) wrap.innerHTML = _loading('Loading memories…');
|
|
594
|
-
|
|
595
|
-
fetch(url)
|
|
596
|
-
.then(function (r) {
|
|
597
|
-
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
598
|
-
return r.json();
|
|
599
|
-
})
|
|
600
|
-
.then(function (d) {
|
|
601
|
-
if (_st.rootId !== id || _st.requestSeq !== requestSeq) return;
|
|
602
|
-
_st = Object.assign({}, _st, { memories: d.memories || [], total: d.total || 0 });
|
|
603
|
-
_renderTable(id, d);
|
|
604
|
-
})
|
|
605
|
-
.catch(function (err) {
|
|
606
|
-
if (_st.rootId !== id || _st.requestSeq !== requestSeq) return;
|
|
607
|
-
var w = document.getElementById(id + '-tbl-wrap');
|
|
608
|
-
if (w) w.innerHTML = '<div class="card-pad" style="color:var(--danger);text-align:center">' +
|
|
609
|
-
'Failed to load memories: ' + _esc(err.message) + '</div>';
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
function _renderTable(id, d) {
|
|
614
|
-
var mems = d.memories || [];
|
|
615
|
-
var total = d.total || 0;
|
|
616
|
-
var wrap = document.getElementById(id + '-tbl-wrap');
|
|
617
|
-
var cntEl = document.getElementById(id + '-cnt-all');
|
|
618
|
-
var subEl = document.getElementById(id + '-sub');
|
|
619
|
-
|
|
620
|
-
if (cntEl) cntEl.textContent = total.toLocaleString();
|
|
621
|
-
if (subEl) {
|
|
622
|
-
var _projs = mems.reduce(function (s, m) {
|
|
623
|
-
if (m.project_name) s.add(m.project_name);
|
|
624
|
-
return s;
|
|
625
|
-
}, new Set()).size;
|
|
626
|
-
var _pStr = _projs > 0
|
|
627
|
-
? ' across ' + _projs + ' project' + (_projs === 1 ? '' : 's')
|
|
628
|
-
: '';
|
|
629
|
-
subEl.textContent = total.toLocaleString() + ' memories' + _pStr +
|
|
630
|
-
'. Every memory shows its provenance — why it was remembered and how strongly it scored.';
|
|
631
|
-
}
|
|
632
|
-
if (!wrap) return;
|
|
633
|
-
|
|
634
|
-
if (mems.length === 0) {
|
|
635
|
-
wrap.innerHTML = '<div class="card-pad" style="text-align:center;padding:40px;' +
|
|
636
|
-
'color:var(--fg-2)">No memories found. Try a different filter.</div>';
|
|
637
|
-
_renderPag(id, d);
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
var rows = mems.map(function (m, idx) {
|
|
642
|
-
var imp = _imp(m.importance);
|
|
643
|
-
var impCls = imp >= 8 ? 'ok' : imp >= 5 ? 'warn' : 'neutral';
|
|
644
|
-
var scorePct = Math.round((parseFloat(m.importance) || 0) * 100);
|
|
645
|
-
var scoreCls = _scoreCls(m.importance);
|
|
646
|
-
var cat = m.category || 'semantic';
|
|
647
|
-
var preview = (m.content || '').substring(0, 120);
|
|
648
|
-
if ((m.content || '').length > 120) preview += '…';
|
|
649
|
-
|
|
650
|
-
return '<tr class="row" data-od-act="drawer" data-idx="' + idx + '" style="cursor:pointer">' +
|
|
651
|
-
'<td style="max-width:420px">' +
|
|
652
|
-
'<b class="mono dim" style="font-size:11px">#' +
|
|
653
|
-
_esc((m.id || '').substring(0, 8)) +
|
|
654
|
-
'</b>' +
|
|
655
|
-
'<div style="margin-top:2px">' + _esc(preview) + '</div>' +
|
|
656
|
-
'</td>' +
|
|
657
|
-
'<td><span class="badge ' + _esc(_catCls(cat)) + '">' + _esc(cat) + '</span></td>' +
|
|
658
|
-
'<td class="mono dim" style="font-size:12px">' + _esc(m.project_name || '—') + '</td>' +
|
|
659
|
-
'<td><b class="num">' + imp + '</b>/10</td>' +
|
|
660
|
-
'<td><span class="badge ' + _esc(scoreCls) + '">' + scorePct + '%</span></td>' +
|
|
661
|
-
'<td class="mono dim" style="font-size:12px">' + _esc(_fmt(m.created_at)) + '</td>' +
|
|
662
|
-
'</tr>';
|
|
663
|
-
}).join('');
|
|
664
|
-
|
|
665
|
-
wrap.innerHTML =
|
|
666
|
-
'<table class="tbl">' +
|
|
667
|
-
'<thead><tr>' +
|
|
668
|
-
'<th>Memory</th><th>Category</th><th>Project</th>' +
|
|
669
|
-
'<th>Importance</th><th>Score</th><th>Created</th>' +
|
|
670
|
-
'</tr></thead>' +
|
|
671
|
-
'<tbody>' + rows + '</tbody>' +
|
|
672
|
-
'</table>';
|
|
673
|
-
|
|
674
|
-
_renderPag(id, d);
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
function _renderPag(id, d) {
|
|
678
|
-
var el = document.getElementById(id + '-pg');
|
|
679
|
-
if (!el) return;
|
|
680
|
-
var tot = d.total || 0;
|
|
681
|
-
var lim = d.limit || _st.pageSize;
|
|
682
|
-
var off = d.offset || (_st.page * _st.pageSize);
|
|
683
|
-
var pg = Math.floor(off / lim);
|
|
684
|
-
var last = Math.max(0, Math.ceil(tot / lim) - 1);
|
|
685
|
-
var show = Math.min(off + lim, tot);
|
|
686
|
-
var from = tot === 0 ? 0 : off + 1;
|
|
687
|
-
|
|
688
|
-
el.innerHTML =
|
|
689
|
-
'<div style="display:flex;justify-content:space-between;align-items:center;' +
|
|
690
|
-
'font-size:12.5px;color:var(--fg-2)">' +
|
|
691
|
-
'<span>Showing ' + from + '–' + show + ' of ' + tot.toLocaleString() + '</span>' +
|
|
692
|
-
'<div class="seg">' +
|
|
693
|
-
'<button ' + (pg <= 0 ? 'disabled style="opacity:.4"' :
|
|
694
|
-
'data-od-act="pg" data-page="' + (pg - 1) + '"') + '>← Prev</button>' +
|
|
695
|
-
'<button disabled style="opacity:.7;cursor:default">Page ' +
|
|
696
|
-
(pg + 1) + ' / ' + (last + 1) + '</button>' +
|
|
697
|
-
'<button ' + (pg >= last ? 'disabled style="opacity:.4"' :
|
|
698
|
-
'data-od-act="pg" data-page="' + (pg + 1) + '"') + '>Next →</button>' +
|
|
699
|
-
'</div>' +
|
|
700
|
-
'</div>';
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
// ── Sort (client-side on current page) ──────────────────────────────────────
|
|
704
|
-
|
|
705
|
-
function _doSort(id, by) {
|
|
706
|
-
_st = Object.assign({}, _st, { sort: by });
|
|
707
|
-
var mems = _st.memories.slice();
|
|
708
|
-
// 'score' and 'importance' both rank by the same underlying importance float
|
|
709
|
-
if (by === 'importance' || by === 'score') {
|
|
710
|
-
mems.sort(function (a, b) {
|
|
711
|
-
return (parseFloat(b.importance) || 0) - (parseFloat(a.importance) || 0);
|
|
712
|
-
});
|
|
713
|
-
} else {
|
|
714
|
-
mems.sort(function (a, b) {
|
|
715
|
-
return String(b.created_at || '').localeCompare(String(a.created_at || ''));
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
_st = Object.assign({}, _st, { memories: mems });
|
|
719
|
-
_renderTable(id, {
|
|
720
|
-
memories: mems, total: _st.total,
|
|
721
|
-
limit: _st.pageSize, offset: _st.page * _st.pageSize,
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// ── Search — POST /api/search (full corpus, 0.5–1.4 s warm) ─────────────────
|
|
726
|
-
|
|
727
|
-
var _searchTimer = null;
|
|
728
|
-
function _doSearch(id, q) {
|
|
729
|
-
clearTimeout(_searchTimer);
|
|
730
|
-
var requestSeq = _st.requestSeq + 1;
|
|
731
|
-
// /api/search is a full-corpus semantic query. It cannot truthfully retain
|
|
732
|
-
// the list endpoint's category/scope selection, so clear those controls
|
|
733
|
-
// before the request rather than leaving the table and chips disagreeing.
|
|
734
|
-
_st = Object.assign({}, _st, {
|
|
735
|
-
searchQ: q || null,
|
|
736
|
-
category: q ? null : _st.category,
|
|
737
|
-
scopeView: q ? 'mine' : _st.scopeView,
|
|
738
|
-
page: 0,
|
|
739
|
-
requestSeq: requestSeq,
|
|
740
|
-
});
|
|
741
|
-
if (q) _rebuildCatBar(id);
|
|
742
|
-
_searchTimer = setTimeout(function () {
|
|
743
|
-
if (_st.rootId !== id || _st.requestSeq !== requestSeq) return;
|
|
744
|
-
if (!q) { _loadMem(id); return; }
|
|
745
|
-
var wrap = document.getElementById(id + '-tbl-wrap');
|
|
746
|
-
if (wrap) wrap.innerHTML = _loading('Searching…');
|
|
747
|
-
fetch('/api/search', { method: 'POST', credentials: 'same-origin',
|
|
748
|
-
headers: { 'Content-Type': 'application/json' },
|
|
749
|
-
slmInvalidatesCache: false,
|
|
750
|
-
slmRequiresWriteAuth: false,
|
|
751
|
-
body: JSON.stringify({ query: q, limit: 50, window: _st.window || '' })
|
|
752
|
-
}).then(function (r) {
|
|
753
|
-
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
754
|
-
return r.json();
|
|
755
|
-
}).then(function (d) {
|
|
756
|
-
if (_st.rootId !== id || _st.requestSeq !== requestSeq) return;
|
|
757
|
-
var mems = (d.results || []).map(_normSearch);
|
|
758
|
-
_st = Object.assign({}, _st, { memories: mems, total: mems.length });
|
|
759
|
-
_renderTable(id, { memories: mems, total: mems.length, limit: mems.length, offset: 0 });
|
|
760
|
-
}).catch(function (err) {
|
|
761
|
-
if (_st.rootId !== id || _st.requestSeq !== requestSeq) return;
|
|
762
|
-
var w = document.getElementById(id + '-tbl-wrap');
|
|
763
|
-
if (w) w.innerHTML = '<div class="card-pad" style="color:var(--danger);text-align:center;' +
|
|
764
|
-
'padding:24px">Search failed: ' + _esc(err.message) + '</div>';
|
|
765
|
-
});
|
|
766
|
-
}, 350);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// ── Timeline fetch & render ──────────────────────────────────────────────────
|
|
770
|
-
|
|
771
|
-
var _tlLoaded = {};
|
|
772
|
-
function _loadTimeline(id) {
|
|
773
|
-
var range = _st.tlRange;
|
|
774
|
-
if (_tlLoaded[id + '-' + range]) return;
|
|
775
|
-
var barsEl = document.getElementById(id + '-bars');
|
|
776
|
-
var ftEl = document.getElementById(id + '-ftypes');
|
|
777
|
-
var startEl = document.getElementById(id + '-tl-start');
|
|
778
|
-
|
|
779
|
-
fetch('/api/v3/timeline/?range=' + range + '&group_by=category&limit=1000')
|
|
780
|
-
.then(function (r) { return r.json(); })
|
|
781
|
-
.then(function (d) {
|
|
782
|
-
var events = d.events || [];
|
|
783
|
-
_tlLoaded[id + '-' + range] = true;
|
|
784
|
-
if (events.length === 0) {
|
|
785
|
-
if (barsEl) barsEl.innerHTML =
|
|
786
|
-
'<div style="display:grid;place-items:center;width:100%;height:100%;' +
|
|
787
|
-
'color:var(--fg-3);font-size:13px">No memory events in this range.</div>';
|
|
788
|
-
if (ftEl) ftEl.innerHTML =
|
|
789
|
-
'<div style="color:var(--fg-3);font-size:13px">No category data available.</div>';
|
|
790
|
-
return;
|
|
791
|
-
}
|
|
792
|
-
_renderBars(id, events, range, barsEl, startEl);
|
|
793
|
-
_renderFtypes(id, events, ftEl);
|
|
794
|
-
})
|
|
795
|
-
.catch(function (err) {
|
|
796
|
-
if (barsEl) barsEl.innerHTML =
|
|
797
|
-
'<div style="color:var(--fg-3);font-size:13px;text-align:center;padding:16px">' +
|
|
798
|
-
'Timeline unavailable: ' + _esc(err.message) + '</div>';
|
|
799
|
-
// TODO: endpoint returns 404 when timeline feature is disabled
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
function _renderBars(id, events, range, barsEl, startEl) {
|
|
804
|
-
if (!barsEl) return;
|
|
805
|
-
var days = range === '30d' ? 30 : 7;
|
|
806
|
-
var today = new Date();
|
|
807
|
-
var counts = new Array(days).fill(0);
|
|
808
|
-
events.forEach(function (ev) {
|
|
809
|
-
var diff = Math.floor((today - new Date(ev.timestamp)) / 86400000);
|
|
810
|
-
if (diff >= 0 && diff < days) counts[days - 1 - diff]++;
|
|
811
|
-
});
|
|
812
|
-
if (typeof slmBars === 'function') {
|
|
813
|
-
slmBars(barsEl, counts);
|
|
814
|
-
} else {
|
|
815
|
-
var maxVal = Math.max.apply(null, counts) || 1;
|
|
816
|
-
barsEl.innerHTML = counts.map(function (v) {
|
|
817
|
-
return '<i style="height:' + Math.max(4, (v / maxVal) * 100) + '%' +
|
|
818
|
-
'" title="' + v + ' events"></i>';
|
|
819
|
-
}).join('');
|
|
820
|
-
}
|
|
821
|
-
if (startEl) startEl.textContent = days + 'd ago';
|
|
822
|
-
var subEl = document.getElementById(id + '-tl-sub');
|
|
823
|
-
if (subEl) subEl.textContent = events.length.toLocaleString() + ' events · last ' + days + ' days';
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function _renderFtypes(id, events, ftEl) {
|
|
827
|
-
if (!ftEl) return;
|
|
828
|
-
var catMap = {};
|
|
829
|
-
events.forEach(function (ev) {
|
|
830
|
-
catMap[ev.category || 'unknown'] = (catMap[ev.category || 'unknown'] || 0) + 1;
|
|
831
|
-
});
|
|
832
|
-
var total = events.length;
|
|
833
|
-
var colors = { temporal:'var(--ok)', semantic:'var(--violet)', episodic:'var(--cyan)', opinion:'var(--warn)' };
|
|
834
|
-
var sorted = Object.keys(catMap).sort(function (a, b) { return catMap[b] - catMap[a]; });
|
|
835
|
-
ftEl.innerHTML = sorted.map(function (cat) {
|
|
836
|
-
var pct = Math.round(catMap[cat] / total * 100);
|
|
837
|
-
var color = colors[cat] || 'var(--fg-3)';
|
|
838
|
-
return '<div style="margin-bottom:13px">' +
|
|
839
|
-
'<div style="display:flex;justify-content:space-between;font-size:13px;margin-bottom:6px">' +
|
|
840
|
-
'<span class="mono">' + _esc(cat) + '</span><b>' + pct + '%</b>' +
|
|
841
|
-
'</div>' +
|
|
842
|
-
'<div class="meter"><i style="width:' + pct + '%;background:' + color + '"></i></div>' +
|
|
843
|
-
'</div>';
|
|
844
|
-
}).join('');
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// ── Clusters fetch & render ──────────────────────────────────────────────────
|
|
848
|
-
|
|
849
|
-
/* Knowledge Overview — cluster summaries, plus an honest health line.
|
|
850
|
-
*
|
|
851
|
-
* Two rules this card exists to obey.
|
|
852
|
-
*
|
|
853
|
-
* IT READS ONLY THE DISPLAY TABLE. These summaries were in the retrieval
|
|
854
|
-
* corpus until 4.0.10, where they out-ranked the user's own words. Moving
|
|
855
|
-
* them out is only worth anything if exactly one surface shows them, and
|
|
856
|
-
* this is that surface.
|
|
857
|
-
*
|
|
858
|
-
* IT DOES NOT DRESS UP JUNK AS INSIGHT. Some stored summaries are a model's
|
|
859
|
-
* non-answer -- "Unfortunately, there is no information available about
|
|
860
|
-
* 'State'..." -- and rendering those as a heading called Knowledge Overview
|
|
861
|
-
* makes the product look broken. The endpoint labels each row's quality; the
|
|
862
|
-
* usable ones are shown and the rest are counted in one plain sentence. Not
|
|
863
|
-
* hidden: hiding them would hide the very problem the release fixes, and a
|
|
864
|
-
* reader who is told "3 could not be generated" trusts the other 47 more.
|
|
865
|
-
*/
|
|
866
|
-
function _loadKnowledgeOverview(id) {
|
|
867
|
-
var box = document.getElementById(id + '-kover');
|
|
868
|
-
if (!box) return;
|
|
869
|
-
// Guarded on the element, not a module flag — same reason as
|
|
870
|
-
// _loadProjectOptions: a stale "already loaded" boolean outlives the DOM
|
|
871
|
-
// it described and leaves a permanent spinner after a re-render.
|
|
872
|
-
if (box.dataset.loaded === '1') return;
|
|
873
|
-
|
|
874
|
-
Promise.all([
|
|
875
|
-
fetch('/api/v3/abstraction/consolidated?limit=24')
|
|
876
|
-
.then(function (r) { return r.ok ? r.json() : { summaries: [], unusable: 0 }; })
|
|
877
|
-
.catch(function () { return { summaries: [], unusable: 0 }; }),
|
|
878
|
-
fetch('/api/v3/abstraction/health')
|
|
879
|
-
.then(function (r) { return r.ok ? r.json() : null; })
|
|
880
|
-
.catch(function () { return null; })
|
|
881
|
-
]).then(function (res) {
|
|
882
|
-
box.dataset.loaded = '1';
|
|
883
|
-
box.innerHTML = _koverHtml(res[0] || {}, res[1]);
|
|
884
|
-
});
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
function _koverHtml(data, health) {
|
|
888
|
-
var all = data.summaries || [];
|
|
889
|
-
var usable = all.filter(function (s) { return s.quality === 'ok'; });
|
|
890
|
-
var unusable = typeof data.unusable === 'number' ? data.unusable
|
|
891
|
-
: (all.length - usable.length);
|
|
892
|
-
|
|
893
|
-
var html = '<h3 style="font-size:15px;margin:0 0 4px">What your memory knows</h3>' +
|
|
894
|
-
'<p style="font-size:12px;color:var(--fg-2);margin:0 0 14px">' +
|
|
895
|
-
'Written by the summarizer from groups of your memories. These are a ' +
|
|
896
|
-
'view of your memory, not memories themselves — they are never returned ' +
|
|
897
|
-
'as answers.' +
|
|
898
|
-
'</p>';
|
|
899
|
-
|
|
900
|
-
if (health) html += _koverHealth(health);
|
|
901
|
-
|
|
902
|
-
if (usable.length === 0) {
|
|
903
|
-
html += '<div style="padding:20px;color:var(--fg-2);font-size:13px">' +
|
|
904
|
-
(all.length === 0
|
|
905
|
-
? 'No summaries yet. They are written in the background as related ' +
|
|
906
|
-
'memories accumulate.'
|
|
907
|
-
: 'None of the ' + all.length + ' stored summaries came back usable. ' +
|
|
908
|
-
'That usually means the summarizer had nothing in common to merge.') +
|
|
909
|
-
'</div>';
|
|
910
|
-
return html;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
html += '<div style="display:grid;gap:12px;' +
|
|
914
|
-
'grid-template-columns:repeat(auto-fill,minmax(280px,1fr))">';
|
|
915
|
-
usable.forEach(function (s) { html += _koverCard(s); });
|
|
916
|
-
html += '</div>';
|
|
917
|
-
|
|
918
|
-
var notes = [];
|
|
919
|
-
if (unusable > 0) {
|
|
920
|
-
notes.push(unusable + (unusable === 1 ? ' summary' : ' summaries') +
|
|
921
|
-
' could not be generated and are not shown. The memories they were ' +
|
|
922
|
-
'built from are unaffected.');
|
|
923
|
-
}
|
|
924
|
-
if (data.near_duplicates > 0) {
|
|
925
|
-
notes.push(data.near_duplicates + ' near-identical ' +
|
|
926
|
-
(data.near_duplicates === 1 ? 'summary was' : 'summaries were') +
|
|
927
|
-
' collapsed into the ones above.');
|
|
928
|
-
}
|
|
929
|
-
if (notes.length) {
|
|
930
|
-
html += '<p style="font-size:12px;color:var(--fg-2);margin-top:12px">' +
|
|
931
|
-
notes.map(_esc).join(' ') + '</p>';
|
|
932
|
-
}
|
|
933
|
-
return html;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
function _koverCard(s) {
|
|
937
|
-
// Every field is escaped. Anything in a memory can reach this screen: the
|
|
938
|
-
// summarizer merges fact content verbatim, so a memory containing markup
|
|
939
|
-
// would otherwise render as markup.
|
|
940
|
-
var body = _koverPlain(s.content);
|
|
941
|
-
var clipped = body.length > 320;
|
|
942
|
-
var shown = clipped ? body.slice(0, 320).replace(/\s+\S*$/, '') + '…' : body;
|
|
943
|
-
|
|
944
|
-
var meta = [];
|
|
945
|
-
if (s.source_count) {
|
|
946
|
-
meta.push(s.source_count + (s.source_count === 1 ? ' memory' : ' memories'));
|
|
947
|
-
}
|
|
948
|
-
var span = _koverSpan(s.source_earliest, s.source_latest);
|
|
949
|
-
if (span) meta.push(span);
|
|
950
|
-
|
|
951
|
-
return '<div style="background:var(--card-2);border:1px solid var(--border);' +
|
|
952
|
-
'border-radius:var(--r-md);padding:14px">' +
|
|
953
|
-
(s.entity_name
|
|
954
|
-
? '<div style="font-size:13px;font-weight:600;margin-bottom:6px">' +
|
|
955
|
-
_esc(s.entity_name) + '</div>'
|
|
956
|
-
: '') +
|
|
957
|
-
'<div style="font-size:13px;line-height:1.5">' + _esc(shown) + '</div>' +
|
|
958
|
-
(meta.length
|
|
959
|
-
? '<div style="margin-top:10px;display:flex;gap:6px;flex-wrap:wrap">' +
|
|
960
|
-
meta.map(_koverChip).join('') +
|
|
961
|
-
'</div>'
|
|
962
|
-
: '') +
|
|
963
|
-
'</div>';
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
/* Flatten a summary to plain prose for display.
|
|
967
|
-
*
|
|
968
|
-
* Mode B/C summaries come back with markdown in them — "**Audit Round**",
|
|
969
|
-
* "**Findings**:" — because a chat-tuned model formats for a chat window.
|
|
970
|
-
* Rendered as text those asterisks read as broken output to exactly the
|
|
971
|
-
* reader this card is for. Escaping is still what protects the page; this
|
|
972
|
-
* only removes the emphasis marks that carry no meaning here.
|
|
973
|
-
*/
|
|
974
|
-
function _koverPlain(text) {
|
|
975
|
-
return String(text || '')
|
|
976
|
-
.replace(/```[\s\S]*?```/g, ' ') // fenced blocks: no room for them
|
|
977
|
-
.replace(/`([^`]*)`/g, '$1') // inline code marks
|
|
978
|
-
.replace(/\*\*([^*]+)\*\*/g, '$1') // bold
|
|
979
|
-
.replace(/(^|\s)\*([^*\s][^*]*)\*/g, '$1$2') // italic, not bullets
|
|
980
|
-
.replace(/^#{1,6}\s+/gm, '') // headings
|
|
981
|
-
.replace(/^\s*[-*+]\s+/gm, '') // list bullets
|
|
982
|
-
.replace(/\s+/g, ' ') // collapse whitespace + newlines
|
|
983
|
-
.trim();
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
/* A chip, not a keyword dump.
|
|
987
|
-
*
|
|
988
|
-
* The neighbouring community-summary API returns its `summary` field as
|
|
989
|
-
* "Topics: CCQ, Resume, P07…", which printed verbatim reads as a broken
|
|
990
|
-
* page. Counts and date spans are rendered as discrete labels instead.
|
|
991
|
-
*/
|
|
992
|
-
function _koverChip(text) {
|
|
993
|
-
return '<span style="font-size:11px;padding:2px 8px;border-radius:999px;' +
|
|
994
|
-
'background:var(--card);border:1px solid var(--border);color:var(--fg-2)">' +
|
|
995
|
-
_esc(text) + '</span>';
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
function _koverSpan(earliest, latest) {
|
|
999
|
-
var a = String(earliest || '').slice(0, 10);
|
|
1000
|
-
var b = String(latest || '').slice(0, 10);
|
|
1001
|
-
if (!a && !b) return '';
|
|
1002
|
-
if (!a || !b || a === b) return a || b;
|
|
1003
|
-
return a + ' to ' + b;
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
/* Whether the memories behind all this can actually be found.
|
|
1007
|
-
*
|
|
1008
|
-
* The one question no screen answered before. A machine ran for months with
|
|
1009
|
-
* 43.7% of its store unreachable by meaning while every status line it showed
|
|
1010
|
-
* said healthy, because nothing counted the reachable share.
|
|
1011
|
-
*/
|
|
1012
|
-
function _koverHealth(h) {
|
|
1013
|
-
var lines = h.summary || [];
|
|
1014
|
-
if (!lines.length) return '';
|
|
1015
|
-
var bad = h.healthy === false;
|
|
1016
|
-
return '<div style="margin:0 0 16px;padding:12px 14px;border-radius:var(--r-md);' +
|
|
1017
|
-
'background:var(--card-2);border-left:3px solid ' +
|
|
1018
|
-
(bad ? 'var(--warn)' : 'var(--ok)') + '">' +
|
|
1019
|
-
lines.map(function (l) {
|
|
1020
|
-
return '<div style="font-size:12px;color:var(--fg-2);line-height:1.5">' +
|
|
1021
|
-
_esc(l) + '</div>';
|
|
1022
|
-
}).join('') +
|
|
1023
|
-
'</div>';
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
function _loadClusters(id) {
|
|
1027
|
-
if (_st.cluLoaded) return;
|
|
1028
|
-
var grid = document.getElementById(id + '-clu-grid');
|
|
1029
|
-
if (!grid) return;
|
|
1030
|
-
fetch('/api/clusters')
|
|
1031
|
-
.then(function (r) {
|
|
1032
|
-
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
1033
|
-
return r.json();
|
|
1034
|
-
})
|
|
1035
|
-
.then(function (d) {
|
|
1036
|
-
_st = Object.assign({}, _st, { cluLoaded: true });
|
|
1037
|
-
var clus = d.clusters || [];
|
|
1038
|
-
var cntEl = document.getElementById(id + '-cnt-clusters');
|
|
1039
|
-
if (cntEl) cntEl.textContent = clus.length.toLocaleString();
|
|
1040
|
-
if (clus.length === 0) {
|
|
1041
|
-
grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;padding:40px;' +
|
|
1042
|
-
'color:var(--fg-2)">No clusters yet. Clusters form as memories accumulate.</div>';
|
|
1043
|
-
return;
|
|
1044
|
-
}
|
|
1045
|
-
_renderClusters(id, clus, grid);
|
|
1046
|
-
})
|
|
1047
|
-
.catch(function (err) {
|
|
1048
|
-
if (grid) grid.innerHTML =
|
|
1049
|
-
'<div style="grid-column:1/-1;text-align:center;padding:24px;' +
|
|
1050
|
-
'color:var(--danger);font-size:13px">Failed to load clusters: ' +
|
|
1051
|
-
_esc(err.message) + '</div>';
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
var _PAL = ['var(--violet)', 'var(--cyan)', 'var(--warn)', 'var(--ok)', 'var(--danger)'];
|
|
1056
|
-
|
|
1057
|
-
function _renderClusters(id, clus, grid) {
|
|
1058
|
-
grid.innerHTML = clus.map(function (c, i) {
|
|
1059
|
-
var color = _PAL[i % _PAL.length];
|
|
1060
|
-
var summary = c.summary || c.categories || '';
|
|
1061
|
-
var preview = summary.length > 80 ? summary.substring(0, 80) + '…' : summary;
|
|
1062
|
-
var cid = String(c.cluster_id || '');
|
|
1063
|
-
return '<div class="launch-card card" style="cursor:pointer"' +
|
|
1064
|
-
' data-od-act="expand-cluster" data-cid="' + _esc(cid) + '">' +
|
|
1065
|
-
'<div class="ic" style="background:color-mix(in srgb,' + color + ' 15%,transparent);color:' + color + '">' +
|
|
1066
|
-
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" width="21" height="21">' +
|
|
1067
|
-
'<path d="M12 3l1.9 4.6L18 9l-3.5 3 1 5-3.5-2.5L8.5 17l1-5L6 9l4.1-1.4z"/>' +
|
|
1068
|
-
'</svg>' +
|
|
1069
|
-
'</div>' +
|
|
1070
|
-
'<h3>' + _esc(preview) + '</h3>' +
|
|
1071
|
-
'<p><b class="num">' + _esc(String(c.member_count)) + '</b> memories · expand →</p>' +
|
|
1072
|
-
'<div style="display:none;margin-top:14px;border-top:1px solid var(--border);' +
|
|
1073
|
-
'padding-top:12px;font-size:13px" id="' + id + '-clu-' + _esc(cid) + '"></div>' +
|
|
1074
|
-
'</div>';
|
|
1075
|
-
}).join('');
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
function _expandCluster(id, cid) {
|
|
1079
|
-
var detEl = document.getElementById(id + '-clu-' + cid);
|
|
1080
|
-
if (!detEl) return;
|
|
1081
|
-
if (detEl.style.display !== 'none') { detEl.style.display = 'none'; return; }
|
|
1082
|
-
detEl.style.display = 'block';
|
|
1083
|
-
if (detEl.dataset.loaded) return;
|
|
1084
|
-
detEl.dataset.loaded = '1';
|
|
1085
|
-
detEl.textContent = 'Loading members…';
|
|
1086
|
-
fetch('/api/clusters/' + encodeURIComponent(cid) + '?limit=5')
|
|
1087
|
-
.then(function (r) { return r.json(); })
|
|
1088
|
-
.then(function (d) {
|
|
1089
|
-
var members = d.members || [];
|
|
1090
|
-
if (members.length === 0) { detEl.textContent = 'No members found.'; return; }
|
|
1091
|
-
detEl.innerHTML = members.map(function (m, i) {
|
|
1092
|
-
var txt = m.content || m.summary || '';
|
|
1093
|
-
return '<div style="margin-bottom:6px;padding-bottom:6px;border-bottom:1px solid var(--border)">' +
|
|
1094
|
-
'<div style="font-size:12.5px">' + (i + 1) + '. ' +
|
|
1095
|
-
_esc(txt.substring(0, 120)) + '</div></div>';
|
|
1096
|
-
}).join('');
|
|
1097
|
-
})
|
|
1098
|
-
.catch(function () { detEl.textContent = 'Failed to load members.'; });
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
// ── Provenance drawer ────────────────────────────────────────────────────────
|
|
1102
|
-
|
|
1103
|
-
function _ensureDrawer() {
|
|
1104
|
-
if (document.getElementById('od-mem-drawer')) return;
|
|
1105
|
-
var scrim = document.createElement('div');
|
|
1106
|
-
scrim.id = 'od-mem-drawer-scrim';
|
|
1107
|
-
scrim.className = 'od-drawer-scrim';
|
|
1108
|
-
scrim.dataset.odAct = 'close-drawer';
|
|
1109
|
-
document.body.appendChild(scrim);
|
|
1110
|
-
var drawer = document.createElement('aside');
|
|
1111
|
-
drawer.id = 'od-mem-drawer';
|
|
1112
|
-
drawer.className = 'od-drawer';
|
|
1113
|
-
document.body.appendChild(drawer);
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
function _openDrawer(idx) {
|
|
1117
|
-
var mem = _st.memories[idx];
|
|
1118
|
-
if (!mem) return;
|
|
1119
|
-
_ensureDrawer();
|
|
1120
|
-
var drawer = document.getElementById('od-mem-drawer');
|
|
1121
|
-
var scrim = document.getElementById('od-mem-drawer-scrim');
|
|
1122
|
-
if (!drawer || !scrim) return;
|
|
1123
|
-
|
|
1124
|
-
var imp = _imp(mem.importance);
|
|
1125
|
-
var cat = mem.category || 'semantic';
|
|
1126
|
-
var scorePct = Math.round((parseFloat(mem.importance) || 0) * 100);
|
|
1127
|
-
|
|
1128
|
-
drawer.innerHTML =
|
|
1129
|
-
'<div style="display:flex;justify-content:space-between;align-items:flex-start">' +
|
|
1130
|
-
'<div>' +
|
|
1131
|
-
'<div style="font-size:12px;color:var(--fg-2)">Memory</div>' +
|
|
1132
|
-
'<h2 style="font-size:19px;margin-top:2px">' +
|
|
1133
|
-
_esc('#' + (mem.id || '').substring(0, 12)) + '</h2>' +
|
|
1134
|
-
'</div>' +
|
|
1135
|
-
'<button class="btn icon ghost" data-od-act="close-drawer">✕</button>' +
|
|
1136
|
-
'</div>' +
|
|
1137
|
-
'<div class="od-prov" style="font-size:14px;line-height:1.7">' +
|
|
1138
|
-
_esc(mem.content || '') +
|
|
1139
|
-
'</div>' +
|
|
1140
|
-
'<div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">' +
|
|
1141
|
-
'<span class="badge ' + _esc(_catCls(cat)) + '">' + _esc(cat) + '</span>' +
|
|
1142
|
-
'<span class="badge neutral">' + _esc(mem.project_name || 'no project') + '</span>' +
|
|
1143
|
-
'<span class="badge ' + (mem.scope === 'global' ? 'success' : mem.scope === 'shared' ? 'warn' : 'neutral') +
|
|
1144
|
-
'">' + _esc(mem.scope || 'personal') + '</span>' +
|
|
1145
|
-
'</div>' +
|
|
1146
|
-
// Scope & sharing control (C2) — set personal/shared/global from the UI
|
|
1147
|
-
'<h3 style="font-size:13px;margin:20px 0 8px">Scope & sharing</h3>' +
|
|
1148
|
-
'<div class="od-prov" style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">' +
|
|
1149
|
-
'<select id="od-scope-sel" style="padding:6px 8px;border-radius:6px;background:var(--card-2);color:var(--fg);border:1px solid var(--border);font-size:13px">' +
|
|
1150
|
-
['personal', 'shared', 'global'].map(function (s) {
|
|
1151
|
-
return '<option value="' + s + '"' + ((mem.scope || 'personal') === s ? ' selected' : '') + '>' + s + '</option>';
|
|
1152
|
-
}).join('') +
|
|
1153
|
-
'</select>' +
|
|
1154
|
-
'<input id="od-scope-shared" placeholder="share with profiles (comma-sep)" ' +
|
|
1155
|
-
'value="' + _esc(_sharedToStr(mem.shared_with)) + '" ' +
|
|
1156
|
-
'style="flex:1;min-width:140px;padding:6px 8px;border-radius:6px;background:var(--card-2);color:var(--fg);border:1px solid var(--border);font-size:13px">' +
|
|
1157
|
-
'<button data-od-act="set-scope" data-mid="' + _esc(mem.id) + '" ' +
|
|
1158
|
-
'style="padding:6px 14px;border:1px solid var(--border);border-radius:6px;background:var(--card-2);color:var(--fg);cursor:pointer;font-size:13px">Apply</button>' +
|
|
1159
|
-
'</div>' +
|
|
1160
|
-
'<h3 style="font-size:13px;margin:20px 0 8px">Why this was remembered</h3>' +
|
|
1161
|
-
'<div class="od-prov">' +
|
|
1162
|
-
'<div style="font-size:13px;color:var(--fg-2);line-height:1.6">' +
|
|
1163
|
-
'Importance: <b>' + imp + '/10</b>. ' +
|
|
1164
|
-
'Score: <b>' + scorePct + '%</b>. ' +
|
|
1165
|
-
'Recalled <b>' + _esc(String(mem.access_count || 0)) + '</b> time' +
|
|
1166
|
-
(mem.access_count === 1 ? '' : 's') + '. ' +
|
|
1167
|
-
'Stored ' + _esc(_ago(mem.created_at)) + '.' +
|
|
1168
|
-
'</div>' +
|
|
1169
|
-
// TODO: /api/memories/{id}/score-breakdown — Semantic/BM25/EntityGraph/Temporal
|
|
1170
|
-
// decomposition is not yet exposed by the daemon; show when available.
|
|
1171
|
-
'</div>' +
|
|
1172
|
-
'<h3 style="font-size:13px;margin:20px 0 8px">Atomic facts</h3>' +
|
|
1173
|
-
'<div id="od-drawer-facts" style="color:var(--fg-3);font-size:13px">Loading facts…</div>' +
|
|
1174
|
-
'<div id="od-drawer-code"></div>' +
|
|
1175
|
-
'<div style="display:flex;gap:8px;margin-top:20px;padding-top:12px;border-top:1px solid var(--border)">' +
|
|
1176
|
-
'<button data-od-act="edit-mem" data-mid="' + _esc(mem.id) + '" style="padding:6px 14px;border:1px solid var(--border);border-radius:6px;background:var(--card-2);color:var(--fg);cursor:pointer;font-size:13px">Edit</button>' +
|
|
1177
|
-
'<button data-od-act="del-mem" data-mid="' + _esc(mem.id) + '" style="padding:6px 14px;border:1px solid var(--danger);border-radius:6px;background:transparent;color:var(--danger);cursor:pointer;font-size:13px">Delete</button>' +
|
|
1178
|
-
'</div><div id="od-mem-act" style="margin-top:10px"></div>';
|
|
1179
|
-
|
|
1180
|
-
drawer.classList.add('open');
|
|
1181
|
-
scrim.classList.add('on');
|
|
1182
|
-
// A row in this pane is an ATOMIC FACT, not a source memory: /api/memories
|
|
1183
|
-
// reports total 3603 on a store holding 830 memories and 3603 facts, and
|
|
1184
|
-
// every row id resolves through /api/facts/{id}. The row carries its parent
|
|
1185
|
-
// separately as memory_id.
|
|
1186
|
-
//
|
|
1187
|
-
// "Atomic facts" therefore needs the PARENT id — it lists the other facts
|
|
1188
|
-
// extracted from the same source memory. Passing mem.id asked
|
|
1189
|
-
// /api/memories/{fact_id}/facts, which has no children to return, so this
|
|
1190
|
-
// section read "No atomic facts recorded for this memory" for every memory
|
|
1191
|
-
// on every store. Not an empty state: the wrong identifier.
|
|
1192
|
-
if (mem.memory_id) {
|
|
1193
|
-
_loadFacts(mem.memory_id);
|
|
1194
|
-
} else {
|
|
1195
|
-
// No parent row: this record was stored directly as a fact rather than
|
|
1196
|
-
// extracted from a longer memory (198 of 3,608 on a real store). Saying
|
|
1197
|
-
// "no atomic facts recorded" there is wrong in a way that matters — it
|
|
1198
|
-
// reads as data missing, when the fact IS the record.
|
|
1199
|
-
var fx = document.getElementById('od-drawer-facts');
|
|
1200
|
-
if (fx) fx.textContent = 'Stored directly — this record is itself the atomic fact.';
|
|
1201
|
-
}
|
|
1202
|
-
// Code links hang off the FACT, so this one takes the row id.
|
|
1203
|
-
if (mem.id) _loadCodeLinks(mem.id);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
function _closeDrawer() {
|
|
1207
|
-
var d = document.getElementById('od-mem-drawer');
|
|
1208
|
-
var s = document.getElementById('od-mem-drawer-scrim');
|
|
1209
|
-
if (d) d.classList.remove('open');
|
|
1210
|
-
if (s) s.classList.remove('on');
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
function _loadFacts(memId) {
|
|
1214
|
-
var el = document.getElementById('od-drawer-facts');
|
|
1215
|
-
if (!el) return;
|
|
1216
|
-
fetch('/api/memories/' + encodeURIComponent(memId) + '/facts')
|
|
1217
|
-
.then(function (r) { return r.json(); })
|
|
1218
|
-
.then(function (d) {
|
|
1219
|
-
var facts = d.facts || [];
|
|
1220
|
-
if (facts.length === 0) {
|
|
1221
|
-
el.textContent = 'No atomic facts recorded for this memory.'; return;
|
|
1222
|
-
}
|
|
1223
|
-
el.innerHTML = facts.map(function (f) {
|
|
1224
|
-
return '<div class="od-prov" style="margin-bottom:8px">' +
|
|
1225
|
-
'<span class="badge neutral" style="font-size:10px">' +
|
|
1226
|
-
_esc(f.fact_type || 'fact') +
|
|
1227
|
-
'</span>' +
|
|
1228
|
-
'<div style="font-size:13px;line-height:1.6;margin-top:4px">' +
|
|
1229
|
-
_esc((f.content || '').substring(0, 200)) +
|
|
1230
|
-
'</div></div>';
|
|
1231
|
-
}).join('');
|
|
1232
|
-
})
|
|
1233
|
-
.catch(function () { if (el) el.textContent = 'Could not load facts.'; });
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
/* Code this memory refers to (4.0.8).
|
|
1237
|
-
*
|
|
1238
|
-
* Renders into the memory drawer — the panel actually used to inspect a
|
|
1239
|
-
* memory. 4.0.7 put this in js/fact-detail.js, which only binds to
|
|
1240
|
-
* `.fact-result-item` rows in the search-results view, so the feature was
|
|
1241
|
-
* invisible to anyone browsing Memories.
|
|
1242
|
-
*
|
|
1243
|
-
* KEYED ON THE ROW'S OWN ID, which is an ATOMIC FACT id. The Memories pane
|
|
1244
|
-
* lists atomic facts — /api/memories returns total 3603 on a store with 830
|
|
1245
|
-
* memories and 3603 facts, and each row id resolves through /api/facts/{id}.
|
|
1246
|
-
* (That mismatch is also why the drawer's "Atomic facts" block always reads
|
|
1247
|
-
* "No atomic facts recorded": it asks /api/memories/{fact_id}/facts, which
|
|
1248
|
-
* has no children to return. Left alone here — separate defect, separate fix.)
|
|
1249
|
-
*
|
|
1250
|
-
* Reads /api/facts/{id}, which serves links from code_graph.db. Recall never
|
|
1251
|
-
* opens that database, so nothing here can affect retrieval.
|
|
1252
|
-
*
|
|
1253
|
-
* textContent throughout: every value is a qualified name or path read out of
|
|
1254
|
-
* an indexed repository, i.e. untrusted input as far as this panel goes.
|
|
1255
|
-
*/
|
|
1256
|
-
function _loadCodeLinks(factId) {
|
|
1257
|
-
var host = document.getElementById('od-drawer-code');
|
|
1258
|
-
if (!host || !factId) return;
|
|
1259
|
-
fetch('/api/facts/' + encodeURIComponent(factId))
|
|
1260
|
-
.then(function (r) { return r.ok ? r.json() : null; })
|
|
1261
|
-
.then(function (d) {
|
|
1262
|
-
var links = (d && d.code_links) || [];
|
|
1263
|
-
if (!links.length) return; // silent when there is nothing to show
|
|
1264
|
-
|
|
1265
|
-
var wrap = document.createElement('div');
|
|
1266
|
-
wrap.style.cssText = 'margin-top:6px;padding-top:6px;border-top:1px dashed var(--border)';
|
|
1267
|
-
|
|
1268
|
-
var label = document.createElement('div');
|
|
1269
|
-
label.style.cssText = 'font-size:11px;color:var(--fg-3);margin-bottom:4px';
|
|
1270
|
-
label.textContent = 'Code referenced (' + links.length + ')';
|
|
1271
|
-
wrap.appendChild(label);
|
|
1272
|
-
|
|
1273
|
-
links.slice(0, 6).forEach(function (l) {
|
|
1274
|
-
var row = document.createElement('div');
|
|
1275
|
-
row.style.cssText = 'font-size:12px;line-height:1.5';
|
|
1276
|
-
|
|
1277
|
-
var code = document.createElement('code');
|
|
1278
|
-
code.style.cssText = 'color:var(--violet)';
|
|
1279
|
-
code.textContent = l.qualified_name || l.name || '?';
|
|
1280
|
-
row.appendChild(code);
|
|
1281
|
-
|
|
1282
|
-
if (l.kind) {
|
|
1283
|
-
var kind = document.createElement('span');
|
|
1284
|
-
kind.style.cssText = 'color:var(--fg-3);font-size:10px;margin-left:6px';
|
|
1285
|
-
kind.textContent = l.kind;
|
|
1286
|
-
row.appendChild(kind);
|
|
1287
|
-
}
|
|
1288
|
-
// A stale link points at code that has moved or gone. Saying so is the
|
|
1289
|
-
// entire value of tracking staleness.
|
|
1290
|
-
if (l.is_stale) {
|
|
1291
|
-
var stale = document.createElement('span');
|
|
1292
|
-
stale.className = 'badge';
|
|
1293
|
-
stale.style.cssText = 'font-size:9px;margin-left:6px';
|
|
1294
|
-
stale.textContent = 'code changed';
|
|
1295
|
-
row.appendChild(stale);
|
|
1296
|
-
}
|
|
1297
|
-
wrap.appendChild(row);
|
|
1298
|
-
});
|
|
1299
|
-
|
|
1300
|
-
if (links.length > 6) {
|
|
1301
|
-
var more = document.createElement('div');
|
|
1302
|
-
more.style.cssText = 'font-size:11px;color:var(--fg-3);margin-top:2px';
|
|
1303
|
-
more.textContent = '… and ' + (links.length - 6) + ' more';
|
|
1304
|
-
wrap.appendChild(more);
|
|
1305
|
-
}
|
|
1306
|
-
host.appendChild(wrap);
|
|
1307
|
-
})
|
|
1308
|
-
.catch(function () { /* display extra: never surface an error here */ });
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
function _startEdit(mid) { // show inline edit form in drawer
|
|
1312
|
-
var m = _st.memories.filter(function (x) { return x.id === mid; })[0];
|
|
1313
|
-
var el = document.getElementById('od-mem-act'); if (!el || !m) return;
|
|
1314
|
-
el.innerHTML = '<textarea id="od-ea" rows="4" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px;background:var(--card-2);color:var(--fg);font-size:13px">' + _esc(m.content) + '</textarea><button data-od-act="save-edit" data-mid="' + _esc(mid) + '" style="display:block;margin-top:6px;padding:6px 14px;border:none;border-radius:6px;background:var(--violet);color:#fff;cursor:pointer">Save</button>';
|
|
1315
|
-
}
|
|
1316
|
-
function _startDel(mid) { // show delete confirmation in drawer
|
|
1317
|
-
var el = document.getElementById('od-mem-act'); if (!el) return;
|
|
1318
|
-
el.innerHTML = '<p style="font-size:13px;color:var(--fg-2);margin-bottom:10px">Permanently delete this memory? This cannot be undone.</p><button data-od-act="confirm-del" data-mid="' + _esc(mid) + '" style="padding:6px 14px;border-radius:6px;background:var(--danger);color:#fff;border:none;cursor:pointer;margin-right:8px">Confirm delete</button><button data-od-act="cancel-act" style="padding:6px 14px;border-radius:6px;background:var(--card-2);border:1px solid var(--border);color:var(--fg);cursor:pointer">Cancel</button>';
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// ── Event delegation ─────────────────────────────────────────────────────────
|
|
1322
|
-
function _wire(container, id) {
|
|
1323
|
-
container.addEventListener('click', function (e) {
|
|
1324
|
-
var el = e.target.closest('[data-od-act]');
|
|
1325
|
-
if (!el) return;
|
|
1326
|
-
var act = el.dataset.odAct;
|
|
1327
|
-
|
|
1328
|
-
if (act === 'sum') {
|
|
1329
|
-
_loadSummary(id, el.dataset.kind, el.dataset.target || '');
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
// Example query chip in the Recall Lab starter state. recall-lab.js owns the
|
|
1333
|
-
// search itself and listens on #recall-lab-search, so fill the box and let it
|
|
1334
|
-
// run — duplicating its fetch here would be a second, divergent code path.
|
|
1335
|
-
if (act === 'recall-eg') {
|
|
1336
|
-
var qBox = document.getElementById('recall-lab-query');
|
|
1337
|
-
var qBtn = document.getElementById('recall-lab-search');
|
|
1338
|
-
if (qBox) qBox.value = el.dataset.q || '';
|
|
1339
|
-
if (qBtn) qBtn.click();
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
if (act === 'tab') {
|
|
1343
|
-
_switchTab(id, el.dataset.tab);
|
|
1344
|
-
return;
|
|
1345
|
-
}
|
|
1346
|
-
if (act === 'cat') {
|
|
1347
|
-
// Toggle on/off chip states without a full re-render
|
|
1348
|
-
var bar = document.getElementById(id + '-cats');
|
|
1349
|
-
if (bar) bar.querySelectorAll('[data-od-act="cat"]').forEach(function (c) {
|
|
1350
|
-
c.classList.toggle('on', c.dataset.cat === el.dataset.cat);
|
|
1351
|
-
});
|
|
1352
|
-
clearTimeout(_searchTimer);
|
|
1353
|
-
_st = Object.assign({}, _st, {
|
|
1354
|
-
category: el.dataset.cat || null, page: 0, searchQ: null,
|
|
1355
|
-
requestSeq: _st.requestSeq + 1,
|
|
1356
|
-
});
|
|
1357
|
-
var searchInput = document.querySelector('#' + id + ' [data-od-act="search"]');
|
|
1358
|
-
if (searchInput) searchInput.value = '';
|
|
1359
|
-
_loadMem(id);
|
|
1360
|
-
return;
|
|
1361
|
-
}
|
|
1362
|
-
if (act === 'sort') {
|
|
1363
|
-
// Update active state on sort buttons in-place
|
|
1364
|
-
var root = document.getElementById(id);
|
|
1365
|
-
if (root) root.querySelectorAll('[data-od-act="sort"]').forEach(function (b) {
|
|
1366
|
-
b.classList.toggle('active', b.dataset.sort === el.dataset.sort);
|
|
1367
|
-
});
|
|
1368
|
-
_doSort(id, el.dataset.sort);
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
if (act === 'scope-view') {
|
|
1372
|
-
var sroot = document.getElementById(id);
|
|
1373
|
-
if (sroot) sroot.querySelectorAll('[data-od-act="scope-view"]').forEach(function (b) {
|
|
1374
|
-
b.classList.toggle('active', b.dataset.scope === el.dataset.scope);
|
|
1375
|
-
});
|
|
1376
|
-
clearTimeout(_searchTimer);
|
|
1377
|
-
_st = Object.assign({}, _st, {
|
|
1378
|
-
scopeView: el.dataset.scope, page: 0, searchQ: null,
|
|
1379
|
-
requestSeq: _st.requestSeq + 1,
|
|
1380
|
-
});
|
|
1381
|
-
var scopedSearchInput = document.querySelector('#' + id + ' [data-od-act="search"]');
|
|
1382
|
-
if (scopedSearchInput) scopedSearchInput.value = '';
|
|
1383
|
-
_loadMem(id);
|
|
1384
|
-
return;
|
|
1385
|
-
}
|
|
1386
|
-
if (act === 'drawer') {
|
|
1387
|
-
var row = el.closest('tr[data-od-act]');
|
|
1388
|
-
var idx = parseInt((row || el).dataset.idx, 10);
|
|
1389
|
-
if (!isNaN(idx)) _openDrawer(idx);
|
|
1390
|
-
return;
|
|
1391
|
-
}
|
|
1392
|
-
if (act === 'close-drawer') { _closeDrawer(); return; }
|
|
1393
|
-
if (act === 'pg') {
|
|
1394
|
-
var pg = parseInt(el.dataset.page, 10);
|
|
1395
|
-
if (!isNaN(pg)) {
|
|
1396
|
-
clearTimeout(_searchTimer);
|
|
1397
|
-
_st = Object.assign({}, _st, {
|
|
1398
|
-
page: pg, searchQ: null, requestSeq: _st.requestSeq + 1,
|
|
1399
|
-
});
|
|
1400
|
-
var pagedSearchInput = document.querySelector('#' + id + ' [data-od-act="search"]');
|
|
1401
|
-
if (pagedSearchInput) pagedSearchInput.value = '';
|
|
1402
|
-
_loadMem(id);
|
|
1403
|
-
}
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
if (act === 'expand-cluster') { _expandCluster(id, el.dataset.cid); return; }
|
|
1407
|
-
if (act === 'tl-range') {
|
|
1408
|
-
var root2 = document.getElementById(id);
|
|
1409
|
-
if (root2) root2.querySelectorAll('[data-od-act="tl-range"]').forEach(function (b) {
|
|
1410
|
-
b.classList.toggle('active', b.dataset.range === el.dataset.range);
|
|
1411
|
-
});
|
|
1412
|
-
_tlLoaded[id + '-' + _st.tlRange] = false; // invalidate cache
|
|
1413
|
-
_st = Object.assign({}, _st, { tlRange: el.dataset.range });
|
|
1414
|
-
_loadTimeline(id);
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
});
|
|
1418
|
-
|
|
1419
|
-
// Search — input event
|
|
1420
|
-
container.addEventListener('change', function (e) {
|
|
1421
|
-
if (e.target.dataset.odAct === 'window') {
|
|
1422
|
-
_st = Object.assign({}, _st, { window: e.target.value || '' });
|
|
1423
|
-
var wq = (_st.searchQ || '').trim();
|
|
1424
|
-
if (wq) _doSearch(id, wq); // re-run active search with the new window
|
|
1425
|
-
}
|
|
1426
|
-
if (e.target.dataset.odAct === 'sum-proj' && e.target.value) {
|
|
1427
|
-
_loadSummary(id, 'project', e.target.value);
|
|
1428
|
-
}
|
|
1429
|
-
});
|
|
1430
|
-
container.addEventListener('input', function (e) {
|
|
1431
|
-
if (e.target.dataset.odAct === 'search') _doSearch(id, e.target.value.trim());
|
|
1432
|
-
});
|
|
1433
|
-
|
|
1434
|
-
// Drawer actions — document-level (drawer is outside container), guarded once
|
|
1435
|
-
if (!window._slmMemDrawerWired) {
|
|
1436
|
-
window._slmMemDrawerWired = true;
|
|
1437
|
-
document.addEventListener('click', function (e) {
|
|
1438
|
-
var el = e.target.closest('[data-od-act]');
|
|
1439
|
-
if (!el) return;
|
|
1440
|
-
var act = el.dataset.odAct;
|
|
1441
|
-
if (act === 'close-drawer') { _closeDrawer(); return; }
|
|
1442
|
-
if (act === 'edit-mem') { _startEdit(el.dataset.mid); return; }
|
|
1443
|
-
if (act === 'del-mem') { _startDel(el.dataset.mid); return; }
|
|
1444
|
-
if (act === 'cancel-act') { var ac = document.getElementById('od-mem-act'); if (ac) ac.innerHTML = ''; return; }
|
|
1445
|
-
if (act === 'set-scope') {
|
|
1446
|
-
var smid = el.dataset.mid;
|
|
1447
|
-
var scopeVal = (document.getElementById('od-scope-sel') || {}).value || 'personal';
|
|
1448
|
-
var sharedVal = ((document.getElementById('od-scope-shared') || {}).value || '').trim();
|
|
1449
|
-
if (scopeVal === 'shared' && !sharedVal) {
|
|
1450
|
-
showToast('Enter at least one profile to share with'); return;
|
|
1451
|
-
}
|
|
1452
|
-
_getMutToken().then(function (tok) {
|
|
1453
|
-
if (!tok) { showToast('Auth unavailable — reload the page'); return; }
|
|
1454
|
-
fetch('/api/memories/' + encodeURIComponent(smid) + '/scope', {
|
|
1455
|
-
method: 'PATCH', credentials: 'same-origin',
|
|
1456
|
-
headers: { 'Content-Type': 'application/json', 'X-Install-Token': tok },
|
|
1457
|
-
body: JSON.stringify({ scope: scopeVal, shared_with: sharedVal }),
|
|
1458
|
-
})
|
|
1459
|
-
.then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
|
|
1460
|
-
.then(function () { showToast('Scope updated → ' + scopeVal); _closeDrawer(); _loadMem(_st.rootId); })
|
|
1461
|
-
.catch(function (e) { showToast('Scope update failed: ' + e.message); });
|
|
1462
|
-
});
|
|
1463
|
-
return;
|
|
1464
|
-
}
|
|
1465
|
-
if (act === 'save-edit' || act === 'confirm-del') {
|
|
1466
|
-
var rid = _st.rootId, isDel = act === 'confirm-del', mid = el.dataset.mid;
|
|
1467
|
-
var content = isDel ? '' : ((document.getElementById('od-ea') || {}).value || '').trim();
|
|
1468
|
-
if (!isDel && !content) { showToast('Content cannot be empty'); return; }
|
|
1469
|
-
_getMutToken().then(function (tok) {
|
|
1470
|
-
if (!tok) { showToast('Auth unavailable — reload the page'); return; }
|
|
1471
|
-
var opts = isDel
|
|
1472
|
-
? {method:'DELETE',credentials:'same-origin',headers:{'X-Install-Token':tok}}
|
|
1473
|
-
: {method:'PATCH',credentials:'same-origin',headers:{'Content-Type':'application/json','X-Install-Token':tok},body:JSON.stringify({content:content})};
|
|
1474
|
-
fetch('/api/memories/' + encodeURIComponent(mid), opts)
|
|
1475
|
-
.then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
|
|
1476
|
-
.then(function () { showToast(isDel ? 'Memory deleted' : 'Memory updated'); _closeDrawer(); _loadMem(rid); })
|
|
1477
|
-
.catch(function (e) { showToast((isDel ? 'Delete' : 'Edit') + ' failed: ' + e.message); });
|
|
1478
|
-
});
|
|
1479
|
-
return;
|
|
1480
|
-
}
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
// ── Public API + auto-init ───────────────────────────────────────────────────
|
|
1486
|
-
|
|
1487
|
-
window.odRenderMemories = render;
|
|
1488
|
-
|
|
1489
|
-
if (document.readyState === 'loading') {
|
|
1490
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
1491
|
-
var p = document.getElementById('memories-pane');
|
|
1492
|
-
if (p) render(p);
|
|
1493
|
-
});
|
|
1494
|
-
} else {
|
|
1495
|
-
var _p = document.getElementById('memories-pane');
|
|
1496
|
-
if (_p) render(_p);
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
}());
|