ltcai 4.0.1 → 4.2.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 (192) hide show
  1. package/README.md +33 -24
  2. package/desktop/electron/main.cjs +44 -0
  3. package/docs/CHANGELOG.md +84 -0
  4. package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +65 -0
  5. package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +70 -0
  6. package/docs/V4_1_VALIDATION_REPORT.md +47 -0
  7. package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +97 -0
  8. package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +91 -0
  9. package/docs/V4_2_VALIDATION_REPORT.md +89 -0
  10. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +31 -26
  11. package/frontend/index.html +24 -0
  12. package/frontend/openapi.json +14436 -0
  13. package/frontend/src/App.tsx +184 -0
  14. package/frontend/src/api/client.ts +320 -0
  15. package/frontend/src/api/openapi.ts +16921 -0
  16. package/frontend/src/components/primitives.tsx +204 -0
  17. package/frontend/src/components/ui/badge.tsx +27 -0
  18. package/frontend/src/components/ui/button.tsx +37 -0
  19. package/frontend/src/components/ui/card.tsx +22 -0
  20. package/frontend/src/components/ui/input.tsx +16 -0
  21. package/frontend/src/components/ui/textarea.tsx +16 -0
  22. package/frontend/src/lib/utils.ts +33 -0
  23. package/frontend/src/main.tsx +23 -0
  24. package/frontend/src/pages/Act.tsx +245 -0
  25. package/frontend/src/pages/Ask.tsx +200 -0
  26. package/frontend/src/pages/Brain.tsx +267 -0
  27. package/frontend/src/pages/Capture.tsx +158 -0
  28. package/frontend/src/pages/Library.tsx +187 -0
  29. package/frontend/src/pages/System.tsx +378 -0
  30. package/frontend/src/routes.ts +85 -0
  31. package/frontend/src/store/appStore.ts +54 -0
  32. package/frontend/src/styles.css +107 -0
  33. package/kg_schema.py +1 -1
  34. package/knowledge_graph.py +4 -4
  35. package/lattice_brain/__init__.py +70 -0
  36. package/lattice_brain/_kg_common.py +1 -0
  37. package/lattice_brain/archive.py +133 -0
  38. package/lattice_brain/context.py +3 -0
  39. package/lattice_brain/conversations.py +3 -0
  40. package/lattice_brain/core.py +82 -0
  41. package/lattice_brain/discovery.py +1 -0
  42. package/lattice_brain/documents.py +1 -0
  43. package/lattice_brain/embeddings.py +82 -0
  44. package/lattice_brain/identity.py +13 -0
  45. package/lattice_brain/ingest.py +1 -0
  46. package/lattice_brain/memory.py +3 -0
  47. package/lattice_brain/network.py +1 -0
  48. package/lattice_brain/projection.py +1 -0
  49. package/lattice_brain/provenance.py +1 -0
  50. package/lattice_brain/retrieval.py +1 -0
  51. package/lattice_brain/schema.py +1 -0
  52. package/lattice_brain/storage/__init__.py +22 -0
  53. package/lattice_brain/storage/base.py +72 -0
  54. package/lattice_brain/storage/docker.py +105 -0
  55. package/lattice_brain/storage/factory.py +31 -0
  56. package/lattice_brain/storage/migration.py +190 -0
  57. package/lattice_brain/storage/postgres.py +123 -0
  58. package/lattice_brain/storage/sqlite.py +128 -0
  59. package/lattice_brain/store.py +3 -0
  60. package/lattice_brain/write_master.py +1 -0
  61. package/latticeai/__init__.py +1 -1
  62. package/latticeai/api/portability.py +69 -0
  63. package/latticeai/api/setup.py +5 -4
  64. package/latticeai/api/static_routes.py +4 -4
  65. package/latticeai/app_factory.py +17 -10
  66. package/latticeai/brain/__init__.py +6 -6
  67. package/latticeai/brain/_kg_common.py +1 -1
  68. package/latticeai/brain/network.py +1 -1
  69. package/latticeai/brain/retrieval.py +15 -0
  70. package/latticeai/brain/store.py +22 -6
  71. package/latticeai/core/config.py +8 -0
  72. package/latticeai/core/marketplace.py +1 -1
  73. package/latticeai/core/multi_agent.py +1 -1
  74. package/latticeai/core/workspace_os.py +1 -1
  75. package/latticeai/services/kg_portability.py +82 -1
  76. package/package.json +55 -15
  77. package/scripts/build_frontend_assets.mjs +38 -0
  78. package/scripts/bump_version.py +4 -1
  79. package/scripts/export_openapi.py +31 -0
  80. package/scripts/lint_frontend.mjs +91 -0
  81. package/scripts/migrate_brain_storage.py +53 -0
  82. package/scripts/run_python.mjs +47 -0
  83. package/scripts/wheel_smoke.py +3 -0
  84. package/src-tauri/Cargo.lock +4833 -0
  85. package/src-tauri/Cargo.toml +19 -0
  86. package/src-tauri/build.rs +3 -0
  87. package/src-tauri/capabilities/default.json +7 -0
  88. package/src-tauri/src/main.rs +78 -0
  89. package/src-tauri/tauri.conf.json +39 -0
  90. package/static/app/asset-manifest.json +32 -0
  91. package/static/app/assets/core-CwxXejkd.js +2 -0
  92. package/static/app/assets/core-CwxXejkd.js.map +1 -0
  93. package/static/app/assets/index-CDjiH_se.css +2 -0
  94. package/static/app/assets/index-C_HAkbAg.js +333 -0
  95. package/static/app/assets/index-C_HAkbAg.js.map +1 -0
  96. package/static/app/index.html +25 -0
  97. package/static/manifest.json +2 -2
  98. package/static/sw.js +4 -4
  99. package/scripts/build_v3_assets.mjs +0 -170
  100. package/scripts/lint_v3.mjs +0 -120
  101. package/static/v3/asset-manifest.json +0 -63
  102. package/static/v3/css/lattice.base.49deefb5.css +0 -128
  103. package/static/v3/css/lattice.base.css +0 -128
  104. package/static/v3/css/lattice.components.cde18231.css +0 -472
  105. package/static/v3/css/lattice.components.css +0 -472
  106. package/static/v3/css/lattice.shell.29d36d85.css +0 -452
  107. package/static/v3/css/lattice.shell.css +0 -452
  108. package/static/v3/css/lattice.tokens.304cbc40.css +0 -135
  109. package/static/v3/css/lattice.tokens.css +0 -135
  110. package/static/v3/css/lattice.views.0a18b6c5.css +0 -360
  111. package/static/v3/css/lattice.views.css +0 -360
  112. package/static/v3/index.html +0 -68
  113. package/static/v3/js/app.c5c80c46.js +0 -26
  114. package/static/v3/js/app.js +0 -26
  115. package/static/v3/js/core/api.ba0fbf14.js +0 -625
  116. package/static/v3/js/core/api.js +0 -625
  117. package/static/v3/js/core/components.f25b3b93.js +0 -230
  118. package/static/v3/js/core/components.js +0 -230
  119. package/static/v3/js/core/dom.a2773eb0.js +0 -148
  120. package/static/v3/js/core/dom.js +0 -148
  121. package/static/v3/js/core/i18n.880e1fec.js +0 -575
  122. package/static/v3/js/core/i18n.js +0 -575
  123. package/static/v3/js/core/router.584570f2.js +0 -37
  124. package/static/v3/js/core/router.js +0 -37
  125. package/static/v3/js/core/routes.37522821.js +0 -101
  126. package/static/v3/js/core/routes.js +0 -101
  127. package/static/v3/js/core/shell.e3f6bbfa.js +0 -420
  128. package/static/v3/js/core/shell.js +0 -420
  129. package/static/v3/js/core/store.7b2aa044.js +0 -123
  130. package/static/v3/js/core/store.js +0 -123
  131. package/static/v3/js/views/account.eff40715.js +0 -143
  132. package/static/v3/js/views/account.js +0 -143
  133. package/static/v3/js/views/activity.0d271ef9.js +0 -67
  134. package/static/v3/js/views/activity.js +0 -67
  135. package/static/v3/js/views/admin-audit.660a1fb1.js +0 -185
  136. package/static/v3/js/views/admin-audit.js +0 -185
  137. package/static/v3/js/views/admin-permissions.a7ae5f09.js +0 -177
  138. package/static/v3/js/views/admin-permissions.js +0 -177
  139. package/static/v3/js/views/admin-policies.3658fd86.js +0 -102
  140. package/static/v3/js/views/admin-policies.js +0 -102
  141. package/static/v3/js/views/admin-private-vpc.7d342d36.js +0 -135
  142. package/static/v3/js/views/admin-private-vpc.js +0 -135
  143. package/static/v3/js/views/admin-security.07c66b72.js +0 -180
  144. package/static/v3/js/views/admin-security.js +0 -180
  145. package/static/v3/js/views/admin-users.f7ac7b43.js +0 -166
  146. package/static/v3/js/views/admin-users.js +0 -166
  147. package/static/v3/js/views/agents.17c5288d.js +0 -564
  148. package/static/v3/js/views/agents.js +0 -564
  149. package/static/v3/js/views/chat.e250e2cc.js +0 -624
  150. package/static/v3/js/views/chat.js +0 -624
  151. package/static/v3/js/views/files.adad14c1.js +0 -365
  152. package/static/v3/js/views/files.js +0 -365
  153. package/static/v3/js/views/graph-canvas.17c15d65.js +0 -509
  154. package/static/v3/js/views/graph-canvas.js +0 -509
  155. package/static/v3/js/views/home.24f8b8ae.js +0 -200
  156. package/static/v3/js/views/home.js +0 -200
  157. package/static/v3/js/views/hooks.37895880.js +0 -220
  158. package/static/v3/js/views/hooks.js +0 -220
  159. package/static/v3/js/views/hybrid-search.2fb63ed9.js +0 -194
  160. package/static/v3/js/views/hybrid-search.js +0 -194
  161. package/static/v3/js/views/knowledge-graph.4d09c537.js +0 -529
  162. package/static/v3/js/views/knowledge-graph.js +0 -529
  163. package/static/v3/js/views/marketplace.ab0583d4.js +0 -141
  164. package/static/v3/js/views/marketplace.js +0 -141
  165. package/static/v3/js/views/mcp.99b5c6a7.js +0 -114
  166. package/static/v3/js/views/mcp.js +0 -114
  167. package/static/v3/js/views/memory.4ebdf474.js +0 -147
  168. package/static/v3/js/views/memory.js +0 -147
  169. package/static/v3/js/views/models.a1ffa147.js +0 -256
  170. package/static/v3/js/views/models.js +0 -256
  171. package/static/v3/js/views/my-computer.d9d9ae1c.js +0 -463
  172. package/static/v3/js/views/my-computer.js +0 -463
  173. package/static/v3/js/views/network.52a4f181.js +0 -97
  174. package/static/v3/js/views/network.js +0 -97
  175. package/static/v3/js/views/pipeline.c522f1ce.js +0 -157
  176. package/static/v3/js/views/pipeline.js +0 -157
  177. package/static/v3/js/views/planning.4876fd77.js +0 -174
  178. package/static/v3/js/views/planning.js +0 -174
  179. package/static/v3/js/views/runs.b63b2afa.js +0 -144
  180. package/static/v3/js/views/runs.js +0 -144
  181. package/static/v3/js/views/settings.b7140634.js +0 -317
  182. package/static/v3/js/views/settings.js +0 -317
  183. package/static/v3/js/views/skills.c6c2f965.js +0 -109
  184. package/static/v3/js/views/skills.js +0 -109
  185. package/static/v3/js/views/snapshots.6f5db095.js +0 -135
  186. package/static/v3/js/views/snapshots.js +0 -135
  187. package/static/v3/js/views/tools.e4f11276.js +0 -108
  188. package/static/v3/js/views/tools.js +0 -108
  189. package/static/v3/js/views/workflows.7752225a.js +0 -213
  190. package/static/v3/js/views/workflows.js +0 -213
  191. package/static/v3/js/views/workspace-admin.c466029b.js +0 -156
  192. package/static/v3/js/views/workspace-admin.js +0 -156
@@ -1,101 +0,0 @@
1
- /* ============================================================================
2
- * Lattice AI v3 — Information architecture (single source of truth)
3
- *
4
- * One declarative table drives the nav rail, command palette, router,
5
- * breadcrumbs, and lazy view loading. Labels are translated at render time.
6
- * ========================================================================== */
7
-
8
- import { t } from "./i18n.880e1fec.js";
9
-
10
- export const MODE_RANK = { basic: 0, advanced: 1, admin: 2 };
11
-
12
- export const GROUPS = [
13
- { id: "brain", labelKey: "group.brain" },
14
- { id: "ask", labelKey: "group.ask" },
15
- { id: "capture", labelKey: "group.capture" },
16
- { id: "act", labelKey: "group.act" },
17
- { id: "library", labelKey: "group.library" },
18
- { id: "system", labelKey: "group.system" },
19
- { id: "admin", labelKey: "group.admin", adminOnly: true },
20
- ];
21
-
22
- function r(key, labelKey, icon, group, minMode, view, titleKey, descKey, extra = {}) {
23
- return { key, labelKey, icon, group, minMode, view, titleKey, descKey, ...extra };
24
- }
25
-
26
- export const ROUTES = [
27
- r("home", "route.home.label", "layout-dashboard", "system", "basic", "home", "route.home.title", "route.home.desc"),
28
- r("account", "route.account.label", "user-circle", "system", "basic", "account", "route.account.title", "route.account.desc"),
29
- r("chat", "route.chat.label", "message-2", "ask", "basic", "chat", "route.chat.title", "route.chat.desc"),
30
- r("files", "route.files.label", "folders", "capture", "basic", "files", "route.files.title", "route.files.desc"),
31
-
32
- r("hybrid-search", "route.hybridSearch.label", "arrows-join", "brain", "basic", "hybrid-search", "route.hybridSearch.title", "route.hybridSearch.desc"),
33
- r("knowledge-graph", "route.knowledgeGraph.label", "chart-dots-3", "brain", "basic", "knowledge-graph", "route.knowledgeGraph.title", "route.knowledgeGraph.desc"),
34
- r("memory", "route.memory.label", "brain", "brain", "basic", "memory", "route.memory.title", "route.memory.desc"),
35
-
36
- r("models", "route.models.label", "cpu", "library", "basic", "models", "route.models.title", "route.models.desc"),
37
- r("agents", "route.agents.label", "robot", "act", "advanced", "agents", "route.agents.title", "route.agents.desc"),
38
- r("runs", "route.runs.label", "progress-check", "act", "advanced", "runs", "route.runs.title", "route.runs.desc"),
39
- r("workflows", "route.workflows.label", "sitemap", "act", "advanced", "workflows", "route.workflows.title", "route.workflows.desc"),
40
-
41
- r("skills", "route.skills.label", "puzzle", "library", "advanced", "skills", "route.skills.title", "route.skills.desc"),
42
- r("hooks", "route.hooks.label", "webhook", "act", "advanced", "hooks", "route.hooks.title", "route.hooks.desc"),
43
- r("mcp", "route.mcp.label", "plug-connected", "library", "advanced", "mcp", "route.mcp.title", "route.mcp.desc"),
44
-
45
- r("workspace-admin", "route.workspaceAdmin.label", "building-community", "system", "basic", "workspace-admin", "route.workspaceAdmin.title", "route.workspaceAdmin.desc"),
46
- r("snapshots", "route.snapshots.label", "history", "system", "basic", "snapshots", "route.snapshots.title", "route.snapshots.desc"),
47
- r("activity", "route.activity.label", "activity", "system", "basic", "activity", "route.activity.title", "route.activity.desc"),
48
- r("network", "route.network.label", "network", "system", "advanced", "network", "route.network.title", "route.network.desc"),
49
- r("settings", "route.settings.label", "settings", "system", "basic", "settings", "route.settings.title", "route.settings.desc"),
50
-
51
- r("pipeline", "route.pipeline.label", "git-branch", "capture", "advanced", "pipeline", "route.pipeline.title", "route.pipeline.desc", { hidden: true }),
52
- r("planning", "route.planning.label", "target-arrow", "act", "advanced", "planning", "route.planning.title", "route.planning.desc", { hidden: true }),
53
- r("my-computer", "route.myComputer.label", "device-desktop-analytics", "system", "advanced", "my-computer", "route.myComputer.title", "route.myComputer.desc", { hidden: true }),
54
- r("marketplace", "route.marketplace.label", "building-store", "library", "advanced", "marketplace", "route.marketplace.title", "route.marketplace.desc", { hidden: true }),
55
- r("tools", "route.tools.label", "tools", "act", "advanced", "tools", "route.tools.title", "route.tools.desc", { hidden: true }),
56
-
57
- r("admin/users", "route.adminUsers.label", "users", "admin", "admin", "admin-users", "route.adminUsers.title", "route.adminUsers.desc", { admin: true }),
58
- r("admin/permissions", "route.adminPermissions.label", "key", "admin", "admin", "admin-permissions", "route.adminPermissions.title", "route.adminPermissions.desc", { admin: true }),
59
- r("admin/audit", "route.adminAudit.label", "report-search", "admin", "admin", "admin-audit", "route.adminAudit.title", "route.adminAudit.desc", { admin: true }),
60
- r("admin/security", "route.adminSecurity.label", "shield-check", "admin", "admin", "admin-security", "route.adminSecurity.title", "route.adminSecurity.desc", { admin: true }),
61
- r("admin/policies", "route.adminPolicies.label", "file-certificate", "admin", "admin", "admin-policies", "route.adminPolicies.title", "route.adminPolicies.desc", { admin: true }),
62
- r("admin/private-vpc", "route.adminVpc.label", "cloud-lock", "admin", "admin", "admin-private-vpc", "route.adminVpc.title", "route.adminVpc.desc", { admin: true }),
63
- ];
64
-
65
- export const ROUTE_BY_KEY = Object.fromEntries(ROUTES.map((route) => [route.key, route]));
66
-
67
- export function groupLabel(group) {
68
- return t(group.labelKey || group.id);
69
- }
70
-
71
- export function localizeRoute(route) {
72
- if (!route) return route;
73
- return {
74
- ...route,
75
- label: t(route.labelKey),
76
- title: t(route.titleKey || route.labelKey),
77
- desc: t(route.descKey || ""),
78
- };
79
- }
80
-
81
- export function visibleRoutes(mode) {
82
- const rank = MODE_RANK[mode] ?? 0;
83
- return ROUTES.filter((route) => {
84
- if (route.hidden) return false;
85
- if (route.admin) return mode === "admin";
86
- return (MODE_RANK[route.minMode] ?? 0) <= rank;
87
- }).map(localizeRoute);
88
- }
89
-
90
- const cache = new Map();
91
- function assetUrl(key, fallback) {
92
- const manifest = window.__LT_ASSET_MANIFEST__;
93
- return (manifest && manifest.assets && manifest.assets[key]) || fallback;
94
- }
95
-
96
- export async function loadView(view) {
97
- if (cache.has(view)) return cache.get(view);
98
- const mod = await import(assetUrl(`static/v3/js/views/${view}.js`, `../views/${view}.js`));
99
- cache.set(view, mod);
100
- return mod;
101
- }
@@ -1,101 +0,0 @@
1
- /* ============================================================================
2
- * Lattice AI v3 — Information architecture (single source of truth)
3
- *
4
- * One declarative table drives the nav rail, command palette, router,
5
- * breadcrumbs, and lazy view loading. Labels are translated at render time.
6
- * ========================================================================== */
7
-
8
- import { t } from "./i18n.js";
9
-
10
- export const MODE_RANK = { basic: 0, advanced: 1, admin: 2 };
11
-
12
- export const GROUPS = [
13
- { id: "brain", labelKey: "group.brain" },
14
- { id: "ask", labelKey: "group.ask" },
15
- { id: "capture", labelKey: "group.capture" },
16
- { id: "act", labelKey: "group.act" },
17
- { id: "library", labelKey: "group.library" },
18
- { id: "system", labelKey: "group.system" },
19
- { id: "admin", labelKey: "group.admin", adminOnly: true },
20
- ];
21
-
22
- function r(key, labelKey, icon, group, minMode, view, titleKey, descKey, extra = {}) {
23
- return { key, labelKey, icon, group, minMode, view, titleKey, descKey, ...extra };
24
- }
25
-
26
- export const ROUTES = [
27
- r("home", "route.home.label", "layout-dashboard", "system", "basic", "home", "route.home.title", "route.home.desc"),
28
- r("account", "route.account.label", "user-circle", "system", "basic", "account", "route.account.title", "route.account.desc"),
29
- r("chat", "route.chat.label", "message-2", "ask", "basic", "chat", "route.chat.title", "route.chat.desc"),
30
- r("files", "route.files.label", "folders", "capture", "basic", "files", "route.files.title", "route.files.desc"),
31
-
32
- r("hybrid-search", "route.hybridSearch.label", "arrows-join", "brain", "basic", "hybrid-search", "route.hybridSearch.title", "route.hybridSearch.desc"),
33
- r("knowledge-graph", "route.knowledgeGraph.label", "chart-dots-3", "brain", "basic", "knowledge-graph", "route.knowledgeGraph.title", "route.knowledgeGraph.desc"),
34
- r("memory", "route.memory.label", "brain", "brain", "basic", "memory", "route.memory.title", "route.memory.desc"),
35
-
36
- r("models", "route.models.label", "cpu", "library", "basic", "models", "route.models.title", "route.models.desc"),
37
- r("agents", "route.agents.label", "robot", "act", "advanced", "agents", "route.agents.title", "route.agents.desc"),
38
- r("runs", "route.runs.label", "progress-check", "act", "advanced", "runs", "route.runs.title", "route.runs.desc"),
39
- r("workflows", "route.workflows.label", "sitemap", "act", "advanced", "workflows", "route.workflows.title", "route.workflows.desc"),
40
-
41
- r("skills", "route.skills.label", "puzzle", "library", "advanced", "skills", "route.skills.title", "route.skills.desc"),
42
- r("hooks", "route.hooks.label", "webhook", "act", "advanced", "hooks", "route.hooks.title", "route.hooks.desc"),
43
- r("mcp", "route.mcp.label", "plug-connected", "library", "advanced", "mcp", "route.mcp.title", "route.mcp.desc"),
44
-
45
- r("workspace-admin", "route.workspaceAdmin.label", "building-community", "system", "basic", "workspace-admin", "route.workspaceAdmin.title", "route.workspaceAdmin.desc"),
46
- r("snapshots", "route.snapshots.label", "history", "system", "basic", "snapshots", "route.snapshots.title", "route.snapshots.desc"),
47
- r("activity", "route.activity.label", "activity", "system", "basic", "activity", "route.activity.title", "route.activity.desc"),
48
- r("network", "route.network.label", "network", "system", "advanced", "network", "route.network.title", "route.network.desc"),
49
- r("settings", "route.settings.label", "settings", "system", "basic", "settings", "route.settings.title", "route.settings.desc"),
50
-
51
- r("pipeline", "route.pipeline.label", "git-branch", "capture", "advanced", "pipeline", "route.pipeline.title", "route.pipeline.desc", { hidden: true }),
52
- r("planning", "route.planning.label", "target-arrow", "act", "advanced", "planning", "route.planning.title", "route.planning.desc", { hidden: true }),
53
- r("my-computer", "route.myComputer.label", "device-desktop-analytics", "system", "advanced", "my-computer", "route.myComputer.title", "route.myComputer.desc", { hidden: true }),
54
- r("marketplace", "route.marketplace.label", "building-store", "library", "advanced", "marketplace", "route.marketplace.title", "route.marketplace.desc", { hidden: true }),
55
- r("tools", "route.tools.label", "tools", "act", "advanced", "tools", "route.tools.title", "route.tools.desc", { hidden: true }),
56
-
57
- r("admin/users", "route.adminUsers.label", "users", "admin", "admin", "admin-users", "route.adminUsers.title", "route.adminUsers.desc", { admin: true }),
58
- r("admin/permissions", "route.adminPermissions.label", "key", "admin", "admin", "admin-permissions", "route.adminPermissions.title", "route.adminPermissions.desc", { admin: true }),
59
- r("admin/audit", "route.adminAudit.label", "report-search", "admin", "admin", "admin-audit", "route.adminAudit.title", "route.adminAudit.desc", { admin: true }),
60
- r("admin/security", "route.adminSecurity.label", "shield-check", "admin", "admin", "admin-security", "route.adminSecurity.title", "route.adminSecurity.desc", { admin: true }),
61
- r("admin/policies", "route.adminPolicies.label", "file-certificate", "admin", "admin", "admin-policies", "route.adminPolicies.title", "route.adminPolicies.desc", { admin: true }),
62
- r("admin/private-vpc", "route.adminVpc.label", "cloud-lock", "admin", "admin", "admin-private-vpc", "route.adminVpc.title", "route.adminVpc.desc", { admin: true }),
63
- ];
64
-
65
- export const ROUTE_BY_KEY = Object.fromEntries(ROUTES.map((route) => [route.key, route]));
66
-
67
- export function groupLabel(group) {
68
- return t(group.labelKey || group.id);
69
- }
70
-
71
- export function localizeRoute(route) {
72
- if (!route) return route;
73
- return {
74
- ...route,
75
- label: t(route.labelKey),
76
- title: t(route.titleKey || route.labelKey),
77
- desc: t(route.descKey || ""),
78
- };
79
- }
80
-
81
- export function visibleRoutes(mode) {
82
- const rank = MODE_RANK[mode] ?? 0;
83
- return ROUTES.filter((route) => {
84
- if (route.hidden) return false;
85
- if (route.admin) return mode === "admin";
86
- return (MODE_RANK[route.minMode] ?? 0) <= rank;
87
- }).map(localizeRoute);
88
- }
89
-
90
- const cache = new Map();
91
- function assetUrl(key, fallback) {
92
- const manifest = window.__LT_ASSET_MANIFEST__;
93
- return (manifest && manifest.assets && manifest.assets[key]) || fallback;
94
- }
95
-
96
- export async function loadView(view) {
97
- if (cache.has(view)) return cache.get(view);
98
- const mod = await import(assetUrl(`static/v3/js/views/${view}.js`, `../views/${view}.js`));
99
- cache.set(view, mod);
100
- return mod;
101
- }
@@ -1,420 +0,0 @@
1
- /* ============================================================================
2
- * Lattice AI v3 — Application shell
3
- * Builds the persistent chrome (nav rail, topbar, view outlet), wires the
4
- * router, workspace + mode + theme switchers, command palette, and mobile
5
- * drawer. Renders views by lazy-loading their module and calling render(ctx).
6
- * ========================================================================== */
7
-
8
- import { h, icon, $, $$ } from "./dom.a2773eb0.js";
9
- import { store } from "./store.7b2aa044.js";
10
- import { api } from "./api.ba0fbf14.js";
11
- import * as c from "./components.f25b3b93.js";
12
- import { createRouter } from "./router.584570f2.js";
13
- import { GROUPS, ROUTE_BY_KEY, MODE_RANK, visibleRoutes, loadView, groupLabel, localizeRoute } from "./routes.37522821.js";
14
- import { setI18nLanguage, t } from "./i18n.880e1fec.js";
15
-
16
- const MODES = [
17
- { key: "basic", labelKey: "shell.mode.basic", icon: "circle" },
18
- { key: "advanced", labelKey: "shell.mode.advanced", icon: "circles" },
19
- { key: "admin", labelKey: "shell.mode.admin", icon: "shield-half" },
20
- ];
21
-
22
- const ctxBase = { h, icon, api, store, c };
23
-
24
- let els = {};
25
- let router;
26
- let currentRoute = null;
27
-
28
- export function boot(rootEl) {
29
- rootEl.classList.add("lt3-app");
30
- rootEl.append(
31
- h("a.lt3-skip", { href: "#lt3-view" }, t("shell.skip")),
32
- h("div.lt3-rail__scrim", { on: { click: closeDrawer } }),
33
- buildRail(),
34
- buildMain(),
35
- );
36
-
37
- cacheEls(rootEl);
38
- store.subscribe(onStateChange);
39
-
40
- router = createRouter({ onRoute: renderRoute, fallback: "knowledge-graph" });
41
- wireGlobalKeys();
42
- router.start();
43
-
44
- // Background: hydrate workspaces, identity, index status.
45
- hydrate();
46
- }
47
-
48
- /* ── Rail ────────────────────────────────────────────────────────────────── */
49
- function buildRail() {
50
- return h("aside.lt3-rail", { id: "lt3-rail", "aria-label": t("shell.primary") },
51
- h("div.lt3-rail__brand",
52
- h("div.lt3-rail__logo", { html: latticeMark() }),
53
- h("div.lt3-rail__word", h("b", "Lattice AI"), h("small", t("shell.privateRuntime"))),
54
- h("button.lt3-iconbtn.lt3-iconbtn--sm.lt3-rail__close", { "aria-label": t("shell.closeMenu"), on: { click: closeDrawer } }, icon("x")),
55
- ),
56
- h("div.lt3-rail__scope", { id: "lt3-scope" }),
57
- h("nav.lt3-rail__nav", { id: "lt3-nav", "aria-label": "Sections" }),
58
- h("div.lt3-rail__foot",
59
- h("div.lt3-rail__status", { id: "lt3-rail-status" }),
60
- h("div.lt3-rail__foot-row",
61
- h("button.lt3-rail__user", { id: "lt3-user", "aria-label": t("shell.account"), on: { click: () => router.navigate("account") } }),
62
- h("button.lt3-iconbtn", { id: "lt3-theme", "aria-label": t("shell.toggleTheme"), title: t("shell.toggleTheme"), on: { click: () => store.toggleTheme() } }, icon("moon")),
63
- ),
64
- ),
65
- );
66
- }
67
-
68
- function renderNav() {
69
- const nav = els.nav;
70
- const mode = store.get().mode;
71
- const routes = visibleRoutes(mode);
72
- nav.replaceChildren();
73
- for (const group of GROUPS) {
74
- const items = routes.filter((r) => r.group === group.id);
75
- if (!items.length) continue;
76
- const groupEl = h("div.lt3-navgroup",
77
- h("div.lt3-navgroup__label", groupLabel(group)),
78
- items.map((r) => navItem(r)),
79
- );
80
- nav.append(groupEl);
81
- }
82
- markActive();
83
- }
84
-
85
- function navItem(route) {
86
- return h("a.lt3-navitem", {
87
- href: "#/" + route.key,
88
- dataset: { key: route.key },
89
- title: route.title || route.label,
90
- on: { click: () => closeDrawer() },
91
- },
92
- icon(route.icon),
93
- h("span.lt3-navitem__copy",
94
- h("span.lt3-navitem__label", route.label),
95
- route.desc ? h("span.lt3-navitem__meta", route.desc) : null,
96
- ),
97
- route.key === "hybrid-search" ? h("span.lt3-navitem__dot", { style: { background: "var(--lt3-pillar-hybrid)" } }) : null,
98
- );
99
- }
100
-
101
- function markActive() {
102
- $$(".lt3-navitem", els.nav).forEach((a) => {
103
- const on = a.dataset.key === (currentRoute && currentRoute.key);
104
- if (on) a.setAttribute("aria-current", "page"); else a.removeAttribute("aria-current");
105
- });
106
- }
107
-
108
- function renderScope() {
109
- const ws = store.activeWorkspace();
110
- els.scope.replaceChildren(
111
- h("button.lt3-scope", { "aria-haspopup": "listbox", on: { click: openScopeMenu } },
112
- h("div.lt3-scope__icon", icon(ws.type === "organization" ? "building-community" : "user")),
113
- h("div.lt3-scope__meta", h("b", ws.name), h("small", `${ws.type} · ${ws.your_role || t("shell.member")}`)),
114
- icon("selector"),
115
- ),
116
- );
117
- }
118
-
119
- function renderUser() {
120
- const u = store.get().user;
121
- const initials = (u.nickname || u.email || "U").slice(0, 2);
122
- els.user.replaceChildren(
123
- h("span.lt3-avatar", initials),
124
- h("div.lt3-rail__user-meta", h("b", u.nickname || u.email || t("shell.you")), h("small", u.role || t("shell.local"))),
125
- );
126
- }
127
-
128
- function updateThemeIcon() {
129
- const dark = document.documentElement.getAttribute("data-lt-theme") === "dark"
130
- || (!store.get().theme && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches);
131
- els.theme.replaceChildren(icon(dark ? "sun" : "moon"));
132
- }
133
-
134
- /* ── Main / topbar ──────────────────────────────────────────────────────── */
135
- function buildMain() {
136
- return h("div.lt3-main",
137
- h("header.lt3-topbar",
138
- h("button.lt3-iconbtn.lt3-topbar__menu", { "aria-label": t("shell.openMenu"), on: { click: openDrawer } }, icon("menu-2")),
139
- h("div.lt3-topbar__crumbs", { id: "lt3-crumbs" }),
140
- h("div.lt3-spacer"),
141
- h("button.lt3-cmd-trigger", { "aria-label": t("shell.searchCommands"), on: { click: openPalette } },
142
- icon("search"), h("span", { id: "lt3-cmd-text" }, t("shell.searchCommands")), h("span.lt3-kbd", "⌘K")),
143
- h("div", { id: "lt3-idxchip" }),
144
- h("div.lt3-mode", { id: "lt3-mode", role: "tablist", "aria-label": t("shell.workspaceMode") },
145
- MODES.map((m) => h("button", {
146
- type: "button", role: "tab", dataset: { mode: m.key },
147
- on: { click: () => store.setMode(m.key) },
148
- }, icon(m.icon), h("span", t(m.labelKey)))),
149
- ),
150
- ),
151
- h("main.lt3-view", { id: "lt3-view", tabindex: "-1" },
152
- h("div.lt3-view__inner", { id: "lt3-outlet" }),
153
- ),
154
- );
155
- }
156
-
157
- function renderMode() {
158
- $$("#lt3-mode button", els.root).forEach((b) => b.dataset.active = String(b.dataset.mode === store.get().mode));
159
- $$("#lt3-mode button", els.root).forEach((b) => {
160
- const mode = MODES.find((m) => m.key === b.dataset.mode);
161
- const span = $("span", b);
162
- if (mode && span) span.textContent = t(mode.labelKey);
163
- });
164
- }
165
-
166
- function renderCrumbs() {
167
- const r = currentRoute;
168
- if (!r) return;
169
- const parts = [h("span.lt3-crumb", store.activeWorkspace().name)];
170
- if (r.group === "admin") parts.push(icon("chevron-right"), h("span.lt3-crumb", t("shell.adminCrumb")));
171
- parts.push(icon("chevron-right"), h("span.lt3-crumb.lt3-crumb--current", r.title || r.label));
172
- els.crumbs.replaceChildren(...parts);
173
- }
174
-
175
- function renderIndexChip() {
176
- els.idxchip.replaceChildren(c.indexChip(store.get().indexStatus));
177
- renderRailStatus();
178
- }
179
-
180
- function renderChromeText() {
181
- const skip = $(".lt3-skip", els.root);
182
- if (skip) skip.textContent = t("shell.skip");
183
- if (els.cmdText) els.cmdText.textContent = t("shell.searchCommands");
184
- const rail = $("#lt3-rail", els.root);
185
- if (rail) rail.setAttribute("aria-label", t("shell.primary"));
186
- const mode = $("#lt3-mode", els.root);
187
- if (mode) mode.setAttribute("aria-label", t("shell.workspaceMode"));
188
- const user = $("#lt3-user", els.root);
189
- if (user) user.setAttribute("aria-label", t("shell.account"));
190
- const theme = $("#lt3-theme", els.root);
191
- if (theme) {
192
- theme.setAttribute("aria-label", t("shell.toggleTheme"));
193
- theme.setAttribute("title", t("shell.toggleTheme"));
194
- }
195
- }
196
-
197
- function renderRailStatus() {
198
- if (!els.railStatus) return;
199
- const status = store.get().indexStatus;
200
- const pipes = status?.pipelines || {};
201
- const keys = ["knowledge_graph", "vector_index", "hybrid"];
202
- const ready = keys.filter((key) => String(pipes[key]?.state || "").toLowerCase() === "ready").length;
203
- const unavailable = !Object.keys(pipes).length;
204
- els.railStatus.replaceChildren(
205
- h("div.lt3-rail__status-top",
206
- h("span.lt3-rail__status-dot", { dataset: { state: unavailable ? "pending" : ready === keys.length ? "ready" : "partial" } }),
207
- h("span", unavailable ? t("shell.indexPending") : t("shell.indexReady", { ready, total: keys.length })),
208
- ),
209
- h("div.lt3-rail__status-sub", unavailable ? t("shell.startBackend") : t("shell.graphVectorHybrid")),
210
- );
211
- }
212
-
213
- /* ── View rendering ─────────────────────────────────────────────────────── */
214
- async function renderRoute({ key, params }) {
215
- let route = localizeRoute(ROUTE_BY_KEY[key] || ROUTE_BY_KEY.home);
216
- // Deep-linking into an admin area surfaces Admin mode so the rail matches.
217
- if (route.admin && store.get().mode !== "admin") store.setMode("admin");
218
- currentRoute = route;
219
- store.setRoute({ key: route.key, params });
220
-
221
- document.title = t("shell.documentTitle", { title: route.title || route.label });
222
- markActive();
223
- renderCrumbs();
224
-
225
- const outlet = els.outlet;
226
- outlet.replaceChildren(c.loading({ lines: 4, block: true }));
227
- els.view.scrollTop = 0;
228
-
229
- try {
230
- const mod = await loadView(route.view);
231
- if (currentRoute !== route) return; // navigated away during load
232
- els.view.classList.toggle("lt3-view--flush", mod.layout === "flush");
233
- const ctx = { ...ctxBase, route, params, navigate: router.navigate, toast: c.toast };
234
- const node = await mod.render(ctx);
235
- if (currentRoute !== route) return;
236
- outlet.replaceChildren(node);
237
- } catch (err) {
238
- console.error("[shell] view render failed:", route.view, err);
239
- outlet.replaceChildren(c.errorState(t("shell.viewFailed", { label: route.label }), () => renderRoute({ key: route.key, params })));
240
- }
241
- }
242
-
243
- function renderCurrent() {
244
- if (currentRoute) renderRoute({ key: currentRoute.key, params: store.get().route.params || {} });
245
- }
246
-
247
- /* ── State reactions ────────────────────────────────────────────────────── */
248
- function onStateChange(_state, change) {
249
- switch (change.type) {
250
- case "mode": renderNav(); renderMode(); renderCurrent(); break;
251
- case "workspace": renderScope(); renderCrumbs(); renderCurrent(); break;
252
- case "workspaces": renderScope(); break;
253
- case "user": renderUser(); break;
254
- case "theme": updateThemeIcon(); break;
255
- case "index": renderIndexChip(); break;
256
- case "language":
257
- setI18nLanguage(store.get().lang);
258
- renderNav(); renderScope(); renderUser(); renderMode(); renderCrumbs(); renderIndexChip(); renderChromeText(); renderCurrent();
259
- break;
260
- }
261
- }
262
-
263
- /* ── Workspace scope menu ───────────────────────────────────────────────── */
264
- function openScopeMenu(ev) {
265
- ev.stopPropagation();
266
- closeMenus();
267
- const rect = ev.currentTarget.getBoundingClientRect();
268
- const list = store.get().workspaces;
269
- const menu = h("div.lt3-menu", { id: "lt3-scope-menu", role: "listbox", style: { top: rect.bottom + 6 + "px", left: rect.left + "px" } },
270
- list.map((w) => h("button.lt3-menu__item", {
271
- role: "option", dataset: { active: String(w.workspace_id === store.get().workspaceId) },
272
- on: { click: () => { store.setWorkspace(w.workspace_id); closeMenus(); } },
273
- },
274
- icon(w.type === "organization" ? "building-community" : "user"),
275
- h("div", h("div", { style: { fontWeight: 600 } }, w.name), h("small.lt3-faint", { style: { textTransform: "capitalize" } }, w.type)),
276
- w.workspace_id === store.get().workspaceId ? icon("check", "") : null,
277
- )),
278
- h("div.lt3-menu__sep"),
279
- h("button.lt3-menu__item", { on: { click: () => { c.toast(t("shell.orgCreationOpens"), "info"); closeMenus(); router.navigate("workspace-admin"); } } },
280
- icon("plus"), t("shell.newOrganization")),
281
- );
282
- document.body.append(menu);
283
- setTimeout(() => document.addEventListener("click", closeMenusOnce, { once: true }), 0);
284
- }
285
- function closeMenus() { $$(".lt3-menu").forEach((m) => m.remove()); }
286
- function closeMenusOnce() { closeMenus(); }
287
-
288
- /* ── Mobile drawer ──────────────────────────────────────────────────────── */
289
- function openDrawer() { els.root.dataset.drawer = "open"; }
290
- function closeDrawer() { delete els.root.dataset.drawer; }
291
-
292
- /* ── Command palette ────────────────────────────────────────────────────── */
293
- function paletteItems() {
294
- const mode = store.get().mode;
295
- const currentRoutes = visibleRoutes(mode);
296
- const nav = currentRoutes.map((r) => ({
297
- group: t("shell.goTo"), label: r.title || r.label, icon: r.icon, hint: r.label === r.title ? groupLabel(GROUPS.find((g) => g.id === r.group) || { labelKey: r.group }) : r.label,
298
- run: () => router.navigate(r.key),
299
- }));
300
- const actions = [
301
- { group: t("shell.actions"), label: t("shell.toggleLightDark"), icon: "contrast", run: () => store.toggleTheme() },
302
- { group: t("shell.actions"), label: `${t("common.status")}: ${t("shell.mode.basic")}`, icon: "circle", run: () => store.setMode("basic") },
303
- { group: t("shell.actions"), label: `${t("common.status")}: ${t("shell.mode.advanced")}`, icon: "circles", run: () => store.setMode("advanced") },
304
- { group: t("shell.actions"), label: `${t("common.status")}: ${t("shell.mode.admin")}`, icon: "shield-half", run: () => store.setMode("admin") },
305
- { group: t("shell.actions"), label: t("shell.newChat"), icon: "message-plus", run: () => router.navigate("chat", { new: "1" }) },
306
- { group: t("shell.actions"), label: t("shell.runHybridSearch"), icon: "arrows-join", run: () => router.navigate("hybrid-search") },
307
- ];
308
- return [...nav, ...actions];
309
- }
310
-
311
- function openPalette() {
312
- if ($("#lt3-palette")) return;
313
- const all = paletteItems();
314
- let active = 0, filtered = all;
315
-
316
- const listEl = h("div.lt3-palette__list");
317
- const input = h("input", { type: "text", placeholder: t("shell.palettePlaceholder"), "aria-label": t("shell.commandPalette"), autocomplete: "off" });
318
- const palette = h("div.lt3-palette", { id: "lt3-palette", role: "dialog", "aria-modal": "true", "aria-label": t("shell.commandPalette") },
319
- h("div.lt3-palette__input", icon("search"), input, h("span.lt3-kbd", "Esc")),
320
- listEl,
321
- );
322
- const scrim = h("div.lt3-scrim", { id: "lt3-palette-scrim", on: { click: close } });
323
- document.body.append(scrim, palette);
324
- input.focus();
325
-
326
- function renderList() {
327
- listEl.replaceChildren();
328
- if (!filtered.length) { listEl.append(h("div.lt3-palette__empty", t("shell.noMatches"))); return; }
329
- let lastGroup = null;
330
- filtered.forEach((item, i) => {
331
- if (item.group !== lastGroup) { listEl.append(h("div.lt3-palette__group-label", item.group)); lastGroup = item.group; }
332
- listEl.append(h("button.lt3-palette__item", {
333
- dataset: { active: String(i === active) },
334
- on: { click: () => { item.run(); close(); }, mousemove: () => { if (active !== i) { active = i; paint(); } } },
335
- }, icon(item.icon), h("span", item.label), item.hint && h("small", item.hint)));
336
- });
337
- }
338
- function paint() { $$(".lt3-palette__item", listEl).forEach((el, i) => el.dataset.active = String(i === active)); ensureVisible(); }
339
- function ensureVisible() {
340
- const el = $$(".lt3-palette__item", listEl)[active];
341
- if (el) el.scrollIntoView({ block: "nearest" });
342
- }
343
- function filter() {
344
- const q = input.value.trim().toLowerCase();
345
- filtered = !q ? all : all.filter((it) => (it.label + " " + (it.hint || "")).toLowerCase().includes(q));
346
- active = 0; renderList();
347
- }
348
- function close() { palette.remove(); scrim.remove(); document.removeEventListener("keydown", onKey, true); }
349
- function onKey(e) {
350
- if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); close(); }
351
- else if (e.key === "ArrowDown") { e.preventDefault(); active = Math.min(filtered.length - 1, active + 1); paint(); }
352
- else if (e.key === "ArrowUp") { e.preventDefault(); active = Math.max(0, active - 1); paint(); }
353
- else if (e.key === "Enter") { e.preventDefault(); const it = filtered[active]; if (it) { it.run(); close(); } }
354
- }
355
- input.addEventListener("input", filter);
356
- document.addEventListener("keydown", onKey, true);
357
- renderList();
358
- }
359
-
360
- function wireGlobalKeys() {
361
- document.addEventListener("keydown", (e) => {
362
- if ((e.metaKey || e.ctrlKey) && (e.key === "k" || e.key === "K")) { e.preventDefault(); openPalette(); }
363
- if (e.key === "Escape") { closeMenus(); closeDrawer(); }
364
- });
365
- }
366
-
367
- /* ── Hydration ──────────────────────────────────────────────────────────── */
368
- async function hydrate() {
369
- // Identity (best-effort; never blocks the UI).
370
- api.raw("/account/profile").then((r) => {
371
- if (r.ok && r.data && (r.data.email || r.data.nickname)) {
372
- store.setUser({ email: r.data.email, nickname: r.data.nickname || r.data.email, role: r.data.role || "user" });
373
- } else { renderUser(); }
374
- });
375
-
376
- // Workspaces from the OS payload (fallback-safe).
377
- api.workspaceOs().then((r) => {
378
- const reg = r.data && r.data.workspace_registry;
379
- if (reg && Array.isArray(reg.workspaces) && reg.workspaces.length) store.setWorkspaces(reg.workspaces);
380
- });
381
-
382
- // Index status powers the topbar chip + Home pillars.
383
- api.indexStatus().then((r) => store.setIndexStatus(r.data));
384
- }
385
-
386
- /* ── Init helpers ───────────────────────────────────────────────────────── */
387
- function cacheEls(root) {
388
- els = {
389
- root,
390
- nav: $("#lt3-nav", root),
391
- scope: $("#lt3-scope", root),
392
- user: $("#lt3-user", root),
393
- theme: $("#lt3-theme", root),
394
- crumbs: $("#lt3-crumbs", root),
395
- idxchip: $("#lt3-idxchip", root),
396
- cmdText: $("#lt3-cmd-text", root),
397
- railStatus: $("#lt3-rail-status", root),
398
- outlet: $("#lt3-outlet", root),
399
- view: $("#lt3-view", root),
400
- };
401
- renderNav();
402
- renderScope();
403
- renderUser();
404
- renderMode();
405
- updateThemeIcon();
406
- renderIndexChip();
407
- renderRailStatus();
408
- renderChromeText();
409
- }
410
-
411
- function latticeMark() {
412
- // Crystalline lattice glyph — the product mark.
413
- return `<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
414
- <path d="M12 2.5 4 7v10l8 4.5L20 17V7L12 2.5Z" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round" opacity=".55"/>
415
- <path d="M12 7.5 7.5 10v4L12 16.5 16.5 14v-4L12 7.5Z" fill="currentColor" opacity=".9"/>
416
- <circle cx="12" cy="2.5" r="1.3" fill="currentColor"/><circle cx="4" cy="7" r="1.1" fill="currentColor"/>
417
- <circle cx="20" cy="7" r="1.1" fill="currentColor"/><circle cx="4" cy="17" r="1.1" fill="currentColor"/>
418
- <circle cx="20" cy="17" r="1.1" fill="currentColor"/><circle cx="12" cy="21.5" r="1.3" fill="currentColor"/>
419
- </svg>`;
420
- }