ltcai 3.3.0 → 3.4.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 (75) hide show
  1. package/README.md +85 -66
  2. package/docs/CHANGELOG.md +36 -0
  3. package/docs/architecture.md +2 -1
  4. package/docs/assets/v3.4.0/agent-run.png +0 -0
  5. package/docs/assets/v3.4.0/agents.png +0 -0
  6. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  7. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  8. package/docs/assets/v3.4.0/chat.png +0 -0
  9. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  10. package/docs/assets/v3.4.0/files.png +0 -0
  11. package/docs/assets/v3.4.0/home.png +0 -0
  12. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  13. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  14. package/docs/assets/v3.4.0/local-agent.png +0 -0
  15. package/docs/assets/v3.4.0/memory.png +0 -0
  16. package/docs/assets/v3.4.0/settings.png +0 -0
  17. package/docs/assets/v3.4.0/vision-input.png +0 -0
  18. package/docs/assets/v3.4.0/workflows.png +0 -0
  19. package/knowledge_graph.py +45 -0
  20. package/knowledge_graph_api.py +10 -0
  21. package/latticeai/__init__.py +1 -1
  22. package/latticeai/api/agents.py +3 -0
  23. package/latticeai/api/hooks.py +39 -0
  24. package/latticeai/api/local_files.py +41 -0
  25. package/latticeai/api/models.py +36 -1
  26. package/latticeai/api/tools.py +16 -1
  27. package/latticeai/api/workflow_designer.py +2 -1
  28. package/latticeai/core/hooks.py +398 -2
  29. package/latticeai/core/marketplace.py +1 -1
  30. package/latticeai/core/multi_agent.py +1 -1
  31. package/latticeai/core/workflow_engine.py +21 -1
  32. package/latticeai/core/workspace_os.py +1 -1
  33. package/latticeai/server_app.py +40 -0
  34. package/latticeai/services/agent_runtime.py +46 -1
  35. package/latticeai/services/upload_service.py +17 -0
  36. package/package.json +1 -1
  37. package/scripts/capture/capture_v340.js +88 -0
  38. package/static/css/{tokens.8b8e31bd.css → tokens.3ba22e37.css} +109 -109
  39. package/static/css/tokens.css +109 -109
  40. package/static/v3/asset-manifest.json +24 -24
  41. package/static/v3/css/{lattice.components.011e988b.css → lattice.components.9b49d614.css} +57 -32
  42. package/static/v3/css/lattice.components.css +57 -32
  43. package/static/v3/css/{lattice.shell.4920f42d.css → lattice.shell.6ceea7c8.css} +75 -31
  44. package/static/v3/css/lattice.shell.css +75 -31
  45. package/static/v3/css/lattice.tokens.css +13 -13
  46. package/static/v3/css/{lattice.tokens.c597ff81.css → lattice.tokens.e7018963.css} +13 -13
  47. package/static/v3/css/{lattice.views.1d326beb.css → lattice.views.22f69117.css} +93 -15
  48. package/static/v3/css/lattice.views.css +93 -15
  49. package/static/v3/js/{app.cf5bb712.js → app.c4acfdd8.js} +1 -1
  50. package/static/v3/js/core/{api.113660c5.js → api.12b568ad.js} +67 -0
  51. package/static/v3/js/core/api.js +67 -0
  52. package/static/v3/js/core/{components.4c83e0a9.js → components.35f02e4c.js} +8 -0
  53. package/static/v3/js/core/components.js +8 -0
  54. package/static/v3/js/core/{routes.07ad6696.js → routes.d214b399.js} +16 -12
  55. package/static/v3/js/core/routes.js +16 -12
  56. package/static/v3/js/core/{shell.9e707234.js → shell.80a6ad82.js} +37 -9
  57. package/static/v3/js/core/shell.js +34 -6
  58. package/static/v3/js/views/agents.014d0b74.js +541 -0
  59. package/static/v3/js/views/agents.js +305 -57
  60. package/static/v3/js/views/{chat.c48fd9e2.js → chat.e6dd7dd0.js} +161 -9
  61. package/static/v3/js/views/chat.js +161 -9
  62. package/static/v3/js/views/files.adad14c1.js +365 -0
  63. package/static/v3/js/views/files.js +212 -79
  64. package/static/v3/js/views/home.24f8b8ae.js +200 -0
  65. package/static/v3/js/views/home.js +96 -15
  66. package/static/v3/js/views/hooks.13845954.js +215 -0
  67. package/static/v3/js/views/hooks.js +117 -1
  68. package/static/v3/js/views/{my-computer.1b2ff621.js → my-computer.c3ef5283.js} +224 -1
  69. package/static/v3/js/views/my-computer.js +224 -1
  70. package/static/v3/js/views/{settings.c7b0cc05.js → settings.8631fa5e.js} +54 -0
  71. package/static/v3/js/views/settings.js +54 -0
  72. package/static/v3/js/views/agents.c373d48c.js +0 -293
  73. package/static/v3/js/views/files.8464634a.js +0 -232
  74. package/static/v3/js/views/home.cdde3b32.js +0 -119
  75. package/static/v3/js/views/hooks.f3edebca.js +0 -99
@@ -1,5 +1,5 @@
1
1
  /* ============================================================================
2
- * Lattice AI v3 — Structural Design Tokens
2
+ * Lattice AI v3.3.1 — Structural Design Tokens
3
3
  *
4
4
  * This layer sits ON TOP of /static/css/tokens.css (the color single-source).
5
5
  * It adds the NON-COLOR structure of the v3 system — spacing, type scale,
@@ -40,9 +40,9 @@
40
40
  --lt3-weight-bold: 700;
41
41
  --lt3-weight-black: 800;
42
42
 
43
- --lt3-tracking-tight: -0.02em;
44
- --lt3-tracking-wide: 0.02em;
45
- --lt3-tracking-caps: 0.14em; /* eyebrow / section labels */
43
+ --lt3-tracking-tight: 0;
44
+ --lt3-tracking-wide: 0;
45
+ --lt3-tracking-caps: 0; /* eyebrow / section labels */
46
46
 
47
47
  /* ── Spacing scale (4pt base) ───────────────────────────────────────── */
48
48
  --lt3-space-0: 0;
@@ -57,18 +57,18 @@
57
57
  --lt3-space-9: 4rem; /* 64 */
58
58
 
59
59
  /* ── Radii ──────────────────────────────────────────────────────────── */
60
- --lt3-radius-xs: 6px;
61
- --lt3-radius-sm: 9px;
62
- --lt3-radius-md: 13px;
63
- --lt3-radius-lg: 18px;
64
- --lt3-radius-xl: 24px;
60
+ --lt3-radius-xs: 4px;
61
+ --lt3-radius-sm: 6px;
62
+ --lt3-radius-md: 8px;
63
+ --lt3-radius-lg: 8px;
64
+ --lt3-radius-xl: 8px;
65
65
  --lt3-radius-pill: 999px;
66
66
 
67
67
  /* ── Elevation (theme-aware via inherited --shadow*) ────────────────── */
68
68
  --lt3-elev-0: none;
69
69
  --lt3-elev-1: var(--shadow-sm);
70
70
  --lt3-elev-2: var(--shadow);
71
- --lt3-elev-3: 0 28px 70px rgba(15, 23, 42, 0.16);
71
+ --lt3-elev-3: 0 28px 70px rgba(30, 36, 48, 0.18);
72
72
 
73
73
  /* ── Motion ─────────────────────────────────────────────────────────── */
74
74
  --lt3-ease: var(--lt-motion-ease, cubic-bezier(0.22, 1, 0.36, 1));
@@ -87,10 +87,10 @@
87
87
  --lt3-z-toast: 100;
88
88
 
89
89
  /* ── Layout rails ───────────────────────────────────────────────────── */
90
- --lt3-rail-w: 268px; /* expanded nav rail */
90
+ --lt3-rail-w: 292px; /* expanded nav rail */
91
91
  --lt3-rail-w-collapsed: 76px;
92
- --lt3-topbar-h: 60px;
93
- --lt3-content-max: 1240px;
92
+ --lt3-topbar-h: 56px;
93
+ --lt3-content-max: 1360px;
94
94
  --lt3-content-pad: var(--lt3-space-6);
95
95
 
96
96
  /* ── Retrieval identity accents (mapped to themed accents) ──────────── */
@@ -1,5 +1,5 @@
1
1
  /* ============================================================================
2
- * Lattice AI v3 — Structural Design Tokens
2
+ * Lattice AI v3.3.1 — Structural Design Tokens
3
3
  *
4
4
  * This layer sits ON TOP of /static/css/tokens.css (the color single-source).
5
5
  * It adds the NON-COLOR structure of the v3 system — spacing, type scale,
@@ -40,9 +40,9 @@
40
40
  --lt3-weight-bold: 700;
41
41
  --lt3-weight-black: 800;
42
42
 
43
- --lt3-tracking-tight: -0.02em;
44
- --lt3-tracking-wide: 0.02em;
45
- --lt3-tracking-caps: 0.14em; /* eyebrow / section labels */
43
+ --lt3-tracking-tight: 0;
44
+ --lt3-tracking-wide: 0;
45
+ --lt3-tracking-caps: 0; /* eyebrow / section labels */
46
46
 
47
47
  /* ── Spacing scale (4pt base) ───────────────────────────────────────── */
48
48
  --lt3-space-0: 0;
@@ -57,18 +57,18 @@
57
57
  --lt3-space-9: 4rem; /* 64 */
58
58
 
59
59
  /* ── Radii ──────────────────────────────────────────────────────────── */
60
- --lt3-radius-xs: 6px;
61
- --lt3-radius-sm: 9px;
62
- --lt3-radius-md: 13px;
63
- --lt3-radius-lg: 18px;
64
- --lt3-radius-xl: 24px;
60
+ --lt3-radius-xs: 4px;
61
+ --lt3-radius-sm: 6px;
62
+ --lt3-radius-md: 8px;
63
+ --lt3-radius-lg: 8px;
64
+ --lt3-radius-xl: 8px;
65
65
  --lt3-radius-pill: 999px;
66
66
 
67
67
  /* ── Elevation (theme-aware via inherited --shadow*) ────────────────── */
68
68
  --lt3-elev-0: none;
69
69
  --lt3-elev-1: var(--shadow-sm);
70
70
  --lt3-elev-2: var(--shadow);
71
- --lt3-elev-3: 0 28px 70px rgba(15, 23, 42, 0.16);
71
+ --lt3-elev-3: 0 28px 70px rgba(30, 36, 48, 0.18);
72
72
 
73
73
  /* ── Motion ─────────────────────────────────────────────────────────── */
74
74
  --lt3-ease: var(--lt-motion-ease, cubic-bezier(0.22, 1, 0.36, 1));
@@ -87,10 +87,10 @@
87
87
  --lt3-z-toast: 100;
88
88
 
89
89
  /* ── Layout rails ───────────────────────────────────────────────────── */
90
- --lt3-rail-w: 268px; /* expanded nav rail */
90
+ --lt3-rail-w: 292px; /* expanded nav rail */
91
91
  --lt3-rail-w-collapsed: 76px;
92
- --lt3-topbar-h: 60px;
93
- --lt3-content-max: 1240px;
92
+ --lt3-topbar-h: 56px;
93
+ --lt3-content-max: 1360px;
94
94
  --lt3-content-pad: var(--lt3-space-6);
95
95
 
96
96
  /* ── Retrieval identity accents (mapped to themed accents) ──────────── */
@@ -7,30 +7,90 @@
7
7
  .lt3-hero {
8
8
  position: relative;
9
9
  overflow: hidden;
10
- padding: var(--lt3-space-7);
11
- border-radius: var(--lt3-radius-xl);
10
+ display: grid;
11
+ grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.75fr);
12
+ gap: var(--lt3-space-6);
13
+ padding: var(--lt3-space-6);
14
+ border-radius: var(--lt3-radius-md);
12
15
  background:
13
- radial-gradient(120% 140% at 100% 0%, var(--lt3-pillar-vector-soft) 0%, transparent 50%),
14
- radial-gradient(120% 140% at 0% 100%, var(--lt3-pillar-graph-soft) 0%, transparent 50%),
16
+ linear-gradient(90deg, var(--surface) 0%, color-mix(in srgb, var(--surface-2) 62%, var(--surface)) 100%),
15
17
  var(--surface);
16
18
  border: 1px solid var(--border);
19
+ box-shadow: var(--lt3-elev-1);
20
+ }
21
+ .lt3-hero::before {
22
+ content: "";
23
+ position: absolute;
24
+ inset: 0;
25
+ pointer-events: none;
26
+ background-image:
27
+ linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
28
+ linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px);
29
+ background-size: calc(var(--lt3-mesh-size) * 0.85) calc(var(--lt3-mesh-size) * 0.85);
30
+ mask-image: linear-gradient(90deg, transparent, #000 34%, #000 100%);
17
31
  }
32
+ .lt3-hero > * { position: relative; z-index: 1; }
18
33
  .lt3-hero__eyebrow { display: inline-flex; align-items: center; gap: var(--lt3-space-2); }
19
- .lt3-hero__title { font-size: var(--lt3-text-3xl); font-weight: var(--lt3-weight-black); letter-spacing: var(--lt3-tracking-tight); margin-top: var(--lt3-space-3); max-width: 20ch; }
34
+ .lt3-hero__title { font-size: var(--lt3-text-3xl); font-weight: var(--lt3-weight-black); letter-spacing: var(--lt3-tracking-tight); margin-top: var(--lt3-space-3); max-width: 22ch; }
20
35
  .lt3-hero__sub { font-size: var(--lt3-text-lg); color: var(--muted); margin-top: var(--lt3-space-3); max-width: 56ch; }
21
36
  .lt3-hero__actions { display: flex; flex-wrap: wrap; gap: var(--lt3-space-3); margin-top: var(--lt3-space-5); }
37
+ .lt3-hero__aside { display: flex; flex-direction: column; gap: var(--lt3-space-3); }
38
+
39
+ .lt3-readiness {
40
+ display: grid;
41
+ gap: var(--lt3-space-2);
42
+ }
43
+ .lt3-readiness__row {
44
+ display: grid;
45
+ grid-template-columns: auto minmax(0, 1fr) auto;
46
+ align-items: center;
47
+ gap: var(--lt3-space-3);
48
+ padding: var(--lt3-space-3);
49
+ border: 1px solid var(--border);
50
+ border-radius: var(--lt3-radius-md);
51
+ background: var(--card);
52
+ }
53
+ .lt3-readiness__icon {
54
+ display: grid;
55
+ place-items: center;
56
+ width: 30px;
57
+ height: 30px;
58
+ border-radius: var(--lt3-radius-xs);
59
+ background: var(--surface-2);
60
+ color: var(--accent);
61
+ }
62
+ .lt3-readiness__title { font-size: var(--lt3-text-sm); font-weight: var(--lt3-weight-semi); }
63
+ .lt3-readiness__meta { font-size: var(--lt3-text-2xs); color: var(--faint); }
64
+ .lt3-mini-lattice {
65
+ display: grid;
66
+ grid-template-columns: repeat(3, minmax(0, 1fr));
67
+ gap: var(--lt3-space-2);
68
+ }
69
+ .lt3-mini-lattice__node {
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: 2px;
73
+ min-height: 88px;
74
+ padding: var(--lt3-space-3);
75
+ border-radius: var(--lt3-radius-md);
76
+ border: 1px solid var(--border);
77
+ background: var(--surface);
78
+ }
79
+ .lt3-mini-lattice__node b { font-size: var(--lt3-text-sm); }
80
+ .lt3-mini-lattice__node span { font-size: var(--lt3-text-2xs); color: var(--faint); }
22
81
 
23
82
  .lt3-quickgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--lt3-space-4); }
24
83
  .lt3-quick {
25
84
  display: flex; flex-direction: column; gap: var(--lt3-space-2);
26
85
  padding: var(--lt3-space-4);
86
+ min-height: 132px;
27
87
  border-radius: var(--lt3-radius-md);
28
- background: var(--surface);
88
+ background: var(--card);
29
89
  border: 1px solid var(--border);
30
90
  transition: transform var(--lt3-dur-2) var(--lt3-ease), border-color var(--lt3-dur-2) var(--lt3-ease);
31
91
  }
32
92
  .lt3-quick:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
33
- .lt3-quick__icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--lt3-radius-sm); background: var(--accent-soft); color: var(--accent); }
93
+ .lt3-quick__icon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--lt3-radius-md); background: var(--accent-soft); color: var(--accent); }
34
94
  .lt3-quick__title { font-size: var(--lt3-text-md); font-weight: var(--lt3-weight-semi); }
35
95
  .lt3-quick__desc { font-size: var(--lt3-text-xs); color: var(--muted); }
36
96
 
@@ -48,7 +108,7 @@
48
108
  .lt3-graph-canvas {
49
109
  position: relative;
50
110
  height: 540px;
51
- border-radius: var(--lt3-radius-lg);
111
+ border-radius: var(--lt3-radius-md);
52
112
  border: 1px solid var(--border);
53
113
  background:
54
114
  radial-gradient(circle at center, var(--graph-grid) 1px, transparent 1.5px),
@@ -120,13 +180,13 @@
120
180
  .lt3-chat {
121
181
  position: relative;
122
182
  display: grid;
123
- grid-template-columns: 264px minmax(0, 1fr) 340px;
183
+ grid-template-columns: 280px minmax(0, 1fr) 340px;
124
184
  height: 100%;
125
185
  overflow: hidden;
126
186
  }
127
187
 
128
188
  /* Conversation list rail */
129
- .lt3-chatlist { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); background: color-mix(in srgb, var(--surface) 55%, transparent); }
189
+ .lt3-chatlist { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); background: var(--sidebar); }
130
190
  .lt3-chatlist__head { flex: none; padding: var(--lt3-space-4); border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--lt3-space-3); }
131
191
  .lt3-chatlist__items { flex: 1; min-height: 0; overflow-y: auto; padding: var(--lt3-space-2); display: flex; flex-direction: column; gap: 2px; }
132
192
  .lt3-convo {
@@ -151,7 +211,8 @@
151
211
  flex: none; display: flex; align-items: center; gap: var(--lt3-space-3);
152
212
  padding: var(--lt3-space-3) var(--lt3-space-5);
153
213
  border-bottom: 1px solid var(--border);
154
- min-height: 56px;
214
+ min-height: 54px;
215
+ background: var(--surface-elevated);
155
216
  }
156
217
  .lt3-chat__title { font-size: var(--lt3-text-md); font-weight: var(--lt3-weight-semi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
157
218
  .lt3-chat__thread { flex: 1; overflow-y: auto; padding: var(--lt3-space-6); display: flex; flex-direction: column; gap: var(--lt3-space-5); }
@@ -180,7 +241,7 @@
180
241
  .lt3-composer__box {
181
242
  display: flex; align-items: flex-end; gap: var(--lt3-space-3);
182
243
  padding: var(--lt3-space-3) var(--lt3-space-3) var(--lt3-space-3) var(--lt3-space-4);
183
- border-radius: var(--lt3-radius-lg);
244
+ border-radius: var(--lt3-radius-md);
184
245
  border: 1px solid var(--border);
185
246
  background: var(--input);
186
247
  transition: border-color var(--lt3-dur-2) var(--lt3-ease), box-shadow var(--lt3-dur-2) var(--lt3-ease);
@@ -191,7 +252,7 @@
191
252
  .lt3-composer__hint { margin-top: var(--lt3-space-2); font-size: var(--lt3-text-2xs); color: var(--faint); text-align: center; }
192
253
 
193
254
  /* Retrieval context column */
194
- .lt3-chat__context { display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--border); background: color-mix(in srgb, var(--surface) 55%, transparent); }
255
+ .lt3-chat__context { display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--border); background: var(--sidebar); }
195
256
  .lt3-chat__context-head { flex: none; padding: var(--lt3-space-4) var(--lt3-space-4) var(--lt3-space-3); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: var(--lt3-space-2); }
196
257
  .lt3-chat__context-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--lt3-space-4); display: flex; flex-direction: column; gap: var(--lt3-space-5); }
197
258
  .lt3-ctx-sec__title { display: flex; align-items: center; gap: var(--lt3-space-2); font-size: var(--lt3-text-2xs); font-weight: var(--lt3-weight-semi); letter-spacing: var(--lt3-tracking-caps); text-transform: uppercase; color: var(--faint); margin-bottom: var(--lt3-space-3); }
@@ -209,7 +270,7 @@
209
270
  .lt3-chat[data-context="open"] .lt3-chat__scrim { display: block; }
210
271
 
211
272
  @media (max-width: 1240px) {
212
- .lt3-chat { grid-template-columns: 264px minmax(0, 1fr); }
273
+ .lt3-chat { grid-template-columns: 280px minmax(0, 1fr); }
213
274
  .lt3-chat__context {
214
275
  position: absolute; top: 0; right: 0; bottom: 0; width: min(340px, 88vw);
215
276
  transform: translateX(102%); transition: transform var(--lt3-dur-3) var(--lt3-ease);
@@ -242,11 +303,18 @@
242
303
  display: flex; flex-direction: column; align-items: center; gap: var(--lt3-space-3);
243
304
  padding: var(--lt3-space-7);
244
305
  border: 1.5px dashed var(--border-strong);
245
- border-radius: var(--lt3-radius-lg);
306
+ border-radius: var(--lt3-radius-md);
246
307
  background: var(--surface-2);
247
308
  text-align: center;
248
309
  transition: border-color var(--lt3-dur-2) var(--lt3-ease), background var(--lt3-dur-2) var(--lt3-ease);
249
310
  }
311
+ .lt3-drop__meta {
312
+ display: flex;
313
+ flex-wrap: wrap;
314
+ justify-content: center;
315
+ gap: var(--lt3-space-2);
316
+ max-width: 720px;
317
+ }
250
318
  .lt3-drop.is-dragover {
251
319
  border-color: var(--accent);
252
320
  background: var(--accent-soft);
@@ -269,6 +337,16 @@
269
337
  /* ── Generic 2-up metric rows used widely ────────────────────────────────── */
270
338
  .lt3-statrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--lt3-space-3); }
271
339
 
340
+ @media (max-width: 980px) {
341
+ .lt3-hero { grid-template-columns: 1fr; padding: var(--lt3-space-5); }
342
+ }
343
+
344
+ @media (max-width: 680px) {
345
+ .lt3-mini-lattice { grid-template-columns: 1fr; }
346
+ .lt3-hero__title { font-size: var(--lt3-text-2xl); }
347
+ .lt3-quick { min-height: auto; }
348
+ }
349
+
272
350
  /* ── Admin shared ────────────────────────────────────────────────────────── */
273
351
  .lt3-keyval { display: grid; grid-template-columns: max-content 1fr; gap: var(--lt3-space-2) var(--lt3-space-5); font-size: var(--lt3-text-sm); }
274
352
  .lt3-keyval dt { color: var(--muted); }
@@ -7,30 +7,90 @@
7
7
  .lt3-hero {
8
8
  position: relative;
9
9
  overflow: hidden;
10
- padding: var(--lt3-space-7);
11
- border-radius: var(--lt3-radius-xl);
10
+ display: grid;
11
+ grid-template-columns: minmax(0, 1.25fr) minmax(300px, 0.75fr);
12
+ gap: var(--lt3-space-6);
13
+ padding: var(--lt3-space-6);
14
+ border-radius: var(--lt3-radius-md);
12
15
  background:
13
- radial-gradient(120% 140% at 100% 0%, var(--lt3-pillar-vector-soft) 0%, transparent 50%),
14
- radial-gradient(120% 140% at 0% 100%, var(--lt3-pillar-graph-soft) 0%, transparent 50%),
16
+ linear-gradient(90deg, var(--surface) 0%, color-mix(in srgb, var(--surface-2) 62%, var(--surface)) 100%),
15
17
  var(--surface);
16
18
  border: 1px solid var(--border);
19
+ box-shadow: var(--lt3-elev-1);
20
+ }
21
+ .lt3-hero::before {
22
+ content: "";
23
+ position: absolute;
24
+ inset: 0;
25
+ pointer-events: none;
26
+ background-image:
27
+ linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
28
+ linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px);
29
+ background-size: calc(var(--lt3-mesh-size) * 0.85) calc(var(--lt3-mesh-size) * 0.85);
30
+ mask-image: linear-gradient(90deg, transparent, #000 34%, #000 100%);
17
31
  }
32
+ .lt3-hero > * { position: relative; z-index: 1; }
18
33
  .lt3-hero__eyebrow { display: inline-flex; align-items: center; gap: var(--lt3-space-2); }
19
- .lt3-hero__title { font-size: var(--lt3-text-3xl); font-weight: var(--lt3-weight-black); letter-spacing: var(--lt3-tracking-tight); margin-top: var(--lt3-space-3); max-width: 20ch; }
34
+ .lt3-hero__title { font-size: var(--lt3-text-3xl); font-weight: var(--lt3-weight-black); letter-spacing: var(--lt3-tracking-tight); margin-top: var(--lt3-space-3); max-width: 22ch; }
20
35
  .lt3-hero__sub { font-size: var(--lt3-text-lg); color: var(--muted); margin-top: var(--lt3-space-3); max-width: 56ch; }
21
36
  .lt3-hero__actions { display: flex; flex-wrap: wrap; gap: var(--lt3-space-3); margin-top: var(--lt3-space-5); }
37
+ .lt3-hero__aside { display: flex; flex-direction: column; gap: var(--lt3-space-3); }
38
+
39
+ .lt3-readiness {
40
+ display: grid;
41
+ gap: var(--lt3-space-2);
42
+ }
43
+ .lt3-readiness__row {
44
+ display: grid;
45
+ grid-template-columns: auto minmax(0, 1fr) auto;
46
+ align-items: center;
47
+ gap: var(--lt3-space-3);
48
+ padding: var(--lt3-space-3);
49
+ border: 1px solid var(--border);
50
+ border-radius: var(--lt3-radius-md);
51
+ background: var(--card);
52
+ }
53
+ .lt3-readiness__icon {
54
+ display: grid;
55
+ place-items: center;
56
+ width: 30px;
57
+ height: 30px;
58
+ border-radius: var(--lt3-radius-xs);
59
+ background: var(--surface-2);
60
+ color: var(--accent);
61
+ }
62
+ .lt3-readiness__title { font-size: var(--lt3-text-sm); font-weight: var(--lt3-weight-semi); }
63
+ .lt3-readiness__meta { font-size: var(--lt3-text-2xs); color: var(--faint); }
64
+ .lt3-mini-lattice {
65
+ display: grid;
66
+ grid-template-columns: repeat(3, minmax(0, 1fr));
67
+ gap: var(--lt3-space-2);
68
+ }
69
+ .lt3-mini-lattice__node {
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: 2px;
73
+ min-height: 88px;
74
+ padding: var(--lt3-space-3);
75
+ border-radius: var(--lt3-radius-md);
76
+ border: 1px solid var(--border);
77
+ background: var(--surface);
78
+ }
79
+ .lt3-mini-lattice__node b { font-size: var(--lt3-text-sm); }
80
+ .lt3-mini-lattice__node span { font-size: var(--lt3-text-2xs); color: var(--faint); }
22
81
 
23
82
  .lt3-quickgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--lt3-space-4); }
24
83
  .lt3-quick {
25
84
  display: flex; flex-direction: column; gap: var(--lt3-space-2);
26
85
  padding: var(--lt3-space-4);
86
+ min-height: 132px;
27
87
  border-radius: var(--lt3-radius-md);
28
- background: var(--surface);
88
+ background: var(--card);
29
89
  border: 1px solid var(--border);
30
90
  transition: transform var(--lt3-dur-2) var(--lt3-ease), border-color var(--lt3-dur-2) var(--lt3-ease);
31
91
  }
32
92
  .lt3-quick:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
33
- .lt3-quick__icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--lt3-radius-sm); background: var(--accent-soft); color: var(--accent); }
93
+ .lt3-quick__icon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--lt3-radius-md); background: var(--accent-soft); color: var(--accent); }
34
94
  .lt3-quick__title { font-size: var(--lt3-text-md); font-weight: var(--lt3-weight-semi); }
35
95
  .lt3-quick__desc { font-size: var(--lt3-text-xs); color: var(--muted); }
36
96
 
@@ -48,7 +108,7 @@
48
108
  .lt3-graph-canvas {
49
109
  position: relative;
50
110
  height: 540px;
51
- border-radius: var(--lt3-radius-lg);
111
+ border-radius: var(--lt3-radius-md);
52
112
  border: 1px solid var(--border);
53
113
  background:
54
114
  radial-gradient(circle at center, var(--graph-grid) 1px, transparent 1.5px),
@@ -120,13 +180,13 @@
120
180
  .lt3-chat {
121
181
  position: relative;
122
182
  display: grid;
123
- grid-template-columns: 264px minmax(0, 1fr) 340px;
183
+ grid-template-columns: 280px minmax(0, 1fr) 340px;
124
184
  height: 100%;
125
185
  overflow: hidden;
126
186
  }
127
187
 
128
188
  /* Conversation list rail */
129
- .lt3-chatlist { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); background: color-mix(in srgb, var(--surface) 55%, transparent); }
189
+ .lt3-chatlist { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); background: var(--sidebar); }
130
190
  .lt3-chatlist__head { flex: none; padding: var(--lt3-space-4); border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--lt3-space-3); }
131
191
  .lt3-chatlist__items { flex: 1; min-height: 0; overflow-y: auto; padding: var(--lt3-space-2); display: flex; flex-direction: column; gap: 2px; }
132
192
  .lt3-convo {
@@ -151,7 +211,8 @@
151
211
  flex: none; display: flex; align-items: center; gap: var(--lt3-space-3);
152
212
  padding: var(--lt3-space-3) var(--lt3-space-5);
153
213
  border-bottom: 1px solid var(--border);
154
- min-height: 56px;
214
+ min-height: 54px;
215
+ background: var(--surface-elevated);
155
216
  }
156
217
  .lt3-chat__title { font-size: var(--lt3-text-md); font-weight: var(--lt3-weight-semi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
157
218
  .lt3-chat__thread { flex: 1; overflow-y: auto; padding: var(--lt3-space-6); display: flex; flex-direction: column; gap: var(--lt3-space-5); }
@@ -180,7 +241,7 @@
180
241
  .lt3-composer__box {
181
242
  display: flex; align-items: flex-end; gap: var(--lt3-space-3);
182
243
  padding: var(--lt3-space-3) var(--lt3-space-3) var(--lt3-space-3) var(--lt3-space-4);
183
- border-radius: var(--lt3-radius-lg);
244
+ border-radius: var(--lt3-radius-md);
184
245
  border: 1px solid var(--border);
185
246
  background: var(--input);
186
247
  transition: border-color var(--lt3-dur-2) var(--lt3-ease), box-shadow var(--lt3-dur-2) var(--lt3-ease);
@@ -191,7 +252,7 @@
191
252
  .lt3-composer__hint { margin-top: var(--lt3-space-2); font-size: var(--lt3-text-2xs); color: var(--faint); text-align: center; }
192
253
 
193
254
  /* Retrieval context column */
194
- .lt3-chat__context { display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--border); background: color-mix(in srgb, var(--surface) 55%, transparent); }
255
+ .lt3-chat__context { display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--border); background: var(--sidebar); }
195
256
  .lt3-chat__context-head { flex: none; padding: var(--lt3-space-4) var(--lt3-space-4) var(--lt3-space-3); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: var(--lt3-space-2); }
196
257
  .lt3-chat__context-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--lt3-space-4); display: flex; flex-direction: column; gap: var(--lt3-space-5); }
197
258
  .lt3-ctx-sec__title { display: flex; align-items: center; gap: var(--lt3-space-2); font-size: var(--lt3-text-2xs); font-weight: var(--lt3-weight-semi); letter-spacing: var(--lt3-tracking-caps); text-transform: uppercase; color: var(--faint); margin-bottom: var(--lt3-space-3); }
@@ -209,7 +270,7 @@
209
270
  .lt3-chat[data-context="open"] .lt3-chat__scrim { display: block; }
210
271
 
211
272
  @media (max-width: 1240px) {
212
- .lt3-chat { grid-template-columns: 264px minmax(0, 1fr); }
273
+ .lt3-chat { grid-template-columns: 280px minmax(0, 1fr); }
213
274
  .lt3-chat__context {
214
275
  position: absolute; top: 0; right: 0; bottom: 0; width: min(340px, 88vw);
215
276
  transform: translateX(102%); transition: transform var(--lt3-dur-3) var(--lt3-ease);
@@ -242,11 +303,18 @@
242
303
  display: flex; flex-direction: column; align-items: center; gap: var(--lt3-space-3);
243
304
  padding: var(--lt3-space-7);
244
305
  border: 1.5px dashed var(--border-strong);
245
- border-radius: var(--lt3-radius-lg);
306
+ border-radius: var(--lt3-radius-md);
246
307
  background: var(--surface-2);
247
308
  text-align: center;
248
309
  transition: border-color var(--lt3-dur-2) var(--lt3-ease), background var(--lt3-dur-2) var(--lt3-ease);
249
310
  }
311
+ .lt3-drop__meta {
312
+ display: flex;
313
+ flex-wrap: wrap;
314
+ justify-content: center;
315
+ gap: var(--lt3-space-2);
316
+ max-width: 720px;
317
+ }
250
318
  .lt3-drop.is-dragover {
251
319
  border-color: var(--accent);
252
320
  background: var(--accent-soft);
@@ -269,6 +337,16 @@
269
337
  /* ── Generic 2-up metric rows used widely ────────────────────────────────── */
270
338
  .lt3-statrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--lt3-space-3); }
271
339
 
340
+ @media (max-width: 980px) {
341
+ .lt3-hero { grid-template-columns: 1fr; padding: var(--lt3-space-5); }
342
+ }
343
+
344
+ @media (max-width: 680px) {
345
+ .lt3-mini-lattice { grid-template-columns: 1fr; }
346
+ .lt3-hero__title { font-size: var(--lt3-text-2xl); }
347
+ .lt3-quick { min-height: auto; }
348
+ }
349
+
272
350
  /* ── Admin shared ────────────────────────────────────────────────────────── */
273
351
  .lt3-keyval { display: grid; grid-template-columns: max-content 1fr; gap: var(--lt3-space-2) var(--lt3-space-5); font-size: var(--lt3-text-sm); }
274
352
  .lt3-keyval dt { color: var(--muted); }
@@ -3,7 +3,7 @@
3
3
  * Boots the shell. Views are lazy-loaded by the router (see core/routes.js).
4
4
  * ========================================================================== */
5
5
 
6
- import { boot } from "./core/shell.9e707234.js";
6
+ import { boot } from "./core/shell.80a6ad82.js";
7
7
 
8
8
  const root = document.getElementById("app");
9
9
  if (root) boot(root);
@@ -440,6 +440,73 @@ export const api = {
440
440
  mcpClaudeServers() { return withFallback("/mcp/claude-code-servers", {}, { servers: [] }); },
441
441
  mcpCustom() { return withFallback("/mcp/custom", {}, { custom: [] }); },
442
442
  mcpRecommend(query, limit = 6) { return raw("/mcp/recommend", { method: "POST", body: { query, limit } }); },
443
+
444
+ /* ── v3.4 Platform Completion ───────────────────────────────────────────
445
+ * Uploaded documents in Files, Connect Folder + Folder Watch over the real
446
+ * on-device runtime, the Local Agent status, and Hooks dispatch/run-log.
447
+ * All endpoints are real (latticeai/api + knowledge_graph_api); fallback-safe. */
448
+
449
+ /** GET /knowledge-graph/documents — uploaded + indexed docs with index state. */
450
+ async documents(limit = 200) {
451
+ const res = await raw(`/knowledge-graph/documents?limit=${encodeURIComponent(limit)}`);
452
+ if (res.ok && res.data && Array.isArray(res.data.documents)) {
453
+ return { ok: true, status: res.status, data: res.data.documents, source: "live", total: res.data.total };
454
+ }
455
+ return { ok: false, status: res.status, data: [], source: "unavailable", error: res.error };
456
+ },
457
+
458
+ // Local Agent (the on-device Lattice runtime: real GET /api/local-agent/status)
459
+ async localAgent() {
460
+ const res = await raw("/api/local-agent/status");
461
+ if (res.ok && res.data && res.data.agent) {
462
+ return { ok: true, status: res.status, data: res.data, source: "live" };
463
+ }
464
+ return {
465
+ ok: false, status: res.status, source: "unavailable",
466
+ data: { agent: { online: false }, health: {}, folders: { connected: 0, watching: 0 }, watch: { available: false, active: {} }, sources: [] },
467
+ };
468
+ },
469
+
470
+ // Connect Folder + Folder Watch (real backend: /knowledge-graph/local/*)
471
+ localRoots() { return withFallback("/knowledge-graph/local/roots", {}, { roots: [] }); },
472
+ async localSources() {
473
+ const res = await raw("/knowledge-graph/local/sources");
474
+ if (res.ok && res.data && Array.isArray(res.data.sources)) {
475
+ return { ok: true, status: res.status, data: res.data, source: "live" };
476
+ }
477
+ return { ok: false, status: res.status, data: { sources: [], watch: { available: false, active: {} } }, source: "unavailable" };
478
+ },
479
+ localWatchStatus() { return raw("/knowledge-graph/local/watch/status"); },
480
+ localWatchStop(source_id) { return raw("/knowledge-graph/local/watch/stop", { method: "POST", body: { source_id } }); },
481
+ approvePermission(token) { return raw(`/permissions/approve/${encodeURIComponent(token)}`, { method: "POST" }); },
482
+ indexFolder(path, opts = {}) {
483
+ return raw("/knowledge-graph/local/index", { method: "POST", body: { path, ...opts } });
484
+ },
485
+ /** One-call Connect Folder: request → self-approve (the click is the consent)
486
+ * → index (+ optional watch). Returns { ok, data, error }. */
487
+ async connectFolder(path, { watch = true, includeOcr = false } = {}) {
488
+ const probe = await raw("/knowledge-graph/local/index", { method: "POST", body: { path, approved: false } });
489
+ const token = probe.data && probe.data.approval_token;
490
+ if (!token) {
491
+ const detail = (probe.data && (probe.data.detail || probe.data.error)) || "the runtime did not return an approval token";
492
+ return { ok: false, error: detail, status: probe.status };
493
+ }
494
+ const approved = await raw(`/permissions/approve/${encodeURIComponent(token)}`, { method: "POST" });
495
+ if (!approved.ok) {
496
+ const detail = (approved.data && (approved.data.detail || approved.data.error)) || "approval failed";
497
+ return { ok: false, error: detail, status: approved.status };
498
+ }
499
+ const res = await raw("/knowledge-graph/local/index", {
500
+ method: "POST",
501
+ body: { path, approved: true, approval_token: token, watch_enabled: watch, include_ocr: includeOcr, consent: { approved: true, source: "files-ui" } },
502
+ });
503
+ if (res.ok && res.data && !res.data.detail) return { ok: true, data: res.data, status: res.status };
504
+ return { ok: false, error: (res.data && (res.data.detail || res.data.error)) || "indexing failed", status: res.status, data: res.data };
505
+ },
506
+
507
+ // Hooks dispatch (real backend: POST /api/hooks/run + GET /api/hooks/runs)
508
+ hookRun(body) { return raw("/api/hooks/run", { method: "POST", body }); },
509
+ hookRuns(limit = 50, kind) { return withFallback(`/api/hooks/runs?limit=${encodeURIComponent(limit)}${kind ? "&kind=" + encodeURIComponent(kind) : ""}`, {}, { runs: [], total: 0 }); },
443
510
  };
444
511
 
445
512
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));