diff --git a/.gitignore b/.gitignore index 86e1e819..a17b6bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ release backend/context_files/ # Editor directories and files -.vscode/ +.vscode/.debug.env .idea .DS_Store *.suo diff --git a/.vscode/.debug.script.mjs b/.vscode/.debug.script.mjs new file mode 100644 index 00000000..9ca93363 --- /dev/null +++ b/.vscode/.debug.script.mjs @@ -0,0 +1,23 @@ +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 new file mode 100644 index 00000000..e40a984e --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // 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 new file mode 100644 index 00000000..7277b491 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,70 @@ +{ + // 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 new file mode 100644 index 00000000..46756060 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,54 @@ +{ + "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 8b4ea125..85d09cde 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Before Debug", "type": "shell", - "command": "node .vscode/.debug.script.js", + "command": "node .vscode/.debug.script.mjs", "isBackground": true, "problemMatcher": { "owner": "typescript", diff --git a/src/components/SearchHistoryDialog.tsx b/src/components/SearchHistoryDialog.tsx index a1f2208d..c4e47b19 100644 --- a/src/components/SearchHistoryDialog.tsx +++ b/src/components/SearchHistoryDialog.tsx @@ -14,10 +14,9 @@ 'use client'; -import { ScanFace, Search, Trash2 } from 'lucide-react'; +import { ScanFace, Search } from 'lucide-react'; import { useEffect, useState } from 'react'; -import { proxyFetchDelete } from '@/api/http'; import GroupedHistoryView from '@/components/GroupedHistoryView'; import { CommandDialog, @@ -31,7 +30,6 @@ 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'; @@ -76,35 +74,9 @@ export function SearchHistoryDialog() { await replayProject(projectStore, navigate, projectId, question, historyId); }; - 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 handleDelete = (taskId: string) => { + // TODO: Implement delete functionality similar to HistorySidebar + console.log('Delete task:', taskId); }; const handleShare = (taskId: string) => { @@ -165,20 +137,6 @@ export function SearchHistoryDialog() {
{task.question}
- ))} diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 4ec516a7..0e6ac202 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -28,7 +28,6 @@ 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(); @@ -159,20 +158,7 @@ export default function Login() { return; } - 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, - }); + setAuth({ email: formData.email, ...data }); setModelType('cloud'); // Record VITE_USE_LOCAL_PROXY value at login const localProxyValue = import.meta.env.VITE_USE_LOCAL_PROXY || null; @@ -191,14 +177,12 @@ export default function Login() { const handleLoginByStack = useCallback( async (token: string) => { try { - // 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 data = await proxyFetchPost( + '/api/login-by_stack?token=' + token, + { + token: token, + } + ); const errorMessage = getLoginErrorMessage(data); if (errorMessage) { @@ -207,21 +191,7 @@ export default function Login() { } console.log('data', data); setModelType('cloud'); - - 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, - }); + setAuth({ email: formData.email, ...data }); // Record VITE_USE_LOCAL_PROXY value at login const localProxyValue = import.meta.env.VITE_USE_LOCAL_PROXY || null; setLocalProxyValue(localProxyValue); @@ -250,11 +220,6 @@ 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; } @@ -322,12 +287,7 @@ export default function Login() { lock = true; setIsLoading(true); - const accessToken = await handleGetToken(code); - if (!accessToken) { - setGeneralError(t('layout.login-failed-please-try-again')); - setIsLoading(false); - return; - } + let accessToken = await handleGetToken(code); handleLoginByStack(accessToken); setTimeout(() => { lock = false; @@ -442,35 +402,39 @@ export default function Login() { {t('layout.sign-up')} -
- - -
-
- {t('layout.or')} -
+ {HAS_STACK_KEYS && ( +
+ + +
+ )} + {HAS_STACK_KEYS && ( +
+ {t('layout.or')} +
+ )}
{generalError && (

diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx index 35c374dc..3100fcd3 100644 --- a/src/pages/SignUp.tsx +++ b/src/pages/SignUp.tsx @@ -27,7 +27,6 @@ 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(); @@ -151,16 +150,13 @@ export default function SignUp() { const handleLoginByStack = useCallback( async (token: string) => { try { - 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, - }); + const data = await proxyFetchPost( + '/api/login-by_stack?token=' + token, + { + token: token, + invite_code: localStorage.getItem('invite_code') || '', + } + ); if (data.code === 10) { setGeneralError( @@ -169,21 +165,7 @@ export default function SignUp() { return; } console.log('data', 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, - }); + setAuth({ email: formData.email, ...data }); navigate('/'); } catch (error: any) { console.error('Login failed:', error); @@ -264,17 +246,12 @@ 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, t] + [location.pathname, handleLoginByStack, handleGetToken, setIsLoading] ); useEffect(() => { diff --git a/src/service/stackAuthApi.ts b/src/service/stackAuthApi.ts deleted file mode 100644 index 0eefc9b4..00000000 --- a/src/service/stackAuthApi.ts +++ /dev/null @@ -1,63 +0,0 @@ -// ========= 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 907ef6c9..ddf89880 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 | null; + username: string; email: string; - user_id?: number | null; + user_id: number; } // auth state interface @@ -107,12 +107,7 @@ const authStore = create()( // auth related methods setAuth: ({ token, username, email, user_id }) => - set({ - token, - email, - username: username ?? null, - user_id: user_id ?? null, - }), + set({ token, username, email, user_id }), logout: () => set({ diff --git a/test/unit/components/SearchHistoryDialog.test.tsx b/test/unit/components/SearchHistoryDialog.test.tsx deleted file mode 100644 index 1ca4caaa..00000000 --- a/test/unit/components/SearchHistoryDialog.test.tsx +++ /dev/null @@ -1,148 +0,0 @@ -// ========= 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 deleted file mode 100644 index 131c800d..00000000 --- a/test/unit/service/stackAuthApi.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -// ========= 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 fbea82c4..61e1d944 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -45,7 +45,9 @@ export default defineConfig(({ command, mode }) => { entry: 'electron/main/index.ts', onstart(args) { if (process.env.VSCODE_DEBUG) { - console.log('[startup] Electron App'); + console.log( + /* For `.vscode/.debug.script.mjs` */ '[startup] Electron App' + ); } else { args.startup(); }