diff --git a/CLAUDE.md b/CLAUDE.md index 3ddc8e9..5d19708 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,6 +37,16 @@ Default login: admin / admin. Guest demo: demo / demo (read-only). **Deploy gotcha**: Vite deletes and recreates `admin/dist/` (new inode), breaking Docker bind mounts. Always `docker compose restart` after `npm run build`. +### Mobile App + +```bash +cd mobile && npm install # First-time setup +cd mobile && npm run build # Production build (vue-tsc type-check + vite build) +cd mobile && npm run dev # Dev server +cd mobile && npx cap sync android # Sync web assets to Android project +cd mobile && npx cap open android # Open in Android Studio → Build APK +``` + ### User Management ```bash @@ -115,7 +125,7 @@ Always run lint locally before pushing. Protected branches require PR workflow ``` ┌──────────────────────────────────────────────────────────────┐ │ Orchestrator (port 8002) │ -│ orchestrator.py + app/routers/ (21 routers, ~371 endpoints) │ +│ orchestrator.py + modules/*/router*.py (~28 routers) │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ Vue 3 Admin Panel (24 views, PWA) │ │ │ │ admin/dist/ │ │ @@ -270,6 +280,8 @@ New routers import domain services directly (`from modules.monitoring.service im **Build**: `cd mobile && npm run build && npx cap sync android`. APK via Android Studio: `npx cap open android` → Build → Build APK. +**No lint/format/test** — mobile app has only `dev`, `build`, `preview` scripts. Type checking happens during `npm run build` via `vue-tsc -b`. + ## Code Patterns **Adding a new API endpoint:** diff --git a/mobile/src/components/MessageBubble.vue b/mobile/src/components/MessageBubble.vue index 8f9685d..0ee581f 100644 --- a/mobile/src/components/MessageBubble.vue +++ b/mobile/src/components/MessageBubble.vue @@ -90,11 +90,11 @@ function cancelEdit() { + >Отмена + >Сохранить @@ -125,7 +125,7 @@ function cancelEdit() { +
@@ -195,11 +195,11 @@ onMounted(loadSessions); {{ formatDate(session.updated) }}

{{ truncate(session.last_message || "", 80) }}

- {{ session.message_count }} messages + {{ session.message_count }} сообщ. + diff --git a/mobile/src/views/ChatView.vue b/mobile/src/views/ChatView.vue index a0206dd..3a5cb05 100644 --- a/mobile/src/views/ChatView.vue +++ b/mobile/src/views/ChatView.vue @@ -143,7 +143,7 @@ async function loadSession() { customPrompt.value = data.session.system_prompt || ""; await scrollToBottom(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to load"; + error.value = e instanceof Error ? e.message : "Не удалось загрузить"; } finally { isLoading.value = false; } @@ -200,7 +200,7 @@ async function sendMessage(content: string) { } break; case "tool_start": - streamingContent.value += "\n_Searching..._\n"; + streamingContent.value += "\n_Поиск..._\n"; break; case "done": isStreaming.value = false; @@ -283,7 +283,7 @@ async function switchBranch(messageId: string) { await loadBranches(); await scrollToBottom(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to switch"; + error.value = e instanceof Error ? e.message : "Не удалось переключить"; } } @@ -298,17 +298,17 @@ async function createNewBranch() { if (showBranches.value) await loadBranches(); await scrollToBottom(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to create branch"; + error.value = e instanceof Error ? e.message : "Не удалось создать ветку"; } } async function deleteBranch() { const activeMessages = messages.value; if (!activeMessages.length) { - error.value = "No messages to delete"; + error.value = "Нет сообщений для удаления"; return; } - if (!confirm("Delete current branch? All messages will be removed from the server.")) return; + if (!confirm("Удалить текущую ветку? Все сообщения будут удалены с сервера.")) return; try { for (let i = activeMessages.length - 1; i >= 0; i--) { const m = activeMessages[i]!; @@ -319,7 +319,7 @@ async function deleteBranch() { messages.value = []; if (showBranches.value) await loadBranches(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to delete"; + error.value = e instanceof Error ? e.message : "Не удалось удалить"; await loadSession(); } } @@ -375,7 +375,7 @@ async function saveContextFiles() { context_files: contextFiles.value, }); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to save files"; + error.value = e instanceof Error ? e.message : "Не удалось сохранить файлы"; } } @@ -393,7 +393,7 @@ async function saveSystemPrompt() { system_prompt: customPrompt.value, }); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to save prompt"; + error.value = e instanceof Error ? e.message : "Не удалось сохранить промпт"; } } @@ -462,7 +462,7 @@ async function handleEditMessage(messageId: string, content: string) { await chatApi.editMessage(sessionId.value, messageId, content); await loadSession(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to edit"; + error.value = e instanceof Error ? e.message : "Не удалось отредактировать"; } } @@ -485,7 +485,7 @@ async function handleSummarizeBranch(messageId: string) { showBranches.value = false; showSettings.value = false; } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to summarize"; + error.value = e instanceof Error ? e.message : "Не удалось суммаризировать"; } } @@ -494,12 +494,12 @@ async function handleRegenerateResponse(messageId: string) { await chatApi.regenerateResponse(sessionId.value, messageId); await loadSession(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to regenerate"; + error.value = e instanceof Error ? e.message : "Не удалось перегенерировать"; } } async function handleDeleteFromMessage(messageId: string) { - if (!confirm("Delete this message and everything after it?")) return; + if (!confirm("Удалить это сообщение и все последующие?")) return; const idx = messages.value.findIndex((m) => m.id === messageId); if (idx < 0) return; try { @@ -512,16 +512,16 @@ async function handleDeleteFromMessage(messageId: string) { messages.value = messages.value.slice(0, idx); if (showBranches.value) await loadBranches(); } catch (e) { - error.value = e instanceof Error ? e.message : "Failed to delete"; + error.value = e instanceof Error ? e.message : "Не удалось удалить"; await loadSession(); } } const anyPanelOpen = computed(() => showBranches.value || showContextFiles.value || showSettings.value); const activePanelName = computed(() => { - if (showBranches.value) return "Branch Tree"; - if (showContextFiles.value) return "Context Files"; - if (showSettings.value) return "Settings"; + if (showBranches.value) return "Дерево веток"; + if (showContextFiles.value) return "Файлы контекста"; + if (showSettings.value) return "Настройки"; return ""; }); @@ -636,7 +636,7 @@ onUnmounted(() => { @@ -817,14 +817,14 @@ onUnmounted(() => {