superlocalmemory 3.7.8 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/ATTRIBUTION.md +1 -3
  3. package/CHANGELOG.md +69 -0
  4. package/README.md +199 -29
  5. package/package.json +4 -2
  6. package/plugin/.claude-plugin/plugin.json +2 -2
  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/agents/slm-governance-advisor.md +80 -0
  30. package/plugin-src/agents/slm-loop-runner.md +71 -0
  31. package/plugin-src/agents/slm-memory-advisor.md +10 -5
  32. package/plugin-src/agents/slm-optimize-advisor.md +9 -3
  33. package/plugin-src/commands/slm-loop.md +31 -0
  34. package/plugin-src/hooks/hooks.json +79 -0
  35. package/plugin-src/manifest.json +7 -2
  36. package/plugin-src/requirements.txt +1 -1
  37. package/plugin-src/rules/AGENTS.md +57 -18
  38. package/plugin-src/rules/CLAUDE.md.fragment +8 -8
  39. package/plugin-src/scripts/slm-launch +46 -7
  40. package/plugin-src/settings.json +9 -0
  41. package/plugin-src/skills/slm-cache/SKILL.md +9 -1
  42. package/plugin-src/skills/slm-compress/SKILL.md +8 -1
  43. package/plugin-src/skills/slm-governance/SKILL.md +248 -0
  44. package/plugin-src/skills/slm-graph/SKILL.md +17 -3
  45. package/plugin-src/skills/slm-loop/SKILL.md +99 -0
  46. package/plugin-src/skills/slm-mesh/SKILL.md +282 -0
  47. package/plugin-src/skills/slm-profile/SKILL.md +148 -0
  48. package/plugin-src/skills/slm-recall/SKILL.md +46 -10
  49. package/plugin-src/skills/slm-remember/SKILL.md +48 -1
  50. package/plugin-src/skills/slm-scope/SKILL.md +176 -0
  51. package/plugin-src/skills/slm-session/SKILL.md +24 -1
  52. package/plugin-src/skills/slm-status/SKILL.md +18 -1
  53. package/pyproject.toml +1 -1
  54. package/scripts/postinstall/validation.js +2 -0
  55. package/scripts/postinstall-interactive.js +74 -2
  56. package/src/superlocalmemory/__init__.py +1 -1
  57. package/src/superlocalmemory/access/__init__.py +3 -0
  58. package/src/superlocalmemory/access/rbac.py +477 -0
  59. package/src/superlocalmemory/cli/commands.py +94 -10
  60. package/src/superlocalmemory/cli/compress_cmd.py +17 -7
  61. package/src/superlocalmemory/cli/loop_cmd.py +192 -0
  62. package/src/superlocalmemory/cli/main.py +39 -4
  63. package/src/superlocalmemory/cli/mesh_cmd.py +38 -0
  64. package/src/superlocalmemory/cli/optimize_cmd.py +3 -0
  65. package/src/superlocalmemory/cli/pending_store.py +49 -13
  66. package/src/superlocalmemory/cli/proxy_cmd.py +4 -0
  67. package/src/superlocalmemory/cli/scale_engine_cmd.py +6 -0
  68. package/src/superlocalmemory/cli/setup_wizard.py +22 -13
  69. package/src/superlocalmemory/compliance/audit.py +6 -0
  70. package/src/superlocalmemory/compliance/gdpr.py +128 -138
  71. package/src/superlocalmemory/compliance/retention.py +176 -45
  72. package/src/superlocalmemory/core/backend_orchestrator.py +5 -43
  73. package/src/superlocalmemory/core/community_summary.py +267 -0
  74. package/src/superlocalmemory/core/config.py +216 -3
  75. package/src/superlocalmemory/core/consolidation_engine.py +95 -22
  76. package/src/superlocalmemory/core/context_cache.py +61 -18
  77. package/src/superlocalmemory/core/embedding_worker.py +17 -2
  78. package/src/superlocalmemory/core/embeddings.py +12 -1
  79. package/src/superlocalmemory/core/engine.py +17 -1
  80. package/src/superlocalmemory/core/engine_ingestion.py +29 -0
  81. package/src/superlocalmemory/core/engine_wiring.py +13 -0
  82. package/src/superlocalmemory/core/entity_community.py +178 -0
  83. package/src/superlocalmemory/core/graph_analyzer.py +39 -2
  84. package/src/superlocalmemory/core/graph_pruner.py +13 -8
  85. package/src/superlocalmemory/core/key_expander.py +138 -0
  86. package/src/superlocalmemory/core/maintenance.py +23 -0
  87. package/src/superlocalmemory/core/modes.py +1 -1
  88. package/src/superlocalmemory/core/mutations.py +2 -2
  89. package/src/superlocalmemory/core/pii.py +105 -0
  90. package/src/superlocalmemory/core/progressive_abstraction.py +208 -0
  91. package/src/superlocalmemory/core/recall_pipeline.py +2 -0
  92. package/src/superlocalmemory/core/recall_worker.py +20 -6
  93. package/src/superlocalmemory/core/scale_engine.py +60 -1
  94. package/src/superlocalmemory/core/security_primitives.py +40 -2
  95. package/src/superlocalmemory/core/store_pipeline.py +35 -11
  96. package/src/superlocalmemory/core/worker_pool.py +21 -6
  97. package/src/superlocalmemory/encoding/entity_reflexion.py +200 -0
  98. package/src/superlocalmemory/encoding/entity_resolver.py +34 -24
  99. package/src/superlocalmemory/encoding/fact_extractor.py +26 -1
  100. package/src/superlocalmemory/encoding/temporal_validator.py +64 -1
  101. package/src/superlocalmemory/evolution/evolution_store.py +122 -45
  102. package/src/superlocalmemory/evolution/llm_dispatch.py +12 -1
  103. package/src/superlocalmemory/evolution/model_selection.py +160 -0
  104. package/src/superlocalmemory/evolution/mutation_generator.py +16 -0
  105. package/src/superlocalmemory/evolution/skill_evolver.py +127 -42
  106. package/src/superlocalmemory/evolution/triggers.py +22 -13
  107. package/src/superlocalmemory/graph/cozo_backend.py +43 -20
  108. package/src/superlocalmemory/hooks/adapter_base.py +5 -1
  109. package/src/superlocalmemory/hooks/auto_recall.py +13 -1
  110. package/src/superlocalmemory/hooks/claude_code_hooks.py +11 -0
  111. package/src/superlocalmemory/hooks/codex_assets.py +64 -5
  112. package/src/superlocalmemory/hooks/hook_daemon.py +20 -3
  113. package/src/superlocalmemory/hooks/memory_protocol.py +54 -0
  114. package/src/superlocalmemory/hooks/portable_kit.py +114 -1
  115. package/src/superlocalmemory/infra/backup.py +12 -1
  116. package/src/superlocalmemory/infra/daemon_identity.py +40 -4
  117. package/src/superlocalmemory/infra/data_root.py +43 -4
  118. package/src/superlocalmemory/infra/event_bus.py +107 -24
  119. package/src/superlocalmemory/infra/rate_limiter.py +93 -0
  120. package/src/superlocalmemory/ingestion/adapter_manager.py +4 -1
  121. package/src/superlocalmemory/ingestion/credentials.py +1 -1
  122. package/src/superlocalmemory/learning/cross_project.py +28 -19
  123. package/src/superlocalmemory/learning/reward_proxy.py +42 -9
  124. package/src/superlocalmemory/loops/__init__.py +56 -0
  125. package/src/superlocalmemory/loops/budget.py +58 -0
  126. package/src/superlocalmemory/loops/engine.py +164 -0
  127. package/src/superlocalmemory/loops/ledger.py +243 -0
  128. package/src/superlocalmemory/loops/models.py +152 -0
  129. package/src/superlocalmemory/loops/rules.py +52 -0
  130. package/src/superlocalmemory/mcp/_daemon_proxy.py +3 -0
  131. package/src/superlocalmemory/mcp/_pool_adapter.py +2 -0
  132. package/src/superlocalmemory/mcp/profiles.py +103 -0
  133. package/src/superlocalmemory/mcp/server.py +21 -49
  134. package/src/superlocalmemory/mcp/tools_active.py +4 -7
  135. package/src/superlocalmemory/mcp/tools_code_graph.py +51 -5
  136. package/src/superlocalmemory/mcp/tools_core.py +8 -1
  137. package/src/superlocalmemory/mcp/tools_evolution.py +6 -3
  138. package/src/superlocalmemory/mcp/tools_loops.py +300 -0
  139. package/src/superlocalmemory/mcp/tools_mesh.py +140 -4
  140. package/src/superlocalmemory/mcp/tools_optimize.py +15 -8
  141. package/src/superlocalmemory/mesh/broker.py +237 -129
  142. package/src/superlocalmemory/mesh/remote_sync.py +50 -8
  143. package/src/superlocalmemory/optimize/NOTICE +1 -6
  144. package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +1 -4
  145. package/src/superlocalmemory/optimize/adapters/openai_adapter.py +1 -4
  146. package/src/superlocalmemory/optimize/cache/semantic.py +27 -19
  147. package/src/superlocalmemory/optimize/compress/align.py +32 -26
  148. package/src/superlocalmemory/optimize/compress/ccr.py +14 -71
  149. package/src/superlocalmemory/optimize/compress/router.py +105 -22
  150. package/src/superlocalmemory/optimize/config/defaults.py +1 -1
  151. package/src/superlocalmemory/optimize/config/schema.py +87 -4
  152. package/src/superlocalmemory/optimize/metrics/counters.py +13 -4
  153. package/src/superlocalmemory/optimize/metrics/estimator.py +0 -3
  154. package/src/superlocalmemory/optimize/proxy/_helpers.py +31 -4
  155. package/src/superlocalmemory/optimize/storage/db.py +38 -9
  156. package/src/superlocalmemory/optimize/storage/schema.py +10 -0
  157. package/src/superlocalmemory/parameterization/pattern_extractor.py +6 -3
  158. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  159. package/src/superlocalmemory/retrieval/bm25_channel.py +68 -10
  160. package/src/superlocalmemory/retrieval/engine.py +168 -26
  161. package/src/superlocalmemory/retrieval/entity_channel.py +7 -5
  162. package/src/superlocalmemory/retrieval/hopfield_channel.py +9 -2
  163. package/src/superlocalmemory/retrieval/semantic_channel.py +114 -21
  164. package/src/superlocalmemory/retrieval/spreading_activation.py +11 -2
  165. package/src/superlocalmemory/retrieval/temporal_channel.py +48 -9
  166. package/src/superlocalmemory/retrieval/temporal_frame.py +102 -0
  167. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +135 -0
  168. package/src/superlocalmemory/retrieval/time_window.py +181 -0
  169. package/src/superlocalmemory/server/api.py +4 -4
  170. package/src/superlocalmemory/server/profile_runtime.py +125 -8
  171. package/src/superlocalmemory/server/rbac_enforce.py +142 -0
  172. package/src/superlocalmemory/server/recall_health.py +24 -3
  173. package/src/superlocalmemory/server/recall_serializer.py +19 -1
  174. package/src/superlocalmemory/server/routes/abstraction.py +115 -0
  175. package/src/superlocalmemory/server/routes/agents.py +128 -38
  176. package/src/superlocalmemory/server/routes/backup.py +34 -10
  177. package/src/superlocalmemory/server/routes/behavioral.py +13 -12
  178. package/src/superlocalmemory/server/routes/brain.py +21 -5
  179. package/src/superlocalmemory/server/routes/chat.py +10 -5
  180. package/src/superlocalmemory/server/routes/compliance.py +171 -21
  181. package/src/superlocalmemory/server/routes/config_api.py +436 -0
  182. package/src/superlocalmemory/server/routes/data_io.py +30 -8
  183. package/src/superlocalmemory/server/routes/entity.py +9 -4
  184. package/src/superlocalmemory/server/routes/events.py +24 -8
  185. package/src/superlocalmemory/server/routes/evolution.py +135 -17
  186. package/src/superlocalmemory/server/routes/helpers.py +16 -1
  187. package/src/superlocalmemory/server/routes/ingest.py +7 -4
  188. package/src/superlocalmemory/server/routes/insights.py +3 -3
  189. package/src/superlocalmemory/server/routes/learning.py +14 -14
  190. package/src/superlocalmemory/server/routes/lifecycle.py +59 -8
  191. package/src/superlocalmemory/server/routes/memories.py +182 -57
  192. package/src/superlocalmemory/server/routes/mesh.py +95 -15
  193. package/src/superlocalmemory/server/routes/optimize.py +33 -1
  194. package/src/superlocalmemory/server/routes/prewarm.py +2 -0
  195. package/src/superlocalmemory/server/routes/profiles.py +63 -17
  196. package/src/superlocalmemory/server/routes/ratelimit.py +124 -0
  197. package/src/superlocalmemory/server/routes/rbac.py +367 -0
  198. package/src/superlocalmemory/server/routes/stats.py +13 -6
  199. package/src/superlocalmemory/server/routes/tiers.py +11 -9
  200. package/src/superlocalmemory/server/routes/v3_api.py +183 -69
  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 +384 -56
  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 +53 -0
  208. package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +108 -0
  209. package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +86 -0
  210. package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +194 -0
  211. package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +87 -0
  212. package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +90 -0
  213. package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +136 -0
  214. package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +163 -0
  215. package/src/superlocalmemory/storage/models.py +4 -0
  216. package/src/superlocalmemory/storage/schema.py +87 -0
  217. package/src/superlocalmemory/storage/schema_v343.py +24 -12
  218. package/src/superlocalmemory/trust/gate.py +49 -8
  219. package/src/superlocalmemory/ui/assets/slm-icon-white.svg +64 -0
  220. package/src/superlocalmemory/ui/assets/slm-icon.svg +36 -0
  221. package/src/superlocalmemory/ui/css/design-system.css +621 -0
  222. package/src/superlocalmemory/ui/css/neural-glass.css +6 -0
  223. package/src/superlocalmemory/ui/css/od-bridge.css +158 -0
  224. package/src/superlocalmemory/ui/favicon.svg +35 -4
  225. package/src/superlocalmemory/ui/index.html +306 -173
  226. package/src/superlocalmemory/ui/js/brain.js +5 -20
  227. package/src/superlocalmemory/ui/js/core.js +47 -31
  228. package/src/superlocalmemory/ui/js/dashboard.js +314 -63
  229. package/src/superlocalmemory/ui/js/event-delegation.js +102 -0
  230. package/src/superlocalmemory/ui/js/knowledge-graph.js +11 -11
  231. package/src/superlocalmemory/ui/js/math-health.js +1 -1
  232. package/src/superlocalmemory/ui/js/memories.js +15 -4
  233. package/src/superlocalmemory/ui/js/memory-chat.js +7 -7
  234. package/src/superlocalmemory/ui/js/ng-entities.js +6 -8
  235. package/src/superlocalmemory/ui/js/ng-ingestion.js +4 -4
  236. package/src/superlocalmemory/ui/js/ng-mesh.js +4 -9
  237. package/src/superlocalmemory/ui/js/ng-shell.js +8 -8
  238. package/src/superlocalmemory/ui/js/ng-skills.js +54 -2
  239. package/src/superlocalmemory/ui/js/od-agents.js +544 -0
  240. package/src/superlocalmemory/ui/js/od-auth-gate.js +257 -0
  241. package/src/superlocalmemory/ui/js/od-backup.js +780 -0
  242. package/src/superlocalmemory/ui/js/od-brain.js +779 -0
  243. package/src/superlocalmemory/ui/js/od-entities.js +579 -0
  244. package/src/superlocalmemory/ui/js/od-graph.js +593 -0
  245. package/src/superlocalmemory/ui/js/od-health.js +539 -0
  246. package/src/superlocalmemory/ui/js/od-mcp.js +508 -0
  247. package/src/superlocalmemory/ui/js/od-memories.js +887 -0
  248. package/src/superlocalmemory/ui/js/od-mesh.js +539 -0
  249. package/src/superlocalmemory/ui/js/od-operations.js +1250 -0
  250. package/src/superlocalmemory/ui/js/od-optimize.js +787 -0
  251. package/src/superlocalmemory/ui/js/od-settings.js +1053 -0
  252. package/src/superlocalmemory/ui/js/od-shell.js +593 -0
  253. package/src/superlocalmemory/ui/js/od-skills.js +573 -0
  254. package/src/superlocalmemory/ui/js/od-team.js +258 -0
  255. package/src/superlocalmemory/ui/js/profiles.js +159 -46
  256. package/src/superlocalmemory/ui/js/settings.js +2 -2
  257. package/src/superlocalmemory/ui/js/timeline.js +34 -5
  258. package/src/superlocalmemory/ui/js/trust-dashboard.js +2 -2
  259. package/src/superlocalmemory/vector/lancedb_backend.py +8 -6
  260. package/src/superlocalmemory/learning/behavioral_listener.py +0 -94
@@ -0,0 +1,257 @@
1
+ // od-auth-gate.js — product-wide login gate (v3.8.0)
2
+ //
3
+ // Personal mode (require_login = false): no gate — the loopback machine owner
4
+ // is trusted, exactly as before. Backward compatible: single-operator users
5
+ // never see a login screen.
6
+ //
7
+ // Company/Enterprise mode (require_login = true):
8
+ // * First run (user_count == 0): a "Create admin" screen. The operator picks
9
+ // the username AND password — SLM ships NO default credentials and never
10
+ // writes a plaintext password to disk (the backend stores an scrypt hash).
11
+ // * Thereafter: a "Sign in" screen unless the caller already holds a valid
12
+ // HttpOnly session cookie (set by POST /api/rbac/login).
13
+ //
14
+ // The gate is UX + attribution only. The daemon independently enforces auth on
15
+ // every sensitive read/mutation server-side, so this screen fails OPEN on a
16
+ // transient status error (never locks the operator out of a working daemon).
17
+ //
18
+ // CSP-safe: no inline handlers, no on*= attributes — every control is wired via
19
+ // addEventListener. All server-supplied text is inserted via textContent.
20
+ //
21
+ // Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar — AGPL-3.0
22
+
23
+ /* global window, document, fetch */
24
+ (function () {
25
+ 'use strict';
26
+
27
+ var OVERLAY_ID = 'slm-auth-gate';
28
+
29
+ // ─── DOM helpers (CSP-safe, XSS-safe) ───────────────────────────────────────
30
+ function elmt(tag, opts) {
31
+ opts = opts || {};
32
+ var e = document.createElement(tag);
33
+ if (opts.cls) e.className = opts.cls;
34
+ if (opts.id) e.id = opts.id;
35
+ if (opts.text != null) e.textContent = String(opts.text);
36
+ if (opts.type) e.type = opts.type;
37
+ if (opts.placeholder) e.placeholder = opts.placeholder;
38
+ if (opts.autocomplete) e.setAttribute('autocomplete', opts.autocomplete);
39
+ if (opts.style) e.style.cssText = opts.style;
40
+ if (opts.attrs) {
41
+ Object.keys(opts.attrs).forEach(function (k) { e.setAttribute(k, opts.attrs[k]); });
42
+ }
43
+ return e;
44
+ }
45
+
46
+ function overlay() {
47
+ var d = document.getElementById(OVERLAY_ID);
48
+ if (d) return d;
49
+ d = elmt('div', {
50
+ id: OVERLAY_ID,
51
+ attrs: { role: 'dialog', 'aria-modal': 'true', 'aria-label': 'Sign in' },
52
+ style: [
53
+ 'position:fixed', 'inset:0', 'z-index:100000',
54
+ 'display:flex', 'align-items:center', 'justify-content:center',
55
+ 'background:#0b0d10', 'background:var(--bg,#0b0d10)',
56
+ 'padding:24px',
57
+ ].join(';'),
58
+ });
59
+ document.body.appendChild(d);
60
+ return d;
61
+ }
62
+
63
+ function removeOverlay() {
64
+ var d = document.getElementById(OVERLAY_ID);
65
+ if (d && d.parentNode) d.parentNode.removeChild(d);
66
+ }
67
+
68
+ function card() {
69
+ var c = elmt('div', {
70
+ style: [
71
+ 'width:100%', 'max-width:380px',
72
+ 'background:#16181d', 'background:var(--card,#16181d)',
73
+ 'border:1px solid rgba(255,255,255,0.08)', 'border-radius:14px',
74
+ 'padding:28px', 'box-shadow:0 12px 40px rgba(0,0,0,0.45)',
75
+ 'color:#e8eaed', 'color:var(--text,#e8eaed)',
76
+ 'font-family:Inter,system-ui,sans-serif',
77
+ ].join(';'),
78
+ });
79
+ var brand = elmt('div', { style: 'display:flex;align-items:center;gap:10px;margin-bottom:18px' });
80
+ var logo = elmt('img', { attrs: { src: 'static/assets/slm-icon.svg', alt: '', width: '28', height: '28' } });
81
+ var name = elmt('div');
82
+ name.appendChild(elmt('div', { text: 'SuperLocalMemory', style: 'font-weight:650;font-size:15px' }));
83
+ name.appendChild(elmt('div', { text: 'by Qualixar', style: 'font-size:12px;opacity:0.6' }));
84
+ brand.appendChild(logo);
85
+ brand.appendChild(name);
86
+ c.appendChild(brand);
87
+ return c;
88
+ }
89
+
90
+ function field(labelText, inputOpts) {
91
+ var wrap = elmt('div', { style: 'margin-bottom:12px' });
92
+ var lbl = elmt('label', { text: labelText, style: 'display:block;font-size:12px;opacity:0.75;margin-bottom:4px' });
93
+ var input = elmt('input', inputOpts);
94
+ input.style.cssText = [
95
+ 'width:100%', 'box-sizing:border-box', 'padding:9px 11px',
96
+ 'background:rgba(255,255,255,0.05)', 'border:1px solid rgba(255,255,255,0.12)',
97
+ 'border-radius:8px', 'color:inherit', 'font-size:14px',
98
+ ].join(';');
99
+ if (inputOpts && inputOpts.id) lbl.setAttribute('for', inputOpts.id);
100
+ wrap.appendChild(lbl);
101
+ wrap.appendChild(input);
102
+ return wrap;
103
+ }
104
+
105
+ function primaryBtn(text) {
106
+ var b = elmt('button', { text: text, type: 'button' });
107
+ b.style.cssText = [
108
+ 'width:100%', 'padding:10px', 'margin-top:6px', 'border:none',
109
+ 'border-radius:8px', 'background:#6c5ce7', 'background:var(--violet,#6c5ce7)',
110
+ 'color:#fff', 'font-size:14px', 'font-weight:600', 'cursor:pointer',
111
+ ].join(';');
112
+ return b;
113
+ }
114
+
115
+ function msgLine() {
116
+ return elmt('p', { style: 'font-size:12.5px;margin:10px 0 0;min-height:16px;color:#ff7b7b' });
117
+ }
118
+
119
+ // ─── API (uses the globally patched fetch: X-Install-Token on POST) ──────────
120
+ function api(url, method, body) {
121
+ var init = { method: method || 'GET', credentials: 'same-origin' };
122
+ if (body) {
123
+ init.headers = { 'Content-Type': 'application/json' };
124
+ init.body = JSON.stringify(body);
125
+ }
126
+ return fetch(url, init).then(function (r) {
127
+ return r.json().catch(function () { return {}; }).then(function (d) {
128
+ return { ok: r.ok, status: r.status, data: d };
129
+ });
130
+ });
131
+ }
132
+
133
+ // ─── Screens ────────────────────────────────────────────────────────────────
134
+ function showSpinner() {
135
+ var o = overlay();
136
+ o.textContent = '';
137
+ var c = card();
138
+ c.appendChild(elmt('p', { text: 'Checking access…', style: 'opacity:0.7;font-size:13px;margin:0' }));
139
+ o.appendChild(c);
140
+ }
141
+
142
+ function showLogin(prefillMsg) {
143
+ var o = overlay();
144
+ o.textContent = '';
145
+ var c = card();
146
+ c.appendChild(elmt('h2', { text: 'Sign in', style: 'font-size:18px;margin:0 0 6px' }));
147
+ c.appendChild(elmt('p', {
148
+ text: 'Use the admin username and password created when this workspace '
149
+ + 'was set up. SuperLocalMemory has no default password. Forgot it? '
150
+ + 'An admin can reset it from Settings › Access.',
151
+ style: 'font-size:12.5px;opacity:0.7;margin:0 0 16px',
152
+ }));
153
+ var user = { id: 'slm-gate-user', placeholder: 'Username', autocomplete: 'username' };
154
+ var pass = { id: 'slm-gate-pass', type: 'password', placeholder: 'Password', autocomplete: 'current-password' };
155
+ c.appendChild(field('Username', user));
156
+ c.appendChild(field('Password', pass));
157
+ var btn = primaryBtn('Sign in');
158
+ var msg = msgLine();
159
+ if (prefillMsg) { msg.style.color = '#7bd88f'; msg.textContent = prefillMsg; }
160
+ c.appendChild(btn);
161
+ c.appendChild(msg);
162
+ o.appendChild(c);
163
+
164
+ function submit() {
165
+ var u = (document.getElementById('slm-gate-user') || {}).value || '';
166
+ var p = (document.getElementById('slm-gate-pass') || {}).value || '';
167
+ if (!u || !p) { msg.style.color = '#ff7b7b'; msg.textContent = 'Enter your username and password.'; return; }
168
+ btn.disabled = true;
169
+ api('/api/rbac/login', 'POST', { username: u, password: p }).then(function (r) {
170
+ btn.disabled = false;
171
+ if (r.ok) { window.location.reload(); return; }
172
+ msg.style.color = '#ff7b7b';
173
+ msg.textContent = (r.data && r.data.detail) || 'Sign in failed.';
174
+ }).catch(function () {
175
+ btn.disabled = false;
176
+ msg.style.color = '#ff7b7b';
177
+ msg.textContent = 'Could not reach the daemon.';
178
+ });
179
+ }
180
+ btn.addEventListener('click', submit);
181
+ c.addEventListener('keydown', function (e) { if (e.key === 'Enter') submit(); });
182
+ }
183
+
184
+ function showCreateAdmin() {
185
+ var o = overlay();
186
+ o.textContent = '';
187
+ var c = card();
188
+ c.appendChild(elmt('h2', { text: 'Welcome — create your admin account', style: 'font-size:18px;margin:0 0 6px' }));
189
+ c.appendChild(elmt('p', {
190
+ text: 'This is the first time SuperLocalMemory has opened on this '
191
+ + 'workspace. Choose an admin username and password right here in your '
192
+ + 'browser — no config files or terminal needed. For your security '
193
+ + 'there is no default login. You can add people or change this later '
194
+ + 'under Settings › Access.',
195
+ style: 'font-size:12.5px;opacity:0.7;margin:0 0 16px',
196
+ }));
197
+ c.appendChild(field('Username', { id: 'slm-gate-nu', placeholder: 'e.g. admin', autocomplete: 'username' }));
198
+ c.appendChild(field('Display name (optional)', { id: 'slm-gate-nn', placeholder: 'Full name', autocomplete: 'name' }));
199
+ c.appendChild(field('Password (min 8 characters)', { id: 'slm-gate-np', type: 'password', placeholder: 'Password', autocomplete: 'new-password' }));
200
+ c.appendChild(field('Confirm password', { id: 'slm-gate-nc', type: 'password', placeholder: 'Re-enter password', autocomplete: 'new-password' }));
201
+ var btn = primaryBtn('Create admin & sign in');
202
+ var msg = msgLine();
203
+ c.appendChild(btn);
204
+ c.appendChild(msg);
205
+ o.appendChild(c);
206
+
207
+ function submit() {
208
+ var u = (document.getElementById('slm-gate-nu') || {}).value || '';
209
+ var n = (document.getElementById('slm-gate-nn') || {}).value || '';
210
+ var p = (document.getElementById('slm-gate-np') || {}).value || '';
211
+ var cc = (document.getElementById('slm-gate-nc') || {}).value || '';
212
+ if (!u) { msg.textContent = 'Choose a username.'; return; }
213
+ if (p.length < 8) { msg.textContent = 'Password must be at least 8 characters.'; return; }
214
+ if (p !== cc) { msg.textContent = 'Passwords do not match.'; return; }
215
+ btn.disabled = true;
216
+ api('/api/rbac/users', 'POST', { username: u, password: p, display_name: n, role: 'admin' })
217
+ .then(function (r) {
218
+ if (!r.ok) {
219
+ btn.disabled = false;
220
+ msg.style.color = '#ff7b7b';
221
+ msg.textContent = (r.data && r.data.detail) || 'Could not create the admin account.';
222
+ return;
223
+ }
224
+ // Auto sign-in so the operator lands straight in the dashboard.
225
+ return api('/api/rbac/login', 'POST', { username: u, password: p }).then(function () {
226
+ window.location.reload();
227
+ });
228
+ }).catch(function () {
229
+ btn.disabled = false;
230
+ msg.style.color = '#ff7b7b';
231
+ msg.textContent = 'Could not reach the daemon.';
232
+ });
233
+ }
234
+ btn.addEventListener('click', submit);
235
+ c.addEventListener('keydown', function (e) { if (e.key === 'Enter') submit(); });
236
+ }
237
+
238
+ // ─── Decision flow ──────────────────────────────────────────────────────────
239
+ function decide() {
240
+ api('/api/rbac/status', 'GET').then(function (r) {
241
+ var s = (r && r.data) || {};
242
+ if (!r.ok || !s.require_login) { removeOverlay(); return; } // Personal mode
243
+ if ((s.user_count || 0) === 0) { showCreateAdmin(); return; } // First run
244
+ api('/api/rbac/whoami', 'GET').then(function (w) {
245
+ var who = (w && w.data) || {};
246
+ if (w.ok && who.kind === 'user') { removeOverlay(); return; } // Already signed in
247
+ showLogin();
248
+ }).catch(function () { removeOverlay(); }); // Fail open
249
+ }).catch(function () { removeOverlay(); }); // Fail open
250
+ }
251
+
252
+ // Paint the overlay immediately (this script is at end of <body>, so body
253
+ // exists) to avoid flashing dashboard content to unauthenticated users in
254
+ // company mode, then resolve the real state.
255
+ showSpinner();
256
+ decide();
257
+ }());