diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..03ea36c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,50 @@ +# # EditorConfig is awesome: https://EditorConfig.org + +# # top-most EditorConfig file +# root = true + +# # Unix-style newlines with a newline ending every file +# [*] +# charset = utf-8 +# end_of_line = lf +# insert_final_newline = true +# trim_trailing_whitespace = true +# indent_style = space +# indent_size = 2 + +# # TypeScript/JavaScript files +# [*.{ts,tsx,js,jsx,mjs,cjs}] +# indent_size = 2 +# quote_type = single + +# # JSON files +# [*.json] +# indent_size = 2 + +# # YAML files +# [*.{yml,yaml}] +# indent_size = 2 + +# # Markdown files +# [*.md] +# trim_trailing_whitespace = false + +# # Package files +# [package.json] +# indent_size = 2 + +# # Config files +# [.{prettierrc,eslintrc,babelrc}] +# indent_size = 2 + +# # HTML files +# [*.html] +# indent_size = 2 + +# # CSS/SCSS files +# [*.{css,scss,sass}] +# indent_size = 2 + +# # Makefile +# [Makefile] +# indent_style = tab diff --git a/.env.example b/.env.example deleted file mode 100644 index ceb0f5c..0000000 --- a/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - -# chat persistence -- sign up on cloud.assistant-ui.com -# NEXT_PUBLIC_ASSISTANT_BASE_URL= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7b8da95..93288c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,31 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug +# Logs +logs +*.log npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* -!.env.example - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# wrangler files +.wrangler +.dev.vars* +.env +extension/chrome +.turbo \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..c287488 --- /dev/null +++ b/.npmrc @@ -0,0 +1,4 @@ +node-linker=isolated +strict-peer-dependencies=false +link-workspace-packages=true +auto-install-peers=true \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..63ecfc6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,29 @@ +# Dependencies +node_modules/ +pnpm-lock.yaml + +# Build outputs +dist/ +build/ +.turbo/ +.cache/ +*.tsbuildinfo + +# Generated files +*.gen.ts +routeTree.gen.ts + +# Extension specific +extension/.wxt/ +extension/dist/ + +# Web specific +web/dist/ +web/.wrangler/ +web/worker/db/migrations/ + +# Misc +coverage/ +.env* +*.log +.DS_Store diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..d36b31a --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,19 @@ +{ + "singleQuote": true, + "semi": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "es5", + "printWidth": 80, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf", + "plugins": ["@ianvs/prettier-plugin-sort-imports"], + "importOrder": [ + "^react$", + "^react-dom$", + "", + "^@/(.*)$", + "^[./]" + ] +} diff --git a/FORMATTING.md b/FORMATTING.md new file mode 100644 index 0000000..9055fab --- /dev/null +++ b/FORMATTING.md @@ -0,0 +1,103 @@ +# Code Formatting and Linting Setup + +This project uses a consistent code formatting and linting setup across the monorepo. + +## Tools Used + +- **Prettier** - Code formatter for consistent style +- **ESLint** - Linter for catching errors and enforcing code quality +- **EditorConfig** - Ensures consistent coding styles across different editors + +## Configuration Files + +- `.prettierrc.json` - Prettier configuration +- `.prettierignore` - Files to exclude from Prettier formatting +- `eslint.config.js` - ESLint configuration (using flat config) +- `.editorconfig` - Editor configuration for consistent coding styles +- `.vscode/settings.json` - VSCode workspace settings + +## Available Commands + +### Format all files in the workspace + +```bash +pnpm format +``` + +### Check formatting without making changes + +```bash +pnpm format:check +``` + +### Run ESLint with auto-fix + +```bash +pnpm lint +``` + +### Check linting without auto-fix + +```bash +pnpm lint:check +``` + +### Run all checks (typecheck, lint, format) + +```bash +pnpm check-all +``` + +## VSCode Integration + +The workspace is configured to: + +- Format on save using Prettier +- Fix ESLint errors on save +- Organize imports on save + +Make sure you have these VSCode extensions installed: + +- ESLint (`dbaeumer.vscode-eslint`) +- Prettier (`esbenp.prettier-vscode`) +- EditorConfig (`EditorConfig.EditorConfig`) + +## Formatting Rules + +### TypeScript/JavaScript + +- Single quotes for strings +- Semicolons required +- 2 space indentation +- Trailing commas (ES5 style) +- 80 character line width +- Arrow function parentheses always + +### Import Organization + +Imports are automatically sorted in this order: + +1. React imports +2. Third-party modules +3. Alias imports (`@/...`) +4. Relative imports + +## Monorepo Considerations + +The configuration files at the root apply to all packages in the monorepo. Individual packages can override settings if needed by creating their own configuration files. + +## Installing Dependencies + +The required ESLint packages have been added to the root `package.json`. Run: + +```bash +pnpm install +``` + +This will install all necessary dependencies including the ESLint packages needed for the configuration. + +## Notes + +- The ESLint configuration uses a simplified setup without TypeScript project references to avoid complexity in the monorepo +- Generated files and build outputs are automatically excluded from linting and formatting +- The import sorting plugin for Prettier is configured but may require the `@ianvs/prettier-plugin-sort-imports` package to be installed diff --git a/README.md b/README.md deleted file mode 100644 index 5bc3887..0000000 --- a/README.md +++ /dev/null @@ -1,25 +0,0 @@ -This is the [assistant-ui](https://github.com/Yonom/assistant-ui) starter project. - -## Getting Started - -First, add your OpenAI API key to `.env.local` file: - -``` -OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -``` - -Then, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts deleted file mode 100644 index 9563b18..0000000 --- a/app/api/chat/route.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { openai } from "@ai-sdk/openai"; -import { frontendTools } from "@assistant-ui/react-ai-sdk"; -import { streamText } from "ai"; -import { experimental_createMCPClient as createMCPClient } from "ai"; - -export const runtime = "edge"; -export const maxDuration = 30; - -const mcpClient = await createMCPClient({ - // TODO adjust this to point to your MCP server URL - transport: { - type: "sse", - url: "http://localhost:8000/sse", - }, -}); - -const mcpTools = await mcpClient.tools(); - -export async function POST(req: Request) { - const { messages, system, tools } = await req.json(); - - const result = streamText({ - model: openai("gpt-4o"), - messages, - // forward system prompt and tools from the frontend - toolCallStreaming: true, - system, - tools: { - ...frontendTools(tools), - ...mcpTools, - }, - onError: console.log, - }); - - return result.toDataStreamResponse(); -} diff --git a/app/assistant.tsx b/app/assistant.tsx deleted file mode 100644 index 4046ccc..0000000 --- a/app/assistant.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; - -import { AssistantRuntimeProvider } from "@assistant-ui/react"; -import { useChatRuntime } from "@assistant-ui/react-ai-sdk"; -import { Thread } from "@/components/assistant-ui/thread"; -import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; -import { AppSidebar } from "@/components/app-sidebar"; -import { Separator } from "@/components/ui/separator"; -import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb"; - -export const Assistant = () => { - const runtime = useChatRuntime({ - api: "/api/chat", - }); - - return ( - - - - -
- - - - - - - Build Your Own ChatGPT UX - - - - - - Starter Template - - - - -
- -
-
-
- ); -}; diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/app/favicon.ico and /dev/null differ diff --git a/app/layout.tsx b/app/layout.tsx deleted file mode 100644 index 3e74711..0000000 --- a/app/layout.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: "assistant-ui Starter App", - description: "Generated by create-assistant-ui", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - ); -} diff --git a/app/page.tsx b/app/page.tsx deleted file mode 100644 index c222980..0000000 --- a/app/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { Assistant } from "./assistant"; - -export default function Home() { - return ; -} diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx deleted file mode 100644 index 3ee4bf5..0000000 --- a/components/app-sidebar.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import * as React from "react" -import { Github, MessagesSquare } from "lucide-react" -import Link from "next/link" -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarHeader, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - SidebarRail, -} from "@/components/ui/sidebar" -import { ThreadList } from "./assistant-ui/thread-list" - -export function AppSidebar({ ...props }: React.ComponentProps) { - return ( - - - - - - -
- -
-
- assistant-ui -
- -
-
-
-
- - - - - - - - - - - -
- -
-
- GitHub - View Source -
- -
- -
-
-
-
- ) -} diff --git a/components/assistant-ui/markdown-text.tsx b/components/assistant-ui/markdown-text.tsx deleted file mode 100644 index 4dbdce1..0000000 --- a/components/assistant-ui/markdown-text.tsx +++ /dev/null @@ -1,132 +0,0 @@ -"use client"; - -import "@assistant-ui/react-markdown/styles/dot.css"; - -import { - CodeHeaderProps, - MarkdownTextPrimitive, - unstable_memoizeMarkdownComponents as memoizeMarkdownComponents, - useIsMarkdownCodeBlock, -} from "@assistant-ui/react-markdown"; -import remarkGfm from "remark-gfm"; -import { FC, memo, useState } from "react"; -import { CheckIcon, CopyIcon } from "lucide-react"; - -import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button"; -import { cn } from "@/lib/utils"; - -const MarkdownTextImpl = () => { - return ( - - ); -}; - -export const MarkdownText = memo(MarkdownTextImpl); - -const CodeHeader: FC = ({ language, code }) => { - const { isCopied, copyToClipboard } = useCopyToClipboard(); - const onCopy = () => { - if (!code || isCopied) return; - copyToClipboard(code); - }; - - return ( -
- {language} - - {!isCopied && } - {isCopied && } - -
- ); -}; - -const useCopyToClipboard = ({ - copiedDuration = 3000, -}: { - copiedDuration?: number; -} = {}) => { - const [isCopied, setIsCopied] = useState(false); - - const copyToClipboard = (value: string) => { - if (!value) return; - - navigator.clipboard.writeText(value).then(() => { - setIsCopied(true); - setTimeout(() => setIsCopied(false), copiedDuration); - }); - }; - - return { isCopied, copyToClipboard }; -}; - -const defaultComponents = memoizeMarkdownComponents({ - h1: ({ className, ...props }) => ( -

- ), - h2: ({ className, ...props }) => ( -

- ), - h3: ({ className, ...props }) => ( -

- ), - h4: ({ className, ...props }) => ( -

- ), - h5: ({ className, ...props }) => ( -

- ), - h6: ({ className, ...props }) => ( -
- ), - p: ({ className, ...props }) => ( -

- ), - a: ({ className, ...props }) => ( - - ), - blockquote: ({ className, ...props }) => ( -

- ), - ul: ({ className, ...props }) => ( -