From 5136c32b68fe961d39a998f0b18aa23440ee0c97 Mon Sep 17 00:00:00 2001 From: Kacper Date: Wed, 17 Dec 2025 20:11:16 +0100 Subject: [PATCH] refactor: move from next js to vite and tanstack router --- apps/app/electron/.eslintrc.js | 5 - apps/app/electron/preload.js | 37 - apps/app/eslint.config.mjs | 20 - apps/app/next.config.ts | 7 - apps/app/postcss.config.mjs | 7 - apps/app/src/app/api/claude/test/route.ts | 97 - apps/app/src/app/api/gemini/test/route.ts | 191 - apps/app/src/app/favicon.ico | Bin 25931 -> 0 bytes apps/app/src/app/layout.tsx | 26 - apps/app/src/app/page.tsx | 255 - apps/app/tsconfig.json | 34 - apps/{app => ui}/.gitignore | 18 +- apps/{app => ui}/components.json | 0 apps/{app => ui}/docs/AGENT_ARCHITECTURE.md | 0 apps/{app => ui}/docs/SESSION_MANAGEMENT.md | 0 apps/ui/eslint.config.mjs | 36 + apps/ui/index.html | 31 + apps/{app => ui}/package.json | 50 +- apps/{app => ui}/playwright.config.ts | 8 +- apps/{app => ui}/public/automaker.svg | 0 apps/{app => ui}/public/file.svg | 0 apps/{app => ui}/public/globe.svg | 0 apps/{app => ui}/public/icon.ico | Bin apps/{app => ui}/public/logo.png | Bin apps/{app => ui}/public/logo_larger.png | Bin apps/{app => ui}/public/next.svg | 0 apps/{app => ui}/public/readme_logo.png | Bin apps/{app => ui}/public/sounds/ding.mp3 | Bin apps/{app => ui}/public/vercel.svg | 0 apps/{app => ui}/public/window.svg | 0 apps/{app => ui}/scripts/prepare-server.js | 0 .../scripts/rebuild-server-natives.js | 0 .../{app => ui}/scripts/setup-e2e-fixtures.js | 0 apps/ui/src/App.tsx | 7 + .../delete-all-archived-sessions-dialog.tsx | 1 - .../src/components/delete-session-dialog.tsx | 0 .../dialogs/board-background-modal.tsx | 3 +- .../dialogs/file-browser-dialog.tsx | 3 +- .../layout/project-setup-dialog.tsx | 1 - .../src/components/layout/sidebar.tsx | 42 +- .../src/components/new-project-modal.tsx | 1 - .../src/components/session-manager.tsx | 1 - .../src/components/ui/accordion.tsx | 1 - .../src/components/ui/autocomplete.tsx | 1 - apps/{app => ui}/src/components/ui/badge.tsx | 0 .../src/components/ui/branch-autocomplete.tsx | 1 - apps/{app => ui}/src/components/ui/button.tsx | 0 apps/{app => ui}/src/components/ui/card.tsx | 0 .../components/ui/category-autocomplete.tsx | 1 - .../src/components/ui/checkbox.tsx | 1 - .../{app => ui}/src/components/ui/command.tsx | 1 - .../src/components/ui/count-up-timer.tsx | 1 - .../src/components/ui/course-promo-badge.tsx | 1 - .../components/ui/delete-confirm-dialog.tsx | 0 .../ui/description-image-dropzone.tsx | 3 +- apps/{app => ui}/src/components/ui/dialog.tsx | 1 - .../src/components/ui/dropdown-menu.tsx | 1 - .../components/ui/feature-image-upload.tsx | 1 - .../src/components/ui/git-diff-panel.tsx | 1 - .../src/components/ui/hotkey-button.tsx | 1 - .../src/components/ui/image-drop-zone.tsx | 1 - apps/{app => ui}/src/components/ui/input.tsx | 0 .../src/components/ui/keyboard-map.tsx | 1 - apps/{app => ui}/src/components/ui/label.tsx | 1 - .../src/components/ui/log-viewer.tsx | 1 - .../src/components/ui/markdown.tsx | 1 - .../{app => ui}/src/components/ui/popover.tsx | 1 - apps/{app => ui}/src/components/ui/sheet.tsx | 1 - apps/{app => ui}/src/components/ui/slider.tsx | 1 - apps/{app => ui}/src/components/ui/tabs.tsx | 1 - .../src/components/ui/textarea.tsx | 0 .../{app => ui}/src/components/ui/tooltip.tsx | 1 - .../src/components/ui/xml-syntax-editor.tsx | 1 - .../src/components/views/agent-tools-view.tsx | 1 - .../src/components/views/agent-view.tsx | 1 - .../src/components/views/analysis-view.tsx | 1 - .../src/components/views/board-view.tsx | 1 - .../views/board-view/board-controls.tsx | 1 - .../views/board-view/board-header.tsx | 1 - .../views/board-view/board-search-bar.tsx | 1 - .../views/board-view/components/index.ts | 0 .../board-view/components/kanban-card.tsx | 1 - .../board-view/components/kanban-column.tsx | 1 - .../components/worktree-selector.tsx | 1 - .../components/views/board-view/constants.ts | 0 .../board-view/dialogs/add-feature-dialog.tsx | 5 +- .../board-view/dialogs/agent-output-modal.tsx | 1 - .../dialogs/commit-worktree-dialog.tsx | 1 - .../dialogs/completed-features-modal.tsx | 1 - .../dialogs/create-branch-dialog.tsx | 1 - .../board-view/dialogs/create-pr-dialog.tsx | 1 - .../dialogs/create-worktree-dialog.tsx | 1 - .../dialogs/delete-all-verified-dialog.tsx | 1 - .../delete-completed-feature-dialog.tsx | 1 - .../dialogs/delete-worktree-dialog.tsx | 1 - .../dialogs/dependency-tree-dialog.tsx | 1 - .../dialogs/edit-feature-dialog.tsx | 1 - .../dialogs/feature-suggestions-dialog.tsx | 1 - .../board-view/dialogs/follow-up-dialog.tsx | 1 - .../views/board-view/dialogs/index.ts | 0 .../views/board-view/hooks/index.ts | 0 .../board-view/hooks/use-board-actions.ts | 0 .../board-view/hooks/use-board-background.ts | 2 +- .../hooks/use-board-column-features.ts | 0 .../board-view/hooks/use-board-drag-drop.ts | 0 .../board-view/hooks/use-board-effects.ts | 0 .../board-view/hooks/use-board-features.ts | 0 .../hooks/use-board-keyboard-shortcuts.ts | 0 .../board-view/hooks/use-board-persistence.ts | 0 .../board-view/hooks/use-follow-up-state.ts | 0 .../board-view/hooks/use-suggestions-state.ts | 0 .../views/board-view/kanban-board.tsx | 1 - .../views/board-view/shared/index.ts | 0 .../board-view/shared/model-constants.ts | 0 .../board-view/shared/model-selector.tsx | 1 - .../board-view/shared/priority-selector.tsx | 1 - .../shared/profile-quick-select.tsx | 1 - .../board-view/shared/testing-tab-content.tsx | 1 - .../shared/thinking-level-selector.tsx | 1 - .../src/components/views/chat-history.tsx | 1 - .../src/components/views/code-view.tsx | 1 - .../src/components/views/context-view.tsx | 1 - .../src/components/views/interview-view.tsx | 7 +- .../src/components/views/profiles-view.tsx | 1 - .../views/profiles-view/components/index.ts | 0 .../profiles-view/components/profile-form.tsx | 1 - .../components/profiles-header.tsx | 0 .../components/sortable-profile-card.tsx | 0 .../views/profiles-view/constants.ts | 0 .../components/views/profiles-view/utils.ts | 0 .../components/views/running-agents-view.tsx | 9 +- .../src/components/views/settings-view.tsx | 1 - .../ai-enhancement/ai-enhancement-section.tsx | 0 .../settings-view/ai-enhancement/index.ts | 0 .../settings-view/api-keys/api-key-field.tsx | 0 .../api-keys/api-keys-section.tsx | 5 +- .../authentication-status-display.tsx | 0 .../api-keys/hooks/use-api-key-management.ts | 0 .../api-keys/security-notice.tsx | 0 .../appearance/appearance-section.tsx | 0 .../settings-view/audio/audio-section.tsx | 0 .../cli-status/claude-cli-status.tsx | 0 .../components/delete-project-dialog.tsx | 0 .../components/keyboard-map-dialog.tsx | 0 .../components/settings-header.tsx | 0 .../components/settings-navigation.tsx | 0 .../views/settings-view/config/navigation.ts | 0 .../danger-zone/danger-zone-section.tsx | 0 .../feature-defaults-section.tsx | 0 .../views/settings-view/hooks/index.ts | 0 .../settings-view/hooks/use-cli-status.ts | 0 .../settings-view/hooks/use-settings-view.ts | 0 .../keyboard-shortcuts-section.tsx | 0 .../views/settings-view/shared/types.ts | 0 .../src/components/views/setup-view.tsx | 8 +- .../components/auth-method-selector.tsx | 0 .../components/cli-installation-card.tsx | 0 .../components/copyable-command-field.tsx | 0 .../views/setup-view/components/index.ts | 0 .../components/ready-state-card.tsx | 0 .../setup-view/components/status-badge.tsx | 0 .../setup-view/components/status-row.tsx | 0 .../setup-view/components/step-indicator.tsx | 0 .../setup-view/components/terminal-output.tsx | 0 .../views/setup-view/dialogs/index.ts | 0 .../views/setup-view/hooks/index.ts | 0 .../setup-view/hooks/use-cli-installation.ts | 0 .../views/setup-view/hooks/use-cli-status.ts | 0 .../views/setup-view/hooks/use-token-save.ts | 0 .../setup-view/steps/claude-setup-step.tsx | 1 - .../views/setup-view/steps/complete-step.tsx | 0 .../setup-view/steps/github-setup-step.tsx | 1 - .../views/setup-view/steps/index.ts | 0 .../views/setup-view/steps/welcome-step.tsx | 0 .../src/components/views/spec-view.tsx | 1 - .../src/components/views/terminal-view.tsx | 3 +- .../views/terminal-view/terminal-panel.tsx | 3 +- .../src/components/views/welcome-view.tsx | 10 +- .../src/components/views/wiki-view.tsx | 1 - .../src/components/workspace-picker-modal.tsx | 1 - apps/{app => ui}/src/config/api-providers.ts | 0 apps/{app => ui}/src/config/app-config.ts | 0 apps/{app => ui}/src/config/model-config.ts | 0 .../{app => ui}/src/config/terminal-themes.ts | 0 apps/{app => ui}/src/config/theme-options.ts | 0 .../src/contexts/file-browser-context.tsx | 1 - apps/{app => ui}/src/hooks/use-auto-mode.ts | 0 .../src/hooks/use-electron-agent.ts | 0 .../src/hooks/use-keyboard-shortcuts.ts | 1 - .../src/hooks/use-message-queue.ts | 0 .../src/hooks/use-scroll-tracking.ts | 0 .../{app => ui}/src/hooks/use-window-state.ts | 0 .../src/lib/agent-context-parser.ts | 0 apps/{app => ui}/src/lib/electron.ts | 6 +- apps/{app => ui}/src/lib/file-picker.ts | 0 apps/{app => ui}/src/lib/http-api-client.ts | 4 +- apps/{app => ui}/src/lib/log-parser.ts | 0 apps/{app => ui}/src/lib/project-init.ts | 0 apps/{app => ui}/src/lib/templates.ts | 0 apps/{app => ui}/src/lib/utils.ts | 0 apps/{app/electron/main.js => ui/src/main.ts} | 159 +- apps/ui/src/preload.ts | 42 + apps/ui/src/renderer.tsx | 9 + apps/ui/src/routes/__root.tsx | 146 + apps/ui/src/routes/agent.tsx | 6 + apps/ui/src/routes/board.tsx | 6 + apps/ui/src/routes/context.tsx | 6 + apps/ui/src/routes/index.tsx | 6 + apps/ui/src/routes/interview.tsx | 6 + apps/ui/src/routes/profiles.tsx | 6 + apps/ui/src/routes/running-agents.tsx | 6 + apps/ui/src/routes/settings.tsx | 6 + apps/ui/src/routes/setup.tsx | 6 + apps/ui/src/routes/spec.tsx | 6 + apps/ui/src/routes/terminal.tsx | 6 + apps/ui/src/routes/wiki.tsx | 6 + apps/{app => ui}/src/store/app-store.ts | 0 apps/{app => ui}/src/store/setup-store.ts | 2 +- .../globals.css => ui/src/styles/global.css} | 0 apps/{app => ui}/src/types/css.d.ts | 0 apps/{app => ui}/src/types/electron.d.ts | 0 apps/{app => ui}/src/types/session.ts | 0 apps/ui/src/utils/router.ts | 14 + apps/{app => ui}/tests/context-view.spec.ts | 0 .../tests/feature-lifecycle.spec.ts | 0 apps/{app => ui}/tests/profiles-view.spec.ts | 0 .../tests/spec-editor-persistence.spec.ts | 0 apps/{app => ui}/tests/utils/api/client.ts | 0 .../tests/utils/components/autocomplete.ts | 0 .../tests/utils/components/dialogs.ts | 0 .../tests/utils/components/modals.ts | 0 .../tests/utils/components/toasts.ts | 0 .../{app => ui}/tests/utils/core/constants.ts | 0 apps/{app => ui}/tests/utils/core/elements.ts | 0 .../tests/utils/core/interactions.ts | 0 apps/{app => ui}/tests/utils/core/waiting.ts | 0 .../tests/utils/features/kanban.ts | 0 .../tests/utils/features/skip-tests.ts | 0 .../tests/utils/features/timers.ts | 0 .../tests/utils/features/waiting-approval.ts | 0 .../tests/utils/files/drag-drop.ts | 0 apps/{app => ui}/tests/utils/git/worktree.ts | 0 .../tests/utils/helpers/concurrency.ts | 0 .../tests/utils/helpers/log-viewer.ts | 0 .../{app => ui}/tests/utils/helpers/scroll.ts | 0 apps/{app => ui}/tests/utils/index.ts | 0 .../tests/utils/navigation/views.ts | 0 .../tests/utils/project/fixtures.ts | 0 apps/{app => ui}/tests/utils/project/setup.ts | 0 apps/{app => ui}/tests/utils/views/agent.ts | 0 apps/{app => ui}/tests/utils/views/board.ts | 0 apps/{app => ui}/tests/utils/views/context.ts | 0 .../{app => ui}/tests/utils/views/profiles.ts | 0 .../{app => ui}/tests/utils/views/settings.ts | 0 apps/{app => ui}/tests/utils/views/setup.ts | 0 .../tests/utils/views/spec-editor.ts | 0 .../tests/worktree-integration.spec.ts | 0 apps/ui/tsconfig.json | 22 + apps/ui/vite.config.mts | 57 + docs/migration-plan-nextjs-to-vite.md | 4 +- init.sh | 6 +- package-lock.json | 19851 ++++++++-------- package.json | 28 +- 263 files changed, 11148 insertions(+), 10276 deletions(-) delete mode 100644 apps/app/electron/.eslintrc.js delete mode 100644 apps/app/electron/preload.js delete mode 100644 apps/app/eslint.config.mjs delete mode 100644 apps/app/next.config.ts delete mode 100644 apps/app/postcss.config.mjs delete mode 100644 apps/app/src/app/api/claude/test/route.ts delete mode 100644 apps/app/src/app/api/gemini/test/route.ts delete mode 100644 apps/app/src/app/favicon.ico delete mode 100644 apps/app/src/app/layout.tsx delete mode 100644 apps/app/src/app/page.tsx delete mode 100644 apps/app/tsconfig.json rename apps/{app => ui}/.gitignore (86%) rename apps/{app => ui}/components.json (100%) rename apps/{app => ui}/docs/AGENT_ARCHITECTURE.md (100%) rename apps/{app => ui}/docs/SESSION_MANAGEMENT.md (100%) create mode 100644 apps/ui/eslint.config.mjs create mode 100644 apps/ui/index.html rename apps/{app => ui}/package.json (77%) rename apps/{app => ui}/playwright.config.ts (90%) rename apps/{app => ui}/public/automaker.svg (100%) rename apps/{app => ui}/public/file.svg (100%) rename apps/{app => ui}/public/globe.svg (100%) rename apps/{app => ui}/public/icon.ico (100%) rename apps/{app => ui}/public/logo.png (100%) rename apps/{app => ui}/public/logo_larger.png (100%) rename apps/{app => ui}/public/next.svg (100%) rename apps/{app => ui}/public/readme_logo.png (100%) rename apps/{app => ui}/public/sounds/ding.mp3 (100%) rename apps/{app => ui}/public/vercel.svg (100%) rename apps/{app => ui}/public/window.svg (100%) rename apps/{app => ui}/scripts/prepare-server.js (100%) rename apps/{app => ui}/scripts/rebuild-server-natives.js (100%) rename apps/{app => ui}/scripts/setup-e2e-fixtures.js (100%) create mode 100644 apps/ui/src/App.tsx rename apps/{app => ui}/src/components/delete-all-archived-sessions-dialog.tsx (99%) rename apps/{app => ui}/src/components/delete-session-dialog.tsx (100%) rename apps/{app => ui}/src/components/dialogs/board-background-modal.tsx (99%) rename apps/{app => ui}/src/components/dialogs/file-browser-dialog.tsx (99%) rename apps/{app => ui}/src/components/layout/project-setup-dialog.tsx (99%) rename apps/{app => ui}/src/components/layout/sidebar.tsx (98%) rename apps/{app => ui}/src/components/new-project-modal.tsx (99%) rename apps/{app => ui}/src/components/session-manager.tsx (99%) rename apps/{app => ui}/src/components/ui/accordion.tsx (99%) rename apps/{app => ui}/src/components/ui/autocomplete.tsx (99%) rename apps/{app => ui}/src/components/ui/badge.tsx (100%) rename apps/{app => ui}/src/components/ui/branch-autocomplete.tsx (98%) rename apps/{app => ui}/src/components/ui/button.tsx (100%) rename apps/{app => ui}/src/components/ui/card.tsx (100%) rename apps/{app => ui}/src/components/ui/category-autocomplete.tsx (98%) rename apps/{app => ui}/src/components/ui/checkbox.tsx (99%) rename apps/{app => ui}/src/components/ui/command.tsx (99%) rename apps/{app => ui}/src/components/ui/count-up-timer.tsx (99%) rename apps/{app => ui}/src/components/ui/course-promo-badge.tsx (99%) rename apps/{app => ui}/src/components/ui/delete-confirm-dialog.tsx (100%) rename apps/{app => ui}/src/components/ui/description-image-dropzone.tsx (99%) rename apps/{app => ui}/src/components/ui/dialog.tsx (99%) rename apps/{app => ui}/src/components/ui/dropdown-menu.tsx (99%) rename apps/{app => ui}/src/components/ui/feature-image-upload.tsx (99%) rename apps/{app => ui}/src/components/ui/git-diff-panel.tsx (99%) rename apps/{app => ui}/src/components/ui/hotkey-button.tsx (99%) rename apps/{app => ui}/src/components/ui/image-drop-zone.tsx (99%) rename apps/{app => ui}/src/components/ui/input.tsx (100%) rename apps/{app => ui}/src/components/ui/keyboard-map.tsx (99%) rename apps/{app => ui}/src/components/ui/label.tsx (97%) rename apps/{app => ui}/src/components/ui/log-viewer.tsx (99%) rename apps/{app => ui}/src/components/ui/markdown.tsx (99%) rename apps/{app => ui}/src/components/ui/popover.tsx (99%) rename apps/{app => ui}/src/components/ui/sheet.tsx (99%) rename apps/{app => ui}/src/components/ui/slider.tsx (99%) rename apps/{app => ui}/src/components/ui/tabs.tsx (99%) rename apps/{app => ui}/src/components/ui/textarea.tsx (100%) rename apps/{app => ui}/src/components/ui/tooltip.tsx (99%) rename apps/{app => ui}/src/components/ui/xml-syntax-editor.tsx (99%) rename apps/{app => ui}/src/components/views/agent-tools-view.tsx (99%) rename apps/{app => ui}/src/components/views/agent-view.tsx (99%) rename apps/{app => ui}/src/components/views/analysis-view.tsx (99%) rename apps/{app => ui}/src/components/views/board-view.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/board-controls.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/board-header.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/board-search-bar.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/components/index.ts (100%) rename apps/{app => ui}/src/components/views/board-view/components/kanban-card.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/components/kanban-column.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/components/worktree-selector.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/constants.ts (100%) rename apps/{app => ui}/src/components/views/board-view/dialogs/add-feature-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/agent-output-modal.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/commit-worktree-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/completed-features-modal.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/create-branch-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/create-pr-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/create-worktree-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/delete-all-verified-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/delete-completed-feature-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/delete-worktree-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/dependency-tree-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/edit-feature-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/feature-suggestions-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/follow-up-dialog.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/dialogs/index.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/index.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-actions.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-background.ts (95%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-column-features.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-drag-drop.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-effects.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-features.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-keyboard-shortcuts.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-board-persistence.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-follow-up-state.ts (100%) rename apps/{app => ui}/src/components/views/board-view/hooks/use-suggestions-state.ts (100%) rename apps/{app => ui}/src/components/views/board-view/kanban-board.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/shared/index.ts (100%) rename apps/{app => ui}/src/components/views/board-view/shared/model-constants.ts (100%) rename apps/{app => ui}/src/components/views/board-view/shared/model-selector.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/shared/priority-selector.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/shared/profile-quick-select.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/shared/testing-tab-content.tsx (99%) rename apps/{app => ui}/src/components/views/board-view/shared/thinking-level-selector.tsx (99%) rename apps/{app => ui}/src/components/views/chat-history.tsx (99%) rename apps/{app => ui}/src/components/views/code-view.tsx (99%) rename apps/{app => ui}/src/components/views/context-view.tsx (99%) rename apps/{app => ui}/src/components/views/interview-view.tsx (99%) rename apps/{app => ui}/src/components/views/profiles-view.tsx (99%) rename apps/{app => ui}/src/components/views/profiles-view/components/index.ts (100%) rename apps/{app => ui}/src/components/views/profiles-view/components/profile-form.tsx (99%) rename apps/{app => ui}/src/components/views/profiles-view/components/profiles-header.tsx (100%) rename apps/{app => ui}/src/components/views/profiles-view/components/sortable-profile-card.tsx (100%) rename apps/{app => ui}/src/components/views/profiles-view/constants.ts (100%) rename apps/{app => ui}/src/components/views/profiles-view/utils.ts (100%) rename apps/{app => ui}/src/components/views/running-agents-view.tsx (97%) rename apps/{app => ui}/src/components/views/settings-view.tsx (99%) rename apps/{app => ui}/src/components/views/settings-view/ai-enhancement/ai-enhancement-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/ai-enhancement/index.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/api-keys/api-key-field.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/api-keys/api-keys-section.tsx (97%) rename apps/{app => ui}/src/components/views/settings-view/api-keys/authentication-status-display.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/api-keys/security-notice.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/appearance/appearance-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/audio/audio-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/cli-status/claude-cli-status.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/components/delete-project-dialog.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/components/keyboard-map-dialog.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/components/settings-header.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/components/settings-navigation.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/config/navigation.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/danger-zone/danger-zone-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/feature-defaults/feature-defaults-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/hooks/index.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/hooks/use-cli-status.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/hooks/use-settings-view.ts (100%) rename apps/{app => ui}/src/components/views/settings-view/keyboard-shortcuts/keyboard-shortcuts-section.tsx (100%) rename apps/{app => ui}/src/components/views/settings-view/shared/types.ts (100%) rename apps/{app => ui}/src/components/views/setup-view.tsx (95%) rename apps/{app => ui}/src/components/views/setup-view/components/auth-method-selector.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/cli-installation-card.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/copyable-command-field.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/index.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/components/ready-state-card.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/status-badge.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/status-row.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/step-indicator.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/components/terminal-output.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/dialogs/index.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/hooks/index.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/hooks/use-cli-installation.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/hooks/use-cli-status.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/hooks/use-token-save.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/steps/claude-setup-step.tsx (99%) rename apps/{app => ui}/src/components/views/setup-view/steps/complete-step.tsx (100%) rename apps/{app => ui}/src/components/views/setup-view/steps/github-setup-step.tsx (99%) rename apps/{app => ui}/src/components/views/setup-view/steps/index.ts (100%) rename apps/{app => ui}/src/components/views/setup-view/steps/welcome-step.tsx (100%) rename apps/{app => ui}/src/components/views/spec-view.tsx (99%) rename apps/{app => ui}/src/components/views/terminal-view.tsx (99%) rename apps/{app => ui}/src/components/views/terminal-view/terminal-panel.tsx (99%) rename apps/{app => ui}/src/components/views/welcome-view.tsx (99%) rename apps/{app => ui}/src/components/views/wiki-view.tsx (99%) rename apps/{app => ui}/src/components/workspace-picker-modal.tsx (99%) rename apps/{app => ui}/src/config/api-providers.ts (100%) rename apps/{app => ui}/src/config/app-config.ts (100%) rename apps/{app => ui}/src/config/model-config.ts (100%) rename apps/{app => ui}/src/config/terminal-themes.ts (100%) rename apps/{app => ui}/src/config/theme-options.ts (100%) rename apps/{app => ui}/src/contexts/file-browser-context.tsx (99%) rename apps/{app => ui}/src/hooks/use-auto-mode.ts (100%) rename apps/{app => ui}/src/hooks/use-electron-agent.ts (100%) rename apps/{app => ui}/src/hooks/use-keyboard-shortcuts.ts (99%) rename apps/{app => ui}/src/hooks/use-message-queue.ts (100%) rename apps/{app => ui}/src/hooks/use-scroll-tracking.ts (100%) rename apps/{app => ui}/src/hooks/use-window-state.ts (100%) rename apps/{app => ui}/src/lib/agent-context-parser.ts (100%) rename apps/{app => ui}/src/lib/electron.ts (99%) rename apps/{app => ui}/src/lib/file-picker.ts (100%) rename apps/{app => ui}/src/lib/http-api-client.ts (99%) rename apps/{app => ui}/src/lib/log-parser.ts (100%) rename apps/{app => ui}/src/lib/project-init.ts (100%) rename apps/{app => ui}/src/lib/templates.ts (100%) rename apps/{app => ui}/src/lib/utils.ts (100%) rename apps/{app/electron/main.js => ui/src/main.ts} (69%) create mode 100644 apps/ui/src/preload.ts create mode 100644 apps/ui/src/renderer.tsx create mode 100644 apps/ui/src/routes/__root.tsx create mode 100644 apps/ui/src/routes/agent.tsx create mode 100644 apps/ui/src/routes/board.tsx create mode 100644 apps/ui/src/routes/context.tsx create mode 100644 apps/ui/src/routes/index.tsx create mode 100644 apps/ui/src/routes/interview.tsx create mode 100644 apps/ui/src/routes/profiles.tsx create mode 100644 apps/ui/src/routes/running-agents.tsx create mode 100644 apps/ui/src/routes/settings.tsx create mode 100644 apps/ui/src/routes/setup.tsx create mode 100644 apps/ui/src/routes/spec.tsx create mode 100644 apps/ui/src/routes/terminal.tsx create mode 100644 apps/ui/src/routes/wiki.tsx rename apps/{app => ui}/src/store/app-store.ts (100%) rename apps/{app => ui}/src/store/setup-store.ts (98%) rename apps/{app/src/app/globals.css => ui/src/styles/global.css} (100%) rename apps/{app => ui}/src/types/css.d.ts (100%) rename apps/{app => ui}/src/types/electron.d.ts (100%) rename apps/{app => ui}/src/types/session.ts (100%) create mode 100644 apps/ui/src/utils/router.ts rename apps/{app => ui}/tests/context-view.spec.ts (100%) rename apps/{app => ui}/tests/feature-lifecycle.spec.ts (100%) rename apps/{app => ui}/tests/profiles-view.spec.ts (100%) rename apps/{app => ui}/tests/spec-editor-persistence.spec.ts (100%) rename apps/{app => ui}/tests/utils/api/client.ts (100%) rename apps/{app => ui}/tests/utils/components/autocomplete.ts (100%) rename apps/{app => ui}/tests/utils/components/dialogs.ts (100%) rename apps/{app => ui}/tests/utils/components/modals.ts (100%) rename apps/{app => ui}/tests/utils/components/toasts.ts (100%) rename apps/{app => ui}/tests/utils/core/constants.ts (100%) rename apps/{app => ui}/tests/utils/core/elements.ts (100%) rename apps/{app => ui}/tests/utils/core/interactions.ts (100%) rename apps/{app => ui}/tests/utils/core/waiting.ts (100%) rename apps/{app => ui}/tests/utils/features/kanban.ts (100%) rename apps/{app => ui}/tests/utils/features/skip-tests.ts (100%) rename apps/{app => ui}/tests/utils/features/timers.ts (100%) rename apps/{app => ui}/tests/utils/features/waiting-approval.ts (100%) rename apps/{app => ui}/tests/utils/files/drag-drop.ts (100%) rename apps/{app => ui}/tests/utils/git/worktree.ts (100%) rename apps/{app => ui}/tests/utils/helpers/concurrency.ts (100%) rename apps/{app => ui}/tests/utils/helpers/log-viewer.ts (100%) rename apps/{app => ui}/tests/utils/helpers/scroll.ts (100%) rename apps/{app => ui}/tests/utils/index.ts (100%) rename apps/{app => ui}/tests/utils/navigation/views.ts (100%) rename apps/{app => ui}/tests/utils/project/fixtures.ts (100%) rename apps/{app => ui}/tests/utils/project/setup.ts (100%) rename apps/{app => ui}/tests/utils/views/agent.ts (100%) rename apps/{app => ui}/tests/utils/views/board.ts (100%) rename apps/{app => ui}/tests/utils/views/context.ts (100%) rename apps/{app => ui}/tests/utils/views/profiles.ts (100%) rename apps/{app => ui}/tests/utils/views/settings.ts (100%) rename apps/{app => ui}/tests/utils/views/setup.ts (100%) rename apps/{app => ui}/tests/utils/views/spec-editor.ts (100%) rename apps/{app => ui}/tests/worktree-integration.spec.ts (100%) create mode 100644 apps/ui/tsconfig.json create mode 100644 apps/ui/vite.config.mts diff --git a/apps/app/electron/.eslintrc.js b/apps/app/electron/.eslintrc.js deleted file mode 100644 index 5c4bdfee..00000000 --- a/apps/app/electron/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - rules: { - "@typescript-eslint/no-require-imports": "off", - }, -}; diff --git a/apps/app/electron/preload.js b/apps/app/electron/preload.js deleted file mode 100644 index 289d2cd7..00000000 --- a/apps/app/electron/preload.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Simplified Electron preload script - * - * Only exposes native features (dialogs, shell) and server URL. - * All other operations go through HTTP API. - */ - -const { contextBridge, ipcRenderer } = require("electron"); - -// Expose minimal API for native features -contextBridge.exposeInMainWorld("electronAPI", { - // Platform info - platform: process.platform, - isElectron: true, - - // Connection check - ping: () => ipcRenderer.invoke("ping"), - - // Get server URL for HTTP client - getServerUrl: () => ipcRenderer.invoke("server:getUrl"), - - // Native dialogs - better UX than prompt() - openDirectory: () => ipcRenderer.invoke("dialog:openDirectory"), - openFile: (options) => ipcRenderer.invoke("dialog:openFile", options), - saveFile: (options) => ipcRenderer.invoke("dialog:saveFile", options), - - // Shell operations - openExternalLink: (url) => ipcRenderer.invoke("shell:openExternal", url), - openPath: (filePath) => ipcRenderer.invoke("shell:openPath", filePath), - - // App info - getPath: (name) => ipcRenderer.invoke("app:getPath", name), - getVersion: () => ipcRenderer.invoke("app:getVersion"), - isPackaged: () => ipcRenderer.invoke("app:isPackaged"), -}); - -console.log("[Preload] Electron API exposed (simplified mode)"); diff --git a/apps/app/eslint.config.mjs b/apps/app/eslint.config.mjs deleted file mode 100644 index 6c419a68..00000000 --- a/apps/app/eslint.config.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { defineConfig, globalIgnores } from "eslint/config"; -import nextVitals from "eslint-config-next/core-web-vitals"; -import nextTs from "eslint-config-next/typescript"; - -const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - // Electron files use CommonJS - "electron/**", - ]), -]); - -export default eslintConfig; diff --git a/apps/app/next.config.ts b/apps/app/next.config.ts deleted file mode 100644 index 65c102b9..00000000 --- a/apps/app/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - output: "export", -}; - -export default nextConfig; diff --git a/apps/app/postcss.config.mjs b/apps/app/postcss.config.mjs deleted file mode 100644 index 61e36849..00000000 --- a/apps/app/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; - -export default config; diff --git a/apps/app/src/app/api/claude/test/route.ts b/apps/app/src/app/api/claude/test/route.ts deleted file mode 100644 index 95dab4ba..00000000 --- a/apps/app/src/app/api/claude/test/route.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -interface AnthropicResponse { - content?: Array<{ type: string; text?: string }>; - model?: string; - error?: { message?: string }; -} - -export async function POST(request: NextRequest) { - try { - const { apiKey } = await request.json(); - - // Use provided API key or fall back to environment variable - const effectiveApiKey = apiKey || process.env.ANTHROPIC_API_KEY; - - if (!effectiveApiKey) { - return NextResponse.json( - { success: false, error: "No API key provided or configured in environment" }, - { status: 400 } - ); - } - - // Send a simple test prompt to the Anthropic API - const response = await fetch("https://api.anthropic.com/v1/messages", { - method: "POST", - headers: { - "Content-Type": "application/json", - "x-api-key": effectiveApiKey, - "anthropic-version": "2023-06-01", - }, - body: JSON.stringify({ - model: "claude-sonnet-4-20250514", - max_tokens: 100, - messages: [ - { - role: "user", - content: "Respond with exactly: 'Claude API connection successful!' and nothing else.", - }, - ], - }), - }); - - if (!response.ok) { - const errorData = (await response.json()) as AnthropicResponse; - const errorMessage = errorData.error?.message || `HTTP ${response.status}`; - - if (response.status === 401) { - return NextResponse.json( - { success: false, error: "Invalid API key. Please check your Anthropic API key." }, - { status: 401 } - ); - } - - if (response.status === 429) { - return NextResponse.json( - { success: false, error: "Rate limit exceeded. Please try again later." }, - { status: 429 } - ); - } - - return NextResponse.json( - { success: false, error: `API error: ${errorMessage}` }, - { status: response.status } - ); - } - - const data = (await response.json()) as AnthropicResponse; - - // Check if we got a valid response - if (data.content && data.content.length > 0) { - const textContent = data.content.find((block) => block.type === "text"); - if (textContent && textContent.type === "text" && textContent.text) { - return NextResponse.json({ - success: true, - message: `Connection successful! Response: "${textContent.text}"`, - model: data.model, - }); - } - } - - return NextResponse.json({ - success: true, - message: "Connection successful! Claude responded.", - model: data.model, - }); - } catch (error: unknown) { - console.error("Claude API test error:", error); - - const errorMessage = - error instanceof Error ? error.message : "Failed to connect to Claude API"; - - return NextResponse.json( - { success: false, error: errorMessage }, - { status: 500 } - ); - } -} diff --git a/apps/app/src/app/api/gemini/test/route.ts b/apps/app/src/app/api/gemini/test/route.ts deleted file mode 100644 index a4830c84..00000000 --- a/apps/app/src/app/api/gemini/test/route.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -interface GeminiContent { - parts: Array<{ - text?: string; - inlineData?: { - mimeType: string; - data: string; - }; - }>; - role?: string; -} - -interface GeminiRequest { - contents: GeminiContent[]; - generationConfig?: { - maxOutputTokens?: number; - temperature?: number; - }; -} - -interface GeminiResponse { - candidates?: Array<{ - content: { - parts: Array<{ - text: string; - }>; - role: string; - }; - finishReason: string; - safetyRatings?: Array<{ - category: string; - probability: string; - }>; - }>; - promptFeedback?: { - safetyRatings?: Array<{ - category: string; - probability: string; - }>; - }; - error?: { - code: number; - message: string; - status: string; - }; -} - -export async function POST(request: NextRequest) { - try { - const { apiKey, imageData, mimeType, prompt } = await request.json(); - - // Use provided API key or fall back to environment variable - const effectiveApiKey = apiKey || process.env.GOOGLE_API_KEY; - - if (!effectiveApiKey) { - return NextResponse.json( - { success: false, error: "No API key provided or configured in environment" }, - { status: 400 } - ); - } - - // Build the request body - const requestBody: GeminiRequest = { - contents: [ - { - parts: [], - }, - ], - generationConfig: { - maxOutputTokens: 150, - temperature: 0.4, - }, - }; - - // Add image if provided - if (imageData && mimeType) { - requestBody.contents[0].parts.push({ - inlineData: { - mimeType: mimeType, - data: imageData, - }, - }); - } - - // Add text prompt - const textPrompt = prompt || (imageData - ? "Describe what you see in this image briefly." - : "Respond with exactly: 'Gemini SDK connection successful!' and nothing else."); - - requestBody.contents[0].parts.push({ - text: textPrompt, - }); - - // Call Gemini API - using gemini-1.5-flash as it supports both text and vision - const model = imageData ? "gemini-1.5-flash" : "gemini-1.5-flash"; - const geminiUrl = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${effectiveApiKey}`; - - const response = await fetch(geminiUrl, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(requestBody), - }); - - const data: GeminiResponse = await response.json(); - - // Check for API errors - if (data.error) { - const errorMessage = data.error.message || "Unknown Gemini API error"; - const statusCode = data.error.code || 500; - - if (statusCode === 400 && errorMessage.includes("API key")) { - return NextResponse.json( - { success: false, error: "Invalid API key. Please check your Google API key." }, - { status: 401 } - ); - } - - if (statusCode === 429) { - return NextResponse.json( - { success: false, error: "Rate limit exceeded. Please try again later." }, - { status: 429 } - ); - } - - return NextResponse.json( - { success: false, error: `API error: ${errorMessage}` }, - { status: statusCode } - ); - } - - // Check for valid response - if (!response.ok) { - return NextResponse.json( - { success: false, error: `HTTP error: ${response.status} ${response.statusText}` }, - { status: response.status } - ); - } - - // Extract response text - if (data.candidates && data.candidates.length > 0 && data.candidates[0].content?.parts?.length > 0) { - const responseText = data.candidates[0].content.parts - .filter((part) => part.text) - .map((part) => part.text) - .join(""); - - return NextResponse.json({ - success: true, - message: `Connection successful! Response: "${responseText.substring(0, 200)}${responseText.length > 200 ? '...' : ''}"`, - model: model, - hasImage: !!imageData, - }); - } - - // Handle blocked responses - if (data.promptFeedback?.safetyRatings) { - return NextResponse.json({ - success: true, - message: "Connection successful! Gemini responded (response may have been filtered).", - model: model, - hasImage: !!imageData, - }); - } - - return NextResponse.json({ - success: true, - message: "Connection successful! Gemini responded.", - model: model, - hasImage: !!imageData, - }); - } catch (error: unknown) { - console.error("Gemini API test error:", error); - - if (error instanceof TypeError && error.message.includes("fetch")) { - return NextResponse.json( - { success: false, error: "Network error. Unable to reach Gemini API." }, - { status: 503 } - ); - } - - const errorMessage = - error instanceof Error ? error.message : "Failed to connect to Gemini API"; - - return NextResponse.json( - { success: false, error: errorMessage }, - { status: 500 } - ); - } -} diff --git a/apps/app/src/app/favicon.ico b/apps/app/src/app/favicon.ico deleted file mode 100644 index 718d6fea4835ec2d246af9800eddb7ffb276240c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/apps/app/src/app/layout.tsx b/apps/app/src/app/layout.tsx deleted file mode 100644 index 2d7df503..00000000 --- a/apps/app/src/app/layout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { Metadata } from "next"; -import { GeistSans } from "geist/font/sans"; -import { GeistMono } from "geist/font/mono"; -import { Toaster } from "sonner"; -import "./globals.css"; -export const metadata: Metadata = { - title: "Automaker - Autonomous AI Development Studio", - description: "Build software autonomously with intelligent orchestration", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - - ); -} diff --git a/apps/app/src/app/page.tsx b/apps/app/src/app/page.tsx deleted file mode 100644 index 29a74578..00000000 --- a/apps/app/src/app/page.tsx +++ /dev/null @@ -1,255 +0,0 @@ -"use client"; - -import { useEffect, useState, useCallback } from "react"; -import { Sidebar } from "@/components/layout/sidebar"; -import { WelcomeView } from "@/components/views/welcome-view"; -import { BoardView } from "@/components/views/board-view"; -import { SpecView } from "@/components/views/spec-view"; -import { AgentView } from "@/components/views/agent-view"; -import { SettingsView } from "@/components/views/settings-view"; -import { InterviewView } from "@/components/views/interview-view"; -import { ContextView } from "@/components/views/context-view"; -import { ProfilesView } from "@/components/views/profiles-view"; -import { SetupView } from "@/components/views/setup-view"; -import { RunningAgentsView } from "@/components/views/running-agents-view"; -import { TerminalView } from "@/components/views/terminal-view"; -import { WikiView } from "@/components/views/wiki-view"; -import { useAppStore } from "@/store/app-store"; -import { useSetupStore } from "@/store/setup-store"; -import { getElectronAPI, isElectron } from "@/lib/electron"; -import { - FileBrowserProvider, - useFileBrowser, - setGlobalFileBrowser, -} from "@/contexts/file-browser-context"; - -function HomeContent() { - const { - currentView, - setCurrentView, - setIpcConnected, - theme, - currentProject, - previewTheme, - getEffectiveTheme, - } = useAppStore(); - const { isFirstRun, setupComplete } = useSetupStore(); - const [isMounted, setIsMounted] = useState(false); - const [streamerPanelOpen, setStreamerPanelOpen] = useState(false); - const { openFileBrowser } = useFileBrowser(); - - // Hidden streamer panel - opens with "\" key - const handleStreamerPanelShortcut = useCallback((event: KeyboardEvent) => { - // Don't trigger when typing in inputs - const activeElement = document.activeElement; - if (activeElement) { - const tagName = activeElement.tagName.toLowerCase(); - if ( - tagName === "input" || - tagName === "textarea" || - tagName === "select" - ) { - return; - } - if (activeElement.getAttribute("contenteditable") === "true") { - return; - } - const role = activeElement.getAttribute("role"); - if (role === "textbox" || role === "searchbox" || role === "combobox") { - return; - } - } - - // Don't trigger with modifier keys - if (event.ctrlKey || event.altKey || event.metaKey) { - return; - } - - // Check for "\" key (backslash) - if (event.key === "\\") { - event.preventDefault(); - setStreamerPanelOpen((prev) => !prev); - } - }, []); - - // Register the "\" shortcut for streamer panel - useEffect(() => { - window.addEventListener("keydown", handleStreamerPanelShortcut); - return () => { - window.removeEventListener("keydown", handleStreamerPanelShortcut); - }; - }, [handleStreamerPanelShortcut]); - - // Compute the effective theme: previewTheme takes priority, then project theme, then global theme - // This is reactive because it depends on previewTheme, currentProject, and theme from the store - const effectiveTheme = getEffectiveTheme(); - - // Prevent hydration issues - useEffect(() => { - setIsMounted(true); - }, []); - - // Initialize global file browser for HttpApiClient - useEffect(() => { - setGlobalFileBrowser(openFileBrowser); - }, [openFileBrowser]); - - // Check if this is first run and redirect to setup if needed - useEffect(() => { - console.log("[Setup Flow] Checking setup state:", { - isMounted, - isFirstRun, - setupComplete, - currentView, - shouldShowSetup: isMounted && isFirstRun && !setupComplete, - }); - - if (isMounted && isFirstRun && !setupComplete) { - console.log( - "[Setup Flow] Redirecting to setup wizard (first run, not complete)" - ); - setCurrentView("setup"); - } else if (isMounted && setupComplete) { - console.log("[Setup Flow] Setup already complete, showing normal view"); - } - }, [isMounted, isFirstRun, setupComplete, setCurrentView, currentView]); - - // Test IPC connection on mount - useEffect(() => { - const testConnection = async () => { - try { - const api = getElectronAPI(); - const result = await api.ping(); - setIpcConnected(result === "pong"); - } catch (error) { - console.error("IPC connection failed:", error); - setIpcConnected(false); - } - }; - - testConnection(); - }, [setIpcConnected]); - - // Apply theme class to document (uses effective theme - preview, project-specific, or global) - useEffect(() => { - const root = document.documentElement; - root.classList.remove( - "dark", - "retro", - "light", - "dracula", - "nord", - "monokai", - "tokyonight", - "solarized", - "gruvbox", - "catppuccin", - "onedark", - "synthwave", - "red" - ); - - if (effectiveTheme === "dark") { - root.classList.add("dark"); - } else if (effectiveTheme === "retro") { - root.classList.add("retro"); - } else if (effectiveTheme === "dracula") { - root.classList.add("dracula"); - } else if (effectiveTheme === "nord") { - root.classList.add("nord"); - } else if (effectiveTheme === "monokai") { - root.classList.add("monokai"); - } else if (effectiveTheme === "tokyonight") { - root.classList.add("tokyonight"); - } else if (effectiveTheme === "solarized") { - root.classList.add("solarized"); - } else if (effectiveTheme === "gruvbox") { - root.classList.add("gruvbox"); - } else if (effectiveTheme === "catppuccin") { - root.classList.add("catppuccin"); - } else if (effectiveTheme === "onedark") { - root.classList.add("onedark"); - } else if (effectiveTheme === "synthwave") { - root.classList.add("synthwave"); - } else if (effectiveTheme === "red") { - root.classList.add("red"); - } else if (effectiveTheme === "light") { - root.classList.add("light"); - } else if (effectiveTheme === "system") { - // System theme - const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches; - if (isDark) { - root.classList.add("dark"); - } else { - root.classList.add("light"); - } - } - }, [effectiveTheme, previewTheme, currentProject, theme]); - - const renderView = () => { - switch (currentView) { - case "welcome": - return ; - case "setup": - return ; - case "board": - return ; - case "spec": - return ; - case "agent": - return ; - case "settings": - return ; - case "interview": - return ; - case "context": - return ; - case "profiles": - return ; - case "running-agents": - return ; - case "terminal": - return ; - case "wiki": - return ; - default: - return ; - } - }; - - // Setup view is full-screen without sidebar - if (currentView === "setup") { - return ( -
- -
- ); - } - - return ( -
- -
- {renderView()} -
- - {/* Hidden streamer panel - opens with "\" key, pushes content */} -
-
- ); -} - -export default function Home() { - return ( - - - - ); -} diff --git a/apps/app/tsconfig.json b/apps/app/tsconfig.json deleted file mode 100644 index cf9c65d3..00000000 --- a/apps/app/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - "**/*.mts" - ], - "exclude": ["node_modules"] -} diff --git a/apps/app/.gitignore b/apps/ui/.gitignore similarity index 86% rename from apps/app/.gitignore rename to apps/ui/.gitignore index cb9812cb..7ea8a360 100644 --- a/apps/app/.gitignore +++ b/apps/ui/.gitignore @@ -13,12 +13,9 @@ # testing /coverage -# next.js -/.next/ -/out/ - -# production -/build +# Vite +/dist/ +/dist-electron/ # misc .DS_Store @@ -33,12 +30,8 @@ yarn-error.log* # env files (can opt-in for committing if needed) .env* -# vercel -.vercel - # typescript *.tsbuildinfo -next-env.d.ts # Playwright /test-results/ @@ -47,5 +40,8 @@ next-env.d.ts /playwright/.cache/ # Electron -/dist/ +/release/ /server-bundle/ + +# TanStack Router generated +src/routeTree.gen.ts diff --git a/apps/app/components.json b/apps/ui/components.json similarity index 100% rename from apps/app/components.json rename to apps/ui/components.json diff --git a/apps/app/docs/AGENT_ARCHITECTURE.md b/apps/ui/docs/AGENT_ARCHITECTURE.md similarity index 100% rename from apps/app/docs/AGENT_ARCHITECTURE.md rename to apps/ui/docs/AGENT_ARCHITECTURE.md diff --git a/apps/app/docs/SESSION_MANAGEMENT.md b/apps/ui/docs/SESSION_MANAGEMENT.md similarity index 100% rename from apps/app/docs/SESSION_MANAGEMENT.md rename to apps/ui/docs/SESSION_MANAGEMENT.md diff --git a/apps/ui/eslint.config.mjs b/apps/ui/eslint.config.mjs new file mode 100644 index 00000000..150f0bad --- /dev/null +++ b/apps/ui/eslint.config.mjs @@ -0,0 +1,36 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import js from "@eslint/js"; +import ts from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; + +const eslintConfig = defineConfig([ + js.configs.recommended, + { + files: ["**/*.ts", "**/*.tsx"], + languageOptions: { + parser: tsParser, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + }, + plugins: { + "@typescript-eslint": ts, + }, + rules: { + ...ts.configs.recommended.rules, + "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "warn", + }, + }, + globalIgnores([ + "dist/**", + "dist-electron/**", + "node_modules/**", + "server-bundle/**", + "release/**", + "src/routeTree.gen.ts", + ]), +]); + +export default eslintConfig; diff --git a/apps/ui/index.html b/apps/ui/index.html new file mode 100644 index 00000000..02e2e0be --- /dev/null +++ b/apps/ui/index.html @@ -0,0 +1,31 @@ + + + + + Automaker - Autonomous AI Development Studio + + + + + + +
+ + + diff --git a/apps/app/package.json b/apps/ui/package.json similarity index 77% rename from apps/app/package.json rename to apps/ui/package.json index ad9100db..2bb464ed 100644 --- a/apps/app/package.json +++ b/apps/ui/package.json @@ -1,5 +1,5 @@ { - "name": "@automaker/app", + "name": "@automaker/ui", "version": "0.1.0", "description": "An autonomous AI development studio that helps you build software faster using AI-powered agents", "homepage": "https://github.com/AutoMaker-Org/automaker", @@ -13,25 +13,25 @@ }, "private": true, "license": "Unlicense", - "main": "electron/main.js", + "main": "dist-electron/main.js", "scripts": { - "dev": "next dev -p 3007", - "dev:web": "next dev -p 3007", - "dev:electron": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron .\"", - "dev:electron:debug": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && OPEN_DEVTOOLS=true electron .\"", - "build": "next build", - "build:electron": "node scripts/prepare-server.js && next build && electron-builder", - "build:electron:win": "node scripts/prepare-server.js && next build && electron-builder --win", - "build:electron:mac": "node scripts/prepare-server.js && next build && electron-builder --mac", - "build:electron:linux": "node scripts/prepare-server.js && next build && electron-builder --linux", + "dev": "vite", + "dev:web": "vite", + "dev:electron": "vite", + "dev:electron:debug": "cross-env OPEN_DEVTOOLS=true vite", + "build": "vite build", + "build:electron": "node scripts/prepare-server.js && vite build && electron-builder", + "build:electron:win": "node scripts/prepare-server.js && vite build && electron-builder --win", + "build:electron:mac": "node scripts/prepare-server.js && vite build && electron-builder --mac", + "build:electron:linux": "node scripts/prepare-server.js && vite build && electron-builder --linux", "postinstall": "electron-builder install-app-deps", - "start": "next start", + "preview": "vite preview", "lint": "eslint", "pretest": "node scripts/setup-e2e-fixtures.js", "test": "playwright test", "test:headed": "playwright test --headed", - "dev:electron:wsl": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron . --no-sandbox --disable-gpu\"", - "dev:electron:wsl:gpu": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && MESA_D3D12_DEFAULT_ADAPTER_NAME=NVIDIA electron . --no-sandbox --disable-gpu-sandbox\"" + "dev:electron:wsl": "cross-env vite", + "dev:electron:wsl:gpu": "cross-env MESA_D3D12_DEFAULT_ADAPTER_NAME=NVIDIA vite" }, "dependencies": { "@codemirror/lang-xml": "^6.1.0", @@ -50,6 +50,7 @@ "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-query": "^5.90.12", + "@tanstack/react-router": "^1.132.41", "@uiw/react-codemirror": "^4.25.4", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-webgl": "^0.18.0", @@ -60,7 +61,6 @@ "dotenv": "^17.2.3", "geist": "^1.5.1", "lucide-react": "^0.556.0", - "next": "^16.0.10", "react": "19.2.0", "react-dom": "19.2.0", "react-markdown": "^10.1.0", @@ -82,20 +82,26 @@ }, "devDependencies": { "@electron/rebuild": "^4.0.2", + "@eslint/js": "^9.0.0", "@playwright/test": "^1.57.0", - "@tailwindcss/postcss": "^4", + "@tailwindcss/vite": "^4.1.13", + "@tanstack/router-plugin": "^1.132.41", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "concurrently": "^9.2.1", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "@vitejs/plugin-react": "^4.5.2", + "cross-env": "^7.0.3", "electron": "39.2.7", "electron-builder": "^26.0.12", "eslint": "^9", - "eslint-config-next": "16.0.7", "tailwindcss": "^4", "tw-animate-css": "^1.4.0", "typescript": "5.9.3", - "wait-on": "^9.0.3" + "vite": "^6.3.5", + "vite-plugin-electron": "^0.29.0", + "vite-plugin-electron-renderer": "^0.14.6" }, "build": { "appId": "com.automaker.app", @@ -103,11 +109,11 @@ "artifactName": "${productName}-${version}-${arch}.${ext}", "afterPack": "./scripts/rebuild-server-natives.js", "directories": { - "output": "dist" + "output": "release" }, "files": [ - "electron/**/*", - "out/**/*", + "dist/**/*", + "dist-electron/**/*", "public/**/*", "!node_modules/**/*" ], diff --git a/apps/app/playwright.config.ts b/apps/ui/playwright.config.ts similarity index 90% rename from apps/app/playwright.config.ts rename to apps/ui/playwright.config.ts index 26f06499..9ffead44 100644 --- a/apps/app/playwright.config.ts +++ b/apps/ui/playwright.config.ts @@ -1,6 +1,6 @@ import { defineConfig, devices } from "@playwright/test"; -const port = process.env.TEST_PORT || 3007; +const port = process.env.TEST_PORT || 5173; const serverPort = process.env.TEST_SERVER_PORT || 3008; const reuseServer = process.env.TEST_REUSE_SERVER === "true"; const mockAgent = process.env.CI === "true" || process.env.AUTOMAKER_MOCK_AGENT === "true"; @@ -43,15 +43,15 @@ export default defineConfig({ ALLOWED_PROJECT_DIRS: "/Users,/home,/tmp,/var/folders", }, }, - // Frontend Next.js server + // Frontend Vite dev server { - command: `npx next dev -p ${port}`, + command: `npm run dev`, url: `http://localhost:${port}`, reuseExistingServer: true, timeout: 120000, env: { ...process.env, - NEXT_PUBLIC_SKIP_SETUP: "true", + VITE_SKIP_SETUP: "true", }, }, ], diff --git a/apps/app/public/automaker.svg b/apps/ui/public/automaker.svg similarity index 100% rename from apps/app/public/automaker.svg rename to apps/ui/public/automaker.svg diff --git a/apps/app/public/file.svg b/apps/ui/public/file.svg similarity index 100% rename from apps/app/public/file.svg rename to apps/ui/public/file.svg diff --git a/apps/app/public/globe.svg b/apps/ui/public/globe.svg similarity index 100% rename from apps/app/public/globe.svg rename to apps/ui/public/globe.svg diff --git a/apps/app/public/icon.ico b/apps/ui/public/icon.ico similarity index 100% rename from apps/app/public/icon.ico rename to apps/ui/public/icon.ico diff --git a/apps/app/public/logo.png b/apps/ui/public/logo.png similarity index 100% rename from apps/app/public/logo.png rename to apps/ui/public/logo.png diff --git a/apps/app/public/logo_larger.png b/apps/ui/public/logo_larger.png similarity index 100% rename from apps/app/public/logo_larger.png rename to apps/ui/public/logo_larger.png diff --git a/apps/app/public/next.svg b/apps/ui/public/next.svg similarity index 100% rename from apps/app/public/next.svg rename to apps/ui/public/next.svg diff --git a/apps/app/public/readme_logo.png b/apps/ui/public/readme_logo.png similarity index 100% rename from apps/app/public/readme_logo.png rename to apps/ui/public/readme_logo.png diff --git a/apps/app/public/sounds/ding.mp3 b/apps/ui/public/sounds/ding.mp3 similarity index 100% rename from apps/app/public/sounds/ding.mp3 rename to apps/ui/public/sounds/ding.mp3 diff --git a/apps/app/public/vercel.svg b/apps/ui/public/vercel.svg similarity index 100% rename from apps/app/public/vercel.svg rename to apps/ui/public/vercel.svg diff --git a/apps/app/public/window.svg b/apps/ui/public/window.svg similarity index 100% rename from apps/app/public/window.svg rename to apps/ui/public/window.svg diff --git a/apps/app/scripts/prepare-server.js b/apps/ui/scripts/prepare-server.js similarity index 100% rename from apps/app/scripts/prepare-server.js rename to apps/ui/scripts/prepare-server.js diff --git a/apps/app/scripts/rebuild-server-natives.js b/apps/ui/scripts/rebuild-server-natives.js similarity index 100% rename from apps/app/scripts/rebuild-server-natives.js rename to apps/ui/scripts/rebuild-server-natives.js diff --git a/apps/app/scripts/setup-e2e-fixtures.js b/apps/ui/scripts/setup-e2e-fixtures.js similarity index 100% rename from apps/app/scripts/setup-e2e-fixtures.js rename to apps/ui/scripts/setup-e2e-fixtures.js diff --git a/apps/ui/src/App.tsx b/apps/ui/src/App.tsx new file mode 100644 index 00000000..a38bfb42 --- /dev/null +++ b/apps/ui/src/App.tsx @@ -0,0 +1,7 @@ +import { RouterProvider } from "@tanstack/react-router"; +import { router } from "./utils/router"; +import "./styles/global.css"; + +export default function App() { + return ; +} diff --git a/apps/app/src/components/delete-all-archived-sessions-dialog.tsx b/apps/ui/src/components/delete-all-archived-sessions-dialog.tsx similarity index 99% rename from apps/app/src/components/delete-all-archived-sessions-dialog.tsx rename to apps/ui/src/components/delete-all-archived-sessions-dialog.tsx index 34d5907a..66b0bae6 100644 --- a/apps/app/src/components/delete-all-archived-sessions-dialog.tsx +++ b/apps/ui/src/components/delete-all-archived-sessions-dialog.tsx @@ -1,4 +1,3 @@ -"use client"; import { Dialog, diff --git a/apps/app/src/components/delete-session-dialog.tsx b/apps/ui/src/components/delete-session-dialog.tsx similarity index 100% rename from apps/app/src/components/delete-session-dialog.tsx rename to apps/ui/src/components/delete-session-dialog.tsx diff --git a/apps/app/src/components/dialogs/board-background-modal.tsx b/apps/ui/src/components/dialogs/board-background-modal.tsx similarity index 99% rename from apps/app/src/components/dialogs/board-background-modal.tsx rename to apps/ui/src/components/dialogs/board-background-modal.tsx index ad1207eb..bf3ccbd4 100644 --- a/apps/app/src/components/dialogs/board-background-modal.tsx +++ b/apps/ui/src/components/dialogs/board-background-modal.tsx @@ -1,4 +1,3 @@ -"use client"; import { useState, useRef, useCallback, useEffect } from "react"; import { ImageIcon, Upload, Loader2, Trash2 } from "lucide-react"; @@ -72,7 +71,7 @@ export function BoardBackgroundModal({ useEffect(() => { if (currentProject && backgroundSettings.imagePath) { const serverUrl = - process.env.NEXT_PUBLIC_SERVER_URL || "http://localhost:3008"; + import.meta.env.VITE_SERVER_URL || "http://localhost:3008"; // Add cache-busting query parameter to force browser to reload image const cacheBuster = imageVersion ? `&v=${imageVersion}` diff --git a/apps/app/src/components/dialogs/file-browser-dialog.tsx b/apps/ui/src/components/dialogs/file-browser-dialog.tsx similarity index 99% rename from apps/app/src/components/dialogs/file-browser-dialog.tsx rename to apps/ui/src/components/dialogs/file-browser-dialog.tsx index 351534d5..2103b622 100644 --- a/apps/app/src/components/dialogs/file-browser-dialog.tsx +++ b/apps/ui/src/components/dialogs/file-browser-dialog.tsx @@ -1,4 +1,3 @@ -"use client"; import { useState, useEffect, useRef } from "react"; import { @@ -71,7 +70,7 @@ export function FileBrowserDialog({ try { // Get server URL from environment or default const serverUrl = - process.env.NEXT_PUBLIC_SERVER_URL || "http://localhost:3008"; + import.meta.env.VITE_SERVER_URL || "http://localhost:3008"; const response = await fetch(`${serverUrl}/api/fs/browse`, { method: "POST", diff --git a/apps/app/src/components/layout/project-setup-dialog.tsx b/apps/ui/src/components/layout/project-setup-dialog.tsx similarity index 99% rename from apps/app/src/components/layout/project-setup-dialog.tsx rename to apps/ui/src/components/layout/project-setup-dialog.tsx index 82453203..d054cd0c 100644 --- a/apps/app/src/components/layout/project-setup-dialog.tsx +++ b/apps/ui/src/components/layout/project-setup-dialog.tsx @@ -1,4 +1,3 @@ -"use client"; import { Sparkles, Clock } from "lucide-react"; import { diff --git a/apps/app/src/components/layout/sidebar.tsx b/apps/ui/src/components/layout/sidebar.tsx similarity index 98% rename from apps/app/src/components/layout/sidebar.tsx rename to apps/ui/src/components/layout/sidebar.tsx index 6f534db4..0df24d55 100644 --- a/apps/app/src/components/layout/sidebar.tsx +++ b/apps/ui/src/components/layout/sidebar.tsx @@ -1,6 +1,5 @@ -"use client"; - import { useState, useMemo, useEffect, useCallback, useRef } from "react"; +import { useNavigate, useLocation } from "@tanstack/react-router"; import { cn } from "@/lib/utils"; import { useAppStore, formatShortcut, type ThemeMode } from "@/store/app-store"; import { CoursePromoBadge } from "@/components/ui/course-promo-badge"; @@ -223,16 +222,17 @@ const BugReportButton = ({ }; export function Sidebar() { + const navigate = useNavigate(); + const location = useLocation(); + const { projects, trashedProjects, currentProject, - currentView, sidebarOpen, projectHistory, upsertAndSetCurrentProject, setCurrentProject, - setCurrentView, toggleSidebar, restoreTrashedProject, deleteTrashedProject, @@ -251,14 +251,13 @@ export function Sidebar() { } = useAppStore(); // Environment variable flags for hiding sidebar items - // Note: Next.js requires static access to process.env variables (no dynamic keys) - const hideTerminal = process.env.NEXT_PUBLIC_HIDE_TERMINAL === "true"; - const hideWiki = process.env.NEXT_PUBLIC_HIDE_WIKI === "true"; + const hideTerminal = import.meta.env.VITE_HIDE_TERMINAL === "true"; + const hideWiki = import.meta.env.VITE_HIDE_WIKI === "true"; const hideRunningAgents = - process.env.NEXT_PUBLIC_HIDE_RUNNING_AGENTS === "true"; - const hideContext = process.env.NEXT_PUBLIC_HIDE_CONTEXT === "true"; - const hideSpecEditor = process.env.NEXT_PUBLIC_HIDE_SPEC_EDITOR === "true"; - const hideAiProfiles = process.env.NEXT_PUBLIC_HIDE_AI_PROFILES === "true"; + import.meta.env.VITE_HIDE_RUNNING_AGENTS === "true"; + const hideContext = import.meta.env.VITE_HIDE_CONTEXT === "true"; + const hideSpecEditor = import.meta.env.VITE_HIDE_SPEC_EDITOR === "true"; + const hideAiProfiles = import.meta.env.VITE_HIDE_AI_PROFILES === "true"; // Get customizable keyboard shortcuts const shortcuts = useKeyboardShortcutsConfig(); @@ -429,7 +428,6 @@ export function Sidebar() { unsubscribe(); }; }, [ - setCurrentView, creatingSpecProjectPath, setupProjectPath, setSpecCreatingForProject, @@ -1177,7 +1175,7 @@ export function Sidebar() { if (item.shortcut) { shortcutsList.push({ key: item.shortcut, - action: () => setCurrentView(item.id as any), + action: () => navigate({ to: `/${item.id}` as const }), description: `Navigate to ${item.label}`, }); } @@ -1187,7 +1185,7 @@ export function Sidebar() { // Add settings shortcut shortcutsList.push({ key: shortcuts.settings, - action: () => setCurrentView("settings"), + action: () => navigate({ to: "/settings" }), description: "Navigate to Settings", }); } @@ -1196,7 +1194,7 @@ export function Sidebar() { }, [ shortcuts, currentProject, - setCurrentView, + navigate, toggleSidebar, projects.length, handleOpenFolder, @@ -1210,7 +1208,9 @@ export function Sidebar() { useKeyboardShortcuts(navigationShortcuts); const isActiveRoute = (id: string) => { - return currentView === id; + // Map view IDs to route paths + const routePath = id === "welcome" ? "/" : `/${id}`; + return location.pathname === routePath; }; return ( @@ -1289,7 +1289,7 @@ export function Sidebar() { "flex items-center gap-3 titlebar-no-drag cursor-pointer group", !sidebarOpen && "flex-col gap-1" )} - onClick={() => setCurrentView("welcome")} + onClick={() => navigate({ to: "/" })} data-testid="logo-button" > {!sidebarOpen ? ( @@ -1847,7 +1847,7 @@ export function Sidebar() { return (