├── packages ├── ai │ ├── index.ts │ ├── lib │ │ ├── react.ts │ │ └── models.ts │ ├── tsconfig.json │ ├── package.json │ └── keys.ts ├── database │ ├── .env.example │ ├── migrations │ │ ├── 0000_chunky_ozymandias.sql │ │ └── meta │ │ │ ├── _journal.json │ │ │ └── 0000_snapshot.json │ ├── schema.ts │ ├── tsconfig.json │ ├── drizzle.config.ts │ ├── keys.ts │ ├── index.ts │ └── package.json ├── storage │ ├── index.ts │ ├── client.ts │ ├── tsconfig.json │ ├── keys.ts │ └── package.json ├── design-system │ ├── postcss.config.mjs │ ├── lib │ │ ├── fonts.ts │ │ └── utils.ts │ ├── components │ │ ├── ui │ │ │ ├── aspect-ratio.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── sonner.tsx │ │ │ ├── label.tsx │ │ │ ├── separator.tsx │ │ │ ├── textarea.tsx │ │ │ ├── progress.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── input.tsx │ │ │ ├── switch.tsx │ │ │ ├── avatar.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── hover-card.tsx │ │ │ ├── toggle.tsx │ │ │ ├── badge.tsx │ │ │ ├── popover.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── alert.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── tabs.tsx │ │ │ ├── resizable.tsx │ │ │ ├── slider.tsx │ │ │ ├── toggle-group.tsx │ │ │ ├── accordion.tsx │ │ │ ├── button.tsx │ │ │ └── card.tsx │ │ └── ai-elements │ │ │ ├── response.tsx │ │ │ ├── image.tsx │ │ │ ├── mode-toggle.tsx │ │ │ ├── suggestion.tsx │ │ │ ├── actions.tsx │ │ │ ├── message.tsx │ │ │ ├── conversation.tsx │ │ │ └── sources.tsx │ ├── tsconfig.json │ ├── providers │ │ └── theme.tsx │ ├── index.tsx │ ├── components.json │ └── hooks │ │ └── use-mobile.ts ├── testing │ ├── tsconfig.json │ ├── package.json │ └── index.js ├── next-config │ ├── tsconfig.json │ ├── package.json │ ├── keys.ts │ └── index.ts └── typescript-config │ ├── react-library.json │ ├── package.json │ ├── nextjs.json │ └── base.json ├── turbo └── generators │ ├── package.json │ ├── templates │ ├── package.json.hbs │ └── tsconfig.json.hbs │ └── config.ts ├── public ├── favicon.ico ├── obby-dev.png ├── splash-image.png ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── logos │ ├── ai │ │ ├── obbylabs.webp │ │ ├── anthropic.svg │ │ ├── groq.svg │ │ ├── xai.svg │ │ ├── togetherai.svg │ │ ├── google.svg │ │ ├── fireworks.svg │ │ ├── vertex.svg │ │ ├── fireworksai.svg │ │ ├── openai.svg │ │ ├── deepseek.svg │ │ └── mistral.svg │ ├── obby │ │ ├── obby-logo.png │ │ ├── obby-logo.webp │ │ ├── obby-logo-dark.png │ │ ├── obby-logo-min.webp │ │ ├── obby-logo-dark.webp │ │ ├── obby-logo-transparent.png │ │ └── obby-logo-transparent.webp │ └── vercel_logo.svg ├── android-chrome-192x192.png ├── android-chrome-512x512.png └── site.webmanifest ├── apps ├── obby │ ├── postcss.config.mjs │ ├── app │ │ ├── icon.png │ │ ├── favicon.ico │ │ ├── styles.css │ │ ├── apple-icon.png │ │ ├── opengraph-image.png │ │ ├── (main) │ │ │ ├── preview.tsx │ │ │ ├── file-explorer.tsx │ │ │ ├── logs.tsx │ │ │ ├── header.tsx │ │ │ └── page.tsx │ │ ├── global-error.tsx │ │ ├── layout.tsx │ │ └── api │ │ │ └── sandboxes │ │ │ └── [sandboxId] │ │ │ ├── cmds │ │ │ └── [cmdId] │ │ │ │ └── route.ts │ │ │ ├── route.ts │ │ │ └── files │ │ │ └── route.ts │ ├── markdown.d.ts │ ├── public │ │ ├── obby-logo-min.webp │ │ ├── vercel.svg │ │ ├── window.svg │ │ ├── file.svg │ │ ├── providers │ │ │ ├── v0.svg │ │ │ ├── groq.svg │ │ │ ├── vercel.svg │ │ │ ├── gemini.svg │ │ │ ├── anthropic.svg │ │ │ ├── openrouter.svg │ │ │ └── openai.svg │ │ ├── globe.svg │ │ └── next.svg │ ├── components │ │ ├── model-selector │ │ │ ├── model-selector.tsx │ │ │ ├── model-selector-cmdk.tsx │ │ │ ├── cmdk │ │ │ │ ├── api-key-section.tsx │ │ │ │ ├── use-provider-key.tsx │ │ │ │ ├── model-section.tsx │ │ │ │ └── provider-sidebar.tsx │ │ │ └── use-available-models.tsx │ │ ├── tabs │ │ │ ├── index.tsx │ │ │ ├── use-tab-state.ts │ │ │ ├── tab-content.tsx │ │ │ ├── tab-group.tsx │ │ │ └── tab-item.tsx │ │ ├── chat │ │ │ ├── message-spinner.tsx │ │ │ ├── types.tsx │ │ │ ├── message-part │ │ │ │ ├── text.tsx │ │ │ │ ├── reasoning.tsx │ │ │ │ ├── get-sandbox-url.tsx │ │ │ │ ├── create-sandbox.tsx │ │ │ │ ├── run-command.tsx │ │ │ │ ├── wait-command.tsx │ │ │ │ ├── generate-files.tsx │ │ │ │ └── index.tsx │ │ │ ├── tool-header.tsx │ │ │ ├── tool-message.tsx │ │ │ └── message.tsx │ │ ├── commands-logs │ │ │ ├── types.ts │ │ │ └── commands-logs.tsx │ │ ├── icons │ │ │ ├── obby-logo.tsx │ │ │ └── github.tsx │ │ ├── panels │ │ │ └── panels.tsx │ │ ├── file-explorer │ │ │ ├── file-content.tsx │ │ │ └── build-file-tree.tsx │ │ └── banner.tsx │ ├── vercel.json │ ├── ai │ │ ├── messages │ │ │ ├── metadata.ts │ │ │ └── data-parts.ts │ │ ├── tools │ │ │ ├── generate-files-prompt.md │ │ │ ├── get-sandbox-url.ts │ │ │ ├── index.ts │ │ │ ├── wait-command.ts │ │ │ └── wait-command.md │ │ └── validation.ts │ ├── instrumentation-client.ts │ ├── lib │ │ ├── is-relative-url.ts │ │ ├── use-local-storage-value.ts │ │ ├── use-index-db-storage.ts │ │ ├── logger.ts │ │ └── indexed-db-adapter.ts │ ├── tsconfig.json │ ├── next.config.ts │ ├── scripts │ │ └── skip-ci.js │ ├── env.ts │ ├── .env.example │ ├── stores │ │ ├── use-provider-keys-store.ts │ │ └── use-model-store.ts │ └── package.json └── web │ ├── app │ ├── icon.png │ ├── opengraph-image.png │ ├── global.css │ ├── api │ │ └── search │ │ │ └── route.ts │ ├── (home) │ │ └── layout.tsx │ ├── docs │ │ ├── layout.tsx │ │ └── [[...slug]] │ │ │ └── page.tsx │ └── layout.tsx │ ├── postcss.config.mjs │ ├── public │ └── obby-logo-min.webp │ ├── next.config.mjs │ ├── lib │ ├── source.ts │ └── layout.shared.tsx │ ├── content │ └── docs │ │ ├── test.mdx │ │ └── meta.json │ ├── mdx-components.tsx │ ├── source.config.ts │ ├── package.json │ ├── tsconfig.json │ ├── .source │ └── index.ts │ └── README.md ├── SECURITY.md ├── tsup.config.ts ├── .vscode ├── extensions.json ├── settings.json └── launch.json ├── pnpm-workspace.yaml ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── pull_request_template.md └── copilot-instructions.md.example ├── tsconfig.json ├── scripts ├── index.ts └── utils.ts ├── turbo.json ├── biome.jsonc ├── README.md ├── LICENSE ├── .zed └── settings.json └── package.json /packages/ai/index.ts: -------------------------------------------------------------------------------- 1 | export * from 'ai'; 2 | -------------------------------------------------------------------------------- /packages/database/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="" -------------------------------------------------------------------------------- /packages/ai/lib/react.ts: -------------------------------------------------------------------------------- 1 | export * from 'ai/react'; 2 | -------------------------------------------------------------------------------- /packages/storage/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@vercel/blob'; 2 | -------------------------------------------------------------------------------- /packages/storage/client.ts: -------------------------------------------------------------------------------- 1 | export * from '@vercel/blob/client'; 2 | -------------------------------------------------------------------------------- /turbo/generators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "commonjs" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /apps/obby/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@repo/design-system/postcss.config.mjs'; 2 | -------------------------------------------------------------------------------- /apps/web/app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/web/app/icon.png -------------------------------------------------------------------------------- /public/obby-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/obby-dev.png -------------------------------------------------------------------------------- /apps/obby/app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/obby/app/icon.png -------------------------------------------------------------------------------- /public/splash-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/splash-image.png -------------------------------------------------------------------------------- /apps/obby/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/obby/app/favicon.ico -------------------------------------------------------------------------------- /apps/obby/app/styles.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @import "@repo/design-system/styles/globals.css"; 3 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /apps/obby/app/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/obby/app/apple-icon.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/obby/markdown.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md' { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /apps/web/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /public/logos/ai/obbylabs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/ai/obbylabs.webp -------------------------------------------------------------------------------- /public/logos/obby/obby-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo.png -------------------------------------------------------------------------------- /apps/obby/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/obby/app/opengraph-image.png -------------------------------------------------------------------------------- /apps/web/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/web/app/opengraph-image.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/logos/obby/obby-logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo.webp -------------------------------------------------------------------------------- /apps/obby/public/obby-logo-min.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/obby/public/obby-logo-min.webp -------------------------------------------------------------------------------- /apps/web/public/obby-logo-min.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/apps/web/public/obby-logo-min.webp -------------------------------------------------------------------------------- /public/logos/obby/obby-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo-dark.png -------------------------------------------------------------------------------- /public/logos/obby/obby-logo-min.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo-min.webp -------------------------------------------------------------------------------- /public/logos/obby/obby-logo-dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo-dark.webp -------------------------------------------------------------------------------- /apps/obby/components/model-selector/model-selector.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export { ModelSelector } from './select/model-selector'; 4 | -------------------------------------------------------------------------------- /apps/obby/components/tabs/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './tab-content'; 2 | export * from './tab-group'; 3 | export * from './tab-item'; 4 | -------------------------------------------------------------------------------- /apps/web/app/global.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | @import 'fumadocs-ui/css/neutral.css'; 3 | @import 'fumadocs-ui/css/preset.css'; 4 | -------------------------------------------------------------------------------- /apps/obby/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://openapi.vercel.sh/vercel.json", 3 | "ignoreCommand": "node scripts/skip-ci.js" 4 | } 5 | -------------------------------------------------------------------------------- /public/logos/obby/obby-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo-transparent.png -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Reporting a Vulnerability 2 | 3 | Please reach out to security@obby.dev with any security concerns or vulnerability reporting. 4 | -------------------------------------------------------------------------------- /public/logos/obby/obby-logo-transparent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eersnington/obby-dev/HEAD/public/logos/obby/obby-logo-transparent.webp -------------------------------------------------------------------------------- /apps/obby/components/model-selector/model-selector-cmdk.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export { ModelSelectorModal } from './cmdk/model-selector-modal'; 4 | -------------------------------------------------------------------------------- /packages/database/migrations/0000_chunky_ozymandias.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE "page" ( 2 | "id" serial PRIMARY KEY NOT NULL, 3 | "name" varchar(255) 4 | ); 5 | -------------------------------------------------------------------------------- /apps/obby/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/obby/ai/messages/metadata.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod/v3'; 2 | 3 | export const metadataSchema = z.object({ 4 | model: z.string(), 5 | }); 6 | 7 | export type Metadata = z.infer; 8 | -------------------------------------------------------------------------------- /packages/design-system/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | '@tailwindcss/postcss': {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /apps/obby/instrumentation-client.ts: -------------------------------------------------------------------------------- 1 | import { initBotId } from 'botid/client/core'; 2 | 3 | initBotId({ 4 | protect: [ 5 | { 6 | path: '/api/chat', 7 | method: 'POST', 8 | }, 9 | ], 10 | }); 11 | -------------------------------------------------------------------------------- /packages/ai/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["**/*.ts", "**/*.tsx"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/testing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["./src/*.tsx"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/database/schema.ts: -------------------------------------------------------------------------------- 1 | import { pgTable, serial, varchar } from 'drizzle-orm/pg-core'; 2 | 3 | export const page = pgTable('page', { 4 | id: serial('id').primaryKey(), 5 | name: varchar('name', { length: 255 }), 6 | }); 7 | -------------------------------------------------------------------------------- /packages/storage/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["**/*.ts", "**/*.tsx"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/database/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["**/*.ts", "**/*.tsx"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/next-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["**/*.ts", "**/*.tsx"], 7 | "exclude": ["node_modules"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/obby/components/tabs/use-tab-state.ts: -------------------------------------------------------------------------------- 1 | import { useQueryState } from 'nuqs'; 2 | 3 | export function useTabState() { 4 | const [tabId, setTabId] = useQueryState('tab', { defaultValue: 'chat' }); 5 | return [tabId, setTabId] as const; 6 | } 7 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | entry: ['scripts/index.ts'], 5 | outDir: 'dist', 6 | sourcemap: false, 7 | minify: true, 8 | dts: true, 9 | format: ['cjs', 'esm'], 10 | }); 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "biomejs.biome", 4 | "bradlc.vscode-tailwindcss", 5 | "Prisma.prisma", 6 | "unifiedjs.vscode-mdx", 7 | "mikestead.dotenv", 8 | "christian-kohler.npm-intellisense" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/web/next.config.mjs: -------------------------------------------------------------------------------- 1 | import { createMDX } from 'fumadocs-mdx/next'; 2 | 3 | const withMDX = createMDX(); 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const config = { 7 | typedRoutes: true, 8 | reactStrictMode: true, 9 | }; 10 | 11 | export default withMDX(config); 12 | -------------------------------------------------------------------------------- /apps/web/app/api/search/route.ts: -------------------------------------------------------------------------------- 1 | import { createFromSource } from 'fumadocs-core/search/server'; 2 | import { source } from '@/lib/source'; 3 | 4 | export const { GET } = createFromSource(source, { 5 | // https://docs.orama.com/docs/orama-js/supported-languages 6 | language: 'english', 7 | }); 8 | -------------------------------------------------------------------------------- /turbo/generators/templates/package.json.hbs: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/{{ name }}", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "clean": "git clean -xdf .cache .turbo dist node_modules", 7 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "git clean -xdf .cache .turbo dist node_modules", 7 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/obby/components/chat/message-spinner.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@repo/design-system/lib/utils'; 2 | import { PulseLoader } from 'react-spinners'; 3 | 4 | export function MessageSpinner({ className }: { className?: string }) { 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /apps/obby/components/chat/types.tsx: -------------------------------------------------------------------------------- 1 | import type { UIMessage } from 'ai'; 2 | import type { DataPart } from '@/ai/messages/data-parts'; 3 | import type { Metadata } from '@/ai/messages/metadata'; 4 | import type { ToolSet } from '@/ai/tools'; 5 | 6 | export type ChatUIMessage = UIMessage; 7 | -------------------------------------------------------------------------------- /packages/database/drizzle.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'drizzle-kit'; 2 | import { keys } from './keys'; 3 | 4 | export default defineConfig({ 5 | schema: './schema.ts', 6 | out: './migrations', 7 | dialect: 'postgresql', 8 | dbCredentials: { 9 | url: keys().DATABASE_URL, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/database/migrations/meta/_journal.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7", 3 | "dialect": "postgresql", 4 | "entries": [ 5 | { 6 | "idx": 0, 7 | "version": "7", 8 | "when": 1754634627346, 9 | "tag": "0000_chunky_ozymandias", 10 | "breakpoints": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /public/logos/ai/anthropic.svg: -------------------------------------------------------------------------------- 1 | Anthropic 2 | -------------------------------------------------------------------------------- /packages/database/keys.ts: -------------------------------------------------------------------------------- 1 | import { createEnv } from '@t3-oss/env-nextjs'; 2 | import { z } from 'zod'; 3 | 4 | export const keys = () => 5 | createEnv({ 6 | server: { 7 | DATABASE_URL: z.string().url(), 8 | }, 9 | runtimeEnv: { 10 | DATABASE_URL: process.env.DATABASE_URL, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/design-system/lib/fonts.ts: -------------------------------------------------------------------------------- 1 | import { cn } from '@repo/design-system/lib/utils'; 2 | import { GeistMono } from 'geist/font/mono'; 3 | import { GeistSans } from 'geist/font/sans'; 4 | 5 | export const fonts = cn( 6 | GeistSans.variable, 7 | GeistMono.variable, 8 | 'touch-manipulation font-sans antialiased' 9 | ); 10 | -------------------------------------------------------------------------------- /apps/web/app/(home)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { HomeLayout } from 'fumadocs-ui/layouts/home'; 2 | import type { ReactNode } from 'react'; 3 | import { baseOptions } from '@/lib/layout.shared'; 4 | 5 | export default function Layout({ children }: { children: ReactNode }) { 6 | return {children}; 7 | } 8 | -------------------------------------------------------------------------------- /apps/web/lib/source.ts: -------------------------------------------------------------------------------- 1 | import { docs } from '@/.source'; 2 | import { loader } from 'fumadocs-core/source'; 3 | 4 | // See https://fumadocs.vercel.app/docs/headless/source-api for more info 5 | export const source = loader({ 6 | // it assigns a URL to your pages 7 | baseUrl: '/docs', 8 | source: docs.toFumadocsSource(), 9 | }); 10 | -------------------------------------------------------------------------------- /turbo/generators/templates/tsconfig.json.hbs: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./*"], 7 | "@repo/*": ["../../packages/*"] 8 | } 9 | }, 10 | "include": ["**/*.ts", "**/*.tsx"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/database/index.ts: -------------------------------------------------------------------------------- 1 | import 'server-only'; 2 | 3 | import { neon } from '@neondatabase/serverless'; 4 | import { drizzle } from 'drizzle-orm/neon-http'; 5 | import { keys } from './keys'; 6 | 7 | export { sql } from 'drizzle-orm'; 8 | 9 | const client = neon(keys().DATABASE_URL); 10 | 11 | export const database = drizzle({ client }); 12 | -------------------------------------------------------------------------------- /packages/ai/lib/models.ts: -------------------------------------------------------------------------------- 1 | import { createOpenAI } from '@ai-sdk/openai'; 2 | import { keys } from '../keys'; 3 | 4 | const openai = createOpenAI({ 5 | apiKey: keys().OPENAI_API_KEY, 6 | compatibility: 'strict', 7 | }); 8 | 9 | export const models = { 10 | chat: openai('gpt-4o-mini'), 11 | embeddings: openai('text-embedding-3-small'), 12 | }; 13 | -------------------------------------------------------------------------------- /packages/storage/keys.ts: -------------------------------------------------------------------------------- 1 | import { createEnv } from '@t3-oss/env-nextjs'; 2 | import { z } from 'zod'; 3 | 4 | export const keys = () => 5 | createEnv({ 6 | server: { 7 | BLOB_READ_WRITE_TOKEN: z.string().optional(), 8 | }, 9 | runtimeEnv: { 10 | BLOB_READ_WRITE_TOKEN: process.env.BLOB_READ_WRITE_TOKEN, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /apps/obby/components/commands-logs/types.ts: -------------------------------------------------------------------------------- 1 | export type Command = { 2 | sandboxId: string; 3 | cmdId: string; 4 | startedAt: number; 5 | command: string; 6 | args: string[]; 7 | exitCode?: number; 8 | logs?: CommandLog[]; 9 | }; 10 | 11 | export type CommandLog = { 12 | data: string; 13 | stream: 'stdout' | 'stderr'; 14 | timestamp: number; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | function AspectRatio({ 6 | ...props 7 | }: React.ComponentProps) { 8 | return 9 | } 10 | 11 | export { AspectRatio } 12 | -------------------------------------------------------------------------------- /apps/obby/components/icons/obby-logo.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | type Props = { 4 | className?: string; 5 | }; 6 | 7 | export function ObbyLogo({ className }: Props) { 8 | return ( 9 | Obby Logo 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/obby/lib/is-relative-url.ts: -------------------------------------------------------------------------------- 1 | import { logger } from './logger'; 2 | 3 | export function isRelativeUrl(url: string): boolean { 4 | try { 5 | new URL(url); 6 | return false; 7 | } catch (error: unknown) { 8 | const message = error instanceof Error ? error.message : String(error); 9 | logger.error('Error parsing URL', message); 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /apps/web/content/docs/test.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Components 3 | description: Components 4 | --- 5 | 6 | ## Code Block 7 | 8 | ```js 9 | console.log('Hello World'); 10 | ``` 11 | 12 | ## Cards 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /apps/web/mdx-components.tsx: -------------------------------------------------------------------------------- 1 | import defaultMdxComponents from 'fumadocs-ui/mdx'; 2 | import type { MDXComponents } from 'mdx/types'; 3 | 4 | // use this function to get MDX components, you will need it for rendering MDX 5 | export function getMDXComponents(components?: MDXComponents): MDXComponents { 6 | return { 7 | ...defaultMdxComponents, 8 | ...components, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /apps/obby/public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/obby/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./*"], 7 | "@repo/*": ["../../packages/*"] 8 | } 9 | }, 10 | "include": [ 11 | "next-env.d.ts", 12 | "next.config.ts", 13 | "**/*.ts", 14 | "**/*.tsx", 15 | ".next/types/**/*.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@repo/design-system/lib/utils" 2 | 3 | function Skeleton({ className, ...props }: React.ComponentProps<"div">) { 4 | return ( 5 |
10 | ) 11 | } 12 | 13 | export { Skeleton } 14 | -------------------------------------------------------------------------------- /apps/obby/next.config.ts: -------------------------------------------------------------------------------- 1 | import { config, withAnalyzer } from '@repo/next-config'; 2 | import { withBotId } from 'botid/next/config'; 3 | import type { NextConfig } from 'next'; 4 | 5 | import { env } from '@/env'; 6 | 7 | let nextConfig: NextConfig = config; 8 | 9 | if (env.ANALYZE === 'true') { 10 | nextConfig = withAnalyzer(nextConfig); 11 | } 12 | 13 | export default withBotId(nextConfig); 14 | -------------------------------------------------------------------------------- /apps/obby/public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/obby/scripts/skip-ci.js: -------------------------------------------------------------------------------- 1 | const { execSync } = require('child_process'); 2 | 3 | const commitMessage = execSync('git log -1 --pretty=%B').toString().trim(); 4 | 5 | if (commitMessage.includes('[skip ci]')) { 6 | console.log('Skipping build due to [skip ci] in commit message.'); 7 | process.exit(0); // this causes Vercel to skip the build 8 | } 9 | 10 | process.exit(1); // continue with build 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - apps/* 3 | - packages/* 4 | overrides: 5 | path-to-regexp@>=4.0.0 <6.3.0: '>=6.3.0' 6 | '@octokit/request-error@>=1.0.0 <5.1.1': '>=5.1.1' 7 | esbuild@<=0.24.2: '>=0.25.0' 8 | '@octokit/request@>=1.0.0 <8.4.1': '>=8.4.1' 9 | '@octokit/plugin-paginate-rest@>=1.0.0 <9.2.2': '>=9.2.2' 10 | cookie@<0.7.0: '>=0.7.0' 11 | prismjs@<1.30.0: '>=1.30.0' 12 | tmp@<=0.2.3: '>=0.2.4' 13 | -------------------------------------------------------------------------------- /packages/design-system/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "plugins": [ 6 | { 7 | "name": "next" 8 | } 9 | ], 10 | "paths": { 11 | "@repo/*": ["../*"], 12 | "@repo/design-system/*": ["./*"] 13 | } 14 | }, 15 | "include": ["**/*.ts", "**/*.tsx"], 16 | "exclude": ["node_modules"] 17 | } 18 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # Maintain dependencies for GitHub Actions 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | open-pull-requests-limit: 10 8 | schedule: 9 | interval: "monthly" 10 | 11 | # Maintain dependencies for npm 12 | - package-ecosystem: "npm" 13 | directory: "/" 14 | open-pull-requests-limit: 10 15 | schedule: 16 | interval: "monthly" 17 | -------------------------------------------------------------------------------- /packages/testing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/testing", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./index.js", 6 | "type": "commonjs", 7 | "scripts": { 8 | "clean": "git clean -xdf .cache .turbo dist node_modules", 9 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 10 | }, 11 | "devDependencies": { 12 | "@vitejs/plugin-react": "^4.5.0", 13 | "vitest": "^3.1.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /apps/web/app/docs/layout.tsx: -------------------------------------------------------------------------------- 1 | import { DocsLayout } from 'fumadocs-ui/layouts/docs'; 2 | import type { ReactNode } from 'react'; 3 | import { baseOptions } from '@/lib/layout.shared'; 4 | import { source } from '@/lib/source'; 5 | 6 | export default function Layout({ children }: { children: ReactNode }) { 7 | return ( 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /apps/obby/components/chat/message-part/text.tsx: -------------------------------------------------------------------------------- 1 | import { Response } from '@repo/design-system/components/ai-elements/response'; 2 | import type { TextUIPart } from 'ai'; 3 | 4 | export function Text({ part }: { part: TextUIPart }) { 5 | return ( 6 |
7 | {part.text} 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/obby/env.ts: -------------------------------------------------------------------------------- 1 | import { keys as ai } from '@repo/ai/keys'; 2 | import { keys as database } from '@repo/database/keys'; 3 | import { keys as core } from '@repo/next-config/keys'; 4 | import { keys as storage } from '@repo/storage/keys'; 5 | import { createEnv } from '@t3-oss/env-nextjs'; 6 | 7 | export const env = createEnv({ 8 | extends: [ai(), core(), database(), storage()], 9 | server: {}, 10 | client: {}, 11 | runtimeEnv: {}, 12 | }); 13 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /apps/obby/components/chat/tool-header.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@repo/design-system/lib/utils'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export function ToolHeader(props: { className?: string; children: ReactNode }) { 5 | return ( 6 |
12 | {props.children} 13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/design-system/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ClassValue } from "clsx"; 2 | import { clsx } from "clsx"; 3 | import { toast } from "sonner"; 4 | import { twMerge } from "tailwind-merge"; 5 | 6 | export const cn = (...inputs: ClassValue[]): string => twMerge(clsx(inputs)); 7 | 8 | export const capitalize = (str: string) => 9 | str.charAt(0).toUpperCase() + str.slice(1); 10 | 11 | export const handleError = (error: unknown): void => { 12 | toast.error(error as string); 13 | }; 14 | -------------------------------------------------------------------------------- /public/logos/ai/groq.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/storage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/storage", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "git clean -xdf .cache .turbo dist node_modules", 7 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 8 | }, 9 | "dependencies": { 10 | "@t3-oss/env-nextjs": "^0.13.4", 11 | "@vercel/blob": "^1.1.1", 12 | "zod": "^3.25.28" 13 | }, 14 | "devDependencies": { 15 | "@repo/typescript-config": "workspace:*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /apps/obby/components/chat/tool-message.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@repo/design-system/lib/utils'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export function ToolMessage(props: { 5 | className?: string; 6 | children: ReactNode; 7 | }) { 8 | return ( 9 |
15 | {props.children} 16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /packages/design-system/providers/theme.tsx: -------------------------------------------------------------------------------- 1 | import type { ThemeProviderProps } from 'next-themes'; 2 | import { ThemeProvider as NextThemeProvider } from 'next-themes'; 3 | 4 | export const ThemeProvider = ({ 5 | children, 6 | ...properties 7 | }: ThemeProviderProps) => ( 8 | 15 | {children} 16 | 17 | ); 18 | -------------------------------------------------------------------------------- /public/logos/ai/xai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/testing/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const path = require('node:path'); 3 | const react = require('@vitejs/plugin-react'); 4 | const { defineConfig } = require('vitest/config'); 5 | 6 | const config = defineConfig({ 7 | plugins: [react()], 8 | test: { 9 | environment: 'jsdom', 10 | }, 11 | resolve: { 12 | alias: { 13 | '@': path.resolve(__dirname, './'), 14 | '@repo': path.resolve(__dirname, '../../packages'), 15 | }, 16 | }, 17 | }); 18 | 19 | module.exports = config; 20 | -------------------------------------------------------------------------------- /packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "allowJs": true, 10 | "jsx": "preserve", 11 | "noEmit": true, 12 | "paths": { 13 | "@/*": ["./*"], 14 | "@repo/*": ["../../packages/*"] 15 | } 16 | }, 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /apps/obby/lib/use-local-storage-value.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useLocalStorageValue(key: string) { 4 | const [value, setValue] = useState(''); 5 | 6 | useEffect(() => { 7 | const storedValue = localStorage.getItem(key); 8 | if (storedValue !== null) { 9 | setValue(storedValue); 10 | } 11 | }, [key]); 12 | 13 | useEffect(() => { 14 | localStorage.setItem(key, value); 15 | }, [key, value]); 16 | 17 | return [value, setValue] as const; 18 | } 19 | -------------------------------------------------------------------------------- /apps/web/content/docs/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Documentation", 3 | "icon": "book", 4 | "items": [ 5 | { 6 | "title": "Overview", 7 | "link": "index" 8 | }, 9 | { 10 | "title": "Setup", 11 | "link": "setup" 12 | }, 13 | { 14 | "title": "Features", 15 | "link": "features" 16 | }, 17 | { 18 | "title": "Usage", 19 | "link": "usage" 20 | }, 21 | { 22 | "title": "Components (demo)", 23 | "link": "test" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /apps/obby/lib/use-index-db-storage.ts: -------------------------------------------------------------------------------- 1 | // storage/indexedDbStorage.ts 2 | import { idbGet, idbPut } from './indexed-db-adapter'; 3 | 4 | export const createIndexedDbStorage = (storeName: string) => ({ 5 | getItem: async (name: string) => { 6 | const value = await idbGet(storeName, name); 7 | return value ?? null; 8 | }, 9 | setItem: async (name: string, value: string) => { 10 | await idbPut(storeName, name, value); 11 | }, 12 | removeItem: async (name: string) => { 13 | await idbPut(storeName, name, null); 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /apps/web/source.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | defineDocs, 4 | frontmatterSchema, 5 | metaSchema, 6 | } from 'fumadocs-mdx/config'; 7 | 8 | // You can customise Zod schemas for frontmatter and `meta.json` here 9 | // see https://fumadocs.dev/docs/mdx/collections#define-docs 10 | export const docs = defineDocs({ 11 | docs: { 12 | schema: frontmatterSchema, 13 | }, 14 | meta: { 15 | schema: metaSchema, 16 | }, 17 | }); 18 | 19 | export default defineConfig({ 20 | mdxOptions: { 21 | // MDX options 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /apps/obby/public/providers/v0.svg: -------------------------------------------------------------------------------- 1 | V0 -------------------------------------------------------------------------------- /apps/obby/app/(main)/preview.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Preview as PreviewComponent } from '@/components/preview/preview'; 4 | import { useSandboxStore } from './state'; 5 | 6 | type Props = { 7 | className?: string; 8 | }; 9 | 10 | export function Preview({ className }: Props) { 11 | const { status, url, sandboxId, paths } = useSandboxStore(); 12 | return ( 13 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/obby/public/providers/groq.svg: -------------------------------------------------------------------------------- 1 | Groq -------------------------------------------------------------------------------- /apps/obby/lib/logger.ts: -------------------------------------------------------------------------------- 1 | import { Effect } from 'effect'; 2 | 3 | const logger = { 4 | info: (message: string, meta?: unknown) => { 5 | Effect.runFork(Effect.logInfo(message, meta)); 6 | }, 7 | debug: (message: string, meta?: unknown) => { 8 | Effect.runFork(Effect.logDebug(message, meta)); 9 | }, 10 | warn: (message: string, meta?: unknown) => { 11 | Effect.runFork(Effect.logWarning(message, meta)); 12 | }, 13 | error: (message: string, meta?: unknown) => { 14 | Effect.runFork(Effect.logError(message, meta)); 15 | }, 16 | }; 17 | 18 | export { logger }; 19 | -------------------------------------------------------------------------------- /apps/obby/app/(main)/file-explorer.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { FileExplorer as FileExplorerComponent } from "@/components/file-explorer/file-explorer"; 4 | import { useSandboxStore } from "./state"; 5 | 6 | type Props = { 7 | className: string; 8 | }; 9 | 10 | export function FileExplorer({ className }: Props) { 11 | const { sandboxId, status, paths } = useSandboxStore(); 12 | return ( 13 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /packages/design-system/index.tsx: -------------------------------------------------------------------------------- 1 | import type { ThemeProviderProps } from 'next-themes'; 2 | import { Toaster } from './components/ui/sonner'; 3 | import { TooltipProvider } from './components/ui/tooltip'; 4 | import { ThemeProvider } from './providers/theme'; 5 | 6 | type DesignSystemProviderProperties = ThemeProviderProps; 7 | 8 | export const DesignSystemProvider = ({ 9 | children, 10 | ...properties 11 | }: DesignSystemProviderProperties) => ( 12 | 13 | {children} 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /apps/obby/public/providers/vercel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | -------------------------------------------------------------------------------- /apps/obby/public/providers/gemini.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/logos/ai/togetherai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/design-system/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "", 8 | "css": "styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@repo/design-system/components", 15 | "utils": "@repo/design-system/lib/utils", 16 | "hooks": "@repo/design-system/hooks", 17 | "lib": "@repo/design-system/lib", 18 | "ui": "@repo/design-system/components/ui" 19 | }, 20 | "iconLibrary": "lucide" 21 | } 22 | -------------------------------------------------------------------------------- /packages/next-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/next-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "git clean -xdf .cache .turbo dist node_modules", 7 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 8 | }, 9 | "devDependencies": { 10 | "@repo/typescript-config": "workspace:*", 11 | "next": "15.5.9" 12 | }, 13 | "dependencies": { 14 | "@next/bundle-analyzer": "15.3.2", 15 | "@prisma/nextjs-monorepo-workaround-plugin": "^6.8.2", 16 | "@t3-oss/env-core": "^0.13.4", 17 | "@t3-oss/env-nextjs": "^0.13.4", 18 | "zod": "^3.25.28" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/obby/.env.example: -------------------------------------------------------------------------------- 1 | # Server 2 | DATABASE_URL="" 3 | 4 | # Client 5 | NEXT_PUBLIC_APP_URL="http://localhost:3000" 6 | NEXT_PUBLIC_DOCS_URL="http://localhost:3001" 7 | 8 | 9 | # AI Provider KEYS (Optional, you can set it in client) 10 | OPENAI_API_KEY="" 11 | AI_GATEWAY_API_KEY="" 12 | ANTHROPIC_API_KEY="" 13 | GOOGLE_GENERATIVE_AI_API_KEY="" 14 | GROQ_API_KEY="" 15 | OPENROUTER_API_KEY="" 16 | 17 | AWS_ACCESS_KEY_ID="" 18 | AWS_SECRET_ACCESS_KEY="" 19 | AWS_REGION="us-east-1" 20 | 21 | FIRECRAWL_API_KEY="" 22 | 23 | # Vercel API keys for Sandbox 24 | VERCEL_TEAM_ID="" 25 | VERCEL_PROJECT_ID="" 26 | 27 | # https://vercel.com/account/settings/tokens 28 | VERCEL_TOKEN="" -------------------------------------------------------------------------------- /apps/obby/components/tabs/tab-content.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { cn } from '@repo/design-system/lib/utils'; 4 | import type { ReactNode } from 'react'; 5 | import { useTabState } from './use-tab-state'; 6 | 7 | type Props = { 8 | className?: string; 9 | children: ReactNode; 10 | tabId: string; 11 | } 12 | 13 | export function TabContent({ children, tabId, className }: Props) { 14 | const [activeTabId] = useTabState(); 15 | return ( 16 |
23 | {children} 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "incremental": false, 10 | "isolatedModules": true, 11 | "lib": ["es2022", "DOM", "DOM.Iterable"], 12 | "module": "NodeNext", 13 | "moduleDetection": "force", 14 | "moduleResolution": "NodeNext", 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022", 19 | "strictNullChecks": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "incremental": false, 10 | "isolatedModules": true, 11 | "lib": [ 12 | "es2022", 13 | "DOM", 14 | "DOM.Iterable" 15 | ], 16 | "module": "NodeNext", 17 | "moduleDetection": "force", 18 | "moduleResolution": "NodeNext", 19 | "resolveJsonModule": true, 20 | "skipLibCheck": true, 21 | "strict": true, 22 | "target": "ES2022", 23 | "strictNullChecks": true 24 | } 25 | } -------------------------------------------------------------------------------- /apps/obby/app/(main)/logs.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { CommandsLogs } from '@/components/commands-logs/commands-logs'; 4 | import { useSandboxStore } from './state'; 5 | 6 | export function Logs(props: { className?: string }) { 7 | const { commands, addLog, upsertCommand } = useSandboxStore(); 8 | return ( 9 | { 13 | upsertCommand(data); 14 | }} 15 | onLog={(data) => { 16 | addLog({ 17 | sandboxId: data.sandboxId, 18 | cmdId: data.cmdId, 19 | log: data.log, 20 | }); 21 | }} 22 | /> 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /apps/obby/components/chat/message-part/reasoning.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ReasoningContent, 3 | ReasoningTrigger, 4 | Reasoning as ReasoningWrapper, 5 | } from '@repo/design-system/components/ai-elements/reasoning'; 6 | import type { ReasoningUIPart } from 'ai'; 7 | 8 | export function Reasoning({ part }: { part: ReasoningUIPart }) { 9 | if (part.state === 'done' && !part.text) { 10 | return null; 11 | } 12 | 13 | return ( 14 | 18 | 19 | {part.text || '_Thinking_'} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /packages/design-system/components/ai-elements/response.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { cn } from '@repo/design-system/lib/utils'; 4 | import { type ComponentProps, memo } from 'react'; 5 | import { Streamdown } from 'streamdown'; 6 | 7 | type ResponseProps = ComponentProps; 8 | 9 | export const Response = memo( 10 | ({ className, ...props }: ResponseProps) => ( 11 | *:first-child]:mt-0 [&>*:last-child]:mb-0', 14 | className 15 | )} 16 | {...props} 17 | /> 18 | ), 19 | (prevProps, nextProps) => prevProps.children === nextProps.children 20 | ); 21 | 22 | Response.displayName = 'Response'; 23 | -------------------------------------------------------------------------------- /packages/design-system/hooks/use-mobile.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const MOBILE_BREAKPOINT = 768; 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState( 7 | undefined 8 | ); 9 | 10 | React.useEffect(() => { 11 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); 12 | const onChange = () => { 13 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 14 | }; 15 | mql.addEventListener('change', onChange); 16 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); 17 | return () => mql.removeEventListener('change', onChange); 18 | }, []); 19 | 20 | return !!isMobile; 21 | } 22 | -------------------------------------------------------------------------------- /apps/obby/components/tabs/tab-group.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { cn } from '@repo/design-system/lib/utils'; 4 | import type { ReactNode } from 'react'; 5 | import { useTabState } from './use-tab-state'; 6 | 7 | type Props = { 8 | className?: string; 9 | children: ReactNode; 10 | tabId: string; 11 | } 12 | 13 | export function TabGroup({ children, tabId, className }: Props) { 14 | const [activeTabId] = useTabState(); 15 | return ( 16 |
23 | {children} 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { Toaster as Sonner, ToasterProps } from "sonner" 5 | 6 | const Toaster = ({ ...props }: ToasterProps) => { 7 | const { theme = "system" } = useTheme() 8 | 9 | return ( 10 | 22 | ) 23 | } 24 | 25 | export { Toaster } 26 | -------------------------------------------------------------------------------- /public/logos/ai/google.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | 6 | import { cn } from "@repo/design-system/lib/utils" 7 | 8 | function Label({ 9 | className, 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 21 | ) 22 | } 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **next-forge version** 14 | I am using version ... 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | **Desktop (please complete the following information):** 30 | - OS: [e.g. MacOS] 31 | - Browser [e.g. chrome v130, safari] 32 | -------------------------------------------------------------------------------- /apps/obby/public/providers/anthropic.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | -------------------------------------------------------------------------------- /packages/design-system/components/ai-elements/image.tsx: -------------------------------------------------------------------------------- 1 | /** biome-ignore-all lint/performance/noImgElement: can't pay bills for vercel image */ 2 | /** biome-ignore-all lint/nursery/useImageSize: intended */ 3 | import { cn } from '@repo/design-system/lib/utils'; 4 | import type { Experimental_GeneratedImage } from 'ai'; 5 | 6 | export type ImageProps = Experimental_GeneratedImage & { 7 | className?: string; 8 | alt?: string; 9 | }; 10 | 11 | export const Image = ({ 12 | base64, 13 | uint8Array, 14 | mediaType, 15 | ...props 16 | }: ImageProps) => ( 17 | {props.alt} 26 | ); 27 | -------------------------------------------------------------------------------- /public/logos/ai/fireworks.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /apps/obby/app/(main)/header.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@repo/design-system/lib/utils"; 2 | import Link from "next/link"; 3 | import { ObbyLogo } from "@/components/icons/obby-logo"; 4 | 5 | type Props = { 6 | className?: string; 7 | }; 8 | 9 | export function Header({ className }: Props) { 10 | return ( 11 |
12 |
13 | 14 | 15 | 16 | 0bby 17 | 18 | 19 |
20 |
21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/database/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/database", 3 | "version": "0.0.0", 4 | "main": "./index.ts", 5 | "types": "./index.ts", 6 | "scripts": { 7 | "clean": "git clean -xdf .cache .turbo dist node_modules", 8 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 9 | }, 10 | "dependencies": { 11 | "@neondatabase/serverless": "^1.0.0", 12 | "@t3-oss/env-nextjs": "^0.13.4", 13 | "drizzle-orm": "^0.44.4", 14 | "server-only": "^0.0.1", 15 | "undici": "^7.10.0", 16 | "ws": "^8.18.2", 17 | "zod": "^3.25.28" 18 | }, 19 | "devDependencies": { 20 | "@repo/typescript-config": "workspace:*", 21 | "@types/node": "22.15.21", 22 | "@types/ws": "^8.18.1", 23 | "bufferutil": "^4.0.9", 24 | "drizzle-kit": "^0.31.4", 25 | "typescript": "^5.8.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { program } from 'commander'; 4 | import { initialize } from './initialize.js'; 5 | import { update } from './update.js'; 6 | 7 | program 8 | .command('init') 9 | .description('Initialize a new next-forge project') 10 | .option('--name ', 'Name of the project') 11 | .option( 12 | '--package-manager ', 13 | 'Package manager to use (npm, yarn, bun, pnpm)' 14 | ) 15 | .option('--disable-git', 'Disable git initialization') 16 | .action(initialize); 17 | 18 | program 19 | .command('update') 20 | .description('Update the project from one version to another') 21 | .option('--from ', 'Version to update from e.g. 1.0.0') 22 | .option('--to ', 'Version to update to e.g. 2.0.0') 23 | .action(update); 24 | 25 | program.parse(process.argv); 26 | -------------------------------------------------------------------------------- /apps/web/lib/layout.shared.tsx: -------------------------------------------------------------------------------- 1 | import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; 2 | import Image from 'next/image'; 3 | 4 | /** 5 | * Shared layout configurations 6 | * 7 | * you can customise layouts individually from: 8 | * Home Layout: app/(home)/layout.tsx 9 | * Docs Layout: app/docs/layout.tsx 10 | */ 11 | export function baseOptions(): BaseLayoutProps { 12 | return { 13 | nav: { 14 | title: ( 15 | <> 16 | Logo 17 | 0bby 18 | 19 | ), 20 | }, 21 | // see https://fumadocs.dev/docs/ui/navigation/links 22 | links: [ 23 | { 24 | text: 'GitHub', 25 | url: 'https://github.com/eersnington/obby-dev', 26 | active: 'nested-url', 27 | }, 28 | ], 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obby-web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build", 7 | "dev": "next dev -p 3001 --turbo", 8 | "start": "next start", 9 | "postinstall": "fumadocs-mdx" 10 | }, 11 | "dependencies": { 12 | "@databuddy/sdk": "^2.0.0", 13 | "fumadocs-core": "15.7.7", 14 | "fumadocs-mdx": "11.8.2", 15 | "fumadocs-ui": "15.7.7", 16 | "next": "15.5.9", 17 | "react": "^19.1.0", 18 | "react-dom": "^19.1.0" 19 | }, 20 | "devDependencies": { 21 | "@tailwindcss/postcss": "^4.1.12", 22 | "@types/mdx": "^2.0.13", 23 | "@types/node": "22.15.21", 24 | "@types/react": "^19.1.5", 25 | "@types/react-dom": "^19.1.5", 26 | "postcss": "^8.5.6", 27 | "tailwindcss": "^4.1.12", 28 | "typescript": "^5.9.2" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "ESNext", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "noEmit": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "preserve", 17 | "incremental": true, 18 | "paths": { 19 | "@/.source": ["./.source/index.ts"], 20 | "@/*": ["./*"] 21 | }, 22 | "plugins": [ 23 | { 24 | "name": "next" 25 | } 26 | ] 27 | }, 28 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /packages/ai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/ai", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "clean": "git clean -xdf .cache .turbo dist node_modules", 7 | "typecheck": "tsc --noEmit --emitDeclarationOnly false" 8 | }, 9 | "dependencies": { 10 | "@ai-sdk/gateway": "^1.0.4", 11 | "@ai-sdk/openai": "^2.0.8", 12 | "@ai-sdk/react": "2.0.0-beta.29", 13 | "@ai-sdk/vercel": "1.0.0-alpha.7", 14 | "@t3-oss/env-nextjs": "^0.13.4", 15 | "ai": "5.0.0-beta.29", 16 | "react": "^19.1.0", 17 | "react-markdown": "^10.1.0", 18 | "tailwind-merge": "^3.3.0", 19 | "zod": "^3.25.28" 20 | }, 21 | "devDependencies": { 22 | "@repo/typescript-config": "workspace:*", 23 | "@types/node": "22.15.21", 24 | "@types/react": "19.1.5", 25 | "@types/react-dom": "^19.1.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please provide a brief description of the changes introduced in this pull request. 4 | 5 | ## Related Issues 6 | 7 | Closes # 8 | 9 | ## Checklist 10 | 11 | - [ ] My code follows the code style of this project. 12 | - [ ] I have performed a self-review of my code. 13 | - [ ] I have commented my code, particularly in hard-to-understand areas. 14 | - [ ] I have updated the documentation, if necessary. 15 | - [ ] I have added tests that prove my fix is effective or my feature works. 16 | - [ ] New and existing tests pass locally with my changes. 17 | 18 | ## Screenshots (if applicable) 19 | 20 | 21 | 22 | ## Additional Notes 23 | 24 | 25 | -------------------------------------------------------------------------------- /apps/obby/components/panels/panels.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@repo/design-system/lib/utils'; 2 | import type { ReactNode } from 'react'; 3 | 4 | type Props = { 5 | className?: string; 6 | children: ReactNode; 7 | }; 8 | 9 | export function Panel({ className, children }: Props) { 10 | return ( 11 |
17 | {children} 18 |
19 | ); 20 | } 21 | 22 | export function PanelHeader({ className, children }: Props) { 23 | return ( 24 |
30 | {children} 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 5 | 6 | import { cn } from "@repo/design-system/lib/utils" 7 | 8 | function Separator({ 9 | className, 10 | orientation = "horizontal", 11 | decorative = true, 12 | ...props 13 | }: React.ComponentProps) { 14 | return ( 15 | 25 | ) 26 | } 27 | 28 | export { Separator } 29 | -------------------------------------------------------------------------------- /packages/design-system/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@repo/design-system/lib/utils" 4 | 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 6 | return ( 7 |