ltcai 3.6.0 → 4.0.1

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 (238) hide show
  1. package/README.md +39 -31
  2. package/docs/CHANGELOG.md +64 -0
  3. package/docs/REALTIME_COLLABORATION.md +3 -3
  4. package/docs/V3_FRONTEND.md +9 -8
  5. package/docs/V4_BRAIN_ARCHITECTURE.md +322 -0
  6. package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +552 -0
  7. package/docs/V4_IMPLEMENTATION_PLAN.md +470 -0
  8. package/docs/kg-schema.md +51 -53
  9. package/docs/spec-vs-impl.md +10 -10
  10. package/kg_schema.py +2 -520
  11. package/knowledge_graph.py +37 -4629
  12. package/knowledge_graph_api.py +11 -127
  13. package/latticeai/__init__.py +1 -1
  14. package/latticeai/api/admin.py +16 -17
  15. package/latticeai/api/agents.py +20 -7
  16. package/latticeai/api/auth.py +46 -15
  17. package/latticeai/api/chat.py +112 -76
  18. package/latticeai/api/health.py +1 -1
  19. package/latticeai/api/hooks.py +1 -1
  20. package/latticeai/api/invitations.py +100 -0
  21. package/latticeai/api/knowledge_graph.py +139 -0
  22. package/latticeai/api/local_files.py +1 -1
  23. package/latticeai/api/mcp.py +23 -11
  24. package/latticeai/api/memory.py +1 -1
  25. package/latticeai/api/models.py +1 -1
  26. package/latticeai/api/network.py +81 -0
  27. package/latticeai/api/plugins.py +3 -6
  28. package/latticeai/api/realtime.py +5 -8
  29. package/latticeai/api/search.py +26 -2
  30. package/latticeai/api/security_dashboard.py +2 -3
  31. package/latticeai/api/setup.py +2 -2
  32. package/latticeai/api/static_routes.py +11 -16
  33. package/latticeai/api/tools.py +3 -0
  34. package/latticeai/api/ui_redirects.py +26 -0
  35. package/latticeai/api/workflow_designer.py +85 -6
  36. package/latticeai/api/workspace.py +93 -57
  37. package/latticeai/app_factory.py +1781 -0
  38. package/latticeai/brain/__init__.py +18 -0
  39. package/latticeai/brain/_kg_common.py +1123 -0
  40. package/latticeai/brain/context.py +213 -0
  41. package/latticeai/brain/conversations.py +236 -0
  42. package/latticeai/brain/discovery.py +1455 -0
  43. package/latticeai/brain/documents.py +218 -0
  44. package/latticeai/brain/identity.py +175 -0
  45. package/latticeai/brain/ingest.py +644 -0
  46. package/latticeai/brain/memory.py +102 -0
  47. package/latticeai/brain/network.py +205 -0
  48. package/latticeai/brain/projection.py +561 -0
  49. package/latticeai/brain/provenance.py +401 -0
  50. package/latticeai/brain/retrieval.py +1316 -0
  51. package/latticeai/brain/schema.py +640 -0
  52. package/latticeai/brain/store.py +216 -0
  53. package/latticeai/brain/write_master.py +225 -0
  54. package/latticeai/core/agent.py +31 -7
  55. package/latticeai/core/audit.py +0 -7
  56. package/latticeai/core/config.py +1 -1
  57. package/latticeai/core/context_builder.py +1 -2
  58. package/latticeai/core/enterprise.py +1 -1
  59. package/latticeai/core/graph_curator.py +2 -2
  60. package/latticeai/core/invitations.py +131 -0
  61. package/latticeai/core/marketplace.py +1 -1
  62. package/latticeai/core/mcp_registry.py +791 -0
  63. package/latticeai/core/model_compat.py +1 -1
  64. package/latticeai/core/model_resolution.py +0 -1
  65. package/latticeai/core/multi_agent.py +238 -4
  66. package/latticeai/core/policy.py +54 -0
  67. package/latticeai/core/realtime.py +65 -44
  68. package/latticeai/core/security.py +1 -1
  69. package/latticeai/core/sessions.py +66 -10
  70. package/latticeai/core/users.py +147 -0
  71. package/latticeai/core/workflow_engine.py +114 -2
  72. package/latticeai/core/workspace_os.py +477 -29
  73. package/latticeai/models/__init__.py +7 -0
  74. package/latticeai/models/router.py +779 -0
  75. package/latticeai/server_app.py +29 -1536
  76. package/latticeai/services/agent_runtime.py +243 -4
  77. package/latticeai/services/app_context.py +75 -14
  78. package/latticeai/services/ingestion.py +47 -0
  79. package/latticeai/services/kg_portability.py +33 -3
  80. package/latticeai/services/memory_service.py +39 -11
  81. package/latticeai/services/model_runtime.py +2 -5
  82. package/latticeai/services/platform_runtime.py +100 -23
  83. package/latticeai/services/run_executor.py +328 -0
  84. package/latticeai/services/search_service.py +17 -8
  85. package/latticeai/services/tool_dispatch.py +12 -2
  86. package/latticeai/services/triggers.py +241 -0
  87. package/latticeai/services/upload_service.py +37 -12
  88. package/latticeai/services/workspace_service.py +55 -16
  89. package/llm_router.py +29 -772
  90. package/ltcai_cli.py +1 -2
  91. package/mcp_registry.py +25 -788
  92. package/p_reinforce.py +124 -14
  93. package/package.json +10 -20
  94. package/scripts/bump_version.py +99 -0
  95. package/scripts/generate_diagrams.py +0 -1
  96. package/scripts/lint_v3.mjs +105 -18
  97. package/scripts/validate_release_artifacts.py +0 -1
  98. package/scripts/wheel_smoke.py +142 -0
  99. package/server.py +11 -7
  100. package/setup_wizard.py +1142 -0
  101. package/static/sw.js +81 -52
  102. package/static/v3/asset-manifest.json +33 -25
  103. package/static/v3/css/{lattice.base.e4cdd05d.css → lattice.base.49deefb5.css} +1 -1
  104. package/static/v3/css/lattice.base.css +1 -1
  105. package/static/v3/css/{lattice.components.9b49d614.css → lattice.components.cde18231.css} +1 -1
  106. package/static/v3/css/lattice.components.css +1 -1
  107. package/static/v3/css/{lattice.shell.8fcc9d33.css → lattice.shell.29d36d85.css} +1 -1
  108. package/static/v3/css/lattice.shell.css +1 -1
  109. package/static/v3/css/{lattice.tokens.e7018963.css → lattice.tokens.304cbc40.css} +3 -0
  110. package/static/v3/css/lattice.tokens.css +3 -0
  111. package/static/v3/css/{lattice.views.22f69117.css → lattice.views.0a18b6c5.css} +2 -2
  112. package/static/v3/css/lattice.views.css +2 -2
  113. package/static/v3/index.html +3 -4
  114. package/static/v3/js/{app.c541f955.js → app.c5c80c46.js} +1 -1
  115. package/static/v3/js/core/{api.33d6320e.js → api.ba0fbf14.js} +58 -1
  116. package/static/v3/js/core/api.js +57 -0
  117. package/static/v3/js/core/i18n.880e1fec.js +575 -0
  118. package/static/v3/js/core/i18n.js +575 -0
  119. package/static/v3/js/core/routes.37522821.js +101 -0
  120. package/static/v3/js/core/routes.js +71 -63
  121. package/static/v3/js/core/{shell.8c163e0e.js → shell.e3f6bbfa.js} +68 -39
  122. package/static/v3/js/core/shell.js +66 -37
  123. package/static/v3/js/core/{store.34ebd5e6.js → store.7b2aa044.js} +11 -1
  124. package/static/v3/js/core/store.js +11 -1
  125. package/static/v3/js/views/account.eff40715.js +143 -0
  126. package/static/v3/js/views/account.js +143 -0
  127. package/static/v3/js/views/activity.0d271ef9.js +67 -0
  128. package/static/v3/js/views/activity.js +67 -0
  129. package/static/v3/js/views/{admin-users.03bac88c.js → admin-users.f7ac7b43.js} +4 -6
  130. package/static/v3/js/views/admin-users.js +4 -6
  131. package/static/v3/js/views/{agents.014d0b74.js → agents.17c5288d.js} +35 -12
  132. package/static/v3/js/views/agents.js +35 -12
  133. package/static/v3/js/views/{chat.e6dd7dd0.js → chat.e250e2cc.js} +23 -0
  134. package/static/v3/js/views/chat.js +23 -0
  135. package/static/v3/js/views/graph-canvas.17c15d65.js +509 -0
  136. package/static/v3/js/views/graph-canvas.js +509 -0
  137. package/static/v3/js/views/{hybrid-search.b22b97e0.js → hybrid-search.2fb63ed9.js} +1 -2
  138. package/static/v3/js/views/hybrid-search.js +1 -2
  139. package/static/v3/js/views/{knowledge-graph.a96040a5.js → knowledge-graph.4d09c537.js} +60 -44
  140. package/static/v3/js/views/knowledge-graph.js +60 -44
  141. package/static/v3/js/views/network.52a4f181.js +97 -0
  142. package/static/v3/js/views/network.js +97 -0
  143. package/static/v3/js/views/{planning.9ac3e313.js → planning.4876fd77.js} +26 -5
  144. package/static/v3/js/views/planning.js +26 -5
  145. package/static/v3/js/views/runs.b63b2afa.js +144 -0
  146. package/static/v3/js/views/runs.js +144 -0
  147. package/static/v3/js/views/{settings.8631fa5e.js → settings.b7140634.js} +7 -8
  148. package/static/v3/js/views/settings.js +7 -8
  149. package/static/v3/js/views/snapshots.6f5db095.js +135 -0
  150. package/static/v3/js/views/snapshots.js +135 -0
  151. package/static/v3/js/views/{workflows.26c57290.js → workflows.7752225a.js} +87 -2
  152. package/static/v3/js/views/workflows.js +87 -2
  153. package/static/v3/js/views/workspace-admin.c466029b.js +156 -0
  154. package/static/v3/js/views/workspace-admin.js +156 -0
  155. package/static/vendor/chart.umd.min.js +20 -0
  156. package/static/vendor/fonts/inter-latin-300-normal.woff2 +0 -0
  157. package/static/vendor/fonts/inter-latin-400-normal.woff2 +0 -0
  158. package/static/vendor/fonts/inter-latin-500-normal.woff2 +0 -0
  159. package/static/vendor/fonts/inter-latin-600-normal.woff2 +0 -0
  160. package/static/vendor/fonts/inter-latin-700-normal.woff2 +0 -0
  161. package/static/vendor/fonts/inter-latin-800-normal.woff2 +0 -0
  162. package/static/vendor/fonts/inter.css +44 -0
  163. package/static/vendor/icons/tabler-icons.min.css +4 -0
  164. package/static/vendor/icons/tabler-icons.woff2 +0 -0
  165. package/static/vendor/marked.min.js +69 -0
  166. package/telegram_bot.py +1 -2
  167. package/tools/commands.py +4 -2
  168. package/tools/computer.py +1 -1
  169. package/tools/documents.py +1 -3
  170. package/tools/filesystem.py +0 -4
  171. package/tools/knowledge.py +1 -3
  172. package/tools/network.py +1 -3
  173. package/codex_telegram_bot.py +0 -195
  174. package/docs/assets/v3.4.0/agent-run.png +0 -0
  175. package/docs/assets/v3.4.0/agents.png +0 -0
  176. package/docs/assets/v3.4.0/before/chat-before.png +0 -0
  177. package/docs/assets/v3.4.0/before/files-before.png +0 -0
  178. package/docs/assets/v3.4.0/chat.png +0 -0
  179. package/docs/assets/v3.4.0/connect-folder.png +0 -0
  180. package/docs/assets/v3.4.0/files.png +0 -0
  181. package/docs/assets/v3.4.0/home.png +0 -0
  182. package/docs/assets/v3.4.0/hooks-dispatch.png +0 -0
  183. package/docs/assets/v3.4.0/knowledge-graph.png +0 -0
  184. package/docs/assets/v3.4.0/local-agent.png +0 -0
  185. package/docs/assets/v3.4.0/memory.png +0 -0
  186. package/docs/assets/v3.4.0/settings.png +0 -0
  187. package/docs/assets/v3.4.0/vision-input.png +0 -0
  188. package/docs/assets/v3.4.0/workflows.png +0 -0
  189. package/docs/assets/v3.4.1/e2e_runtime_log.txt +0 -42
  190. package/docs/assets/v3.4.1/hooks-dispatch.png +0 -0
  191. package/docs/assets/v3.4.1/local-agent.png +0 -0
  192. package/docs/images/admin-dashboard.png +0 -0
  193. package/docs/images/architecture.png +0 -0
  194. package/docs/images/enterprise.png +0 -0
  195. package/docs/images/graph.png +0 -0
  196. package/docs/images/hero.gif +0 -0
  197. package/docs/images/knowledge-graph.png +0 -0
  198. package/docs/images/lattice-ai-demo.gif +0 -0
  199. package/docs/images/lattice-ai-hero.png +0 -0
  200. package/docs/images/logo.svg +0 -33
  201. package/docs/images/mobile-responsive.png +0 -0
  202. package/docs/images/model-recommendation.png +0 -0
  203. package/docs/images/onboarding.png +0 -0
  204. package/docs/images/organization.png +0 -0
  205. package/docs/images/pipeline.png +0 -0
  206. package/docs/images/screenshot-admin.png +0 -0
  207. package/docs/images/screenshot-chat.png +0 -0
  208. package/docs/images/screenshot-graph.png +0 -0
  209. package/docs/images/skills.png +0 -0
  210. package/docs/images/workspace-dark.png +0 -0
  211. package/docs/images/workspace-light.png +0 -0
  212. package/docs/images/workspace.png +0 -0
  213. package/requirements.txt +0 -16
  214. package/static/account.html +0 -115
  215. package/static/activity.html +0 -73
  216. package/static/admin.html +0 -488
  217. package/static/agents.html +0 -139
  218. package/static/chat.html +0 -844
  219. package/static/css/reference/account.css +0 -439
  220. package/static/css/reference/admin.css +0 -610
  221. package/static/css/reference/base.css +0 -1661
  222. package/static/css/reference/chat.css +0 -4623
  223. package/static/css/reference/graph.css +0 -1016
  224. package/static/css/responsive.css +0 -861
  225. package/static/graph.html +0 -124
  226. package/static/platform.css +0 -104
  227. package/static/plugins.html +0 -136
  228. package/static/scripts/account.js +0 -238
  229. package/static/scripts/admin.js +0 -1614
  230. package/static/scripts/chat.js +0 -5081
  231. package/static/scripts/graph.js +0 -1804
  232. package/static/scripts/platform.js +0 -64
  233. package/static/scripts/ux.js +0 -167
  234. package/static/scripts/workspace.js +0 -948
  235. package/static/v3/js/core/routes.2ce3815a.js +0 -93
  236. package/static/workflows.html +0 -146
  237. package/static/workspace.css +0 -1121
  238. package/static/workspace.html +0 -357
package/static/chat.html DELETED
@@ -1,844 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">
7
- <title>Lattice AI — All-in-One Multimodal Workspace</title>
8
- <script src="/static/scripts/ux.js"></script>
9
-
10
- <!-- PWA -->
11
- <link rel="manifest" href="/manifest.json">
12
- <meta name="theme-color" content="#f3ecff">
13
- <meta name="mobile-web-app-capable" content="yes">
14
- <meta name="apple-mobile-web-app-capable" content="yes">
15
- <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
16
- <meta name="apple-mobile-web-app-title" content="LatticeAI">
17
- <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
18
- <link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png">
19
-
20
- <link rel="preconnect" href="https://fonts.googleapis.com">
21
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
22
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap">
23
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
24
- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
25
-
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">
34
- </head>
35
-
36
- <body class="lattice-ref-chat">
37
- <!-- 배경 장식 -->
38
- <div class="bg-shapes">
39
- <div class="bg-orb bg-orb-1"></div>
40
- <div class="bg-orb bg-orb-2"></div>
41
- <div class="bg-orb bg-orb-3"></div>
42
- </div>
43
- <div class="bg-grid"></div>
44
-
45
-
46
- <div class="app-layout">
47
- <div class="sidebar-overlay" onclick="closeSidebar();closeGraphNav&&closeGraphNav();closeAdminRail&&closeAdminRail()"></div>
48
- <!-- Sidebar -->
49
- <aside class="sidebar">
50
- <div class="sidebar-header">
51
- <div class="logo-box"><i class="ti ti-brain"></i></div>
52
- <div>
53
- <div class="brand-title">Lattice AI</div>
54
- <div class="brand-subtitle" id="sidebar-workspace-label">개인 워크스페이스</div>
55
- </div>
56
- <button class="sidebar-close" onclick="closeSidebar()" title="닫기"><i class="ti ti-x"></i></button>
57
- </div>
58
- <div class="user-strip">
59
- <div class="user-avatar" id="user-avatar-initial">G</div>
60
- <div style="min-width:0">
61
- <div style="font-size:12.5px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis"><span id="user-nickname-display">Guest</span></div>
62
- <div class="workspace-type-line" id="user-workspace-display">개인 워크스페이스</div>
63
- </div>
64
- </div>
65
- <nav class="reference-side-nav" id="side-nav" aria-label="Lattice AI navigation"></nav>
66
- <div class="sidebar-search">
67
- <div class="sidebar-search-wrap">
68
- <i class="ti ti-search"></i>
69
- <input type="text" id="history-search-input" placeholder="대화 검색..." oninput="onHistorySearch(this.value)">
70
- </div>
71
- </div>
72
- <div class="sidebar-primary-actions">
73
- <button id="new-chat-btn" class="new-chat-btn"><i class="ti ti-plus"></i> New Chat</button>
74
- </div>
75
- <div class="history-container" id="history-container">
76
- <!-- History items -->
77
- </div>
78
- <div class="sidebar-footer">
79
- <button id="admin-btn" class="admin-btn" onclick="openAdminPanel()"><i class="ti ti-shield-lock"></i> <span data-i18n="admin_dashboard">관리자 대시보드</span></button>
80
- </div>
81
- </aside>
82
-
83
- <!-- Main Chat Area -->
84
- <main class="main-chat">
85
- <header class="chat-header">
86
- <div class="header-left">
87
- <button class="sidebar-toggle" onclick="toggleSidebar()" title="메뉴"><i class="ti ti-menu-2"></i></button>
88
- <div class="mode-segmented" id="mode-segmented" role="tablist" aria-label="작업 모드"></div>
89
- </div>
90
- <div class="header-pills">
91
- <button class="theme-toggle" onclick="toggleTheme()" title="테마 전환" aria-label="라이트/다크 테마 전환"><i class="ti ti-moon"></i><i class="ti ti-sun"></i></button>
92
- <div class="lang-picker" id="header-lang-picker">
93
- <button class="logout-btn" id="lang-btn" onclick="toggleLangMenu('header-lang-picker')" title="Language"><i class="ti ti-language"></i> Language</button>
94
- <div class="lang-picker-menu" id="header-lang-picker-menu">
95
- <div class="lang-option" id="header-lang-ko" onclick="setLang('ko')">🇰🇷 한국어</div>
96
- <div class="lang-option" id="header-lang-en" onclick="setLang('en')">🇺🇸 English</div>
97
- </div>
98
- </div>
99
- <button onclick="openAcctModal()" class="logout-btn" title="계정 설정"><i class="ti ti-user"></i></button>
100
- <button onclick="logout()" class="logout-btn" data-i18n="logout">로그아웃</button>
101
- </div>
102
- </header>
103
-
104
- <div class="acct-modal-overlay" id="acct-modal-overlay" onclick="if(event.target===this)closeAcctModal()">
105
- <div class="acct-modal">
106
- <div class="acct-tabs">
107
- <button class="acct-tab active" id="tab-profile" onclick="switchAcctTab('profile')" data-i18n="tab_profile">프로필</button>
108
- <button class="acct-tab" id="tab-password" onclick="switchAcctTab('password')" data-i18n="tab_password">비밀번호</button>
109
- </div>
110
- <div class="acct-body">
111
- <div class="acct-tab-panel active" id="panel-profile">
112
- <div class="pw-field">
113
- <label data-i18n="label_name">이름</label>
114
- <input type="text" id="profile-name" placeholder="이름" data-i18n-ph="ph_name">
115
- </div>
116
- <div class="pw-field">
117
- <label data-i18n="label_nickname">닉네임</label>
118
- <input type="text" id="profile-nickname" placeholder="닉네임" data-i18n-ph="ph_nickname">
119
- </div>
120
- <div class="pw-msg" id="profile-msg"></div>
121
- <div class="pw-actions">
122
- <button class="pw-cancel" onclick="closeAcctModal()" data-i18n="btn_cancel">취소</button>
123
- <button class="pw-submit" id="profile-submit-btn" onclick="submitProfileChange()" data-i18n="btn_save">저장</button>
124
- </div>
125
- </div>
126
- <div class="acct-tab-panel" id="panel-password">
127
- <div class="pw-field">
128
- <label data-i18n="label_cur_pw">현재 비밀번호</label>
129
- <input type="password" id="pw-cur" placeholder="현재 비밀번호" data-i18n-ph="ph_cur_pw">
130
- </div>
131
- <div class="pw-field">
132
- <label data-i18n="label_new_pw">새 비밀번호</label>
133
- <input type="password" id="pw-new" placeholder="새 비밀번호 (4자 이상)" data-i18n-ph="ph_new_pw">
134
- </div>
135
- <div class="pw-field">
136
- <label data-i18n="label_new_pw2">새 비밀번호 확인</label>
137
- <input type="password" id="pw-new2" placeholder="새 비밀번호 재입력" data-i18n-ph="ph_new_pw2">
138
- </div>
139
- <div class="pw-msg" id="pw-msg"></div>
140
- <div class="pw-actions">
141
- <button class="pw-cancel" onclick="closeAcctModal()" data-i18n="btn_cancel">취소</button>
142
- <button class="pw-submit" id="pw-submit-btn" onclick="submitPwChange()" data-i18n="btn_change">변경</button>
143
- </div>
144
- </div>
145
- </div>
146
- </div>
147
- </div>
148
-
149
- <!-- MCP 관리 모달 -->
150
- <div class="mcp-modal-overlay" id="mcp-modal-overlay" onclick="if(event.target===this)closeMcpModal()">
151
- <div class="mcp-modal">
152
- <div class="mcp-modal-header">
153
- <h3><i class="ti ti-plug-connected"></i> MCP 서버 관리</h3>
154
- <button class="mcp-modal-close" onclick="closeMcpModal()"><i class="ti ti-x"></i></button>
155
- </div>
156
- <div class="mcp-tabs" id="mcp-tabs">
157
- <button class="mcp-tab active" onclick="switchMcpTab('registry',this)">🗂 레지스트리</button>
158
- <button class="mcp-tab" onclick="switchMcpTab('claude-code',this)">🤖 Claude Code</button>
159
- <button class="mcp-tab" onclick="switchMcpTab('custom',this)">➕ 직접 추가</button>
160
- </div>
161
- <div class="mcp-modal-body" id="mcp-modal-body">
162
- <div style="color:var(--faint);font-size:13px;text-align:center;padding:24px">로딩 중...</div>
163
- </div>
164
- </div>
165
- </div>
166
-
167
- <section class="ops-strip" aria-label="workspace status">
168
- <div class="ops-card primary interactive" onclick="openModelPanel()">
169
- <div>
170
- <div class="ops-label">모델 상태</div>
171
- <div id="ops-model" class="ops-value">AI 모델</div>
172
- <div id="ops-model-meta" class="ops-meta">로컬 런타임</div>
173
- </div>
174
- <div class="ops-icon"><i class="ti ti-cpu-2"></i></div>
175
- </div>
176
- <div class="ops-card interactive" id="pipeline-ops-card" onclick="openPipelineModal()">
177
- <div>
178
- <div class="ops-label">파이프라인</div>
179
- <div id="ops-pipeline-value" class="ops-value">멀티 LLM 파이프라인</div>
180
- <div id="ops-pipeline-meta" class="ops-meta">Plan → Execute → Review 모델 설정</div>
181
- </div>
182
- <div class="ops-icon"><i class="ti ti-git-branch"></i></div>
183
- </div>
184
- <div class="ops-card interactive" onclick="openVpcPanel()">
185
- <div>
186
- <div class="ops-label">관리자 네트워크</div>
187
- <div id="ops-vpc" class="ops-value" data-i18n="vpc_not_set">설정 안 됨</div>
188
- <div id="ops-vpc-meta" class="ops-meta" data-i18n="vpc_click_to_set">클릭하여 VPC 연결 설정</div>
189
- </div>
190
- <div class="ops-icon"><i class="ti ti-cloud-lock"></i></div>
191
- </div>
192
- <div class="ops-card interactive" onclick="openAdminPanel()">
193
- <div>
194
- <div class="ops-label">관리자 보안</div>
195
- <div class="ops-value" data-i18n="security_monitor">민감정보 감시</div>
196
- <div id="security-admin-meta" class="ops-meta" data-i18n="admin_dashboard_access">관리자 대시보드 접근</div>
197
- </div>
198
- <div class="ops-icon"><i class="ti ti-shield-check"></i></div>
199
- </div>
200
- </section>
201
-
202
- <div class="messages-viewport" id="chat-viewport">
203
- <section class="home-dash" id="home-view">
204
- <!-- 헤더 -->
205
- <div class="home-dash-head">
206
- <h1 id="home-welcome-title">안녕하세요, 사용자님</h1>
207
- <p id="home-welcome-sub">개인 AI 워크스페이스</p>
208
- </div>
209
-
210
- <!-- 상단 상태 카드 -->
211
- <div class="home-dash-cards" id="home-dash-cards">
212
- <!-- AI 상태 -->
213
- <div class="hdc-card" id="home-ai-card">
214
- <div class="hdc-title"><i class="ti ti-cpu-2"></i> AI 상태</div>
215
- <div class="hdc-model-badge" id="home-model-badge">모델 로딩 중...</div>
216
- <div class="hdc-stats">
217
- <div class="hdc-stat-row">
218
- <span class="hdc-stat-label">메모리</span>
219
- <div class="hdc-bar"><div class="hdc-bar-fill" id="home-mem-bar" style="width:0%"></div></div>
220
- <span class="hdc-stat-val" id="home-mem-pct">—</span>
221
- </div>
222
- <div class="hdc-stat-row">
223
- <span class="hdc-stat-label">CPU</span>
224
- <div class="hdc-bar"><div class="hdc-bar-fill hdc-cpu" id="home-cpu-bar" style="width:0%"></div></div>
225
- <span class="hdc-stat-val" id="home-cpu-pct">—</span>
226
- </div>
227
- <div class="hdc-stat-row">
228
- <span class="hdc-stat-label">GPU</span>
229
- <div class="hdc-bar"><div class="hdc-bar-fill hdc-gpu" id="home-gpu-bar" style="width:0%"></div></div>
230
- <span class="hdc-stat-val" id="home-gpu-pct">—</span>
231
- </div>
232
- </div>
233
- <button class="hdc-btn" onclick="openModelPanel()"><i class="ti ti-refresh"></i> 모델 변경</button>
234
- </div>
235
-
236
- <!-- 지식 그래프 -->
237
- <div class="hdc-card" id="home-kg-card">
238
- <div class="hdc-title"><i class="ti ti-chart-dots-3"></i> 지식 그래프</div>
239
- <div class="hdc-counts">
240
- <div class="hdc-count-item"><span id="home-kg-nodes">—</span><label>노드</label></div>
241
- <div class="hdc-count-sep"></div>
242
- <div class="hdc-count-item"><span id="home-kg-edges">—</span><label>연결</label></div>
243
- </div>
244
- <div class="hdc-kg-mini" id="home-kg-mini"></div>
245
- <button class="hdc-btn" onclick="openDataGraph()"><i class="ti ti-arrow-right"></i> 그래프 보기</button>
246
- </div>
247
-
248
- <div class="hdc-card hdc-setup" id="home-setup-card">
249
- <div class="hdc-title"><i class="ti ti-settings-automation"></i> 자동 설정</div>
250
- <div class="hdc-setup-count">
251
- <span id="home-setup-num">—</span>
252
- <label>설치 가능한 도구</label>
253
- </div>
254
- <button class="hdc-btn" onclick="openSetupWizard()"><i class="ti ti-player-play"></i> 설정 시작</button>
255
- </div>
256
- </div>
257
-
258
- <!-- 하단: 최근 채팅 + 최근 파일 -->
259
- <div class="home-dash-recent">
260
- <div class="hdr-panel">
261
- <div class="hdr-head">
262
- <span><i class="ti ti-message-circle"></i> 최근 채팅</span>
263
- <button onclick="startNewChat()">전부 보기 →</button>
264
- </div>
265
- <div class="hdr-list" id="home-recent-chats">
266
- <div class="hdr-empty">대화 기록이 없습니다</div>
267
- </div>
268
- </div>
269
- <div class="hdr-panel">
270
- <div class="hdr-head">
271
- <span><i class="ti ti-file-text"></i> 최근 파일</span>
272
- <button onclick="openLocalBrowser()">파일 열기 →</button>
273
- </div>
274
- <div class="hdr-list" id="home-recent-files">
275
- <div class="hdr-empty">파일이 없습니다</div>
276
- </div>
277
- </div>
278
- </div>
279
- </section>
280
- <section class="empty-state" id="empty-state">
281
- <!-- 채팅 뷰일 때만 표시되는 힌트 -->
282
- <div class="chat-empty-hint">
283
- <i class="ti ti-message-circle"></i>
284
- <h2 id="chat-empty-title">Lattice AI</h2>
285
- <p id="chat-empty-desc">로컬 모델, 파일, 지식 그래프, 멀티모달 작업을 한 대화 흐름에서 연결하는 개인 AI 워크스페이스입니다.</p>
286
- <div class="chat-capability-row" id="chat-capability-row">
287
- <span>파일 생성</span>
288
- <span>지식 정리</span>
289
- <span>내 컴퓨터에서 실행</span>
290
- </div>
291
- </div>
292
- </section>
293
- </div>
294
-
295
- <div class="input-area">
296
- <div class="input-box">
297
- <div id="preview-area" class="preview-bar" style="display: none;">
298
- <div style="position: relative;">
299
- <img id="img-preview" class="preview-thumb" src="">
300
- <div class="remove-preview" onclick="removeImage()">×</div>
301
- </div>
302
- </div>
303
- <div id="attach-preview-row" class="attach-preview-row"></div>
304
- <div class="input-row">
305
- <label class="action-btn" title="이미지 첨부">
306
- <i class="ti ti-camera" style="font-size: 20px;"></i>
307
- <input type="file" id="image-input" accept="image/*" hidden onchange="previewImage(this)">
308
- </label>
309
- <label class="action-btn" title="문서 첨부 (PDF/DOCX/XLSX/PPTX/TXT)">
310
- <i class="ti ti-paperclip" style="font-size: 20px;"></i>
311
- <input type="file" id="doc-input" accept=".pdf,.docx,.xlsx,.pptx,.txt,.md,.csv" hidden onchange="attachDocument(this)">
312
- </label>
313
- <textarea id="user-input" placeholder="Lattice AI에게 작업을 지시하세요..." rows="1" data-i18n-ph="ph_input"></textarea>
314
- <button class="send-btn" id="send-btn"><i class="ti ti-send"></i></button>
315
- </div>
316
- <div class="file-toolbar" style="display:none"></div>
317
- </div>
318
- </div>
319
- </main>
320
- </div>
321
-
322
- <div class="onboarding-overlay" id="onboarding-overlay" aria-live="polite">
323
- <section class="onboarding-card" role="dialog" aria-modal="true" aria-labelledby="onboarding-title">
324
- <div class="onboarding-top">
325
- <div class="onboarding-kicker">Lattice AI Onboarding</div>
326
- <div class="onboarding-steps" id="onboarding-steps"></div>
327
- </div>
328
- <div class="onboarding-body" id="onboarding-body"></div>
329
- <div class="onboarding-actions" id="onboarding-actions"></div>
330
- </section>
331
- </div>
332
-
333
- <div class="workspace-modal-overlay" id="workspace-modal-overlay">
334
- <section class="workspace-modal" role="dialog" aria-modal="true" aria-labelledby="workspace-title">
335
- <div class="modal-kicker">Lattice AI</div>
336
- <h2 id="workspace-title" data-i18n="workspace_title">워크스페이스 선택</h2>
337
- <p data-i18n="workspace_sub">사용 목적에 맞는 시작 공간을 고르면 홈 화면과 기본 도구가 그 흐름에 맞춰 정리됩니다.</p>
338
- <div class="workspace-options">
339
- <button class="workspace-card" onclick="selectWorkspace('personal')">
340
- <div class="workspace-icon"><i class="ti ti-user"></i></div>
341
- <h3 data-i18n="workspace_personal">개인 워크스페이스</h3>
342
- <span data-i18n="workspace_personal_sub">개인 프로젝트, 로컬 파일, 지식베이스 중심</span>
343
- </button>
344
- <button class="workspace-card" onclick="selectWorkspace('company')">
345
- <div class="workspace-icon"><i class="ti ti-building-skyscraper"></i></div>
346
- <h3 data-i18n="workspace_company">회사 워크스페이스</h3>
347
- <span data-i18n="workspace_company_sub">SSO, 보안 정책, 팀 운영 대시보드 중심</span>
348
- </button>
349
- </div>
350
- <div class="modal-footnote" data-i18n="workspace_note">나중에 상단 모드 버튼에서 다시 바꿀 수 있습니다.</div>
351
- </section>
352
- </div>
353
-
354
- <div class="mode-modal-overlay" id="mode-modal-overlay" onclick="if(event.target===this)closeModeSelector()">
355
- <section class="mode-modal" role="dialog" aria-modal="true" aria-labelledby="mode-title">
356
- <button class="mode-close" onclick="closeModeSelector()" title="닫기"><i class="ti ti-x"></i></button>
357
- <div class="modal-kicker">Mode Select</div>
358
- <h2 id="mode-title" data-i18n="mode_title">모드 선택</h2>
359
- <p data-i18n="mode_sub">작업 성격에 맞춰 Lattice AI의 화면 밀도와 기본 프롬프트를 전환합니다.</p>
360
- <div class="mode-options">
361
- <button class="mode-card selected" id="mode-card-default" onclick="selectMode('default')">
362
- <div class="mode-icon"><i class="ti ti-layout-dashboard"></i></div>
363
- <h3 data-i18n="mode_default">기본 모드</h3>
364
- <span data-i18n="mode_default_sub">대화, 파일 생성, 지식 정리를 한 화면에서</span>
365
- </button>
366
- <button class="mode-card" id="mode-card-advanced" onclick="selectMode('advanced')">
367
- <div class="mode-icon"><i class="ti ti-terminal-2"></i></div>
368
- <h3 data-i18n="mode_advanced">고급 모드</h3>
369
- <span data-i18n="mode_advanced_sub">같은 기능을 더 자세한 설명으로 표시</span>
370
- </button>
371
- <button class="mode-card" id="mode-card-admin" onclick="selectMode('admin')">
372
- <div class="mode-icon"><i class="ti ti-shield-lock"></i></div>
373
- <h3 data-i18n="mode_admin">관리자 모드</h3>
374
- <span data-i18n="mode_admin_sub">사용자, 정책, 감사 로그 관리</span>
375
- </button>
376
- </div>
377
- </section>
378
- </div>
379
-
380
- <div id="model-overlay" class="model-overlay">
381
- <section class="model-panel">
382
- <div class="model-panel-header">
383
- <div>
384
- <h2 data-i18n="model_switcher">모델 스위처</h2>
385
- <p style="color: var(--muted); font-size: 12px; margin-top: 4px;" data-i18n="model_switcher_sub">제작 국가, 제작 회사, 실행 방식, 인터넷 사용 여부를 확인하고 모델을 선택합니다.</p>
386
- </div>
387
- <button class="admin-close" onclick="closeModelPanel()"><i class="ti ti-x"></i></button>
388
- </div>
389
- <div id="model-list" class="model-list"></div>
390
- </section>
391
- </div>
392
-
393
- <!-- ── 권한 요청 다이얼로그 ── -->
394
- <div id="perm-overlay" class="perm-overlay" style="display:none">
395
- <div class="perm-dialog">
396
- <div class="perm-icon"><i class="ti ti-shield-lock"></i></div>
397
- <div class="perm-title" id="perm-title" data-i18n="perm_title">파일 접근 요청</div>
398
- <div class="perm-path" id="perm-path"></div>
399
- <div class="perm-desc" id="perm-desc"></div>
400
- <div class="perm-actions">
401
- <button class="perm-deny-btn" onclick="resolvePermission(false)" data-i18n="btn_deny">거부</button>
402
- <button class="perm-allow-btn" onclick="resolvePermission(true)" data-i18n="btn_allow">허용</button>
403
- </div>
404
- </div>
405
- </div>
406
-
407
- <!-- ── 멀티 LLM 파이프라인 모달 ── -->
408
- <div id="pipeline-overlay" class="admin-overlay" style="display:none" onclick="if(event.target===this)closePipelineModal()">
409
- <section class="admin-panel" style="max-width:520px">
410
- <div class="model-panel-header">
411
- <div>
412
- <h2><i class="ti ti-git-branch" style="color:var(--accent)"></i> 멀티 LLM 파이프라인</h2>
413
- <p style="color:var(--muted);font-size:12px;margin-top:4px">각 단계에 사용할 LLM을 지정합니다. 동일 모델을 여러 단계에 써도 됩니다.</p>
414
- </div>
415
- <button class="admin-close" onclick="closePipelineModal()"><i class="ti ti-x"></i></button>
416
- </div>
417
-
418
- <div style="display:flex;flex-direction:column;gap:16px;padding:0 4px 4px">
419
- <!-- Planning -->
420
- <div class="pipeline-phase-row">
421
- <div class="pipeline-phase-label">
422
- <span class="pipeline-phase-badge" style="background:rgba(99,102,241,0.15);color:var(--accent)">📋 Planning</span>
423
- <span style="color:var(--muted);font-size:11px">계획 수립 · 유저와 함께 검토</span>
424
- </div>
425
- <select id="pipeline-planning-select" class="pipeline-select">
426
- <option value="">현재 로드된 모델 (기본)</option>
427
- </select>
428
- </div>
429
-
430
- <!-- Executing -->
431
- <div class="pipeline-phase-row">
432
- <div class="pipeline-phase-label">
433
- <span class="pipeline-phase-badge" style="background:rgba(34,197,94,0.12);color:var(--success)">⚙️ Executing</span>
434
- <span style="color:var(--muted);font-size:11px">코드 작성 · 파일 생성 · 툴 호출</span>
435
- </div>
436
- <select id="pipeline-executing-select" class="pipeline-select">
437
- <option value="">현재 로드된 모델 (기본)</option>
438
- </select>
439
- </div>
440
-
441
- <!-- Reviewing -->
442
- <div class="pipeline-phase-row">
443
- <div class="pipeline-phase-label">
444
- <span class="pipeline-phase-badge" style="background:rgba(251,146,60,0.12);color:var(--warning)">🔍 Reviewing</span>
445
- <span style="color:var(--muted);font-size:11px">결과 검증 · 최종 답변 생성</span>
446
- </div>
447
- <select id="pipeline-reviewing-select" class="pipeline-select">
448
- <option value="">현재 로드된 모델 (기본)</option>
449
- </select>
450
- </div>
451
-
452
- <div style="background:rgba(99,102,241,0.07);border:1px solid rgba(99,102,241,0.15);border-radius:10px;padding:12px;font-size:12px;color:var(--muted)">
453
- <i class="ti ti-info-circle" style="color:var(--accent)"></i>
454
- 모달을 닫고 채팅창에 작업을 입력하면 <b style="color:var(--text)">Pipeline 모드</b>로 실행됩니다.<br>
455
- 계획이 완성되면 UI에서 검토 후 <b style="color:var(--accent)">✅ Done</b>을 눌러야 실행이 시작됩니다.
456
- </div>
457
-
458
- <div style="display:flex;gap:8px;justify-content:flex-end">
459
- <button onclick="resetPipeline()" style="background:none;border:1px solid var(--border);color:var(--muted);padding:8px 16px;border-radius:8px;cursor:pointer;font-size:13px">초기화</button>
460
- <button onclick="savePipelineAndClose()" style="background:var(--accent);border:none;color:#fff;padding:8px 20px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:600"><i class="ti ti-check"></i> 저장</button>
461
- </div>
462
- </div>
463
- </section>
464
- </div>
465
-
466
- <!-- ── 파일 생성 패널 ── -->
467
- <div id="file-create-overlay" class="admin-overlay" style="display:none">
468
- <section class="admin-panel" style="max-width:480px">
469
- <div class="admin-header">
470
- <div>
471
- <h2 id="file-create-title"><i class="ti ti-file-plus"></i> 파일 만들기</h2>
472
- <p style="color:var(--muted);font-size:12px;margin-top:4px" id="file-create-desc">제목과 내용을 입력하세요.</p>
473
- </div>
474
- <button class="admin-close" onclick="closeFileCreate()"><i class="ti ti-x"></i></button>
475
- </div>
476
- <div class="admin-body">
477
- <div class="admin-form-grid" id="file-create-form"></div>
478
- <div class="vpc-save-row">
479
- <span id="file-create-status" class="vpc-status-copy"></span>
480
- <button class="admin-action" onclick="submitFileCreate()"><i class="ti ti-sparkles"></i> 생성</button>
481
- </div>
482
- </div>
483
- </section>
484
- </div>
485
-
486
- <!-- ── 파일 에디터 ── -->
487
- <div id="file-editor-overlay" class="admin-overlay" style="display:none">
488
- <section class="admin-panel" style="max-width:720px;height:min(85dvh, calc(100dvh - 24px));display:flex;flex-direction:column">
489
- <div class="admin-header" style="flex-shrink:0">
490
- <div style="min-width:0;flex:1">
491
- <h2><i class="ti ti-file-pencil" style="color:var(--accent)"></i> 파일 편집</h2>
492
- <div id="editor-filepath" style="color:var(--faint);font-size:11px;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></div>
493
- </div>
494
- <button class="admin-close" onclick="closeFileEditor()"><i class="ti ti-x"></i></button>
495
- </div>
496
- <div style="flex:1;display:flex;flex-direction:column;padding:0 20px 16px;min-height:0">
497
- <textarea id="file-editor-content"
498
- style="flex:1;width:100%;background:rgba(15,18,15,0.8);border:1px solid var(--border);border-radius:8px;
499
- color:var(--text);font-family:monospace;font-size:13px;line-height:1.6;
500
- padding:14px;resize:none;outline:none;margin-top:12px"
501
- spellcheck="false"></textarea>
502
- <div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">
503
- <button class="admin-action" onclick="saveLocalFile()" style="flex:1">
504
- <i class="ti ti-device-floppy"></i> 저장
505
- </button>
506
- <button class="admin-action" onclick="sendFileToChat()" style="flex:1;background:rgba(111,66,232,0.12);border-color:rgba(111,66,232,0.28)">
507
- <i class="ti ti-send"></i> AI에게 보내기
508
- </button>
509
- <button class="status-btn" onclick="closeFileEditor();showModalLayer('local-browser-overlay')" style="flex:1">
510
- <i class="ti ti-arrow-left"></i> 탐색기로
511
- </button>
512
- </div>
513
- <div id="editor-status" style="font-size:12px;color:var(--accent);margin-top:8px;min-height:18px;text-align:center"></div>
514
- </div>
515
- </section>
516
- </div>
517
-
518
- <!-- ── 로컬 파일 브라우저 ── -->
519
- <div id="local-browser-overlay" class="admin-overlay" style="display:none">
520
- <section class="admin-panel" style="max-width:560px">
521
- <div class="admin-header">
522
- <div style="flex:1;min-width:0">
523
- <h2><i class="ti ti-folder-open" style="color:var(--accent)"></i> 로컬 파일</h2>
524
- <div id="local-breadcrumb" style="color:var(--faint);font-size:11px;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">~</div>
525
- </div>
526
- <button class="admin-close" onclick="closeLocalBrowser()"><i class="ti ti-x"></i></button>
527
- </div>
528
- <div class="admin-body" style="padding-top:10px">
529
- <!-- 즐겨찾기 -->
530
- <div id="local-favorites" style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px">
531
- <button class="status-btn" style="font-size:12px;padding:5px 10px" onclick="localNav('~')"><i class="ti ti-home"></i> 홈</button>
532
- <button class="status-btn" style="font-size:12px;padding:5px 10px" onclick="localNav('~/Downloads')"><i class="ti ti-download"></i> 다운로드</button>
533
- <button class="status-btn" style="font-size:12px;padding:5px 10px" onclick="localNav('~/Desktop')"><i class="ti ti-device-desktop"></i> 데스크탑</button>
534
- <button class="status-btn" style="font-size:12px;padding:5px 10px" onclick="localNav('~/Documents')"><i class="ti ti-files"></i> 문서</button>
535
- <button class="status-btn" style="font-size:12px;padding:5px 10px" onclick="localNavUp()"><i class="ti ti-arrow-up"></i> 위로</button>
536
- </div>
537
- <div id="local-browser-result" style="min-height:80px;max-height:420px;overflow-y:auto"></div>
538
- </div>
539
- </section>
540
- </div>
541
-
542
- <div id="admin-overlay" class="admin-overlay">
543
- <section class="admin-panel">
544
- <div class="admin-header">
545
- <div>
546
- <h2>관리자 대시보드</h2>
547
- <p style="color: var(--muted); font-size: 12px; margin-top: 4px;">대화 로그와 사용자 권한을 관리합니다.</p>
548
- </div>
549
- <button class="admin-close" onclick="closeAdminPanel()"><i class="ti ti-x"></i></button>
550
- </div>
551
- <div class="admin-body">
552
- <div class="admin-stats" id="admin-stats"></div>
553
- <h3 class="admin-section-title">Private VPC</h3>
554
- <div class="admin-form-grid">
555
- <div class="admin-field">
556
- <label for="vpc-provider">Provider</label>
557
- <input id="vpc-provider" class="admin-input" placeholder="AWS">
558
- </div>
559
- <div class="admin-field">
560
- <label for="vpc-region">Region</label>
561
- <input id="vpc-region" class="admin-input" placeholder="ap-northeast-2">
562
- </div>
563
- <div class="admin-field">
564
- <label for="vpc-cidr">CIDR Block</label>
565
- <input id="vpc-cidr" class="admin-input" placeholder="10.42.0.0/16">
566
- </div>
567
- <div class="admin-field">
568
- <label for="vpc-endpoint">Private Endpoint</label>
569
- <input id="vpc-endpoint" class="admin-input" placeholder="ltcai-private.local">
570
- </div>
571
- <div class="admin-field">
572
- <label for="vpc-vpn">VPN Status</label>
573
- <input id="vpc-vpn" class="admin-input" placeholder="standby">
574
- </div>
575
- <div class="admin-field">
576
- <label for="vpc-peering">Peering Status</label>
577
- <input id="vpc-peering" class="admin-input" placeholder="not_configured">
578
- </div>
579
- <div class="admin-field full">
580
- <label for="vpc-subnets">Private Subnets</label>
581
- <input id="vpc-subnets" class="admin-input" placeholder="10.42.10.0/24, 10.42.20.0/24">
582
- </div>
583
- <div class="admin-field full">
584
- <label for="vpc-notes">Notes</label>
585
- <textarea id="vpc-notes" class="admin-textarea" placeholder="운영 메모"></textarea>
586
- </div>
587
- </div>
588
- <div class="vpc-save-row">
589
- <span id="vpc-save-status" class="vpc-status-copy">VPC 프로필은 관리자만 수정할 수 있습니다.</span>
590
- <button class="admin-action" onclick="saveVpcConfig()">저장</button>
591
- </div>
592
- <h3 class="admin-section-title">민감도 분석</h3>
593
- <div id="sensitivity-summary" class="field-cloud"></div>
594
- <div class="sensitivity-grid">
595
- <div class="sensitivity-panel">
596
- <h4><i class="ti ti-alert-triangle"></i> 위험 필드</h4>
597
- <div id="risk-fields" class="sensitivity-list"></div>
598
- </div>
599
- <div class="sensitivity-panel">
600
- <h4><i class="ti ti-shield-check"></i> 준수 필드</h4>
601
- <div id="compliance-fields" class="sensitivity-list"></div>
602
- </div>
603
- </div>
604
- <h3 class="admin-section-title">사용자 관리</h3>
605
- <div id="admin-users"></div>
606
- </div>
607
- </section>
608
- </div>
609
-
610
- <!-- ── VPC Connection Panel ────────────────────────────── -->
611
- <div id="vpc-overlay" class="admin-overlay" style="display:none">
612
- <section class="admin-panel">
613
- <div class="admin-header">
614
- <div>
615
- <h2><i class="ti ti-cloud-lock" style="color:var(--accent)"></i> Private VPC 연결</h2>
616
- <p style="color:var(--muted);font-size:12px;margin-top:4px;">클라우드 VPC 또는 사설망에 연결합니다.</p>
617
- </div>
618
- <button class="admin-close" onclick="closeVpcPanel()"><i class="ti ti-x"></i></button>
619
- </div>
620
- <div class="admin-body">
621
- <div id="vpc-connection-status-bar" class="vpc-connection-status">
622
- <div class="vpc-status-dot" id="vpc-dot"></div>
623
- <span id="vpc-status-text">VPC 상태 확인 중...</span>
624
- </div>
625
- <div class="vpc-provider-tabs">
626
- <button class="vpc-tab-btn active" onclick="selectVpcProvider('AWS',this)">AWS</button>
627
- <button class="vpc-tab-btn" onclick="selectVpcProvider('GCP',this)">GCP</button>
628
- <button class="vpc-tab-btn" onclick="selectVpcProvider('Azure',this)">Azure</button>
629
- <button class="vpc-tab-btn" onclick="selectVpcProvider('Custom',this)">Custom</button>
630
- </div>
631
- <div class="admin-form-grid">
632
- <div class="admin-field">
633
- <label for="vp-provider">Provider</label>
634
- <input id="vp-provider" class="admin-input" placeholder="AWS" readonly>
635
- </div>
636
- <div class="admin-field">
637
- <label for="vp-region">Region</label>
638
- <input id="vp-region" class="admin-input" placeholder="ap-northeast-2">
639
- </div>
640
- <div class="admin-field">
641
- <label for="vp-cidr">CIDR Block</label>
642
- <input id="vp-cidr" class="admin-input" placeholder="10.42.0.0/16">
643
- </div>
644
- <div class="admin-field">
645
- <label for="vp-endpoint">Private Endpoint</label>
646
- <input id="vp-endpoint" class="admin-input" placeholder="ltcai-private.local">
647
- </div>
648
- <div class="admin-field">
649
- <label for="vp-vpn">VPN Status</label>
650
- <input id="vp-vpn" class="admin-input" placeholder="standby">
651
- </div>
652
- <div class="admin-field">
653
- <label for="vp-peering">Peering Status</label>
654
- <input id="vp-peering" class="admin-input" placeholder="not_configured">
655
- </div>
656
- <div class="admin-field full">
657
- <label for="vp-subnets">Private Subnets</label>
658
- <input id="vp-subnets" class="admin-input" placeholder="10.42.10.0/24, 10.42.20.0/24">
659
- </div>
660
- <div class="admin-field full">
661
- <label for="vp-notes">메모</label>
662
- <textarea id="vp-notes" class="admin-textarea" placeholder="운영 메모 (선택)"></textarea>
663
- </div>
664
- </div>
665
- <div class="vpc-save-row">
666
- <span id="vp-save-status" class="vpc-status-copy"></span>
667
- <button class="admin-action" onclick="saveVpcFromPanel()"><i class="ti ti-device-floppy"></i> 저장</button>
668
- </div>
669
- </div>
670
- </section>
671
- </div>
672
-
673
- <!-- ── Status Summary Panel ────────────────────────────── -->
674
- <div id="status-overlay" class="admin-overlay" style="display:none">
675
- <section class="admin-panel" style="max-width:480px">
676
- <div class="admin-header">
677
- <div>
678
- <h2><i class="ti ti-info-circle" style="color:var(--accent)"></i> 내 상태</h2>
679
- <p style="color:var(--muted);font-size:12px;margin-top:4px;">워크스페이스와 계정 상태를 확인합니다.</p>
680
- </div>
681
- <button class="admin-close" onclick="closeStatusPanel()"><i class="ti ti-x"></i></button>
682
- </div>
683
- <div class="admin-body" id="status-panel-body">
684
- <div class="sensitivity-preview">상태를 불러오는 중...</div>
685
- </div>
686
- </section>
687
- </div>
688
-
689
- <div id="advanced-settings-overlay" class="advanced-settings-overlay" onclick="if(event.target===this)closeAdvancedSettingsPanel()">
690
- <section class="advanced-settings-panel">
691
- <header>
692
- <div>
693
- <h2>고급 설정</h2>
694
- <p style="color:var(--muted);font-size:12px;margin-top:4px;">개발자와 파워유저용 설정입니다.</p>
695
- </div>
696
- <button class="admin-close" onclick="closeAdvancedSettingsPanel()"><i class="ti ti-x"></i></button>
697
- </header>
698
- <div class="advanced-settings-body">
699
- <button class="advanced-settings-action" onclick="closeAdvancedSettingsPanel();openSetupWizard()">
700
- <i class="ti ti-device-analytics"></i>
701
- <span>환경 재분석</span>
702
- </button>
703
- <button class="advanced-settings-action" onclick="closeAdvancedSettingsPanel();openMcpModal()">
704
- <i class="ti ti-plug-connected"></i>
705
- <span>MCP 관리</span>
706
- </button>
707
- </div>
708
- </section>
709
- </div>
710
-
711
- <div id="cu-overlay" class="admin-overlay" style="display:none">
712
- <!-- 내 컴퓨터 Panel -->
713
- <section class="admin-panel" id="cu-panel" style="max-width:760px">
714
- <div class="admin-header">
715
- <div>
716
- <h2><i class="ti ti-device-desktop-code" style="color:var(--accent)"></i> 내 컴퓨터</h2>
717
- <p style="color:var(--muted);font-size:12px;margin-top:4px;">Lattice AI가 사용자의 허용을 받아 이 컴퓨터의 파일, 화면, 앱 작업을 도와줍니다.</p>
718
- </div>
719
- <button class="admin-close" onclick="closeCuPanel()"><i class="ti ti-x"></i></button>
720
- </div>
721
- <div class="admin-body" style="padding:0;display:flex;flex-direction:column;gap:0">
722
- <!-- Status bar -->
723
- <div id="cu-status-bar" style="padding:10px 18px;background:var(--surface-2);border-bottom:1px solid var(--border);font-size:12px;color:var(--muted);display:flex;align-items:center;gap:8px">
724
- <span id="cu-status-dot" style="width:8px;height:8px;border-radius:50%;background:var(--faint);display:inline-block"></span>
725
- <span id="cu-status-text">상태 확인 중...</span>
726
- <button onclick="cuRefreshStatus()" style="margin-left:auto;background:none;border:1px solid var(--border);color:var(--muted);padding:3px 10px;border-radius:6px;font-size:11px;cursor:pointer">새로고침</button>
727
- </div>
728
- <!-- Main layout: screenshot + controls -->
729
- <div style="display:flex;gap:0;flex:1;min-height:0">
730
- <!-- Screenshot viewer -->
731
- <div style="flex:1;padding:14px;border-right:1px solid var(--border);display:flex;flex-direction:column;gap:10px">
732
- <div style="display:flex;align-items:center;justify-content:space-between">
733
- <span style="font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em">화면 미리보기</span>
734
- <button onclick="cuTakeScreenshot()" style="background:var(--accent-soft);border:1px solid rgba(111,66,232,0.25);color:var(--accent);padding:4px 12px;border-radius:7px;font-size:12px;cursor:pointer;display:flex;align-items:center;gap:5px"><i class="ti ti-camera"></i> 캡처</button>
735
- </div>
736
- <div id="cu-screenshot-container" style="flex:1;background:var(--surface-3);border:1px solid var(--border);border-radius:10px;overflow:hidden;min-height:260px;display:flex;align-items:center;justify-content:center;position:relative">
737
- <div id="cu-screenshot-placeholder" style="color:var(--faint);font-size:13px;text-align:center"><i class="ti ti-photo-scan" style="font-size:32px;display:block;margin-bottom:8px;opacity:.4"></i>캡처 버튼을 눌러 화면을 확인하세요</div>
738
- <img id="cu-screenshot-img" src="" alt="screenshot" style="display:none;width:100%;height:100%;object-fit:contain">
739
- <div id="cu-screenshot-spinner" style="display:none;position:absolute;inset:0;background:rgba(8,9,12,.7);display:none;align-items:center;justify-content:center;font-size:13px;color:var(--accent)"><i class="ti ti-loader-2" style="animation:spin 1s linear infinite;font-size:24px"></i></div>
740
- </div>
741
- <div id="cu-screenshot-meta" style="font-size:11px;color:var(--faint);text-align:center"></div>
742
- </div>
743
- <!-- Controls panel -->
744
- <div class="cu-controls-panel" style="padding:14px;display:flex;flex-direction:column;gap:12px;overflow-y:auto">
745
- <!-- Agent task input -->
746
- <div>
747
- <div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px">AI 자동 작업</div>
748
- <textarea id="cu-task-input" placeholder="예: Safari 열고 apple.com 접속해줘&#10;예: 현재 화면에서 버튼 찾아서 클릭해줘" 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
- <div style="display:flex;gap:6px;margin-top:6px">
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
- <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
- </div>
753
- </div>
754
- <!-- Manual controls -->
755
- <div class="cu-dev-controls">
756
- <div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px">수동 제어</div>
757
- <div style="display:flex;flex-direction:column;gap:6px">
758
- <div style="display:flex;gap:6px">
759
- <input id="cu-click-x" type="number" placeholder="X" style="width:60px;background:var(--surface-3);border:1px solid var(--border);border-radius:6px;padding:5px 7px;color:var(--text);font-size:12px">
760
- <input id="cu-click-y" type="number" placeholder="Y" style="width:60px;background:var(--surface-3);border:1px solid var(--border);border-radius:6px;padding:5px 7px;color:var(--text);font-size:12px">
761
- <button onclick="cuManualClick()" style="flex:1;background:var(--surface-3);border:1px solid var(--border);color:var(--text);padding:5px;border-radius:6px;font-size:12px;cursor:pointer">클릭</button>
762
- </div>
763
- <div style="display:flex;gap:6px">
764
- <input id="cu-type-text" type="text" placeholder="입력할 텍스트..." style="flex:1;background:var(--surface-3);border:1px solid var(--border);border-radius:6px;padding:5px 8px;color:var(--text);font-size:12px">
765
- <button onclick="cuManualType()" style="background:var(--surface-3);border:1px solid var(--border);color:var(--text);padding:5px 10px;border-radius:6px;font-size:12px;cursor:pointer">입력</button>
766
- </div>
767
- <div style="display:flex;gap:6px">
768
- <input id="cu-key-input" type="text" placeholder="키 (예: return, command+c)" style="flex:1;background:var(--surface-3);border:1px solid var(--border);border-radius:6px;padding:5px 8px;color:var(--text);font-size:12px">
769
- <button onclick="cuManualKey()" style="background:var(--surface-3);border:1px solid var(--border);color:var(--text);padding:5px 10px;border-radius:6px;font-size:12px;cursor:pointer">키</button>
770
- </div>
771
- </div>
772
- </div>
773
- <!-- Action log -->
774
- <div class="cu-dev-controls" style="flex:1;display:flex;flex-direction:column">
775
- <div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between">
776
- <span>실행 로그</span>
777
- <button onclick="document.getElementById('cu-log').innerHTML=''" style="background:none;border:none;color:var(--faint);font-size:11px;cursor:pointer">지우기</button>
778
- </div>
779
- <div id="cu-log" style="flex:1;background:var(--surface-3);border:1px solid var(--border);border-radius:8px;padding:8px;font-size:11px;font-family:monospace;color:var(--muted);overflow-y:auto;max-height:200px;min-height:80px"></div>
780
- </div>
781
- <!-- Permission note -->
782
- <div style="background:rgba(240,168,50,.07);border:1px solid rgba(240,168,50,.2);border-radius:8px;padding:9px 11px;font-size:11px;color:var(--warning)">
783
- <i class="ti ti-alert-triangle"></i> macOS 손쉬운 사용 권한 필요<br>
784
- <span style="opacity:.7">시스템 설정 → 개인 정보 보호 → 손쉬운 사용</span>
785
- </div>
786
- </div>
787
- </div>
788
- </div>
789
- </section>
790
- </div>
791
-
792
-
793
- <!-- ══════════════════════════════════════════════════════════════════
794
- Setup Wizard Overlay
795
- ══════════════════════════════════════════════════════════════════ -->
796
- <div id="setup-overlay">
797
- <div class="wizard-card">
798
-
799
- <!-- Header -->
800
- <div class="wizard-header">
801
- <div>
802
- <div class="wizard-title">환경 재분석</div>
803
- <div class="wizard-subtitle" id="wiz-subtitle">PC 환경을 분석해 최적 구성을 자동으로 추천합니다</div>
804
- </div>
805
- <div style="display:flex;align-items:center;gap:18px;">
806
- <div class="wizard-steps">
807
- <div class="wstep" id="wstep-1">
808
- <div class="wstep-dot">1</div>
809
- <span>환경 분석</span>
810
- </div>
811
- <div class="wstep-sep" id="wsep-1"></div>
812
- <div class="wstep" id="wstep-2">
813
- <div class="wstep-dot">2</div>
814
- <span>항목 선택</span>
815
- </div>
816
- <div class="wstep-sep" id="wsep-2"></div>
817
- <div class="wstep" id="wstep-3">
818
- <div class="wstep-dot">3</div>
819
- <span>설치 · 연결</span>
820
- </div>
821
- </div>
822
- <button class="wizard-close" onclick="closeSetupWizard()">✕</button>
823
- </div>
824
- </div>
825
-
826
- <!-- Body -->
827
- <div class="wizard-body" id="wizard-body">
828
- <!-- injected by JS -->
829
- </div>
830
-
831
- <!-- Footer -->
832
- <div class="wizard-footer">
833
- <div class="wizard-footer-info" id="wiz-footer-info"></div>
834
- <div class="wizard-btn-row" id="wiz-btn-row"></div>
835
- </div>
836
-
837
- </div>
838
- </div>
839
-
840
-
841
- <script src="/static/scripts/chat.js"></script>
842
- </body>
843
-
844
- </html>