ltcai 2.2.7 → 3.1.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.
- package/README.md +72 -34
- package/docs/CHANGELOG.md +119 -0
- package/docs/V3_BACKEND_ARCHITECTURE.md +138 -0
- package/docs/V3_FRONTEND.md +139 -0
- package/knowledge_graph.py +649 -21
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/admin.py +47 -0
- package/latticeai/api/agents.py +54 -31
- package/latticeai/api/auth.py +5 -2
- package/latticeai/api/chat.py +10 -2
- package/latticeai/api/search.py +240 -0
- package/latticeai/api/static_routes.py +11 -2
- package/latticeai/core/config.py +18 -0
- package/latticeai/core/embedding_providers.py +625 -0
- package/latticeai/core/local_embeddings.py +86 -0
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/server_app.py +65 -1
- package/latticeai/services/agent_runtime.py +245 -0
- package/latticeai/services/search_service.py +346 -0
- package/package.json +13 -6
- package/scripts/build_v3_assets.mjs +164 -0
- package/scripts/capture/README.md +28 -0
- package/scripts/capture/capture_enterprise.js +8 -0
- package/scripts/capture/capture_graph.js +8 -0
- package/scripts/capture/capture_onboarding.js +8 -0
- package/scripts/capture/capture_page.js +43 -0
- package/scripts/capture/capture_release_media.js +125 -0
- package/scripts/capture/capture_skills.js +8 -0
- package/scripts/capture/capture_workspace.js +8 -0
- package/scripts/generate_diagrams.py +513 -0
- package/scripts/lint_v3.mjs +33 -0
- package/scripts/release-0.3.1.sh +105 -0
- package/scripts/take_screenshots.js +69 -0
- package/scripts/validate_release_artifacts.py +167 -0
- package/static/account.html +9 -9
- package/static/activity.html +4 -4
- package/static/admin.html +8 -8
- package/static/agents.html +4 -4
- package/static/chat.html +10 -10
- package/static/css/reference/account.css +137 -1
- package/static/css/reference/chat.css +31 -37
- package/static/css/responsive.css +42 -0
- package/static/css/tokens.5a595671.css +260 -0
- package/static/css/tokens.css +125 -130
- package/static/graph.html +9 -9
- package/static/manifest.json +3 -3
- package/static/plugins.html +4 -4
- package/static/scripts/account.js +4 -4
- package/static/scripts/chat.js +40 -8
- package/static/scripts/workspace.js +78 -0
- package/static/sw.js +3 -1
- package/static/v3/asset-manifest.json +47 -0
- package/static/v3/css/lattice.base.css +128 -0
- package/static/v3/css/lattice.base.e4cdd05d.css +128 -0
- package/static/v3/css/lattice.components.011e988b.css +447 -0
- package/static/v3/css/lattice.components.css +447 -0
- package/static/v3/css/lattice.shell.4920f42d.css +407 -0
- package/static/v3/css/lattice.shell.css +407 -0
- package/static/v3/css/lattice.tokens.c597ff81.css +132 -0
- package/static/v3/css/lattice.tokens.css +132 -0
- package/static/v3/css/lattice.views.3ee19d4e.css +277 -0
- package/static/v3/css/lattice.views.css +277 -0
- package/static/v3/index.html +69 -0
- package/static/v3/js/app.46fb61d9.js +26 -0
- package/static/v3/js/app.js +26 -0
- package/static/v3/js/core/api.22a41d42.js +344 -0
- package/static/v3/js/core/api.js +344 -0
- package/static/v3/js/core/components.4c83e0a9.js +222 -0
- package/static/v3/js/core/components.js +222 -0
- package/static/v3/js/core/dom.a2773eb0.js +148 -0
- package/static/v3/js/core/dom.js +148 -0
- package/static/v3/js/core/router.584570f2.js +37 -0
- package/static/v3/js/core/router.js +37 -0
- package/static/v3/js/core/routes.f935dd50.js +78 -0
- package/static/v3/js/core/routes.js +78 -0
- package/static/v3/js/core/shell.1b6199d6.js +363 -0
- package/static/v3/js/core/shell.js +363 -0
- package/static/v3/js/core/store.34ebd5e6.js +113 -0
- package/static/v3/js/core/store.js +113 -0
- package/static/v3/js/views/admin-audit.660a1fb1.js +185 -0
- package/static/v3/js/views/admin-audit.js +185 -0
- package/static/v3/js/views/admin-permissions.a7ae5f09.js +177 -0
- package/static/v3/js/views/admin-permissions.js +177 -0
- package/static/v3/js/views/admin-policies.3658fd86.js +102 -0
- package/static/v3/js/views/admin-policies.js +102 -0
- package/static/v3/js/views/admin-private-vpc.7d342d36.js +135 -0
- package/static/v3/js/views/admin-private-vpc.js +135 -0
- package/static/v3/js/views/admin-security.07c66b72.js +180 -0
- package/static/v3/js/views/admin-security.js +180 -0
- package/static/v3/js/views/admin-users.03bac88c.js +168 -0
- package/static/v3/js/views/admin-users.js +168 -0
- package/static/v3/js/views/agents.14e48bdd.js +193 -0
- package/static/v3/js/views/agents.js +193 -0
- package/static/v3/js/views/chat.718144ce.js +449 -0
- package/static/v3/js/views/chat.js +449 -0
- package/static/v3/js/views/files.4935197e.js +186 -0
- package/static/v3/js/views/files.js +186 -0
- package/static/v3/js/views/home.cdde3b32.js +119 -0
- package/static/v3/js/views/home.js +119 -0
- package/static/v3/js/views/hybrid-search.b22b97e0.js +195 -0
- package/static/v3/js/views/hybrid-search.js +195 -0
- package/static/v3/js/views/knowledge-graph.a14ea7e7.js +237 -0
- package/static/v3/js/views/knowledge-graph.js +237 -0
- package/static/v3/js/views/models.a1ffa147.js +256 -0
- package/static/v3/js/views/models.js +256 -0
- package/static/v3/js/views/my-computer.1b2ff621.js +237 -0
- package/static/v3/js/views/my-computer.js +237 -0
- package/static/v3/js/views/pipeline.c522f1ce.js +157 -0
- package/static/v3/js/views/pipeline.js +157 -0
- package/static/v3/js/views/settings.4f777210.js +250 -0
- package/static/v3/js/views/settings.js +250 -0
- package/static/workflows.html +4 -4
- package/static/workspace.css +340 -2
- package/static/workspace.html +43 -24
- package/docs/images/tmp_frames/frame_00.png +0 -0
- package/docs/images/tmp_frames/frame_01.png +0 -0
- package/docs/images/tmp_frames/frame_02.png +0 -0
- package/docs/images/tmp_frames/frame_03.png +0 -0
- package/docs/images/tmp_frames/hero_00.png +0 -0
- package/docs/images/tmp_frames/hero_01.png +0 -0
- package/docs/images/tmp_frames/hero_02.png +0 -0
- package/docs/images/tmp_frames/hero_03.png +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* Syntax-check every Lattice AI v3 frontend ES module (node --check, ESM auto-detect).
|
|
3
|
+
* Exits non-zero on the first failure so it can gate `npm run lint`. */
|
|
4
|
+
import { readdirSync, statSync } from "node:fs";
|
|
5
|
+
import { join, dirname } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
|
|
9
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..", "static", "v3", "js");
|
|
10
|
+
|
|
11
|
+
function walk(dir) {
|
|
12
|
+
const out = [];
|
|
13
|
+
for (const name of readdirSync(dir)) {
|
|
14
|
+
const p = join(dir, name);
|
|
15
|
+
if (statSync(p).isDirectory()) out.push(...walk(p));
|
|
16
|
+
else if (name.endsWith(".js")) out.push(p);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const files = walk(root).sort();
|
|
22
|
+
let failed = 0;
|
|
23
|
+
for (const file of files) {
|
|
24
|
+
const r = spawnSync(process.execPath, ["--check", file], { encoding: "utf8" });
|
|
25
|
+
if (r.status === 0) {
|
|
26
|
+
console.log(`ok ${file.replace(root, "static/v3/js")}`);
|
|
27
|
+
} else {
|
|
28
|
+
failed++;
|
|
29
|
+
console.error(`FAIL ${file.replace(root, "static/v3/js")}\n${r.stderr || r.stdout}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
console.log(`\nv3 frontend: ${files.length - failed}/${files.length} modules pass`);
|
|
33
|
+
process.exit(failed ? 1 : 0);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Release 0.3.1 — finalize commit + push.
|
|
3
|
+
#
|
|
4
|
+
# 이 스크립트는 sandbox 권한 제약으로 Claude가 마지막 git 명령을 끝내지 못했기 때문에
|
|
5
|
+
# 사용자 본인 터미널에서 한 번 실행하기 위한 마무리 스크립트입니다.
|
|
6
|
+
#
|
|
7
|
+
# 사전 조건:
|
|
8
|
+
# - 5개 피드백을 반영한 코드/문서/테스트/CI 변경이 워킹트리에 적용되어 있음
|
|
9
|
+
# - 빌드 산출물(dist/ltcai-0.3.1*, ltcai-0.3.1.tgz)이 생성되어 있음 (gitignore라 commit에는 안 들어감)
|
|
10
|
+
#
|
|
11
|
+
# 사용법:
|
|
12
|
+
# bash scripts/release-0.3.1.sh
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
cd "$(dirname "$0")/.."
|
|
17
|
+
|
|
18
|
+
# 1. stale lock 정리
|
|
19
|
+
if [ -f .git/index.lock ]; then
|
|
20
|
+
rm -f .git/index.lock
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# 2. 변경된 파일 add
|
|
24
|
+
git add -A
|
|
25
|
+
|
|
26
|
+
# 3. 어떤 게 들어가는지 확인용 짧은 요약
|
|
27
|
+
echo "--- staged summary ---"
|
|
28
|
+
git diff --cached --stat | tail -40
|
|
29
|
+
|
|
30
|
+
# 4. commit
|
|
31
|
+
git commit -m "Release 0.3.1 — model loading reliability + auto graph + security console
|
|
32
|
+
|
|
33
|
+
External review (5 items) reflected:
|
|
34
|
+
|
|
35
|
+
1. lattice_ai_model_recommend_download_load_issue.txt
|
|
36
|
+
- latticeai/core/model_resolution.py: ModelResolution unifies
|
|
37
|
+
input_id / engine / resolved_model / download_id / load_id /
|
|
38
|
+
expected_current across all stages.
|
|
39
|
+
- prepare_and_load_model() + /engines/prepare-model/stream now share
|
|
40
|
+
the same ModelResolution; LM Studio instance_id is reconciled via
|
|
41
|
+
resolution.update_after_load().
|
|
42
|
+
|
|
43
|
+
2. lattice_ai_manual_model_select_auto_download_load_fix.txt
|
|
44
|
+
- server.py runs _smoke_test_loaded_model() right after load and
|
|
45
|
+
returns ready_to_chat / compatibility_status / smoke_test in the
|
|
46
|
+
response. Cloud models are skipped to avoid user cost.
|
|
47
|
+
- /models response now carries engine_options + compat_profiles.
|
|
48
|
+
- chat.js trusts response.current (not the clicked model id);
|
|
49
|
+
surfaces compatibility warnings; selectModelByCard() helper.
|
|
50
|
+
|
|
51
|
+
3. lattice_ai_model_compat_fast_path.txt
|
|
52
|
+
- latticeai/core/model_compat.py: family detection, family profiles
|
|
53
|
+
(stop tokens, disable_draft, postprocess, generation params),
|
|
54
|
+
fast_postprocess, validate_smoke_response, compat_cache. Fast /
|
|
55
|
+
Slow / Recovery path structure.
|
|
56
|
+
|
|
57
|
+
4. lattice_ai_auto_graph_direction.txt
|
|
58
|
+
- latticeai/core/graph_curator.py: topic extraction → alias
|
|
59
|
+
clustering (auto-merge) → promotion (with secret/dup/min-sources
|
|
60
|
+
filters) → thread story edges → behavior-signal curation.
|
|
61
|
+
|
|
62
|
+
5. lattice_ai_admin_security_dashboard_review.txt
|
|
63
|
+
- latticeai/api/security_dashboard.py: 11 endpoints under
|
|
64
|
+
/admin/security/* — overview / users / events / event detail /
|
|
65
|
+
conversation summary+raw / files / file detail+content / raw /
|
|
66
|
+
export. Hard-secret redaction enforced on every response;
|
|
67
|
+
admin_view_sensitive_raw audit event recorded for raw access.
|
|
68
|
+
- admin.html + admin.js: AI Security & Audit Command Center panel
|
|
69
|
+
with Security Overview cards, User Risk stacked bar, sensitive-
|
|
70
|
+
type donut, drill-down, raw explorer, JSON/CSV/XLSX/PDF export.
|
|
71
|
+
|
|
72
|
+
Tests / CI:
|
|
73
|
+
- 28 new unit tests under tests/unit/test_{model_compat,
|
|
74
|
+
model_resolution,graph_curator,security_dashboard}.py — all passing.
|
|
75
|
+
- .github/workflows/ci.yml syntax-check extended for new modules.
|
|
76
|
+
- .github/workflows/release.yml added — tag push v* triggers PyPI /
|
|
77
|
+
npm / VS Code Marketplace / Open VSX publish. Secrets:
|
|
78
|
+
PYPI_TOKEN, NPM_TOKEN, VSCE_PAT, OVSX_TOKEN (empty ones auto-skip).
|
|
79
|
+
|
|
80
|
+
Version bumps:
|
|
81
|
+
- package.json 0.3.0 → 0.3.1
|
|
82
|
+
- pyproject.toml 0.3.0 → 0.3.1
|
|
83
|
+
- vscode-extension/package.json 0.3.0 → 0.3.1
|
|
84
|
+
|
|
85
|
+
Docs:
|
|
86
|
+
- docs/CHANGELOG.md: 0.3.1 section
|
|
87
|
+
- README.md: 'What's new in 0.3.1'
|
|
88
|
+
- RELEASE.md: auto-publish via tag flow"
|
|
89
|
+
|
|
90
|
+
# 5. push to origin/main
|
|
91
|
+
git push origin main
|
|
92
|
+
|
|
93
|
+
# 6. annotated release tag (CI release.yml triggers on v* tags)
|
|
94
|
+
git tag -a v0.3.1 -m "Lattice AI 0.3.1 — model loading reliability + auto graph + security console"
|
|
95
|
+
git push origin v0.3.1
|
|
96
|
+
|
|
97
|
+
echo ""
|
|
98
|
+
echo "✅ Release 0.3.1 pushed."
|
|
99
|
+
echo ""
|
|
100
|
+
echo "다음 단계:"
|
|
101
|
+
echo " 1. GitHub → Repository Settings → Secrets and variables → Actions에"
|
|
102
|
+
echo " PYPI_TOKEN / NPM_TOKEN / VSCE_PAT / OVSX_TOKEN 을 등록."
|
|
103
|
+
echo " 2. 등록된 secret이 있는 채널은 .github/workflows/release.yml의 v0.3.1"
|
|
104
|
+
echo " trigger로 자동 publish 됩니다. 미등록 채널은 자동 skip."
|
|
105
|
+
echo " 3. 수동 publish가 필요하면 RELEASE.md 참고."
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lattice AI — automated screenshot capture
|
|
3
|
+
* Usage: SESSION_TOKEN=xxx node scripts/take_screenshots.js
|
|
4
|
+
*/
|
|
5
|
+
let playwright;
|
|
6
|
+
try { playwright = require('playwright'); } catch(e) {
|
|
7
|
+
playwright = require('/tmp/node_modules/playwright');
|
|
8
|
+
}
|
|
9
|
+
const { chromium } = playwright;
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
|
|
13
|
+
const BASE = 'http://localhost:4825';
|
|
14
|
+
const OUT = path.join(__dirname, '..', 'docs', 'images');
|
|
15
|
+
const TOKEN = process.env.SESSION_TOKEN || '';
|
|
16
|
+
fs.mkdirSync(OUT, { recursive: true });
|
|
17
|
+
|
|
18
|
+
const PAGES = [
|
|
19
|
+
{ name: 'chat', url: `${BASE}/`, wait: 3500 },
|
|
20
|
+
{ name: 'admin', url: `${BASE}/admin`, wait: 3000 },
|
|
21
|
+
{ name: 'graph', url: `${BASE}/graph`, wait: 3500 },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
(async () => {
|
|
25
|
+
const browser = await chromium.launch({ headless: true });
|
|
26
|
+
const ctx = await browser.newContext({
|
|
27
|
+
viewport: { width: 1440, height: 900 },
|
|
28
|
+
deviceScaleFactor: 2,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Inject session cookie so we skip the login page
|
|
32
|
+
if (TOKEN) {
|
|
33
|
+
await ctx.addCookies([{
|
|
34
|
+
name: 'session_token',
|
|
35
|
+
value: TOKEN,
|
|
36
|
+
domain: 'localhost',
|
|
37
|
+
path: '/',
|
|
38
|
+
httpOnly: true,
|
|
39
|
+
secure: false,
|
|
40
|
+
}]);
|
|
41
|
+
console.log('🍪 Session cookie injected');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const pg of PAGES) {
|
|
45
|
+
const page = await ctx.newPage();
|
|
46
|
+
console.log(`📸 ${pg.name} → ${pg.url}`);
|
|
47
|
+
try {
|
|
48
|
+
await page.goto(pg.url, { waitUntil: 'networkidle', timeout: 20000 });
|
|
49
|
+
await page.waitForTimeout(pg.wait);
|
|
50
|
+
|
|
51
|
+
// Dismiss any open modals
|
|
52
|
+
await page.evaluate(() => {
|
|
53
|
+
document.querySelectorAll('.modal-backdrop, [data-bs-backdrop], dialog[open]')
|
|
54
|
+
.forEach(el => { el.style.display = 'none'; });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const outPath = path.join(OUT, `screenshot-${pg.name}.png`);
|
|
58
|
+
await page.screenshot({ path: outPath, fullPage: false });
|
|
59
|
+
console.log(` ✅ → ${outPath}`);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error(` ❌ ${pg.name}: ${e.message}`);
|
|
62
|
+
} finally {
|
|
63
|
+
await page.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await browser.close();
|
|
68
|
+
console.log('\n✅ Done!');
|
|
69
|
+
})();
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate release artifacts for a single, explicit version.
|
|
3
|
+
|
|
4
|
+
The release workflow must never upload ``dist/*`` with a glob: that bundles
|
|
5
|
+
*every* historical build and risks shipping a stale version. This validator is
|
|
6
|
+
the guard rail. It checks that exactly the expected 1.1.0-style artifacts exist
|
|
7
|
+
for the requested version, that no version string is mismatched, and (best
|
|
8
|
+
effort) that the VSIX actually contains the compiled extension entrypoint.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python scripts/validate_release_artifacts.py 1.1.0
|
|
12
|
+
python scripts/validate_release_artifacts.py 1.1.0 --require-vsix
|
|
13
|
+
python scripts/validate_release_artifacts.py 1.1.0 --dist dist --json
|
|
14
|
+
|
|
15
|
+
Exit code is non-zero on any failure so CI can fail fast.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import re
|
|
23
|
+
import sys
|
|
24
|
+
import zipfile
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Dict, List, Optional
|
|
27
|
+
|
|
28
|
+
SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+([.-][0-9A-Za-z.]+)?$")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _expected_names(version: str) -> Dict[str, str]:
|
|
32
|
+
return {
|
|
33
|
+
"wheel": f"ltcai-{version}-py3-none-any.whl",
|
|
34
|
+
"sdist": f"ltcai-{version}.tar.gz",
|
|
35
|
+
"vsix": f"ltcai-{version}.vsix",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _vsix_has_entrypoint(path: Path) -> bool:
|
|
40
|
+
"""True if the VSIX contains the compiled extension entrypoint."""
|
|
41
|
+
try:
|
|
42
|
+
with zipfile.ZipFile(path) as zf:
|
|
43
|
+
names = zf.namelist()
|
|
44
|
+
except (zipfile.BadZipFile, OSError):
|
|
45
|
+
return False
|
|
46
|
+
return any(name.endswith("extension/out/extension.js") for name in names)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _vsix_version(path: Path) -> Optional[str]:
|
|
50
|
+
try:
|
|
51
|
+
with zipfile.ZipFile(path) as zf:
|
|
52
|
+
for name in zf.namelist():
|
|
53
|
+
if name.endswith("extension/package.json"):
|
|
54
|
+
data = json.loads(zf.read(name).decode("utf-8"))
|
|
55
|
+
return str(data.get("version") or "")
|
|
56
|
+
except Exception:
|
|
57
|
+
return None
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def validate(
|
|
62
|
+
version: str,
|
|
63
|
+
dist_dir: Path,
|
|
64
|
+
*,
|
|
65
|
+
require_vsix: bool,
|
|
66
|
+
require_tgz: bool,
|
|
67
|
+
) -> Dict[str, object]:
|
|
68
|
+
errors: List[str] = []
|
|
69
|
+
warnings: List[str] = []
|
|
70
|
+
found: Dict[str, object] = {}
|
|
71
|
+
|
|
72
|
+
if not SEMVER_RE.match(version):
|
|
73
|
+
errors.append(f"version '{version}' is not a valid semantic version")
|
|
74
|
+
|
|
75
|
+
if not dist_dir.is_dir():
|
|
76
|
+
errors.append(f"dist directory not found: {dist_dir}")
|
|
77
|
+
return {"version": version, "ok": False, "errors": errors, "warnings": warnings, "found": found}
|
|
78
|
+
|
|
79
|
+
expected = _expected_names(version)
|
|
80
|
+
|
|
81
|
+
# Required Python artifacts.
|
|
82
|
+
for key in ("wheel", "sdist"):
|
|
83
|
+
artifact = dist_dir / expected[key]
|
|
84
|
+
if artifact.is_file():
|
|
85
|
+
found[key] = str(artifact)
|
|
86
|
+
else:
|
|
87
|
+
errors.append(f"missing {key}: {artifact.name}")
|
|
88
|
+
|
|
89
|
+
# VSIX: required only when asked, but validate contents when present.
|
|
90
|
+
vsix = dist_dir / expected["vsix"]
|
|
91
|
+
if vsix.is_file():
|
|
92
|
+
found["vsix"] = str(vsix)
|
|
93
|
+
if not _vsix_has_entrypoint(vsix):
|
|
94
|
+
errors.append(f"{vsix.name} is missing extension/out/extension.js (compile step skipped?)")
|
|
95
|
+
vsix_ver = _vsix_version(vsix)
|
|
96
|
+
if vsix_ver and vsix_ver != version:
|
|
97
|
+
errors.append(f"{vsix.name} internal version '{vsix_ver}' != expected '{version}'")
|
|
98
|
+
elif require_vsix:
|
|
99
|
+
errors.append(f"missing vsix: {vsix.name}")
|
|
100
|
+
|
|
101
|
+
# npm pack tarball lives at repo root, not dist/.
|
|
102
|
+
if require_tgz:
|
|
103
|
+
tgz = dist_dir.parent / f"ltcai-{version}.tgz"
|
|
104
|
+
if tgz.is_file():
|
|
105
|
+
found["tgz"] = str(tgz)
|
|
106
|
+
else:
|
|
107
|
+
warnings.append(f"npm tarball not found: {tgz.name} (run `npm pack`)")
|
|
108
|
+
|
|
109
|
+
# Guard against stale-version mixing: warn loudly about other-version builds
|
|
110
|
+
# so a `dist/*` glob upload is obviously unsafe.
|
|
111
|
+
other_versions = set()
|
|
112
|
+
for item in dist_dir.glob("ltcai-*"):
|
|
113
|
+
# Capture just the semver core (e.g. 1.1.0), not packaging suffixes
|
|
114
|
+
# like -py3-none-any.whl / .tar.gz / .vsix.
|
|
115
|
+
m = re.match(r"ltcai-(\d+\.\d+\.\d+)(?:[-.]|$)", item.name)
|
|
116
|
+
if m and m.group(1) != version:
|
|
117
|
+
other_versions.add(m.group(1))
|
|
118
|
+
if other_versions:
|
|
119
|
+
warnings.append(
|
|
120
|
+
"dist/ also contains other versions "
|
|
121
|
+
f"{sorted(other_versions)} — NEVER upload with a `dist/*` glob; "
|
|
122
|
+
f"upload only the explicit {version} filenames."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
"version": version,
|
|
127
|
+
"ok": not errors,
|
|
128
|
+
"errors": errors,
|
|
129
|
+
"warnings": warnings,
|
|
130
|
+
"found": found,
|
|
131
|
+
"expected": expected,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
136
|
+
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
137
|
+
parser.add_argument("version", help="exact version to validate, e.g. 1.1.0")
|
|
138
|
+
parser.add_argument("--dist", default="dist", help="dist directory (default: dist)")
|
|
139
|
+
parser.add_argument("--require-vsix", action="store_true", help="fail if the VSIX is absent")
|
|
140
|
+
parser.add_argument("--require-tgz", action="store_true", help="check for npm pack tarball at repo root")
|
|
141
|
+
parser.add_argument("--json", action="store_true", help="emit machine-readable JSON")
|
|
142
|
+
args = parser.parse_args(argv)
|
|
143
|
+
|
|
144
|
+
result = validate(
|
|
145
|
+
args.version,
|
|
146
|
+
Path(args.dist),
|
|
147
|
+
require_vsix=args.require_vsix,
|
|
148
|
+
require_tgz=args.require_tgz,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if args.json:
|
|
152
|
+
print(json.dumps(result, indent=2))
|
|
153
|
+
else:
|
|
154
|
+
status = "OK" if result["ok"] else "FAILED"
|
|
155
|
+
print(f"Release artifact validation for v{result['version']}: {status}")
|
|
156
|
+
for key, path in result["found"].items():
|
|
157
|
+
print(f" found {key}: {Path(path).name}")
|
|
158
|
+
for warning in result["warnings"]:
|
|
159
|
+
print(f" WARN: {warning}")
|
|
160
|
+
for error in result["errors"]:
|
|
161
|
+
print(f" ERROR: {error}")
|
|
162
|
+
|
|
163
|
+
return 0 if result["ok"] else 1
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
if __name__ == "__main__":
|
|
167
|
+
raise SystemExit(main())
|
package/static/account.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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>Lattice AI</title>
|
|
7
|
-
<script src="/static/scripts/ux.js
|
|
7
|
+
<script src="/static/scripts/ux.js"></script>
|
|
8
8
|
<link rel="manifest" href="/manifest.json">
|
|
9
9
|
<meta name="theme-color" content="#f3ecff">
|
|
10
10
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
15
15
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
|
|
16
16
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
|
17
|
-
<link rel="stylesheet" href="/static/css/tokens.css
|
|
18
|
-
<link rel="stylesheet" href="/static/css/reference/base.css
|
|
19
|
-
<link rel="stylesheet" href="/static/css/reference/account.css
|
|
20
|
-
<link rel="stylesheet" href="/static/css/reference/admin.css
|
|
21
|
-
<link rel="stylesheet" href="/static/css/reference/graph.css
|
|
22
|
-
<link rel="stylesheet" href="/static/css/reference/chat.css
|
|
23
|
-
<link rel="stylesheet" href="/static/css/responsive.css
|
|
17
|
+
<link rel="stylesheet" href="/static/css/tokens.css">
|
|
18
|
+
<link rel="stylesheet" href="/static/css/reference/base.css">
|
|
19
|
+
<link rel="stylesheet" href="/static/css/reference/account.css">
|
|
20
|
+
<link rel="stylesheet" href="/static/css/reference/admin.css">
|
|
21
|
+
<link rel="stylesheet" href="/static/css/reference/graph.css">
|
|
22
|
+
<link rel="stylesheet" href="/static/css/reference/chat.css">
|
|
23
|
+
<link rel="stylesheet" href="/static/css/responsive.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body class="lattice-ref-auth">
|
|
26
26
|
<div class="orb orb-1"></div>
|
|
@@ -110,6 +110,6 @@
|
|
|
110
110
|
<a href="#" onclick="return false;" id="privacy-link">개인정보 처리방침</a>
|
|
111
111
|
</footer>
|
|
112
112
|
|
|
113
|
-
<script src="/static/scripts/account.js
|
|
113
|
+
<script src="/static/scripts/account.js"></script>
|
|
114
114
|
</body>
|
|
115
115
|
</html>
|
package/static/activity.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>Realtime Activity — Lattice AI</title>
|
|
7
|
-
<script src="/static/scripts/ux.js
|
|
8
|
-
<link rel="stylesheet" href="/static/css/tokens.css
|
|
9
|
-
<link rel="stylesheet" href="/static/platform.css
|
|
10
|
-
<link rel="stylesheet" href="/static/css/responsive.css
|
|
7
|
+
<script src="/static/scripts/ux.js"></script>
|
|
8
|
+
<link rel="stylesheet" href="/static/css/tokens.css" />
|
|
9
|
+
<link rel="stylesheet" href="/static/platform.css" />
|
|
10
|
+
<link rel="stylesheet" href="/static/css/responsive.css" />
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<main>
|
package/static/admin.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
|
|
7
7
|
<title>Lattice AI Admin</title>
|
|
8
|
-
<script src="/static/scripts/ux.js
|
|
8
|
+
<script src="/static/scripts/ux.js"></script>
|
|
9
9
|
<link rel="manifest" href="/manifest.json">
|
|
10
10
|
<meta name="theme-color" content="#f3ecff">
|
|
11
11
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
16
16
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
|
|
17
17
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
|
18
|
-
<link rel="stylesheet" href="/static/css/tokens.css
|
|
19
|
-
<link rel="stylesheet" href="/static/css/reference/base.css
|
|
20
|
-
<link rel="stylesheet" href="/static/css/reference/account.css
|
|
21
|
-
<link rel="stylesheet" href="/static/css/reference/admin.css
|
|
22
|
-
<link rel="stylesheet" href="/static/css/reference/graph.css
|
|
23
|
-
<link rel="stylesheet" href="/static/css/reference/chat.css
|
|
24
|
-
<link rel="stylesheet" href="/static/css/responsive.css
|
|
18
|
+
<link rel="stylesheet" href="/static/css/tokens.css">
|
|
19
|
+
<link rel="stylesheet" href="/static/css/reference/base.css">
|
|
20
|
+
<link rel="stylesheet" href="/static/css/reference/account.css">
|
|
21
|
+
<link rel="stylesheet" href="/static/css/reference/admin.css">
|
|
22
|
+
<link rel="stylesheet" href="/static/css/reference/graph.css">
|
|
23
|
+
<link rel="stylesheet" href="/static/css/reference/chat.css">
|
|
24
|
+
<link rel="stylesheet" href="/static/css/responsive.css">
|
|
25
25
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
26
26
|
</head>
|
|
27
27
|
|
package/static/agents.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>Multi-Agent Runtime — Lattice AI</title>
|
|
7
|
-
<script src="/static/scripts/ux.js
|
|
8
|
-
<link rel="stylesheet" href="/static/css/tokens.css
|
|
9
|
-
<link rel="stylesheet" href="/static/platform.css
|
|
10
|
-
<link rel="stylesheet" href="/static/css/responsive.css
|
|
7
|
+
<script src="/static/scripts/ux.js"></script>
|
|
8
|
+
<link rel="stylesheet" href="/static/css/tokens.css" />
|
|
9
|
+
<link rel="stylesheet" href="/static/platform.css" />
|
|
10
|
+
<link rel="stylesheet" href="/static/css/responsive.css" />
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<main>
|
package/static/chat.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
|
|
7
7
|
<title>Lattice AI — All-in-One Multimodal Workspace</title>
|
|
8
|
-
<script src="/static/scripts/ux.js
|
|
8
|
+
<script src="/static/scripts/ux.js"></script>
|
|
9
9
|
|
|
10
10
|
<!-- PWA -->
|
|
11
11
|
<link rel="manifest" href="/manifest.json">
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
25
25
|
|
|
26
26
|
<!-- ── Setup Wizard Styles ──────────────────────────────────────────── -->
|
|
27
|
-
<link rel="stylesheet" href="/static/css/tokens.css
|
|
28
|
-
<link rel="stylesheet" href="/static/css/reference/base.css
|
|
29
|
-
<link rel="stylesheet" href="/static/css/reference/account.css
|
|
30
|
-
<link rel="stylesheet" href="/static/css/reference/admin.css
|
|
31
|
-
<link rel="stylesheet" href="/static/css/reference/graph.css
|
|
32
|
-
<link rel="stylesheet" href="/static/css/reference/chat.css
|
|
33
|
-
<link rel="stylesheet" href="/static/css/responsive.css
|
|
27
|
+
<link rel="stylesheet" href="/static/css/tokens.css">
|
|
28
|
+
<link rel="stylesheet" href="/static/css/reference/base.css">
|
|
29
|
+
<link rel="stylesheet" href="/static/css/reference/account.css">
|
|
30
|
+
<link rel="stylesheet" href="/static/css/reference/admin.css">
|
|
31
|
+
<link rel="stylesheet" href="/static/css/reference/graph.css">
|
|
32
|
+
<link rel="stylesheet" href="/static/css/reference/chat.css">
|
|
33
|
+
<link rel="stylesheet" href="/static/css/responsive.css">
|
|
34
34
|
</head>
|
|
35
35
|
|
|
36
36
|
<body class="lattice-ref-chat">
|
|
@@ -747,7 +747,7 @@
|
|
|
747
747
|
<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px">AI 자동 작업</div>
|
|
748
748
|
<textarea id="cu-task-input" placeholder="예: Safari 열고 apple.com 접속해줘 예: 현재 화면에서 버튼 찾아서 클릭해줘" style="width:100%;background:var(--surface-3);border:1px solid var(--border);border-radius:8px;padding:10px;color:var(--text);font-size:13px;resize:vertical;min-height:80px;font-family:inherit;outline:none"></textarea>
|
|
749
749
|
<div style="display:flex;gap:6px;margin-top:6px">
|
|
750
|
-
<button id="cu-run-btn" onclick="cuRunAgent()" style="flex:1;background:
|
|
750
|
+
<button id="cu-run-btn" onclick="cuRunAgent()" style="flex:1;background:var(--accent);border:none;color:#fff;padding:8px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px"><i class="ti ti-player-play"></i> 실행</button>
|
|
751
751
|
<button id="cu-stop-btn" onclick="cuStopAgent()" style="background:rgba(248,113,113,0.12);border:1px solid rgba(248,113,113,0.25);color:var(--danger);padding:8px 14px;border-radius:8px;font-size:13px;cursor:pointer;display:none"><i class="ti ti-player-stop"></i></button>
|
|
752
752
|
</div>
|
|
753
753
|
</div>
|
|
@@ -838,7 +838,7 @@
|
|
|
838
838
|
</div>
|
|
839
839
|
|
|
840
840
|
|
|
841
|
-
<script src="/static/scripts/chat.js
|
|
841
|
+
<script src="/static/scripts/chat.js"></script>
|
|
842
842
|
</body>
|
|
843
843
|
|
|
844
844
|
</html>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Lattice AI — account / auth page (account.html, body.lattice-ref-auth). Token-native. */
|
|
2
2
|
/* ============================================================
|
|
3
3
|
ACCOUNT / AUTH PAGE (account.html)
|
|
4
|
-
|
|
4
|
+
Token-native product entry surface — unified with chat/graph/admin pages.
|
|
5
5
|
============================================================ */
|
|
6
6
|
|
|
7
7
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
@@ -301,3 +301,139 @@
|
|
|
301
301
|
-webkit-text-fill-color: currentColor;
|
|
302
302
|
color: var(--text);
|
|
303
303
|
}
|
|
304
|
+
|
|
305
|
+
/* Product-grade auth surface — functional entry point, token-native. */
|
|
306
|
+
.lattice-ref-auth {
|
|
307
|
+
background: var(--app-bg);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.lattice-ref-auth::before {
|
|
311
|
+
background:
|
|
312
|
+
linear-gradient(90deg, rgba(12, 92, 115, 0.05) 1px, transparent 1px),
|
|
313
|
+
linear-gradient(180deg, rgba(12, 92, 115, 0.05) 1px, transparent 1px);
|
|
314
|
+
background-size: 42px 42px;
|
|
315
|
+
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.32), transparent 76%);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.lattice-ref-auth::after,
|
|
319
|
+
.lattice-ref-auth .orb,
|
|
320
|
+
.auth-wave,
|
|
321
|
+
.auth-network {
|
|
322
|
+
display: none;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.auth-titlebar {
|
|
326
|
+
background: var(--surface-elevated);
|
|
327
|
+
border-bottom-color: var(--line);
|
|
328
|
+
color: var(--text);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.auth-window-brand i,
|
|
332
|
+
.lattice-ref-auth .hero-logo-mark {
|
|
333
|
+
color: var(--accent);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.auth-window-controls span::before,
|
|
337
|
+
.auth-window-controls span::after {
|
|
338
|
+
background: var(--text);
|
|
339
|
+
border-color: var(--text);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.lattice-ref-auth .login-shell {
|
|
343
|
+
width: min(980px, calc(100vw - 36px));
|
|
344
|
+
grid-template-columns: minmax(300px, 430px) minmax(280px, 1fr);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.lattice-ref-auth .brand-preview {
|
|
348
|
+
display: block;
|
|
349
|
+
border-radius: 8px;
|
|
350
|
+
background:
|
|
351
|
+
linear-gradient(135deg, var(--accent-soft), transparent 58%),
|
|
352
|
+
var(--surface);
|
|
353
|
+
border-color: var(--line);
|
|
354
|
+
box-shadow: none;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.lattice-ref-auth .preview-node {
|
|
358
|
+
border-radius: 8px;
|
|
359
|
+
background: var(--surface-2);
|
|
360
|
+
border-color: var(--line);
|
|
361
|
+
box-shadow: none;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.lattice-ref-auth .preview-node::after {
|
|
365
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
366
|
+
border-radius: 8px;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.lattice-ref-auth .preview-line {
|
|
370
|
+
background: linear-gradient(90deg, transparent, var(--accent-2), transparent);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.lattice-ref-auth .card {
|
|
374
|
+
border-radius: 8px;
|
|
375
|
+
background: var(--surface-elevated);
|
|
376
|
+
border-color: var(--line);
|
|
377
|
+
box-shadow: var(--shadow);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.lattice-ref-auth .card::before {
|
|
381
|
+
background: linear-gradient(90deg, transparent, var(--accent), var(--accent-2), transparent);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.lattice-ref-auth .title {
|
|
385
|
+
background: none;
|
|
386
|
+
color: var(--text);
|
|
387
|
+
-webkit-text-fill-color: currentColor;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.lattice-ref-auth .subtitle {
|
|
391
|
+
color: var(--muted);
|
|
392
|
+
font-weight: 700;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.lattice-ref-auth .input,
|
|
396
|
+
.lattice-ref-auth .auth-field,
|
|
397
|
+
.lattice-ref-auth .sso-btn {
|
|
398
|
+
background: var(--input);
|
|
399
|
+
border-color: var(--line);
|
|
400
|
+
color: var(--text);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.lattice-ref-auth .input:focus,
|
|
404
|
+
.lattice-ref-auth .auth-field:focus-within {
|
|
405
|
+
border-color: var(--accent);
|
|
406
|
+
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.lattice-ref-auth .submit {
|
|
410
|
+
background: var(--accent);
|
|
411
|
+
box-shadow: none;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.lattice-ref-auth .submit:hover {
|
|
415
|
+
background: var(--accent-deep);
|
|
416
|
+
box-shadow: none;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.lattice-ref-auth .local-start,
|
|
420
|
+
.lattice-ref-auth .register-cta,
|
|
421
|
+
.lattice-ref-auth .switch a {
|
|
422
|
+
color: var(--accent);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.lattice-ref-auth .lang-btn,
|
|
426
|
+
.lattice-ref-auth .lang-menu {
|
|
427
|
+
border-color: var(--line);
|
|
428
|
+
box-shadow: none;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
@media (max-width: 760px) {
|
|
432
|
+
.lattice-ref-auth .login-shell {
|
|
433
|
+
grid-template-columns: 1fr;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.lattice-ref-auth .brand-preview {
|
|
437
|
+
display: none;
|
|
438
|
+
}
|
|
439
|
+
}
|