mirror of
https://github.com/stackblitz/bolt.new
synced 2025-02-05 20:46:43 +00:00
Fix linting issues
This commit is contained in:
parent
fe3e2ebddf
commit
7d8f811886
@ -10,6 +10,7 @@ interface APIKeyManagerProps {
|
|||||||
labelForGetApiKey?: string;
|
labelForGetApiKey?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export const APIKeyManager: React.FC<APIKeyManagerProps> = ({ provider, apiKey, setApiKey }) => {
|
export const APIKeyManager: React.FC<APIKeyManagerProps> = ({ provider, apiKey, setApiKey }) => {
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const [tempKey, setTempKey] = useState(apiKey);
|
const [tempKey, setTempKey] = useState(apiKey);
|
||||||
|
@ -9,7 +9,7 @@ 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 { MODEL_LIST, DEFAULT_PROVIDER, PROVIDER_LIST, initializeModelList } from '~/utils/constants';
|
import { MODEL_LIST, PROVIDER_LIST, initializeModelList } from '~/utils/constants';
|
||||||
import { Messages } from './Messages.client';
|
import { Messages } from './Messages.client';
|
||||||
import { SendButton } from './SendButton.client';
|
import { SendButton } from './SendButton.client';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@ -27,22 +27,25 @@ const EXAMPLE_PROMPTS = [
|
|||||||
{ text: 'How do I center a div?' },
|
{ text: 'How do I center a div?' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const providerList = PROVIDER_LIST;
|
const providerList = PROVIDER_LIST;
|
||||||
|
|
||||||
|
// @ts-ignore TODO: Introduce proper types
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList, apiKeys }) => {
|
const ModelSelector = ({ model, setModel, provider, setProvider, modelList, providerList, apiKeys }) => {
|
||||||
return (
|
return (
|
||||||
<div className="mb-2 flex gap-2 flex-col sm:flex-row">
|
<div className="mb-2 flex gap-2 flex-col sm:flex-row">
|
||||||
<select
|
<select
|
||||||
value={provider?.name}
|
value={provider?.name}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setProvider(providerList.find((p) => p.name === e.target.value));
|
setProvider(providerList.find((p: ProviderInfo) => p.name === e.target.value));
|
||||||
|
|
||||||
const firstModel = [...modelList].find((m) => m.provider == e.target.value);
|
const firstModel = [...modelList].find((m) => m.provider == e.target.value);
|
||||||
setModel(firstModel ? firstModel.name : '');
|
setModel(firstModel ? firstModel.name : '');
|
||||||
}}
|
}}
|
||||||
className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
|
className="flex-1 p-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all"
|
||||||
>
|
>
|
||||||
{providerList.map((provider) => (
|
{providerList.map((provider: ProviderInfo) => (
|
||||||
<option key={provider.name} value={provider.name}>
|
<option key={provider.name} value={provider.name}>
|
||||||
{provider.name}
|
{provider.name}
|
||||||
</option>
|
</option>
|
||||||
|
@ -2,7 +2,6 @@ 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 { 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, useChatHistory } from '~/lib/persistence';
|
import { db, deleteById, getAll, chatId, type ChatHistoryItem, useChatHistory } from '~/lib/persistence';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
|
@ -52,7 +52,7 @@ export function getBaseURL(cloudflareEnv: Env, provider: string) {
|
|||||||
return env.OPENAI_LIKE_API_BASE_URL || cloudflareEnv.OPENAI_LIKE_API_BASE_URL;
|
return env.OPENAI_LIKE_API_BASE_URL || cloudflareEnv.OPENAI_LIKE_API_BASE_URL;
|
||||||
case 'LMStudio':
|
case 'LMStudio':
|
||||||
return env.LMSTUDIO_API_BASE_URL || cloudflareEnv.LMSTUDIO_API_BASE_URL || 'http://localhost:1234';
|
return env.LMSTUDIO_API_BASE_URL || cloudflareEnv.LMSTUDIO_API_BASE_URL || 'http://localhost:1234';
|
||||||
case 'Ollama':
|
case 'Ollama': {
|
||||||
let baseUrl = env.OLLAMA_API_BASE_URL || cloudflareEnv.OLLAMA_API_BASE_URL || 'http://localhost:11434';
|
let baseUrl = env.OLLAMA_API_BASE_URL || cloudflareEnv.OLLAMA_API_BASE_URL || 'http://localhost:11434';
|
||||||
|
|
||||||
if (env.RUNNING_IN_DOCKER === 'true') {
|
if (env.RUNNING_IN_DOCKER === 'true') {
|
||||||
@ -60,6 +60,7 @@ export function getBaseURL(cloudflareEnv: Env, provider: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return baseUrl;
|
return baseUrl;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@ import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
|||||||
import { createMistral } from '@ai-sdk/mistral';
|
import { createMistral } from '@ai-sdk/mistral';
|
||||||
import { createCohere } from '@ai-sdk/cohere';
|
import { createCohere } from '@ai-sdk/cohere';
|
||||||
|
|
||||||
export function getAnthropicModel(apiKey: string, model: string) {
|
export function getAnthropicModel(apiKey: string | undefined, model: string) {
|
||||||
const anthropic = createAnthropic({
|
const anthropic = createAnthropic({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
return anthropic(model);
|
return anthropic(model);
|
||||||
}
|
}
|
||||||
export function getOpenAILikeModel(baseURL: string, apiKey: string, model: string) {
|
export function getOpenAILikeModel(baseURL: string, apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
baseURL,
|
baseURL,
|
||||||
apiKey,
|
apiKey,
|
||||||
@ -27,7 +27,7 @@ export function getOpenAILikeModel(baseURL: string, apiKey: string, model: strin
|
|||||||
return openai(model);
|
return openai(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCohereAIModel(apiKey: string, model: string) {
|
export function getCohereAIModel(apiKey: string | undefined, model: string) {
|
||||||
const cohere = createCohere({
|
const cohere = createCohere({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
@ -35,7 +35,7 @@ export function getCohereAIModel(apiKey: string, model: string) {
|
|||||||
return cohere(model);
|
return cohere(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOpenAIModel(apiKey: string, model: string) {
|
export function getOpenAIModel(apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
@ -43,7 +43,7 @@ export function getOpenAIModel(apiKey: string, model: string) {
|
|||||||
return openai(model);
|
return openai(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMistralModel(apiKey: string, model: string) {
|
export function getMistralModel(apiKey: string | undefined, model: string) {
|
||||||
const mistral = createMistral({
|
const mistral = createMistral({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
@ -51,7 +51,7 @@ export function getMistralModel(apiKey: string, model: string) {
|
|||||||
return mistral(model);
|
return mistral(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGoogleModel(apiKey: string, model: string) {
|
export function getGoogleModel(apiKey: string | undefined, model: string) {
|
||||||
const google = createGoogleGenerativeAI({
|
const google = createGoogleGenerativeAI({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
@ -59,7 +59,7 @@ export function getGoogleModel(apiKey: string, model: string) {
|
|||||||
return google(model);
|
return google(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGroqModel(apiKey: string, model: string) {
|
export function getGroqModel(apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
baseURL: 'https://api.groq.com/openai/v1',
|
baseURL: 'https://api.groq.com/openai/v1',
|
||||||
apiKey,
|
apiKey,
|
||||||
@ -68,7 +68,7 @@ export function getGroqModel(apiKey: string, model: string) {
|
|||||||
return openai(model);
|
return openai(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHuggingFaceModel(apiKey: string, model: string) {
|
export function getHuggingFaceModel(apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
baseURL: 'https://api-inference.huggingface.co/v1/',
|
baseURL: 'https://api-inference.huggingface.co/v1/',
|
||||||
apiKey,
|
apiKey,
|
||||||
@ -78,16 +78,16 @@ export function getHuggingFaceModel(apiKey: string, model: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getOllamaModel(baseURL: string, model: string) {
|
export function getOllamaModel(baseURL: string, model: string) {
|
||||||
const Ollama = ollama(model, {
|
const ollamaInstance = ollama(model, {
|
||||||
numCtx: 32768,
|
numCtx: 32768,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ollama.config.baseURL = `${baseURL}/api`;
|
ollamaInstance.config.baseURL = `${baseURL}/api`;
|
||||||
|
|
||||||
return Ollama;
|
return ollamaInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDeepseekModel(apiKey: string, model: string) {
|
export function getDeepseekModel(apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
baseURL: 'https://api.deepseek.com/beta',
|
baseURL: 'https://api.deepseek.com/beta',
|
||||||
apiKey,
|
apiKey,
|
||||||
@ -96,7 +96,7 @@ export function getDeepseekModel(apiKey: string, model: string) {
|
|||||||
return openai(model);
|
return openai(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOpenRouterModel(apiKey: string, model: string) {
|
export function getOpenRouterModel(apiKey: string | undefined, model: string) {
|
||||||
const openRouter = createOpenRouter({
|
const openRouter = createOpenRouter({
|
||||||
apiKey,
|
apiKey,
|
||||||
});
|
});
|
||||||
@ -113,7 +113,7 @@ export function getLMStudioModel(baseURL: string, model: string) {
|
|||||||
return lmstudio(model);
|
return lmstudio(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getXAIModel(apiKey: string, model: string) {
|
export function getXAIModel(apiKey: string | undefined, model: string) {
|
||||||
const openai = createOpenAI({
|
const openai = createOpenAI({
|
||||||
baseURL: 'https://api.x.ai/v1',
|
baseURL: 'https://api.x.ai/v1',
|
||||||
apiKey,
|
apiKey,
|
||||||
|
@ -110,6 +110,7 @@ export function useChatHistory() {
|
|||||||
toast.success('Chat duplicated successfully');
|
toast.success('Chat duplicated successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Failed to duplicate chat');
|
toast.error('Failed to duplicate chat');
|
||||||
|
console.log(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { WebContainer, type WebContainerProcess } from '@webcontainer/api';
|
import { WebContainer } from '@webcontainer/api';
|
||||||
import { atom, map, type MapStore } from 'nanostores';
|
import { atom, map, type MapStore } from 'nanostores';
|
||||||
import * as nodePath from 'node:path';
|
import * as nodePath from 'node:path';
|
||||||
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';
|
import type { ActionCallbackData } from './message-parser';
|
||||||
import type { ITerminal } from '~/types/terminal';
|
|
||||||
import type { BoltShell } from '~/utils/shell';
|
import type { BoltShell } from '~/utils/shell';
|
||||||
|
|
||||||
const logger = createScopedLogger('ActionRunner');
|
const logger = createScopedLogger('ActionRunner');
|
||||||
@ -94,9 +93,10 @@ export class ActionRunner {
|
|||||||
|
|
||||||
this.#updateAction(actionId, { ...action, ...data.action, executed: !isStreaming });
|
this.#updateAction(actionId, { ...action, ...data.action, executed: !isStreaming });
|
||||||
|
|
||||||
|
// eslint-disable-next-line consistent-return
|
||||||
return (this.#currentExecutionPromise = this.#currentExecutionPromise
|
return (this.#currentExecutionPromise = this.#currentExecutionPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return this.#executeAction(actionId, isStreaming);
|
this.#executeAction(actionId, isStreaming);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Action failed:', error);
|
console.error('Action failed:', error);
|
||||||
@ -127,12 +127,11 @@ export class ActionRunner {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* adding a delay to avoid any race condition between 2 start actions
|
* adding a delay to avoid any race condition between 2 start actions
|
||||||
* i am up for a better approch
|
* i am up for a better approach
|
||||||
*/
|
*/
|
||||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import JSZip from 'jszip';
|
|||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';
|
import { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';
|
||||||
import * as nodePath from 'node:path';
|
import * as nodePath from 'node:path';
|
||||||
import type { WebContainerProcess } from '@webcontainer/api';
|
|
||||||
import { extractRelativePath } from '~/utils/diff';
|
import { extractRelativePath } from '~/utils/diff';
|
||||||
|
|
||||||
export interface ArtifactState {
|
export interface ArtifactState {
|
||||||
@ -42,7 +41,6 @@ export class WorkbenchStore {
|
|||||||
unsavedFiles: WritableAtom<Set<string>> = import.meta.hot?.data.unsavedFiles ?? atom(new Set<string>());
|
unsavedFiles: WritableAtom<Set<string>> = import.meta.hot?.data.unsavedFiles ?? atom(new Set<string>());
|
||||||
modifiedFiles = new Set<string>();
|
modifiedFiles = new Set<string>();
|
||||||
artifactIdList: string[] = [];
|
artifactIdList: string[] = [];
|
||||||
#boltTerminal: { terminal: ITerminal; process: WebContainerProcess } | undefined;
|
|
||||||
#globalExecutionQueue = Promise.resolve();
|
#globalExecutionQueue = Promise.resolve();
|
||||||
constructor() {
|
constructor() {
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
@ -439,6 +437,8 @@ export class WorkbenchStore {
|
|||||||
});
|
});
|
||||||
return { path: extractRelativePath(filePath), sha: blob.sha };
|
return { path: extractRelativePath(filePath), sha: blob.sha };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ const PROVIDER_LIST: ProviderInfo[] = [
|
|||||||
{ name: 'deepseek-coder', label: 'Deepseek-Coder', provider: 'Deepseek', maxTokenAllowed: 8000 },
|
{ name: 'deepseek-coder', label: 'Deepseek-Coder', provider: 'Deepseek', maxTokenAllowed: 8000 },
|
||||||
{ name: 'deepseek-chat', label: 'Deepseek-Chat', provider: 'Deepseek', maxTokenAllowed: 8000 },
|
{ name: 'deepseek-chat', label: 'Deepseek-Chat', provider: 'Deepseek', maxTokenAllowed: 8000 },
|
||||||
],
|
],
|
||||||
getApiKeyLink: 'https://platform.deepseek.com/api_keys',
|
getApiKeyLink: 'https://platform.deepseek.com/apiKeys',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Mistral',
|
name: 'Mistral',
|
||||||
@ -242,8 +242,8 @@ const getOllamaBaseUrl = () => {
|
|||||||
|
|
||||||
async function getOllamaModels(): Promise<ModelInfo[]> {
|
async function getOllamaModels(): Promise<ModelInfo[]> {
|
||||||
try {
|
try {
|
||||||
const base_url = getOllamaBaseUrl();
|
const baseUrl = getOllamaBaseUrl();
|
||||||
const response = await fetch(`${base_url}/api/tags`);
|
const response = await fetch(`${baseUrl}/api/tags`);
|
||||||
const data = (await response.json()) as OllamaApiResponse;
|
const data = (await response.json()) as OllamaApiResponse;
|
||||||
|
|
||||||
return data.models.map((model: OllamaModel) => ({
|
return data.models.map((model: OllamaModel) => ({
|
||||||
@ -252,6 +252,7 @@ async function getOllamaModels(): Promise<ModelInfo[]> {
|
|||||||
provider: 'Ollama',
|
provider: 'Ollama',
|
||||||
maxTokenAllowed: 8000,
|
maxTokenAllowed: 8000,
|
||||||
}));
|
}));
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -259,16 +260,16 @@ async function getOllamaModels(): Promise<ModelInfo[]> {
|
|||||||
|
|
||||||
async function getOpenAILikeModels(): Promise<ModelInfo[]> {
|
async function getOpenAILikeModels(): Promise<ModelInfo[]> {
|
||||||
try {
|
try {
|
||||||
const base_url = import.meta.env.OPENAI_LIKE_API_BASE_URL || '';
|
const baseUrl = import.meta.env.OPENAI_LIKE_API_BASE_URL || '';
|
||||||
|
|
||||||
if (!base_url) {
|
if (!baseUrl) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const api_key = import.meta.env.OPENAI_LIKE_API_KEY ?? '';
|
const apiKey = import.meta.env.OPENAI_LIKE_API_KEY ?? '';
|
||||||
const response = await fetch(`${base_url}/models`, {
|
const response = await fetch(`${baseUrl}/models`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${api_key}`,
|
Authorization: `Bearer ${apiKey}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const res = (await response.json()) as any;
|
const res = (await response.json()) as any;
|
||||||
@ -278,6 +279,7 @@ async function getOpenAILikeModels(): Promise<ModelInfo[]> {
|
|||||||
label: model.id,
|
label: model.id,
|
||||||
provider: 'OpenAILike',
|
provider: 'OpenAILike',
|
||||||
}));
|
}));
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -318,8 +320,8 @@ async function getOpenRouterModels(): Promise<ModelInfo[]> {
|
|||||||
|
|
||||||
async function getLMStudioModels(): Promise<ModelInfo[]> {
|
async function getLMStudioModels(): Promise<ModelInfo[]> {
|
||||||
try {
|
try {
|
||||||
const base_url = import.meta.env.LMSTUDIO_API_BASE_URL || 'http://localhost:1234';
|
const baseUrl = import.meta.env.LMSTUDIO_API_BASE_URL || 'http://localhost:1234';
|
||||||
const response = await fetch(`${base_url}/v1/models`);
|
const response = await fetch(`${baseUrl}/v1/models`);
|
||||||
const data = (await response.json()) as any;
|
const data = (await response.json()) as any;
|
||||||
|
|
||||||
return data.data.map((model: any) => ({
|
return data.data.map((model: any) => ({
|
||||||
@ -327,6 +329,7 @@ async function getLMStudioModels(): Promise<ModelInfo[]> {
|
|||||||
label: model.id,
|
label: model.id,
|
||||||
provider: 'LMStudio',
|
provider: 'LMStudio',
|
||||||
}));
|
}));
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ export async function newShellProcess(webcontainer: WebContainer, terminal: ITer
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ExecutionResult = { output: string; exitCode: number } | undefined;
|
||||||
|
|
||||||
export class BoltShell {
|
export class BoltShell {
|
||||||
#initialized: (() => void) | undefined;
|
#initialized: (() => void) | undefined;
|
||||||
#readyPromise: Promise<void>;
|
#readyPromise: Promise<void>;
|
||||||
@ -61,36 +63,39 @@ export class BoltShell {
|
|||||||
executionState = atom<{ sessionId: string; active: boolean; executionPrms?: Promise<any> } | undefined>();
|
executionState = atom<{ sessionId: string; active: boolean; executionPrms?: Promise<any> } | undefined>();
|
||||||
#outputStream: ReadableStreamDefaultReader<string> | undefined;
|
#outputStream: ReadableStreamDefaultReader<string> | undefined;
|
||||||
#shellInputStream: WritableStreamDefaultWriter<string> | undefined;
|
#shellInputStream: WritableStreamDefaultWriter<string> | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.#readyPromise = new Promise((resolve) => {
|
this.#readyPromise = new Promise((resolve) => {
|
||||||
this.#initialized = resolve;
|
this.#initialized = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ready() {
|
ready() {
|
||||||
return this.#readyPromise;
|
return this.#readyPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
async init(webcontainer: WebContainer, terminal: ITerminal) {
|
async init(webcontainer: WebContainer, terminal: ITerminal) {
|
||||||
this.#webcontainer = webcontainer;
|
this.#webcontainer = webcontainer;
|
||||||
this.#terminal = terminal;
|
this.#terminal = terminal;
|
||||||
|
|
||||||
const callback = (data: string) => {
|
|
||||||
console.log(data);
|
|
||||||
};
|
|
||||||
const { process, output } = await this.newBoltShellProcess(webcontainer, terminal);
|
const { process, output } = await this.newBoltShellProcess(webcontainer, terminal);
|
||||||
this.#process = process;
|
this.#process = process;
|
||||||
this.#outputStream = output.getReader();
|
this.#outputStream = output.getReader();
|
||||||
await this.waitTillOscCode('interactive');
|
await this.waitTillOscCode('interactive');
|
||||||
this.#initialized?.();
|
this.#initialized?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
get terminal() {
|
get terminal() {
|
||||||
return this.#terminal;
|
return this.#terminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
get process() {
|
get process() {
|
||||||
return this.#process;
|
return this.#process;
|
||||||
}
|
}
|
||||||
async executeCommand(sessionId: string, command: string) {
|
|
||||||
|
async executeCommand(sessionId: string, command: string): Promise<ExecutionResult> {
|
||||||
if (!this.process || !this.terminal) {
|
if (!this.process || !this.terminal) {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = this.executionState.get();
|
const state = this.executionState.get();
|
||||||
@ -109,14 +114,15 @@ export class BoltShell {
|
|||||||
this.terminal.input(command.trim() + '\n');
|
this.terminal.input(command.trim() + '\n');
|
||||||
|
|
||||||
//wait for the execution to finish
|
//wait for the execution to finish
|
||||||
const executionPrms = this.getCurrentExecutionResult();
|
const executionPromise = this.getCurrentExecutionResult();
|
||||||
this.executionState.set({ sessionId, active: true, executionPrms });
|
this.executionState.set({ sessionId, active: true, executionPrms: executionPromise });
|
||||||
|
|
||||||
const resp = await executionPrms;
|
const resp = await executionPromise;
|
||||||
this.executionState.set({ sessionId, active: false });
|
this.executionState.set({ sessionId, active: false });
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
async newBoltShellProcess(webcontainer: WebContainer, terminal: ITerminal) {
|
async newBoltShellProcess(webcontainer: WebContainer, terminal: ITerminal) {
|
||||||
const args: string[] = [];
|
const args: string[] = [];
|
||||||
|
|
||||||
@ -167,10 +173,12 @@ export class BoltShell {
|
|||||||
|
|
||||||
return { process, output: internalOutput };
|
return { process, output: internalOutput };
|
||||||
}
|
}
|
||||||
async getCurrentExecutionResult() {
|
|
||||||
|
async getCurrentExecutionResult(): Promise<ExecutionResult> {
|
||||||
const { output, exitCode } = await this.waitTillOscCode('exit');
|
const { output, exitCode } = await this.waitTillOscCode('exit');
|
||||||
return { output, exitCode };
|
return { output, exitCode };
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitTillOscCode(waitCode: string) {
|
async waitTillOscCode(waitCode: string) {
|
||||||
let fullOutput = '';
|
let fullOutput = '';
|
||||||
let exitCode: number = 0;
|
let exitCode: number = 0;
|
||||||
@ -192,7 +200,7 @@ export class BoltShell {
|
|||||||
fullOutput += text;
|
fullOutput += text;
|
||||||
|
|
||||||
// Check if command completion signal with exit code
|
// Check if command completion signal with exit code
|
||||||
const [, osc, , pid, code] = text.match(/\x1b\]654;([^\x07=]+)=?((-?\d+):(\d+))?\x07/) || [];
|
const [, osc, , , code] = text.match(/\x1b\]654;([^\x07=]+)=?((-?\d+):(\d+))?\x07/) || [];
|
||||||
|
|
||||||
if (osc === 'exit') {
|
if (osc === 'exit') {
|
||||||
exitCode = parseInt(code, 10);
|
exitCode = parseInt(code, 10);
|
||||||
@ -206,6 +214,7 @@ export class BoltShell {
|
|||||||
return { output: fullOutput, exitCode };
|
return { output: fullOutput, exitCode };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newBoltShellProcess() {
|
export function newBoltShellProcess() {
|
||||||
return new BoltShell();
|
return new BoltShell();
|
||||||
}
|
}
|
||||||
|
3
worker-configuration.d.ts
vendored
3
worker-configuration.d.ts
vendored
@ -9,4 +9,7 @@ interface Env {
|
|||||||
OPENAI_LIKE_API_BASE_URL: string;
|
OPENAI_LIKE_API_BASE_URL: string;
|
||||||
DEEPSEEK_API_KEY: string;
|
DEEPSEEK_API_KEY: string;
|
||||||
LMSTUDIO_API_BASE_URL: string;
|
LMSTUDIO_API_BASE_URL: string;
|
||||||
|
GOOGLE_GENERATIVE_AI_API_KEY: string;
|
||||||
|
MISTRAL_API_KEY: string;
|
||||||
|
XAI_API_KEY: string;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user