ltcai 4.0.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +33 -24
  2. package/desktop/electron/main.cjs +44 -0
  3. package/docs/CHANGELOG.md +84 -0
  4. package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +65 -0
  5. package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +70 -0
  6. package/docs/V4_1_VALIDATION_REPORT.md +47 -0
  7. package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +97 -0
  8. package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +91 -0
  9. package/docs/V4_2_VALIDATION_REPORT.md +89 -0
  10. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +31 -26
  11. package/frontend/index.html +24 -0
  12. package/frontend/openapi.json +14436 -0
  13. package/frontend/src/App.tsx +184 -0
  14. package/frontend/src/api/client.ts +320 -0
  15. package/frontend/src/api/openapi.ts +16921 -0
  16. package/frontend/src/components/primitives.tsx +204 -0
  17. package/frontend/src/components/ui/badge.tsx +27 -0
  18. package/frontend/src/components/ui/button.tsx +37 -0
  19. package/frontend/src/components/ui/card.tsx +22 -0
  20. package/frontend/src/components/ui/input.tsx +16 -0
  21. package/frontend/src/components/ui/textarea.tsx +16 -0
  22. package/frontend/src/lib/utils.ts +33 -0
  23. package/frontend/src/main.tsx +23 -0
  24. package/frontend/src/pages/Act.tsx +245 -0
  25. package/frontend/src/pages/Ask.tsx +200 -0
  26. package/frontend/src/pages/Brain.tsx +267 -0
  27. package/frontend/src/pages/Capture.tsx +158 -0
  28. package/frontend/src/pages/Library.tsx +187 -0
  29. package/frontend/src/pages/System.tsx +378 -0
  30. package/frontend/src/routes.ts +85 -0
  31. package/frontend/src/store/appStore.ts +54 -0
  32. package/frontend/src/styles.css +107 -0
  33. package/kg_schema.py +1 -1
  34. package/knowledge_graph.py +4 -4
  35. package/lattice_brain/__init__.py +70 -0
  36. package/lattice_brain/_kg_common.py +1 -0
  37. package/lattice_brain/archive.py +133 -0
  38. package/lattice_brain/context.py +3 -0
  39. package/lattice_brain/conversations.py +3 -0
  40. package/lattice_brain/core.py +82 -0
  41. package/lattice_brain/discovery.py +1 -0
  42. package/lattice_brain/documents.py +1 -0
  43. package/lattice_brain/embeddings.py +82 -0
  44. package/lattice_brain/identity.py +13 -0
  45. package/lattice_brain/ingest.py +1 -0
  46. package/lattice_brain/memory.py +3 -0
  47. package/lattice_brain/network.py +1 -0
  48. package/lattice_brain/projection.py +1 -0
  49. package/lattice_brain/provenance.py +1 -0
  50. package/lattice_brain/retrieval.py +1 -0
  51. package/lattice_brain/schema.py +1 -0
  52. package/lattice_brain/storage/__init__.py +22 -0
  53. package/lattice_brain/storage/base.py +72 -0
  54. package/lattice_brain/storage/docker.py +105 -0
  55. package/lattice_brain/storage/factory.py +31 -0
  56. package/lattice_brain/storage/migration.py +190 -0
  57. package/lattice_brain/storage/postgres.py +123 -0
  58. package/lattice_brain/storage/sqlite.py +128 -0
  59. package/lattice_brain/store.py +3 -0
  60. package/lattice_brain/write_master.py +1 -0
  61. package/latticeai/__init__.py +1 -1
  62. package/latticeai/api/portability.py +69 -0
  63. package/latticeai/api/setup.py +5 -4
  64. package/latticeai/api/static_routes.py +4 -4
  65. package/latticeai/app_factory.py +17 -10
  66. package/latticeai/brain/__init__.py +6 -6
  67. package/latticeai/brain/_kg_common.py +1 -1
  68. package/latticeai/brain/network.py +1 -1
  69. package/latticeai/brain/retrieval.py +15 -0
  70. package/latticeai/brain/store.py +22 -6
  71. package/latticeai/core/config.py +8 -0
  72. package/latticeai/core/marketplace.py +1 -1
  73. package/latticeai/core/multi_agent.py +1 -1
  74. package/latticeai/core/workspace_os.py +1 -1
  75. package/latticeai/services/kg_portability.py +82 -1
  76. package/package.json +55 -15
  77. package/scripts/build_frontend_assets.mjs +38 -0
  78. package/scripts/bump_version.py +4 -1
  79. package/scripts/export_openapi.py +31 -0
  80. package/scripts/lint_frontend.mjs +91 -0
  81. package/scripts/migrate_brain_storage.py +53 -0
  82. package/scripts/run_python.mjs +47 -0
  83. package/scripts/wheel_smoke.py +3 -0
  84. package/src-tauri/Cargo.lock +4833 -0
  85. package/src-tauri/Cargo.toml +19 -0
  86. package/src-tauri/build.rs +3 -0
  87. package/src-tauri/capabilities/default.json +7 -0
  88. package/src-tauri/src/main.rs +78 -0
  89. package/src-tauri/tauri.conf.json +39 -0
  90. package/static/app/asset-manifest.json +32 -0
  91. package/static/app/assets/core-CwxXejkd.js +2 -0
  92. package/static/app/assets/core-CwxXejkd.js.map +1 -0
  93. package/static/app/assets/index-CDjiH_se.css +2 -0
  94. package/static/app/assets/index-C_HAkbAg.js +333 -0
  95. package/static/app/assets/index-C_HAkbAg.js.map +1 -0
  96. package/static/app/index.html +25 -0
  97. package/static/manifest.json +2 -2
  98. package/static/sw.js +4 -4
  99. package/scripts/build_v3_assets.mjs +0 -170
  100. package/scripts/lint_v3.mjs +0 -120
  101. package/static/v3/asset-manifest.json +0 -63
  102. package/static/v3/css/lattice.base.49deefb5.css +0 -128
  103. package/static/v3/css/lattice.base.css +0 -128
  104. package/static/v3/css/lattice.components.cde18231.css +0 -472
  105. package/static/v3/css/lattice.components.css +0 -472
  106. package/static/v3/css/lattice.shell.29d36d85.css +0 -452
  107. package/static/v3/css/lattice.shell.css +0 -452
  108. package/static/v3/css/lattice.tokens.304cbc40.css +0 -135
  109. package/static/v3/css/lattice.tokens.css +0 -135
  110. package/static/v3/css/lattice.views.0a18b6c5.css +0 -360
  111. package/static/v3/css/lattice.views.css +0 -360
  112. package/static/v3/index.html +0 -68
  113. package/static/v3/js/app.c5c80c46.js +0 -26
  114. package/static/v3/js/app.js +0 -26
  115. package/static/v3/js/core/api.ba0fbf14.js +0 -625
  116. package/static/v3/js/core/api.js +0 -625
  117. package/static/v3/js/core/components.f25b3b93.js +0 -230
  118. package/static/v3/js/core/components.js +0 -230
  119. package/static/v3/js/core/dom.a2773eb0.js +0 -148
  120. package/static/v3/js/core/dom.js +0 -148
  121. package/static/v3/js/core/i18n.880e1fec.js +0 -575
  122. package/static/v3/js/core/i18n.js +0 -575
  123. package/static/v3/js/core/router.584570f2.js +0 -37
  124. package/static/v3/js/core/router.js +0 -37
  125. package/static/v3/js/core/routes.37522821.js +0 -101
  126. package/static/v3/js/core/routes.js +0 -101
  127. package/static/v3/js/core/shell.e3f6bbfa.js +0 -420
  128. package/static/v3/js/core/shell.js +0 -420
  129. package/static/v3/js/core/store.7b2aa044.js +0 -123
  130. package/static/v3/js/core/store.js +0 -123
  131. package/static/v3/js/views/account.eff40715.js +0 -143
  132. package/static/v3/js/views/account.js +0 -143
  133. package/static/v3/js/views/activity.0d271ef9.js +0 -67
  134. package/static/v3/js/views/activity.js +0 -67
  135. package/static/v3/js/views/admin-audit.660a1fb1.js +0 -185
  136. package/static/v3/js/views/admin-audit.js +0 -185
  137. package/static/v3/js/views/admin-permissions.a7ae5f09.js +0 -177
  138. package/static/v3/js/views/admin-permissions.js +0 -177
  139. package/static/v3/js/views/admin-policies.3658fd86.js +0 -102
  140. package/static/v3/js/views/admin-policies.js +0 -102
  141. package/static/v3/js/views/admin-private-vpc.7d342d36.js +0 -135
  142. package/static/v3/js/views/admin-private-vpc.js +0 -135
  143. package/static/v3/js/views/admin-security.07c66b72.js +0 -180
  144. package/static/v3/js/views/admin-security.js +0 -180
  145. package/static/v3/js/views/admin-users.f7ac7b43.js +0 -166
  146. package/static/v3/js/views/admin-users.js +0 -166
  147. package/static/v3/js/views/agents.17c5288d.js +0 -564
  148. package/static/v3/js/views/agents.js +0 -564
  149. package/static/v3/js/views/chat.e250e2cc.js +0 -624
  150. package/static/v3/js/views/chat.js +0 -624
  151. package/static/v3/js/views/files.adad14c1.js +0 -365
  152. package/static/v3/js/views/files.js +0 -365
  153. package/static/v3/js/views/graph-canvas.17c15d65.js +0 -509
  154. package/static/v3/js/views/graph-canvas.js +0 -509
  155. package/static/v3/js/views/home.24f8b8ae.js +0 -200
  156. package/static/v3/js/views/home.js +0 -200
  157. package/static/v3/js/views/hooks.37895880.js +0 -220
  158. package/static/v3/js/views/hooks.js +0 -220
  159. package/static/v3/js/views/hybrid-search.2fb63ed9.js +0 -194
  160. package/static/v3/js/views/hybrid-search.js +0 -194
  161. package/static/v3/js/views/knowledge-graph.4d09c537.js +0 -529
  162. package/static/v3/js/views/knowledge-graph.js +0 -529
  163. package/static/v3/js/views/marketplace.ab0583d4.js +0 -141
  164. package/static/v3/js/views/marketplace.js +0 -141
  165. package/static/v3/js/views/mcp.99b5c6a7.js +0 -114
  166. package/static/v3/js/views/mcp.js +0 -114
  167. package/static/v3/js/views/memory.4ebdf474.js +0 -147
  168. package/static/v3/js/views/memory.js +0 -147
  169. package/static/v3/js/views/models.a1ffa147.js +0 -256
  170. package/static/v3/js/views/models.js +0 -256
  171. package/static/v3/js/views/my-computer.d9d9ae1c.js +0 -463
  172. package/static/v3/js/views/my-computer.js +0 -463
  173. package/static/v3/js/views/network.52a4f181.js +0 -97
  174. package/static/v3/js/views/network.js +0 -97
  175. package/static/v3/js/views/pipeline.c522f1ce.js +0 -157
  176. package/static/v3/js/views/pipeline.js +0 -157
  177. package/static/v3/js/views/planning.4876fd77.js +0 -174
  178. package/static/v3/js/views/planning.js +0 -174
  179. package/static/v3/js/views/runs.b63b2afa.js +0 -144
  180. package/static/v3/js/views/runs.js +0 -144
  181. package/static/v3/js/views/settings.b7140634.js +0 -317
  182. package/static/v3/js/views/settings.js +0 -317
  183. package/static/v3/js/views/skills.c6c2f965.js +0 -109
  184. package/static/v3/js/views/skills.js +0 -109
  185. package/static/v3/js/views/snapshots.6f5db095.js +0 -135
  186. package/static/v3/js/views/snapshots.js +0 -135
  187. package/static/v3/js/views/tools.e4f11276.js +0 -108
  188. package/static/v3/js/views/tools.js +0 -108
  189. package/static/v3/js/views/workflows.7752225a.js +0 -213
  190. package/static/v3/js/views/workflows.js +0 -213
  191. package/static/v3/js/views/workspace-admin.c466029b.js +0 -156
  192. package/static/v3/js/views/workspace-admin.js +0 -156
@@ -0,0 +1,25 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
+ <meta name="color-scheme" content="dark light" />
7
+ <title>Lattice AI · Digital Brain</title>
8
+ <link rel="manifest" href="/manifest.json" />
9
+ <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png" />
10
+ <script>
11
+ (function () {
12
+ try {
13
+ var theme = localStorage.getItem("lattice.theme");
14
+ if (theme === "light" || theme === "dark") document.documentElement.dataset.theme = theme;
15
+ } catch (e) {}
16
+ })();
17
+ </script>
18
+ <script type="module" crossorigin src="/static/app/assets/index-C_HAkbAg.js"></script>
19
+ <link rel="stylesheet" crossorigin href="/static/app/assets/index-CDjiH_se.css">
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ <noscript>Lattice AI requires JavaScript for the local Digital Brain desktop shell.</noscript>
24
+ </body>
25
+ </html>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "Lattice AI",
3
3
  "short_name": "LatticeAI",
4
- "description": "Local-first AI workspace platform for knowledge graphs, vector index, hybrid search, agents, and workspace modes",
4
+ "description": "Local-first Digital Brain desktop platform for knowledge graphs, durable memory, hybrid search, agents, and signed brain exchange",
5
5
  "start_url": "/app",
6
6
  "id": "/",
7
7
  "display": "standalone",
@@ -28,7 +28,7 @@
28
28
  {
29
29
  "name": "새 대화",
30
30
  "short_name": "대화",
31
- "url": "/app#/chat",
31
+ "url": "/app#/ask",
32
32
  "icons": [{ "src": "/icons/icon-192.png", "sizes": "192x192" }]
33
33
  }
34
34
  ]
package/static/sw.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Lattice Service Worker — PWA install + offline shell for the /app SPA.
2
- // Strategy: precache the v3 bundle from its asset manifest (hashed files),
2
+ // Strategy: precache the Vite app bundle from its asset manifest,
3
3
  // cache-first for static assets, network-only for everything dynamic.
4
- const CACHE = "lattice-v4";
5
- const MANIFEST_URL = "/static/v3/asset-manifest.json";
4
+ const CACHE = "lattice-v410";
5
+ const MANIFEST_URL = "/static/app/asset-manifest.json";
6
6
 
7
7
  // Non-manifest assets the shell needs offline.
8
8
  const SHELL = [
@@ -29,7 +29,7 @@ async function precache() {
29
29
  const res = await fetch(MANIFEST_URL, { cache: "no-cache" });
30
30
  const manifest = await res.json();
31
31
  const entry = manifest.entrypoints || {};
32
- manifestPaths = [entry.app, ...(entry.styles || []), ...Object.values(manifest.assets || {})]
32
+ manifestPaths = [entry.app, ...Object.values(manifest.assets || {})]
33
33
  .filter(Boolean);
34
34
  } catch (err) {
35
35
  // Offline install: shell precache below still applies.
@@ -1,170 +0,0 @@
1
- #!/usr/bin/env node
2
- /*
3
- * Build the v3 browser asset manifest.
4
- *
5
- * The source files stay importable in development. This script writes hashed
6
- * siblings next to each runtime asset, rewrites ES-module imports to those
7
- * hashed siblings, and emits static/v3/asset-manifest.json for /app.
8
- */
9
- import { createHash } from "node:crypto";
10
- import {
11
- existsSync,
12
- mkdirSync,
13
- readdirSync,
14
- readFileSync,
15
- rmSync,
16
- statSync,
17
- writeFileSync,
18
- } from "node:fs";
19
- import { basename, dirname, extname, join, relative } from "node:path";
20
- import { fileURLToPath } from "node:url";
21
-
22
- const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
23
- const staticRoot = join(repoRoot, "static");
24
- const manifestPath = join(staticRoot, "v3", "asset-manifest.json");
25
-
26
- // Version is sourced from package.json — the single source of truth for the
27
- // release. Never hard-code a version string in the generated manifest.
28
- const pkgVersion = JSON.parse(
29
- readFileSync(join(repoRoot, "package.json"), "utf8"),
30
- ).version;
31
-
32
- const cssSources = [
33
- "static/css/tokens.css",
34
- "static/v3/css/lattice.tokens.css",
35
- "static/v3/css/lattice.base.css",
36
- "static/v3/css/lattice.components.css",
37
- "static/v3/css/lattice.shell.css",
38
- "static/v3/css/lattice.views.css",
39
- ];
40
-
41
- const moduleRoot = join(staticRoot, "v3", "js");
42
- const entry = "static/v3/js/app.js";
43
-
44
- function posix(p) {
45
- return p.replaceAll("\\", "/");
46
- }
47
-
48
- function sha(text) {
49
- return createHash("sha256").update(text).digest("hex").slice(0, 8);
50
- }
51
-
52
- function repoPath(abs) {
53
- return posix(relative(repoRoot, abs));
54
- }
55
-
56
- function publicUrl(repoRel) {
57
- return "/" + posix(repoRel);
58
- }
59
-
60
- function walk(dir) {
61
- const out = [];
62
- for (const name of readdirSync(dir)) {
63
- const p = join(dir, name);
64
- const st = statSync(p);
65
- if (st.isDirectory()) out.push(...walk(p));
66
- else if (name.endsWith(".js")) out.push(p);
67
- }
68
- return out;
69
- }
70
-
71
- function removeGenerated(dir, ext) {
72
- if (!existsSync(dir)) return;
73
- for (const name of readdirSync(dir)) {
74
- const p = join(dir, name);
75
- const st = statSync(p);
76
- if (st.isDirectory()) removeGenerated(p, ext);
77
- else if (new RegExp(`\\.[0-9a-f]{8}\\${ext}$`).test(name)) rmSync(p);
78
- }
79
- }
80
-
81
- removeGenerated(join(staticRoot, "css"), ".css");
82
- removeGenerated(join(staticRoot, "v3", "css"), ".css");
83
- removeGenerated(moduleRoot, ".js");
84
-
85
- const modules = new Map();
86
- for (const abs of walk(moduleRoot)) {
87
- modules.set(repoPath(abs), {
88
- abs,
89
- rel: repoPath(abs),
90
- source: readFileSync(abs, "utf8"),
91
- deps: [],
92
- });
93
- }
94
-
95
- const importFromRe = /\b(?:import|export)\s+(?:[^"'()]*?\s+from\s*)?["']([^"']+\.js)["']/g;
96
- for (const mod of modules.values()) {
97
- const deps = [];
98
- let match;
99
- while ((match = importFromRe.exec(mod.source))) {
100
- const spec = match[1];
101
- if (!spec.startsWith(".")) continue;
102
- const depRel = repoPath(join(dirname(mod.abs), spec));
103
- if (modules.has(depRel)) deps.push(depRel);
104
- }
105
- mod.deps = deps;
106
- }
107
-
108
- const hashMemo = new Map();
109
- function moduleHash(rel, stack = []) {
110
- if (hashMemo.has(rel)) return hashMemo.get(rel);
111
- if (stack.includes(rel)) return sha(modules.get(rel).source);
112
- const mod = modules.get(rel);
113
- const depHashes = mod.deps
114
- .sort()
115
- .map((dep) => `${dep}:${moduleHash(dep, [...stack, rel])}`)
116
- .join("\n");
117
- const h = sha(`${mod.source}\n/* dependency-hashes */\n${depHashes}`);
118
- hashMemo.set(rel, h);
119
- return h;
120
- }
121
-
122
- for (const rel of modules.keys()) moduleHash(rel);
123
-
124
- function hashedRel(rel, hash) {
125
- const ext = extname(rel);
126
- return posix(join(dirname(rel), `${basename(rel, ext)}.${hash}${ext}`));
127
- }
128
-
129
- const assets = {};
130
-
131
- for (const sourceRel of cssSources) {
132
- const abs = join(repoRoot, sourceRel);
133
- const source = readFileSync(abs, "utf8");
134
- const outRel = hashedRel(sourceRel, sha(source));
135
- writeFileSync(join(repoRoot, outRel), source, "utf8");
136
- assets[sourceRel] = publicUrl(outRel);
137
- }
138
-
139
- function rewriteModule(mod) {
140
- return mod.source.replace(importFromRe, (full, spec) => {
141
- if (!spec.startsWith(".")) return full;
142
- const depRel = repoPath(join(dirname(mod.abs), spec));
143
- const depHash = hashMemo.get(depRel);
144
- if (!depHash) return full;
145
- const depOutAbs = join(repoRoot, hashedRel(depRel, depHash));
146
- const nextSpec = posix(relative(dirname(join(repoRoot, hashedRel(mod.rel, hashMemo.get(mod.rel)))), depOutAbs));
147
- const normalized = nextSpec.startsWith(".") ? nextSpec : `./${nextSpec}`;
148
- return full.replace(spec, normalized);
149
- });
150
- }
151
-
152
- for (const mod of modules.values()) {
153
- const outRel = hashedRel(mod.rel, hashMemo.get(mod.rel));
154
- mkdirSync(dirname(join(repoRoot, outRel)), { recursive: true });
155
- writeFileSync(join(repoRoot, outRel), rewriteModule(mod), "utf8");
156
- assets[mod.rel] = publicUrl(outRel);
157
- }
158
-
159
- const manifest = {
160
- version: pkgVersion,
161
- generated_at: "deterministic",
162
- entrypoints: {
163
- app: assets[entry],
164
- styles: cssSources.map((rel) => assets[rel]),
165
- },
166
- assets,
167
- };
168
-
169
- writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
170
- console.log(`wrote ${repoPath(manifestPath)} with ${Object.keys(assets).length} assets`);
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env node
2
- /* Lattice v3 frontend lint. Gates `npm run lint`:
3
- * 1. Syntax-check every v3 ES module (node --check).
4
- * 2. Design tokens: no raw hex/rgb colors in static/v3/css outside the two
5
- * token files (lattice.tokens.css, tokens.css) — themed surfaces must use
6
- * var(--…) tokens.
7
- * 3. No inline style colors in view JS (style="…color: #…" or
8
- * style.color = "#…" literals).
9
- * 4. Privacy: zero CDN/external URLs in shipped static HTML/CSS/JS —
10
- * fonts/icons/libs are vendored under static/vendor.
11
- * 5. i18n: routes, shell, and new v4 parity views must use the SPA i18n
12
- * runtime instead of inert localStorage-only language toggles.
13
- * Exits non-zero on any failure. */
14
- import { readdirSync, statSync, readFileSync } from "node:fs";
15
- import { join, dirname, relative } from "node:path";
16
- import { fileURLToPath } from "node:url";
17
- import { spawnSync } from "node:child_process";
18
-
19
- const repo = join(dirname(fileURLToPath(import.meta.url)), "..");
20
- const v3js = join(repo, "static", "v3", "js");
21
- const v3css = join(repo, "static", "v3", "css");
22
- const staticRoot = join(repo, "static");
23
-
24
- function walk(dir, ext) {
25
- const out = [];
26
- for (const name of readdirSync(dir)) {
27
- const p = join(dir, name);
28
- if (statSync(p).isDirectory()) out.push(...walk(p, ext));
29
- else if (ext.some((e) => name.endsWith(e))) out.push(p);
30
- }
31
- return out;
32
- }
33
-
34
- let failed = 0;
35
- const fail = (msg) => { failed++; console.error(`FAIL ${msg}`); };
36
-
37
- // ── 1. syntax ────────────────────────────────────────────────────────────
38
- const modules = walk(v3js, [".js"]).sort();
39
- let syntaxOk = 0;
40
- for (const file of modules) {
41
- const r = spawnSync(process.execPath, ["--check", file], { encoding: "utf8" });
42
- if (r.status === 0) syntaxOk++;
43
- else fail(`${relative(repo, file)}\n${r.stderr || r.stdout}`);
44
- }
45
- console.log(`syntax: ${syntaxOk}/${modules.length} v3 modules pass`);
46
-
47
- // ── 2. raw colors in v3 css (outside token files) ────────────────────────
48
- const TOKEN_FILES = new Set(["lattice.tokens.css", "tokens.css"]);
49
- const colorRe = /#[0-9a-fA-F]{3,8}\b|rgba?\(/;
50
- let cssChecked = 0;
51
- for (const file of walk(v3css, [".css"]).sort()) {
52
- const base = file.split("/").pop();
53
- if (TOKEN_FILES.has(base) || /\.[0-9a-f]{8}\.css$/.test(base)) continue; // tokens + hashed builds
54
- cssChecked++;
55
- const lines = readFileSync(file, "utf8").split("\n");
56
- lines.forEach((line, i) => {
57
- const code = line.split("/*")[0];
58
- // mask-image gradients use #000/transparent as ALPHA values, not themed
59
- // colors — they are theme-independent and exempt.
60
- if (/mask-image|-webkit-mask/.test(code)) return;
61
- if (colorRe.test(code)) fail(`${relative(repo, file)}:${i + 1} raw color (use a var(--…) token): ${line.trim().slice(0, 90)}`);
62
- });
63
- }
64
- console.log(`tokens: ${cssChecked} non-token v3 css files scanned for raw colors`);
65
-
66
- // ── 3. inline style colors in view JS ────────────────────────────────────
67
- const inlineColorRe = /style\s*=\s*["'`][^"'`]*(?:color|background)\s*:\s*(#|rgb)/i;
68
- const styleAssignRe = /\.style\.(color|background(?:Color)?)\s*=\s*["'`](#|rgb)/i;
69
- let jsChecked = 0;
70
- for (const file of modules) {
71
- if (/\.[0-9a-f]{8}\.js$/.test(file)) continue; // hashed builds mirror sources
72
- jsChecked++;
73
- const lines = readFileSync(file, "utf8").split("\n");
74
- lines.forEach((line, i) => {
75
- if (inlineColorRe.test(line) || styleAssignRe.test(line)) {
76
- fail(`${relative(repo, file)}:${i + 1} inline style color (use a token/class): ${line.trim().slice(0, 90)}`);
77
- }
78
- });
79
- }
80
- console.log(`inline-style: ${jsChecked} v3 source modules scanned`);
81
-
82
- // ── 4. no CDN/external asset URLs in shipped static files ────────────────
83
- const cdnRe = /https?:\/\/(fonts\.googleapis\.com|fonts\.gstatic\.com|cdn\.jsdelivr\.net|unpkg\.com|cdnjs\.cloudflare\.com)/;
84
- let shippedChecked = 0;
85
- for (const file of walk(staticRoot, [".html", ".css", ".js"]).sort()) {
86
- if (file.includes(`${join("static", "vendor")}`)) continue; // vendored copies may cite origins in comments
87
- shippedChecked++;
88
- const lines = readFileSync(file, "utf8").split("\n");
89
- lines.forEach((line, i) => {
90
- if (cdnRe.test(line)) fail(`${relative(repo, file)}:${i + 1} CDN reference (vendor it under static/vendor): ${line.trim().slice(0, 90)}`);
91
- });
92
- }
93
- console.log(`privacy: ${shippedChecked} shipped static files scanned for CDN URLs`);
94
-
95
- // ── 5. i18n acceptance for T9 surfaces ──────────────────────────────────
96
- const i18nRequired = [
97
- "static/v3/js/core/routes.js",
98
- "static/v3/js/core/shell.js",
99
- "static/v3/js/views/account.js",
100
- "static/v3/js/views/workspace-admin.js",
101
- "static/v3/js/views/snapshots.js",
102
- "static/v3/js/views/activity.js",
103
- "static/v3/js/views/runs.js",
104
- "static/v3/js/views/network.js",
105
- ];
106
- let i18nChecked = 0;
107
- for (const rel of i18nRequired) {
108
- const file = join(repo, rel);
109
- const text = readFileSync(file, "utf8");
110
- i18nChecked++;
111
- if (!/i18n\.js/.test(text)) fail(`${rel}: missing i18n runtime import`);
112
- if (!/\bt\(/.test(text)) fail(`${rel}: no translation lookup found`);
113
- }
114
- console.log(`i18n: ${i18nChecked} route/shell/parity modules checked`);
115
-
116
- if (failed) {
117
- console.error(`\nv3 frontend lint: ${failed} failure(s)`);
118
- process.exit(1);
119
- }
120
- console.log(`\nv3 frontend lint: all checks pass`);
@@ -1,63 +0,0 @@
1
- {
2
- "version": "4.0.1",
3
- "generated_at": "deterministic",
4
- "entrypoints": {
5
- "app": "/static/v3/js/app.c5c80c46.js",
6
- "styles": [
7
- "/static/css/tokens.3ba22e37.css",
8
- "/static/v3/css/lattice.tokens.304cbc40.css",
9
- "/static/v3/css/lattice.base.49deefb5.css",
10
- "/static/v3/css/lattice.components.cde18231.css",
11
- "/static/v3/css/lattice.shell.29d36d85.css",
12
- "/static/v3/css/lattice.views.0a18b6c5.css"
13
- ]
14
- },
15
- "assets": {
16
- "static/css/tokens.css": "/static/css/tokens.3ba22e37.css",
17
- "static/v3/css/lattice.tokens.css": "/static/v3/css/lattice.tokens.304cbc40.css",
18
- "static/v3/css/lattice.base.css": "/static/v3/css/lattice.base.49deefb5.css",
19
- "static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.cde18231.css",
20
- "static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.29d36d85.css",
21
- "static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.0a18b6c5.css",
22
- "static/v3/js/app.js": "/static/v3/js/app.c5c80c46.js",
23
- "static/v3/js/core/api.js": "/static/v3/js/core/api.ba0fbf14.js",
24
- "static/v3/js/core/components.js": "/static/v3/js/core/components.f25b3b93.js",
25
- "static/v3/js/core/dom.js": "/static/v3/js/core/dom.a2773eb0.js",
26
- "static/v3/js/core/i18n.js": "/static/v3/js/core/i18n.880e1fec.js",
27
- "static/v3/js/core/router.js": "/static/v3/js/core/router.584570f2.js",
28
- "static/v3/js/core/routes.js": "/static/v3/js/core/routes.37522821.js",
29
- "static/v3/js/core/shell.js": "/static/v3/js/core/shell.e3f6bbfa.js",
30
- "static/v3/js/core/store.js": "/static/v3/js/core/store.7b2aa044.js",
31
- "static/v3/js/views/account.js": "/static/v3/js/views/account.eff40715.js",
32
- "static/v3/js/views/activity.js": "/static/v3/js/views/activity.0d271ef9.js",
33
- "static/v3/js/views/admin-audit.js": "/static/v3/js/views/admin-audit.660a1fb1.js",
34
- "static/v3/js/views/admin-permissions.js": "/static/v3/js/views/admin-permissions.a7ae5f09.js",
35
- "static/v3/js/views/admin-policies.js": "/static/v3/js/views/admin-policies.3658fd86.js",
36
- "static/v3/js/views/admin-private-vpc.js": "/static/v3/js/views/admin-private-vpc.7d342d36.js",
37
- "static/v3/js/views/admin-security.js": "/static/v3/js/views/admin-security.07c66b72.js",
38
- "static/v3/js/views/admin-users.js": "/static/v3/js/views/admin-users.f7ac7b43.js",
39
- "static/v3/js/views/agents.js": "/static/v3/js/views/agents.17c5288d.js",
40
- "static/v3/js/views/chat.js": "/static/v3/js/views/chat.e250e2cc.js",
41
- "static/v3/js/views/files.js": "/static/v3/js/views/files.adad14c1.js",
42
- "static/v3/js/views/graph-canvas.js": "/static/v3/js/views/graph-canvas.17c15d65.js",
43
- "static/v3/js/views/home.js": "/static/v3/js/views/home.24f8b8ae.js",
44
- "static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.37895880.js",
45
- "static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.2fb63ed9.js",
46
- "static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.4d09c537.js",
47
- "static/v3/js/views/marketplace.js": "/static/v3/js/views/marketplace.ab0583d4.js",
48
- "static/v3/js/views/mcp.js": "/static/v3/js/views/mcp.99b5c6a7.js",
49
- "static/v3/js/views/memory.js": "/static/v3/js/views/memory.4ebdf474.js",
50
- "static/v3/js/views/models.js": "/static/v3/js/views/models.a1ffa147.js",
51
- "static/v3/js/views/my-computer.js": "/static/v3/js/views/my-computer.d9d9ae1c.js",
52
- "static/v3/js/views/network.js": "/static/v3/js/views/network.52a4f181.js",
53
- "static/v3/js/views/pipeline.js": "/static/v3/js/views/pipeline.c522f1ce.js",
54
- "static/v3/js/views/planning.js": "/static/v3/js/views/planning.4876fd77.js",
55
- "static/v3/js/views/runs.js": "/static/v3/js/views/runs.b63b2afa.js",
56
- "static/v3/js/views/settings.js": "/static/v3/js/views/settings.b7140634.js",
57
- "static/v3/js/views/skills.js": "/static/v3/js/views/skills.c6c2f965.js",
58
- "static/v3/js/views/snapshots.js": "/static/v3/js/views/snapshots.6f5db095.js",
59
- "static/v3/js/views/tools.js": "/static/v3/js/views/tools.e4f11276.js",
60
- "static/v3/js/views/workflows.js": "/static/v3/js/views/workflows.7752225a.js",
61
- "static/v3/js/views/workspace-admin.js": "/static/v3/js/views/workspace-admin.c466029b.js"
62
- }
63
- }
@@ -1,128 +0,0 @@
1
- /* ============================================================================
2
- * Lattice AI v3 — Base layer (reset + element defaults + lattice backdrop)
3
- * Token-native: no themed hex values, everything via var(--*).
4
- * ========================================================================== */
5
-
6
- *, *::before, *::after { box-sizing: border-box; }
7
-
8
- html, body { height: 100%; }
9
-
10
- body {
11
- margin: 0;
12
- font-family: var(--lt3-font-sans);
13
- font-size: var(--lt3-text-md);
14
- line-height: var(--lt3-leading-normal);
15
- color: var(--text);
16
- background: var(--bg);
17
- -webkit-font-smoothing: antialiased;
18
- text-rendering: optimizeLegibility;
19
- overflow: hidden; /* shell owns scroll regions */
20
- }
21
-
22
- /* The signature lattice backdrop — a faint structural mesh of nodes+edges.
23
- Sits behind the whole app; reinforces the "lattice" identity without noise. */
24
- .lt3-app::before {
25
- content: "";
26
- position: fixed;
27
- inset: 0;
28
- z-index: 0;
29
- pointer-events: none;
30
- background:
31
- radial-gradient(circle at center, var(--lt3-mesh-node) 0.9px, transparent 1.1px),
32
- linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
33
- linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px),
34
- var(--app-bg);
35
- background-size:
36
- var(--lt3-mesh-size) var(--lt3-mesh-size),
37
- var(--lt3-mesh-size) var(--lt3-mesh-size),
38
- var(--lt3-mesh-size) var(--lt3-mesh-size),
39
- cover;
40
- background-position: center;
41
- mask-image: radial-gradient(ellipse 120% 90% at 50% -10%, #000 55%, transparent 100%);
42
- opacity: 0.9;
43
- }
44
-
45
- h1, h2, h3, h4, p, figure { margin: 0; }
46
-
47
- a { color: inherit; text-decoration: none; }
48
-
49
- button {
50
- font: inherit;
51
- color: inherit;
52
- cursor: pointer;
53
- border: none;
54
- background: none;
55
- }
56
-
57
- input, select, textarea { font: inherit; color: inherit; }
58
-
59
- textarea { resize: vertical; }
60
-
61
- img, svg { display: block; max-width: 100%; }
62
-
63
- code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
64
-
65
- :root[data-lt-icons="fallback"] .ti {
66
- display: inline-grid;
67
- place-items: center;
68
- min-width: 1em;
69
- min-height: 1em;
70
- font-family: var(--lt3-font-mono);
71
- font-size: 0.72em;
72
- font-style: normal;
73
- font-weight: 800;
74
- line-height: 1;
75
- text-transform: uppercase;
76
- }
77
-
78
- :root[data-lt-icons="fallback"] .ti::before {
79
- content: attr(data-fallback);
80
- }
81
-
82
- :focus-visible {
83
- outline: 2px solid var(--focus-ring);
84
- outline-offset: 2px;
85
- border-radius: var(--lt3-radius-xs);
86
- }
87
-
88
- ::-webkit-scrollbar { width: 8px; height: 8px; }
89
- ::-webkit-scrollbar-track { background: transparent; }
90
- ::-webkit-scrollbar-thumb {
91
- background: color-mix(in srgb, var(--border-strong) 60%, transparent);
92
- border-radius: 99px;
93
- border: 2px solid transparent;
94
- background-clip: padding-box;
95
- }
96
- ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: padding-box; }
97
-
98
- /* Accessible visually-hidden utility */
99
- .lt3-sr {
100
- position: absolute !important;
101
- width: 1px; height: 1px;
102
- padding: 0; margin: -1px;
103
- overflow: hidden; clip: rect(0,0,0,0);
104
- white-space: nowrap; border: 0;
105
- }
106
-
107
- .lt3-skip {
108
- position: fixed;
109
- top: var(--lt3-space-3);
110
- left: var(--lt3-space-3);
111
- z-index: var(--lt3-z-toast);
112
- padding: var(--lt3-space-2) var(--lt3-space-4);
113
- background: var(--accent);
114
- color: var(--lt3-on-accent);
115
- border-radius: var(--lt3-radius-sm);
116
- transform: translateY(-200%);
117
- transition: transform var(--lt3-dur-2) var(--lt3-ease);
118
- }
119
- .lt3-skip:focus { transform: translateY(0); }
120
-
121
- @media (prefers-reduced-motion: reduce) {
122
- *, *::before, *::after {
123
- animation-duration: 0.001ms !important;
124
- animation-iteration-count: 1 !important;
125
- transition-duration: 0.001ms !important;
126
- scroll-behavior: auto !important;
127
- }
128
- }
@@ -1,128 +0,0 @@
1
- /* ============================================================================
2
- * Lattice AI v3 — Base layer (reset + element defaults + lattice backdrop)
3
- * Token-native: no themed hex values, everything via var(--*).
4
- * ========================================================================== */
5
-
6
- *, *::before, *::after { box-sizing: border-box; }
7
-
8
- html, body { height: 100%; }
9
-
10
- body {
11
- margin: 0;
12
- font-family: var(--lt3-font-sans);
13
- font-size: var(--lt3-text-md);
14
- line-height: var(--lt3-leading-normal);
15
- color: var(--text);
16
- background: var(--bg);
17
- -webkit-font-smoothing: antialiased;
18
- text-rendering: optimizeLegibility;
19
- overflow: hidden; /* shell owns scroll regions */
20
- }
21
-
22
- /* The signature lattice backdrop — a faint structural mesh of nodes+edges.
23
- Sits behind the whole app; reinforces the "lattice" identity without noise. */
24
- .lt3-app::before {
25
- content: "";
26
- position: fixed;
27
- inset: 0;
28
- z-index: 0;
29
- pointer-events: none;
30
- background:
31
- radial-gradient(circle at center, var(--lt3-mesh-node) 0.9px, transparent 1.1px),
32
- linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
33
- linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px),
34
- var(--app-bg);
35
- background-size:
36
- var(--lt3-mesh-size) var(--lt3-mesh-size),
37
- var(--lt3-mesh-size) var(--lt3-mesh-size),
38
- var(--lt3-mesh-size) var(--lt3-mesh-size),
39
- cover;
40
- background-position: center;
41
- mask-image: radial-gradient(ellipse 120% 90% at 50% -10%, #000 55%, transparent 100%);
42
- opacity: 0.9;
43
- }
44
-
45
- h1, h2, h3, h4, p, figure { margin: 0; }
46
-
47
- a { color: inherit; text-decoration: none; }
48
-
49
- button {
50
- font: inherit;
51
- color: inherit;
52
- cursor: pointer;
53
- border: none;
54
- background: none;
55
- }
56
-
57
- input, select, textarea { font: inherit; color: inherit; }
58
-
59
- textarea { resize: vertical; }
60
-
61
- img, svg { display: block; max-width: 100%; }
62
-
63
- code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
64
-
65
- :root[data-lt-icons="fallback"] .ti {
66
- display: inline-grid;
67
- place-items: center;
68
- min-width: 1em;
69
- min-height: 1em;
70
- font-family: var(--lt3-font-mono);
71
- font-size: 0.72em;
72
- font-style: normal;
73
- font-weight: 800;
74
- line-height: 1;
75
- text-transform: uppercase;
76
- }
77
-
78
- :root[data-lt-icons="fallback"] .ti::before {
79
- content: attr(data-fallback);
80
- }
81
-
82
- :focus-visible {
83
- outline: 2px solid var(--focus-ring);
84
- outline-offset: 2px;
85
- border-radius: var(--lt3-radius-xs);
86
- }
87
-
88
- ::-webkit-scrollbar { width: 8px; height: 8px; }
89
- ::-webkit-scrollbar-track { background: transparent; }
90
- ::-webkit-scrollbar-thumb {
91
- background: color-mix(in srgb, var(--border-strong) 60%, transparent);
92
- border-radius: 99px;
93
- border: 2px solid transparent;
94
- background-clip: padding-box;
95
- }
96
- ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: padding-box; }
97
-
98
- /* Accessible visually-hidden utility */
99
- .lt3-sr {
100
- position: absolute !important;
101
- width: 1px; height: 1px;
102
- padding: 0; margin: -1px;
103
- overflow: hidden; clip: rect(0,0,0,0);
104
- white-space: nowrap; border: 0;
105
- }
106
-
107
- .lt3-skip {
108
- position: fixed;
109
- top: var(--lt3-space-3);
110
- left: var(--lt3-space-3);
111
- z-index: var(--lt3-z-toast);
112
- padding: var(--lt3-space-2) var(--lt3-space-4);
113
- background: var(--accent);
114
- color: var(--lt3-on-accent);
115
- border-radius: var(--lt3-radius-sm);
116
- transform: translateY(-200%);
117
- transition: transform var(--lt3-dur-2) var(--lt3-ease);
118
- }
119
- .lt3-skip:focus { transform: translateY(0); }
120
-
121
- @media (prefers-reduced-motion: reduce) {
122
- *, *::before, *::after {
123
- animation-duration: 0.001ms !important;
124
- animation-iteration-count: 1 !important;
125
- transition-duration: 0.001ms !important;
126
- scroll-behavior: auto !important;
127
- }
128
- }