From 4bc31a32e2e66ddf4d7fe08f97592a726670fb3a Mon Sep 17 00:00:00 2001 From: MrPiglr Date: Tue, 27 Jan 2026 06:16:41 +0000 Subject: [PATCH] modified: app/App.tsx --- .gitignore | 70 +- PROJECT_BACKUP.md | 7404 ++++++++ README.md | 22 +- aethex-studio-mockup.html | 701 + app/App.tsx | 25 +- app/layout.tsx | 2 + app/page.tsx | 18 +- app/studio-theme.css | 865 + apphosting.yaml | 7 + components.json | 8 +- components/FileTree.tsx | 25 +- components/NexusSyncMonitor.tsx | 2 +- components/StudioBottomPanel.tsx | 4 + components/StudioEditor.tsx | 51 + components/StudioLayout.tsx | 81 + components/StudioNetworkViz.tsx | 29 + components/StudioRightPanel.tsx | 26 + components/StudioSidebar.tsx | 75 + next-env.d.ts | 3 +- next.config.js | 2 +- next.config.ts | 35 + package-lock.json | 15611 ++++++++++------ package.json | 117 +- src/App.tsx | 695 +- src/ErrorFallback.tsx | 7 +- src/ai/dev.ts | 6 + src/ai/flows/ai-help-from-prompt.ts | 129 + .../ai-suggested-sync-conflict-resolution.ts | 120 + src/ai/flows/contextual-code-suggestions.ts | 111 + src/ai/genkit.ts | 7 + src/app/dashboard/page.tsx | 5 + src/app/globals.css | 23 + src/app/ide/page.tsx | 9 + src/app/layout.tsx | 35 + src/app/page.tsx | 5 + src/components/AIChat.tsx | 2 +- src/components/CodeEditor.tsx | 4 +- src/components/CommandPalette.tsx | 1 + src/components/ConsolePanel.tsx | 2 +- src/components/EducationPanel.tsx | 2 +- src/components/FileTree.tsx | 82 +- src/components/InteractiveTerminal.tsx | 34 +- src/components/NewProjectModal.tsx | 1 + src/components/PassportLogin.tsx | 3 +- src/components/PlatformSelector.tsx | 30 +- src/components/PreviewModal.tsx | 5 +- src/components/SearchInFilesPanel.tsx | 4 +- src/components/TemplatesDrawer.tsx | 16 +- src/components/ThemeSwitcher.tsx | 13 +- src/components/Toolbar.tsx | 2 +- src/components/TranslationPanel.tsx | 24 +- src/components/WelcomeDialog.tsx | 2 +- src/components/aethex/aethex-studio.tsx | 109 + src/components/aethex/ai-assistant.tsx | 40 + src/components/aethex/ai-chat.tsx | 37 + src/components/aethex/asset-library-panel.tsx | 21 + src/components/aethex/bottom-panel.tsx | 62 + src/components/aethex/certification-panel.tsx | 21 + src/components/aethex/checkbox.tsx | 20 + src/components/aethex/code-editor.tsx | 82 + src/components/aethex/console-panel.tsx | 20 + .../aethex/cross-platform-preview.tsx | 16 + src/components/aethex/cross-platform-view.tsx | 369 + src/components/aethex/dashboard-page.tsx | 115 + src/components/aethex/desktop-app-panel.tsx | 22 + src/components/aethex/education-panel.tsx | 22 + .../aethex/enterprise-analytics-panel.tsx | 20 + src/components/aethex/file-navigator.tsx | 24 + src/components/aethex/file-tabs.tsx | 5 + src/components/aethex/file-tree.tsx | 5 + src/components/aethex/game-preview-panel.tsx | 14 + src/components/aethex/icons.tsx | 90 + src/components/aethex/input.tsx | 19 + src/components/aethex/login-page.tsx | 69 + src/components/aethex/new-project-modal.tsx | 24 + src/components/aethex/nexus-sync-monitor.tsx | 16 + src/components/aethex/onboarding-dialog.tsx | 15 + src/components/aethex/passport-login.tsx | 15 + src/components/aethex/preview-modal.tsx | 16 + src/components/aethex/progress.tsx | 12 + src/components/aethex/spatial-panel.tsx | 14 + src/components/aethex/switch.tsx | 19 + src/components/aethex/tabs.tsx | 23 + src/components/aethex/teacher-dashboard.tsx | 22 + src/components/aethex/team-collab-panel.tsx | 22 + src/components/aethex/templates-drawer.tsx | 22 + src/components/aethex/textarea.tsx | 20 + src/components/aethex/translation-panel.tsx | 21 + src/components/aethex/uefn-panel.tsx | 21 + src/components/aethex/user-profile.tsx | 15 + src/components/aethex/welcome-dialog.tsx | 15 + .../aethex/workspace-card-skeleton.tsx | 12 + src/components/aethex/workspace-card.tsx | 27 + src/components/ui/alert.tsx | 2 +- src/components/ui/button.tsx | 2 +- src/components/ui/card.tsx | 2 +- src/components/ui/chart.tsx | 43 +- src/components/ui/context-menu.tsx | 102 +- src/components/ui/tabs-extra.tsx | 7 +- src/components/ui/tabs.tsx | 4 +- src/components/ui/tooltip.tsx | 4 +- src/lib/aethex-data.ts | 127 + src/lib/placeholder-images.ts | 17 + src/lib/templates.ts | 6 - src/lib/workspaces.ts | 26 + src/types/lucide-react.d.ts | 36 + src/types/radix-ui-context-menu.d.ts | 17 + src/types/radix-ui.d.ts | 3 + store/editor-zustand.ts | 56 + tsconfig.json | 1 + 110 files changed, 21551 insertions(+), 7019 deletions(-) create mode 100644 PROJECT_BACKUP.md create mode 100644 aethex-studio-mockup.html create mode 100644 app/studio-theme.css create mode 100644 apphosting.yaml create mode 100644 components/StudioBottomPanel.tsx create mode 100644 components/StudioEditor.tsx create mode 100644 components/StudioLayout.tsx create mode 100644 components/StudioNetworkViz.tsx create mode 100644 components/StudioRightPanel.tsx create mode 100644 components/StudioSidebar.tsx create mode 100644 next.config.ts create mode 100644 src/ai/dev.ts create mode 100644 src/ai/flows/ai-help-from-prompt.ts create mode 100644 src/ai/flows/ai-suggested-sync-conflict-resolution.ts create mode 100644 src/ai/flows/contextual-code-suggestions.ts create mode 100644 src/ai/genkit.ts create mode 100644 src/app/dashboard/page.tsx create mode 100644 src/app/globals.css create mode 100644 src/app/ide/page.tsx create mode 100644 src/app/layout.tsx create mode 100644 src/app/page.tsx create mode 100644 src/components/aethex/aethex-studio.tsx create mode 100644 src/components/aethex/ai-assistant.tsx create mode 100644 src/components/aethex/ai-chat.tsx create mode 100644 src/components/aethex/asset-library-panel.tsx create mode 100644 src/components/aethex/bottom-panel.tsx create mode 100644 src/components/aethex/certification-panel.tsx create mode 100644 src/components/aethex/checkbox.tsx create mode 100644 src/components/aethex/code-editor.tsx create mode 100644 src/components/aethex/console-panel.tsx create mode 100644 src/components/aethex/cross-platform-preview.tsx create mode 100644 src/components/aethex/cross-platform-view.tsx create mode 100644 src/components/aethex/dashboard-page.tsx create mode 100644 src/components/aethex/desktop-app-panel.tsx create mode 100644 src/components/aethex/education-panel.tsx create mode 100644 src/components/aethex/enterprise-analytics-panel.tsx create mode 100644 src/components/aethex/file-navigator.tsx create mode 100644 src/components/aethex/file-tabs.tsx create mode 100644 src/components/aethex/file-tree.tsx create mode 100644 src/components/aethex/game-preview-panel.tsx create mode 100644 src/components/aethex/icons.tsx create mode 100644 src/components/aethex/input.tsx create mode 100644 src/components/aethex/login-page.tsx create mode 100644 src/components/aethex/new-project-modal.tsx create mode 100644 src/components/aethex/nexus-sync-monitor.tsx create mode 100644 src/components/aethex/onboarding-dialog.tsx create mode 100644 src/components/aethex/passport-login.tsx create mode 100644 src/components/aethex/preview-modal.tsx create mode 100644 src/components/aethex/progress.tsx create mode 100644 src/components/aethex/spatial-panel.tsx create mode 100644 src/components/aethex/switch.tsx create mode 100644 src/components/aethex/tabs.tsx create mode 100644 src/components/aethex/teacher-dashboard.tsx create mode 100644 src/components/aethex/team-collab-panel.tsx create mode 100644 src/components/aethex/templates-drawer.tsx create mode 100644 src/components/aethex/textarea.tsx create mode 100644 src/components/aethex/translation-panel.tsx create mode 100644 src/components/aethex/uefn-panel.tsx create mode 100644 src/components/aethex/user-profile.tsx create mode 100644 src/components/aethex/welcome-dialog.tsx create mode 100644 src/components/aethex/workspace-card-skeleton.tsx create mode 100644 src/components/aethex/workspace-card.tsx create mode 100644 src/lib/aethex-data.ts create mode 100644 src/lib/placeholder-images.ts create mode 100644 src/lib/workspaces.ts create mode 100644 src/types/lucide-react.d.ts create mode 100644 src/types/radix-ui-context-menu.d.ts create mode 100644 src/types/radix-ui.d.ts create mode 100644 store/editor-zustand.ts diff --git a/.gitignore b/.gitignore index 85cab76..02de707 100644 --- a/.gitignore +++ b/.gitignore @@ -7,11 +7,62 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* -node_modules -dist -dist-ssr -*-dist -*.local +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + + +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# archives +*.zip # Next.js .next @@ -35,3 +86,12 @@ pids .devcontainer/ .spark-workbench-id + +.env +**/agent-eval-report* +packages +pids +.file-manifest +.devcontainer/ + +.spark-workbench-id diff --git a/PROJECT_BACKUP.md b/PROJECT_BACKUP.md new file mode 100644 index 0000000..36e72b7 --- /dev/null +++ b/PROJECT_BACKUP.md @@ -0,0 +1,7404 @@ +# Project Backup + +This file contains a full backup of all your project files. You can copy the contents of this file to your local machine to recreate the project. + +--- + +## FILE: .env + +``` + +``` + +--- + +## FILE: .gitignore + +``` +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# archives +*.zip +``` + +--- + +## FILE: README.md + +```md +# Firebase Studio + +This is a NextJS starter in Firebase Studio. + +To get started, take a look at src/app/page.tsx. +``` + +--- + +## FILE: apphosting.yaml + +```yaml +# Settings to manage and configure a Firebase App Hosting backend. +# https://firebase.google.com/docs/app-hosting/configure + +runConfig: + # Increase this value if you'd like to automatically spin up + # more instances in response to increased traffic. + maxInstances: 1 +``` + +--- + +## FILE: components.json + +```json +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} +``` + +--- + +## FILE: next-env.d.ts + +```ts +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +``` + +--- + +## FILE: next.config.ts + +```ts +import type {NextConfig} from 'next'; + +const nextConfig: NextConfig = { + /* config options here */ + typescript: { + ignoreBuildErrors: true, + }, + eslint: { + ignoreDuringBuilds: true, + }, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'placehold.co', + port: '', + pathname: '/**', + }, + { + protocol: 'https', + hostname: 'images.unsplash.com', + port: '', + pathname: '/**', + }, + { + protocol: 'https', + hostname: 'picsum.photos', + port: '', + pathname: '/**', + }, + ], + }, +}; + +export default nextConfig; +``` + +--- + +## FILE: package.json + +```json +{ + "name": "nextn", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack -p 9002", + "genkit:dev": "genkit start -- tsx src/ai/dev.ts", + "genkit:watch": "genkit start -- tsx --watch src/ai/dev.ts", + "build": "NODE_ENV=production next build", + "start": "next start", + "lint": "next lint", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@genkit-ai/google-genai": "^1.20.0", + "@genkit-ai/next": "^1.20.0", + "@hookform/resolvers": "^4.1.3", + "@radix-ui/react-accordion": "^1.2.3", + "@radix-ui/react-alert-dialog": "^1.1.6", + "@radix-ui/react-avatar": "^1.1.3", + "@radix-ui/react-checkbox": "^1.1.4", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-menubar": "^1.1.6", + "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-radio-group": "^1.2.3", + "@radix-ui/react-scroll-area": "^1.2.3", + "@radix-ui/react-select": "^2.1.6", + "@radix-ui/react-separator": "^1.1.2", + "@radix-ui/react-slider": "^1.2.3", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.1.3", + "@radix-ui/react-tabs": "^1.1.3", + "@radix-ui/react-toast": "^1.2.6", + "@radix-ui/react-tooltip": "^1.1.8", + "@tailwindcss/typography": "^0.5.13", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "date-fns": "^3.6.0", + "dotenv": "^16.5.0", + "embla-carousel-react": "^8.6.0", + "firebase": "^11.9.1", + "genkit": "^1.20.0", + "lucide-react": "^0.475.0", + "marked": "^12.0.2", + "next": "15.5.9", + "patch-package": "^8.0.0", + "react": "^19.2.1", + "react-day-picker": "^9.11.3", + "react-dom": "^19.2.1", + "react-hook-form": "^7.54.2", + "react-syntax-highlighter": "^15.5.0", + "recharts": "^2.15.1", + "tailwind-merge": "^3.0.1", + "tailwindcss-animate": "^1.0.7", + "zod": "^3.24.2" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^19.2.1", + "@types/react-dom": "^19.2.1", + "@types/react-syntax-highlighter": "^15.5.13", + "genkit-cli": "^1.20.0", + "postcss": "^8", + "tailwindcss": "^3.4.1", + "typescript": "^5" + } +} +``` + +--- + +## FILE: src/ai/dev.ts + +```ts +import { config } from 'dotenv'; +config(); + +import '@/ai/flows/ai-suggested-sync-conflict-resolution.ts'; +import '@/ai/flows/contextual-code-suggestions.ts'; +import '@/ai/flows/ai-help-from-prompt.ts'; +``` + +--- + +## FILE: src/ai/flows/ai-help-from-prompt.ts + +```ts +'use server'; + +/** + * @fileOverview This file defines a Genkit flow that helps new users by suggesting an initial set of code files + * and project structure based on a simple prompt describing the desired application. + * + * - aiHelpFromPrompt - A function that takes a prompt and returns suggested code files and project structure. + * - AIHelpFromPromptInput - The input type for the aiHelpFromPrompt function. + * - AIHelpFromPromptOutput - The return type for the aiHelpFromPrompt function. + */ + +import {ai} from '@/ai/genkit'; +import {z} from 'genkit'; + +const AIHelpFromPromptInputSchema = z.object({ + prompt: z.string().describe('A prompt describing the type of application to build.'), +}); +export type AIHelpFromPromptInput = z.infer; + +const AIHelpFromPromptOutputSchema = z.object({ + suggestedFiles: z.array(z.object({ + filePath: z.string().describe('The path for the suggested file.'), + fileContent: z.string().describe('The content of the suggested file.'), + })).describe('An array of suggested code files and their content.'), + explanation: z.string().describe('An explanation of the suggested file structure and code.'), +}); +export type AIHelpFromPromptOutput = z.infer; + +export async function aiHelpFromPrompt(input: AIHelpFromPromptInput): Promise { + return aiHelpFromPromptFlow(input); +} + +const prompt = ai.definePrompt({ + name: 'aiHelpFromPromptPrompt', + input: {schema: AIHelpFromPromptInputSchema}, + output: {schema: AIHelpFromPromptOutputSchema}, + prompt: `You are an AI assistant designed to help new users quickly start developing applications. + + Based on the user's prompt describing the desired application, suggest an initial set of code files and a project structure to get them started. + + Provide the suggested files as an array of objects, each containing the file path and the file content. + Explain the suggested file structure and the code in detail so that the user understands the purpose of each file and how they fit together. + + User Prompt: {{{prompt}}} + + Example Output: + { + "suggestedFiles": [ + { + "filePath": "src/components/MyComponent.tsx", + "fileContent": "// MyComponent.tsx\nimport React from 'react';\n\nconst MyComponent = () => {\n return (\n
\n

Hello, world!

\n
\n );\n};\n\nexport default MyComponent;" + }, + { + "filePath": "src/pages/index.tsx", + "fileContent": "// index.tsx\nimport MyComponent from '../components/MyComponent';\n\nconst Home = () => {\n return (\n
\n \n
\n );\n};\n\nexport default Home;" + } + ], + "explanation": "This project structure includes a component (MyComponent.tsx) and a page (index.tsx) that uses the component. This is a basic structure for a React application." + } + `, +}); + +const aiHelpFromPromptFlow = ai.defineFlow( + { + name: 'aiHelpFromPromptFlow', + inputSchema: AIHelpFromPromptInputSchema, + outputSchema: AIHelpFromPromptOutputSchema, + }, + async input => { + const {output} = await prompt(input, { + config: { + safetySettings: [ + { + category: 'HARM_CATEGORY_HATE_SPEECH', + threshold: 'BLOCK_ONLY_HIGH', + }, + { + category: 'HARM_CATEGORY_DANGEROUS_CONTENT', + threshold: 'BLOCK_NONE', + }, + { + category: 'HARM_CATEGORY_HARASSMENT', + threshold: 'BLOCK_MEDIUM_AND_ABOVE', + }, + { + category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + ], + }, + }); + return output!; + } +); + + +``` + +--- + +## FILE: src/ai/flows/ai-suggested-sync-conflict-resolution.ts + +```ts +'use server'; + +/** + * @fileOverview An AI agent that detects synchronization conflicts between platform-specific code and data, + * and suggests solutions to resolve them. + * + * - aiSuggestedSyncConflictResolution - A function that handles the conflict resolution process. + * - AISuggestedSyncConflictResolutionInput - The input type for the aiSuggestedSyncConflictResolution function. + * - AISuggestedSyncConflictResolutionOutput - The return type for the aiSuggestedSyncConflictResolution function. + */ + +import {ai} from '@/ai/genkit'; +import {z} from 'genkit'; + +const AISuggestedSyncConflictResolutionInputSchema = z.object({ + robloxCode: z.string().describe('The Lua code for the Roblox platform.'), + webCode: z.string().describe('The JavaScript code for the web platform.'), + mobileCode: z.string().describe('The React Native code for the mobile platform.'), + sharedState: z.string().describe('The shared state data in JSON format.'), +}); +export type AISuggestedSyncConflictResolutionInput = z.infer; + +const AISuggestedSyncConflictResolutionOutputSchema = z.object({ + conflictDetected: z.boolean().describe('Whether a synchronization conflict was detected.'), + suggestedSolutions: z.array(z.string()).describe('An array of suggested solutions to resolve the conflicts.'), + explanation: z.string().describe('Explanation of the detected conflicts and suggested solutions.'), +}); +export type AISuggestedSyncConflictResolutionOutput = z.infer; + +export async function aiSuggestedSyncConflictResolution(input: AISuggestedSyncConflictResolutionInput): Promise { + return aiSuggestedSyncConflictResolutionFlow(input); +} + +const prompt = ai.definePrompt({ + name: 'aiSuggestedSyncConflictResolutionPrompt', + input: {schema: AISuggestedSyncConflictResolutionInputSchema}, + output: {schema: AISuggestedSyncConflictResolutionOutputSchema}, + prompt: `You are an AI assistant specialized in detecting synchronization conflicts between different platform codebases and suggesting solutions. + +You are given the code for Roblox (Lua), Web (JavaScript), and Mobile (React Native), as well as the shared state data in JSON format. Analyze the code and the shared state to identify any inconsistencies or conflicts. + +Based on your analysis, determine if there are any conflicts, and suggest solutions to resolve them. Explain the conflicts and the suggested solutions in detail. + +Roblox Code: +{{robloxCode}} + +Web Code: +{{webCode}} + +Mobile Code: +{{mobileCode}} + +Shared State: +{{sharedState}}`, +}); + +const aiSuggestedSyncConflictResolutionFlow = ai.defineFlow( + { + name: 'aiSuggestedSyncConflictResolutionFlow', + inputSchema: AISuggestedSyncConflictResolutionInputSchema, + outputSchema: AISuggestedSyncConflictResolutionOutputSchema, + }, + async input => { + const {output} = await prompt(input, { + config: { + safetySettings: [ + { + category: 'HARM_CATEGORY_HATE_SPEECH', + threshold: 'BLOCK_ONLY_HIGH', + }, + { + category: 'HARM_CATEGORY_DANGEROUS_CONTENT', + threshold: 'BLOCK_NONE', + }, + { + category: 'HARM_CATEGORY_HARASSMENT', + threshold: 'BLOCK_MEDIUM_AND_ABOVE', + }, + { + category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', + threshold: 'BLOCK_LOW_AND_ABOVE', + }, + ], + }, + }); + return output!; + } +); + + +``` + +--- + +## FILE: src/ai/flows/contextual-code-suggestions.ts + +```ts +'use server'; +/** + * @fileOverview This file defines a Genkit flow for providing contextual code suggestions. + * + * - contextualCodeSuggestions - A function that takes the current file content and cursor position + * and returns code suggestions. + * - ContextualCodeSuggestionsInput - The input type for the contextualCodeSuggestions function. + * - ContextualCodeSuggestionsOutput - The return type for the contextualCodeSuggestions function. + */ + +import {ai} from '@/ai/genkit'; +import {z} from 'genkit'; + +const ContextualCodeSuggestionsInputSchema = z.object({ + fileContent: z.string().describe('The content of the currently open file.'), + cursorPosition: z.number().describe('The cursor position within the file.'), + language: z.string().describe('The programming language of the file.'), + context: z.string().optional().describe('Additional context for code suggestions, e.g., error messages or related code snippets.'), +}); +export type ContextualCodeSuggestionsInput = z.infer< + typeof ContextualCodeSuggestionsInputSchema +>; + +const ContextualCodeSuggestionsOutputSchema = z.object({ + suggestions: z + .array(z.string()) + .describe('An array of code suggestions based on the context.'), +}); +export type ContextualCodeSuggestionsOutput = z.infer< + typeof ContextualCodeSuggestionsOutputSchema +>; + +export async function contextualCodeSuggestions( + input: ContextualCodeSuggestionsInput +): Promise { + return contextualCodeSuggestionsFlow(input); +} + +const prompt = ai.definePrompt({ + name: 'contextualCodeSuggestionsPrompt', + input: {schema: ContextualCodeSuggestionsInputSchema}, + output: {schema: ContextualCodeSuggestionsOutputSchema}, + prompt: `You are an AI assistant that provides code suggestions and autocompletions based on the context of the currently open file and cursor position. + + Given the following file content, cursor position, programming language, and any available context, provide a list of code suggestions that would be helpful to the developer. + + File Content: + {{fileContent}} + + Cursor Position: {{cursorPosition}} + + Programming Language: {{language}} + + Context: {{context}} + + Suggestions should be relevant to the current context, incorporate best practices, and avoid common mistakes. Return the suggestions as an array of strings. + + Example: + [ + "console.log('Hello, world!');", + "// Add a comment to explain the code", + "function myFunction() {\n // Function body\n }", + ]`, +}); + +const contextualCodeSuggestionsFlow = ai.defineFlow( + { + name: 'contextualCodeSuggestionsFlow', + inputSchema: ContextualCodeSuggestionsInputSchema, + outputSchema: ContextualCodeSuggestionsOutputSchema, + }, + async input => { + const {output} = await prompt(input); + return output!; + } +); + +``` + +--- + +## FILE: src/ai/genkit.ts + +```ts +import {genkit} from 'genkit'; +import {googleAI} from '@genkit-ai/google-genai'; + +export const ai = genkit({ + plugins: [googleAI()], + model: 'googleai/gemini-2.5-flash', +}); + +``` + +--- + +## FILE: src/app/dashboard/page.tsx + +```tsx +import { DashboardPage } from "@/components/aethex/dashboard-page"; + +export default function Page() { + return ; +} + +``` + +--- + +## FILE: src/app/globals.css + +```css +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 278 52% 49%; + --primary-foreground: 0 0% 98%; + --secondary: 277 100% 25%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 180 100% 25%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 278 52% 49%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + } + .dark { + --background: 0 0% 13.3%; + --foreground: 0 0% 98%; + --card: 0 0% 20%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 13.3%; + --popover-foreground: 0 0% 98%; + --primary: 278 52% 49%; + --primary-foreground: 0 0% 98%; + --secondary: 277 100% 25%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 20%; + --muted-foreground: 0 0% 63.9%; + --accent: 180 100% 25%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 25%; + --input: 0 0% 25%; + --ring: 278 52% 49%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +``` + +--- + +## FILE: src/app/ide/page.tsx + +```tsx +import { AethexStudio } from "@/components/aethex/aethex-studio"; + +export default function IdePage() { + return ( +
+ +
+ ); +} + +``` + +--- + +## FILE: src/app/layout.tsx + +```tsx +import type { Metadata } from "next"; +import { Toaster } from "@/components/ui/toaster"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "AeThex Studio", + description: "The Next-Generation Cross-Platform IDE", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + + + + {children} + + + + ); +} + +``` + +--- + +## FILE: src/app/page.tsx + +```tsx +import { LoginPage } from "@/components/aethex/login-page"; + +export default function Page() { + return ; +} + +``` + +--- + +## FILE: src/components/aethex/aethex-studio.tsx + +```tsx +"use client"; + +import { useState } from "react"; +import { + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from "@/components/ui/resizable"; +import { Navbar } from "./navbar"; +import { FileNavigator } from "./file-navigator"; +import { MainView } from "./main-view"; +import { BottomPanel } from "./bottom-panel"; +import { AiAssistant } from "./ai-assistant"; +import { + openFiles as initialOpenFiles, + fileTree as initialFileTree, + File as OpenFileType, + FolderNode, + FileNode, +} from "@/lib/aethex-data"; +import { NewProjectModal } from "./new-project-modal"; +import { + ProjectTemplate, + generateFileContent, +} from "@/lib/templates"; +import type { NewProjectFormValues } from "./new-project-modal"; + +export type { OpenFileType }; + +export function AethexStudio() { + const [openFiles, setOpenFiles] = useState(initialOpenFiles); + const [activeTab, setActiveTab] = useState(openFiles[0]?.id || ""); + const [fileTree, setFileTree] = useState(initialFileTree); + const [isNewProjectModalOpen, setIsNewProjectModalOpen] = useState(false); + + const handleOpenFile = (file: OpenFileType) => { + if (!openFiles.find((f) => f.id === file.id)) { + setOpenFiles((prev) => [...prev, file]); + } + setActiveTab(file.id); + }; + + const handleCloseFile = (fileId: string) => { + const newOpenFiles = openFiles.filter((file) => file.id !== fileId); + setOpenFiles(newOpenFiles); + + if (activeTab === fileId) { + if (newOpenFiles.length > 0) { + setActiveTab(newOpenFiles[newOpenFiles.length - 1].id); + } else { + setActiveTab(""); + } + } + }; + + const handleCreateProject = ( + template: ProjectTemplate, + config: NewProjectFormValues + ) => { + const newFileTree: FolderNode = { + ...template.fileTree, + name: config.projectName, + }; + setFileTree(newFileTree); + + let mainFileToOpen: OpenFileType | undefined; + + const findMainFile = (node: FolderNode | FileNode, currentPath: string) => { + if (mainFileToOpen) return; + const newPath = currentPath ? `${currentPath}/${node.name}` : node.name; + if (node.type === "file" && node.name === template.mainFile) { + mainFileToOpen = { + id: newPath, + name: node.name, + language: node.language, + content: generateFileContent(node.name, node.language), + }; + } else if (node.type === "folder" && node.children) { + for (const child of node.children) { + findMainFile(child, newPath); + } + } + }; + findMainFile(newFileTree, ""); + + if (mainFileToOpen) { + setOpenFiles([mainFileToOpen]); + setActiveTab(mainFileToOpen.id); + } else { + setOpenFiles([]); + setActiveTab(""); + } + + setIsNewProjectModalOpen(false); + }; + + const handleAiGeneratedFiles = (files: { filePath: string, fileContent: string }[]) => { + const addNodeToTree = ( + root: FolderNode, + path: string + ): FolderNode => { + const parts = path.split('/'); + // The AI generates paths relative to the project root, e.g., "src/components/new.tsx" + // The file tree's root is the project folder itself, so we start traversing from its children. + let currentNode: FolderNode | undefined = root; + + // Handle cases where AI gives a full path vs relative + const pathParts = parts[0] === root.name ? parts.slice(1) : parts; + + for (let i = 0; i < pathParts.length - 1; i++) { + const part = pathParts[i]; + let nextNode = currentNode.children.find( + (child) => child.name === part && child.type === 'folder' + ) as FolderNode | undefined; + + if (!nextNode) { + nextNode = { name: part, type: 'folder', children: [] }; + currentNode.children.push(nextNode); + } + currentNode = nextNode; + } + + // Add the file node if it doesn't exist + const fileName = pathParts[pathParts.length - 1]; + if (currentNode && !currentNode.children.some((child) => child.name === fileName)) { + currentNode.children.push({ + name: fileName, + type: 'file', + language: fileName.split('.').pop() || 'text', + }); + } + + return { ...root }; + }; + + let newFileTree = fileTree; + files.forEach(file => { + newFileTree = addNodeToTree(newFileTree, file.filePath); + }); + setFileTree(newFileTree); + + const newFilesToOpen: OpenFileType[] = files.map(file => ({ + id: file.filePath.startsWith(fileTree.name) ? file.filePath : `${fileTree.name}/${file.filePath}`, + name: file.filePath.split('/').pop() || 'untitled', + language: file.filePath.split('.').pop() || 'text', + content: file.fileContent, + })); + + setOpenFiles(prevOpenFiles => { + const updatedOpenFiles = [...prevOpenFiles]; + newFilesToOpen.forEach(newFile => { + const existingFileIndex = updatedOpenFiles.findIndex(f => f.id === newFile.id); + if (existingFileIndex !== -1) { + updatedOpenFiles[existingFileIndex].content = newFile.content; + } else { + updatedOpenFiles.push(newFile); + } + }); + return updatedOpenFiles; + }); + + if (newFilesToOpen.length > 0) { + setActiveTab(newFilesToOpen[newFilesToOpen.length - 1].id); + } + }; + + return ( + <> +
+ setIsNewProjectModalOpen(true)} /> +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ setIsNewProjectModalOpen(false)} + onCreateProject={handleCreateProject} + /> + + ); +} + +``` + +--- + +## FILE: src/components/aethex/ai-assistant.tsx + +```tsx +"use client"; + +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { Textarea } from "@/components/ui/textarea"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Send, + Bot, + Loader2, + Copy, + Code, + Sparkles, + MessageSquarePlus, + FlaskConical, + BookText, +} from "lucide-react"; +import { AethexLogo } from "./icons"; +import { useState, useRef, useEffect, memo } from "react"; +import { aiHelpFromPrompt } from "@/ai/flows/ai-help-from-prompt"; +import { cn } from "@/lib/utils"; +import { marked } from "marked"; +import SyntaxHighlighter from "react-syntax-highlighter"; +import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs"; +import { useToast } from "@/hooks/use-toast"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +type Message = { + id: string; + role: "user" | "assistant" | "system"; + content: string; +}; + +const CodeBlock = memo( + ({ language, code }: { language: string; code: string }) => { + const { toast } = useToast(); + + const handleCopy = () => { + navigator.clipboard.writeText(code); + toast({ title: "Code copied to clipboard!" }); + }; + + const handleInsert = () => { + toast({ + title: "Coming Soon!", + description: "Inserting code into the editor is not yet implemented.", + }); + }; + + return ( +
+
+ {language} +
+ + + + + + +

Insert into editor

+
+
+
+ + + + + + + +

Copy code

+
+
+
+
+
+ + {code} + +
+ ); + } +); +CodeBlock.displayName = "CodeBlock"; + +const ChatMessage = memo(({ message }: { message: Message }) => { + if (message.role === "system") { + return ( +
+ {message.content} +
+ ); + } + + const isUser = message.role === "user"; + const parts = message.content + .split(/(\`\`\`(?:[a-zA-Z0-9-]*)\n[\s\S]+?\n\`\`\`)/g) + .filter(Boolean); + + return ( +
+ {isUser && ( + + U + + )} +
+ {parts.map((part, index) => { + const codeBlockMatch = part.match( + /\`\`\`(.*?)\n([\s\S]+?)\n\`\`\`/ + ); + if (codeBlockMatch) { + const language = codeBlockMatch[1] || "text"; + const code = codeBlockMatch[2]; + return ; + } else { + return ( +
+ ); + } + })} +
+ {!isUser && ( + + + + + + )} +
+ ); +}); +ChatMessage.displayName = "ChatMessage"; + +type AiAssistantProps = { + onFilesGenerated: (files: { filePath: string, fileContent: string }[]) => void; +}; + +export function AiAssistant({ onFilesGenerated }: AiAssistantProps) { + const [messages, setMessages] = useState([ + { + id: "1", + role: "assistant", + content: + "Hello! I'm your AI assistant. How can I help you with your project today? You can ask me to explain code, generate tests, or even create a new project structure.", + }, + ]); + const [input, setInput] = useState(""); + const [loading, setLoading] = useState(false); + const scrollAreaRef = useRef(null); + const { toast } = useToast(); + + useEffect(() => { + if (scrollAreaRef.current) { + scrollAreaRef.current.scrollTo({ + top: scrollAreaRef.current.scrollHeight, + behavior: "smooth", + }); + } + }, [messages]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!input.trim() || loading) return; + + const userMessage: Message = { + id: Date.now().toString(), + role: "user", + content: input, + }; + setMessages((prev) => [...prev, userMessage]); + const currentInput = input; + setInput(""); + setLoading(true); + + try { + const result = await aiHelpFromPrompt({ prompt: currentInput }); + + let assistantContent = result.explanation; + + if (result.suggestedFiles && result.suggestedFiles.length > 0) { + onFilesGenerated(result.suggestedFiles); + assistantContent += `\n\nHere are the files I've generated for you:\n`; + result.suggestedFiles.forEach((file) => { + const lang = file.filePath.split(".").pop() || ""; + assistantContent += `\n**${file.filePath}**\n\`\`\`${lang}\n${file.fileContent}\n\`\`\``; + }); + const systemMessage: Message = { + id: Date.now().toString() + "-system", + role: "system", + content: "File suggestions have been opened in the editor for you to review.", + }; + setMessages((prev) => [...prev, systemMessage]); + } + + const assistantMessage: Message = { + id: Date.now().toString(), + role: "assistant", + content: assistantContent, + }; + setMessages((prev) => [...prev, assistantMessage]); + } catch (error) { + console.error("AI assistant error:", error); + const errorMessage: Message = { + id: Date.now().toString(), + role: "assistant", + content: + "Sorry, I encountered an issue while processing your request. Please try again.", + }; + setMessages((prev) => [...prev, errorMessage]); + } finally { + setLoading(false); + } + }; + + const handleQuickAction = (action: string) => { + toast({ + title: "Coming Soon!", + description: `The "${action}" feature is not yet implemented.`, + }); + }; + + const quickActions = [ + { label: "Explain selected code", icon: BookText, action: "Explain selected code" }, + { label: "Add comments", icon: MessageSquarePlus, action: "Add comments" }, + { label: "Convert to cross-platform", icon: Sparkles, action: "Convert to cross-platform" }, + { label: "Generate tests", icon: FlaskConical, action: "Generate tests" }, + ] + + return ( +
+
+
+ +

AI Assistant

+
+
+
+

Token Usage

+

12.5K / 500K

+
+ +
+
+ + +
+ {messages.map((message) => ( + + ))} + {loading && ( +
+ + U + +
+ + Waiting for response... +
+
+ )} +
+
+ +
+
+ {quickActions.map(({label, icon: Icon, action}) => ( + + ))} +
+
+