mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-02 02:01:47 +00:00
refactor(tui): store-driven turn state + slash registry + module split
Hoist turn state from a 286-line hook into $turnState atom + turnController
singleton. createGatewayEventHandler becomes a typed dispatch over the
controller; its ctx shrinks from 30 fields to 5. Event-handler refs and 16
threaded actions are gone.
Fold three createSlash*Handler factories into a data-driven SlashCommand[]
registry under slash/commands/{core,session,ops}.ts. Aliases are data;
findSlashCommand does name+alias lookup. Shared guarded/guardedErr combinator
in slash/guarded.ts.
Split constants.ts + app/helpers.ts into config/ (timing/limits/env),
content/ (faces/placeholders/hotkeys/verbs/charms/fortunes), domain/ (roles/
details/messages/paths/slash/viewport/usage), protocol/ (interpolation/paste).
Type every RPC response in gatewayTypes.ts (26 new interfaces); drop all
`(r: any)` across slash + main app.
Shrink useMainApp from 1216 -> 646 lines by extracting useSessionLifecycle,
useSubmission, useConfigSync. Add <Fg> themed primitive and strip ~50
`as any` color casts.
Tests: 50 passing. Build + type-check clean.
This commit is contained in:
parent
9c71f3a6ea
commit
68ecdb6e26
56 changed files with 3666 additions and 4117 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { INTERPOLATION_RE, LONG_MSG } from '../constants.js'
|
||||
import { THINKING_COT_MAX } from '../config/limits.js'
|
||||
import type { ThinkingMode } from '../types.js'
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
|
|
@ -73,7 +73,7 @@ export const pasteTokenLabel = (text: string, lineCount: number) => {
|
|||
: `[[ ${preview} [${fmtK(lineCount)} lines] ]]`
|
||||
}
|
||||
|
||||
export const thinkingPreview = (reasoning: string, mode: ThinkingMode, max: number) => {
|
||||
export const thinkingPreview = (reasoning: string, mode: ThinkingMode, max: number = THINKING_COT_MAX) => {
|
||||
const raw = reasoning.trim()
|
||||
|
||||
if (!raw || mode === 'collapsed') {
|
||||
|
|
@ -155,8 +155,6 @@ export const lastCotTrailIndex = (trail: readonly string[]) => {
|
|||
return -1
|
||||
}
|
||||
|
||||
export const THINKING_COT_MAX = 160
|
||||
|
||||
export const estimateRows = (text: string, w: number, compact = false) => {
|
||||
let fence: { char: '`' | '~'; len: number } | null = null
|
||||
let rows = 0
|
||||
|
|
@ -213,25 +211,7 @@ const COMPACT_NUMBER = new Intl.NumberFormat('en-US', {
|
|||
|
||||
export const fmtK = (n: number) => COMPACT_NUMBER.format(n).replace(/[KMBT]$/, s => s.toLowerCase())
|
||||
|
||||
export const hasInterpolation = (s: string) => {
|
||||
INTERPOLATION_RE.lastIndex = 0
|
||||
|
||||
return INTERPOLATION_RE.test(s)
|
||||
}
|
||||
|
||||
export const pick = <T>(a: T[]) => a[Math.floor(Math.random() * a.length)]!
|
||||
|
||||
export const userDisplay = (text: string): string => {
|
||||
if (text.length <= LONG_MSG) {
|
||||
return text
|
||||
}
|
||||
|
||||
const first = text.split('\n')[0]?.trim() ?? ''
|
||||
const words = first.split(/\s+/).filter(Boolean)
|
||||
const prefix = (words.length > 1 ? words.slice(0, 4).join(' ') : first).slice(0, 80)
|
||||
|
||||
return `${prefix || '(message)'} [long message]`
|
||||
}
|
||||
|
||||
export const isPasteBackedText = (text: string): boolean =>
|
||||
/\[\[paste:\d+(?:[^\n]*?)\]\]|\[paste #\d+ (?:attached|excerpt)(?:[^\n]*?)\]/.test(text)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue