diff --git a/rkix-studio/README.md b/rkix-studio/README.md new file mode 100644 index 0000000..f2a6ceb --- /dev/null +++ b/rkix-studio/README.md @@ -0,0 +1,20 @@ +# RKix Studio + +AI-powered coding assistant platform with GitHub integration. + +## Features +- 💬 AI Chat - Interact with GPT-4o for coding help +- 📋 Task Management - Create and track coding tasks +- 🔗 GitHub Integration - Browse repos, edit files, create branches & PRs +- 🔐 Authentication - Magic Link & Google Sign-in + +## Tech Stack +- React + TypeScript +- Tailwind CSS + shadcn/ui +- OpenAI GPT-4o +- GitHub API +- Zite Database + +## Structure +- `src/components/` - React components (Layout, ChatView, ReposView, etc.) +- `src/api/` - Backend endpoints (chat, tasks, GitHub operations) diff --git a/rkix-studio/src/App.tsx b/rkix-studio/src/App.tsx new file mode 100644 index 0000000..8e3b64c --- /dev/null +++ b/rkix-studio/src/App.tsx @@ -0,0 +1,27 @@ +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; +import { Toaster } from '@/components/ui/sonner'; +import Layout from '@/components/Layout'; +import ChatView from '@/components/ChatView'; +import TasksView from '@/components/TasksView'; +import TaskDetailView from '@/components/TaskDetailView'; +import ReposView from '@/components/ReposView'; +import RepoDetailView from '@/components/RepoDetailView'; + +export default function App() { + return ( + + + + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + + ); +} \ No newline at end of file diff --git a/rkix-studio/src/api/createChat.ts b/rkix-studio/src/api/createChat.ts new file mode 100644 index 0000000..91ce11b --- /dev/null +++ b/rkix-studio/src/api/createChat.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; +import { createEndpoint, Chats } from 'zite-integrations-backend-sdk'; + +export default createEndpoint({ + description: 'Create a new chat', + inputSchema: z.object({ title: z.string().optional() }), + outputSchema: z.object({ id: z.string(), title: z.string(), createdAt: z.string().optional() }), + execute: async ({ input }) => { + const chat = await Chats.create({ record: { title: input.title || 'New Chat', createdAt: new Date().toISOString() } }); + return { id: chat.id, title: chat.title || 'New Chat', createdAt: chat.createdAt }; + }, +}); \ No newline at end of file diff --git a/rkix-studio/src/api/deleteChat.ts b/rkix-studio/src/api/deleteChat.ts new file mode 100644 index 0000000..5cfdc63 --- /dev/null +++ b/rkix-studio/src/api/deleteChat.ts @@ -0,0 +1,14 @@ +import { z } from 'zod'; +import { createEndpoint, Chats, Messages } from 'zite-integrations-backend-sdk'; + +export default createEndpoint({ + description: 'Delete a chat and its messages', + inputSchema: z.object({ chatId: z.string() }), + outputSchema: z.object({ success: z.boolean() }), + execute: async ({ input }) => { + const { records: msgs } = await Messages.findAll({ filters: { chat: input.chatId } }); + for (const m of msgs) { await Messages.delete({ id: m.id }); } + await Chats.delete({ id: input.chatId }); + return { success: true }; + }, +}); \ No newline at end of file diff --git a/rkix-studio/src/api/getChats.ts b/rkix-studio/src/api/getChats.ts new file mode 100644 index 0000000..5629ef5 --- /dev/null +++ b/rkix-studio/src/api/getChats.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; +import { createEndpoint, Chats } from 'zite-integrations-backend-sdk'; + +export default createEndpoint({ + description: 'Get all chats sorted by creation date', + inputSchema: z.object({}), + outputSchema: z.object({ chats: z.array(z.object({ id: z.string(), title: z.string(), createdAt: z.string().optional() })) }), + execute: async () => { + const { records } = await Chats.findAll({ limit: 50 }); + const sorted = records.sort((a, b) => { + const da = a.createdAt ? new Date(a.createdAt).getTime() : 0; + const db = b.createdAt ? new Date(b.createdAt).getTime() : 0; + return db - da; + }); + return { chats: sorted.map(c => ({ id: c.id, title: c.title || 'New Chat', createdAt: c.createdAt })) }; + }, +}); \ No newline at end of file diff --git a/rkix-studio/src/api/getMessages.ts b/rkix-studio/src/api/getMessages.ts new file mode 100644 index 0000000..d591cf8 --- /dev/null +++ b/rkix-studio/src/api/getMessages.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; +import { createEndpoint, Messages } from 'zite-integrations-backend-sdk'; + +export default createEndpoint({ + description: 'Get messages for a chat', + inputSchema: z.object({ chatId: z.string() }), + outputSchema: z.object({ messages: z.array(z.object({ id: z.string(), content: z.string(), role: z.string(), createdAt: z.string().optional() })) }), + execute: async ({ input }) => { + const { records } = await Messages.findAll({ filters: { chat: input.chatId }, limit: 200 }); + const sorted = records.sort((a, b) => { + const da = a.createdAt ? new Date(a.createdAt).getTime() : 0; + const db = b.createdAt ? new Date(b.createdAt).getTime() : 0; + return da - db; + }); + return { messages: sorted.map(m => ({ id: m.id, content: m.content || '', role: (m.role || 'User').toLowerCase(), createdAt: m.createdAt })) }; + }, +}); \ No newline at end of file diff --git a/rkix-studio/src/api/getTasks.ts b/rkix-studio/src/api/getTasks.ts new file mode 100644 index 0000000..b8e381f --- /dev/null +++ b/rkix-studio/src/api/getTasks.ts @@ -0,0 +1,19 @@ +import { z } from 'zod'; +import { createEndpoint, Tasks } from 'zite-integrations-backend-sdk'; + +export default createEndpoint({ + description: 'Get all tasks', + inputSchema: z.object({ status: z.string().optional() }), + outputSchema: z.object({ tasks: z.array(z.object({ id: z.string(), title: z.string(), status: z.string(), context: z.string().optional(), log: z.string().optional(), filesChanged: z.string().optional(), createdAt: z.string().optional() })) }), + execute: async ({ input }) => { + const filters: Record = {}; + if (input.status) filters.status = input.status; + const { records } = await Tasks.findAll({ filters, limit: 100 }); + const sorted = records.sort((a, b) => { + const da = a.createdAt ? new Date(a.createdAt).getTime() : 0; + const db = b.createdAt ? new Date(b.createdAt).getTime() : 0; + return db - da; + }); + return { tasks: sorted.map(t => ({ id: t.id, title: t.title || 'Untitled Task', status: (t.status || 'Queued').toLowerCase(), context: t.context, log: t.log, filesChanged: t.filesChanged, createdAt: t.createdAt })) }; + }, +}); \ No newline at end of file