Dax 3 miesięcy temu
rodzic
commit
104a895a71

+ 79 - 6
packages/opencode/src/cli/cmd/tui/app.tsx

@@ -29,6 +29,63 @@ import { Session as SessionApi } from "@/session"
 import { TuiEvent } from "./event"
 import { TuiEvent } from "./event"
 import { KVProvider, useKV } from "./context/kv"
 import { KVProvider, useKV } from "./context/kv"
 
 
+async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
+  return new Promise((resolve) => {
+    let timeout: NodeJS.Timeout
+
+    const cleanup = () => {
+      process.stdin.setRawMode(false)
+      process.stdin.removeListener("data", handler)
+      clearTimeout(timeout)
+    }
+
+    const handler = (data: Buffer) => {
+      const str = data.toString()
+      const match = str.match(/\x1b]11;([^\x07\x1b]+)/)
+      if (match) {
+        cleanup()
+        const color = match[1]
+        // Parse RGB values from color string
+        // Formats: rgb:RR/GG/BB or #RRGGBB or rgb(R,G,B)
+        let r = 0,
+          g = 0,
+          b = 0
+
+        if (color.startsWith("rgb:")) {
+          const parts = color.substring(4).split("/")
+          r = parseInt(parts[0], 16) >> 8 // Convert 16-bit to 8-bit
+          g = parseInt(parts[1], 16) >> 8 // Convert 16-bit to 8-bit
+          b = parseInt(parts[2], 16) >> 8 // Convert 16-bit to 8-bit
+        } else if (color.startsWith("#")) {
+          r = parseInt(color.substring(1, 3), 16)
+          g = parseInt(color.substring(3, 5), 16)
+          b = parseInt(color.substring(5, 7), 16)
+        } else if (color.startsWith("rgb(")) {
+          const parts = color.substring(4, color.length - 1).split(",")
+          r = parseInt(parts[0])
+          g = parseInt(parts[1])
+          b = parseInt(parts[2])
+        }
+
+        // Calculate luminance using relative luminance formula
+        const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
+
+        // Determine if dark or light based on luminance threshold
+        resolve(luminance > 0.5 ? "light" : "dark")
+      }
+    }
+
+    process.stdin.setRawMode(true)
+    process.stdin.on("data", handler)
+    process.stdout.write("\x1b]11;?\x07")
+
+    timeout = setTimeout(() => {
+      cleanup()
+      resolve("dark")
+    }, 1000)
+  })
+}
+
 export function tui(input: {
 export function tui(input: {
   url: string
   url: string
   sessionID?: string
   sessionID?: string
@@ -38,7 +95,9 @@ export function tui(input: {
   onExit?: () => Promise<void>
   onExit?: () => Promise<void>
 }) {
 }) {
   // promise to prevent immediate exit
   // promise to prevent immediate exit
-  return new Promise<void>((resolve) => {
+  return new Promise<void>(async (resolve) => {
+    const mode = await getTerminalBackgroundColor()
+
     const routeData: Route | undefined = input.sessionID
     const routeData: Route | undefined = input.sessionID
       ? {
       ? {
           type: "session",
           type: "session",
@@ -65,8 +124,12 @@ export function tui(input: {
                   <RouteProvider data={routeData}>
                   <RouteProvider data={routeData}>
                     <SDKProvider url={input.url}>
                     <SDKProvider url={input.url}>
                       <SyncProvider>
                       <SyncProvider>
-                        <ThemeProvider>
-                          <LocalProvider initialModel={input.model} initialAgent={input.agent} initialPrompt={input.prompt}>
+                        <ThemeProvider mode={mode}>
+                          <LocalProvider
+                            initialModel={input.model}
+                            initialAgent={input.agent}
+                            initialPrompt={input.prompt}
+                          >
                             <KeybindProvider>
                             <KeybindProvider>
                               <DialogProvider>
                               <DialogProvider>
                                 <CommandProvider>
                                 <CommandProvider>
@@ -109,7 +172,7 @@ function App() {
   const sync = useSync()
   const sync = useSync()
   const toast = useToast()
   const toast = useToast()
   const [sessionExists, setSessionExists] = createSignal(false)
   const [sessionExists, setSessionExists] = createSignal(false)
-  const { theme } = useTheme()
+  const { theme, mode, setMode } = useTheme()
   const exit = useExit()
   const exit = useExit()
 
 
   useKeyboard(async (evt) => {
   useKeyboard(async (evt) => {
@@ -238,6 +301,14 @@ function App() {
       },
       },
       category: "System",
       category: "System",
     },
     },
+    {
+      title: `Switch to ${mode() === "dark" ? "light" : "dark"} mode`,
+      value: "theme.switch_mode",
+      onSelect: () => {
+        setMode(mode() === "dark" ? "light" : "dark")
+      },
+      category: "System",
+    },
     {
     {
       title: "Help",
       title: "Help",
       value: "help.show",
       value: "help.show",
@@ -251,7 +322,7 @@ function App() {
       value: "app.exit",
       value: "app.exit",
       onSelect: exit,
       onSelect: exit,
       category: "System",
       category: "System",
-    }
+    },
   ])
   ])
 
 
   createEffect(() => {
   createEffect(() => {
@@ -335,7 +406,9 @@ function App() {
             paddingRight={1}
             paddingRight={1}
           >
           >
             <text fg={theme.textMuted}>open</text>
             <text fg={theme.textMuted}>open</text>
-            <text attributes={TextAttributes.BOLD}>code </text>
+            <text fg={theme.text} attributes={TextAttributes.BOLD}>
+              code{" "}
+            </text>
             <text fg={theme.textMuted}>v{Installation.VERSION}</text>
             <text fg={theme.textMuted}>v{Installation.VERSION}</text>
           </box>
           </box>
           <box paddingLeft={1} paddingRight={1}>
           <box paddingLeft={1} paddingRight={1}>

+ 13 - 8
packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx

@@ -14,12 +14,14 @@ export function DialogStatus() {
   return (
   return (
     <box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
     <box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
       <box flexDirection="row" justifyContent="space-between">
       <box flexDirection="row" justifyContent="space-between">
-        <text attributes={TextAttributes.BOLD}>Status</text>
+        <text fg={theme.text} attributes={TextAttributes.BOLD}>
+          Status
+        </text>
         <text fg={theme.textMuted}>esc</text>
         <text fg={theme.textMuted}>esc</text>
       </box>
       </box>
       <Show when={Object.keys(sync.data.mcp).length > 0} fallback={<text>No MCP Servers</text>}>
       <Show when={Object.keys(sync.data.mcp).length > 0} fallback={<text>No MCP Servers</text>}>
         <box>
         <box>
-          <text>{Object.keys(sync.data.mcp).length} MCP Servers</text>
+          <text fg={theme.text}>{Object.keys(sync.data.mcp).length} MCP Servers</text>
           <For each={Object.entries(sync.data.mcp)}>
           <For each={Object.entries(sync.data.mcp)}>
             {([key, item]) => (
             {([key, item]) => (
               <box flexDirection="row" gap={1}>
               <box flexDirection="row" gap={1}>
@@ -35,7 +37,7 @@ export function DialogStatus() {
                 >
                 >
                 </text>
                 </text>
-                <text wrapMode="word">
+                <text fg={theme.text} wrapMode="word">
                   <b>{key}</b>{" "}
                   <b>{key}</b>{" "}
                   <span style={{ fg: theme.textMuted }}>
                   <span style={{ fg: theme.textMuted }}>
                     <Switch>
                     <Switch>
@@ -52,7 +54,7 @@ export function DialogStatus() {
       </Show>
       </Show>
       {sync.data.lsp.length > 0 && (
       {sync.data.lsp.length > 0 && (
         <box>
         <box>
-          <text>{sync.data.lsp.length} LSP Servers</text>
+          <text fg={theme.text}>{sync.data.lsp.length} LSP Servers</text>
           <For each={sync.data.lsp}>
           <For each={sync.data.lsp}>
             {(item) => (
             {(item) => (
               <box flexDirection="row" gap={1}>
               <box flexDirection="row" gap={1}>
@@ -67,7 +69,7 @@ export function DialogStatus() {
                 >
                 >
                 </text>
                 </text>
-                <text wrapMode="word">
+                <text fg={theme.text} wrapMode="word">
                   <b>{item.id}</b> <span style={{ fg: theme.textMuted }}>{item.root}</span>
                   <b>{item.id}</b> <span style={{ fg: theme.textMuted }}>{item.root}</span>
                 </text>
                 </text>
               </box>
               </box>
@@ -75,9 +77,12 @@ export function DialogStatus() {
           </For>
           </For>
         </box>
         </box>
       )}
       )}
-      <Show when={enabledFormatters().length > 0} fallback={<text>No Formatters</text>}>
+      <Show
+        when={enabledFormatters().length > 0}
+        fallback={<text fg={theme.text}>No Formatters</text>}
+      >
         <box>
         <box>
-          <text>{enabledFormatters().length} Formatters</text>
+          <text fg={theme.text}>{enabledFormatters().length} Formatters</text>
           <For each={enabledFormatters()}>
           <For each={enabledFormatters()}>
             {(item) => (
             {(item) => (
               <box flexDirection="row" gap={1}>
               <box flexDirection="row" gap={1}>
@@ -89,7 +94,7 @@ export function DialogStatus() {
                 >
                 >
                 </text>
                 </text>
-                <text wrapMode="word">
+                <text wrapMode="word" fg={theme.text}>
                   <b>{item.name}</b>
                   <b>{item.name}</b>
                 </text>
                 </text>
               </box>
               </box>

+ 12 - 12
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

@@ -11,7 +11,7 @@ import {
 } from "@opentui/core"
 } from "@opentui/core"
 import { createEffect, createMemo, Match, Switch, type JSX, onMount, batch } from "solid-js"
 import { createEffect, createMemo, Match, Switch, type JSX, onMount, batch } from "solid-js"
 import { useLocal } from "@tui/context/local"
 import { useLocal } from "@tui/context/local"
-import { SyntaxTheme, useTheme } from "@tui/context/theme"
+import { useTheme } from "@tui/context/theme"
 import { SplitBorder } from "@tui/component/border"
 import { SplitBorder } from "@tui/component/border"
 import { useSDK } from "@tui/context/sdk"
 import { useSDK } from "@tui/context/sdk"
 import { useRoute } from "@tui/context/route"
 import { useRoute } from "@tui/context/route"
@@ -60,7 +60,7 @@ export function Prompt(props: PromptProps) {
   const history = usePromptHistory()
   const history = usePromptHistory()
   const command = useCommandDialog()
   const command = useCommandDialog()
   const renderer = useRenderer()
   const renderer = useRenderer()
-  const { theme } = useTheme()
+  const { theme, syntax } = useTheme()
 
 
   const textareaKeybindings = createMemo(() => {
   const textareaKeybindings = createMemo(() => {
     const newlineBindings = keybind.all.input_newline || []
     const newlineBindings = keybind.all.input_newline || []
@@ -86,9 +86,9 @@ export function Prompt(props: PromptProps) {
     ]
     ]
   })
   })
 
 
-  const fileStyleId = SyntaxTheme.getStyleId("extmark.file")!
-  const agentStyleId = SyntaxTheme.getStyleId("extmark.agent")!
-  const pasteStyleId = SyntaxTheme.getStyleId("extmark.paste")!
+  const fileStyleId = syntax().getStyleId("extmark.file")!
+  const agentStyleId = syntax().getStyleId("extmark.agent")!
+  const pasteStyleId = syntax().getStyleId("extmark.paste")!
   let promptPartTypeId: number
   let promptPartTypeId: number
 
 
   command.register(() => {
   command.register(() => {
@@ -315,9 +315,9 @@ export function Prompt(props: PromptProps) {
     const sessionID = props.sessionID
     const sessionID = props.sessionID
       ? props.sessionID
       ? props.sessionID
       : await (async () => {
       : await (async () => {
-        const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id)
-        return sessionID
-      })()
+          const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id)
+          return sessionID
+        })()
     const messageID = Identifier.ascending("message")
     const messageID = Identifier.ascending("message")
     let inputText = store.prompt.input
     let inputText = store.prompt.input
 
 
@@ -680,7 +680,7 @@ export function Prompt(props: PromptProps) {
               onMouseDown={(r: MouseEvent) => r.target?.focus()}
               onMouseDown={(r: MouseEvent) => r.target?.focus()}
               focusedBackgroundColor={theme.backgroundElement}
               focusedBackgroundColor={theme.backgroundElement}
               cursorColor={theme.primary}
               cursorColor={theme.primary}
-              syntaxStyle={SyntaxTheme}
+              syntaxStyle={syntax()}
             />
             />
           </box>
           </box>
           <box
           <box
@@ -691,7 +691,7 @@ export function Prompt(props: PromptProps) {
           ></box>
           ></box>
         </box>
         </box>
         <box flexDirection="row" justifyContent="space-between">
         <box flexDirection="row" justifyContent="space-between">
-          <text flexShrink={0} wrapMode="none">
+          <text flexShrink={0} wrapMode="none" fg={theme.text}>
             <span style={{ fg: theme.textMuted }}>{local.model.parsed().provider}</span>{" "}
             <span style={{ fg: theme.textMuted }}>{local.model.parsed().provider}</span>{" "}
             <span style={{ bold: true }}>{local.model.parsed().model}</span>
             <span style={{ bold: true }}>{local.model.parsed().model}</span>
           </text>
           </text>
@@ -701,14 +701,14 @@ export function Prompt(props: PromptProps) {
             </Match>
             </Match>
             <Match when={status() === "working"}>
             <Match when={status() === "working"}>
               <box flexDirection="row" gap={1}>
               <box flexDirection="row" gap={1}>
-                <text>
+                <text fg={theme.text}>
                   esc <span style={{ fg: theme.textMuted }}>interrupt</span>
                   esc <span style={{ fg: theme.textMuted }}>interrupt</span>
                 </text>
                 </text>
               </box>
               </box>
             </Match>
             </Match>
             <Match when={props.hint}>{props.hint!}</Match>
             <Match when={props.hint}>{props.hint!}</Match>
             <Match when={true}>
             <Match when={true}>
-              <text>
+              <text fg={theme.text}>
                 ctrl+p <span style={{ fg: theme.textMuted }}>commands</span>
                 ctrl+p <span style={{ fg: theme.textMuted }}>commands</span>
               </text>
               </text>
             </Match>
             </Match>

Plik diff jest za duży
+ 538 - 529
packages/opencode/src/cli/cmd/tui/context/theme.tsx


+ 2 - 2
packages/opencode/src/cli/cmd/tui/routes/home.tsx

@@ -27,7 +27,7 @@ export function Home() {
   const Hint = (
   const Hint = (
     <Show when={Object.keys(sync.data.mcp).length > 0}>
     <Show when={Object.keys(sync.data.mcp).length > 0}>
       <box flexShrink={0} flexDirection="row" gap={1}>
       <box flexShrink={0} flexDirection="row" gap={1}>
-        <text>
+        <text fg={theme.text}>
           <Switch>
           <Switch>
             <Match when={mcpError()}>
             <Match when={mcpError()}>
               <span style={{ fg: theme.error }}>•</span> mcp errors{" "}
               <span style={{ fg: theme.error }}>•</span> mcp errors{" "}
@@ -76,7 +76,7 @@ function HelpRow(props: ParentProps<{ keybind: keyof KeybindsConfig }>) {
   const { theme } = useTheme()
   const { theme } = useTheme()
   return (
   return (
     <box flexDirection="row" justifyContent="space-between" width="100%">
     <box flexDirection="row" justifyContent="space-between" width="100%">
-      <text>{props.children}</text>
+      <text fg={theme.text}>{props.children}</text>
       <text fg={theme.primary}>{keybind.print(props.keybind)}</text>
       <text fg={theme.primary}>{keybind.print(props.keybind)}</text>
     </box>
     </box>
   )
   )

+ 2 - 2
packages/opencode/src/cli/cmd/tui/routes/session/header.tsx

@@ -51,7 +51,7 @@ export function Header() {
       borderColor={theme.backgroundElement}
       borderColor={theme.backgroundElement}
       flexShrink={0}
       flexShrink={0}
     >
     >
-      <text>
+      <text fg={theme.text}>
         <span style={{ bold: true, fg: theme.accent }}>#</span>{" "}
         <span style={{ bold: true, fg: theme.accent }}>#</span>{" "}
         <span style={{ bold: true }}>{session().title}</span>
         <span style={{ bold: true }}>{session().title}</span>
       </text>
       </text>
@@ -64,7 +64,7 @@ export function Header() {
               </text>
               </text>
             </Match>
             </Match>
             <Match when={true}>
             <Match when={true}>
-              <text wrapMode="word">
+              <text fg={theme.text} wrapMode="word">
                 /share <span style={{ fg: theme.textMuted }}>to create a shareable link</span>
                 /share <span style={{ fg: theme.textMuted }}>to create a shareable link</span>
               </text>
               </text>
             </Match>
             </Match>

+ 16 - 13
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -15,7 +15,7 @@ import path from "path"
 import { useRouteData } from "@tui/context/route"
 import { useRouteData } from "@tui/context/route"
 import { useSync } from "@tui/context/sync"
 import { useSync } from "@tui/context/sync"
 import { SplitBorder } from "@tui/component/border"
 import { SplitBorder } from "@tui/component/border"
-import { SyntaxTheme, useTheme } from "@tui/context/theme"
+import { useTheme } from "@tui/context/theme"
 import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers } from "@opentui/core"
 import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers } from "@opentui/core"
 import { Prompt, type PromptRef } from "@tui/component/prompt"
 import { Prompt, type PromptRef } from "@tui/component/prompt"
 import type {
 import type {
@@ -641,7 +641,7 @@ function UserMessage(props: {
         borderColor={color()}
         borderColor={color()}
         flexShrink={0}
         flexShrink={0}
       >
       >
-        <text>{text()?.text}</text>
+        <text fg={theme.text}>{text()?.text}</text>
         <Show when={files().length}>
         <Show when={files().length}>
           <box flexDirection="row" paddingBottom={1} paddingTop={1} gap={1} flexWrap="wrap">
           <box flexDirection="row" paddingBottom={1} paddingTop={1} gap={1} flexWrap="wrap">
             <For each={files()}>
             <For each={files()}>
@@ -652,7 +652,7 @@ function UserMessage(props: {
                   return theme.secondary
                   return theme.secondary
                 })
                 })
                 return (
                 return (
-                  <text>
+                  <text fg={theme.text}>
                     <span style={{ bg: bg(), fg: theme.background }}>
                     <span style={{ bg: bg(), fg: theme.background }}>
                       {" "}
                       {" "}
                       {MIME_BADGE[file.mime] ?? file.mime}{" "}
                       {MIME_BADGE[file.mime] ?? file.mime}{" "}
@@ -667,7 +667,7 @@ function UserMessage(props: {
             </For>
             </For>
           </box>
           </box>
         </Show>
         </Show>
-        <text>
+        <text fg={theme.text}>
           {sync.data.config.username ?? "You"}{" "}
           {sync.data.config.username ?? "You"}{" "}
           <Show
           <Show
             when={queued()}
             when={queued()}
@@ -782,7 +782,7 @@ function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }
           paddingLeft={2}
           paddingLeft={2}
           backgroundColor={theme.backgroundPanel}
           backgroundColor={theme.backgroundPanel}
         >
         >
-          <text>{props.part.text.trim()}</text>
+          <text fg={theme.text}>{props.part.text.trim()}</text>
         </box>
         </box>
       </box>
       </box>
     </Show>
     </Show>
@@ -791,13 +791,14 @@ function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }
 
 
 function TextPart(props: { part: TextPart; message: AssistantMessage }) {
 function TextPart(props: { part: TextPart; message: AssistantMessage }) {
   const ctx = use()
   const ctx = use()
+  const { syntax } = useTheme()
   return (
   return (
     <Show when={props.part.text.trim()}>
     <Show when={props.part.text.trim()}>
       <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
       <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
         <code
         <code
           filetype="markdown"
           filetype="markdown"
           drawUnstyledText={false}
           drawUnstyledText={false}
-          syntaxStyle={SyntaxTheme}
+          syntaxStyle={syntax()}
           content={props.part.text.trim()}
           content={props.part.text.trim()}
           conceal={ctx.conceal()}
           conceal={ctx.conceal()}
         />
         />
@@ -997,7 +998,7 @@ ToolRegistry.register<typeof WriteTool>({
   name: "write",
   name: "write",
   container: "block",
   container: "block",
   render(props) {
   render(props) {
-    const { theme } = useTheme()
+    const { theme, syntax } = useTheme()
     const lines = createMemo(() => {
     const lines = createMemo(() => {
       return props.input.content?.split("\n") ?? []
       return props.input.content?.split("\n") ?? []
     })
     })
@@ -1028,7 +1029,7 @@ ToolRegistry.register<typeof WriteTool>({
           <box paddingLeft={1} flexGrow={1}>
           <box paddingLeft={1} flexGrow={1}>
             <code
             <code
               filetype={filetype(props.input.filePath!)}
               filetype={filetype(props.input.filePath!)}
-              syntaxStyle={SyntaxTheme}
+              syntaxStyle={syntax()}
               content={code()}
               content={code()}
             />
             />
           </box>
           </box>
@@ -1131,6 +1132,7 @@ ToolRegistry.register<typeof EditTool>({
   container: "block",
   container: "block",
   render(props) {
   render(props) {
     const ctx = use()
     const ctx = use()
+    const { theme, syntax } = useTheme()
 
 
     const style = createMemo(() => (ctx.width > 120 ? "split" : "stacked"))
     const style = createMemo(() => (ctx.width > 120 ? "split" : "stacked"))
 
 
@@ -1210,21 +1212,21 @@ ToolRegistry.register<typeof EditTool>({
         </ToolTitle>
         </ToolTitle>
         <Switch>
         <Switch>
           <Match when={props.permission["diff"]}>
           <Match when={props.permission["diff"]}>
-            <text>{props.permission["diff"]?.trim()}</text>
+            <text fg={theme.text}>{props.permission["diff"]?.trim()}</text>
           </Match>
           </Match>
           <Match when={diff() && style() === "split"}>
           <Match when={diff() && style() === "split"}>
             <box paddingLeft={1} flexDirection="row" gap={2}>
             <box paddingLeft={1} flexDirection="row" gap={2}>
               <box flexGrow={1} flexBasis={0}>
               <box flexGrow={1} flexBasis={0}>
-                <code filetype={ft()} syntaxStyle={SyntaxTheme} content={diff()!.oldContent} />
+                <code filetype={ft()} syntaxStyle={syntax()} content={diff()!.oldContent} />
               </box>
               </box>
               <box flexGrow={1} flexBasis={0}>
               <box flexGrow={1} flexBasis={0}>
-                <code filetype={ft()} syntaxStyle={SyntaxTheme} content={diff()!.newContent} />
+                <code filetype={ft()} syntaxStyle={syntax()} content={diff()!.newContent} />
               </box>
               </box>
             </box>
             </box>
           </Match>
           </Match>
           <Match when={code()}>
           <Match when={code()}>
             <box paddingLeft={1}>
             <box paddingLeft={1}>
-              <code filetype={ft()} syntaxStyle={SyntaxTheme} content={code()} />
+              <code filetype={ft()} syntaxStyle={syntax()} content={code()} />
             </box>
             </box>
           </Match>
           </Match>
         </Switch>
         </Switch>
@@ -1237,6 +1239,7 @@ ToolRegistry.register<typeof PatchTool>({
   name: "patch",
   name: "patch",
   container: "block",
   container: "block",
   render(props) {
   render(props) {
+    const { theme } = useTheme()
     return (
     return (
       <>
       <>
         <ToolTitle icon="%" fallback="Preparing patch..." when={true}>
         <ToolTitle icon="%" fallback="Preparing patch..." when={true}>
@@ -1244,7 +1247,7 @@ ToolRegistry.register<typeof PatchTool>({
         </ToolTitle>
         </ToolTitle>
         <Show when={props.output}>
         <Show when={props.output}>
           <box>
           <box>
-            <text>{props.output?.trim()}</text>
+            <text fg={theme.text}>{props.output?.trim()}</text>
           </box>
           </box>
         </Show>
         </Show>
       </>
       </>

+ 7 - 7
packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx

@@ -42,7 +42,7 @@ export function Sidebar(props: { sessionID: string }) {
     <Show when={session()}>
     <Show when={session()}>
       <box flexShrink={0} gap={1} width={40}>
       <box flexShrink={0} gap={1} width={40}>
         <box>
         <box>
-          <text>
+          <text fg={theme.text}>
             <b>{session().title}</b>
             <b>{session().title}</b>
           </text>
           </text>
           <Show when={session().share?.url}>
           <Show when={session().share?.url}>
@@ -50,7 +50,7 @@ export function Sidebar(props: { sessionID: string }) {
           </Show>
           </Show>
         </box>
         </box>
         <box>
         <box>
-          <text>
+          <text fg={theme.text}>
             <b>Context</b>
             <b>Context</b>
           </text>
           </text>
           <text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text>
           <text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text>
@@ -59,7 +59,7 @@ export function Sidebar(props: { sessionID: string }) {
         </box>
         </box>
         <Show when={Object.keys(sync.data.mcp).length > 0}>
         <Show when={Object.keys(sync.data.mcp).length > 0}>
           <box>
           <box>
-            <text>
+            <text fg={theme.text}>
               <b>MCP</b>
               <b>MCP</b>
             </text>
             </text>
             <For each={Object.entries(sync.data.mcp)}>
             <For each={Object.entries(sync.data.mcp)}>
@@ -77,7 +77,7 @@ export function Sidebar(props: { sessionID: string }) {
                   >
                   >
                   </text>
                   </text>
-                  <text wrapMode="word">
+                  <text fg={theme.text} wrapMode="word">
                     {key}{" "}
                     {key}{" "}
                     <span style={{ fg: theme.textMuted }}>
                     <span style={{ fg: theme.textMuted }}>
                       <Switch>
                       <Switch>
@@ -96,7 +96,7 @@ export function Sidebar(props: { sessionID: string }) {
         </Show>
         </Show>
         <Show when={sync.data.lsp.length > 0}>
         <Show when={sync.data.lsp.length > 0}>
           <box>
           <box>
-            <text>
+            <text fg={theme.text}>
               <b>LSP</b>
               <b>LSP</b>
             </text>
             </text>
             <For each={sync.data.lsp}>
             <For each={sync.data.lsp}>
@@ -123,7 +123,7 @@ export function Sidebar(props: { sessionID: string }) {
         </Show>
         </Show>
         <Show when={session().summary?.diffs}>
         <Show when={session().summary?.diffs}>
           <box>
           <box>
-            <text>
+            <text fg={theme.text}>
               <b>Modified Files</b>
               <b>Modified Files</b>
             </text>
             </text>
             <For each={session().summary?.diffs || []}>
             <For each={session().summary?.diffs || []}>
@@ -155,7 +155,7 @@ export function Sidebar(props: { sessionID: string }) {
         </Show>
         </Show>
         <Show when={todo().length > 0}>
         <Show when={todo().length > 0}>
           <box>
           <box>
-            <text>
+            <text fg={theme.text}>
               <b>Todo</b>
               <b>Todo</b>
             </text>
             </text>
             <For each={todo()}>
             <For each={todo()}>

+ 3 - 1
packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx

@@ -161,7 +161,9 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
     <box gap={1}>
     <box gap={1}>
       <box paddingLeft={3} paddingRight={2}>
       <box paddingLeft={3} paddingRight={2}>
         <box flexDirection="row" justifyContent="space-between">
         <box flexDirection="row" justifyContent="space-between">
-          <text attributes={TextAttributes.BOLD}>{props.title}</text>
+          <text fg={theme.text} attributes={TextAttributes.BOLD}>
+            {props.title}
+          </text>
           <text fg={theme.textMuted}>esc</text>
           <text fg={theme.textMuted}>esc</text>
         </box>
         </box>
         <box paddingTop={1} paddingBottom={1}>
         <box paddingTop={1} paddingBottom={1}>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików