chore: format code

This commit is contained in:
GitHub Action
2025-11-08 01:59:02 +00:00
parent 16357e8041
commit 34ff87d504
182 changed files with 940 additions and 3646 deletions

View File

@@ -115,11 +115,7 @@ export function tui(input: {
render(
() => {
return (
<ErrorBoundary
fallback={(error, reset) => (
<ErrorComponent error={error} reset={reset} onExit={onExit} />
)}
>
<ErrorBoundary fallback={(error, reset) => <ErrorComponent error={error} reset={reset} onExit={onExit} />}>
<ExitProvider onExit={onExit}>
<KVProvider>
<ToastProvider>
@@ -413,12 +409,7 @@ function App() {
flexShrink={0}
>
<box flexDirection="row">
<box
flexDirection="row"
backgroundColor={theme.backgroundElement}
paddingLeft={1}
paddingRight={1}
>
<box flexDirection="row" backgroundColor={theme.backgroundElement} paddingLeft={1} paddingRight={1}>
<text fg={theme.textMuted}>open</text>
<text fg={theme.text} attributes={TextAttributes.BOLD}>
code{" "}
@@ -434,11 +425,7 @@ function App() {
tab
</text>
<text fg={local.agent.color(local.agent.current().name)}>{""}</text>
<text
bg={local.agent.color(local.agent.current().name)}
fg={theme.background}
wrapMode={undefined}
>
<text bg={local.agent.color(local.agent.current().name)} fg={theme.background} wrapMode={undefined}>
<span style={{ bold: true }}> {local.agent.current().name.toUpperCase()}</span>
<span> AGENT </span>
</text>

View File

@@ -52,11 +52,7 @@ export function DialogModel() {
description: provider.name,
category: provider.name,
})),
filter(
(x) =>
Boolean(ref()?.filter) ||
!local.model.recent().find((y) => isDeepEqual(y, x.value)),
),
filter((x) => Boolean(ref()?.filter) || !local.model.recent().find((y) => isDeepEqual(y, x.value))),
),
),
),

View File

@@ -20,9 +20,7 @@ export function DialogSessionList() {
const deleteKeybind = "ctrl+d"
const currentSessionID = createMemo(() =>
route.data.type === "session" ? route.data.sessionID : undefined,
)
const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined))
const options = createMemo(() => {
const today = new Date().toDateString()

View File

@@ -77,10 +77,7 @@ export function DialogStatus() {
</For>
</box>
)}
<Show
when={enabledFormatters().length > 0}
fallback={<text fg={theme.text}>No Formatters</text>}
>
<Show when={enabledFormatters().length > 0} fallback={<text fg={theme.text}>No Formatters</text>}>
<box>
<text fg={theme.text}>{enabledFormatters().length} Formatters</text>
<For each={enabledFormatters()}>

View File

@@ -3,19 +3,9 @@ import { TextAttributes } from "@opentui/core"
import { For } from "solid-js"
import { useTheme } from "@tui/context/theme"
const LOGO_LEFT = [
` `,
`█▀▀█ █▀▀█ █▀▀█ █▀▀▄`,
`█░░█ █░░█ █▀▀▀ █░░█`,
`▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`,
]
const LOGO_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█░░█ █░░█ █▀▀▀ █░░█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`]
const LOGO_RIGHT = [
``,
`█▀▀▀ █▀▀█ █▀▀█ █▀▀█`,
`█░░░ █░░█ █░░█ █▀▀▀`,
`▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`,
]
const LOGO_RIGHT = [``, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█░░░ █░░█ █░░█ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`]
export function Logo() {
const { theme } = useTheme()

View File

@@ -83,12 +83,7 @@ export function Autocomplete(props: {
const extmarkStart = store.index
const extmarkEnd = extmarkStart + Bun.stringWidth(virtualText)
const styleId =
part.type === "file"
? props.fileStyleId
: part.type === "agent"
? props.agentStyleId
: undefined
const styleId = part.type === "file" ? props.fileStyleId : part.type === "agent" ? props.agentStyleId : undefined
const extmarkId = input.extmarks.create({
start: extmarkStart,
@@ -185,9 +180,7 @@ export function Autocomplete(props: {
)
})
const session = createMemo(() =>
props.sessionID ? sync.session.get(props.sessionID) : undefined,
)
const session = createMemo(() => (props.sessionID ? sync.session.get(props.sessionID) : undefined))
const commands = createMemo((): AutocompleteOption[] => {
const results: AutocompleteOption[] = []
const s = session()
@@ -324,9 +317,7 @@ export function Autocomplete(props: {
const options = createMemo(() => {
const mixed: AutocompleteOption[] = (
store.visible === "@"
? [...agents(), ...(files.loading ? files.latest || [] : files())]
: [...commands()]
store.visible === "@" ? [...agents(), ...(files.loading ? files.latest || [] : files())] : [...commands()]
).filter((x) => x.disabled !== true)
const currentFilter = filter()
if (!currentFilter) return mixed.slice(0, 10)
@@ -393,9 +384,7 @@ export function Autocomplete(props: {
return
}
// Check if a space was typed after the trigger character
const currentText = props
.input()
.getTextRange(store.index + 1, props.input().cursorOffset + 1)
const currentText = props.input().getTextRange(store.index + 1, props.input().cursorOffset + 1)
if (currentText.includes(" ")) {
hide()
}
@@ -433,13 +422,8 @@ export function Autocomplete(props: {
if (e.name === "@") {
const cursorOffset = props.input().cursorOffset
const charBeforeCursor =
cursorOffset === 0
? undefined
: props.input().getTextRange(cursorOffset - 1, cursorOffset)
const canTrigger =
charBeforeCursor === undefined ||
charBeforeCursor === "" ||
/\s/.test(charBeforeCursor)
cursorOffset === 0 ? undefined : props.input().getTextRange(cursorOffset - 1, cursorOffset)
const canTrigger = charBeforeCursor === undefined || charBeforeCursor === "" || /\s/.test(charBeforeCursor)
if (canTrigger) show("@")
}
@@ -487,10 +471,7 @@ export function Autocomplete(props: {
{option.display}
</text>
<Show when={option.description}>
<text
fg={index() === store.selected ? theme.background : theme.textMuted}
wrapMode="none"
>
<text fg={index() === store.selected ? theme.background : theme.textMuted} wrapMode="none">
{option.description}
</text>
</Show>

View File

@@ -334,9 +334,7 @@ export function Prompt(props: PromptProps) {
// Expand pasted text inline before submitting
const allExtmarks = input.extmarks.getAllForTypeId(promptPartTypeId)
const sortedExtmarks = allExtmarks.sort(
(a: { start: number }, b: { start: number }) => b.start - a.start,
)
const sortedExtmarks = allExtmarks.sort((a: { start: number }, b: { start: number }) => b.start - a.start)
for (const extmark of sortedExtmarks) {
const partIndex = store.extmarkToPartIndex.get(extmark.id)
@@ -499,28 +497,15 @@ export function Prompt(props: PromptProps) {
<box
flexDirection="row"
{...SplitBorder}
borderColor={
keybind.leader ? theme.accent : store.mode === "shell" ? theme.secondary : theme.border
}
borderColor={keybind.leader ? theme.accent : store.mode === "shell" ? theme.secondary : theme.border}
justifyContent="space-evenly"
>
<box
backgroundColor={theme.backgroundElement}
width={3}
height="100%"
alignItems="center"
paddingTop={1}
>
<box backgroundColor={theme.backgroundElement} width={3} height="100%" alignItems="center" paddingTop={1}>
<text attributes={TextAttributes.BOLD} fg={theme.primary}>
{store.mode === "normal" ? ">" : "!"}
</text>
</box>
<box
paddingTop={1}
paddingBottom={1}
backgroundColor={theme.backgroundElement}
flexGrow={1}
>
<box paddingTop={1} paddingBottom={1} backgroundColor={theme.backgroundElement} flexGrow={1}>
<textarea
placeholder={
props.showPlaceholder
@@ -575,10 +560,7 @@ export function Prompt(props: PromptProps) {
return
}
if (store.mode === "shell") {
if (
(e.name === "backspace" && input.visualCursor.offset === 0) ||
e.name === "escape"
) {
if ((e.name === "backspace" && input.visualCursor.offset === 0) || e.name === "escape") {
setStore("mode", "normal")
e.preventDefault()
return
@@ -588,8 +570,7 @@ export function Prompt(props: PromptProps) {
if (!autocomplete.visible) {
if (
(keybind.match("history_previous", e) && input.cursorOffset === 0) ||
(keybind.match("history_next", e) &&
input.cursorOffset === input.plainText.length)
(keybind.match("history_next", e) && input.cursorOffset === input.plainText.length)
) {
const direction = keybind.match("history_previous", e) ? -1 : 1
const item = history.move(direction, input.plainText)
@@ -605,12 +586,8 @@ export function Prompt(props: PromptProps) {
return
}
if (keybind.match("history_previous", e) && input.visualCursor.visualRow === 0)
input.cursorOffset = 0
if (
keybind.match("history_next", e) &&
input.visualCursor.visualRow === input.height - 1
)
if (keybind.match("history_previous", e) && input.visualCursor.visualRow === 0) input.cursorOffset = 0
if (keybind.match("history_next", e) && input.visualCursor.visualRow === input.height - 1)
input.cursorOffset = input.plainText.length
}
}}
@@ -701,12 +678,7 @@ export function Prompt(props: PromptProps) {
syntaxStyle={syntax()}
/>
</box>
<box
backgroundColor={theme.backgroundElement}
width={1}
justifyContent="center"
alignItems="center"
></box>
<box backgroundColor={theme.backgroundElement} width={1} justifyContent="center" alignItems="center"></box>
</box>
<box flexDirection="row" justifyContent="space-between">
<text flexShrink={0} wrapMode="none" fg={theme.text}>
@@ -727,8 +699,7 @@ export function Prompt(props: PromptProps) {
<Match when={props.hint}>{props.hint!}</Match>
<Match when={true}>
<text fg={theme.text}>
{keybind.print("command_list")}{" "}
<span style={{ fg: theme.textMuted }}>commands</span>
{keybind.print("command_list")} <span style={{ fg: theme.textMuted }}>commands</span>
</text>
</Match>
</Switch>

View File

@@ -22,9 +22,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
return !!provider?.models[model.modelID]
}
function getFirstValidModel(
...modelFns: (() => { providerID: string; modelID: string } | undefined)[]
) {
function getFirstValidModel(...modelFns: (() => { providerID: string; modelID: string } | undefined)[]) {
for (const modelFn of modelFns) {
const model = modelFn()
if (!model) continue
@@ -213,9 +211,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const current = currentModel()
if (!current) return
const recent = modelStore.recent
const index = recent.findIndex(
(x) => x.providerID === current.providerID && x.modelID === current.modelID,
)
const index = recent.findIndex((x) => x.providerID === current.providerID && x.modelID === current.modelID)
if (index === -1) return
let next = index + direction
if (next < 0) next = recent.length - 1

View File

@@ -146,12 +146,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
}
const result = Binary.search(messages, event.properties.info.id, (m) => m.id)
if (result.found) {
setStore(
"message",
event.properties.info.sessionID,
result.index,
reconcile(event.properties.info),
)
setStore("message", event.properties.info.sessionID, result.index, reconcile(event.properties.info))
break
}
setStore(
@@ -186,12 +181,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
}
const result = Binary.search(parts, event.properties.part.id, (p) => p.id)
if (result.found) {
setStore(
"part",
event.properties.part.messageID,
result.index,
reconcile(event.properties.part),
)
setStore("part", event.properties.part.messageID, result.index, reconcile(event.properties.part))
break
}
setStore(

View File

@@ -528,13 +528,7 @@ function generateSyntax(theme: Theme) {
},
},
{
scope: [
"variable.builtin",
"type.builtin",
"function.builtin",
"module.builtin",
"constant.builtin",
],
scope: ["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin"],
style: {
foreground: theme.error,
},

View File

@@ -26,11 +26,7 @@ export function Home() {
</Match>
<Match when={true}>
<span style={{ fg: theme.success }}></span>{" "}
{Locale.pluralize(
Object.values(sync.data.mcp).length,
"{} mcp server",
"{} mcp servers",
)}
{Locale.pluralize(Object.values(sync.data.mcp).length, "{} mcp server", "{} mcp servers")}
</Match>
</Switch>
</text>
@@ -39,14 +35,7 @@ export function Home() {
)
return (
<box
flexGrow={1}
justifyContent="center"
alignItems="center"
paddingLeft={2}
paddingRight={2}
gap={1}
>
<box flexGrow={1} justifyContent="center" alignItems="center" paddingLeft={2} paddingRight={2} gap={1}>
<Logo />
<box width={39}>
<HelpRow keybind="command_list">Commands</HelpRow>

View File

@@ -7,9 +7,7 @@ import { useRoute } from "@tui/context/route"
export function DialogMessage(props: { messageID: string; sessionID: string }) {
const sync = useSync()
const sdk = useSDK()
const message = createMemo(() =>
sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID),
)
const message = createMemo(() => sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID))
const route = useRoute()
return (

View File

@@ -19,9 +19,7 @@ export function DialogTimeline(props: { sessionID: string; onMove: (messageID: s
const result = [] as DialogSelectOption<string>[]
for (const message of messages) {
if (message.role !== "user") continue
const part = (sync.data.part[message.id] ?? []).find(
(x) => x.type === "text" && !x.synthetic,
) as TextPart
const part = (sync.data.part[message.id] ?? []).find((x) => x.type === "text" && !x.synthetic) as TextPart
if (!part) continue
result.push({
title: part.text.replace(/\n/g, " "),
@@ -35,11 +33,5 @@ export function DialogTimeline(props: { sessionID: string; onMove: (messageID: s
return result
})
return (
<DialogSelect
onMove={(option) => props.onMove(option.value)}
title="Timeline"
options={options()}
/>
)
return <DialogSelect onMove={(option) => props.onMove(option.value)} title="Timeline" options={options()} />
}

View File

@@ -46,16 +46,10 @@ export function Header() {
})
const context = createMemo(() => {
const last = messages().findLast(
(x) => x.role === "assistant" && x.tokens.output > 0,
) as AssistantMessage
const last = messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage
if (!last) return
const total =
last.tokens.input +
last.tokens.output +
last.tokens.reasoning +
last.tokens.cache.read +
last.tokens.cache.write
last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
const model = sync.data.provider.find((x) => x.id === last.providerID)?.models[last.modelID]
let result = total.toLocaleString()
if (model?.limit.context) {
@@ -67,13 +61,7 @@ export function Header() {
const { theme } = useTheme()
return (
<box
paddingLeft={1}
paddingRight={1}
{...SplitBorder}
borderColor={theme.backgroundElement}
flexShrink={0}
>
<box paddingLeft={1} paddingRight={1} {...SplitBorder} borderColor={theme.backgroundElement} flexShrink={0}>
<Show
when={shareEnabled()}
fallback={

View File

@@ -19,14 +19,7 @@ import { SplitBorder } from "@tui/component/border"
import { useTheme } from "@tui/context/theme"
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers } from "@opentui/core"
import { Prompt, type PromptRef } from "@tui/component/prompt"
import type {
AssistantMessage,
Part,
ToolPart,
UserMessage,
TextPart,
ReasoningPart,
} from "@opencode-ai/sdk"
import type { AssistantMessage, Part, ToolPart, UserMessage, TextPart, ReasoningPart } from "@opencode-ai/sdk"
import { useLocal } from "@tui/context/local"
import { Locale } from "@/util/locale"
import type { Tool } from "@/tool/tool"
@@ -41,13 +34,7 @@ import type { EditTool } from "@/tool/edit"
import type { PatchTool } from "@/tool/patch"
import type { WebFetchTool } from "@/tool/webfetch"
import type { TaskTool } from "@/tool/task"
import {
useKeyboard,
useRenderer,
useTerminalDimensions,
type BoxProps,
type JSX,
} from "@opentui/solid"
import { useKeyboard, useRenderer, useTerminalDimensions, type BoxProps, type JSX } from "@opentui/solid"
import { useSDK } from "@tui/context/sdk"
import { useCommandDialog } from "@tui/component/dialog-command"
import { Shimmer } from "@tui/ui/shimmer"
@@ -653,14 +640,7 @@ export function Session() {
conceal,
}}
>
<box
flexDirection="row"
paddingBottom={1}
paddingTop={1}
paddingLeft={2}
paddingRight={2}
gap={2}
>
<box flexDirection="row" paddingBottom={1} paddingTop={1} paddingLeft={2} paddingRight={2} gap={2}>
<box flexGrow={1} gap={1}>
<Show when={session()}>
<Show when={session().parentID}>
@@ -675,19 +655,13 @@ export function Session() {
paddingRight={2}
>
<text fg={theme.text}>
Previous{" "}
<span style={{ fg: theme.textMuted }}>
{keybind.print("session_child_cycle_reverse")}
</span>
Previous <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle_reverse")}</span>
</text>
<text fg={theme.text}>
<b>Viewing subagent session</b>
</text>
<text fg={theme.text}>
<span style={{ fg: theme.textMuted }}>
{keybind.print("session_child_cycle")}
</span>{" "}
Next
<span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle")}</span> Next
</text>
</box>
</Show>
@@ -743,18 +717,12 @@ export function Session() {
paddingTop={1}
paddingBottom={1}
paddingLeft={2}
backgroundColor={
hover() ? theme.backgroundElement : theme.backgroundPanel
}
backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
>
<text fg={theme.textMuted}>{revert()!.reverted.length} message reverted</text>
<text fg={theme.textMuted}>
{revert()!.reverted.length} message reverted
</text>
<text fg={theme.textMuted}>
<span style={{ fg: theme.text }}>
{keybind.print("messages_redo")}
</span>{" "}
or /redo to restore
<span style={{ fg: theme.text }}>{keybind.print("messages_redo")}</span> or /redo to
restore
</text>
<Show when={revert()!.diffFiles?.length}>
<box marginTop={1}>
@@ -763,16 +731,10 @@ export function Session() {
<text>
{file.filename}
<Show when={file.additions > 0}>
<span style={{ fg: theme.diffAdded }}>
{" "}
+{file.additions}
</span>
<span style={{ fg: theme.diffAdded }}> +{file.additions}</span>
</Show>
<Show when={file.deletions > 0}>
<span style={{ fg: theme.diffRemoved }}>
{" "}
-{file.deletions}
</span>
<span style={{ fg: theme.diffRemoved }}> -{file.deletions}</span>
</Show>
</text>
)}
@@ -792,9 +754,7 @@ export function Session() {
index={index()}
onMouseUp={() => {
if (renderer.getSelection()?.getSelectedText()) return
dialog.replace(() => (
<DialogMessage messageID={message.id} sessionID={route.sessionID} />
))
dialog.replace(() => <DialogMessage messageID={message.id} sessionID={route.sessionID} />)
}}
message={message as UserMessage}
parts={sync.data.part[message.id] ?? []}
@@ -850,9 +810,7 @@ function UserMessage(props: {
index: number
pending?: string
}) {
const text = createMemo(
() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0],
)
const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0])
const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : [])))
const sync = useSync()
const { theme } = useTheme()
@@ -893,14 +851,8 @@ function UserMessage(props: {
})
return (
<text fg={theme.text}>
<span style={{ bg: bg(), fg: theme.background }}>
{" "}
{MIME_BADGE[file.mime] ?? file.mime}{" "}
</span>
<span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}>
{" "}
{file.filename}{" "}
</span>
<span style={{ bg: bg(), fg: theme.background }}> {MIME_BADGE[file.mime] ?? file.mime} </span>
<span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}> {file.filename} </span>
</text>
)
}}
@@ -911,16 +863,9 @@ function UserMessage(props: {
{sync.data.config.username ?? "You"}{" "}
<Show
when={queued()}
fallback={
<span style={{ fg: theme.textMuted }}>
({Locale.time(props.message.time.created)})
</span>
}
fallback={<span style={{ fg: theme.textMuted }}>({Locale.time(props.message.time.created)})</span>}
>
<span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}>
{" "}
QUEUED{" "}
</span>
<span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}> QUEUED </span>
</Show>
</text>
</box>
@@ -960,8 +905,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
<Show
when={
!props.message.time.completed ||
(props.last &&
props.parts.some((item) => item.type === "step-finish" && item.reason === "tool-calls"))
(props.last && props.parts.some((item) => item.type === "step-finish" && item.reason === "tool-calls"))
}
>
<box
@@ -973,9 +917,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
customBorderChars={SplitBorder.customBorderChars}
borderColor={theme.backgroundElement}
>
<text fg={local.agent.color(props.message.mode)}>
{Locale.titlecase(props.message.mode)}
</text>
<text fg={local.agent.color(props.message.mode)}>{Locale.titlecase(props.message.mode)}</text>
<Shimmer text={`${props.message.modelID}`} color={theme.text} />
</box>
</Show>
@@ -987,9 +929,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las
>
<box paddingLeft={3}>
<text marginTop={1}>
<span style={{ fg: local.agent.color(props.message.mode) }}>
{Locale.titlecase(props.message.mode)}
</span>{" "}
<span style={{ fg: local.agent.color(props.message.mode) }}>{Locale.titlecase(props.message.mode)}</span>{" "}
<span style={{ fg: theme.textMuted }}>{props.message.modelID}</span>
</text>
</box>
@@ -1016,12 +956,7 @@ function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }
customBorderChars={SplitBorder.customBorderChars}
borderColor={theme.backgroundPanel}
>
<box
paddingTop={1}
paddingBottom={1}
paddingLeft={2}
backgroundColor={theme.backgroundPanel}
>
<box paddingTop={1} paddingBottom={1} paddingLeft={2} backgroundColor={theme.backgroundPanel}>
<text fg={theme.text}>{props.part.text.trim()}</text>
</box>
</box>
@@ -1261,16 +1196,10 @@ ToolRegistry.register<typeof WriteTool>({
</ToolTitle>
<box flexDirection="row">
<box flexShrink={0}>
<For each={numbers()}>
{(value) => <text style={{ fg: theme.textMuted }}>{value}</text>}
</For>
<For each={numbers()}>{(value) => <text style={{ fg: theme.textMuted }}>{value}</text>}</For>
</box>
<box paddingLeft={1} flexGrow={1}>
<code
filetype={filetype(props.input.filePath!)}
syntaxStyle={syntax()}
content={code()}
/>
<code filetype={filetype(props.input.filePath!)} syntaxStyle={syntax()} content={code()} />
</box>
</box>
</>
@@ -1285,8 +1214,7 @@ ToolRegistry.register<typeof GlobTool>({
return (
<>
<ToolTitle icon="✱" fallback="Finding files..." when={props.input.pattern}>
Glob "{props.input.pattern}"{" "}
<Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
Glob "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
<Show when={props.metadata.count}>({props.metadata.count} matches)</Show>
</ToolTitle>
</>
@@ -1300,8 +1228,7 @@ ToolRegistry.register<typeof GrepTool>({
render(props) {
return (
<ToolTitle icon="✱" fallback="Searching content..." when={props.input.pattern}>
Grep "{props.input.pattern}"{" "}
<Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
Grep "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
<Show when={props.metadata.matches}>({props.metadata.matches} matches)</Show>
</ToolTitle>
)
@@ -1337,11 +1264,7 @@ ToolRegistry.register<typeof TaskTool>({
return (
<>
<ToolTitle
icon="%"
fallback="Delegating..."
when={props.input.subagent_type ?? props.input.description}
>
<ToolTitle icon="%" fallback="Delegating..." when={props.input.subagent_type ?? props.input.description}>
Task [{props.input.subagent_type ?? "unknown"}] {props.input.description}
</ToolTitle>
<Show when={props.metadata.summary?.length}>

View File

@@ -22,16 +22,10 @@ export function Sidebar(props: { sessionID: string }) {
})
const context = createMemo(() => {
const last = messages().findLast(
(x) => x.role === "assistant" && x.tokens.output > 0,
) as AssistantMessage
const last = messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage
if (!last) return
const total =
last.tokens.input +
last.tokens.output +
last.tokens.reasoning +
last.tokens.cache.read +
last.tokens.cache.write
last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
const model = sync.data.provider.find((x) => x.id === last.providerID)?.models[last.modelID]
return {
tokens: total.toLocaleString(),
@@ -84,9 +78,7 @@ export function Sidebar(props: { sessionID: string }) {
<span style={{ fg: theme.textMuted }}>
<Switch>
<Match when={item.status === "connected"}>Connected</Match>
<Match when={item.status === "failed" && item}>
{(val) => <i>{val().error}</i>}
</Match>
<Match when={item.status === "failed" && item}>{(val) => <i>{val().error}</i>}</Match>
<Match when={item.status === "disabled"}>Disabled in configuration</Match>
</Switch>
</span>
@@ -162,9 +154,7 @@ export function Sidebar(props: { sessionID: string }) {
</text>
<For each={todo()}>
{(todo) => (
<text
style={{ fg: todo.status === "in_progress" ? theme.success : theme.textMuted }}
>
<text style={{ fg: todo.status === "in_progress" ? theme.success : theme.textMuted }}>
[{todo.status === "completed" ? "✓" : " "}] {todo.content}
</text>
)}

View File

@@ -41,12 +41,7 @@ export const TuiSpawnCommand = cmd({
)
cwd = new URL("../../../../", import.meta.url).pathname
} else cmd.push(process.execPath)
cmd.push(
"attach",
server.url.toString(),
"--dir",
args.project ? path.resolve(args.project) : process.cwd(),
)
cmd.push("attach", server.url.toString(), "--dir", args.project ? path.resolve(args.project) : process.cwd())
const proc = Bun.spawn({
cmd,
cwd,

View File

@@ -99,9 +99,7 @@ export const TuiThreadCommand = cmd({
const worker = new Worker(workerPath, {
env: Object.fromEntries(
Object.entries(process.env).filter(
(entry): entry is [string, string] => entry[1] !== undefined,
),
Object.entries(process.env).filter((entry): entry is [string, string] => entry[1] !== undefined),
),
})
worker.onerror = console.error

View File

@@ -53,9 +53,7 @@ export function DialogConfirm(props: DialogConfirmProps) {
dialog.clear()
}}
>
<text fg={key === store.active ? theme.background : theme.textMuted}>
{Locale.titlecase(key)}
</text>
<text fg={key === store.active ? theme.background : theme.textMuted}>{Locale.titlecase(key)}</text>
</box>
)}
</For>

View File

@@ -20,17 +20,10 @@ export function DialogHelp() {
<text fg={theme.textMuted}>esc/enter</text>
</box>
<box paddingBottom={1}>
<text fg={theme.textMuted}>
Press Ctrl+P to see all available actions and commands in any context.
</text>
<text fg={theme.textMuted}>Press Ctrl+P to see all available actions and commands in any context.</text>
</box>
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
<box
paddingLeft={3}
paddingRight={3}
backgroundColor={theme.primary}
onMouseUp={() => dialog.clear()}
>
<box paddingLeft={3} paddingRight={3} backgroundColor={theme.primary} onMouseUp={() => dialog.clear()}>
<text fg={theme.background}>ok</text>
</box>
</box>

View File

@@ -57,8 +57,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
const result = pipe(
props.options,
filter((x) => x.disabled !== true),
(x) =>
!needle ? x : fuzzysort.go(needle, x, { keys: ["title", "category"] }).map((x) => x.obj),
(x) => (!needle ? x : fuzzysort.go(needle, x, { keys: ["title", "category"] }).map((x) => x.obj)),
)
return result
})
@@ -214,15 +213,11 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
props.onSelect?.(option)
}}
onMouseOver={() => {
const index = filtered().findIndex((x) =>
isDeepEqual(x.value, option.value),
)
const index = filtered().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
backgroundColor={
active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)
}
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
paddingLeft={1}
paddingRight={1}
gap={1}
@@ -230,9 +225,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
<Option
title={option.title}
footer={option.footer}
description={
option.description !== category ? option.description : undefined
}
description={option.description !== category ? option.description : undefined}
active={active()}
current={isDeepEqual(option.value, props.current)}
/>
@@ -248,9 +241,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
<For each={props.keybind ?? []}>
{(item) => (
<text>
<span style={{ fg: theme.text, attributes: TextAttributes.BOLD }}>
{Keybind.toString(item.keybind)}
</span>
<span style={{ fg: theme.text, attributes: TextAttributes.BOLD }}>{Keybind.toString(item.keybind)}</span>
<span style={{ fg: theme.textMuted }}> {item.title}</span>
</text>
)}
@@ -284,10 +275,7 @@ function Option(props: {
wrapMode="none"
>
{Locale.truncate(props.title, 62)}
<span style={{ fg: props.active ? theme.background : theme.textMuted }}>
{" "}
{props.description}
</span>
<span style={{ fg: props.active ? theme.background : theme.textMuted }}> {props.description}</span>
</text>
<Show when={props.footer}>
<box flexShrink={0}>

View File

@@ -5,10 +5,7 @@ import { join } from "node:path"
import { CliRenderer } from "@opentui/core"
export namespace Editor {
export async function open(opts: {
value: string
renderer: CliRenderer
}): Promise<string | undefined> {
export async function open(opts: { value: string; renderer: CliRenderer }): Promise<string | undefined> {
const editor = process.env["EDITOR"]
if (!editor) return