Skip to content

Commit

Permalink
fix: remove monorepo
Browse files Browse the repository at this point in the history
  • Loading branch information
samdenty committed Sep 25, 2024
1 parent d364a6f commit 6fb59d2
Show file tree
Hide file tree
Showing 137 changed files with 191 additions and 1,226 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ jobs:
with:
wranglerVersion: '* -w'
packageManager: pnpm
workingDirectory: 'packages/bolt'
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy
Expand Down
77 changes: 53 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,84 @@
# Bolt Monorepo
# Bolt

Welcome to the Bolt monorepo! This repository contains the codebase for Bolt, an AI assistant developed by StackBlitz.
Bolt is an AI assistant developed by StackBlitz. This package contains the UI interface for Bolt as well as the server components, built using [Remix Run](https://remix.run/).

## Repository Structure
## Prerequisites

Currently, this monorepo contains a single package:

- [`bolt`](packages/bolt): The main package containing the UI interface for Bolt as well as the server components.

As the project grows, additional packages may be added to this workspace.

## Getting Started

### Prerequisites
Before you begin, ensure you have the following installed:

- Node.js (v20.15.1)
- pnpm (v9.4.0)

### Installation
## Setup

1. Clone the repository:
1. Clone the repository (if you haven't already):

```bash
git clone https://github.com/stackblitz/bolt.git
cd bolt
```

2. Install dependencies:

```bash
pnpm i
pnpm install
```

3. Create a `.env.local` file in the root directory and add your Anthropic API key:

```
ANTHROPIC_API_KEY=XXX
```

Optionally, you an set the debug level or disable authentication:

```
VITE_LOG_LEVEL=debug
VITE_DISABLE_AUTH=1
```

3. Optionally, init git hooks:
If you want to run authentication against a local StackBlitz instance, add:

```
VITE_CLIENT_ORIGIN=https://local.stackblitz.com:3000
```

**Important**: Never commit your `.env.local` file to version control. It's already included in .gitignore.

## Available Scripts

- `pnpm run dev`: Starts the development server.
- `pnpm run build`: Builds the project.
- `pnpm run start`: Runs the built application locally using Wrangler Pages. This script uses `bindings.sh` to set up necessary bindings so you don't have to duplicate environment variables.
- `pnpm run preview`: Builds the project and then starts it locally, useful for testing the production build. Note, HTTP streaming currently doesn't work as expected with `wrangler pages dev`.
- `pnpm test:` Runs the test suite using Vitest.
- `pnpm run typecheck`: Runs TypeScript type checking.
- `pnpm run typegen`: Generates TypeScript types using Wrangler.
- `pnpm run deploy`: Builds the project and deploys it to Cloudflare Pages.

## Development

To start the development server:

```bash
pnpmx husky
pnpm run dev
```

### Development
This will start the Remix Vite development server.

To start developing the Bolt UI:
## Testing

1. Navigate to the bolt package:
Run the test suite with:

```bash
cd packages/bolt
pnpm test
```

2. Start the development server:
## Deployment

To deploy the application to Cloudflare Pages:

```bash
pnpm run dev
pnpm run deploy
```

Make sure you have the necessary permissions and Wrangler is correctly configured for your Cloudflare account.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useChat } from 'ai/react';
import { useAnimate } from 'framer-motion';
import { memo, useEffect, useRef, useState } from 'react';
import { cssTransition, toast, ToastContainer } from 'react-toastify';
import { AnalyticsAction, AnalyticsTrackEvent, sendAnalyticsEvent } from '~/lib/analytics';
import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
import { useChatHistory } from '~/lib/persistence';
import { chatStore } from '~/lib/stores/chat';
Expand Down Expand Up @@ -195,18 +194,6 @@ export const ChatImpl = memo(({ initialMessages, storeMessageHistory }: ChatProp
resetEnhancer();

textareaRef.current?.blur();

const event = messages.length === 0 ? AnalyticsTrackEvent.ChatCreated : AnalyticsTrackEvent.MessageSent;

sendAnalyticsEvent({
action: AnalyticsAction.Track,
payload: {
event,
properties: {
message: _input,
},
},
});
};

const [messageRef, scrollRef] = useSnapScroll();
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useStore } from '@nanostores/react';
import { chatStore } from '~/lib/stores/chat';
import { workbenchStore } from '~/lib/stores/workbench';
import { classNames } from '~/utils/classNames';
import { OpenStackBlitz } from './OpenStackBlitz.client';

interface HeaderActionButtonsProps {}

Expand Down Expand Up @@ -40,9 +39,6 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
<div className="i-ph:code-bold" />
</Button>
</div>
<div className="flex ml-2">
<OpenStackBlitz />
</div>
</div>
);
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
38 changes: 38 additions & 0 deletions app/lib/analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { CLIENT_ORIGIN } from '~/lib/constants';
import { request as doRequest } from '~/lib/fetch';

export interface Identity {
userId?: string | null;
guestId?: string | null;
segmentWriteKey?: string | null;
avatar?: string;
}

const MESSAGE_PREFIX = 'Bolt';

export enum AnalyticsTrackEvent {
MessageSent = `${MESSAGE_PREFIX} Message Sent`,
MessageComplete = `${MESSAGE_PREFIX} Message Complete`,
ChatCreated = `${MESSAGE_PREFIX} Chat Created`,
}

export async function identifyUser(access: string): Promise<Identity | undefined> {
const response = await doRequest(`${CLIENT_ORIGIN}/api/identify`, {
method: 'GET',
headers: { authorization: `Bearer ${access}` },
});

const body = await response.json();

if (!response.ok) {
return undefined;
}

// convert numerical identity values to strings
const stringified = Object.entries(body).map(([key, value]) => [
key,
typeof value === 'number' ? value.toString() : value,
]);

return Object.fromEntries(stringified) as Identity;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useState, useEffect } from 'react';
import { atom } from 'nanostores';
import type { Message } from 'ai';
import { toast } from 'react-toastify';
import { AnalyticsAction, sendAnalyticsEvent } from '~/lib/analytics';
import { workbenchStore } from '~/lib/stores/workbench';
import { getMessages, getNextId, getUrlId, openDatabase, setMessages } from './db';

Expand Down Expand Up @@ -107,14 +106,4 @@ function navigateChat(nextId: string) {
url.pathname = `/chat/${nextId}`;

window.history.replaceState({}, '', url);

// since the `replaceState` call doesn't trigger a page reload, we need to manually log this event
sendAnalyticsEvent({
action: AnalyticsAction.Page,
payload: {
properties: {
url: url.href,
},
},
});
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 1 addition & 17 deletions packages/bolt/app/root.tsx → app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { useStore } from '@nanostores/react';
import type { LinksFunction } from '@remix-run/cloudflare';
import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLocation } from '@remix-run/react';
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react';
import tailwindReset from '@unocss/reset/tailwind-compat.css?url';
import { useEffect } from 'react';
import { sendAnalyticsEvent, AnalyticsAction } from './lib/analytics';
import { themeStore } from './lib/stores/theme';
import { stripIndents } from './utils/stripIndent';

Expand Down Expand Up @@ -55,20 +53,6 @@ const inlineThemeCode = stripIndents`
export function Layout({ children }: { children: React.ReactNode }) {
const theme = useStore(themeStore);

const { pathname } = useLocation();

// log page events when the window location changes
useEffect(() => {
sendAnalyticsEvent({
action: AnalyticsAction.Page,
payload: {
properties: {
url: window.location.href,
},
},
});
}, [pathname]);

return (
<html lang="en" data-theme={theme}>
<head>
Expand Down
File renamed without changes.
17 changes: 2 additions & 15 deletions packages/bolt/app/routes/api.chat.ts → app/routes/api.chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,21 @@ import { MAX_RESPONSE_SEGMENTS, MAX_TOKENS } from '~/lib/.server/llm/constants';
import { CONTINUE_PROMPT } from '~/lib/.server/llm/prompts';
import { streamText, type Messages, type StreamingOptions } from '~/lib/.server/llm/stream-text';
import SwitchableStream from '~/lib/.server/llm/switchable-stream';
import type { Session } from '~/lib/.server/sessions';
import { AnalyticsAction, AnalyticsTrackEvent, sendEventInternal } from '~/lib/analytics';

export async function action(args: ActionFunctionArgs) {
return actionWithAuth(args, chatAction);
}

async function chatAction({ context, request }: ActionFunctionArgs, session: Session) {
async function chatAction({ context, request }: ActionFunctionArgs) {
const { messages } = await request.json<{ messages: Messages }>();

const stream = new SwitchableStream();

try {
const options: StreamingOptions = {
toolChoice: 'none',
onFinish: async ({ text: content, finishReason, usage }) => {
onFinish: async ({ text: content, finishReason }) => {
if (finishReason !== 'length') {
await sendEventInternal(session, {
action: AnalyticsAction.Track,
payload: {
event: AnalyticsTrackEvent.MessageComplete,
properties: {
usage,
finishReason,
},
},
});

return stream.close();
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default [
},
{
files: [...tsFileExtensions, ...jsFileExtensions, '**/*.tsx'],
ignores: ['packages/bolt/functions/*'],
ignores: ['functions/*'],
rules: {
'no-restricted-imports': [
'error',
Expand Down
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
Loading

0 comments on commit 6fb59d2

Please sign in to comment.