ltcai 10.8.0 → 10.9.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 (84) hide show
  1. package/README.md +54 -52
  2. package/docs/CHANGELOG.md +37 -0
  3. package/docs/COMMUNITY_AND_PLUGINS.md +1 -1
  4. package/docs/DEVELOPMENT.md +1 -1
  5. package/docs/ONBOARDING.md +1 -1
  6. package/docs/OPERATIONS.md +1 -1
  7. package/docs/TRUST_MODEL.md +1 -1
  8. package/docs/WHY_LATTICE.md +1 -1
  9. package/docs/kg-schema.md +1 -1
  10. package/lattice_brain/__init__.py +1 -1
  11. package/lattice_brain/runtime/multi_agent.py +1 -1
  12. package/latticeai/__init__.py +1 -1
  13. package/latticeai/api/chat.py +9 -6
  14. package/latticeai/api/chat_agent_http.py +2 -1
  15. package/latticeai/api/chat_history.py +4 -2
  16. package/latticeai/api/chat_intents.py +14 -14
  17. package/latticeai/api/knowledge_graph.py +5 -4
  18. package/latticeai/api/local_files.py +25 -15
  19. package/latticeai/api/mcp.py +15 -11
  20. package/latticeai/api/memory.py +2 -1
  21. package/latticeai/api/models.py +39 -24
  22. package/latticeai/api/network_boundary.py +9 -4
  23. package/latticeai/api/portability.py +27 -19
  24. package/latticeai/api/project_sessions.py +7 -5
  25. package/latticeai/api/review_queue.py +12 -7
  26. package/latticeai/api/setup.py +10 -11
  27. package/latticeai/api/static_routes.py +62 -46
  28. package/latticeai/api/tools.py +7 -6
  29. package/latticeai/core/legacy_compatibility.py +1 -1
  30. package/latticeai/core/marketplace.py +1 -1
  31. package/latticeai/core/mcp_registry.py +20 -4
  32. package/latticeai/core/messages.py +222 -0
  33. package/latticeai/core/workspace_os_constants.py +1 -1
  34. package/latticeai/integrations/telegram_bot.py +20 -18
  35. package/latticeai/services/architecture_readiness.py +1 -1
  36. package/latticeai/services/model_loading.py +63 -27
  37. package/latticeai/services/product_readiness.py +1 -1
  38. package/package.json +3 -2
  39. package/scripts/check_current_release_docs.mjs +1 -1
  40. package/scripts/check_server_i18n.mjs +96 -0
  41. package/scripts/release_screen_claims.json +17 -8
  42. package/src-tauri/Cargo.lock +1 -1
  43. package/src-tauri/Cargo.toml +1 -1
  44. package/src-tauri/tauri.conf.json +1 -1
  45. package/static/app/asset-manifest.json +37 -37
  46. package/static/app/assets/{Act-CbQNsFgc.js → Act-CS9IeqUX.js} +1 -1
  47. package/static/app/assets/{AdminConsole-Bs8SR8fE.js → AdminConsole-3UkIEWGA.js} +1 -1
  48. package/static/app/assets/{Brain-BZIPsZlH.js → Brain-B22EmNqS.js} +1 -1
  49. package/static/app/assets/{BrainHome-BaH5MDce.js → BrainHome-CMDqgJF4.js} +2 -2
  50. package/static/app/assets/{BrainSignals-aDt-nSsW.js → BrainSignals-BeE8RJo3.js} +1 -1
  51. package/static/app/assets/{Capture-DDv940Bv.js → Capture-ZX9bQh68.js} +1 -1
  52. package/static/app/assets/{CommandPalette-Dq_MmPBl.js → CommandPalette-86m4FCcN.js} +1 -1
  53. package/static/app/assets/{Library-BkShbqmN.js → Library-Bhz5LUca.js} +1 -1
  54. package/static/app/assets/{LivingBrain-CXb8094H.js → LivingBrain-BSa0wpFG.js} +1 -1
  55. package/static/app/assets/{ProductFlow-BaiqFWLO.js → ProductFlow-IP4Q-5aQ.js} +1 -1
  56. package/static/app/assets/{ReviewCard-Be7E7X18.js → ReviewCard-BepjSDpN.js} +1 -1
  57. package/static/app/assets/{System-DCstbTxC.js → System-Bwx1h_jT.js} +1 -1
  58. package/static/app/assets/arrow-left-ig7AZU8B.js +1 -0
  59. package/static/app/assets/{bot-BR0eoeXY.js → bot-DQj0-LkM.js} +1 -1
  60. package/static/app/assets/{brain-BmWa1wea.js → brain-D8OEwmVj.js} +1 -1
  61. package/static/app/assets/{button-U1nU7xX4.js → button-CmTknyAP.js} +1 -1
  62. package/static/app/assets/{circle-pause-DG5KHjDL.js → circle-pause-yTCWRziJ.js} +1 -1
  63. package/static/app/assets/{circle-play-Chhcuq90.js → circle-play-Ccrva84R.js} +1 -1
  64. package/static/app/assets/{cpu-pkOSlT9h.js → cpu-CbJqWTlS.js} +1 -1
  65. package/static/app/assets/{download-CSRwz923.js → download-CkSzbzU-.js} +1 -1
  66. package/static/app/assets/{folder-open-DiMJ7W_7.js → folder-open-CKyjQ4PU.js} +1 -1
  67. package/static/app/assets/{hard-drive-iyLPAPdp.js → hard-drive-DAzk9um0.js} +1 -1
  68. package/static/app/assets/{index-BZRvGOM2.css → index-BfD-jhA9.css} +1 -1
  69. package/static/app/assets/{index-_ldE9TAX.js → index-CxOcwsHV.js} +3 -3
  70. package/static/app/assets/{input-e_r2hFAY.js → input-DcMETmZ7.js} +1 -1
  71. package/static/app/assets/{permissionCopy-9uOHktz3.js → permissionCopy-BVf13_25.js} +1 -1
  72. package/static/app/assets/{primitives-CnEAOmg2.js → primitives-CQV9Q2YM.js} +1 -1
  73. package/static/app/assets/search-CXGASMMH.js +1 -0
  74. package/static/app/assets/{share-2-DLDJJKmI.js → share-2-COWCHNZm.js} +1 -1
  75. package/static/app/assets/{shield-alert-BTtE-2EZ.js → shield-alert-BDrvilyK.js} +1 -1
  76. package/static/app/assets/{textarea-Bbzkcgqe.js → textarea-rUmsc8cP.js} +1 -1
  77. package/static/app/assets/{useFocusTrap-DJzQd-Za.js → useFocusTrap-Bi5UY_8v.js} +1 -1
  78. package/static/app/assets/{useQuery-6R_tqHRe.js → useQuery-C-AicB-3.js} +1 -1
  79. package/static/app/assets/{utils-XDsjcrhS.js → utils-BMwWg78e.js} +1 -1
  80. package/static/app/assets/{workspace-CwrG8LHq.js → workspace-Y93tls8P.js} +1 -1
  81. package/static/app/index.html +4 -4
  82. package/static/sw.js +1 -1
  83. package/static/app/assets/arrow-left-DC9Oquhs.js +0 -1
  84. package/static/app/assets/search-veep4n6f.js +0 -1
@@ -157,9 +157,12 @@ async def send_message(client, chat_id, text, reply_markup=None):
157
157
  async def send_photo(client, chat_id, file_path: Path, caption: str = ""):
158
158
  url = f"{API_URL}/sendPhoto"
159
159
  try:
160
- with open(file_path, "rb") as f:
161
- res = await client.post(url, data={"chat_id": str(chat_id), "caption": caption[:1024]},
162
- files={"photo": (file_path.name, f)}, timeout=60.0)
160
+ # Read on a worker thread: a screenshot is megabytes, and reading it
161
+ # inline stalled the bot's poll loop (and everything else on the loop)
162
+ # for the length of the read.
163
+ blob = await asyncio.to_thread(Path(file_path).read_bytes)
164
+ res = await client.post(url, data={"chat_id": str(chat_id), "caption": caption[:1024]},
165
+ files={"photo": (file_path.name, blob)}, timeout=60.0)
163
166
  if res.status_code != 200:
164
167
  await send_message(client, chat_id, f"사진 전송 실패 ({res.status_code})")
165
168
  except Exception as e:
@@ -169,15 +172,15 @@ async def send_photo(client, chat_id, file_path: Path, caption: str = ""):
169
172
  async def send_document(client, chat_id, file_path, caption=None, filename=None):
170
173
  url = f"{API_URL}/sendDocument"
171
174
  try:
172
- with open(file_path, "rb") as f:
173
- res = await client.post(
174
- url,
175
- data={"chat_id": str(chat_id), **({"caption": caption[:1024]} if caption else {})},
176
- files={"document": (filename or Path(file_path).name, f)},
177
- timeout=300.0,
178
- )
179
- if res.status_code != 200:
180
- logger.error("파일 전송 실패 (%s): %s", res.status_code, safe_log_text(res.text))
175
+ blob = await asyncio.to_thread(Path(file_path).read_bytes)
176
+ res = await client.post(
177
+ url,
178
+ data={"chat_id": str(chat_id), **({"caption": caption[:1024]} if caption else {})},
179
+ files={"document": (filename or Path(file_path).name, blob)},
180
+ timeout=300.0,
181
+ )
182
+ if res.status_code != 200:
183
+ logger.error("파일 전송 실패 (%s): %s", res.status_code, safe_log_text(res.text))
181
184
  except Exception as e:
182
185
  logger.error("파일 전송 실패: %s", safe_log_text(e))
183
186
 
@@ -584,12 +587,11 @@ async def process_document_file(client, chat_id, file_id: str, filename: str, ca
584
587
  try:
585
588
  tmp.write_bytes(raw)
586
589
  async with _server_client() as lc:
587
- with open(tmp, "rb") as f:
588
- res = await lc.post(
589
- UPLOAD_DOC_URL,
590
- files={"file": (filename, f)},
591
- timeout=60.0,
592
- )
590
+ res = await lc.post(
591
+ UPLOAD_DOC_URL,
592
+ files={"file": (filename, raw)},
593
+ timeout=60.0,
594
+ )
593
595
  if res.status_code == 200:
594
596
  data = res.json()
595
597
  chars = data.get("chars") or len(raw)
@@ -16,7 +16,7 @@ from typing import Any, Dict, List
16
16
 
17
17
  from latticeai.core.legacy_compatibility import legacy_shim_report
18
18
 
19
- ARCHITECTURE_VERSION_TARGET = "10.8.0"
19
+ ARCHITECTURE_VERSION_TARGET = "10.9.0"
20
20
 
21
21
  PREFERRED_REFACTORING_ORDER = [
22
22
  "agent-runtime",
@@ -78,36 +78,22 @@ def _get_model_runtime_deps(runtime_state: Any):
78
78
  }
79
79
 
80
80
 
81
- async def prepare_and_load_model(
81
+ def _prepare_model_sources(
82
+ deps: Any,
83
+ parsed_provider: str,
84
+ parsed_model: str,
82
85
  model_id: str,
83
- request: Any,
84
- engine: Optional[str] = None,
85
- user_email: Optional[str] = None,
86
- adapter_path: Optional[str] = None,
87
- draft_model_id: Optional[str] = None,
88
- allow_download: bool = False,
89
- *,
90
- runtime_state: Any,
91
- ) -> Dict[str, object]:
92
- deps = _get_model_runtime_deps(runtime_state)
93
- model_id = deps["normalize_local_model_request"](model_id, engine)
94
- if not model_id:
95
- raise ModelRuntimeError(status_code=400, detail="모델 식별자가 비어 있습니다.")
96
-
97
- resolution = deps["_ModelResolution"].from_request(
98
- model_id,
99
- engine=engine,
100
- user_email=user_email or deps["get_current_user"](request),
101
- engine_aliases=deps["MODEL_ENGINE_ALIASES"],
102
- )
86
+ allow_download: bool,
87
+ ) -> Dict[str, Any]:
88
+ """Make sure the engine and weights this model needs exist locally.
103
89
 
104
- parsed_provider, parsed_model = deps["parse_model_ref"](model_id)
105
- if parsed_provider == "mlx":
106
- parsed_provider = "local_mlx"
107
- compatibility = deps["_model_runtime_compatibility"](parsed_model, engine=parsed_provider)
108
- if compatibility.get("supported") is False:
109
- raise ModelRuntimeError(status_code=400, detail=compatibility)
90
+ Every branch here shells out, downloads, or waits on a child server, so this
91
+ is deliberately a plain sync function: callers run it on a worker thread
92
+ (see :func:`prepare_and_load_model`) rather than on the event loop.
110
93
 
94
+ Returns the four values the caller needs back, including the two the
95
+ LM Studio branch rewrites (``parsed_model`` and ``model_id``).
96
+ """
111
97
  local_engines = {"local_mlx", "ollama", "vllm", "lmstudio", "llamacpp"}
112
98
  install_result: Dict[str, object] = {}
113
99
  download_result: Optional[Dict[str, object]] = None
@@ -169,6 +155,56 @@ async def prepare_and_load_model(
169
155
  model_id = f"lmstudio:{resolved_model}"
170
156
  download_result = ensured
171
157
 
158
+ return {
159
+ "install_result": install_result,
160
+ "download_result": download_result,
161
+ "parsed_model": parsed_model,
162
+ "model_id": model_id,
163
+ }
164
+
165
+
166
+ async def prepare_and_load_model(
167
+ model_id: str,
168
+ request: Any,
169
+ engine: Optional[str] = None,
170
+ user_email: Optional[str] = None,
171
+ adapter_path: Optional[str] = None,
172
+ draft_model_id: Optional[str] = None,
173
+ allow_download: bool = False,
174
+ *,
175
+ runtime_state: Any,
176
+ ) -> Dict[str, object]:
177
+ deps = _get_model_runtime_deps(runtime_state)
178
+ model_id = deps["normalize_local_model_request"](model_id, engine)
179
+ if not model_id:
180
+ raise ModelRuntimeError(status_code=400, detail="모델 식별자가 비어 있습니다.")
181
+
182
+ resolution = deps["_ModelResolution"].from_request(
183
+ model_id,
184
+ engine=engine,
185
+ user_email=user_email or deps["get_current_user"](request),
186
+ engine_aliases=deps["MODEL_ENGINE_ALIASES"],
187
+ )
188
+
189
+ parsed_provider, parsed_model = deps["parse_model_ref"](model_id)
190
+ if parsed_provider == "mlx":
191
+ parsed_provider = "local_mlx"
192
+ compatibility = deps["_model_runtime_compatibility"](parsed_model, engine=parsed_provider)
193
+ if compatibility.get("supported") is False:
194
+ raise ModelRuntimeError(status_code=400, detail=compatibility)
195
+
196
+ # Engine install, model download and local-server startup are all blocking
197
+ # and all measured in minutes. Run on the event loop they froze the whole
198
+ # server for the duration — the UI could not even poll /health to find out
199
+ # why. One hop to a worker thread; the async shape above is unchanged.
200
+ sources = await asyncio.to_thread(
201
+ _prepare_model_sources, deps, parsed_provider, parsed_model, model_id, allow_download
202
+ )
203
+ install_result = sources["install_result"]
204
+ download_result = sources["download_result"]
205
+ parsed_model = sources["parsed_model"]
206
+ model_id = sources["model_id"]
207
+
172
208
  effective_email = (user_email or deps["get_current_user"](request) or "").strip()
173
209
  user_api_key = deps["get_user_api_key"](effective_email, parsed_provider) if parsed_provider != "local_mlx" else None
174
210
  msg = await deps["router"].load_model(
@@ -18,7 +18,7 @@ from typing import Any, Dict, List
18
18
 
19
19
  from latticeai.services.architecture_readiness import architecture_readiness
20
20
 
21
- PRODUCT_VERSION_TARGET = "10.8.0"
21
+ PRODUCT_VERSION_TARGET = "10.9.0"
22
22
 
23
23
 
24
24
  @dataclass(frozen=True)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "10.8.0",
3
+ "version": "10.9.0",
4
4
  "description": "Lattice AI — local-first Digital Brain that keeps your knowledge durable across any AI model.",
5
5
  "homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
6
6
  "repository": {
@@ -24,9 +24,10 @@
24
24
  "build:assets": "vite build && node scripts/build_frontend_assets.mjs",
25
25
  "build:python": "node scripts/run_python.mjs -m build",
26
26
  "check:python": "node scripts/run_python.mjs scripts/check_python.py",
27
- "lint": "npm run lint:python && node --check tests/visual/mock_server.cjs && node --check tests/visual/v3.spec.js && npm run lint:frontend && npm run frontend:openapi:check && node scripts/check_i18n_literals.mjs && npm run check:i18n-namespaces && npm run check:bundle && npm run check:legacy-debt && npm run test:browser-extension && npm run test:vscode-extension && node scripts/check_release_evidence_bound.mjs",
27
+ "lint": "npm run lint:python && node --check tests/visual/mock_server.cjs && node --check tests/visual/v3.spec.js && npm run lint:frontend && npm run frontend:openapi:check && node scripts/check_i18n_literals.mjs && npm run check:i18n-namespaces && npm run check:bundle && npm run check:legacy-debt && npm run check:server-i18n && npm run test:browser-extension && npm run test:vscode-extension && node scripts/check_release_evidence_bound.mjs",
28
28
  "check:release-evidence-bound": "node scripts/check_release_evidence_bound.mjs",
29
29
  "check:legacy-debt": "node scripts/check_legacy_debt.mjs",
30
+ "check:server-i18n": "node scripts/check_server_i18n.mjs",
30
31
  "lint:python": "node scripts/run_python.mjs -m ruff check . && npm run typecheck:python",
31
32
  "lint:frontend": "node scripts/lint_frontend.mjs",
32
33
  "check:bundle": "node scripts/check_bundle_budget.mjs",
@@ -6,7 +6,7 @@ const root = process.cwd();
6
6
  const pkg = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8"));
7
7
  const version = pkg.version;
8
8
  const releaseDir = `output/release/v${version}`;
9
- const releaseTheme = "Within Reach";
9
+ const releaseTheme = "Never Blocks";
10
10
  const title = `${version} — ${releaseTheme}`;
11
11
  const escapedVersion = version.replaceAll(".", "\\.");
12
12
 
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Server-side i18n ratchet.
4
+ *
5
+ * Every string the API hands a person used to be a literal at the raise site,
6
+ * written in whichever language the author happened to be thinking in. One user
7
+ * could get `"사용자를 찾을 수 없습니다."` from one router and, two files over,
8
+ * `"Knowledge Graph ingestion is disabled."` — half the product in a language
9
+ * they never chose.
10
+ *
11
+ * `latticeai/core/messages.py` fixed the mechanism; this gate keeps the fix from
12
+ * eroding. Routers listed in LOCALIZED below are done: they must raise through
13
+ * `http_error(...)` / `translate(...)`, never a literal. Routers not yet listed
14
+ * are honestly *not* claimed to be localized — adding one to the list is how a
15
+ * migration is declared finished, and from then on it cannot slip back.
16
+ *
17
+ * Pass-throughs (`detail=str(exc)`, `detail=exc.to_detail()`, a variable) are
18
+ * allowed: the wording belongs to the service that raised, and moving it here
19
+ * would only relocate the problem.
20
+ */
21
+ import { readFileSync, readdirSync } from "node:fs";
22
+ import { join } from "node:path";
23
+
24
+ const API_DIR = "latticeai/api";
25
+
26
+ // Routers whose user-facing details are in the message catalog. Append here
27
+ // when a router is migrated — never remove. Module names carry no extension:
28
+ // `check_legacy_debt.mjs` rejects a bare "<module>.py" literal in scripts/,
29
+ // which is how the removed root shims used to be referenced.
30
+ const LOCALIZED = [
31
+ "admin",
32
+ "auth",
33
+ "browser",
34
+ "chat",
35
+ "chat_history",
36
+ "chat_intents",
37
+ "knowledge_graph",
38
+ "local_files",
39
+ "mcp",
40
+ "memory",
41
+ "models",
42
+ "network_boundary",
43
+ "portability",
44
+ "project_sessions",
45
+ "review_queue",
46
+ "setup",
47
+ "tools",
48
+ ];
49
+
50
+ const failures = [];
51
+ const known = new Set(readdirSync(API_DIR).filter((name) => name.endsWith(".py")));
52
+
53
+ for (const name of LOCALIZED) {
54
+ const file = `${name}.py`;
55
+ if (!known.has(file)) {
56
+ failures.push(`${file}: listed as localized but no such router exists`);
57
+ continue;
58
+ }
59
+ const lines = readFileSync(join(API_DIR, file), "utf8").split("\n");
60
+ lines.forEach((line, index) => {
61
+ const match = line.match(/detail\s*=\s*(.+)$/);
62
+ if (!match) return;
63
+ const value = match[1].trim();
64
+ // Anything that is not a quoted literal is a pass-through: `str(exc)`, a
65
+ // variable, `translate(...)`, a dict. Those carry no wording of their own.
66
+ if (!/^f?"/.test(value)) return;
67
+ // A literal used as an argument to a string method — `"; ".join(errors)` —
68
+ // is a separator, not a message.
69
+ if (/^f?"[^"]*"\s*\./.test(value)) return;
70
+ // An empty string carries no wording either.
71
+ if (/^f?"\s*"/.test(value)) return;
72
+ failures.push(
73
+ `${file}:${index + 1}: literal error detail — use http_error("<key>", …) `
74
+ + `with a key in latticeai/core/messages.py\n ${line.trim()}`,
75
+ );
76
+ });
77
+ }
78
+
79
+ if (failures.length) {
80
+ console.error("Server i18n gate failed:\n");
81
+ for (const failure of failures) console.error(" " + failure);
82
+ console.error(
83
+ `\n${failures.length} literal detail(s) in routers declared localized.`
84
+ + "\nAdd the message to latticeai/core/messages.py (both ko and en) and raise"
85
+ + "\nvia http_error(status, key, resolve_language(request)).",
86
+ );
87
+ process.exit(1);
88
+ }
89
+
90
+ const remaining = [...known].filter(
91
+ (entry) => entry !== "__init__.py" && !LOCALIZED.includes(entry.replace(/\.py$/, "")),
92
+ ).length;
93
+ console.log(
94
+ `Server i18n gate: ${LOCALIZED.length} router(s) localized and locked; `
95
+ + `${remaining} not yet claimed.`,
96
+ );
@@ -22,16 +22,25 @@
22
22
  ],
23
23
 
24
24
  "10.8.0": {
25
- "01-login.png": {},
26
- "02-recommended-models.png": {},
27
- "03-install-load-progress.png": {},
28
- "05-memory-graph.png": {
29
- "_why": "The provenance meter in this screen's header wrapped into a ragged three-line block that ran into the page title. It is a bordered column with a straight left edge now."
30
- },
31
25
  "04-brain-chat-home.png": {
32
- "_why": "The Brain organism sits in this screen's greeting banner and moved 7.34% of that band between 10.6.3 and 10.7.0 with no layout intent, which is why 04 carries the 8% live threshold. 10.8.0 changed the suggestion deck and the shelf row below the composer; measuring that region directly is both stricter (the claim names where) and able to see a change the whole-image metric cannot.",
33
- "region": [0.0, 0.45, 1.0, 0.85],
26
+ "_why": "Elevated brain-chat-home visual layout with glassmorphic station card, ambient radial mesh aura, gradient title, glowing dot prompt cards, and refined toolbar styling.",
34
27
  "min_pct": 1.5
35
28
  }
29
+ },
30
+
31
+ "10.9.0": {
32
+ "_why": [
33
+ "This release claims no screen redesign, and the empty claim is the",
34
+ "honest statement of that: 10.9.0 is a correctness release (event-loop",
35
+ "blocking, a focus ring that faded in too slowly to see, an organism",
36
+ "stuck in 'thinking', localized server errors).",
37
+ "",
38
+ "Its two visual changes are both invisible at the capture viewport by",
39
+ "construction. The welcome step's compaction lives under",
40
+ "`@media (max-height: 820px)` and captures run at 1440x900; the capture",
41
+ "pills' focus border only differs while an input inside them has focus,",
42
+ "which no screenshot holds. `tests/visual/v3.spec.js` asserts both",
43
+ "directly instead — a pixel diff is the wrong instrument for either."
44
+ ]
36
45
  }
37
46
  }
@@ -1584,7 +1584,7 @@ dependencies = [
1584
1584
 
1585
1585
  [[package]]
1586
1586
  name = "lattice-ai-desktop"
1587
- version = "10.8.0"
1587
+ version = "10.9.0"
1588
1588
  dependencies = [
1589
1589
  "plist",
1590
1590
  "serde",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "lattice-ai-desktop"
3
- version = "10.8.0"
3
+ version = "10.9.0"
4
4
  description = "Lattice AI Digital Brain desktop shell"
5
5
  authors = ["TaeSoo Park"]
6
6
  edition = "2021"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://schema.tauri.app/config/2",
3
3
  "productName": "Lattice AI",
4
- "version": "10.8.0",
4
+ "version": "10.9.0",
5
5
  "identifier": "ai.lattice.desktop",
6
6
  "build": {
7
7
  "beforeDevCommand": "npm run frontend:dev",
@@ -1,45 +1,45 @@
1
1
  {
2
- "version": "10.8.0",
2
+ "version": "10.9.0",
3
3
  "generated_at": "vite",
4
4
  "entrypoints": {
5
- "app": "/static/app/assets/index-_ldE9TAX.js"
5
+ "app": "/static/app/assets/index-CxOcwsHV.js"
6
6
  },
7
7
  "assets": {
8
8
  "../node_modules/@tauri-apps/api/core.js": "/static/app/assets/core-CwxXejkd.js",
9
- "_BrainSignals-aDt-nSsW.js": "/static/app/assets/BrainSignals-aDt-nSsW.js",
10
- "_LivingBrain-CXb8094H.js": "/static/app/assets/LivingBrain-CXb8094H.js",
11
- "_ReviewCard-Be7E7X18.js": "/static/app/assets/ReviewCard-Be7E7X18.js",
12
- "_arrow-left-DC9Oquhs.js": "/static/app/assets/arrow-left-DC9Oquhs.js",
13
- "_bot-BR0eoeXY.js": "/static/app/assets/bot-BR0eoeXY.js",
14
- "_brain-BmWa1wea.js": "/static/app/assets/brain-BmWa1wea.js",
15
- "_button-U1nU7xX4.js": "/static/app/assets/button-U1nU7xX4.js",
16
- "_circle-pause-DG5KHjDL.js": "/static/app/assets/circle-pause-DG5KHjDL.js",
17
- "_circle-play-Chhcuq90.js": "/static/app/assets/circle-play-Chhcuq90.js",
18
- "_cpu-pkOSlT9h.js": "/static/app/assets/cpu-pkOSlT9h.js",
19
- "_download-CSRwz923.js": "/static/app/assets/download-CSRwz923.js",
20
- "_folder-open-DiMJ7W_7.js": "/static/app/assets/folder-open-DiMJ7W_7.js",
21
- "_hard-drive-iyLPAPdp.js": "/static/app/assets/hard-drive-iyLPAPdp.js",
22
- "_input-e_r2hFAY.js": "/static/app/assets/input-e_r2hFAY.js",
23
- "_permissionCopy-9uOHktz3.js": "/static/app/assets/permissionCopy-9uOHktz3.js",
24
- "_primitives-CnEAOmg2.js": "/static/app/assets/primitives-CnEAOmg2.js",
25
- "_search-veep4n6f.js": "/static/app/assets/search-veep4n6f.js",
26
- "_share-2-DLDJJKmI.js": "/static/app/assets/share-2-DLDJJKmI.js",
27
- "_shield-alert-BTtE-2EZ.js": "/static/app/assets/shield-alert-BTtE-2EZ.js",
28
- "_textarea-Bbzkcgqe.js": "/static/app/assets/textarea-Bbzkcgqe.js",
29
- "_useFocusTrap-DJzQd-Za.js": "/static/app/assets/useFocusTrap-DJzQd-Za.js",
30
- "_useQuery-6R_tqHRe.js": "/static/app/assets/useQuery-6R_tqHRe.js",
31
- "_utils-XDsjcrhS.js": "/static/app/assets/utils-XDsjcrhS.js",
32
- "_workspace-CwrG8LHq.js": "/static/app/assets/workspace-CwrG8LHq.js",
33
- "index.html": "/static/app/assets/index-_ldE9TAX.js",
34
- "assets/index-BZRvGOM2.css": "/static/app/assets/index-BZRvGOM2.css",
35
- "src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-BaiqFWLO.js",
36
- "src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-Bs8SR8fE.js",
37
- "src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-BaH5MDce.js",
38
- "src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-Dq_MmPBl.js",
39
- "src/pages/Act.tsx": "/static/app/assets/Act-CbQNsFgc.js",
40
- "src/pages/Brain.tsx": "/static/app/assets/Brain-BZIPsZlH.js",
41
- "src/pages/Capture.tsx": "/static/app/assets/Capture-DDv940Bv.js",
42
- "src/pages/Library.tsx": "/static/app/assets/Library-BkShbqmN.js",
43
- "src/pages/System.tsx": "/static/app/assets/System-DCstbTxC.js"
9
+ "_BrainSignals-BeE8RJo3.js": "/static/app/assets/BrainSignals-BeE8RJo3.js",
10
+ "_LivingBrain-BSa0wpFG.js": "/static/app/assets/LivingBrain-BSa0wpFG.js",
11
+ "_ReviewCard-BepjSDpN.js": "/static/app/assets/ReviewCard-BepjSDpN.js",
12
+ "_arrow-left-ig7AZU8B.js": "/static/app/assets/arrow-left-ig7AZU8B.js",
13
+ "_bot-DQj0-LkM.js": "/static/app/assets/bot-DQj0-LkM.js",
14
+ "_brain-D8OEwmVj.js": "/static/app/assets/brain-D8OEwmVj.js",
15
+ "_button-CmTknyAP.js": "/static/app/assets/button-CmTknyAP.js",
16
+ "_circle-pause-yTCWRziJ.js": "/static/app/assets/circle-pause-yTCWRziJ.js",
17
+ "_circle-play-Ccrva84R.js": "/static/app/assets/circle-play-Ccrva84R.js",
18
+ "_cpu-CbJqWTlS.js": "/static/app/assets/cpu-CbJqWTlS.js",
19
+ "_download-CkSzbzU-.js": "/static/app/assets/download-CkSzbzU-.js",
20
+ "_folder-open-CKyjQ4PU.js": "/static/app/assets/folder-open-CKyjQ4PU.js",
21
+ "_hard-drive-DAzk9um0.js": "/static/app/assets/hard-drive-DAzk9um0.js",
22
+ "_input-DcMETmZ7.js": "/static/app/assets/input-DcMETmZ7.js",
23
+ "_permissionCopy-BVf13_25.js": "/static/app/assets/permissionCopy-BVf13_25.js",
24
+ "_primitives-CQV9Q2YM.js": "/static/app/assets/primitives-CQV9Q2YM.js",
25
+ "_search-CXGASMMH.js": "/static/app/assets/search-CXGASMMH.js",
26
+ "_share-2-COWCHNZm.js": "/static/app/assets/share-2-COWCHNZm.js",
27
+ "_shield-alert-BDrvilyK.js": "/static/app/assets/shield-alert-BDrvilyK.js",
28
+ "_textarea-rUmsc8cP.js": "/static/app/assets/textarea-rUmsc8cP.js",
29
+ "_useFocusTrap-Bi5UY_8v.js": "/static/app/assets/useFocusTrap-Bi5UY_8v.js",
30
+ "_useQuery-C-AicB-3.js": "/static/app/assets/useQuery-C-AicB-3.js",
31
+ "_utils-BMwWg78e.js": "/static/app/assets/utils-BMwWg78e.js",
32
+ "_workspace-Y93tls8P.js": "/static/app/assets/workspace-Y93tls8P.js",
33
+ "index.html": "/static/app/assets/index-CxOcwsHV.js",
34
+ "assets/index-BfD-jhA9.css": "/static/app/assets/index-BfD-jhA9.css",
35
+ "src/components/ProductFlow.tsx": "/static/app/assets/ProductFlow-IP4Q-5aQ.js",
36
+ "src/features/admin/AdminConsole.tsx": "/static/app/assets/AdminConsole-3UkIEWGA.js",
37
+ "src/features/brain/BrainHome.tsx": "/static/app/assets/BrainHome-CMDqgJF4.js",
38
+ "src/features/command/CommandPalette.tsx": "/static/app/assets/CommandPalette-86m4FCcN.js",
39
+ "src/pages/Act.tsx": "/static/app/assets/Act-CS9IeqUX.js",
40
+ "src/pages/Brain.tsx": "/static/app/assets/Brain-B22EmNqS.js",
41
+ "src/pages/Capture.tsx": "/static/app/assets/Capture-ZX9bQh68.js",
42
+ "src/pages/Library.tsx": "/static/app/assets/Library-Bhz5LUca.js",
43
+ "src/pages/System.tsx": "/static/app/assets/System-Bwx1h_jT.js"
44
44
  }
45
45
  }