From 9f3c47d6da4a5377c14c2b89029b7130227956a7 Mon Sep 17 00:00:00 2001
From: Marco De Nichilo <36410465+marcodenic@users.noreply.github.com>
Date: Mon, 5 Jan 2026 17:38:55 +0000
Subject: [PATCH] Add Agent terminal panel for viewing bash command output
- Add new "Agent" tab to terminal panel that displays real-time output from agent bash commands
- Auto-focus Agent tab when agent runs commands (unless user has interacted with PTY terminals)
- Show spinner indicator on Agent tab when commands are running
- Support ANSI color codes in output using ansi-to-html
- Hide Agent tab in empty session state (before first message)
- Fix duplicate terminal creation on session load by adding ready() check and creating guard
- Track user interaction with PTY terminals to control auto-focus behavior
---
bun.lock | 13 +-
packages/app/package.json | 1 +
packages/app/src/app.tsx | 13 +-
.../app/src/components/agent-terminal.tsx | 149 ++++++++++++++++++
packages/app/src/context/agent-terminal.tsx | 134 ++++++++++++++++
packages/app/src/context/terminal.tsx | 25 ++-
packages/app/src/pages/session.tsx | 32 +++-
7 files changed, 356 insertions(+), 11 deletions(-)
create mode 100644 packages/app/src/components/agent-terminal.tsx
create mode 100644 packages/app/src/context/agent-terminal.tsx
diff --git a/bun.lock b/bun.lock
index 8c57d8630fc..3c97e62a5d3 100644
--- a/bun.lock
+++ b/bun.lock
@@ -40,6 +40,7 @@
"@solidjs/meta": "catalog:",
"@solidjs/router": "catalog:",
"@thisbeyond/solid-dnd": "0.7.5",
+ "ansi-to-html": "0.7.2",
"diff": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "0.3.0",
@@ -1911,6 +1912,8 @@
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+ "ansi-to-html": ["ansi-to-html@0.7.2", "", { "dependencies": { "entities": "^2.2.0" }, "bin": { "ansi-to-html": "bin/ansi-to-html" } }, "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g=="],
+
"ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="],
"any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="],
@@ -2305,7 +2308,7 @@
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
- "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+ "entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="],
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
@@ -4239,6 +4242,8 @@
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
+ "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+
"dot-prop/type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="],
"drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
@@ -4281,6 +4286,10 @@
"html-minifier-terser/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="],
+ "html-minifier-terser/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+
+ "htmlparser2/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+
"js-beautify/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
"jsonwebtoken/jws": ["jws@3.2.2", "", { "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="],
@@ -4599,6 +4608,8 @@
"@jsx-email/cli/vite/rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="],
+ "@jsx-email/doiuse-email/htmlparser2/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
+
"@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
diff --git a/packages/app/package.json b/packages/app/package.json
index 97805892e56..8c4c0c041b8 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -45,6 +45,7 @@
"@solidjs/meta": "catalog:",
"@solidjs/router": "catalog:",
"@thisbeyond/solid-dnd": "0.7.5",
+ "ansi-to-html": "0.7.2",
"diff": "catalog:",
"fuzzysort": "catalog:",
"ghostty-web": "0.3.0",
diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index e41575e7ad4..7bb7f94b8ed 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -15,6 +15,7 @@ import { LayoutProvider } from "@/context/layout"
import { GlobalSDKProvider } from "@/context/global-sdk"
import { ServerProvider, useServer } from "@/context/server"
import { TerminalProvider } from "@/context/terminal"
+import { AgentTerminalProvider } from "@/context/agent-terminal"
import { PromptProvider } from "@/context/prompt"
import { FileProvider } from "@/context/file"
import { NotificationProvider } from "@/context/notification"
@@ -89,11 +90,13 @@ export function App() {
component={(p) => (
-
-
-
-
-
+
+
+
+
+
+
+
)}
diff --git a/packages/app/src/components/agent-terminal.tsx b/packages/app/src/components/agent-terminal.tsx
new file mode 100644
index 00000000000..fa9f2c7a055
--- /dev/null
+++ b/packages/app/src/components/agent-terminal.tsx
@@ -0,0 +1,149 @@
+import { createEffect, createMemo, For, on, Show, type JSX } from "solid-js"
+import { useAgentTerminal, type BashCommand } from "@/context/agent-terminal"
+import { resolveThemeVariant, useTheme } from "@opencode-ai/ui/theme"
+import AnsiToHtml from "ansi-to-html"
+
+function useAnsiConverter() {
+ const theme = useTheme()
+
+ return createMemo(() => {
+ const isDark = theme.mode() === "dark"
+ const currentTheme = theme.themes()[theme.themeId()]
+
+ // Default ANSI colors
+ const defaultColors = isDark
+ ? {
+ fg: "#d4d4d4",
+ black: "#1a1a1a",
+ red: "#ff5f56",
+ green: "#5af78e",
+ yellow: "#f3f99d",
+ blue: "#57c7ff",
+ magenta: "#ff6ac1",
+ cyan: "#9aedfe",
+ white: "#f1f1f0",
+ brightBlack: "#686868",
+ brightRed: "#ff6e6e",
+ brightGreen: "#69ff94",
+ brightYellow: "#ffffa5",
+ brightBlue: "#69a0ff",
+ brightMagenta: "#ff77ff",
+ brightCyan: "#a4ffff",
+ brightWhite: "#ffffff",
+ }
+ : {
+ fg: "#211e1e",
+ black: "#000000",
+ red: "#c91b00",
+ green: "#00c200",
+ yellow: "#c7c400",
+ blue: "#0068ff",
+ magenta: "#c930c7",
+ cyan: "#00c5c7",
+ white: "#c7c7c7",
+ brightBlack: "#686868",
+ brightRed: "#ff6e67",
+ brightGreen: "#5ffa68",
+ brightYellow: "#fffc67",
+ brightBlue: "#6871ff",
+ brightMagenta: "#ff77ff",
+ brightCyan: "#60fdff",
+ brightWhite: "#ffffff",
+ }
+
+ // Pull semantic colors from theme if available
+ if (currentTheme) {
+ const variant = isDark ? currentTheme.dark : currentTheme.light
+ if (variant?.seeds) {
+ const resolved = resolveThemeVariant(variant, isDark)
+ // Map theme semantic colors to ANSI where appropriate
+ if (resolved["syntax-critical"]) defaultColors.red = resolved["syntax-critical"] as string
+ if (resolved["syntax-success"]) defaultColors.green = resolved["syntax-success"] as string
+ if (resolved["syntax-warning"]) defaultColors.yellow = resolved["syntax-warning"] as string
+ if (resolved["syntax-info"]) defaultColors.cyan = resolved["syntax-info"] as string
+ if (resolved["text-base"]) defaultColors.fg = resolved["text-base"] as string
+ }
+ }
+
+ return new AnsiToHtml({
+ fg: defaultColors.fg,
+ bg: "transparent",
+ colors: [
+ defaultColors.black,
+ defaultColors.red,
+ defaultColors.green,
+ defaultColors.yellow,
+ defaultColors.blue,
+ defaultColors.magenta,
+ defaultColors.cyan,
+ defaultColors.white,
+ defaultColors.brightBlack,
+ defaultColors.brightRed,
+ defaultColors.brightGreen,
+ defaultColors.brightYellow,
+ defaultColors.brightBlue,
+ defaultColors.brightMagenta,
+ defaultColors.brightCyan,
+ defaultColors.brightWhite,
+ ],
+ escapeXML: true,
+ })
+ })
+}
+
+function CommandBlock(props: { command: BashCommand }) {
+ const convert = useAnsiConverter()
+
+ return (
+ <>
+
+ $
+ {props.command.command}
+
+
+
+
+ >
+ )
+}
+
+export function AgentTerminal(): JSX.Element {
+ const agentTerminal = useAgentTerminal()
+ const theme = useTheme()
+ let container: HTMLDivElement | undefined
+
+ const backgroundColor = createMemo(() => {
+ const mode = theme.mode()
+ const currentTheme = theme.themes()[theme.themeId()]
+ if (!currentTheme) return mode === "dark" ? "#191515" : "#fcfcfc"
+ const variant = mode === "dark" ? currentTheme.dark : currentTheme.light
+ if (!variant?.seeds) return mode === "dark" ? "#191515" : "#fcfcfc"
+ const resolved = resolveThemeVariant(variant, mode === "dark")
+ return resolved["background-stronger"] ?? (mode === "dark" ? "#191515" : "#fcfcfc")
+ })
+
+ // Auto-scroll to bottom when new output arrives
+ createEffect(
+ on(
+ () => agentTerminal.commands(),
+ () => {
+ if (container) {
+ container.scrollTo({ top: container.scrollHeight, behavior: "smooth" })
+ }
+ },
+ ),
+ )
+
+ return (
+
+
+ Agent commands will appear here
+
+
{(cmd) => }
+
+ )
+}
diff --git a/packages/app/src/context/agent-terminal.tsx b/packages/app/src/context/agent-terminal.tsx
new file mode 100644
index 00000000000..8c9cd7dbdbd
--- /dev/null
+++ b/packages/app/src/context/agent-terminal.tsx
@@ -0,0 +1,134 @@
+import { createStore } from "solid-js/store"
+import { createSimpleContext } from "@opencode-ai/ui/context"
+import { createEffect, createMemo } from "solid-js"
+import { useParams } from "@solidjs/router"
+import { useSync } from "./sync"
+import { useTerminal } from "./terminal"
+import type { Part, ToolPart } from "@opencode-ai/sdk/v2/client"
+
+export type BashCommand = {
+ id: string
+ messageID: string
+ command: string
+ description: string
+ output: string
+ status: "pending" | "running" | "completed" | "error"
+ time: { start?: number; end?: number }
+ exitCode?: number
+}
+
+function isBashToolPart(part: Part): part is ToolPart {
+ return part.type === "tool" && part.tool === "bash"
+}
+
+function extractBashCommand(part: ToolPart): BashCommand {
+ const state = part.state
+ const input = state.input as { command?: string; description?: string }
+
+ const base = {
+ id: part.id,
+ messageID: part.messageID,
+ command: input.command ?? "",
+ description: input.description ?? "",
+ }
+
+ switch (state.status) {
+ case "pending":
+ return { ...base, output: "", status: "pending", time: {} }
+ case "running":
+ return {
+ ...base,
+ output: (state.metadata?.output as string) ?? "",
+ status: "running",
+ time: { start: state.time.start },
+ }
+ case "completed":
+ return {
+ ...base,
+ output: (state.metadata?.output as string) ?? state.output ?? "",
+ status: "completed",
+ time: { start: state.time.start, end: state.time.end },
+ exitCode: state.metadata?.exit as number | undefined,
+ }
+ case "error":
+ return {
+ ...base,
+ output: state.error ?? "",
+ status: "error",
+ time: { start: state.time.start, end: state.time.end },
+ }
+ }
+}
+
+export const { use: useAgentTerminal, provider: AgentTerminalProvider } = createSimpleContext({
+ name: "AgentTerminal",
+ init: () => {
+ const sync = useSync()
+ const terminal = useTerminal()
+ const params = useParams()
+
+ const [store, setStore] = createStore<{
+ cleared: boolean
+ previousActiveCount: number
+ }>({
+ cleared: false,
+ previousActiveCount: 0,
+ })
+
+ const sessionID = createMemo(() => params.id)
+
+ const messages = createMemo(() => {
+ const id = sessionID()
+ if (!id) return []
+ return sync.data.message[id] ?? []
+ })
+
+ const bashCommands = createMemo(() => {
+ if (store.cleared) return []
+ const msgs = messages()
+ const allParts = sync.data.part
+ const commands: BashCommand[] = []
+
+ for (const msg of msgs) {
+ const parts = allParts[msg.id] ?? []
+ for (const part of parts) {
+ if (isBashToolPart(part)) {
+ commands.push(extractBashCommand(part))
+ }
+ }
+ }
+
+ return commands
+ })
+
+ const hasActiveCommand = createMemo(() =>
+ bashCommands().some((c) => c.status === "running" || c.status === "pending"),
+ )
+
+ // Auto-focus to agent tab when a new command starts (if user hasn't interacted with PTY terminals)
+ createEffect(() => {
+ const activeCount = bashCommands().filter((c) => c.status === "running" || c.status === "pending").length
+ const previousCount = store.previousActiveCount
+
+ // A new command started
+ if (activeCount > previousCount && activeCount > 0) {
+ // Only auto-focus if user hasn't interacted with PTY terminals
+ if (!terminal.hasUserInteracted()) {
+ terminal.open("agent")
+ }
+ }
+
+ setStore("previousActiveCount", activeCount)
+ })
+
+ return {
+ commands: bashCommands,
+ hasActiveCommand,
+ clear() {
+ setStore("cleared", true)
+ // Reset after a tick so new commands can come in
+ setTimeout(() => setStore("cleared", false), 0)
+ },
+ }
+ },
+})
diff --git a/packages/app/src/context/terminal.tsx b/packages/app/src/context/terminal.tsx
index e9a07077cef..bdb97334f3c 100644
--- a/packages/app/src/context/terminal.tsx
+++ b/packages/app/src/context/terminal.tsx
@@ -26,16 +26,25 @@ export const { use: useTerminal, provider: TerminalProvider } = createSimpleCont
createStore<{
active?: string
all: LocalPTY[]
+ hasUserInteracted: boolean
}>({
all: [],
+ hasUserInteracted: false,
}),
)
+ let creating = false
+
return {
ready,
all: createMemo(() => Object.values(store.all)),
active: createMemo(() => store.active),
- new() {
+ new(options?: { auto?: boolean }) {
+ if (creating) return
+ creating = true
+ if (!options?.auto) {
+ setStore("hasUserInteracted", true)
+ }
sdk.client.pty
.create({ title: `Terminal ${store.all.length + 1}` })
.then((pty) => {
@@ -48,11 +57,18 @@ export const { use: useTerminal, provider: TerminalProvider } = createSimpleCont
title: pty.data?.title ?? "Terminal",
},
])
- setStore("active", id)
+ // Don't auto-activate if this is an auto-created terminal
+ // Let the agent tab stay focused
+ if (!options?.auto) {
+ setStore("active", id)
+ }
})
.catch((e) => {
console.error("Failed to create terminal", e)
})
+ .finally(() => {
+ creating = false
+ })
},
update(pty: Partial & { id: string }) {
setStore("all", (x) => x.map((x) => (x.id === pty.id ? { ...x, ...pty } : x)))
@@ -88,8 +104,13 @@ export const { use: useTerminal, provider: TerminalProvider } = createSimpleCont
}
},
open(id: string) {
+ // Mark as user interacted if opening a PTY terminal (not the agent tab)
+ if (id !== "agent") {
+ setStore("hasUserInteracted", true)
+ }
setStore("active", id)
},
+ hasUserInteracted: () => store.hasUserInteracted,
async close(id: string) {
batch(() => {
setStore(
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 1b044975209..c75ed3866f9 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -22,6 +22,9 @@ import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, close
import type { DragEvent } from "@thisbeyond/solid-dnd"
import { useSync } from "@/context/sync"
import { useTerminal, type LocalPTY } from "@/context/terminal"
+import { useAgentTerminal } from "@/context/agent-terminal"
+import { AgentTerminal } from "@/components/agent-terminal"
+import { Spinner } from "@opencode-ai/ui/spinner"
import { useLayout } from "@/context/layout"
import { Terminal } from "@/components/terminal"
import { checksum, base64Decode } from "@opencode-ai/util/encode"
@@ -57,6 +60,25 @@ function same(a: readonly T[], b: readonly T[]) {
type DiffStyle = "unified" | "split"
+function AgentTerminalTab() {
+ const params = useParams()
+ const agentTerminal = useAgentTerminal()
+
+ // Don't show Agent tab in empty state (no session yet)
+ if (!params.id) return null
+
+ return (
+
+
+ }>
+
+
+ Agent
+
+
+ )
+}
+
interface SessionReviewTabProps {
diffs: () => FileDiff[]
view: () => ReturnType["view"]>
@@ -294,9 +316,9 @@ export default function Page() {
})
createEffect(() => {
- if (layout.terminal.opened()) {
+ if (layout.terminal.opened() && terminal.ready()) {
if (terminal.all().length === 0) {
- terminal.new()
+ terminal.new({ auto: true }) // auto-create, don't count as user interaction
}
}
})
@@ -1271,9 +1293,10 @@ export default function Page() {
keybind={command.keybind("terminal.new")}
class="flex items-center"
>
-
+ terminal.new()} />
+
{(pty) => (
@@ -1282,6 +1305,9 @@ export default function Page() {
)}
+
+
+