mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
fix(tui): raise picker selection contrast with inverse + bold
Selected rows in the model/session/skills pickers and approval/clarify prompts only changed from dim gray to cornsilk, which reads as low contrast on lighter themes and LCDs (reported during TUI v2 blitz). Switch the selected row to `inverse bold` with the brand accent color across modelPicker, sessionPicker, skillsHub, and prompts so the highlight is terminal-portable and unambiguous. Unselected rows stay dim. Also extends the sessionPicker middle meta column (which was always dim) to inherit the row's selection state.
This commit is contained in:
parent
c3b8c8e42c
commit
fc6a27098e
24 changed files with 248 additions and 93 deletions
|
|
@ -3,12 +3,13 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
import { useStdin } from '@hermes/ink'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useStdin } from '@hermes/ink'
|
||||
|
||||
import type { PasteEvent } from '../components/textInput.js'
|
||||
import { LARGE_PASTE } from '../config/limits.js'
|
||||
import type { ImageAttachResponse, InputDetectDropResponse } from '../gatewayTypes.js'
|
||||
import { useCompletion } from '../hooks/useCompletion.js'
|
||||
import { useInputHistory } from '../hooks/useInputHistory.js'
|
||||
import { useQueue } from '../hooks/useQueue.js'
|
||||
|
|
@ -16,7 +17,6 @@ import { isUsableClipboardText, readClipboardText } from '../lib/clipboard.js'
|
|||
import { readOsc52Clipboard } from '../lib/osc52.js'
|
||||
import { isRemoteShellSession } from '../lib/terminalSetup.js'
|
||||
import { pasteTokenLabel, stripTrailingPasteNewlines } from '../lib/text.js'
|
||||
import type { ImageAttachResponse, InputDetectDropResponse } from '../gatewayTypes.js'
|
||||
|
||||
import type { MaybePromise, PasteSnippet, UseComposerStateOptions, UseComposerStateResult } from './interfaces.js'
|
||||
import { $isBlocked } from './overlayStore.js'
|
||||
|
|
@ -79,8 +79,8 @@ export function looksLikeDroppedPath(text: string): boolean {
|
|||
trimmed.startsWith("'/") ||
|
||||
trimmed.startsWith('"~') ||
|
||||
trimmed.startsWith("'~") ||
|
||||
(/^[A-Za-z]:[/\\]/.test(trimmed)) ||
|
||||
(/^["'][A-Za-z]:[/\\]/.test(trimmed))
|
||||
/^[A-Za-z]:[/\\]/.test(trimmed) ||
|
||||
/^["'][A-Za-z]:[/\\]/.test(trimmed)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
|
@ -90,13 +90,19 @@ export function looksLikeDroppedPath(text: string): boolean {
|
|||
// unnecessary RPC round-trips.
|
||||
if (trimmed.startsWith('/')) {
|
||||
const rest = trimmed.slice(1)
|
||||
|
||||
return rest.includes('/') || rest.includes('.')
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function useComposerState({ gw, onClipboardPaste, onImageAttached, submitRef }: UseComposerStateOptions): UseComposerStateResult {
|
||||
export function useComposerState({
|
||||
gw,
|
||||
onClipboardPaste,
|
||||
onImageAttached,
|
||||
submitRef
|
||||
}: UseComposerStateOptions): UseComposerStateResult {
|
||||
const [input, setInput] = useState('')
|
||||
const [inputBuf, setInputBuf] = useState<string[]>([])
|
||||
const [pasteSnips, setPasteSnips] = useState<PasteSnippet[]>([])
|
||||
|
|
@ -119,7 +125,12 @@ export function useComposerState({ gw, onClipboardPaste, onImageAttached, submit
|
|||
}, [historyDraftRef, setQueueEdit, setHistoryIdx])
|
||||
|
||||
const handleResolvedPaste = useCallback(
|
||||
async ({ bracketed, cursor, text, value }: Omit<PasteEvent, 'hotkey'>): Promise<null | { cursor: number; value: string }> => {
|
||||
async ({
|
||||
bracketed,
|
||||
cursor,
|
||||
text,
|
||||
value
|
||||
}: Omit<PasteEvent, 'hotkey'>): Promise<null | { cursor: number; value: string }> => {
|
||||
const cleanedText = stripTrailingPasteNewlines(text)
|
||||
|
||||
if (!cleanedText || !/[^\n]/.test(cleanedText)) {
|
||||
|
|
@ -131,6 +142,7 @@ export function useComposerState({ gw, onClipboardPaste, onImageAttached, submit
|
|||
}
|
||||
|
||||
const sid = getUiState().sid
|
||||
|
||||
if (sid && looksLikeDroppedPath(cleanedText)) {
|
||||
try {
|
||||
const attached = await gw.request<ImageAttachResponse>('image.attach', {
|
||||
|
|
@ -141,6 +153,7 @@ export function useComposerState({ gw, onClipboardPaste, onImageAttached, submit
|
|||
if (attached?.name) {
|
||||
onImageAttached?.(attached)
|
||||
const remainder = attached.remainder?.trim() ?? ''
|
||||
|
||||
if (!remainder) {
|
||||
return { cursor, value }
|
||||
}
|
||||
|
|
@ -198,20 +211,29 @@ export function useComposerState({ gw, onClipboardPaste, onImageAttached, submit
|
|||
)
|
||||
|
||||
const handleTextPaste = useCallback(
|
||||
({ bracketed, cursor, hotkey, text, value }: PasteEvent): MaybePromise<null | { cursor: number; value: string }> => {
|
||||
({
|
||||
bracketed,
|
||||
cursor,
|
||||
hotkey,
|
||||
text,
|
||||
value
|
||||
}: PasteEvent): MaybePromise<null | { cursor: number; value: string }> => {
|
||||
if (hotkey) {
|
||||
const preferOsc52 = isRemoteShellSession(process.env)
|
||||
|
||||
const readPreferredText = preferOsc52
|
||||
? readOsc52Clipboard(querier).then(async osc52Text => {
|
||||
if (isUsableClipboardText(osc52Text)) {
|
||||
return osc52Text
|
||||
}
|
||||
|
||||
return readClipboardText()
|
||||
})
|
||||
: readClipboardText().then(async clipText => {
|
||||
if (isUsableClipboardText(clipText)) {
|
||||
return clipText
|
||||
}
|
||||
|
||||
return readOsc52Clipboard(querier)
|
||||
})
|
||||
|
||||
|
|
@ -221,6 +243,7 @@ export function useComposerState({ gw, onClipboardPaste, onImageAttached, submit
|
|||
}
|
||||
|
||||
void onClipboardPaste(false)
|
||||
|
||||
return null
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue