superlocalmemory 3.7.8 → 3.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/ATTRIBUTION.md +1 -3
  3. package/CHANGELOG.md +129 -0
  4. package/README.md +205 -123
  5. package/package.json +12 -3
  6. package/plugin/.claude-plugin/plugin.json +2 -3
  7. package/plugin/CLAUDE.md +8 -8
  8. package/plugin/agents/slm-governance-advisor.md +80 -0
  9. package/plugin/agents/slm-loop-runner.md +71 -0
  10. package/plugin/agents/slm-memory-advisor.md +10 -5
  11. package/plugin/agents/slm-optimize-advisor.md +9 -3
  12. package/plugin/commands/slm-loop.md +31 -0
  13. package/plugin/hooks/hooks.json +79 -0
  14. package/plugin/requirements.txt +1 -1
  15. package/plugin/scripts/slm-launch +46 -7
  16. package/plugin/settings.json +9 -0
  17. package/plugin/skills/slm-cache/SKILL.md +9 -1
  18. package/plugin/skills/slm-compress/SKILL.md +8 -1
  19. package/plugin/skills/slm-governance/SKILL.md +248 -0
  20. package/plugin/skills/slm-graph/SKILL.md +17 -3
  21. package/plugin/skills/slm-loop/SKILL.md +99 -0
  22. package/plugin/skills/slm-mesh/SKILL.md +282 -0
  23. package/plugin/skills/slm-profile/SKILL.md +148 -0
  24. package/plugin/skills/slm-recall/SKILL.md +46 -10
  25. package/plugin/skills/slm-remember/SKILL.md +48 -1
  26. package/plugin/skills/slm-scope/SKILL.md +176 -0
  27. package/plugin/skills/slm-session/SKILL.md +24 -1
  28. package/plugin/skills/slm-status/SKILL.md +18 -1
  29. package/plugin-src/rules/AGENTS.md +57 -18
  30. package/plugin-src/skills/slm-cache/SKILL.md +9 -1
  31. package/plugin-src/skills/slm-compress/SKILL.md +8 -1
  32. package/plugin-src/skills/slm-graph/SKILL.md +17 -3
  33. package/plugin-src/skills/slm-recall/SKILL.md +46 -10
  34. package/plugin-src/skills/slm-remember/SKILL.md +48 -1
  35. package/plugin-src/skills/slm-session/SKILL.md +24 -1
  36. package/plugin-src/skills/slm-status/SKILL.md +18 -1
  37. package/pyproject.toml +2 -1
  38. package/scripts/postinstall/validation.js +2 -0
  39. package/scripts/postinstall-interactive.js +74 -2
  40. package/src/superlocalmemory/__init__.py +1 -1
  41. package/src/superlocalmemory/access/__init__.py +3 -0
  42. package/src/superlocalmemory/access/rbac.py +477 -0
  43. package/src/superlocalmemory/cli/commands.py +228 -17
  44. package/src/superlocalmemory/cli/compress_cmd.py +17 -7
  45. package/src/superlocalmemory/cli/daemon.py +7 -0
  46. package/src/superlocalmemory/cli/loop_cmd.py +187 -0
  47. package/src/superlocalmemory/cli/main.py +49 -8
  48. package/src/superlocalmemory/cli/mesh_cmd.py +38 -0
  49. package/src/superlocalmemory/cli/optimize_cmd.py +3 -0
  50. package/src/superlocalmemory/cli/pending_store.py +49 -13
  51. package/src/superlocalmemory/cli/proxy_cmd.py +4 -0
  52. package/src/superlocalmemory/cli/scale_engine_cmd.py +6 -0
  53. package/src/superlocalmemory/cli/setup_wizard.py +22 -13
  54. package/src/superlocalmemory/cli/version_banner.py +17 -3
  55. package/src/superlocalmemory/compliance/audit.py +6 -0
  56. package/src/superlocalmemory/compliance/gdpr.py +128 -138
  57. package/src/superlocalmemory/compliance/retention.py +176 -45
  58. package/src/superlocalmemory/core/backend_orchestrator.py +23 -59
  59. package/src/superlocalmemory/core/community_summary.py +267 -0
  60. package/src/superlocalmemory/core/config.py +216 -3
  61. package/src/superlocalmemory/core/consolidation_engine.py +95 -22
  62. package/src/superlocalmemory/core/context_cache.py +61 -18
  63. package/src/superlocalmemory/core/embedding_worker.py +21 -7
  64. package/src/superlocalmemory/core/embeddings.py +131 -46
  65. package/src/superlocalmemory/core/engine.py +41 -22
  66. package/src/superlocalmemory/core/engine_ingestion.py +359 -43
  67. package/src/superlocalmemory/core/engine_wiring.py +13 -0
  68. package/src/superlocalmemory/core/entity_community.py +178 -0
  69. package/src/superlocalmemory/core/graph_analyzer.py +39 -2
  70. package/src/superlocalmemory/core/graph_pruner.py +13 -8
  71. package/src/superlocalmemory/core/ingestion_command.py +134 -25
  72. package/src/superlocalmemory/core/injection.py +12 -7
  73. package/src/superlocalmemory/core/key_expander.py +138 -0
  74. package/src/superlocalmemory/core/maintenance.py +23 -0
  75. package/src/superlocalmemory/core/maintenance_scheduler.py +17 -7
  76. package/src/superlocalmemory/core/modes.py +1 -1
  77. package/src/superlocalmemory/core/mutations.py +2 -2
  78. package/src/superlocalmemory/core/pii.py +105 -0
  79. package/src/superlocalmemory/core/progressive_abstraction.py +208 -0
  80. package/src/superlocalmemory/core/recall_pipeline.py +7 -3
  81. package/src/superlocalmemory/core/recall_worker.py +20 -6
  82. package/src/superlocalmemory/core/scale_engine.py +60 -1
  83. package/src/superlocalmemory/core/security_primitives.py +40 -2
  84. package/src/superlocalmemory/core/store_pipeline.py +186 -29
  85. package/src/superlocalmemory/core/worker_pool.py +21 -6
  86. package/src/superlocalmemory/encoding/entity_reflexion.py +200 -0
  87. package/src/superlocalmemory/encoding/entity_resolver.py +34 -24
  88. package/src/superlocalmemory/encoding/fact_extractor.py +26 -1
  89. package/src/superlocalmemory/encoding/temporal_validator.py +64 -1
  90. package/src/superlocalmemory/evolution/evolution_store.py +122 -45
  91. package/src/superlocalmemory/evolution/llm_dispatch.py +12 -1
  92. package/src/superlocalmemory/evolution/model_selection.py +160 -0
  93. package/src/superlocalmemory/evolution/mutation_generator.py +16 -0
  94. package/src/superlocalmemory/evolution/skill_evolver.py +127 -42
  95. package/src/superlocalmemory/evolution/triggers.py +22 -13
  96. package/src/superlocalmemory/graph/cozo_backend.py +43 -20
  97. package/src/superlocalmemory/hooks/adapter_base.py +5 -1
  98. package/src/superlocalmemory/hooks/auto_recall.py +13 -1
  99. package/src/superlocalmemory/hooks/claude_code_hooks.py +11 -0
  100. package/src/superlocalmemory/hooks/codex_assets.py +64 -5
  101. package/src/superlocalmemory/hooks/hook_daemon.py +20 -3
  102. package/src/superlocalmemory/hooks/hook_handlers.py +6 -1
  103. package/src/superlocalmemory/hooks/memory_protocol.py +54 -0
  104. package/src/superlocalmemory/hooks/portable_kit.py +148 -3
  105. package/src/superlocalmemory/infra/backup.py +12 -1
  106. package/src/superlocalmemory/infra/daemon_identity.py +40 -4
  107. package/src/superlocalmemory/infra/data_root.py +43 -4
  108. package/src/superlocalmemory/infra/event_bus.py +107 -24
  109. package/src/superlocalmemory/infra/rate_limiter.py +93 -0
  110. package/src/superlocalmemory/ingestion/adapter_manager.py +4 -1
  111. package/src/superlocalmemory/ingestion/credentials.py +1 -1
  112. package/src/superlocalmemory/learning/cross_project.py +28 -19
  113. package/src/superlocalmemory/learning/model_rollback.py +3 -0
  114. package/src/superlocalmemory/learning/ranker_retrain_online.py +2 -0
  115. package/src/superlocalmemory/learning/reward.py +50 -0
  116. package/src/superlocalmemory/learning/reward_proxy.py +42 -9
  117. package/src/superlocalmemory/learning/source_quality.py +523 -1
  118. package/src/superlocalmemory/loops/__init__.py +56 -0
  119. package/src/superlocalmemory/loops/budget.py +58 -0
  120. package/src/superlocalmemory/loops/engine.py +164 -0
  121. package/src/superlocalmemory/loops/ledger.py +263 -0
  122. package/src/superlocalmemory/loops/models.py +152 -0
  123. package/src/superlocalmemory/loops/rules.py +52 -0
  124. package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
  125. package/src/superlocalmemory/mcp/_pool_adapter.py +2 -0
  126. package/src/superlocalmemory/mcp/profiles.py +103 -0
  127. package/src/superlocalmemory/mcp/server.py +32 -79
  128. package/src/superlocalmemory/mcp/tools_active.py +4 -7
  129. package/src/superlocalmemory/mcp/tools_code_graph.py +51 -5
  130. package/src/superlocalmemory/mcp/tools_core.py +12 -4
  131. package/src/superlocalmemory/mcp/tools_evolution.py +6 -3
  132. package/src/superlocalmemory/mcp/tools_learning.py +2 -2
  133. package/src/superlocalmemory/mcp/tools_loops.py +300 -0
  134. package/src/superlocalmemory/mcp/tools_mesh.py +140 -4
  135. package/src/superlocalmemory/mcp/tools_optimize.py +15 -8
  136. package/src/superlocalmemory/mesh/broker.py +237 -129
  137. package/src/superlocalmemory/mesh/remote_sync.py +50 -8
  138. package/src/superlocalmemory/optimize/NOTICE +1 -6
  139. package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +1 -4
  140. package/src/superlocalmemory/optimize/adapters/openai_adapter.py +1 -4
  141. package/src/superlocalmemory/optimize/cache/semantic.py +27 -19
  142. package/src/superlocalmemory/optimize/compress/align.py +32 -26
  143. package/src/superlocalmemory/optimize/compress/ccr.py +14 -71
  144. package/src/superlocalmemory/optimize/compress/router.py +105 -22
  145. package/src/superlocalmemory/optimize/config/defaults.py +1 -1
  146. package/src/superlocalmemory/optimize/config/schema.py +87 -4
  147. package/src/superlocalmemory/optimize/metrics/counters.py +13 -4
  148. package/src/superlocalmemory/optimize/metrics/estimator.py +0 -3
  149. package/src/superlocalmemory/optimize/proxy/_helpers.py +31 -4
  150. package/src/superlocalmemory/optimize/storage/db.py +38 -9
  151. package/src/superlocalmemory/optimize/storage/schema.py +10 -0
  152. package/src/superlocalmemory/parameterization/pattern_extractor.py +6 -3
  153. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  154. package/src/superlocalmemory/retrieval/bm25_channel.py +68 -10
  155. package/src/superlocalmemory/retrieval/engine.py +221 -47
  156. package/src/superlocalmemory/retrieval/entity_channel.py +7 -5
  157. package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -2
  158. package/src/superlocalmemory/retrieval/reranker.py +3 -4
  159. package/src/superlocalmemory/retrieval/semantic_channel.py +114 -21
  160. package/src/superlocalmemory/retrieval/spreading_activation.py +11 -2
  161. package/src/superlocalmemory/retrieval/temporal_channel.py +48 -9
  162. package/src/superlocalmemory/retrieval/temporal_frame.py +102 -0
  163. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +135 -0
  164. package/src/superlocalmemory/retrieval/time_window.py +181 -0
  165. package/src/superlocalmemory/server/api.py +4 -4
  166. package/src/superlocalmemory/server/config_file.py +90 -0
  167. package/src/superlocalmemory/server/origin.py +50 -0
  168. package/src/superlocalmemory/server/profile_runtime.py +125 -8
  169. package/src/superlocalmemory/server/rbac_enforce.py +142 -0
  170. package/src/superlocalmemory/server/recall_health.py +24 -3
  171. package/src/superlocalmemory/server/recall_serializer.py +19 -1
  172. package/src/superlocalmemory/server/routes/abstraction.py +115 -0
  173. package/src/superlocalmemory/server/routes/agents.py +128 -38
  174. package/src/superlocalmemory/server/routes/backup.py +317 -70
  175. package/src/superlocalmemory/server/routes/behavioral.py +349 -71
  176. package/src/superlocalmemory/server/routes/brain.py +69 -12
  177. package/src/superlocalmemory/server/routes/chat.py +10 -5
  178. package/src/superlocalmemory/server/routes/compliance.py +171 -21
  179. package/src/superlocalmemory/server/routes/config_api.py +438 -0
  180. package/src/superlocalmemory/server/routes/data_io.py +30 -8
  181. package/src/superlocalmemory/server/routes/entity.py +108 -26
  182. package/src/superlocalmemory/server/routes/events.py +24 -8
  183. package/src/superlocalmemory/server/routes/evolution.py +189 -68
  184. package/src/superlocalmemory/server/routes/helpers.py +16 -1
  185. package/src/superlocalmemory/server/routes/ingest.py +7 -4
  186. package/src/superlocalmemory/server/routes/insights.py +3 -3
  187. package/src/superlocalmemory/server/routes/learning.py +289 -118
  188. package/src/superlocalmemory/server/routes/learning_telemetry.py +153 -0
  189. package/src/superlocalmemory/server/routes/lifecycle.py +59 -8
  190. package/src/superlocalmemory/server/routes/memories.py +182 -57
  191. package/src/superlocalmemory/server/routes/mesh.py +200 -31
  192. package/src/superlocalmemory/server/routes/optimize.py +33 -1
  193. package/src/superlocalmemory/server/routes/prewarm.py +2 -0
  194. package/src/superlocalmemory/server/routes/profiles.py +63 -17
  195. package/src/superlocalmemory/server/routes/ratelimit.py +132 -0
  196. package/src/superlocalmemory/server/routes/rbac.py +367 -0
  197. package/src/superlocalmemory/server/routes/stats.py +103 -158
  198. package/src/superlocalmemory/server/routes/tiers.py +11 -9
  199. package/src/superlocalmemory/server/routes/token.py +3 -13
  200. package/src/superlocalmemory/server/routes/v3_api.py +247 -89
  201. package/src/superlocalmemory/server/routes/ws.py +5 -2
  202. package/src/superlocalmemory/server/security_middleware.py +12 -5
  203. package/src/superlocalmemory/server/ui.py +20 -5
  204. package/src/superlocalmemory/server/unified_daemon.py +827 -72
  205. package/src/superlocalmemory/server/write_identity.py +38 -8
  206. package/src/superlocalmemory/storage/database.py +265 -53
  207. package/src/superlocalmemory/storage/migration_runner.py +132 -1
  208. package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +5 -0
  209. package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +108 -0
  210. package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +86 -0
  211. package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +194 -0
  212. package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +87 -0
  213. package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +90 -0
  214. package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +136 -0
  215. package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +163 -0
  216. package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +270 -0
  217. package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +137 -0
  218. package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +93 -0
  219. package/src/superlocalmemory/storage/migrations/__init__.py +4 -0
  220. package/src/superlocalmemory/storage/models.py +4 -0
  221. package/src/superlocalmemory/storage/schema.py +136 -1
  222. package/src/superlocalmemory/storage/schema_v32.py +2 -0
  223. package/src/superlocalmemory/storage/schema_v343.py +24 -12
  224. package/src/superlocalmemory/storage/schema_v347.py +4 -0
  225. package/src/superlocalmemory/trust/gate.py +49 -8
  226. package/src/superlocalmemory/ui/assets/slm-icon-white.svg +64 -0
  227. package/src/superlocalmemory/ui/assets/slm-icon.svg +36 -0
  228. package/src/superlocalmemory/ui/css/design-system.css +621 -0
  229. package/src/superlocalmemory/ui/css/neural-glass.css +6 -0
  230. package/src/superlocalmemory/ui/css/od-bridge.css +158 -0
  231. package/src/superlocalmemory/ui/favicon.svg +35 -4
  232. package/src/superlocalmemory/ui/index.html +303 -173
  233. package/src/superlocalmemory/ui/js/brain.js +5 -20
  234. package/src/superlocalmemory/ui/js/core.js +100 -41
  235. package/src/superlocalmemory/ui/js/dashboard.js +403 -65
  236. package/src/superlocalmemory/ui/js/event-delegation.js +102 -0
  237. package/src/superlocalmemory/ui/js/knowledge-graph.js +11 -11
  238. package/src/superlocalmemory/ui/js/math-health.js +1 -1
  239. package/src/superlocalmemory/ui/js/memories.js +15 -4
  240. package/src/superlocalmemory/ui/js/memory-chat.js +7 -7
  241. package/src/superlocalmemory/ui/js/ng-entities.js +6 -8
  242. package/src/superlocalmemory/ui/js/ng-ingestion.js +4 -4
  243. package/src/superlocalmemory/ui/js/ng-mesh.js +4 -9
  244. package/src/superlocalmemory/ui/js/ng-shell.js +8 -8
  245. package/src/superlocalmemory/ui/js/ng-skills.js +54 -2
  246. package/src/superlocalmemory/ui/js/od-agents.js +544 -0
  247. package/src/superlocalmemory/ui/js/od-auth-gate.js +257 -0
  248. package/src/superlocalmemory/ui/js/od-backup.js +871 -0
  249. package/src/superlocalmemory/ui/js/od-brain.js +816 -0
  250. package/src/superlocalmemory/ui/js/od-entities.js +579 -0
  251. package/src/superlocalmemory/ui/js/od-graph.js +600 -0
  252. package/src/superlocalmemory/ui/js/od-health.js +539 -0
  253. package/src/superlocalmemory/ui/js/od-mcp.js +508 -0
  254. package/src/superlocalmemory/ui/js/od-memories.js +929 -0
  255. package/src/superlocalmemory/ui/js/od-mesh.js +553 -0
  256. package/src/superlocalmemory/ui/js/od-operations.js +1250 -0
  257. package/src/superlocalmemory/ui/js/od-optimize.js +787 -0
  258. package/src/superlocalmemory/ui/js/od-settings.js +1107 -0
  259. package/src/superlocalmemory/ui/js/od-shell.js +809 -0
  260. package/src/superlocalmemory/ui/js/od-skills.js +600 -0
  261. package/src/superlocalmemory/ui/js/od-team.js +258 -0
  262. package/src/superlocalmemory/ui/js/profiles.js +159 -46
  263. package/src/superlocalmemory/ui/js/settings.js +17 -3
  264. package/src/superlocalmemory/ui/js/timeline.js +34 -5
  265. package/src/superlocalmemory/ui/js/trust-dashboard.js +2 -2
  266. package/src/superlocalmemory/vector/lancedb_backend.py +8 -6
  267. package/plugin-src/.mcp.json +0 -12
  268. package/plugin-src/agents/slm-memory-advisor.md +0 -44
  269. package/plugin-src/agents/slm-optimize-advisor.md +0 -38
  270. package/plugin-src/hooks/.gitkeep +0 -0
  271. package/plugin-src/hooks/hooks.json +0 -23
  272. package/plugin-src/manifest.json +0 -25
  273. package/plugin-src/requirements.txt +0 -1
  274. package/plugin-src/rules/CLAUDE.md.fragment +0 -44
  275. package/plugin-src/scripts/ensure-venv.bat +0 -122
  276. package/plugin-src/scripts/ensure-venv.sh +0 -105
  277. package/plugin-src/scripts/slm-launch +0 -23
  278. package/plugin-src/scripts/slm-launch.bat +0 -23
  279. package/plugin-src/settings.json +0 -16
  280. package/src/superlocalmemory/learning/behavioral_listener.py +0 -94
@@ -21,7 +21,8 @@
21
21
  (() => {
22
22
  'use strict';
23
23
 
24
- const TOKEN_STORAGE_KEY = 'slm_install_token';
24
+ // B2 (3.7.9): token kept in a private closure var, never sessionStorage.
25
+ let _tokenCache = null;
25
26
 
26
27
  // --------------------------------------------------------------------
27
28
  // Safe DOM helper — the ONLY way this file creates nodes.
@@ -69,25 +70,9 @@
69
70
  // --------------------------------------------------------------------
70
71
  // Token handling — auto-fetch from local daemon, never prompt user.
71
72
  // --------------------------------------------------------------------
72
- function readToken() {
73
- try {
74
- return window.sessionStorage
75
- ? window.sessionStorage.getItem(TOKEN_STORAGE_KEY)
76
- : null;
77
- } catch (e) {
78
- return null;
79
- }
80
- }
73
+ function readToken() { return _tokenCache; }
81
74
 
82
- function writeToken(value) {
83
- try {
84
- if (window.sessionStorage) {
85
- window.sessionStorage.setItem(TOKEN_STORAGE_KEY, value);
86
- }
87
- } catch (e) {
88
- // storage disabled — keep in-memory.
89
- }
90
- }
75
+ function writeToken(value) { _tokenCache = value; }
91
76
 
92
77
  async function fetchTokenFromServer() {
93
78
  try {
@@ -426,7 +411,7 @@
426
411
  function cardBandit(b) {
427
412
  const data = b || {};
428
413
  const wrap = EL('section', {className: 'brain-section'});
429
- wrap.appendChild(EL('h4', {text: 'Adaptive ranking (bandit)'}));
414
+ wrap.appendChild(EL('h4', {text: 'Adaptive ranking'}));
430
415
 
431
416
  const top = data.top_arm_global;
432
417
  const topText = top
@@ -16,27 +16,30 @@
16
16
  window.SLM_FETCH_TIMEOUT_MS = 15000;
17
17
  window.SLM_INSTALL_TOKEN_KEY = 'slm_install_token';
18
18
 
19
- window.slmInstallToken = async function (forceRefresh) {
20
- if (!forceRefresh) {
21
- var cached = sessionStorage.getItem(window.SLM_INSTALL_TOKEN_KEY);
22
- if (cached) return cached;
23
- }
24
- var response = await window.__slmOriginalFetch(
25
- '/internal/token',
26
- {credentials: 'same-origin'}
27
- );
28
- if (!response.ok) return '';
29
- var payload = await response.json();
30
- var token = payload && payload.token ? payload.token : '';
31
- if (token) sessionStorage.setItem(window.SLM_INSTALL_TOKEN_KEY, token);
32
- return token;
33
- };
34
-
35
- // Global fetch patch: apply the abort timeout to every relative-URL request
19
+ // B2 (3.7.9): the install token is kept in a private closure, never in
20
+ // sessionStorage — a stored token is trivially readable by any injected
21
+ // script (sessionStorage.getItem), which was the theft leg of the XSS chain.
22
+ window.slmInstallToken = (function () {
23
+ var _cache = null; // in-memory only; not on window, not in storage
24
+ return async function (forceRefresh) {
25
+ if (!forceRefresh && _cache) return _cache;
26
+ var response = await window.__slmOriginalFetch(
27
+ '/internal/token',
28
+ {credentials: 'same-origin'}
29
+ );
30
+ if (!response.ok) return '';
31
+ var payload = await response.json();
32
+ var token = payload && payload.token ? payload.token : '';
33
+ if (token) _cache = token;
34
+ return token;
35
+ };
36
+ })();
37
+
38
+ // Global fetch patch: apply the abort timeout to every same-origin request
36
39
  // automatically. 17 UI modules call bare fetch() — patching here avoids
37
40
  // touching each one and guarantees no future callsite can regress to an
38
- // un-timed fetch that holds the spinner forever. Absolute URLs (external
39
- // resources) are passed through unchanged. Callers that already supply
41
+ // un-timed fetch that holds the spinner forever. External URLs are passed
42
+ // through unchanged. Callers that already supply
40
43
  // `signal` keep their own behavior. `init.timeoutMs` lets callers override
41
44
  // the default per-request.
42
45
  (function patchFetch() {
@@ -46,25 +49,68 @@ window.slmInstallToken = async function (forceRefresh) {
46
49
  window.__slmOriginalFetch = _origFetch;
47
50
  window.fetch = function (input, init) {
48
51
  init = Object.assign({}, init || {});
49
- var urlStr = typeof input === 'string' ? input : (input && input.url) || '';
50
- var isRelative = !(/^https?:\/\//i.test(urlStr));
52
+ var urlStr = typeof input === 'string'
53
+ ? input
54
+ : (input && (input.url || input.href)) || '';
55
+ // Resolve every URL before deciding whether it is local. In particular,
56
+ // protocol-relative URLs such as //host/path inherit the current scheme
57
+ // but are not same-origin and must never receive the install token.
58
+ var isSameOrigin = false;
59
+ var requestUrl = null;
60
+ try {
61
+ requestUrl = new URL(urlStr, window.location.href);
62
+ isSameOrigin = requestUrl.origin === window.location.origin;
63
+ } catch (e) {
64
+ // A malformed URL is handled by native fetch. Treat it as external
65
+ // here so it cannot obtain local credentials while failing.
66
+ }
51
67
  var method = String(
52
68
  init.method || (input && input.method) || 'GET'
53
69
  ).toUpperCase();
54
70
  var mutating = ['POST', 'PUT', 'PATCH', 'DELETE'].indexOf(method) !== -1;
71
+ var invalidatesCache = init.slmInvalidatesCache !== false;
72
+ var requiresWriteAuth = init.slmRequiresWriteAuth !== false;
73
+ delete init.slmInvalidatesCache;
74
+ delete init.slmRequiresWriteAuth;
75
+
76
+ function invalidateAfterMutation(request) {
77
+ if (!isSameOrigin || !mutating || !invalidatesCache) return request;
78
+ return request.then(function (response) {
79
+ if (
80
+ response && response.ok &&
81
+ typeof window.slmInvalidatePanes === 'function'
82
+ ) {
83
+ window.slmInvalidatePanes();
84
+ }
85
+ if (
86
+ response && response.ok &&
87
+ typeof window.slmInvalidateDashboardCache === 'function'
88
+ ) {
89
+ window.slmInvalidateDashboardCache();
90
+ }
91
+ return response;
92
+ });
93
+ }
55
94
 
56
95
  function send() {
57
- if (!isRelative || init.signal) {
58
- return _origFetch(input, init);
96
+ if (!isSameOrigin || init.signal) {
97
+ return invalidateAfterMutation(_origFetch(input, init));
59
98
  }
60
99
  var controller = new AbortController();
61
100
  var timeoutMs = init.timeoutMs || window.SLM_FETCH_TIMEOUT_MS;
62
101
  var timer = setTimeout(function () { controller.abort(); }, timeoutMs);
63
102
  init.signal = controller.signal;
64
- return _origFetch(input, init).finally(function () { clearTimeout(timer); });
103
+ return invalidateAfterMutation(
104
+ _origFetch(input, init).finally(function () { clearTimeout(timer); })
105
+ );
65
106
  }
66
107
 
67
- if (isRelative && mutating && urlStr !== '/internal/token') {
108
+ if (
109
+ isSameOrigin &&
110
+ mutating &&
111
+ requiresWriteAuth &&
112
+ (!requestUrl || requestUrl.pathname !== '/internal/token')
113
+ ) {
68
114
  return window.slmInstallToken(false).then(function (token) {
69
115
  if (!token) throw new Error('local write credential unavailable');
70
116
  var headers = new Headers(
@@ -460,22 +506,30 @@ function populateFilters(categories, projects) {
460
506
  // Clear existing options beyond the first placeholder to prevent duplicates on refresh
461
507
  if (categorySelect) while (categorySelect.options.length > 1) categorySelect.remove(1);
462
508
  if (projectSelect) while (projectSelect.options.length > 1) projectSelect.remove(1);
463
- categories.forEach(function(cat) {
464
- if (cat.category) {
465
- var option = document.createElement('option');
466
- option.value = cat.category;
467
- option.textContent = cat.category + ' (' + cat.count + ')';
468
- categorySelect.appendChild(option);
469
- }
470
- });
471
- projects.forEach(function(proj) {
472
- if (proj.project_name) {
473
- var option = document.createElement('option');
474
- option.value = proj.project_name;
475
- option.textContent = proj.project_name + ' (' + proj.count + ')';
476
- projectSelect.appendChild(option);
477
- }
478
- });
509
+ // Guard appendChild: in the OD dashboard #filter-category / #filter-project
510
+ // live in a folded pane and are frequently absent. Without these guards a
511
+ // null.appendChild threw, tripping the loadStats() catch and zeroing every
512
+ // dashboard counter after a profile create/switch.
513
+ if (categorySelect) {
514
+ categories.forEach(function(cat) {
515
+ if (cat.category) {
516
+ var option = document.createElement('option');
517
+ option.value = cat.category;
518
+ option.textContent = cat.category + ' (' + cat.count + ')';
519
+ categorySelect.appendChild(option);
520
+ }
521
+ });
522
+ }
523
+ if (projectSelect) {
524
+ projects.forEach(function(proj) {
525
+ if (proj.project_name) {
526
+ var option = document.createElement('option');
527
+ option.value = proj.project_name;
528
+ option.textContent = proj.project_name + ' (' + proj.count + ')';
529
+ projectSelect.appendChild(option);
530
+ }
531
+ });
532
+ }
479
533
  }
480
534
 
481
535
  // ============================================================================
@@ -491,6 +545,11 @@ window.addEventListener('DOMContentLoaded', function() {
491
545
  loadProfiles();
492
546
  loadStats();
493
547
  loadGraph();
548
+ // DASH-V1/V2/V3 fix: populate the landing-page cards (Operating Mode,
549
+ // LLM Provider, Memories facts, Version) on first paint. loadDashboard()
550
+ // was only bound to visibilitychange/focus/hashchange, none of which fire
551
+ // on a fresh load, so those cards were stuck on their static "Loading…".
552
+ if (typeof loadDashboard === 'function') loadDashboard();
494
553
 
495
554
  // v2.5 — Event Bus + Agent Registry (graceful if functions don't exist)
496
555
  if (typeof initEventStream === 'function') initEventStream();