ソースを参照

fix(tui): simplify thinking toggle styling (#28487)

Aiden Cline 3 ヶ月 前
コミット
f5a8202b41

+ 8 - 0
AGENTS.md

@@ -4,6 +4,14 @@
 - Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
 - Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility.
 
+## Commits and PR Titles
+
+Use conventional commit-style messages and PR titles: `type(scope): summary`.
+
+Valid types are `feat`, `fix`, `docs`, `chore`, `refactor`, and `test`. Scopes are optional; use the affected package or area when helpful, e.g. `core`, `opencode`, `tui`, `app`, `desktop`, `sdk`, or `plugin`.
+
+Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`.
+
 ## Style Guide
 
 ### General Principles

+ 19 - 9
packages/opencode/src/cli/cmd/tui/feature-plugins/system/session-v2.tsx

@@ -411,12 +411,9 @@ function AssistantReasoning(props: {
       <Switch>
         <Match when={!inMinimal() || expanded()}>
           <box
-            paddingLeft={2}
+            paddingLeft={3}
             marginTop={1}
             flexDirection="column"
-            border={["left"]}
-            customBorderChars={SplitBorder.customBorderChars}
-            borderColor={theme.backgroundElement}
             flexShrink={0}
             onMouseUp={toggle}
           >
@@ -425,17 +422,20 @@ function AssistantReasoning(props: {
               drawUnstyledText={false}
               streaming={true}
               syntaxStyle={props.subtleSyntax}
-              content={(inMinimal() ? " " : "") + "_Thinking:_ " + content()}
+              content={(inMinimal() ? "- " : "") + "_Thinking:_ " + content()}
               conceal={true}
               fg={theme.textMuted}
             />
           </box>
         </Match>
         <Match when={isDone()}>
-          <box paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
-            <text fg={theme.textMuted} wrapMode="none">
-              {title() ? "▶ Thought: " + title() : "▶ Thought"}
-            </text>
+          <box
+            paddingLeft={3}
+            marginTop={1}
+            flexShrink={0}
+            onMouseUp={toggle}
+          >
+            <CollapsedReasoningText title={title()} />
           </box>
         </Match>
         <Match when={true}>
@@ -448,6 +448,16 @@ function AssistantReasoning(props: {
   )
 }
 
+function CollapsedReasoningText(props: { title: string | null }) {
+  const { theme } = useTheme()
+
+  return (
+    <text fg={theme.warning} wrapMode="none">
+      <span style={{ fg: theme.warning, italic: true }}>{props.title ? "+ Thought · " + props.title : "+ Thought"}</span>
+    </text>
+  )
+}
+
 function AssistantTool(props: { part: SessionMessageAssistantTool; sessionID: string }) {
   const input = createMemo(() => toolInputRecord(props.part.state.input))
   const toolprops = {

+ 23 - 15
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -1533,12 +1533,9 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
           {/* Full markdown block: `show` mode, or `hide` after the user opens it. */}
           <box
             id={"text-" + props.part.id}
-            paddingLeft={2}
+            paddingLeft={3}
             marginTop={1}
             flexDirection="column"
-            border={["left"]}
-            customBorderChars={SplitBorder.customBorderChars}
-            borderColor={theme.backgroundElement}
             onMouseUp={toggle}
           >
             <code
@@ -1546,26 +1543,24 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
               drawUnstyledText={false}
               streaming={true}
               syntaxStyle={subtleSyntax()}
-              content={(inMinimal() ? " " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
+              content={(inMinimal() ? "- " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
               conceal={ctx.conceal()}
               fg={theme.textMuted}
             />
           </box>
         </Match>
         <Match when={isDone()}>
-          {/* Settled: ▶ at the start as the click-to-expand cue. */}
-          <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
-            <text fg={theme.textMuted} wrapMode="none">
-              {"▶ " +
-                (title()
-                  ? "Thought: " + title() + " · " + Locale.duration(duration())
-                  : "Thought for " + Locale.duration(duration()))}
-            </text>
+          <box
+            id={"text-" + props.part.id}
+            paddingLeft={3}
+            marginTop={1}
+            flexShrink={0}
+            onMouseUp={toggle}
+          >
+            <CollapsedReasoningText title={title()} duration={duration()} />
           </box>
         </Match>
         <Match when={true}>
-          {/* Streaming: leading animated spinner, no disclosure arrow yet — it
-              snaps in once reasoning settles, signalling "done, click to expand". */}
           <box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
             <Spinner color={theme.textMuted}>{title() ? "Thinking: " + title() : "Thinking"}</Spinner>
           </box>
@@ -1575,6 +1570,19 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
   )
 }
 
+function CollapsedReasoningText(props: { title: string | null; duration: number }) {
+  const { theme } = useTheme()
+  const duration = () => Locale.duration(props.duration)
+
+  return (
+    <text fg={theme.warning} wrapMode="none">
+      <span style={{ fg: theme.warning, italic: true }}>
+        {props.title ? "+ Thought · " + props.title + " · " + duration() : "+ Thought · " + duration()}
+      </span>
+    </text>
+  )
+}
+
 function TextPart(props: { last: boolean; part: TextPart; message: AssistantMessage }) {
   const ctx = use()
   const { theme, syntax } = useTheme()