ltcai 8.7.0 → 8.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 (103) hide show
  1. package/README.md +38 -26
  2. package/auto_setup.py +73 -8
  3. package/docs/CHANGELOG.md +63 -0
  4. package/docs/CODE_REVIEW_2026-07-06.md +764 -0
  5. package/docs/COMMUNITY_AND_PLUGINS.md +4 -3
  6. package/docs/DEVELOPMENT.md +10 -10
  7. package/docs/LEGACY_COMPATIBILITY.md +33 -14
  8. package/docs/ONBOARDING.md +2 -2
  9. package/docs/PRODUCT_DIRECTION_REVIEW.md +3 -2
  10. package/docs/TRUST_MODEL.md +5 -1
  11. package/docs/WHY_LATTICE.md +4 -3
  12. package/docs/architecture.md +4 -0
  13. package/docs/kg-schema.md +1 -1
  14. package/kg_schema.py +1 -1
  15. package/knowledge_graph.py +2 -2
  16. package/lattice_brain/__init__.py +1 -1
  17. package/lattice_brain/conversations.py +156 -21
  18. package/lattice_brain/core.py +1 -1
  19. package/lattice_brain/graph/_kg_common.py +12 -34
  20. package/lattice_brain/graph/json_utils.py +25 -0
  21. package/lattice_brain/graph/retrieval.py +66 -27
  22. package/lattice_brain/graph/runtime.py +16 -0
  23. package/lattice_brain/ingestion.py +35 -20
  24. package/lattice_brain/runtime/agent_runtime.py +37 -3
  25. package/lattice_brain/runtime/multi_agent.py +1 -1
  26. package/latticeai/__init__.py +1 -1
  27. package/latticeai/api/chat.py +31 -14
  28. package/latticeai/api/mcp.py +3 -2
  29. package/latticeai/api/models.py +4 -1
  30. package/latticeai/api/permissions.py +69 -30
  31. package/latticeai/api/setup.py +17 -2
  32. package/latticeai/api/tools.py +104 -62
  33. package/latticeai/app_factory.py +93 -10
  34. package/latticeai/core/agent.py +25 -7
  35. package/latticeai/core/legacy_compatibility.py +36 -25
  36. package/latticeai/core/marketplace.py +1 -1
  37. package/latticeai/core/sessions.py +11 -3
  38. package/latticeai/core/tool_registry.py +15 -4
  39. package/latticeai/core/workspace_os.py +1 -1
  40. package/latticeai/runtime/bootstrap.py +1 -1
  41. package/latticeai/runtime/persistence_runtime.py +1 -1
  42. package/latticeai/runtime/platform_services_runtime.py +1 -1
  43. package/latticeai/services/app_context.py +1 -0
  44. package/latticeai/services/architecture_readiness.py +2 -2
  45. package/latticeai/services/memory_service.py +38 -7
  46. package/latticeai/services/model_engines.py +79 -12
  47. package/latticeai/services/model_runtime.py +24 -4
  48. package/latticeai/services/process_audit.py +208 -0
  49. package/latticeai/services/product_readiness.py +11 -11
  50. package/latticeai/services/search_service.py +106 -30
  51. package/latticeai/services/tool_dispatch.py +66 -0
  52. package/latticeai/services/workspace_service.py +15 -0
  53. package/package.json +1 -1
  54. package/scripts/check_i18n_literals.mjs +20 -8
  55. package/scripts/i18n_literal_allowlist.json +34 -0
  56. package/scripts/lint_frontend.mjs +6 -2
  57. package/setup_wizard.py +185 -19
  58. package/src-tauri/Cargo.lock +1 -1
  59. package/src-tauri/Cargo.toml +1 -1
  60. package/src-tauri/tauri.conf.json +1 -1
  61. package/static/app/asset-manifest.json +11 -11
  62. package/static/app/assets/{Act-_U7mhXir.js → Act-fZokUnC0.js} +1 -1
  63. package/static/app/assets/{Brain-BxyTHZ21.js → Brain-DtyuWubr.js} +2 -2
  64. package/static/app/assets/{Capture-DyDKWNh9.js → Capture-D5KV3Cu7.js} +1 -1
  65. package/static/app/assets/{Library-DJ8KioFM.js → Library-C9kyFkSt.js} +1 -1
  66. package/static/app/assets/{System-C0FIb3OO.js → System-VbChmX7r.js} +1 -1
  67. package/static/app/assets/index-DCh5AoXt.css +2 -0
  68. package/static/app/assets/index-DPdcPoF0.js +17 -0
  69. package/static/app/assets/{primitives-BywkNS3f.js → primitives-DFeanEV6.js} +1 -1
  70. package/static/app/assets/{textarea-CQ61Rycp.js → textarea-CD8UNKIy.js} +1 -1
  71. package/static/app/index.html +2 -2
  72. package/static/sw.js +1 -1
  73. package/lattice_brain/_kg_common.py +0 -11
  74. package/lattice_brain/discovery.py +0 -11
  75. package/lattice_brain/documents.py +0 -11
  76. package/lattice_brain/identity.py +0 -11
  77. package/lattice_brain/ingest.py +0 -11
  78. package/lattice_brain/network.py +0 -11
  79. package/lattice_brain/projection.py +0 -11
  80. package/lattice_brain/provenance.py +0 -11
  81. package/lattice_brain/retrieval.py +0 -11
  82. package/lattice_brain/schema.py +0 -11
  83. package/lattice_brain/store.py +0 -11
  84. package/lattice_brain/write_master.py +0 -11
  85. package/latticeai/brain/__init__.py +0 -36
  86. package/latticeai/brain/_kg_common.py +0 -17
  87. package/latticeai/brain/context.py +0 -17
  88. package/latticeai/brain/conversations.py +0 -17
  89. package/latticeai/brain/discovery.py +0 -17
  90. package/latticeai/brain/documents.py +0 -17
  91. package/latticeai/brain/identity.py +0 -17
  92. package/latticeai/brain/ingest.py +0 -17
  93. package/latticeai/brain/memory.py +0 -17
  94. package/latticeai/brain/network.py +0 -17
  95. package/latticeai/brain/projection.py +0 -17
  96. package/latticeai/brain/provenance.py +0 -17
  97. package/latticeai/brain/retrieval.py +0 -17
  98. package/latticeai/brain/schema.py +0 -17
  99. package/latticeai/brain/store.py +0 -17
  100. package/latticeai/brain/write_master.py +0 -17
  101. package/latticeai/services/agent_runtime.py +0 -11
  102. package/static/app/assets/index-Bh7IIlyY.js +0 -16
  103. package/static/app/assets/index-_M5aCv21.css +0 -2
package/setup_wizard.py CHANGED
@@ -21,6 +21,14 @@ import time
21
21
  from pathlib import Path
22
22
  from typing import Any, AsyncIterator, Dict, List, Tuple
23
23
 
24
+ from latticeai.services.process_audit import (
25
+ CommandConfirmationError,
26
+ append_process_audit_event,
27
+ command_plan,
28
+ command_plan_for_commands,
29
+ require_command_confirmation,
30
+ )
31
+
24
32
  # ── Helpers ───────────────────────────────────────────────────────────────────
25
33
 
26
34
  def _cmd(args: List[str], timeout: int = 10) -> str:
@@ -33,6 +41,61 @@ def _cmd(args: List[str], timeout: int = 10) -> str:
33
41
  def _sse(data: Dict) -> str:
34
42
  return f"data: {_json.dumps(data, ensure_ascii=False)}\n\n"
35
43
 
44
+
45
+ def _action_commands(action: Dict[str, Any]) -> List[List[str]]:
46
+ atype = action.get("type")
47
+ if atype == "pip":
48
+ return [[sys.executable, "-m", "pip", "install", "--upgrade", str(pkg)] for pkg in action.get("packages", [])]
49
+ if atype == "brew":
50
+ package = str(action.get("package") or "")
51
+ return [["brew", "install", package]] if package else []
52
+ return []
53
+
54
+
55
+ def _action_command_plan(action: Dict[str, Any], *, name: str) -> Dict[str, Any] | None:
56
+ commands = _action_commands(action)
57
+ if not commands:
58
+ return None
59
+ return command_plan_for_commands(
60
+ commands,
61
+ name=name,
62
+ purpose="setup_wizard_install",
63
+ metadata={"action_type": action.get("type")},
64
+ )
65
+
66
+
67
+ def _attach_action_plan(action: Dict[str, Any] | None, *, name: str) -> Dict[str, Any] | None:
68
+ if not isinstance(action, dict):
69
+ return action
70
+ plan = _action_command_plan(action, name=name)
71
+ if not plan:
72
+ return action
73
+ hydrated = dict(action)
74
+ hydrated["command_plan"] = plan
75
+ hydrated["confirmation_token"] = plan["confirmation_token"]
76
+ return hydrated
77
+
78
+
79
+ def _hydrate_install_actions(groups: Dict[str, Any]) -> Dict[str, Any]:
80
+ for group_name in ("components", "engines", "models", "mcps"):
81
+ items = groups.get(group_name)
82
+ if not isinstance(items, list):
83
+ continue
84
+ for item in items:
85
+ if isinstance(item, dict):
86
+ item["action"] = _attach_action_plan(
87
+ item.get("action"),
88
+ name=str(item.get("id") or item.get("name") or group_name),
89
+ )
90
+ return groups
91
+
92
+
93
+ def _verify_action_confirmation(action: Dict[str, Any], token: str | None, *, name: str) -> bool:
94
+ plan = _action_command_plan(action, name=name)
95
+ if not plan:
96
+ return True
97
+ return str(token or "").strip() == plan["confirmation_token"]
98
+
36
99
  OFFICIAL_DOWNLOADS: Dict[str, str] = {
37
100
  "homebrew": "https://brew.sh",
38
101
  "python": "https://www.python.org/downloads/",
@@ -933,7 +996,7 @@ def get_recommendations(env: Dict[str, Any]) -> Dict[str, Any]:
933
996
  },
934
997
  ]
935
998
 
936
- return {
999
+ return _hydrate_install_actions({
937
1000
  "components": components,
938
1001
  "engines": engines,
939
1002
  "models": models,
@@ -954,7 +1017,7 @@ def get_recommendations(env: Dict[str, Any]) -> Dict[str, Any]:
954
1017
  "is_apple_silicon": is_apple,
955
1018
  "max_model_gb": round(max_model_gb, 1),
956
1019
  },
957
- }
1020
+ })
958
1021
 
959
1022
  # ── Installation Stream ───────────────────────────────────────────────────────
960
1023
 
@@ -972,7 +1035,12 @@ def _verify_action(action: Dict[str, Any]) -> Tuple[bool, str]:
972
1035
  return True, "검증 항목 없음"
973
1036
 
974
1037
 
975
- async def _repair_action(action: Dict[str, Any]) -> Tuple[bool, str]:
1038
+ async def _repair_action(
1039
+ action: Dict[str, Any],
1040
+ *,
1041
+ confirmation_token: str | None = None,
1042
+ actor: str | None = None,
1043
+ ) -> Tuple[bool, str]:
976
1044
  binary = action.get("binary")
977
1045
  if binary:
978
1046
  repair_path_for(binary)
@@ -982,15 +1050,23 @@ async def _repair_action(action: Dict[str, Any]) -> Tuple[bool, str]:
982
1050
  if action.get("type") == "pip":
983
1051
  packages = action.get("packages", [])
984
1052
  if packages:
1053
+ if not _verify_action_confirmation(action, confirmation_token, name="repair_action"):
1054
+ return False, "설치 명령 확인 토큰이 일치하지 않습니다."
985
1055
  for pkg in packages:
986
- success, err = await _pip_install(pkg)
1056
+ success, err = await _pip_install(pkg, confirmed=True, actor=actor)
987
1057
  if not success:
988
1058
  return False, err
989
1059
  return _verify_action(action)
990
1060
  return False, "자동 복구 방법을 찾지 못했습니다."
991
1061
 
992
1062
 
993
- async def install_stream(items: List[Dict], router: Any) -> AsyncIterator[str]:
1063
+ async def install_stream(
1064
+ items: List[Dict],
1065
+ router: Any,
1066
+ *,
1067
+ confirmation_token: str | None = None,
1068
+ user_email: str | None = None,
1069
+ ) -> AsyncIterator[str]:
994
1070
  for item in items:
995
1071
  item_id = item.get("id", "unknown")
996
1072
  name = item.get("name", item_id)
@@ -1006,10 +1082,14 @@ async def install_stream(items: List[Dict], router: Any) -> AsyncIterator[str]:
1006
1082
 
1007
1083
  if atype == "pip":
1008
1084
  packages = action.get("packages", [])
1085
+ token = confirmation_token or action.get("confirmation_token") or (action.get("command_plan") or {}).get("confirmation_token")
1086
+ if not _verify_action_confirmation(action, token, name=str(item_id)):
1087
+ yield _sse({"id": item_id, "status": "error", "msg": "설치 명령 확인 토큰이 일치하지 않습니다."})
1088
+ continue
1009
1089
  ok = True
1010
1090
  for pkg in packages:
1011
1091
  yield _sse({"id": item_id, "status": "running", "msg": f"pip install {pkg} ..."})
1012
- success, err = await _pip_install(pkg)
1092
+ success, err = await _pip_install(pkg, confirmed=True, actor=user_email)
1013
1093
  if success:
1014
1094
  yield _sse({"id": item_id, "status": "progress", "msg": f"{pkg} 설치 완료"})
1015
1095
  else:
@@ -1023,13 +1103,17 @@ async def install_stream(items: List[Dict], router: Any) -> AsyncIterator[str]:
1023
1103
  yield _sse({"id": item_id, "status": "done", "msg": f"{name} 설치 · 검증 완료 ✅\n{detail}"})
1024
1104
  else:
1025
1105
  yield _sse({"id": item_id, "status": "running", "msg": f"검증 실패 — 자동 복구 중...\n{detail}"})
1026
- repaired, repair_msg = await _repair_action(action)
1106
+ repaired, repair_msg = await _repair_action(action, confirmation_token=token, actor=user_email)
1027
1107
  yield _sse({"id": item_id, "status": "done" if repaired else "error", "msg": repair_msg[:500]})
1028
1108
 
1029
1109
  elif atype == "brew":
1030
1110
  pkg = action.get("package", "")
1111
+ token = confirmation_token or action.get("confirmation_token") or (action.get("command_plan") or {}).get("confirmation_token")
1112
+ if not _verify_action_confirmation(action, token, name=str(item_id)):
1113
+ yield _sse({"id": item_id, "status": "error", "msg": "설치 명령 확인 토큰이 일치하지 않습니다."})
1114
+ continue
1031
1115
  yield _sse({"id": item_id, "status": "running", "msg": f"brew install {pkg} ..."})
1032
- success, err = await _brew_install(pkg)
1116
+ success, err = await _brew_install(pkg, confirmed=True, actor=user_email)
1033
1117
  if success:
1034
1118
  yield _sse({"id": item_id, "status": "running", "msg": "설치 완료 감지 · PATH 보정 중..."})
1035
1119
  binary = action.get("binary")
@@ -1040,7 +1124,7 @@ async def install_stream(items: List[Dict], router: Any) -> AsyncIterator[str]:
1040
1124
  yield _sse({"id": item_id, "status": "done", "msg": f"{name} 설치 · 연결 · 검증 완료 ✅\n{detail}"})
1041
1125
  else:
1042
1126
  yield _sse({"id": item_id, "status": "running", "msg": f"검증 실패 — 자동 복구 중...\n{detail}"})
1043
- repaired, repair_msg = await _repair_action(action)
1127
+ repaired, repair_msg = await _repair_action(action, confirmation_token=token, actor=user_email)
1044
1128
  yield _sse({"id": item_id, "status": "done" if repaired else "error", "msg": repair_msg[:500]})
1045
1129
  else:
1046
1130
  url = action.get("official_url") or action.get("url")
@@ -1094,49 +1178,131 @@ async def install_stream(items: List[Dict], router: Any) -> AsyncIterator[str]:
1094
1178
  yield _sse({"status": "complete", "msg": "모든 항목 처리 완료!"})
1095
1179
 
1096
1180
 
1097
- async def _pip_install(package: str) -> Tuple[bool, str]:
1181
+ async def _pip_install(
1182
+ package: str,
1183
+ *,
1184
+ confirmation_token: str | None = None,
1185
+ confirmed: bool = False,
1186
+ actor: str | None = None,
1187
+ ) -> Tuple[bool, str]:
1188
+ command = [sys.executable, "-m", "pip", "install", "--upgrade", package]
1189
+ plan = command_plan(
1190
+ command,
1191
+ name=f"pip:{package}",
1192
+ purpose="setup_wizard_install",
1193
+ metadata={"package": package},
1194
+ )
1098
1195
  try:
1196
+ if not confirmed:
1197
+ require_command_confirmation(command, confirmation_token, purpose="setup_wizard_install")
1198
+ append_process_audit_event("setup_wizard_install", plan=plan, status="started", user_email=actor)
1099
1199
  proc = await asyncio.create_subprocess_exec(
1100
- sys.executable, "-m", "pip", "install", "--upgrade", package,
1200
+ *command,
1101
1201
  stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
1102
1202
  )
1103
1203
  _, stderr = await asyncio.wait_for(proc.communicate(), timeout=600)
1204
+ stderr_text = stderr.decode(errors="replace")
1205
+ append_process_audit_event(
1206
+ "setup_wizard_install",
1207
+ plan=plan,
1208
+ status="finished",
1209
+ user_email=actor,
1210
+ returncode=proc.returncode,
1211
+ stderr=stderr_text,
1212
+ )
1104
1213
  if proc.returncode == 0:
1105
1214
  return True, ""
1106
- return False, stderr.decode(errors="replace")
1215
+ return False, stderr_text
1216
+ except CommandConfirmationError as e:
1217
+ append_process_audit_event("setup_wizard_install", plan=plan, status="denied", user_email=actor, error=str(e))
1218
+ return False, str(e)
1107
1219
  except asyncio.TimeoutError:
1220
+ append_process_audit_event("setup_wizard_install", plan=plan, status="timeout", user_email=actor)
1108
1221
  return False, "설치 시간 초과 (10분)"
1109
1222
  except Exception as e:
1223
+ append_process_audit_event("setup_wizard_install", plan=plan, status="error", user_email=actor, error=str(e))
1110
1224
  return False, str(e)
1111
1225
 
1112
1226
 
1113
- async def _brew_install(package: str) -> Tuple[bool, str]:
1227
+ async def _brew_install(
1228
+ package: str,
1229
+ *,
1230
+ confirmation_token: str | None = None,
1231
+ confirmed: bool = False,
1232
+ actor: str | None = None,
1233
+ ) -> Tuple[bool, str]:
1114
1234
  brew = shutil.which("brew")
1115
1235
  if not brew:
1116
1236
  return False, "Homebrew 미설치 — https://brew.sh 에서 설치하세요"
1237
+ command = [brew, "install", package]
1238
+ plan = command_plan(
1239
+ command,
1240
+ name=f"brew:{package}",
1241
+ purpose="setup_wizard_install",
1242
+ metadata={"package": package},
1243
+ )
1117
1244
  try:
1245
+ if not confirmed:
1246
+ require_command_confirmation(command, confirmation_token, purpose="setup_wizard_install")
1247
+ append_process_audit_event("setup_wizard_install", plan=plan, status="started", user_email=actor)
1118
1248
  proc = await asyncio.create_subprocess_exec(
1119
- brew, "install", package,
1249
+ *command,
1120
1250
  stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
1121
1251
  )
1122
1252
  _, stderr = await asyncio.wait_for(proc.communicate(), timeout=300)
1253
+ stderr_text = stderr.decode(errors="replace")
1254
+ append_process_audit_event(
1255
+ "setup_wizard_install",
1256
+ plan=plan,
1257
+ status="finished",
1258
+ user_email=actor,
1259
+ returncode=proc.returncode,
1260
+ stderr=stderr_text,
1261
+ )
1123
1262
  if proc.returncode == 0:
1124
1263
  return True, ""
1125
- return False, stderr.decode(errors="replace")
1264
+ return False, stderr_text
1265
+ except CommandConfirmationError as e:
1266
+ append_process_audit_event("setup_wizard_install", plan=plan, status="denied", user_email=actor, error=str(e))
1267
+ return False, str(e)
1126
1268
  except asyncio.TimeoutError:
1269
+ append_process_audit_event("setup_wizard_install", plan=plan, status="timeout", user_email=actor)
1127
1270
  return False, "설치 시간 초과 (5분)"
1128
1271
  except Exception as e:
1272
+ append_process_audit_event("setup_wizard_install", plan=plan, status="error", user_email=actor, error=str(e))
1129
1273
  return False, str(e)
1130
1274
 
1131
1275
 
1132
1276
  def open_url(url: str) -> None:
1277
+ command: List[str]
1133
1278
  try:
1134
1279
  system = platform.system()
1135
1280
  if system == "Darwin":
1136
- subprocess.Popen(["open", url])
1281
+ command = ["open", url]
1282
+ plan = command_plan(command, name="open_url", purpose="setup_wizard_open_url")
1283
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="started")
1284
+ subprocess.Popen(command)
1285
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="spawned")
1137
1286
  elif system == "Windows":
1138
- subprocess.Popen(["start", "", url], shell=True)
1287
+ command = ["start", "", url]
1288
+ plan = command_plan(command, name="open_url", purpose="setup_wizard_open_url")
1289
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="started")
1290
+ subprocess.Popen(command, shell=True)
1291
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="spawned")
1139
1292
  else:
1140
- subprocess.Popen(["xdg-open", url])
1141
- except Exception:
1293
+ command = ["xdg-open", url]
1294
+ plan = command_plan(command, name="open_url", purpose="setup_wizard_open_url")
1295
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="started")
1296
+ subprocess.Popen(command)
1297
+ append_process_audit_event("setup_wizard_open_url", plan=plan, status="spawned")
1298
+ except Exception as exc:
1299
+ try:
1300
+ append_process_audit_event(
1301
+ "setup_wizard_open_url",
1302
+ plan=command_plan(["open_url", url], name="open_url", purpose="setup_wizard_open_url"),
1303
+ status="error",
1304
+ error=str(exc),
1305
+ )
1306
+ except Exception:
1307
+ pass
1142
1308
  pass
@@ -1584,7 +1584,7 @@ dependencies = [
1584
1584
 
1585
1585
  [[package]]
1586
1586
  name = "lattice-ai-desktop"
1587
- version = "8.7.0"
1587
+ version = "8.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 = "8.7.0"
3
+ version = "8.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": "8.7.0",
4
+ "version": "8.9.0",
5
5
  "identifier": "ai.lattice.desktop",
6
6
  "build": {
7
7
  "beforeDevCommand": "npm run frontend:dev",
@@ -1,19 +1,19 @@
1
1
  {
2
- "version": "8.7.0",
2
+ "version": "8.9.0",
3
3
  "generated_at": "vite",
4
4
  "entrypoints": {
5
- "app": "/static/app/assets/index-Bh7IIlyY.js"
5
+ "app": "/static/app/assets/index-DPdcPoF0.js"
6
6
  },
7
7
  "assets": {
8
8
  "../node_modules/@tauri-apps/api/core.js": "/static/app/assets/core-CwxXejkd.js",
9
- "_primitives-BywkNS3f.js": "/static/app/assets/primitives-BywkNS3f.js",
10
- "_textarea-CQ61Rycp.js": "/static/app/assets/textarea-CQ61Rycp.js",
11
- "index.html": "/static/app/assets/index-Bh7IIlyY.js",
12
- "assets/index-_M5aCv21.css": "/static/app/assets/index-_M5aCv21.css",
13
- "src/pages/Act.tsx": "/static/app/assets/Act-_U7mhXir.js",
14
- "src/pages/Brain.tsx": "/static/app/assets/Brain-BxyTHZ21.js",
15
- "src/pages/Capture.tsx": "/static/app/assets/Capture-DyDKWNh9.js",
16
- "src/pages/Library.tsx": "/static/app/assets/Library-DJ8KioFM.js",
17
- "src/pages/System.tsx": "/static/app/assets/System-C0FIb3OO.js"
9
+ "_primitives-DFeanEV6.js": "/static/app/assets/primitives-DFeanEV6.js",
10
+ "_textarea-CD8UNKIy.js": "/static/app/assets/textarea-CD8UNKIy.js",
11
+ "index.html": "/static/app/assets/index-DPdcPoF0.js",
12
+ "assets/index-DCh5AoXt.css": "/static/app/assets/index-DCh5AoXt.css",
13
+ "src/pages/Act.tsx": "/static/app/assets/Act-fZokUnC0.js",
14
+ "src/pages/Brain.tsx": "/static/app/assets/Brain-DtyuWubr.js",
15
+ "src/pages/Capture.tsx": "/static/app/assets/Capture-D5KV3Cu7.js",
16
+ "src/pages/Library.tsx": "/static/app/assets/Library-C9kyFkSt.js",
17
+ "src/pages/System.tsx": "/static/app/assets/System-VbChmX7r.js"
18
18
  }
19
19
  }