diff --git a/.gitignore b/.gitignore index c6d0044..e68838c 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ node_modules/ /playwright-report/ /blob-report/ /playwright/.cache/ + +# clerk configuration (can include secrets) +/.clerk/ diff --git a/package.json b/package.json index b8ddf7f..28c6aa4 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "main": "dist/main/main.js", "scripts": { "dev": "next dev", - "build": "pnpm build:workers && next build", + "build": "pnpm workers:build && next build", "start": "next start", "postinstall": "#prisma generate", "typecheck": "tsc --noEmit", @@ -33,6 +33,10 @@ "test:e2e:ui": "playwright test --ui" }, "dependencies": { + "@ai-sdk/openai": "^1.3.20", + "@ai-sdk/react": "^1.2.9", + "@ai-sdk/xai": "^1.2.15", + "@clerk/nextjs": "^6.18.0", "@monaco-editor/react": "^4.7.0", "@prisma/client": "^6.5.0", "@radix-ui/react-avatar": "^1.1.7", @@ -73,6 +77,7 @@ "lodash": "^4.17.21", "lucide-react": "^0.503.0", "marked": "^15.0.11", + "monaco-editor": "^0.52.2", "monaco-themes": "^0.4.4", "motion": "^12.7.5", "next": "^15.2.3", @@ -86,10 +91,11 @@ "socket.io-client": "^4.8.1", "sonner": "^2.0.3", "tailwind-merge": "^3.2.0", + "tiptap-markdown": "^0.8.10", "tw-animate-css": "^1.2.8", "utf-8-validate": "^6.0.5", "ws": "^8.18.1", - "zod": "^3.24.2", + "zod": "^3.24.3", "zustand": "^5.0.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a66aba6..f3b8506 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,18 @@ importers: .: dependencies: + '@ai-sdk/openai': + specifier: ^1.3.20 + version: 1.3.20(zod@3.24.3) + '@ai-sdk/react': + specifier: ^1.2.9 + version: 1.2.9(react@19.1.0)(zod@3.24.3) + '@ai-sdk/xai': + specifier: ^1.2.15 + version: 1.2.15(zod@3.24.3) + '@clerk/nextjs': + specifier: ^6.18.0 + version: 6.18.0(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@monaco-editor/react': specifier: ^4.7.0 version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -128,6 +140,9 @@ importers: marked: specifier: ^15.0.11 version: 15.0.11 + monaco-editor: + specifier: ^0.52.2 + version: 0.52.2 monaco-themes: specifier: ^0.4.4 version: 0.4.4 @@ -167,6 +182,9 @@ importers: tailwind-merge: specifier: ^3.2.0 version: 3.2.0 + tiptap-markdown: + specifier: ^0.8.10 + version: 0.8.10(@tiptap/core@2.11.7(@tiptap/pm@2.11.7)) tw-animate-css: specifier: ^1.2.8 version: 1.2.8 @@ -177,7 +195,7 @@ importers: specifier: ^8.18.1 version: 8.18.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) zod: - specifier: ^3.24.2 + specifier: ^3.24.3 version: 3.24.3 zustand: specifier: ^5.0.3 @@ -297,6 +315,18 @@ packages: '@adobe/css-tools@4.4.2': resolution: {integrity: sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==} + '@ai-sdk/openai-compatible@0.2.13': + resolution: {integrity: sha512-tB+lL8Z3j0qDod/mvxwjrPhbLUHp/aQW+NvMoJaqeTtP+Vmv5qR800pncGczxn5WN0pllQm+7aIRDnm69XeSbg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + + '@ai-sdk/openai@1.3.20': + resolution: {integrity: sha512-/DflUy7ROG9k6n6YTXMBFPbujBKnbGY58f3CwvicLvDar9nDAloVnUWd3LUoOxpSVnX8vtQ7ngxF52SLWO6RwQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@ai-sdk/provider-utils@2.2.7': resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==} engines: {node: '>=18'} @@ -323,6 +353,12 @@ packages: peerDependencies: zod: ^3.23.8 + '@ai-sdk/xai@1.2.15': + resolution: {integrity: sha512-18qEYyVHIqTiOMePE00bfx4kJrTHM4dV3D3Rpe+eBISlY80X1FnzZRnRTJo3Q6MOSmW5+ZKVaX9jtryhoFpn0A==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.0.0 + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -474,6 +510,46 @@ packages: cpu: [x64] os: [win32] + '@clerk/backend@1.30.0': + resolution: {integrity: sha512-VB8a0jbfb5eiHENCT9ts8ISozUbKOcREj2rXQaYcOhEQ1EzO6Jng1Pb0nRR4RojsAvPe9XGMQrA4FufHp+dUWQ==} + engines: {node: '>=18.17.0'} + peerDependencies: + svix: ^1.62.0 + peerDependenciesMeta: + svix: + optional: true + + '@clerk/clerk-react@5.30.0': + resolution: {integrity: sha512-ruC8I31wu5vpYFTZ5Qj+avZwHbyzmhY6fatV6EzYMCIu7tOgDK5Af92gerfJ5drbRTL+NM4tDPmSNXiMIdS/nw==} + engines: {node: '>=18.17.0'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + + '@clerk/nextjs@6.18.0': + resolution: {integrity: sha512-7cWFserYByK65eSX7eCyGXHlDb3ejNTyf3O8nHc4DgDLHjZn5dJA+6J0Hz1XSgUATOCSbnmkKSy1iekNMvSnYA==} + engines: {node: '>=18.17.0'} + peerDependencies: + next: ^13.5.7 || ^14.2.25 || ^15.2.3 + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + + '@clerk/shared@3.7.4': + resolution: {integrity: sha512-Ua6MyDyXjkfrV4h7ftC5LUsz7YL+0athsiNuMUyYjE3x8r/vmJzhLjZJ7C2C3KhDq2XnMWud0iQ7SGRTop+9WQ==} + engines: {node: '>=18.17.0'} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@clerk/types@4.55.1': + resolution: {integrity: sha512-BS/shDMWfQ7M8Jlms/RJFH20N8cK1EfAWKTpiIiICFi5e/5H0gpaaWx277x341GQz4gZzVDPGdF+EhoknYOrWQ==} + engines: {node: '>=18.17.0'} + '@csstools/color-helpers@5.0.2': resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} engines: {node: '>=18'} @@ -2020,18 +2096,27 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/linkify-it@3.0.5': + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} '@types/lodash@4.17.16': resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} + '@types/markdown-it@13.0.9': + resolution: {integrity: sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==} + '@types/markdown-it@14.1.2': resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/mdurl@1.0.5': + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + '@types/mdurl@2.0.0': resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} @@ -2572,6 +2657,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -2705,6 +2794,9 @@ packages: dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -3276,6 +3368,10 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3425,6 +3521,9 @@ packages: loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} @@ -3471,6 +3570,13 @@ packages: resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + + markdown-it-task-lists@2.1.1: + resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==} + markdown-it@14.1.0: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true @@ -3699,6 +3805,9 @@ packages: sass: optional: true + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-abi@3.74.0: resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} engines: {node: '>=10'} @@ -4205,6 +4314,9 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -4256,6 +4368,13 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + snakecase-keys@8.0.1: + resolution: {integrity: sha512-Sj51kE1zC7zh6TDlNNz0/Jn1n5HiHdoQErxO8jLtnyrkJW/M5PrI7x05uDgY3BO7OUQYKCvmeMurW6BPUdwEOw==} + engines: {node: '>=18'} + socket.io-adapter@2.5.5: resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} @@ -4464,6 +4583,11 @@ packages: tippy.js@6.3.7: resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + tiptap-markdown@0.8.10: + resolution: {integrity: sha512-iDVkR2BjAqkTDtFX0h94yVvE2AihCXlF0Q7RIXSJPRSR5I0PA1TMuAg6FHFpmqTn4tPxJ0by0CK7PUMlnFLGEQ==} + peerDependencies: + '@tiptap/core': ^2.0.3 + tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} @@ -4520,6 +4644,10 @@ packages: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} + type-fest@4.40.1: + resolution: {integrity: sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -4894,6 +5022,18 @@ snapshots: '@adobe/css-tools@4.4.2': {} + '@ai-sdk/openai-compatible@0.2.13(zod@3.24.3)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.7(zod@3.24.3) + zod: 3.24.3 + + '@ai-sdk/openai@1.3.20(zod@3.24.3)': + dependencies: + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.7(zod@3.24.3) + zod: 3.24.3 + '@ai-sdk/provider-utils@2.2.7(zod@3.24.3)': dependencies: '@ai-sdk/provider': 1.1.3 @@ -4922,6 +5062,13 @@ snapshots: zod: 3.24.3 zod-to-json-schema: 3.24.5(zod@3.24.3) + '@ai-sdk/xai@1.2.15(zod@3.24.3)': + dependencies: + '@ai-sdk/openai-compatible': 0.2.13(zod@3.24.3) + '@ai-sdk/provider': 1.1.3 + '@ai-sdk/provider-utils': 2.2.7(zod@3.24.3) + zod: 3.24.3 + '@alloc/quick-lru@5.2.0': {} '@ampproject/remapping@2.3.0': @@ -5088,6 +5235,55 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true + '@clerk/backend@1.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@clerk/shared': 3.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@clerk/types': 4.55.1 + cookie: 1.0.2 + snakecase-keys: 8.0.1 + tslib: 2.8.1 + transitivePeerDependencies: + - react + - react-dom + + '@clerk/clerk-react@5.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@clerk/shared': 3.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@clerk/types': 4.55.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + tslib: 2.8.1 + + '@clerk/nextjs@6.18.0(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@clerk/backend': 1.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@clerk/clerk-react': 5.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@clerk/shared': 3.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@clerk/types': 4.55.1 + next: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + server-only: 0.0.1 + tslib: 2.8.1 + transitivePeerDependencies: + - svix + + '@clerk/shared@3.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@clerk/types': 4.55.1 + dequal: 2.0.3 + glob-to-regexp: 0.4.1 + js-cookie: 3.0.5 + std-env: 3.9.0 + swr: 2.3.3(react@19.1.0) + optionalDependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@clerk/types@4.55.1': + dependencies: + csstype: 3.1.3 + '@csstools/color-helpers@5.0.2': {} '@csstools/css-calc@2.1.3(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': @@ -6560,10 +6756,17 @@ snapshots: dependencies: '@types/node': 20.17.30 + '@types/linkify-it@3.0.5': {} + '@types/linkify-it@5.0.0': {} '@types/lodash@4.17.16': {} + '@types/markdown-it@13.0.9': + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + '@types/markdown-it@14.1.2': dependencies: '@types/linkify-it': 5.0.0 @@ -6573,6 +6776,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/mdurl@1.0.5': {} + '@types/mdurl@2.0.0': {} '@types/ms@2.1.0': {} @@ -7231,6 +7436,8 @@ snapshots: cookie@0.7.2: {} + cookie@1.0.2: {} + core-util-is@1.0.2: optional: true @@ -7366,6 +7573,11 @@ snapshots: dom-accessibility-api@0.5.16: {} + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dotenv-expand@11.0.7: dependencies: dotenv: 16.5.0 @@ -8060,6 +8272,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 + js-cookie@3.0.5: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -8200,6 +8414,10 @@ snapshots: loupe@3.1.3: {} + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lowercase-keys@2.0.0: {} lru-cache@10.4.3: {} @@ -8262,6 +8480,10 @@ snapshots: - bluebird - supports-color + map-obj@4.3.0: {} + + markdown-it-task-lists@2.1.1: {} + markdown-it@14.1.0: dependencies: argparse: 2.0.1 @@ -8464,6 +8686,11 @@ snapshots: - '@babel/core' - babel-plugin-macros + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + node-abi@3.74.0: dependencies: semver: 7.7.1 @@ -9018,6 +9245,8 @@ snapshots: dependencies: randombytes: 2.1.0 + server-only@0.0.1: {} + set-blocking@2.0.0: {} sharp@0.34.1: @@ -9097,6 +9326,17 @@ snapshots: smart-buffer@4.2.0: {} + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + snakecase-keys@8.0.1: + dependencies: + map-obj: 4.3.0 + snake-case: 3.0.4 + type-fest: 4.40.1 + socket.io-adapter@2.5.5(bufferutil@4.0.9)(utf-8-validate@6.0.5): dependencies: debug: 4.3.7 @@ -9321,6 +9561,14 @@ snapshots: dependencies: '@popperjs/core': 2.11.8 + tiptap-markdown@0.8.10(@tiptap/core@2.11.7(@tiptap/pm@2.11.7)): + dependencies: + '@tiptap/core': 2.11.7(@tiptap/pm@2.11.7) + '@types/markdown-it': 13.0.9 + markdown-it: 14.1.0 + markdown-it-task-lists: 2.1.1 + prosemirror-markdown: 1.13.2 + tldts-core@6.1.86: {} tldts@6.1.86: @@ -9362,6 +9610,8 @@ snapshots: type-fest@0.13.1: optional: true + type-fest@4.40.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 diff --git a/public/workers/workers/file-system.worker.js b/public/workers/workers/file-system.worker.js index 219b73f..899b76b 100644 --- a/public/workers/workers/file-system.worker.js +++ b/public/workers/workers/file-system.worker.js @@ -79,15 +79,15 @@ async function listFilesNonRecursively(dirPath = "") { const dirHandle = await getDirHandleFromPath(dirPath); const files = []; try { - console.log("[Worker] Starting to list directory contents"); + // console.log("[Worker] Starting to list directory contents"); const handle = dirHandle; for await (const entry of handle.values()) { const entryPath = dirPath ? `${dirPath}/${entry.name}` : entry.name; - console.log("[Worker] Processing entry:", entryPath); + // console.log("[Worker] Processing entry:", entryPath); const fileInfo = await getFileInfo(entry, entry.name, entryPath); files.push(fileInfo); } - console.log("[Worker] Found", files.length, "files in directory"); + // console.log("[Worker] Found", files.length, "files in directory"); } catch (error) { console.error("[Worker] Error listing files in", dirPath, ":", error); diff --git a/src/app/(ide)/@editor/default.tsx b/src/app/(ide)/@editor/default.tsx index 1c36d3d..6a40406 100644 --- a/src/app/(ide)/@editor/default.tsx +++ b/src/app/(ide)/@editor/default.tsx @@ -2,4 +2,4 @@ export default function Default() { return null; -} +} \ No newline at end of file diff --git a/src/app/(ide)/ide/layout.tsx b/src/app/(ide)/ide/layout.tsx index 1b93aaa..010000f 100644 --- a/src/app/(ide)/ide/layout.tsx +++ b/src/app/(ide)/ide/layout.tsx @@ -25,10 +25,13 @@ export default function IDELayout({ terminal: ReactNode; agent: ReactNode; }) { - const { loadDirectory } = useFileStore(useShallow(state => ({ + const { loadDirectory, filteredFiles, searchQuery } = useFileStore(useShallow(state => ({ loadDirectory: state.loadDirectory, + filteredFiles: state.filteredFiles, + searchQuery: state.searchQuery, }))); + const { projects, activeProject, removeProject, setActiveProject } = useIDEStore(useShallow(state => ({ projects: state.projects, @@ -115,6 +118,10 @@ export default function IDELayout({ +
+ {filteredFiles.length} items + {searchQuery && " (filtered)"} +
); } diff --git a/src/app/(ide)/layout.tsx b/src/app/(ide)/layout.tsx index cd2da8e..5b6a671 100644 --- a/src/app/(ide)/layout.tsx +++ b/src/app/(ide)/layout.tsx @@ -1,3 +1,4 @@ +import { CommandDialogDemo } from "@/components/commandbar/commandbar"; import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; import { cookies } from "next/headers"; import type { ReactNode } from "react"; @@ -14,6 +15,7 @@ export default async function IDELayout({ children }: { children: ReactNode }) { {/* */} + ); } diff --git a/src/app/(landing)/layout.tsx b/src/app/(landing)/layout.tsx index cfc1e7d..691c076 100644 --- a/src/app/(landing)/layout.tsx +++ b/src/app/(landing)/layout.tsx @@ -1,4 +1,5 @@ import Header from "@/components/layout/Header"; +import { ClerkProvider } from "@clerk/nextjs"; export default function LandingLayout({ children, @@ -6,10 +7,12 @@ export default function LandingLayout({ children: React.ReactNode; }) { return ( -
-
-
{children}
- {/*
*/} -
+ +
+
+
{children}
+ {/*
*/} +
+
); } diff --git a/src/app/(landing)/page.tsx b/src/app/(landing)/page.tsx index 5988cd9..2c8be4a 100644 --- a/src/app/(landing)/page.tsx +++ b/src/app/(landing)/page.tsx @@ -1,5 +1,4 @@ import { Hero } from "@/components/landing/Hero"; - export const dynamic = "force-dynamic"; export default function Home() { @@ -8,6 +7,7 @@ export default function Home() {
{/* Hero Section */} +
); diff --git a/src/app/api/completion/prompt.ts b/src/app/api/completion/prompt.ts new file mode 100644 index 0000000..646c05c --- /dev/null +++ b/src/app/api/completion/prompt.ts @@ -0,0 +1,24 @@ +export const GenerateInstructions = (language: string) => ({ + content: `## Task: Code Completion + + ### Language: ${language} + + ### Instructions: + - You are a world class coding assistant. + - Given the current text, context, and the last character of the user input, provide a suggestion for code completion. + - The suggestion must be based on the current text, as well as the text before the cursor. + - This is not a conversation, so please do not ask questions or prompt for additional information. + + ### Notes + - NEVER INCLUDE ANY MARKDOWN IN THE RESPONSE - THIS MEANS CODEBLOCKS AS WELL. + - Never include any annotations such as "# Suggestion:" or "# Suggestions:". + - Newlines should be included after any of the following characters: "{", "[", "(", ")", "]", "}", and ",". + - Never suggest a newline after a space or newline. + - Ensure that newline suggestions follow the same indentation as the current line. + - The suggestion must start with the last character of the current user input. + - Only ever return the code snippet, do not return any markdown unless it is part of the code snippet. + - Do not return any code that is already present in the current text. + - Do not return anything that is not valid code. + - If you do not have a suggestion, return an empty string.`, + role: "system", + }); \ No newline at end of file diff --git a/src/app/api/completion/route.ts b/src/app/api/completion/route.ts new file mode 100644 index 0000000..7fa7721 --- /dev/null +++ b/src/app/api/completion/route.ts @@ -0,0 +1,18 @@ +import { openai } from "@ai-sdk/openai"; +import { streamText } from "ai"; + +// Allow streaming responses up to 30 seconds +export const maxDuration = 30; + +export async function POST(req: Request) { + const { messages } = await req.json(); + + const result = streamText({ + model: openai("gpt-4o"), + messages, + maxTokens: 16, + temperature: 0.1, + }); + + return result.toDataStreamResponse(); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 55d7d85..d6397f4 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,8 +1,10 @@ import "@/styles/globals.css"; import { FileStoreInitializer } from "@/components/file-store-initializer"; +import { env } from "@/env"; import type { Metadata } from "next"; import { Geist } from "next/font/google"; +import { Toaster } from "sonner"; export const metadata: Metadata = { title: "Floki", @@ -21,14 +23,17 @@ export default function RootLayout({ return ( -