diff --git a/.gitignore b/.gitignore index a17b6bb3f..86e1e8190 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ release backend/context_files/ # Editor directories and files -.vscode/.debug.env +.vscode/ .idea .DS_Store *.suo diff --git a/.vscode/.debug.script.mjs b/.vscode/.debug.script.mjs deleted file mode 100644 index 9ca93363c..000000000 --- a/.vscode/.debug.script.mjs +++ /dev/null @@ -1,23 +0,0 @@ -import fs from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import { createRequire } from 'node:module' -import { spawn } from 'node:child_process' - -const pkg = createRequire(import.meta.url)('../package.json') -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - -// write .debug.env -const envContent = Object.entries(pkg.debug.env).map(([key, val]) => `${key}=${val}`) -fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n')) - -// bootstrap -spawn( - // TODO: terminate `npm run dev` when Debug exits. - process.platform === 'win32' ? 'npm.cmd' : 'npm', - ['run', 'dev'], - { - stdio: 'inherit', - env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }), - }, -) \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index e40a984eb..000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "mrmlnc.vscode-json5", - "ms-python.python", - "ms-python.debugpy", - // Linting / Formatting - "esbenp.prettier-vscode", - "dbaeumer.vscode-eslint", - "bradlc.vscode-tailwindcss" - ] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7277b4912..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "compounds": [ - { - "name": "Debug App", - "preLaunchTask": "Before Debug", - "configurations": [ - "Debug Main Process", - "Debug Renderer Process" - ], - "presentation": { - "hidden": false, - "group": "", - "order": 1 - }, - "stopAll": true - } - ], - "configurations": [ - { - "name": "Debug Main Process", - "type": "node", - "request": "launch", - "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", - "windows": { - "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" - }, - "runtimeArgs": [ - "--no-sandbox", - "--remote-debugging-port=9229", - "." - ], - "envFile": "${workspaceFolder}/.vscode/.debug.env", - "console": "integratedTerminal" - }, - { - "name": "Debug Renderer Process", - "port": 9229, - "request": "attach", - "type": "chrome", - "timeout": 60000, - "skipFiles": [ - "/**", - "${workspaceRoot}/node_modules/**", - "${workspaceRoot}/dist-electron/**", - // Skip files in host(VITE_DEV_SERVER_URL) - "http://127.0.0.1:7777/**" - ] - }, - { - "name": "Debug Python Backend (Attach)", - "type": "debugpy", - "request": "attach", - "connect": { - "host": "localhost", - "port": 5678 - }, - "pathMappings": [ - { - "localRoot": "${workspaceFolder}/backend", - "remoteRoot": "." - } - ], - "justMyCode": false - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 467560604..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.tsc.autoDetect": "off", - "json.schemas": [ - { - "fileMatch": [ - "/*electron-builder.json5", - "/*electron-builder.json" - ], - "url": "https://json.schemastore.org/electron-builder" - } - ], - "cSpell.words": [ - "Eigent" - ], - "i18n-ally.localesPaths": [ - "backend/lang", - "server/lang", - "src/i18n", - "src/i18n/locales" - ], - // Prettier & ESLint configuration - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit", - "source.organizeImports": "explicit" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[jsonc]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "prettier.requireConfig": true, - "eslint.validate": [ - "javascript", - "javascriptreact", - "typescript", - "typescriptreact" - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 85d09cdea..8b4ea1253 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Before Debug", "type": "shell", - "command": "node .vscode/.debug.script.mjs", + "command": "node .vscode/.debug.script.js", "isBackground": true, "problemMatcher": { "owner": "typescript", diff --git a/src/components/SearchHistoryDialog.tsx b/src/components/SearchHistoryDialog.tsx index c4e47b19b..a1f2208d5 100644 --- a/src/components/SearchHistoryDialog.tsx +++ b/src/components/SearchHistoryDialog.tsx @@ -14,9 +14,10 @@ 'use client'; -import { ScanFace, Search } from 'lucide-react'; +import { ScanFace, Search, Trash2 } from 'lucide-react'; import { useEffect, useState } from 'react'; +import { proxyFetchDelete } from '@/api/http'; import GroupedHistoryView from '@/components/GroupedHistoryView'; import { CommandDialog, @@ -30,6 +31,7 @@ import { import useChatStoreAdapter from '@/hooks/useChatStoreAdapter'; import { replayProject } from '@/lib'; import { fetchHistoryTasks } from '@/service/historyApi'; +import { getAuthStore } from '@/store/authStore'; import { useGlobalStore } from '@/store/globalStore'; import { VisuallyHidden } from '@radix-ui/react-visually-hidden'; import { useTranslation } from 'react-i18next'; @@ -74,9 +76,35 @@ export function SearchHistoryDialog() { await replayProject(projectStore, navigate, projectId, question, historyId); }; - const handleDelete = (taskId: string) => { - // TODO: Implement delete functionality similar to HistorySidebar - console.log('Delete task:', taskId); + const handleDelete = async (historyId: string, callback?: () => void) => { + try { + await proxyFetchDelete(`/api/chat/history/${historyId}`); + + // Also delete local files for this task if available (via Electron IPC) + const history = historyTasks.find( + (item) => String(item.id) === String(historyId) + ); + const { email } = getAuthStore(); + if (history?.task_id && (window as any).ipcRenderer) { + try { + await (window as any).ipcRenderer.invoke( + 'delete-task-files', + email, + history.task_id, + history.project_id ?? undefined + ); + } catch (error) { + console.warn('Local file cleanup failed:', error); + } + } + + setHistoryTasks((list) => + list.filter((item) => String(item.id) !== String(historyId)) + ); + callback?.(); + } catch (error) { + console.error('Failed to delete history task:', error); + } }; const handleShare = (taskId: string) => { @@ -137,6 +165,20 @@ export function SearchHistoryDialog() {
{task.question}
+ ))} diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 0e6ac2026..4ec516a7b 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -28,6 +28,7 @@ import github2 from '@/assets/github2.svg'; import google from '@/assets/google.svg'; import WindowControls from '@/components/WindowControls'; import { hasStackKeys } from '@/lib'; +import { loginByStackWithAutoCreate } from '@/service/stackAuthApi'; import { useTranslation } from 'react-i18next'; const HAS_STACK_KEYS = hasStackKeys(); @@ -158,7 +159,20 @@ export default function Login() { return; } - setAuth({ email: formData.email, ...data }); + const token = (data as any)?.token as string | undefined; + const email = + ((data as any)?.email as string | undefined) ?? formData.email; + if (!token) { + setGeneralError(t('layout.login-failed-please-try-again')); + return; + } + + setAuth({ + token, + email, + username: (data as any)?.username ?? null, + user_id: (data as any)?.user_id ?? null, + }); setModelType('cloud'); // Record VITE_USE_LOCAL_PROXY value at login const localProxyValue = import.meta.env.VITE_USE_LOCAL_PROXY || null; @@ -177,12 +191,14 @@ export default function Login() { const handleLoginByStack = useCallback( async (token: string) => { try { - const data = await proxyFetchPost( - '/api/login-by_stack?token=' + token, - { - token: token, - } - ); + // 1) Try normal login (existing profile) + // 2) If not found, auto-create profile via signup and continue + const data = await loginByStackWithAutoCreate(token); + + if (!data) { + setGeneralError(t('layout.login-failed-please-try-again')); + return; + } const errorMessage = getLoginErrorMessage(data); if (errorMessage) { @@ -191,7 +207,21 @@ export default function Login() { } console.log('data', data); setModelType('cloud'); - setAuth({ email: formData.email, ...data }); + + const authToken = (data as any)?.token as string | undefined; + const email = + ((data as any)?.email as string | undefined) ?? formData.email; + if (!authToken) { + setGeneralError(t('layout.login-failed-please-try-again')); + return; + } + + setAuth({ + token: authToken, + email, + username: (data as any)?.username ?? null, + user_id: (data as any)?.user_id ?? null, + }); // Record VITE_USE_LOCAL_PROXY value at login const localProxyValue = import.meta.env.VITE_USE_LOCAL_PROXY || null; setLocalProxyValue(localProxyValue); @@ -220,6 +250,11 @@ export default function Login() { const handleReloadBtn = async (type: string) => { if (!app) { + // Keep the buttons visible so users discover the option, but make it + // clear when Stack OAuth isn't configured for local builds. + setGeneralError( + 'Social sign-in is not configured for this build. Set VITE_STACK_PROJECT_ID, VITE_STACK_PUBLISHABLE_CLIENT_KEY, and VITE_STACK_SECRET_SERVER_KEY.' + ); console.error('Stack app not initialized'); return; } @@ -287,7 +322,12 @@ export default function Login() { lock = true; setIsLoading(true); - let accessToken = await handleGetToken(code); + const accessToken = await handleGetToken(code); + if (!accessToken) { + setGeneralError(t('layout.login-failed-please-try-again')); + setIsLoading(false); + return; + } handleLoginByStack(accessToken); setTimeout(() => { lock = false; @@ -402,39 +442,35 @@ export default function Login() { {t('layout.sign-up')} - {HAS_STACK_KEYS && ( -
- - -
- )} - {HAS_STACK_KEYS && ( -
- {t('layout.or')} -
- )} +
+ + +
+
+ {t('layout.or')} +
{generalError && (

diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx index 3100fcd39..35c374dc5 100644 --- a/src/pages/SignUp.tsx +++ b/src/pages/SignUp.tsx @@ -27,6 +27,7 @@ import eye from '@/assets/eye.svg'; import github2 from '@/assets/github2.svg'; import google from '@/assets/google.svg'; import { hasStackKeys } from '@/lib'; +import { loginByStackToken } from '@/service/stackAuthApi'; import { useTranslation } from 'react-i18next'; const HAS_STACK_KEYS = hasStackKeys(); @@ -150,13 +151,16 @@ export default function SignUp() { const handleLoginByStack = useCallback( async (token: string) => { try { - const data = await proxyFetchPost( - '/api/login-by_stack?token=' + token, - { - token: token, - invite_code: localStorage.getItem('invite_code') || '', - } - ); + if (!token) { + setGeneralError(t('layout.login-failed-please-try-again')); + return; + } + const inviteCode = localStorage.getItem('invite_code') || ''; + const data = await loginByStackToken({ + token, + type: 'signup', + inviteCode: inviteCode || undefined, + }); if (data.code === 10) { setGeneralError( @@ -165,7 +169,21 @@ export default function SignUp() { return; } console.log('data', data); - setAuth({ email: formData.email, ...data }); + + const authToken = (data as any)?.token as string | undefined; + const email = + ((data as any)?.email as string | undefined) ?? formData.email; + if (!authToken) { + setGeneralError(t('layout.login-failed-please-try-again')); + return; + } + + setAuth({ + token: authToken, + email, + username: (data as any)?.username ?? null, + user_id: (data as any)?.user_id ?? null, + }); navigate('/'); } catch (error: any) { console.error('Login failed:', error); @@ -246,12 +264,17 @@ export default function SignUp() { lock = true; setIsLoading(true); const accessToken = await handleGetToken(code); + if (!accessToken) { + setGeneralError(t('layout.login-failed-please-try-again')); + setIsLoading(false); + return; + } await handleLoginByStack(accessToken); setTimeout(() => { lock = false; }, 1500); }, - [location.pathname, handleLoginByStack, handleGetToken, setIsLoading] + [location.pathname, handleLoginByStack, handleGetToken, setIsLoading, t] ); useEffect(() => { diff --git a/src/service/stackAuthApi.ts b/src/service/stackAuthApi.ts new file mode 100644 index 000000000..0eefc9b43 --- /dev/null +++ b/src/service/stackAuthApi.ts @@ -0,0 +1,63 @@ +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= + +import { proxyFetchPost } from '@/api/http'; + +export type StackAuthFlowType = 'login' | 'signup'; + +type StackLoginResponse = { + code?: number; + text?: string; + [key: string]: any; +}; + +function isUserNotFoundResponse( + res: StackLoginResponse | null | undefined +): boolean { + if (!res || typeof res !== 'object') return false; + if (res.code !== 1) return false; + const text = String(res.text ?? '').toLowerCase(); + return text.includes('user not found'); +} + +export async function loginByStackToken(params: { + token: string; + type: StackAuthFlowType; + inviteCode?: string; +}): Promise { + const searchParams = new URLSearchParams(); + searchParams.set('token', params.token); + searchParams.set('type', params.type); + if (params.inviteCode) { + searchParams.set('invite_code', params.inviteCode); + } + + // Endpoint is defined as POST, but consumes query params. + return proxyFetchPost(`/api/login-by_stack?${searchParams.toString()}`, { + token: params.token, + invite_code: params.inviteCode ?? '', + }); +} + +/** + * Attempts a passwordless SSO login first, and auto-creates the user if not found. + * This matches the UX request: “check existing profile; if missing, create like signup”. + */ +export async function loginByStackWithAutoCreate( + token: string +): Promise { + const loginRes = await loginByStackToken({ token, type: 'login' }); + if (!isUserNotFoundResponse(loginRes)) return loginRes; + return loginByStackToken({ token, type: 'signup' }); +} diff --git a/src/store/authStore.ts b/src/store/authStore.ts index ddf89880a..907ef6c9f 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -32,9 +32,9 @@ type CloudModelType = // auth info interface interface AuthInfo { token: string; - username: string; + username?: string | null; email: string; - user_id: number; + user_id?: number | null; } // auth state interface @@ -107,7 +107,12 @@ const authStore = create()( // auth related methods setAuth: ({ token, username, email, user_id }) => - set({ token, username, email, user_id }), + set({ + token, + email, + username: username ?? null, + user_id: user_id ?? null, + }), logout: () => set({ diff --git a/test/unit/components/SearchHistoryDialog.test.tsx b/test/unit/components/SearchHistoryDialog.test.tsx new file mode 100644 index 000000000..1ca4caaa0 --- /dev/null +++ b/test/unit/components/SearchHistoryDialog.test.tsx @@ -0,0 +1,148 @@ +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= + +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { SearchHistoryDialog } from '../../../src/components/SearchHistoryDialog'; + +// ---- Mocks ---- + +vi.mock('react-router-dom', () => ({ + useNavigate: () => vi.fn(), +})); + +vi.mock('@/hooks/useChatStoreAdapter', () => ({ + default: () => ({ + chatStore: { activeTaskId: undefined }, + projectStore: { + getProjectById: vi.fn(() => null), + setHistoryId: vi.fn(), + setActiveProject: vi.fn(), + }, + }), +})); + +vi.mock('@/store/globalStore', () => ({ + useGlobalStore: () => ({ history_type: 'list' }), +})); + +const proxyFetchDeleteMock = vi.fn().mockResolvedValue({ code: 0 }); +vi.mock('@/api/http', () => ({ + proxyFetchDelete: (...args: any[]) => proxyFetchDeleteMock(...args), +})); + +vi.mock('@/store/authStore', () => ({ + getAuthStore: () => ({ email: 'test@example.com' }), +})); + +vi.mock('@/service/historyApi', () => ({ + fetchHistoryTasks: (setter: (tasks: any[]) => void) => { + setter([ + { + id: '1', + task_id: 'task-1', + project_id: 'project-1', + question: 'My history item', + }, + ]); + }, +})); + +vi.mock('@/components/ui/command', () => ({ + CommandDialog: ({ open, children }: any) => + open ?

{children}
: null, + CommandEmpty: ({ children }: any) =>
{children}
, + CommandGroup: ({ children }: any) =>
{children}
, + CommandInput: (props: any) => , + CommandItem: ({ children, onSelect }: any) => ( +
onSelect?.('')}> + {children} +
+ ), + CommandList: ({ children }: any) =>
{children}
, + CommandSeparator: () =>
, +})); + +vi.mock('../../../src/components/ui/button', () => ({ + Button: ({ children, onClick, ...rest }: any) => ( + + ), +})); + +vi.mock('../../../src/components/ui/dialog', () => ({ + DialogTitle: ({ children }: any) =>
{children}
, +})); + +vi.mock('@radix-ui/react-visually-hidden', () => ({ + VisuallyHidden: ({ children }: any) => {children}, +})); + +vi.mock('lucide-react', () => ({ + Search: (props: any) =>
, + ScanFace: (props: any) =>
, + Trash2: (props: any) =>
, +})); + +vi.mock('@/components/GroupedHistoryView', () => ({ + default: () =>
, +})); + +vi.mock('@/lib', () => ({ + replayProject: vi.fn(), +})); + +describe('SearchHistoryDialog', () => { + beforeEach(() => { + vi.clearAllMocks(); + (window as any).ipcRenderer = { + invoke: vi.fn().mockResolvedValue(undefined), + }; + }); + + it('deletes a history item from list view', async () => { + const user = userEvent.setup(); + render(); + + // Open dialog + await user.click(screen.getByRole('button')); + + // History item should appear + await waitFor(() => { + expect(screen.getByText('My history item')).toBeInTheDocument(); + }); + + // Click delete button + const deleteButton = screen.getByRole('button', { name: 'Delete history' }); + await user.click(deleteButton); + + await waitFor(() => { + expect(proxyFetchDeleteMock).toHaveBeenCalledWith('/api/chat/history/1'); + }); + + expect((window as any).ipcRenderer.invoke).toHaveBeenCalledWith( + 'delete-task-files', + 'test@example.com', + 'task-1', + 'project-1' + ); + + await waitFor(() => { + expect(screen.queryByText('My history item')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/test/unit/service/stackAuthApi.test.ts b/test/unit/service/stackAuthApi.test.ts new file mode 100644 index 000000000..131c800de --- /dev/null +++ b/test/unit/service/stackAuthApi.test.ts @@ -0,0 +1,84 @@ +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + loginByStackToken, + loginByStackWithAutoCreate, +} from '../../../src/service/stackAuthApi'; + +vi.mock('@/api/http', () => ({ + proxyFetchPost: vi.fn(), +})); + +describe('stackAuthApi', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('falls back to signup when login returns user not found', async () => { + const { proxyFetchPost } = await import('@/api/http'); + + vi.mocked(proxyFetchPost) + .mockResolvedValueOnce({ code: 1, text: 'User not found' }) + .mockResolvedValueOnce({ code: 0, token: 't', email: 'e@example.com' }); + + const res = await loginByStackWithAutoCreate('stack-token'); + + expect(res.code).toBe(0); + expect(vi.mocked(proxyFetchPost)).toHaveBeenCalledTimes(2); + + const firstUrl = vi.mocked(proxyFetchPost).mock.calls[0][0] as string; + const secondUrl = vi.mocked(proxyFetchPost).mock.calls[1][0] as string; + + expect(firstUrl).toContain('/api/login-by_stack?'); + expect(firstUrl).toContain('type=login'); + expect(secondUrl).toContain('type=signup'); + }); + + it('does not fall back to signup for account/password error', async () => { + const { proxyFetchPost } = await import('@/api/http'); + + vi.mocked(proxyFetchPost).mockResolvedValueOnce({ + code: 10, + text: 'Account or password error', + }); + + const res = await loginByStackWithAutoCreate('stack-token'); + + expect(res.code).toBe(10); + expect(res.text).toBe('Account or password error'); + expect(vi.mocked(proxyFetchPost)).toHaveBeenCalledTimes(1); + + const firstUrl = vi.mocked(proxyFetchPost).mock.calls[0][0] as string; + expect(firstUrl).toContain('/api/login-by_stack?'); + expect(firstUrl).toContain('type=login'); + }); + + it('includes invite_code in query when provided', async () => { + const { proxyFetchPost } = await import('@/api/http'); + + vi.mocked(proxyFetchPost).mockResolvedValueOnce({ code: 0 }); + + await loginByStackToken({ + token: 'stack-token', + type: 'signup', + inviteCode: 'INV123', + }); + + const url = vi.mocked(proxyFetchPost).mock.calls[0][0] as string; + expect(url).toContain('invite_code=INV123'); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 61e1d944f..fbea82c4e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -45,9 +45,7 @@ export default defineConfig(({ command, mode }) => { entry: 'electron/main/index.ts', onstart(args) { if (process.env.VSCODE_DEBUG) { - console.log( - /* For `.vscode/.debug.script.mjs` */ '[startup] Electron App' - ); + console.log('[startup] Electron App'); } else { args.startup(); }