mirror of
https://github.com/stackblitz/bolt.new
synced 2025-06-26 18:17:50 +00:00
Merge f17cefbb52
into eda10b1212
This commit is contained in:
commit
fc14fc739d
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
@ -1,2 +1,2 @@
|
|||||||
nodejs 20.15.1
|
nodejs 22.14.0
|
||||||
pnpm 9.4.0
|
pnpm 10.12.3
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
import React, { type RefCallback } from 'react';
|
import React, { type RefCallback } from 'react';
|
||||||
import { ClientOnly } from 'remix-utils/client-only';
|
import { ClientOnly } from 'remix-utils/client-only';
|
||||||
|
import styles from './BaseChat.module.scss';
|
||||||
|
import { Messages } from './Messages.client';
|
||||||
|
import { SendButton } from './SendButton.client';
|
||||||
import { Menu } from '~/components/sidebar/Menu.client';
|
import { Menu } from '~/components/sidebar/Menu.client';
|
||||||
import { IconButton } from '~/components/ui/IconButton';
|
import { IconButton } from '~/components/ui/IconButton';
|
||||||
import { Workbench } from '~/components/workbench/Workbench.client';
|
import { Workbench } from '~/components/workbench/Workbench.client';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { Messages } from './Messages.client';
|
|
||||||
import { SendButton } from './SendButton.client';
|
|
||||||
|
|
||||||
import styles from './BaseChat.module.scss';
|
|
||||||
|
|
||||||
interface BaseChatProps {
|
interface BaseChatProps {
|
||||||
textareaRef?: React.RefObject<HTMLTextAreaElement> | undefined;
|
textareaRef?: React.RefObject<HTMLTextAreaElement | null> | undefined;
|
||||||
messageRef?: RefCallback<HTMLDivElement> | undefined;
|
messageRef?: RefCallback<HTMLDivElement> | undefined;
|
||||||
scrollRef?: RefCallback<HTMLDivElement> | undefined;
|
scrollRef?: RefCallback<HTMLDivElement> | undefined;
|
||||||
showChat?: boolean;
|
showChat?: boolean;
|
||||||
|
@ -4,6 +4,7 @@ import { useChat } from 'ai/react';
|
|||||||
import { useAnimate } from 'framer-motion';
|
import { useAnimate } from 'framer-motion';
|
||||||
import { memo, useEffect, useRef, useState } from 'react';
|
import { memo, useEffect, useRef, useState } from 'react';
|
||||||
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
import { cssTransition, toast, ToastContainer } from 'react-toastify';
|
||||||
|
import { BaseChat } from './BaseChat';
|
||||||
import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
|
import { useMessageParser, usePromptEnhancer, useShortcuts, useSnapScroll } from '~/lib/hooks';
|
||||||
import { useChatHistory } from '~/lib/persistence';
|
import { useChatHistory } from '~/lib/persistence';
|
||||||
import { chatStore } from '~/lib/stores/chat';
|
import { chatStore } from '~/lib/stores/chat';
|
||||||
@ -11,7 +12,6 @@ import { workbenchStore } from '~/lib/stores/workbench';
|
|||||||
import { fileModificationsToHTML } from '~/utils/diff';
|
import { fileModificationsToHTML } from '~/utils/diff';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
||||||
import { BaseChat } from './BaseChat';
|
|
||||||
|
|
||||||
const toastAnimation = cssTransition({
|
const toastAnimation = cssTransition({
|
||||||
enter: 'animated fadeInRight',
|
enter: 'animated fadeInRight',
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { memo, useEffect, useState } from 'react';
|
import { memo, useEffect, useState } from 'react';
|
||||||
import { bundledLanguages, codeToHtml, isSpecialLang, type BundledLanguage, type SpecialLanguage } from 'shiki';
|
import { bundledLanguages, codeToHtml, isSpecialLang, type BundledLanguage, type SpecialLanguage } from 'shiki';
|
||||||
|
import styles from './CodeBlock.module.scss';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
|
|
||||||
import styles from './CodeBlock.module.scss';
|
|
||||||
|
|
||||||
const logger = createScopedLogger('CodeBlock');
|
const logger = createScopedLogger('CodeBlock');
|
||||||
|
|
||||||
interface CodeBlockProps {
|
interface CodeBlockProps {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import ReactMarkdown, { type Components } from 'react-markdown';
|
import ReactMarkdown, { type Components } from 'react-markdown';
|
||||||
import type { BundledLanguage } from 'shiki';
|
import type { BundledLanguage } from 'shiki';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
|
||||||
import { rehypePlugins, remarkPlugins, allowedHTMLElements } from '~/utils/markdown';
|
|
||||||
import { Artifact } from './Artifact';
|
import { Artifact } from './Artifact';
|
||||||
import { CodeBlock } from './CodeBlock';
|
import { CodeBlock } from './CodeBlock';
|
||||||
|
|
||||||
import styles from './Markdown.module.scss';
|
import styles from './Markdown.module.scss';
|
||||||
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
|
import { rehypePlugins, remarkPlugins, allowedHTMLElements } from '~/utils/markdown';
|
||||||
|
|
||||||
const logger = createScopedLogger('MarkdownComponent');
|
const logger = createScopedLogger('MarkdownComponent');
|
||||||
|
|
||||||
@ -61,14 +61,15 @@ export const Markdown = memo(({ children, html = false, limitedMarkdown = false
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<div className={styles.MarkdownContent}>
|
||||||
allowedElements={allowedHTMLElements}
|
<ReactMarkdown
|
||||||
className={styles.MarkdownContent}
|
allowedElements={allowedHTMLElements}
|
||||||
components={components}
|
components={components}
|
||||||
remarkPlugins={remarkPlugins(limitedMarkdown)}
|
remarkPlugins={remarkPlugins(limitedMarkdown)}
|
||||||
rehypePlugins={rehypePlugins(html)}
|
rehypePlugins={rehypePlugins(html)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { classNames } from '~/utils/classNames';
|
|
||||||
import { AssistantMessage } from './AssistantMessage';
|
import { AssistantMessage } from './AssistantMessage';
|
||||||
import { UserMessage } from './UserMessage';
|
import { UserMessage } from './UserMessage';
|
||||||
|
import { classNames } from '~/utils/classNames';
|
||||||
|
|
||||||
interface MessagesProps {
|
interface MessagesProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { modificationsRegex } from '~/utils/diff';
|
|
||||||
import { Markdown } from './Markdown';
|
import { Markdown } from './Markdown';
|
||||||
|
import { modificationsRegex } from '~/utils/diff';
|
||||||
|
|
||||||
interface UserMessageProps {
|
interface UserMessageProps {
|
||||||
content: string;
|
content: string;
|
||||||
|
@ -17,14 +17,14 @@ import {
|
|||||||
type Tooltip,
|
type Tooltip,
|
||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { memo, useEffect, useRef, useState, type MutableRefObject } from 'react';
|
import { memo, useEffect, useRef, useState, type MutableRefObject } from 'react';
|
||||||
import type { Theme } from '~/types/theme';
|
|
||||||
import { classNames } from '~/utils/classNames';
|
|
||||||
import { debounce } from '~/utils/debounce';
|
|
||||||
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
|
||||||
import { BinaryContent } from './BinaryContent';
|
import { BinaryContent } from './BinaryContent';
|
||||||
import { getTheme, reconfigureTheme } from './cm-theme';
|
import { getTheme, reconfigureTheme } from './cm-theme';
|
||||||
import { indentKeyBinding } from './indent';
|
import { indentKeyBinding } from './indent';
|
||||||
import { getLanguage } from './languages';
|
import { getLanguage } from './languages';
|
||||||
|
import type { Theme } from '~/types/theme';
|
||||||
|
import { classNames } from '~/utils/classNames';
|
||||||
|
import { debounce } from '~/utils/debounce';
|
||||||
|
import { createScopedLogger, renderLogger } from '~/utils/logger';
|
||||||
|
|
||||||
const logger = createScopedLogger('CodeMirrorEditor');
|
const logger = createScopedLogger('CodeMirrorEditor');
|
||||||
|
|
||||||
@ -135,10 +135,10 @@ export const CodeMirrorEditor = memo(
|
|||||||
const [languageCompartment] = useState(new Compartment());
|
const [languageCompartment] = useState(new Compartment());
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const viewRef = useRef<EditorView>();
|
const viewRef = useRef<EditorView | null>(null);
|
||||||
const themeRef = useRef<Theme>();
|
const themeRef = useRef<Theme | null>(null);
|
||||||
const docRef = useRef<EditorDocument>();
|
const docRef = useRef<EditorDocument | null>(null);
|
||||||
const editorStatesRef = useRef<EditorStates>();
|
const editorStatesRef = useRef<EditorStates | null>(null);
|
||||||
const onScrollRef = useRef(onScroll);
|
const onScrollRef = useRef(onScroll);
|
||||||
const onChangeRef = useRef(onChange);
|
const onChangeRef = useRef(onChange);
|
||||||
const onSaveRef = useRef(onSave);
|
const onSaveRef = useRef(onSave);
|
||||||
@ -151,7 +151,7 @@ export const CodeMirrorEditor = memo(
|
|||||||
onScrollRef.current = onScroll;
|
onScrollRef.current = onScroll;
|
||||||
onChangeRef.current = onChange;
|
onChangeRef.current = onChange;
|
||||||
onSaveRef.current = onSave;
|
onSaveRef.current = onSave;
|
||||||
docRef.current = doc;
|
docRef.current = doc ?? null;
|
||||||
themeRef.current = theme;
|
themeRef.current = theme;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ export const CodeMirrorEditor = memo(
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
viewRef.current?.destroy();
|
viewRef.current?.destroy();
|
||||||
viewRef.current = undefined;
|
viewRef.current = null;
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Compartment, type Extension } from '@codemirror/state';
|
import { Compartment, type Extension } from '@codemirror/state';
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import { vscodeDark, vscodeLight } from '@uiw/codemirror-theme-vscode';
|
import { vscodeDark, vscodeLight } from '@uiw/codemirror-theme-vscode';
|
||||||
import type { Theme } from '~/types/theme.js';
|
|
||||||
import type { EditorSettings } from './CodeMirrorEditor.js';
|
import type { EditorSettings } from './CodeMirrorEditor.js';
|
||||||
|
import type { Theme } from '~/types/theme.js';
|
||||||
|
|
||||||
export const darkTheme = EditorView.theme({}, { dark: true });
|
export const darkTheme = EditorView.theme({}, { dark: true });
|
||||||
export const themeSelection = new Compartment();
|
export const themeSelection = new Compartment();
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { ClientOnly } from 'remix-utils/client-only';
|
import { ClientOnly } from 'remix-utils/client-only';
|
||||||
import { chatStore } from '~/lib/stores/chat';
|
|
||||||
import { classNames } from '~/utils/classNames';
|
|
||||||
import { HeaderActionButtons } from './HeaderActionButtons.client';
|
import { HeaderActionButtons } from './HeaderActionButtons.client';
|
||||||
import { ChatDescription } from '~/lib/persistence/ChatDescription.client';
|
import { ChatDescription } from '~/lib/persistence/ChatDescription.client';
|
||||||
|
import { chatStore } from '~/lib/stores/chat';
|
||||||
|
import { classNames } from '~/utils/classNames';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const chat = useStore(chatStore);
|
const chat = useStore(chatStore);
|
||||||
|
@ -23,7 +23,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="i-bolt:chat text-sm" />
|
<div className="i-ph:chat-text-bold" />
|
||||||
</Button>
|
</Button>
|
||||||
<div className="w-[1px] bg-bolt-elements-borderColor" />
|
<div className="w-[1px] bg-bolt-elements-borderColor" />
|
||||||
<Button
|
<Button
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { motion, type Variants } from 'framer-motion';
|
import { motion, type Variants } from 'framer-motion';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { HistoryItem } from './HistoryItem';
|
||||||
|
import { binDates } from './date-binning';
|
||||||
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
||||||
import { IconButton } from '~/components/ui/IconButton';
|
|
||||||
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
||||||
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { logger } from '~/utils/logger';
|
import { logger } from '~/utils/logger';
|
||||||
import { HistoryItem } from './HistoryItem';
|
|
||||||
import { binDates } from './date-binning';
|
|
||||||
|
|
||||||
const menuVariants = {
|
const menuVariants = {
|
||||||
closed: {
|
closed: {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import * as RadixDialog from '@radix-ui/react-dialog';
|
import * as RadixDialog from '@radix-ui/react-dialog';
|
||||||
import { motion, type Variants } from 'framer-motion';
|
import { motion, type Variants } from 'framer-motion';
|
||||||
import React, { memo, type ReactNode } from 'react';
|
import React, { memo, type ReactNode } from 'react';
|
||||||
|
import { IconButton } from './IconButton';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { IconButton } from './IconButton';
|
|
||||||
|
|
||||||
export { Close as DialogClose, Root as DialogRoot } from '@radix-ui/react-dialog';
|
export { Close as DialogClose, Root as DialogRoot } from '@radix-ui/react-dialog';
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ type IconButtonWithoutChildrenProps = {
|
|||||||
|
|
||||||
type IconButtonWithChildrenProps = {
|
type IconButtonWithChildrenProps = {
|
||||||
icon?: undefined;
|
icon?: undefined;
|
||||||
children: string | JSX.Element | JSX.Element[];
|
children: string | React.ReactElement | React.ReactElement[];
|
||||||
} & BaseIconButtonProps;
|
} & BaseIconButtonProps;
|
||||||
|
|
||||||
type IconButtonProps = IconButtonWithoutChildrenProps | IconButtonWithChildrenProps;
|
type IconButtonProps = IconButtonWithoutChildrenProps | IconButtonWithChildrenProps;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
|
|
||||||
@ -5,7 +6,7 @@ interface PanelHeaderButtonProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
disabledClassName?: string;
|
disabledClassName?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
children: string | JSX.Element | Array<JSX.Element | string>;
|
children: string | React.ReactElement | Array<React.ReactElement | string>;
|
||||||
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
import * as React from 'react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
@ -37,7 +38,7 @@ export const Slider = genericMemo(<T,>({ selected, options, setSelected }: Slide
|
|||||||
|
|
||||||
interface SliderButtonProps {
|
interface SliderButtonProps {
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
children: string | JSX.Element | Array<JSX.Element | string>;
|
children: string | React.ReactElement | Array<React.ReactElement | string>;
|
||||||
setSelected: () => void;
|
setSelected: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { memo, useEffect, useState } from 'react';
|
import { memo, useEffect, useState } from 'react';
|
||||||
import { themeStore, toggleTheme } from '~/lib/stores/theme';
|
|
||||||
import { IconButton } from './IconButton';
|
import { IconButton } from './IconButton';
|
||||||
|
import { themeStore, toggleTheme } from '~/lib/stores/theme';
|
||||||
|
|
||||||
interface ThemeSwitchProps {
|
interface ThemeSwitchProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels';
|
import { Panel, PanelGroup, PanelResizeHandle, type ImperativePanelHandle } from 'react-resizable-panels';
|
||||||
|
import { FileBreadcrumb } from './FileBreadcrumb';
|
||||||
|
import { FileTree } from './FileTree';
|
||||||
|
import { Terminal, type TerminalRef } from './terminal/Terminal';
|
||||||
import {
|
import {
|
||||||
CodeMirrorEditor,
|
CodeMirrorEditor,
|
||||||
type EditorDocument,
|
type EditorDocument,
|
||||||
@ -20,9 +23,6 @@ import { classNames } from '~/utils/classNames';
|
|||||||
import { WORK_DIR } from '~/utils/constants';
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
import { renderLogger } from '~/utils/logger';
|
import { renderLogger } from '~/utils/logger';
|
||||||
import { isMobile } from '~/utils/mobile';
|
import { isMobile } from '~/utils/mobile';
|
||||||
import { FileBreadcrumb } from './FileBreadcrumb';
|
|
||||||
import { FileTree } from './FileTree';
|
|
||||||
import { Terminal, type TerminalRef } from './terminal/Terminal';
|
|
||||||
|
|
||||||
interface EditorPanelProps {
|
interface EditorPanelProps {
|
||||||
files?: FileMap;
|
files?: FileMap;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||||
import { AnimatePresence, motion, type Variants } from 'framer-motion';
|
import { AnimatePresence, motion, type Variants } from 'framer-motion';
|
||||||
import { memo, useEffect, useRef, useState } from 'react';
|
import { memo, useEffect, useRef, useState } from 'react';
|
||||||
|
import FileTree from './FileTree';
|
||||||
import type { FileMap } from '~/lib/stores/files';
|
import type { FileMap } from '~/lib/stores/files';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { WORK_DIR } from '~/utils/constants';
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { renderLogger } from '~/utils/logger';
|
import { renderLogger } from '~/utils/logger';
|
||||||
import FileTree from './FileTree';
|
|
||||||
|
|
||||||
const WORK_DIR_REGEX = new RegExp(`^${WORK_DIR.split('/').slice(0, -1).join('/').replaceAll('/', '\\/')}/`);
|
const WORK_DIR_REGEX = new RegExp(`^${WORK_DIR.split('/').slice(0, -1).join('/').replaceAll('/', '\\/')}/`);
|
||||||
|
|
||||||
@ -87,7 +87,9 @@ export const FileBreadcrumb = memo<FileBreadcrumbProps>(({ files, pathSegments =
|
|||||||
<DropdownMenu.Root open={isActive} modal={false}>
|
<DropdownMenu.Root open={isActive} modal={false}>
|
||||||
<DropdownMenu.Trigger asChild>
|
<DropdownMenu.Trigger asChild>
|
||||||
<span
|
<span
|
||||||
ref={(ref) => (segmentRefs.current[index] = ref)}
|
ref={(ref) => {
|
||||||
|
segmentRefs.current[index] = ref;
|
||||||
|
}}
|
||||||
className={classNames('flex items-center gap-1.5 cursor-pointer shrink-0', {
|
className={classNames('flex items-center gap-1.5 cursor-pointer shrink-0', {
|
||||||
'text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary': !isActive,
|
'text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary': !isActive,
|
||||||
'text-bolt-elements-textPrimary underline': isActive,
|
'text-bolt-elements-textPrimary underline': isActive,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { PortDropdown } from './PortDropdown';
|
||||||
import { IconButton } from '~/components/ui/IconButton';
|
import { IconButton } from '~/components/ui/IconButton';
|
||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
import { PortDropdown } from './PortDropdown';
|
|
||||||
|
|
||||||
export const Preview = memo(() => {
|
export const Preview = memo(() => {
|
||||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { motion, type HTMLMotionProps, type Variants } from 'framer-motion';
|
import { motion, type HTMLMotionProps, type Variants } from 'framer-motion';
|
||||||
import { computed } from 'nanostores';
|
import { computed } from 'nanostores';
|
||||||
|
import * as React from 'react';
|
||||||
import { memo, useCallback, useEffect } from 'react';
|
import { memo, useCallback, useEffect } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { EditorPanel } from './EditorPanel';
|
||||||
|
import { Preview } from './Preview';
|
||||||
import {
|
import {
|
||||||
type OnChangeCallback as OnEditorChange,
|
type OnChangeCallback as OnEditorChange,
|
||||||
type OnScrollCallback as OnEditorScroll,
|
type OnScrollCallback as OnEditorScroll,
|
||||||
@ -14,8 +17,6 @@ import { workbenchStore, type WorkbenchViewType } from '~/lib/stores/workbench';
|
|||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
import { renderLogger } from '~/utils/logger';
|
import { renderLogger } from '~/utils/logger';
|
||||||
import { EditorPanel } from './EditorPanel';
|
|
||||||
import { Preview } from './Preview';
|
|
||||||
|
|
||||||
interface WorkspaceProps {
|
interface WorkspaceProps {
|
||||||
chatStarted?: boolean;
|
chatStarted?: boolean;
|
||||||
@ -175,7 +176,7 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
interface ViewProps extends HTMLMotionProps<'div'> {
|
interface ViewProps extends HTMLMotionProps<'div'> {
|
||||||
children: JSX.Element;
|
children: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
const View = memo(({ children, ...props }: ViewProps) => {
|
const View = memo(({ children, ...props }: ViewProps) => {
|
||||||
|
@ -2,9 +2,9 @@ import { FitAddon } from '@xterm/addon-fit';
|
|||||||
import { WebLinksAddon } from '@xterm/addon-web-links';
|
import { WebLinksAddon } from '@xterm/addon-web-links';
|
||||||
import { Terminal as XTerm } from '@xterm/xterm';
|
import { Terminal as XTerm } from '@xterm/xterm';
|
||||||
import { forwardRef, memo, useEffect, useImperativeHandle, useRef } from 'react';
|
import { forwardRef, memo, useEffect, useImperativeHandle, useRef } from 'react';
|
||||||
|
import { getTerminalTheme } from './theme';
|
||||||
import type { Theme } from '~/lib/stores/theme';
|
import type { Theme } from '~/lib/stores/theme';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
import { getTerminalTheme } from './theme';
|
|
||||||
|
|
||||||
const logger = createScopedLogger('Terminal');
|
const logger = createScopedLogger('Terminal');
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export interface TerminalProps {
|
|||||||
export const Terminal = memo(
|
export const Terminal = memo(
|
||||||
forwardRef<TerminalRef, TerminalProps>(({ className, theme, readonly, onTerminalReady, onTerminalResize }, ref) => {
|
forwardRef<TerminalRef, TerminalProps>(({ className, theme, readonly, onTerminalReady, onTerminalResize }, ref) => {
|
||||||
const terminalElementRef = useRef<HTMLDivElement>(null);
|
const terminalElementRef = useRef<HTMLDivElement>(null);
|
||||||
const terminalRef = useRef<XTerm>();
|
const terminalRef = useRef<XTerm | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const element = terminalElementRef.current!;
|
const element = terminalElementRef.current!;
|
||||||
|
@ -5,5 +5,5 @@ export function getAnthropicModel(apiKey: string) {
|
|||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
return anthropic('claude-3-5-sonnet-20240620');
|
return anthropic('claude-3-5-sonnet-20241022');
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { streamText as _streamText, convertToCoreMessages } from 'ai';
|
import { streamText as _streamText, convertToCoreMessages } from 'ai';
|
||||||
import { getAPIKey } from '~/lib/.server/llm/api-key';
|
|
||||||
import { getAnthropicModel } from '~/lib/.server/llm/model';
|
|
||||||
import { MAX_TOKENS } from './constants';
|
import { MAX_TOKENS } from './constants';
|
||||||
import { getSystemPrompt } from './prompts';
|
import { getSystemPrompt } from './prompts';
|
||||||
|
import { getAPIKey } from '~/lib/.server/llm/api-key';
|
||||||
|
import { getAnthropicModel } from '~/lib/.server/llm/model';
|
||||||
|
|
||||||
interface ToolResult<Name extends string, Args, Result> {
|
interface ToolResult<Name extends string, Args, Result> {
|
||||||
|
state: 'result';
|
||||||
toolCallId: string;
|
toolCallId: string;
|
||||||
toolName: Name;
|
toolName: Name;
|
||||||
args: Args;
|
args: Args;
|
||||||
|
@ -2,9 +2,9 @@ import { useRef, useCallback } from 'react';
|
|||||||
|
|
||||||
export function useSnapScroll() {
|
export function useSnapScroll() {
|
||||||
const autoScrollRef = useRef(true);
|
const autoScrollRef = useRef(true);
|
||||||
const scrollNodeRef = useRef<HTMLDivElement>();
|
const scrollNodeRef = useRef<HTMLDivElement | null>(null);
|
||||||
const onScrollRef = useRef<() => void>();
|
const onScrollRef = useRef<(() => void) | null>(null);
|
||||||
const observerRef = useRef<ResizeObserver>();
|
const observerRef = useRef<ResizeObserver | null>(null);
|
||||||
|
|
||||||
const messageRef = useCallback((node: HTMLDivElement | null) => {
|
const messageRef = useCallback((node: HTMLDivElement | null) => {
|
||||||
if (node) {
|
if (node) {
|
||||||
@ -22,7 +22,7 @@ export function useSnapScroll() {
|
|||||||
observer.observe(node);
|
observer.observe(node);
|
||||||
} else {
|
} else {
|
||||||
observerRef.current?.disconnect();
|
observerRef.current?.disconnect();
|
||||||
observerRef.current = undefined;
|
observerRef.current = null;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ export function useSnapScroll() {
|
|||||||
scrollNodeRef.current?.removeEventListener('scroll', onScrollRef.current);
|
scrollNodeRef.current?.removeEventListener('scroll', onScrollRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollNodeRef.current = undefined;
|
scrollNodeRef.current = null;
|
||||||
onScrollRef.current = undefined;
|
onScrollRef.current = null;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
|
||||||
import type { ChatHistoryItem } from './useChatHistory';
|
import type { ChatHistoryItem } from './useChatHistory';
|
||||||
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
|
|
||||||
const logger = createScopedLogger('ChatHistory');
|
const logger = createScopedLogger('ChatHistory');
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { useLoaderData, useNavigate } from '@remix-run/react';
|
import { useLoaderData, useNavigate } from '@remix-run/react';
|
||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { atom } from 'nanostores';
|
|
||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
|
import { atom } from 'nanostores';
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
|
||||||
import { getMessages, getNextId, getUrlId, openDatabase, setMessages } from './db';
|
import { getMessages, getNextId, getUrlId, openDatabase, setMessages } from './db';
|
||||||
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
|
|
||||||
export interface ChatHistoryItem {
|
export interface ChatHistoryItem {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
import * as nodePath from 'node:path';
|
||||||
import { WebContainer } from '@webcontainer/api';
|
import { WebContainer } from '@webcontainer/api';
|
||||||
import { map, type MapStore } from 'nanostores';
|
import { map, type MapStore } from 'nanostores';
|
||||||
import * as nodePath from 'node:path';
|
import type { ActionCallbackData } from './message-parser';
|
||||||
import type { BoltAction } from '~/types/actions';
|
import type { BoltAction } from '~/types/actions';
|
||||||
import { createScopedLogger } from '~/utils/logger';
|
import { createScopedLogger } from '~/utils/logger';
|
||||||
import { unreachable } from '~/utils/unreachable';
|
import { unreachable } from '~/utils/unreachable';
|
||||||
import type { ActionCallbackData } from './message-parser';
|
|
||||||
|
|
||||||
const logger = createScopedLogger('ActionRunner');
|
const logger = createScopedLogger('ActionRunner');
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { atom, computed, map, type MapStore, type WritableAtom } from 'nanostores';
|
import { atom, computed, map, type MapStore, type WritableAtom } from 'nanostores';
|
||||||
import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
|
|
||||||
import type { FileMap, FilesStore } from './files';
|
import type { FileMap, FilesStore } from './files';
|
||||||
|
import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
|
||||||
|
|
||||||
export type EditorDocuments = Record<string, EditorDocument>;
|
export type EditorDocuments = Record<string, EditorDocument>;
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { Buffer } from 'node:buffer';
|
||||||
|
import * as nodePath from 'node:path';
|
||||||
import type { PathWatcherEvent, WebContainer } from '@webcontainer/api';
|
import type { PathWatcherEvent, WebContainer } from '@webcontainer/api';
|
||||||
import { getEncoding } from 'istextorbinary';
|
import { getEncoding } from 'istextorbinary';
|
||||||
import { map, type MapStore } from 'nanostores';
|
import { map, type MapStore } from 'nanostores';
|
||||||
import { Buffer } from 'node:buffer';
|
|
||||||
import * as nodePath from 'node:path';
|
|
||||||
import { bufferWatchEvents } from '~/utils/buffer';
|
import { bufferWatchEvents } from '~/utils/buffer';
|
||||||
import { WORK_DIR } from '~/utils/constants';
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
import { computeFileModifications } from '~/utils/diff';
|
import { computeFileModifications } from '~/utils/diff';
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { atom, map, type MapStore, type ReadableAtom, type WritableAtom } from 'nanostores';
|
import { atom, map, type MapStore, type ReadableAtom, type WritableAtom } from 'nanostores';
|
||||||
|
import { EditorStore } from './editor';
|
||||||
|
import { FilesStore, type FileMap } from './files';
|
||||||
|
import { PreviewsStore } from './previews';
|
||||||
|
import { TerminalStore } from './terminal';
|
||||||
import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
|
import type { EditorDocument, ScrollPosition } from '~/components/editor/codemirror/CodeMirrorEditor';
|
||||||
import { ActionRunner } from '~/lib/runtime/action-runner';
|
import { ActionRunner } from '~/lib/runtime/action-runner';
|
||||||
import type { ActionCallbackData, ArtifactCallbackData } from '~/lib/runtime/message-parser';
|
import type { ActionCallbackData, ArtifactCallbackData } from '~/lib/runtime/message-parser';
|
||||||
import { webcontainer } from '~/lib/webcontainer';
|
import { webcontainer } from '~/lib/webcontainer';
|
||||||
import type { ITerminal } from '~/types/terminal';
|
import type { ITerminal } from '~/types/terminal';
|
||||||
import { unreachable } from '~/utils/unreachable';
|
import { unreachable } from '~/utils/unreachable';
|
||||||
import { EditorStore } from './editor';
|
|
||||||
import { FilesStore, type FileMap } from './files';
|
|
||||||
import { PreviewsStore } from './previews';
|
|
||||||
import { TerminalStore } from './terminal';
|
|
||||||
|
|
||||||
export interface ArtifactState {
|
export interface ArtifactState {
|
||||||
id: string;
|
id: string;
|
||||||
|
13
app/root.tsx
13
app/root.tsx
@ -2,14 +2,13 @@ import { useStore } from '@nanostores/react';
|
|||||||
import type { LinksFunction } from '@remix-run/cloudflare';
|
import type { LinksFunction } from '@remix-run/cloudflare';
|
||||||
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react';
|
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react';
|
||||||
import tailwindReset from '@unocss/reset/tailwind-compat.css?url';
|
import tailwindReset from '@unocss/reset/tailwind-compat.css?url';
|
||||||
import { themeStore } from './lib/stores/theme';
|
|
||||||
import { stripIndents } from './utils/stripIndent';
|
|
||||||
import { createHead } from 'remix-island';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
|
|
||||||
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
|
||||||
import globalStyles from './styles/index.scss?url';
|
|
||||||
import xtermStyles from '@xterm/xterm/css/xterm.css?url';
|
import xtermStyles from '@xterm/xterm/css/xterm.css?url';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
|
||||||
|
import { createHead } from 'remix-island';
|
||||||
|
import { themeStore } from './lib/stores/theme';
|
||||||
|
import globalStyles from './styles/index.scss?url';
|
||||||
|
import { stripIndents } from './utils/stripIndent';
|
||||||
|
|
||||||
import 'virtual:uno.css';
|
import 'virtual:uno.css';
|
||||||
|
|
||||||
|
@ -34,13 +34,23 @@ async function chatAction({ context, request }: ActionFunctionArgs) {
|
|||||||
|
|
||||||
const result = await streamText(messages, context.cloudflare.env, options);
|
const result = await streamText(messages, context.cloudflare.env, options);
|
||||||
|
|
||||||
return stream.switchSource(result.toAIStream());
|
return (
|
||||||
|
/**
|
||||||
|
* WARNING: toAIStream has been removed from streamText.
|
||||||
|
* See migration guide at https://sdk.vercel.ai/docs/migrations.
|
||||||
|
*/
|
||||||
|
stream.switchSource(result.toDataStream())
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await streamText(messages, context.cloudflare.env, options);
|
const result = await streamText(messages, context.cloudflare.env, options);
|
||||||
|
|
||||||
stream.switchSource(result.toAIStream());
|
/**
|
||||||
|
* WARNING: toAIStream has been removed from streamText.
|
||||||
|
* See migration guide at https://sdk.vercel.ai/docs/migrations.
|
||||||
|
*/
|
||||||
|
stream.switchSource(result.toDataStream());
|
||||||
|
|
||||||
return new Response(stream.readable, {
|
return new Response(stream.readable, {
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { type ActionFunctionArgs } from '@remix-run/cloudflare';
|
import { type ActionFunctionArgs } from '@remix-run/cloudflare';
|
||||||
import { StreamingTextResponse, parseStreamPart } from 'ai';
|
|
||||||
import { streamText } from '~/lib/.server/llm/stream-text';
|
import { streamText } from '~/lib/.server/llm/stream-text';
|
||||||
import { stripIndents } from '~/utils/stripIndent';
|
import { stripIndents } from '~/utils/stripIndent';
|
||||||
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
|
|
||||||
export async function action(args: ActionFunctionArgs) {
|
export async function action(args: ActionFunctionArgs) {
|
||||||
return enhancerAction(args);
|
return enhancerAction(args);
|
||||||
}
|
}
|
||||||
@ -32,23 +28,13 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
|
|||||||
context.cloudflare.env,
|
context.cloudflare.env,
|
||||||
);
|
);
|
||||||
|
|
||||||
const transformStream = new TransformStream({
|
/**
|
||||||
transform(chunk, controller) {
|
* WARNING: toAIStream has been removed from streamText
|
||||||
const processedChunk = decoder
|
* See migration guide at https://sdk.vercel.ai/docs/migrations.
|
||||||
.decode(chunk)
|
*/
|
||||||
.split('\n')
|
// result.toDataStream().pipeThrough(transformStream);
|
||||||
.filter((line) => line !== '')
|
|
||||||
.map(parseStreamPart)
|
|
||||||
.map((part) => part.value)
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
controller.enqueue(encoder.encode(processedChunk));
|
return result.toDataStreamResponse();
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const transformedStream = result.toAIStream().pipeThrough(transformStream);
|
|
||||||
|
|
||||||
return new StreamingTextResponse(transformedStream);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
@use '../variables.scss' as *;
|
||||||
|
@use '../z-index.scss' as *;
|
||||||
|
|
||||||
[data-resize-handle] {
|
[data-resize-handle] {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
@import './variables.scss';
|
@use './variables.scss' as *;
|
||||||
@import './z-index.scss';
|
@use './z-index.scss' as *;
|
||||||
@import './animations.scss';
|
@use './animations.scss' as *;
|
||||||
@import './components/terminal.scss';
|
@use './components/terminal.scss' as *;
|
||||||
@import './components/resize-handle.scss';
|
@use './components/resize-handle.scss' as *;
|
||||||
@import './components/code.scss';
|
@use './components/code.scss' as *;
|
||||||
@import './components/editor.scss';
|
@use './components/editor.scss' as *;
|
||||||
@import './components/toast.scss';
|
@use './components/toast.scss' as *;
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createTwoFilesPatch } from 'diff';
|
import { createTwoFilesPatch } from 'diff';
|
||||||
import type { FileMap } from '~/lib/stores/files';
|
|
||||||
import { MODIFICATIONS_TAG_NAME } from './constants';
|
import { MODIFICATIONS_TAG_NAME } from './constants';
|
||||||
|
import type { FileMap } from '~/lib/stores/files';
|
||||||
|
|
||||||
export const modificationsRegex = new RegExp(
|
export const modificationsRegex = new RegExp(
|
||||||
`^<${MODIFICATIONS_TAG_NAME}>[\\s\\S]*?<\\/${MODIFICATIONS_TAG_NAME}>\\s+`,
|
`^<${MODIFICATIONS_TAG_NAME}>[\\s\\S]*?<\\/${MODIFICATIONS_TAG_NAME}>\\s+`,
|
||||||
|
@ -11,7 +11,7 @@ interface Logger {
|
|||||||
setLevel: (level: DebugLevel) => void;
|
setLevel: (level: DebugLevel) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentLevel: DebugLevel = import.meta.env.VITE_LOG_LEVEL ?? import.meta.env.DEV ? 'debug' : 'info';
|
let currentLevel: DebugLevel = (import.meta.env.VITE_LOG_LEVEL ?? import.meta.env.DEV) ? 'debug' : 'info';
|
||||||
|
|
||||||
const isWorker = 'HTMLRewriter' in globalThis;
|
const isWorker = 'HTMLRewriter' in globalThis;
|
||||||
const supportsColor = !isWorker;
|
const supportsColor = !isWorker;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
import type { UnistNode, UnistParent } from 'node_modules/unist-util-visit/lib';
|
||||||
import rehypeRaw from 'rehype-raw';
|
import rehypeRaw from 'rehype-raw';
|
||||||
|
import rehypeSanitize, { defaultSchema, type Options as RehypeSanitizeOptions } from 'rehype-sanitize';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import type { PluggableList, Plugin } from 'unified';
|
import type { PluggableList, Plugin } from 'unified';
|
||||||
import rehypeSanitize, { defaultSchema, type Options as RehypeSanitizeOptions } from 'rehype-sanitize';
|
|
||||||
import { SKIP, visit } from 'unist-util-visit';
|
import { SKIP, visit } from 'unist-util-visit';
|
||||||
import type { UnistNode, UnistParent } from 'node_modules/unist-util-visit/lib';
|
|
||||||
|
|
||||||
export const allowedHTMLElements = [
|
export const allowedHTMLElements = [
|
||||||
'a',
|
'a',
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
export const genericMemo: <T extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>>(
|
export const genericMemo: <T extends keyof React.JSX.IntrinsicElements | React.JSXElementConstructor<any>>(
|
||||||
component: T,
|
component: T,
|
||||||
propsAreEqual?: (prevProps: React.ComponentProps<T>, nextProps: React.ComponentProps<T>) => boolean,
|
propsAreEqual?: (prevProps: React.ComponentProps<T>, nextProps: React.ComponentProps<T>) => boolean,
|
||||||
) => T & { displayName?: string } = memo;
|
) => T & { displayName?: string } = memo;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { WebContainer } from '@webcontainer/api';
|
import type { WebContainer } from '@webcontainer/api';
|
||||||
import type { ITerminal } from '~/types/terminal';
|
|
||||||
import { withResolvers } from './promises';
|
import { withResolvers } from './promises';
|
||||||
|
import type { ITerminal } from '~/types/terminal';
|
||||||
|
|
||||||
export async function newShellProcess(webcontainer: WebContainer, terminal: ITerminal) {
|
export async function newShellProcess(webcontainer: WebContainer, terminal: ITerminal) {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
|
@ -12,6 +12,7 @@ export default [
|
|||||||
'@blitz/catch-error-name': 'off',
|
'@blitz/catch-error-name': 'off',
|
||||||
'@typescript-eslint/no-this-alias': 'off',
|
'@typescript-eslint/no-this-alias': 'off',
|
||||||
'@typescript-eslint/no-empty-object-type': 'off',
|
'@typescript-eslint/no-empty-object-type': 'off',
|
||||||
|
'@blitz/lines-around-comment': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
91
package.json
91
package.json
@ -3,7 +3,7 @@
|
|||||||
"description": "StackBlitz AI Agent",
|
"description": "StackBlitz AI Agent",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@9.4.0",
|
"packageManager": "pnpm@10.12.3",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -20,82 +20,83 @@
|
|||||||
"preview": "pnpm run build && pnpm run start"
|
"preview": "pnpm run build && pnpm run start"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.18.0"
|
"node": ">=22.14.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "^0.0.39",
|
"@ai-sdk/anthropic": "^1.2.12",
|
||||||
"@codemirror/autocomplete": "^6.17.0",
|
"@codemirror/autocomplete": "^6.18.6",
|
||||||
"@codemirror/commands": "^6.6.0",
|
"@codemirror/commands": "^6.8.1",
|
||||||
"@codemirror/lang-cpp": "^6.0.2",
|
"@codemirror/lang-cpp": "^6.0.3",
|
||||||
"@codemirror/lang-css": "^6.2.1",
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
"@codemirror/lang-html": "^6.4.9",
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
"@codemirror/lang-javascript": "^6.2.4",
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@codemirror/lang-markdown": "^6.2.5",
|
"@codemirror/lang-markdown": "^6.3.3",
|
||||||
"@codemirror/lang-python": "^6.1.6",
|
"@codemirror/lang-python": "^6.2.1",
|
||||||
"@codemirror/lang-sass": "^6.0.2",
|
"@codemirror/lang-sass": "^6.0.2",
|
||||||
"@codemirror/lang-wast": "^6.0.2",
|
"@codemirror/lang-wast": "^6.0.2",
|
||||||
"@codemirror/language": "^6.10.2",
|
"@codemirror/language": "^6.11.1",
|
||||||
"@codemirror/search": "^6.5.6",
|
"@codemirror/search": "^6.5.11",
|
||||||
"@codemirror/state": "^6.4.1",
|
"@codemirror/state": "^6.5.2",
|
||||||
"@codemirror/view": "^6.28.4",
|
"@codemirror/view": "^6.37.2",
|
||||||
"@iconify-json/ph": "^1.1.13",
|
"@iconify-json/ph": "^1.1.13",
|
||||||
"@iconify-json/svg-spinners": "^1.1.2",
|
"@iconify-json/svg-spinners": "^1.1.2",
|
||||||
"@lezer/highlight": "^1.2.0",
|
"@lezer/highlight": "^1.2.0",
|
||||||
"@nanostores/react": "^0.7.2",
|
"@nanostores/react": "^1.0.0",
|
||||||
"@radix-ui/react-dialog": "^1.1.1",
|
"@radix-ui/react-dialog": "^1.1.1",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||||
"@remix-run/cloudflare": "^2.10.2",
|
"@remix-run/cloudflare": "^2.10.2",
|
||||||
"@remix-run/cloudflare-pages": "^2.10.2",
|
"@remix-run/cloudflare-pages": "^2.10.2",
|
||||||
"@remix-run/react": "^2.10.2",
|
"@remix-run/react": "^2.10.2",
|
||||||
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
||||||
"@unocss/reset": "^0.61.0",
|
"@unocss/reset": "^66.3.1",
|
||||||
"@webcontainer/api": "1.3.0-internal.10",
|
"@webcontainer/api": "1.6.4-internal.2",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"ai": "^3.3.4",
|
"ai": "^4.3.16",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^4.1.0",
|
||||||
"diff": "^5.2.0",
|
"diff": "^8.0.2",
|
||||||
"framer-motion": "^11.2.12",
|
"framer-motion": "^12.19.1",
|
||||||
"isbot": "^4.1.0",
|
"isbot": "^5.1.28",
|
||||||
"istextorbinary": "^9.5.0",
|
"istextorbinary": "^9.5.0",
|
||||||
"jose": "^5.6.3",
|
"jose": "^6.0.11",
|
||||||
"nanostores": "^0.10.3",
|
"nanostores": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-hotkeys-hook": "^4.5.0",
|
"react-hotkeys-hook": "^5.1.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^10.1.0",
|
||||||
"react-resizable-panels": "^2.0.20",
|
"react-resizable-panels": "^3.0.3",
|
||||||
"react-toastify": "^10.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"rehype-sanitize": "^6.0.0",
|
"rehype-sanitize": "^6.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
"remix-island": "^0.2.0",
|
"remix-island": "^0.2.0",
|
||||||
"remix-utils": "^7.6.0",
|
"remix-utils": "^8.7.0",
|
||||||
"shiki": "^1.9.1",
|
"shiki": "^3.7.0",
|
||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitz/eslint-plugin": "0.1.0",
|
"@blitz/eslint-plugin": "0.1.4",
|
||||||
"@cloudflare/workers-types": "^4.20240620.0",
|
"@cloudflare/workers-types": "^4.20241127.0",
|
||||||
"@remix-run/dev": "^2.10.0",
|
"@remix-run/dev": "^2.10.0",
|
||||||
"@types/diff": "^5.2.1",
|
"@types/diff": "^7.0.2",
|
||||||
"@types/react": "^18.2.20",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^19.1.6",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^4.1.0",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.3.2",
|
||||||
|
"sass-embedded": "^1.89.2",
|
||||||
"typescript": "^5.5.2",
|
"typescript": "^5.5.2",
|
||||||
"unified": "^11.0.5",
|
"unified": "^11.0.5",
|
||||||
"unocss": "^0.61.3",
|
"unocss": "^66.3.1",
|
||||||
"vite": "^5.3.1",
|
"vite": "^7.0.0",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
"vite-plugin-node-polyfills": "^0.23.0",
|
||||||
"vite-plugin-optimize-css-modules": "^1.1.0",
|
"vite-plugin-optimize-css-modules": "^1.1.0",
|
||||||
"vite-tsconfig-paths": "^4.3.2",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^2.0.1",
|
"vitest": "^3.2.4",
|
||||||
"wrangler": "^3.63.2",
|
"wrangler": "^4.21.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
11079
pnpm-lock.yaml
11079
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
import { globSync } from 'fast-glob';
|
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { basename } from 'node:path';
|
import { basename } from 'node:path';
|
||||||
|
import { globSync } from 'fast-glob';
|
||||||
import { defineConfig, presetIcons, presetUno, transformerDirectives } from 'unocss';
|
import { defineConfig, presetIcons, presetUno, transformerDirectives } from 'unocss';
|
||||||
|
|
||||||
const iconPaths = globSync('./icons/*.svg');
|
const iconPaths = globSync('./icons/*.svg');
|
||||||
|
@ -20,6 +20,7 @@ export default defineConfig((config) => {
|
|||||||
v3_fetcherPersist: true,
|
v3_fetcherPersist: true,
|
||||||
v3_relativeSplatPath: true,
|
v3_relativeSplatPath: true,
|
||||||
v3_throwAbortReason: true,
|
v3_throwAbortReason: true,
|
||||||
|
v3_lazyRouteDiscovery: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
UnoCSS(),
|
UnoCSS(),
|
||||||
|
Loading…
Reference in New Issue
Block a user