opentui(v6): tool-name emphasis, thought styling, HERMES_TUI_TOOL_OUTPUT_LINES
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
* copies only the expanded body content. Fully themed (no hardcoded styles).
|
||||
*/
|
||||
import { type ToolPartState } from '../logic/store.ts'
|
||||
import type { ThemeColors } from '../logic/theme.ts'
|
||||
import { useDimensions } from './dimensions.tsx'
|
||||
import { createSignal, Show } from 'solid-js'
|
||||
|
||||
@@ -49,6 +50,24 @@ function fmtElapsed(s: number): string {
|
||||
return r ? `${m}m ${r}s` : `${m}m`
|
||||
}
|
||||
|
||||
/**
|
||||
* Header tool-NAME style — the name is the PRIMARY cue for what a settled tool
|
||||
* IS, so it renders in the primary text color + BOLD (the transcript otherwise
|
||||
* reads as undifferentiated muted rows). The failed state's error coloring
|
||||
* wins (still bold — failures should be unmistakable alongside the ✗ glyph);
|
||||
* a running part keeps its current muted treatment (the ⚡ glyph + live
|
||||
* elapsed already carry the running signal). Exported so tests can pin the
|
||||
* selection logic (char frames carry no color/attribute info).
|
||||
*/
|
||||
export function toolNameStyle(
|
||||
state: { failed: boolean; running: boolean },
|
||||
color: ThemeColors
|
||||
): { fg: string; bold: boolean } {
|
||||
if (state.failed) return { bold: true, fg: color.error }
|
||||
if (state.running) return { bold: false, fg: color.muted }
|
||||
return { bold: true, fg: color.text }
|
||||
}
|
||||
|
||||
/**
|
||||
* Live ` · 12s` elapsed for a RUNNING part. Mounted only under the running
|
||||
* `<Show>`, so its useElapsedTick subscription starts/stops the SHARED 1s
|
||||
@@ -92,8 +111,9 @@ export function ToolPart(props: { part: ToolPartState }) {
|
||||
// expandable body. `error` only lands on tool.complete, so running stays ⚡.
|
||||
const failed = () => !running() && Boolean(props.part.error)
|
||||
const headGlyph = () => (failed() ? '✗' : collapsible() ? (expanded() ? '▼' : '▶') : '⚡')
|
||||
// accent glyph MARKS the tool (draws the eye); the rest is muted so tools read
|
||||
// as the dim, secondary tier below the bright assistant answer (Ink hierarchy).
|
||||
// accent glyph MARKS the tool (draws the eye); the NAME is primary (bold text
|
||||
// via toolNameStyle) so WHAT the tool is reads at a glance; subtitle/metadata
|
||||
// stay muted — the secondary tier below the bright assistant answer.
|
||||
const headColor = () => (failed() ? theme().color.error : theme().color.accent)
|
||||
const subWidth = () => Math.max(1, bodyWidth() - props.part.name.length - 2)
|
||||
|
||||
@@ -114,7 +134,11 @@ export function ToolPart(props: { part: ToolPartState }) {
|
||||
free-form drag over a tool yields only the expanded body content,
|
||||
never the header label. */}
|
||||
<text selectable={false}>
|
||||
<span style={{ fg: theme().color.muted }}>{props.part.name}</span>
|
||||
{/* the NAME is the primary cue (text + bold; error when failed;
|
||||
muted while running) — see toolNameStyle. Subtitle stays muted. */}
|
||||
<span style={toolNameStyle({ failed: failed(), running: running() }, theme().color)}>
|
||||
{props.part.name}
|
||||
</span>
|
||||
{/* subtitle shows while running too (the gateway argsPreview — e.g.
|
||||
the command being executed) so a running tool reads `⚡ terminal
|
||||
sleep 8 · 12s`, Ink parity. */}
|
||||
|
||||
Reference in New Issue
Block a user