ltcai 2.2.2 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -19
- package/codex_telegram_bot.py +6 -2
- package/docs/CHANGELOG.md +72 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/static_routes.py +10 -0
- package/latticeai/core/logging_safety.py +62 -0
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +4 -2
- package/static/account.html +9 -4
- package/static/activity.html +4 -4
- package/static/admin.html +8 -3
- package/static/agents.html +4 -4
- package/static/chat.html +15 -10
- package/static/css/reference/account.css +303 -0
- package/static/css/reference/admin.css +610 -0
- package/static/css/reference/base.css +1658 -0
- package/static/{lattice-reference.css → css/reference/chat.css} +243 -3599
- package/static/css/reference/graph.css +1016 -0
- package/static/css/responsive.css +206 -1
- package/static/css/tokens.css +16 -5
- package/static/favicon.ico +0 -0
- package/static/graph.html +9 -4
- package/static/platform.css +1 -1
- package/static/plugins.html +4 -4
- package/static/scripts/chat.js +187 -69
- package/static/sw.js +5 -3
- package/static/workflows.html +4 -4
- package/static/workspace.css +70 -14
- package/static/workspace.html +5 -5
- package/telegram_bot.py +18 -14
package/static/scripts/chat.js
CHANGED
|
@@ -14,17 +14,133 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
14
14
|
let telegramHistorySyncEnabled = false;
|
|
15
15
|
let telegramHistorySyncInFlight = false;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
// ── 멀티 LLM 파이프라인 상태 ──
|
|
18
|
+
let pipelineConfig = { planning: null, executing: null, reviewing: null };
|
|
19
|
+
let pipelineActive = false; // true이면 전송 시 pipeline 모드
|
|
20
|
+
const MODAL_LAYER_IDS = [
|
|
21
|
+
'acct-modal-overlay',
|
|
22
|
+
'mcp-modal-overlay',
|
|
23
|
+
'workspace-modal-overlay',
|
|
24
|
+
'mode-modal-overlay',
|
|
25
|
+
'model-overlay',
|
|
26
|
+
'pipeline-overlay',
|
|
27
|
+
'admin-overlay',
|
|
28
|
+
'vpc-overlay',
|
|
29
|
+
'status-overlay',
|
|
30
|
+
'file-create-overlay',
|
|
31
|
+
'file-editor-overlay',
|
|
32
|
+
'local-browser-overlay',
|
|
33
|
+
'advanced-settings-overlay',
|
|
34
|
+
'cu-overlay',
|
|
35
|
+
'setup-overlay',
|
|
36
|
+
'onboarding-overlay',
|
|
37
|
+
'perm-overlay',
|
|
38
|
+
];
|
|
39
|
+
const MODAL_LAYER_SET = new Set(MODAL_LAYER_IDS);
|
|
40
|
+
let activeModalLayerId = null;
|
|
41
|
+
let restoreModalLayerId = null;
|
|
42
|
+
let bodyOverflowBeforeModal = '';
|
|
43
|
+
|
|
44
|
+
function modalLayerEl(id) {
|
|
45
|
+
return document.getElementById(id);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isModalLayerVisible(el) {
|
|
49
|
+
if (!el) return false;
|
|
50
|
+
return el.classList.contains('open') || getComputedStyle(el).display !== 'none';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function refreshBodyModalLock() {
|
|
54
|
+
const hasOpen = MODAL_LAYER_IDS.some(id => isModalLayerVisible(modalLayerEl(id)));
|
|
55
|
+
if (hasOpen) {
|
|
56
|
+
if (!document.body.classList.contains('modal-open')) {
|
|
57
|
+
bodyOverflowBeforeModal = document.body.style.overflow || '';
|
|
58
|
+
}
|
|
59
|
+
document.body.classList.add('modal-open');
|
|
60
|
+
document.body.style.overflow = 'hidden';
|
|
61
|
+
} else {
|
|
62
|
+
document.body.classList.remove('modal-open');
|
|
63
|
+
document.body.style.overflow = bodyOverflowBeforeModal;
|
|
64
|
+
bodyOverflowBeforeModal = '';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function hideModalElement(id) {
|
|
69
|
+
const el = modalLayerEl(id);
|
|
70
|
+
if (!el) return;
|
|
71
|
+
el.classList.remove('open');
|
|
72
|
+
el.style.display = 'none';
|
|
73
|
+
el.setAttribute('aria-hidden', 'true');
|
|
74
|
+
if ('inert' in el) el.inert = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function showModalLayer(id, options = {}) {
|
|
78
|
+
const el = modalLayerEl(id);
|
|
79
|
+
if (!el) return;
|
|
80
|
+
const current = activeModalLayerId && activeModalLayerId !== id ? activeModalLayerId : null;
|
|
81
|
+
MODAL_LAYER_IDS.forEach(otherId => {
|
|
82
|
+
if (otherId !== id) hideModalElement(otherId);
|
|
83
|
+
});
|
|
84
|
+
if (options.restorePrevious && current) restoreModalLayerId = current;
|
|
85
|
+
else if (!options.keepRestore) restoreModalLayerId = null;
|
|
86
|
+
el.removeAttribute('aria-hidden');
|
|
87
|
+
if ('inert' in el) el.inert = false;
|
|
88
|
+
el.classList.add('open');
|
|
89
|
+
el.style.display = 'flex';
|
|
90
|
+
activeModalLayerId = id;
|
|
91
|
+
refreshBodyModalLock();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function closeModalLayer(id, options = {}) {
|
|
95
|
+
hideModalElement(id);
|
|
96
|
+
if (activeModalLayerId === id) activeModalLayerId = null;
|
|
97
|
+
const restoreId = restoreModalLayerId;
|
|
98
|
+
if (!options.skipRestore) restoreModalLayerId = null;
|
|
99
|
+
refreshBodyModalLock();
|
|
100
|
+
if (!options.skipRestore && restoreId && restoreId !== id) {
|
|
101
|
+
showModalLayer(restoreId, { keepRestore: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function closeAllModalLayers() {
|
|
106
|
+
MODAL_LAYER_IDS.forEach(hideModalElement);
|
|
107
|
+
activeModalLayerId = null;
|
|
108
|
+
restoreModalLayerId = null;
|
|
109
|
+
refreshBodyModalLock();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function dismissModalLayer(id) {
|
|
113
|
+
if (id === 'perm-overlay') {
|
|
114
|
+
resolvePermission(false);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
closeModalLayer(id);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
document.addEventListener('keydown', (event) => {
|
|
121
|
+
if (event.key !== 'Escape') return;
|
|
122
|
+
const visible = [...MODAL_LAYER_IDS].reverse().find(id => isModalLayerVisible(modalLayerEl(id)));
|
|
123
|
+
if (!visible) return;
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
dismissModalLayer(visible);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
document.addEventListener('click', (event) => {
|
|
129
|
+
const target = event.target;
|
|
130
|
+
if (target && target.id && MODAL_LAYER_SET.has(target.id)) dismissModalLayer(target.id);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
window.addEventListener('pagehide', closeAllModalLayers);
|
|
134
|
+
window.addEventListener('popstate', closeAllModalLayers);
|
|
135
|
+
window.addEventListener('hashchange', closeAllModalLayers);
|
|
136
|
+
|
|
137
|
+
function openPipelineModal() {
|
|
138
|
+
showModalLayer('pipeline-overlay');
|
|
139
|
+
loadPipelineModelOptions();
|
|
140
|
+
}
|
|
141
|
+
function closePipelineModal() {
|
|
142
|
+
closeModalLayer('pipeline-overlay');
|
|
143
|
+
}
|
|
28
144
|
function resetPipeline() {
|
|
29
145
|
pipelineConfig = { planning: null, executing: null, reviewing: null };
|
|
30
146
|
pipelineActive = false;
|
|
@@ -731,12 +847,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
731
847
|
focusChatInput();
|
|
732
848
|
}
|
|
733
849
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
850
|
+
function openAdvancedSettingsPanel() {
|
|
851
|
+
showModalLayer('advanced-settings-overlay');
|
|
852
|
+
}
|
|
737
853
|
|
|
738
|
-
|
|
739
|
-
|
|
854
|
+
function closeAdvancedSettingsPanel() {
|
|
855
|
+
closeModalLayer('advanced-settings-overlay');
|
|
740
856
|
}
|
|
741
857
|
|
|
742
858
|
function updateWorkspaceModeUi() {
|
|
@@ -778,19 +894,19 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
778
894
|
}
|
|
779
895
|
|
|
780
896
|
function selectWorkspace(kind) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
897
|
+
setWorkspacePreference(kind);
|
|
898
|
+
closeModalLayer('workspace-modal-overlay');
|
|
899
|
+
updateWorkspaceModeUi();
|
|
900
|
+
openModeSelector();
|
|
901
|
+
}
|
|
786
902
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
903
|
+
function openModeSelector() {
|
|
904
|
+
updateWorkspaceModeUi();
|
|
905
|
+
showModalLayer('mode-modal-overlay');
|
|
906
|
+
}
|
|
791
907
|
|
|
792
|
-
|
|
793
|
-
|
|
908
|
+
function closeModeSelector() {
|
|
909
|
+
closeModalLayer('mode-modal-overlay');
|
|
794
910
|
}
|
|
795
911
|
|
|
796
912
|
function selectMode(mode) {
|
|
@@ -829,12 +945,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
829
945
|
async function startOnboardingIfNeeded(force = false) {
|
|
830
946
|
updateWorkspaceModeUi();
|
|
831
947
|
const forceAfterLogin = consumeSetupAfterLoginFlag();
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
948
|
+
const hasLoadedModel = await modelLoadedForChat();
|
|
949
|
+
if (!force && !forceAfterLogin && onboardingComplete() && hasLoadedModel) {
|
|
950
|
+
closeModalLayer('onboarding-overlay');
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
showModalLayer('onboarding-overlay');
|
|
838
954
|
if (forceAfterLogin || !hasLoadedModel) {
|
|
839
955
|
renderPcAnalysis();
|
|
840
956
|
} else {
|
|
@@ -1051,7 +1167,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
1051
1167
|
// Top pick callout
|
|
1052
1168
|
const top = rec.top_pick;
|
|
1053
1169
|
const topHtml = top ? `
|
|
1054
|
-
<div style="border:1px solid
|
|
1170
|
+
<div style="border:1px solid var(--success);background:var(--accent-soft);color:var(--text);border-radius:10px;padding:10px 12px;margin:8px 0">
|
|
1055
1171
|
<div style="font-weight:700">⭐ Best for this PC — ${escapeHtml(top.name || top.id)} ${badge('recommended')}</div>
|
|
1056
1172
|
<div style="font-size:12px;opacity:0.8;margin-top:3px">${escapeHtml(top.reason || '')}</div>
|
|
1057
1173
|
<div style="font-size:12px;margin-top:4px">${escapeHtml(top.size || '')} · ${escapeHtml(ram(top))} · ${escapeHtml(nextStep(rec.engine))}</div>
|
|
@@ -1362,12 +1478,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
1362
1478
|
`);
|
|
1363
1479
|
}
|
|
1364
1480
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1481
|
+
function finishOnboarding(mode) {
|
|
1482
|
+
selectMode(mode);
|
|
1483
|
+
setOnboardingComplete();
|
|
1484
|
+
closeModalLayer('onboarding-overlay');
|
|
1485
|
+
showChat();
|
|
1486
|
+
}
|
|
1371
1487
|
|
|
1372
1488
|
function switchAcctTab(tab) {
|
|
1373
1489
|
['profile', 'password'].forEach(t => {
|
|
@@ -1390,10 +1506,10 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
1390
1506
|
document.getElementById('profile-nickname').value = data.nickname || '';
|
|
1391
1507
|
}
|
|
1392
1508
|
} catch {}
|
|
1393
|
-
|
|
1509
|
+
showModalLayer('acct-modal-overlay');
|
|
1394
1510
|
}
|
|
1395
1511
|
function closeAcctModal() {
|
|
1396
|
-
|
|
1512
|
+
closeModalLayer('acct-modal-overlay');
|
|
1397
1513
|
}
|
|
1398
1514
|
document.addEventListener('click', (e) => {
|
|
1399
1515
|
const overlay = document.getElementById('acct-modal-overlay');
|
|
@@ -1707,7 +1823,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
1707
1823
|
}
|
|
1708
1824
|
|
|
1709
1825
|
async function openModelPanel() {
|
|
1710
|
-
|
|
1826
|
+
showModalLayer('model-overlay');
|
|
1711
1827
|
document.getElementById('model-list').innerHTML = '<div class="sensitivity-preview">실행 엔진과 모델 목록을 불러오는 중입니다...</div>';
|
|
1712
1828
|
try {
|
|
1713
1829
|
const res = await apiFetch('/engines');
|
|
@@ -1742,7 +1858,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
1742
1858
|
}
|
|
1743
1859
|
|
|
1744
1860
|
function closeModelPanel() {
|
|
1745
|
-
|
|
1861
|
+
closeModalLayer('model-overlay');
|
|
1746
1862
|
}
|
|
1747
1863
|
|
|
1748
1864
|
async function installEngine(engineId) {
|
|
@@ -2194,7 +2310,9 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2194
2310
|
if (!t) {
|
|
2195
2311
|
t = document.createElement('div');
|
|
2196
2312
|
t.id = 'ltcai-toast';
|
|
2197
|
-
|
|
2313
|
+
// Styling lives in static/css/responsive.css (#ltcai-toast) so the
|
|
2314
|
+
// toast is token-driven and adapts to light/dark. Only the opacity
|
|
2315
|
+
// animation state is toggled inline below.
|
|
2198
2316
|
document.body.appendChild(t);
|
|
2199
2317
|
}
|
|
2200
2318
|
t.textContent = msg;
|
|
@@ -2204,7 +2322,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2204
2322
|
}
|
|
2205
2323
|
|
|
2206
2324
|
function closeAdminPanel() {
|
|
2207
|
-
|
|
2325
|
+
closeModalLayer('admin-overlay');
|
|
2208
2326
|
}
|
|
2209
2327
|
|
|
2210
2328
|
// ── VPC Panel ────────────────────────────────────────
|
|
@@ -2235,7 +2353,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2235
2353
|
}
|
|
2236
2354
|
|
|
2237
2355
|
async function openVpcPanel() {
|
|
2238
|
-
|
|
2356
|
+
showModalLayer('vpc-overlay');
|
|
2239
2357
|
try {
|
|
2240
2358
|
const res = await apiFetch('/vpc/status');
|
|
2241
2359
|
if (res.ok) fillVpcPanelForm(await res.json());
|
|
@@ -2243,7 +2361,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2243
2361
|
}
|
|
2244
2362
|
|
|
2245
2363
|
function closeVpcPanel() {
|
|
2246
|
-
|
|
2364
|
+
closeModalLayer('vpc-overlay');
|
|
2247
2365
|
}
|
|
2248
2366
|
|
|
2249
2367
|
function selectVpcProvider(name, btn) {
|
|
@@ -2293,7 +2411,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2293
2411
|
|
|
2294
2412
|
// ── Status Summary Panel ─────────────────────────────
|
|
2295
2413
|
async function openStatusPanel() {
|
|
2296
|
-
|
|
2414
|
+
showModalLayer('status-overlay');
|
|
2297
2415
|
document.getElementById('status-panel-body').innerHTML = '<div class="sensitivity-preview">상태를 불러오는 중...</div>';
|
|
2298
2416
|
try {
|
|
2299
2417
|
const mode = getCurrentMode();
|
|
@@ -2362,7 +2480,7 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2362
2480
|
}
|
|
2363
2481
|
|
|
2364
2482
|
function closeStatusPanel() {
|
|
2365
|
-
|
|
2483
|
+
closeModalLayer('status-overlay');
|
|
2366
2484
|
}
|
|
2367
2485
|
|
|
2368
2486
|
// ── 파일 생성 패널 ────────────────────────────────────
|
|
@@ -2415,11 +2533,11 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2415
2533
|
</div>`;
|
|
2416
2534
|
}
|
|
2417
2535
|
document.getElementById('file-create-form').innerHTML = formHtml;
|
|
2418
|
-
|
|
2536
|
+
showModalLayer('file-create-overlay');
|
|
2419
2537
|
}
|
|
2420
2538
|
|
|
2421
2539
|
function closeFileCreate() {
|
|
2422
|
-
|
|
2540
|
+
closeModalLayer('file-create-overlay');
|
|
2423
2541
|
}
|
|
2424
2542
|
|
|
2425
2543
|
function _formatBytes(b) {
|
|
@@ -2507,24 +2625,24 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2507
2625
|
document.getElementById('perm-title').textContent = '파일 접근 요청';
|
|
2508
2626
|
document.getElementById('perm-path').textContent = path;
|
|
2509
2627
|
document.getElementById('perm-desc').textContent = `AI가 아래 경로에 대한 "${actionLabel}" 작업을 요청합니다. 허용하시겠습니까?`;
|
|
2510
|
-
|
|
2628
|
+
showModalLayer('perm-overlay', { restorePrevious: true });
|
|
2511
2629
|
});
|
|
2512
2630
|
}
|
|
2513
2631
|
|
|
2514
2632
|
function resolvePermission(allowed) {
|
|
2515
|
-
|
|
2633
|
+
closeModalLayer('perm-overlay');
|
|
2516
2634
|
if (_permResolve) { _permResolve(allowed); _permResolve = null; }
|
|
2517
2635
|
}
|
|
2518
2636
|
|
|
2519
2637
|
let _localCurrentPath = '~';
|
|
2520
2638
|
|
|
2521
2639
|
async function openLocalBrowser() {
|
|
2522
|
-
|
|
2640
|
+
showModalLayer('local-browser-overlay');
|
|
2523
2641
|
await localNav(_localCurrentPath || '~');
|
|
2524
2642
|
}
|
|
2525
2643
|
|
|
2526
2644
|
function closeLocalBrowser() {
|
|
2527
|
-
|
|
2645
|
+
closeModalLayer('local-browser-overlay');
|
|
2528
2646
|
}
|
|
2529
2647
|
|
|
2530
2648
|
async function localNav(path) {
|
|
@@ -2710,8 +2828,8 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2710
2828
|
document.getElementById('editor-filepath').textContent = path;
|
|
2711
2829
|
document.getElementById('file-editor-content').value = text;
|
|
2712
2830
|
document.getElementById('editor-status').textContent = '';
|
|
2713
|
-
|
|
2714
|
-
|
|
2831
|
+
closeModalLayer('local-browser-overlay', { skipRestore: true });
|
|
2832
|
+
showModalLayer('file-editor-overlay');
|
|
2715
2833
|
} catch(e) {
|
|
2716
2834
|
resultEl.innerHTML = `
|
|
2717
2835
|
<div class="sensitivity-preview">⚠️ 문서 읽기 실패: ${escapeHtml(e.message)}<br>
|
|
@@ -2761,15 +2879,15 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2761
2879
|
document.getElementById('editor-filepath').textContent = path;
|
|
2762
2880
|
document.getElementById('file-editor-content').value = content;
|
|
2763
2881
|
document.getElementById('editor-status').textContent = '';
|
|
2764
|
-
|
|
2765
|
-
|
|
2882
|
+
closeModalLayer('local-browser-overlay', { skipRestore: true });
|
|
2883
|
+
showModalLayer('file-editor-overlay');
|
|
2766
2884
|
} catch(e) {
|
|
2767
2885
|
resultEl.innerHTML = `<div class="sensitivity-preview">${escapeHtml(e.message)}</div>`;
|
|
2768
2886
|
}
|
|
2769
2887
|
}
|
|
2770
2888
|
|
|
2771
2889
|
function closeFileEditor() {
|
|
2772
|
-
|
|
2890
|
+
closeModalLayer('file-editor-overlay');
|
|
2773
2891
|
}
|
|
2774
2892
|
|
|
2775
2893
|
async function saveLocalFile() {
|
|
@@ -2860,8 +2978,8 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
2860
2978
|
document.getElementById('file-editor-content').value = text;
|
|
2861
2979
|
document.getElementById('editor-status').textContent = '⚠️ 이미지/표 등 비텍스트 요소는 표시되지 않을 수 있습니다';
|
|
2862
2980
|
document.getElementById('editor-status').style.color = 'var(--accent-2)';
|
|
2863
|
-
|
|
2864
|
-
|
|
2981
|
+
closeModalLayer('local-browser-overlay', { skipRestore: true });
|
|
2982
|
+
showModalLayer('file-editor-overlay');
|
|
2865
2983
|
} catch(e) {
|
|
2866
2984
|
resultEl.innerHTML = `<div class="sensitivity-preview">텍스트 추출 실패: ${escapeHtml(e.message)}</div>`;
|
|
2867
2985
|
}
|
|
@@ -4186,12 +4304,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
4186
4304
|
let cuAgentAbort = null;
|
|
4187
4305
|
|
|
4188
4306
|
async function openCuPanel() {
|
|
4189
|
-
|
|
4307
|
+
showModalLayer('cu-overlay');
|
|
4190
4308
|
await cuRefreshStatus();
|
|
4191
4309
|
}
|
|
4192
4310
|
|
|
4193
4311
|
function closeCuPanel() {
|
|
4194
|
-
|
|
4312
|
+
closeModalLayer('cu-overlay');
|
|
4195
4313
|
}
|
|
4196
4314
|
|
|
4197
4315
|
async function cuRefreshStatus() {
|
|
@@ -4358,12 +4476,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
4358
4476
|
let _wizItems = []; // items selected by user in step 2
|
|
4359
4477
|
|
|
4360
4478
|
function openSetupWizard() {
|
|
4361
|
-
|
|
4479
|
+
showModalLayer('setup-overlay');
|
|
4362
4480
|
_runStep1();
|
|
4363
4481
|
}
|
|
4364
4482
|
|
|
4365
4483
|
function closeSetupWizard() {
|
|
4366
|
-
|
|
4484
|
+
closeModalLayer('setup-overlay');
|
|
4367
4485
|
}
|
|
4368
4486
|
|
|
4369
4487
|
// Prevent click-through on overlay background
|
|
@@ -4678,12 +4796,12 @@ const chatViewport = document.getElementById('chat-viewport');
|
|
|
4678
4796
|
let _mcpCurrentTab = 'registry';
|
|
4679
4797
|
|
|
4680
4798
|
async function openMcpModal() {
|
|
4681
|
-
|
|
4799
|
+
showModalLayer('mcp-modal-overlay');
|
|
4682
4800
|
await renderMcpModal(_mcpCurrentTab);
|
|
4683
4801
|
}
|
|
4684
4802
|
|
|
4685
4803
|
function closeMcpModal() {
|
|
4686
|
-
|
|
4804
|
+
closeModalLayer('mcp-modal-overlay');
|
|
4687
4805
|
}
|
|
4688
4806
|
|
|
4689
4807
|
function switchMcpTab(tab, btn) {
|
package/static/sw.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// Lattice AI Service Worker — enables PWA install on Android/iOS
|
|
2
2
|
// Strategy: network-first for API, cache-first for static assets.
|
|
3
|
-
const CACHE = "ltcai-
|
|
3
|
+
const CACHE = "ltcai-v226";
|
|
4
4
|
const STATIC = [
|
|
5
5
|
"/",
|
|
6
6
|
"/workspace",
|
|
7
|
-
"/static/lattice-reference.css",
|
|
8
|
-
"/static/workspace.css",
|
|
9
7
|
"/static/css/tokens.css",
|
|
8
|
+
"/static/css/reference/base.css",
|
|
9
|
+
"/static/css/reference/chat.css",
|
|
10
|
+
"/static/css/responsive.css",
|
|
11
|
+
"/static/workspace.css",
|
|
10
12
|
"/static/scripts/chat.js",
|
|
11
13
|
"/static/scripts/admin.js",
|
|
12
14
|
"/static/scripts/graph.js",
|
package/static/workflows.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Workflow Designer — Lattice AI</title>
|
|
7
|
-
<script src="/static/scripts/ux.js?v=2.2.
|
|
8
|
-
<link rel="stylesheet" href="/static/css/tokens.css?v=2.2.
|
|
9
|
-
<link rel="stylesheet" href="/static/platform.css?v=2.2.
|
|
10
|
-
<link rel="stylesheet" href="/static/css/responsive.css?v=2.2.
|
|
7
|
+
<script src="/static/scripts/ux.js?v=2.2.7"></script>
|
|
8
|
+
<link rel="stylesheet" href="/static/css/tokens.css?v=2.2.7" />
|
|
9
|
+
<link rel="stylesheet" href="/static/platform.css?v=2.2.7" />
|
|
10
|
+
<link rel="stylesheet" href="/static/css/responsive.css?v=2.2.7" />
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<main>
|
package/static/workspace.css
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
--bg: var(--lt-bg, #f6f7f9);
|
|
6
6
|
--surface: var(--lt-surface, #ffffff);
|
|
7
7
|
--surface-2: var(--lt-surface-2, #f0f4f8);
|
|
8
|
+
--input: var(--lt-input, var(--surface));
|
|
8
9
|
--ink: var(--lt-ink, #101828);
|
|
9
10
|
--muted: var(--lt-muted, #667085);
|
|
10
11
|
--line: var(--lt-line, #d9e0e8);
|
|
@@ -199,8 +200,8 @@ h2 {
|
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
.secondary-action {
|
|
202
|
-
background: #e6efff;
|
|
203
|
-
color:
|
|
203
|
+
background: var(--accent-soft, #e6efff);
|
|
204
|
+
color: var(--blue);
|
|
204
205
|
padding: 0 12px;
|
|
205
206
|
font-weight: 700;
|
|
206
207
|
}
|
|
@@ -317,7 +318,7 @@ h2 {
|
|
|
317
318
|
|
|
318
319
|
.list-item {
|
|
319
320
|
border: 1px solid var(--line);
|
|
320
|
-
background:
|
|
321
|
+
background: var(--surface-2);
|
|
321
322
|
border-radius: 8px;
|
|
322
323
|
padding: 12px;
|
|
323
324
|
display: grid;
|
|
@@ -354,8 +355,9 @@ h2 {
|
|
|
354
355
|
.tag {
|
|
355
356
|
font-size: 11px;
|
|
356
357
|
font-weight: 800;
|
|
357
|
-
color:
|
|
358
|
-
background:
|
|
358
|
+
color: var(--ink);
|
|
359
|
+
background: var(--surface-2);
|
|
360
|
+
border: 1px solid var(--line);
|
|
359
361
|
border-radius: 999px;
|
|
360
362
|
padding: 3px 8px;
|
|
361
363
|
}
|
|
@@ -373,7 +375,7 @@ input, select, textarea {
|
|
|
373
375
|
border: 1px solid var(--line);
|
|
374
376
|
border-radius: 8px;
|
|
375
377
|
color: var(--ink);
|
|
376
|
-
background:
|
|
378
|
+
background: var(--input);
|
|
377
379
|
min-height: 38px;
|
|
378
380
|
padding: 9px 10px;
|
|
379
381
|
}
|
|
@@ -468,7 +470,7 @@ textarea {
|
|
|
468
470
|
top: 3px;
|
|
469
471
|
left: 3px;
|
|
470
472
|
border-radius: 50%;
|
|
471
|
-
background:
|
|
473
|
+
background: var(--surface);
|
|
472
474
|
transition: transform 160ms ease;
|
|
473
475
|
}
|
|
474
476
|
|
|
@@ -597,10 +599,10 @@ textarea {
|
|
|
597
599
|
.quickswitch-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
|
|
598
600
|
.switch-chip {
|
|
599
601
|
display: inline-flex; align-items: center; gap: 6px;
|
|
600
|
-
border: 1px solid var(--line); background:
|
|
602
|
+
border: 1px solid var(--line); background: var(--surface-2); color: var(--ink);
|
|
601
603
|
border-radius: 999px; padding: 6px 12px; font-weight: 700; font-size: 13px; cursor: pointer;
|
|
602
604
|
}
|
|
603
|
-
.switch-chip.active { border-color: var(--blue); background: #eef2ff; color: var(--blue); }
|
|
605
|
+
.switch-chip.active { border-color: var(--blue); background: var(--accent-soft, #eef2ff); color: var(--blue); }
|
|
604
606
|
|
|
605
607
|
/* Entity explorer */
|
|
606
608
|
.entity-card { text-align: left; cursor: pointer; width: 100%; font: inherit; }
|
|
@@ -615,10 +617,10 @@ textarea {
|
|
|
615
617
|
/* Skill marketplace tabs */
|
|
616
618
|
.tab-bar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
|
|
617
619
|
.tab {
|
|
618
|
-
border: 1px solid var(--line); background:
|
|
620
|
+
border: 1px solid var(--line); background: var(--surface-2); color: var(--muted);
|
|
619
621
|
border-radius: 999px; padding: 6px 14px; font-weight: 700; font-size: 13px; cursor: pointer;
|
|
620
622
|
}
|
|
621
|
-
.tab.active { border-color: var(--blue); background: #eef2ff; color: var(--blue); }
|
|
623
|
+
.tab.active { border-color: var(--blue); background: var(--accent-soft, #eef2ff); color: var(--blue); }
|
|
622
624
|
.tab-count {
|
|
623
625
|
display: inline-block; min-width: 16px; padding: 0 5px; margin-left: 4px;
|
|
624
626
|
border-radius: 999px; background: var(--red); color: #fff; font-size: 11px;
|
|
@@ -633,7 +635,7 @@ textarea {
|
|
|
633
635
|
}
|
|
634
636
|
.capability-card {
|
|
635
637
|
display: flex; align-items: center; gap: 10px;
|
|
636
|
-
border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; background:
|
|
638
|
+
border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; background: var(--surface-2);
|
|
637
639
|
}
|
|
638
640
|
.capability-card i { font-size: 18px; }
|
|
639
641
|
.capability-card.off i { color: var(--muted); }
|
|
@@ -650,7 +652,7 @@ textarea {
|
|
|
650
652
|
min-width: 0;
|
|
651
653
|
border: 1px solid var(--line);
|
|
652
654
|
border-radius: 8px;
|
|
653
|
-
background:
|
|
655
|
+
background: var(--surface-2);
|
|
654
656
|
padding: 14px;
|
|
655
657
|
display: grid;
|
|
656
658
|
gap: 7px;
|
|
@@ -691,7 +693,7 @@ textarea {
|
|
|
691
693
|
.skill-progress-track {
|
|
692
694
|
height: 7px;
|
|
693
695
|
border-radius: 999px;
|
|
694
|
-
background:
|
|
696
|
+
background: var(--surface-3, var(--surface-2));
|
|
695
697
|
overflow: hidden;
|
|
696
698
|
}
|
|
697
699
|
.skill-progress-track span {
|
|
@@ -725,3 +727,57 @@ textarea {
|
|
|
725
727
|
.small-action { min-height: 44px; }
|
|
726
728
|
.workspace-rail a { min-height: 44px; display: flex; align-items: center; }
|
|
727
729
|
}
|
|
730
|
+
|
|
731
|
+
:root[data-lt-theme="dark"] main {
|
|
732
|
+
background:
|
|
733
|
+
radial-gradient(circle at 80% 14%, rgba(167, 139, 250, 0.12), transparent 30%),
|
|
734
|
+
linear-gradient(180deg, var(--bg) 0%, #10122c 100%);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
:root[data-lt-theme="dark"] .workspace-band,
|
|
738
|
+
:root[data-lt-theme="dark"] .workspace-panel,
|
|
739
|
+
:root[data-lt-theme="dark"] .metric-card {
|
|
740
|
+
background: rgba(22, 22, 58, 0.92);
|
|
741
|
+
border-color: rgba(160, 170, 230, 0.22);
|
|
742
|
+
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.38);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
:root[data-lt-theme="dark"] input,
|
|
746
|
+
:root[data-lt-theme="dark"] select,
|
|
747
|
+
:root[data-lt-theme="dark"] textarea,
|
|
748
|
+
:root[data-lt-theme="dark"] .list-item,
|
|
749
|
+
:root[data-lt-theme="dark"] .health-card,
|
|
750
|
+
:root[data-lt-theme="dark"] .capability-card,
|
|
751
|
+
:root[data-lt-theme="dark"] .switch-chip,
|
|
752
|
+
:root[data-lt-theme="dark"] .tab,
|
|
753
|
+
:root[data-lt-theme="dark"] .tag {
|
|
754
|
+
background: rgba(255, 255, 255, 0.06);
|
|
755
|
+
border-color: rgba(160, 170, 230, 0.22);
|
|
756
|
+
color: var(--ink);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
:root[data-lt-theme="dark"] input::placeholder,
|
|
760
|
+
:root[data-lt-theme="dark"] textarea::placeholder {
|
|
761
|
+
color: rgba(226, 232, 255, 0.48);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
:root[data-lt-theme="dark"] .status-pill,
|
|
765
|
+
:root[data-lt-theme="dark"] .workspace-role-pill {
|
|
766
|
+
background: rgba(255, 255, 255, 0.10);
|
|
767
|
+
color: var(--blue);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
:root[data-lt-theme="dark"] .status-complete {
|
|
771
|
+
background: rgba(52, 211, 153, 0.16);
|
|
772
|
+
color: #86efac;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
:root[data-lt-theme="dark"] .status-running {
|
|
776
|
+
background: rgba(251, 191, 36, 0.16);
|
|
777
|
+
color: #fbbf24;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
:root[data-lt-theme="dark"] .status-failed {
|
|
781
|
+
background: rgba(244, 113, 113, 0.16);
|
|
782
|
+
color: #fca5a5;
|
|
783
|
+
}
|