mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
- Implement detachTerminal method in WorkbenchStore and TerminalStore - Add getTerminal method to Terminal component for cleanup - Improve terminal tab management with close functionality - Add cleanup for terminal processes on unmount - Remove unused ActionRunner references across components - Remove unused file-watcher utility - Add cleanup for streams in chat api endpoint - Instruct selectStarterTemplate to only use shadcn templates when explicitly asked to.
69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
import type { WebContainer, WebContainerProcess } from '@webcontainer/api';
|
|
import { atom, type WritableAtom } from 'nanostores';
|
|
import type { ITerminal } from '~/types/terminal';
|
|
import { newBoltShellProcess, newShellProcess } from '~/utils/shell';
|
|
import { coloredText } from '~/utils/terminal';
|
|
|
|
export class TerminalStore {
|
|
#webcontainer: Promise<WebContainer>;
|
|
#terminals: Array<{ terminal: ITerminal; process: WebContainerProcess }> = [];
|
|
#boltTerminal = newBoltShellProcess();
|
|
|
|
showTerminal: WritableAtom<boolean> = import.meta.hot?.data.showTerminal ?? atom(true);
|
|
|
|
constructor(webcontainerPromise: Promise<WebContainer>) {
|
|
this.#webcontainer = webcontainerPromise;
|
|
|
|
if (import.meta.hot) {
|
|
import.meta.hot.data.showTerminal = this.showTerminal;
|
|
}
|
|
}
|
|
get boltTerminal() {
|
|
return this.#boltTerminal;
|
|
}
|
|
|
|
toggleTerminal(value?: boolean) {
|
|
this.showTerminal.set(value !== undefined ? value : !this.showTerminal.get());
|
|
}
|
|
async attachBoltTerminal(terminal: ITerminal) {
|
|
try {
|
|
const wc = await this.#webcontainer;
|
|
await this.#boltTerminal.init(wc, terminal);
|
|
} catch (error: any) {
|
|
terminal.write(coloredText.red('Failed to spawn bolt shell\n\n') + error.message);
|
|
return;
|
|
}
|
|
}
|
|
|
|
async attachTerminal(terminal: ITerminal) {
|
|
try {
|
|
const shellProcess = await newShellProcess(await this.#webcontainer, terminal);
|
|
this.#terminals.push({ terminal, process: shellProcess });
|
|
} catch (error: any) {
|
|
terminal.write(coloredText.red('Failed to spawn shell\n\n') + error.message);
|
|
return;
|
|
}
|
|
}
|
|
|
|
async detachTerminal(terminal: ITerminal) {
|
|
const terminalIndex = this.#terminals.findIndex((t) => t.terminal === terminal);
|
|
|
|
if (terminalIndex !== -1) {
|
|
const { process } = this.#terminals[terminalIndex];
|
|
|
|
try {
|
|
process.kill();
|
|
} catch (error) {
|
|
console.warn('Failed to kill terminal process:', error);
|
|
}
|
|
this.#terminals.splice(terminalIndex, 1);
|
|
}
|
|
}
|
|
|
|
onTerminalResize(cols: number, rows: number) {
|
|
for (const { process } of this.#terminals) {
|
|
process.resize({ cols, rows });
|
|
}
|
|
}
|
|
}
|