diff --git a/ui-tui/src/app.tsx b/ui-tui/src/app.tsx
index 45feafff5b..bdb1c82798 100644
--- a/ui-tui/src/app.tsx
+++ b/ui-tui/src/app.tsx
@@ -455,11 +455,16 @@ export function App({ gw }: { gw: GatewayClient }) {
})
}, [])
- const setTrail = (next: string[]) => { turnToolsRef.current = next; return next }
+ const setTrail = (next: string[]) => {
+ turnToolsRef.current = next
+
+ return next
+ }
const pruneTransient = useCallback(() => {
setTurnTrail(prev => {
const next = prev.filter(l => !isTransientTrailLine(l))
+
return next.length === prev.length ? prev : setTrail(next)
})
}, [])
@@ -480,7 +485,9 @@ export function App({ gw }: { gw: GatewayClient }) {
const answerClarify = useCallback(
(answer: string) => {
- if (!clarify) return
+ if (!clarify) {
+ return
+ }
const label = TOOL_VERBS.clarify ?? 'clarify'
@@ -491,7 +498,12 @@ export function App({ gw }: { gw: GatewayClient }) {
if (answer) {
persistedToolLabelsRef.current.add(label)
- appendMessage({ role: 'system', text: '', kind: 'trail', tools: [buildToolTrailLine('clarify', clarify.question)] })
+ appendMessage({
+ role: 'system',
+ text: '',
+ kind: 'trail',
+ tools: [buildToolTrailLine('clarify', clarify.question)]
+ })
appendMessage({ role: 'user', text: answer })
} else {
sys('prompt cancelled')
@@ -1457,8 +1469,11 @@ export function App({ gw }: { gw: GatewayClient }) {
const wasInterrupted = interruptedRef.current
const savedReasoning = reasoningRef.current.trim()
const persisted = persistedToolLabelsRef.current
- const savedTools = turnToolsRef.current
- .filter(l => isToolTrailResultLine(l) && ![...persisted].some(p => sameToolTrailGroup(p, l)))
+
+ const savedTools = turnToolsRef.current.filter(
+ l => isToolTrailResultLine(l) && ![...persisted].some(p => sameToolTrailGroup(p, l))
+ )
+
const finalText = (p?.rendered ?? p?.text ?? buf.current).trimStart()
idle()
diff --git a/ui-tui/src/components/markdown.tsx b/ui-tui/src/components/markdown.tsx
index 8d5cf888fe..6a59227734 100644
--- a/ui-tui/src/components/markdown.tsx
+++ b/ui-tui/src/components/markdown.tsx
@@ -10,11 +10,11 @@ const FOOTNOTE_RE = /^\[\^([^\]]+)\]:\s*(.*)$/
const DEF_RE = /^\s*:\s+(.+)$/
const TABLE_DIVIDER_CELL_RE = /^:?-{3,}:?$/
const MD_URL_RE = '((?:[^\\s()]|\\([^\\s()]*\\))+?)'
-const INLINE_RE =
- new RegExp(
- `(!\\[(.*?)\\]\\(${MD_URL_RE}\\)|\\[(.+?)\\]\\(${MD_URL_RE}\\)|<((?:https?:\\/\\/|mailto:)[^>\\s]+|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})>|~~(.+?)~~|\`([^\\\`]+)\`|\\*\\*(.+?)\\*\\*|__(.+?)__|\\*(.+?)\\*|_(.+?)_|==(.+?)==|\\[\\^([^\\]]+)\\]|\\^([^^\\s][^^]*?)\\^|~([^~\\s][^~]*?)~|(https?:\\/\\/[^\\s<]+))`,
- 'g'
- )
+
+const INLINE_RE = new RegExp(
+ `(!\\[(.*?)\\]\\(${MD_URL_RE}\\)|\\[(.+?)\\]\\(${MD_URL_RE}\\)|<((?:https?:\\/\\/|mailto:)[^>\\s]+|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})>|~~(.+?)~~|\`([^\\\`]+)\`|\\*\\*(.+?)\\*\\*|__(.+?)__|\\*(.+?)\\*|_(.+?)_|==(.+?)==|\\[\\^([^\\]]+)\\]|\\^([^^\\s][^^]*?)\\^|~([^~\\s][^~]*?)~|(https?:\\/\\/[^\\s<]+))`,
+ 'g'
+)
type Fence = {
char: '`' | '~'
@@ -171,11 +171,7 @@ function MdInline({ t, text }: { t: Theme; text: string }) {
parts.push(renderAutolink(parts.length, t, url))
if (tail) {
- parts.push(
-
- {tail}
-
- )
+ parts.push({tail})
}
}
@@ -193,16 +189,8 @@ export function Md({ compact, t, text }: { compact?: boolean; t: Theme; text: st
const lines = text.split('\n')
const nodes: ReactNode[] = []
let i = 0
- let prevKind:
- | 'blank'
- | 'code'
- | 'heading'
- | 'list'
- | 'paragraph'
- | 'quote'
- | 'rule'
- | 'table'
- | null = null
+
+ let prevKind: 'blank' | 'code' | 'heading' | 'list' | 'paragraph' | 'quote' | 'rule' | 'table' | null = null
const gap = () => {
if (nodes.length && prevKind !== 'blank') {
@@ -400,7 +388,7 @@ export function Md({ compact, t, text }: { compact?: boolean; t: Theme; text: st
nodes.push(
- ·
+ ·
)
diff --git a/ui-tui/src/components/maskedPrompt.tsx b/ui-tui/src/components/maskedPrompt.tsx
index c9e1100995..f159cc681f 100644
--- a/ui-tui/src/components/maskedPrompt.tsx
+++ b/ui-tui/src/components/maskedPrompt.tsx
@@ -2,6 +2,7 @@ import { Box, Text } from '@hermes/ink'
import { useState } from 'react'
import type { Theme } from '../theme.js'
+
import { TextInput } from './textInput.js'
export function MaskedPrompt({
diff --git a/ui-tui/src/components/prompts.tsx b/ui-tui/src/components/prompts.tsx
index 69a2bb8a85..4e546f3d8b 100644
--- a/ui-tui/src/components/prompts.tsx
+++ b/ui-tui/src/components/prompts.tsx
@@ -3,6 +3,7 @@ import { useState } from 'react'
import type { Theme } from '../theme.js'
import type { ApprovalReq, ClarifyReq } from '../types.js'
+
import { TextInput } from './textInput.js'
export function ApprovalPrompt({ onChoice, req, t }: { onChoice: (s: string) => void; req: ApprovalReq; t: Theme }) {
@@ -88,20 +89,31 @@ export function ClarifyPrompt({
useInput((ch, key) => {
if (key.escape) {
typing && choices.length ? setTyping(false) : onCancel()
+
return
}
- if (typing) return
+ if (typing) {
+ return
+ }
- if (key.upArrow && sel > 0) setSel(s => s - 1)
- if (key.downArrow && sel < choices.length) setSel(s => s + 1)
+ if (key.upArrow && sel > 0) {
+ setSel(s => s - 1)
+ }
+
+ if (key.downArrow && sel < choices.length) {
+ setSel(s => s + 1)
+ }
if (key.return) {
sel === choices.length ? setTyping(true) : choices[sel] && onAnswer(choices[sel]!)
}
const n = parseInt(ch)
- if (n >= 1 && n <= choices.length) onAnswer(choices[n - 1]!)
+
+ if (n >= 1 && n <= choices.length) {
+ onAnswer(choices[n - 1]!)
+ }
})
if (typing || !choices.length) {
@@ -126,7 +138,9 @@ export function ClarifyPrompt({
{[...choices, 'Other (type your answer)'].map((c, i) => (
{sel === i ? '▸ ' : ' '}
- {i + 1}. {c}
+
+ {i + 1}. {c}
+
))}
diff --git a/ui-tui/src/lib/text.ts b/ui-tui/src/lib/text.ts
index 3c5ccbcc7d..82a87c91f2 100644
--- a/ui-tui/src/lib/text.ts
+++ b/ui-tui/src/lib/text.ts
@@ -54,8 +54,7 @@ export const buildToolTrailLine = (name: string, context: string, error?: boolea
export const isToolTrailResultLine = (line: string) => line.endsWith(' ✓') || line.endsWith(' ✗')
/** Ephemeral status lines that should vanish once the next phase starts. */
-export const isTransientTrailLine = (line: string) =>
- line.startsWith('drafting ') || line === 'analyzing tool output…'
+export const isTransientTrailLine = (line: string) => line.startsWith('drafting ') || line === 'analyzing tool output…'
/** Whether a persisted/activity tool line belongs to the same tool label as a newer line. */
export const sameToolTrailGroup = (label: string, entry: string) =>