@@ -7,6 +7,13 @@ import { supportedEfforts, type ReasoningEffort } from "../../provider/reasoning
77import { PROVIDER_TIERS , type ProviderTier , type TierConfig } from "../../config/settings.js" ;
88import { formatTierChain , normalizeTierDefinition } from "../../config/inference-sources.js" ;
99import type { AgentProfile } from "../../agent/profiles.js" ;
10+ import { useTerminalSize } from "../hooks/use-terminal-size.js" ;
11+ import {
12+ STACK_FORM_COLUMNS ,
13+ fitTrailingText ,
14+ formContentWidth ,
15+ wrapHelpSegments ,
16+ } from "./form-reflow.js" ;
1017
1118// Effort display: undefined means "no override" (field omitted); "none" is
1219// OpenAI's explicit disable-reasoning value. Both read as "off".
@@ -254,6 +261,15 @@ export function AgentModal({
254261 unauthedProviders,
255262 onRequestLogin,
256263} : AgentModalProps ) : ReactNode {
264+ const { columns } = useTerminalSize ( ) ;
265+ const stackFields = columns < STACK_FORM_COLUMNS ;
266+ const contentWidth = formContentWidth ( columns , stackFields ) ;
267+ // Label column widths used in row layout; stacked layout uses full content width for values.
268+ const providerLabelWidth = 16 ;
269+ const profileLabelWidth = 14 ;
270+ const valueWidth = stackFields
271+ ? contentWidth
272+ : Math . max ( 8 , contentWidth - Math . max ( providerLabelWidth , profileLabelWidth ) - 1 ) ;
257273 const initialProvider = Math . max (
258274 0 ,
259275 providers . findIndex ( ( p ) => p . name === activeProvider ) ,
@@ -785,13 +801,40 @@ export function AgentModal({
785801 setFormError ( null ) ;
786802 } ) ;
787803
804+ const helpText = ( ( ) : string | null => {
805+ switch ( step ) {
806+ case "provider" :
807+ return "Up/Down navigate · Enter models · a add · e edit · x remove · t tiers · p profiles · Esc close" ;
808+ case "tiers" :
809+ return "Up/Down navigate · Enter add · e edit chain · m mode · c clear · Esc back" ;
810+ case "tier-chain" :
811+ return "Up/Down leg · a/Enter add · x remove · u/d reorder · m mode · Esc back" ;
812+ case "profiles" :
813+ return "Up/Down navigate · a add · e edit · x remove · Esc back" ;
814+ case "profile-form" :
815+ return "Up/Down fields · Left/Right for tier · Enter next/save · Esc cancel" ;
816+ case "profile-delete" :
817+ return "y remove · n cancel · Esc back" ;
818+ case "model" :
819+ return "Up/Down navigate · Enter effort · Esc back" ;
820+ case "effort" :
821+ return "Up/Down navigate · Enter use now · d set as default · Esc back" ;
822+ case "form" :
823+ return "Up/Down fields · Left/Right toggle keyless · Enter next/save · Esc cancel" ;
824+ case "delete" :
825+ return "y remove · n cancel · Esc back" ;
826+ }
827+ } ) ( ) ;
828+ const helpLines = helpText !== null ? wrapHelpSegments ( helpText . split ( " · " ) , contentWidth ) : [ ] ;
829+
788830 return (
789831 < Box
790832 flexDirection = "column"
791- paddingX = { 2 }
833+ paddingX = { stackFields ? 1 : 2 }
792834 paddingY = { 1 }
793835 marginX = { 1 }
794836 marginY = { 1 }
837+ width = { Math . max ( 16 , columns - 2 ) }
795838 >
796839 < Text bold color = { color ( "accent" ) } >
797840 Agent Configuration
@@ -871,16 +914,18 @@ export function AgentModal({
871914 const assignment = tiers [ tier ] ;
872915 const isCursor = i === tierIndex ;
873916 const assignmentLabel = formatTierChain ( assignment ) ;
917+ const rowDir = stackFields ? "column" : "row" ;
874918 return (
875- < Box key = { tier } flexDirection = "row" gap = { 2 } >
876- < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
877- { isCursor ? ">" : " " }
878- </ Text >
879- < Box width = { 10 } flexShrink = { 0 } >
919+ < Box key = { tier } flexDirection = { rowDir } gap = { stackFields ? 0 : 2 } >
920+ < Box flexDirection = "row" gap = { 1 } >
921+ < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
922+ { isCursor ? ">" : " " }
923+ </ Text >
880924 < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } > { tier } </ Text >
881925 </ Box >
882926 < Text color = { assignment !== undefined ? color ( "text" ) : color ( "muted" ) } >
883- { assignmentLabel }
927+ { stackFields ? " " : "" }
928+ { fitTrailingText ( assignmentLabel , stackFields ? contentWidth - 2 : Math . max ( 8 , contentWidth - 12 ) ) }
884929 </ Text >
885930 </ Box >
886931 ) ;
@@ -898,17 +943,27 @@ export function AgentModal({
898943 { models . map ( ( m , i ) => {
899944 const isActive = selectedProvider ?. name === activeProvider && m === activeModel ;
900945 const isCursor = i === modelIndex ;
946+ const desc = MODEL_DESCRIPTIONS [ m ] ;
947+ const namePart = `${ isActive ? "* " : " " } ${ m } ` ;
948+ const showDescInline = desc !== undefined && ! stackFields && namePart . length + desc . length + 4 < contentWidth ;
901949 return (
902- < Box key = { m } flexDirection = "row" gap = { 1 } >
903- < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
904- { isCursor ? ">" : " " }
905- </ Text >
906- < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } >
907- { isActive ? "* " : " " }
908- { m }
909- </ Text >
910- { MODEL_DESCRIPTIONS [ m ] !== undefined && (
911- < Text color = { color ( "muted" ) } > — { MODEL_DESCRIPTIONS [ m ] } </ Text >
950+ < Box key = { m } flexDirection = "column" >
951+ < Box flexDirection = "row" gap = { 1 } >
952+ < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
953+ { isCursor ? ">" : " " }
954+ </ Text >
955+ < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } >
956+ { fitTrailingText ( namePart , contentWidth - 2 ) }
957+ </ Text >
958+ { showDescInline && (
959+ < Text color = { color ( "muted" ) } > — { desc } </ Text >
960+ ) }
961+ </ Box >
962+ { desc !== undefined && ! showDescInline && (
963+ < Text color = { color ( "muted" ) } >
964+ { " " }
965+ { fitTrailingText ( desc , contentWidth - 2 ) }
966+ </ Text >
912967 ) }
913968 </ Box >
914969 ) ;
@@ -927,17 +982,27 @@ export function AgentModal({
927982 { efforts . map ( ( e , i ) => {
928983 const isActive = e === activeEffort ;
929984 const isCursor = i === effortIndex ;
985+ const desc = EFFORT_DESCRIPTIONS [ e ] ;
986+ const namePart = `${ isActive ? "* " : " " } ${ effortLabel ( e ) } ` ;
987+ const showDescInline = desc !== undefined && ! stackFields && namePart . length + desc . length + 4 < contentWidth ;
930988 return (
931- < Box key = { e } flexDirection = "row" gap = { 1 } >
932- < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
933- { isCursor ? ">" : " " }
934- </ Text >
935- < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } >
936- { isActive ? "* " : " " }
937- { effortLabel ( e ) }
938- </ Text >
939- { EFFORT_DESCRIPTIONS [ e ] !== undefined && (
940- < Text color = { color ( "muted" ) } > — { EFFORT_DESCRIPTIONS [ e ] } </ Text >
989+ < Box key = { e } flexDirection = "column" >
990+ < Box flexDirection = "row" gap = { 1 } >
991+ < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
992+ { isCursor ? ">" : " " }
993+ </ Text >
994+ < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } >
995+ { fitTrailingText ( namePart , contentWidth - 2 ) }
996+ </ Text >
997+ { showDescInline && (
998+ < Text color = { color ( "muted" ) } > — { desc } </ Text >
999+ ) }
1000+ </ Box >
1001+ { desc !== undefined && ! showDescInline && (
1002+ < Text color = { color ( "muted" ) } >
1003+ { " " }
1004+ { fitTrailingText ( desc , contentWidth - 2 ) }
1005+ </ Text >
9411006 ) }
9421007 </ Box >
9431008 ) ;
@@ -961,39 +1026,66 @@ export function AgentModal({
9611026 const isCursor = i === formIndex ;
9621027 const value = formValues [ field ] ;
9631028 const isKeyless = formValues . keyless === "yes" ;
1029+ const showCaret =
1030+ isCursor &&
1031+ field !== "keyless" &&
1032+ field !== "bifrostVirtualKey" &&
1033+ ! ( field === "apiKey" && isKeyless ) ;
1034+ const rawDisplay =
1035+ field === "keyless" || field === "bifrostVirtualKey"
1036+ ? null
1037+ : field === "apiKey" && isKeyless
1038+ ? "(disabled — keyless provider)"
1039+ : value . length > 0
1040+ ? maskInput ( field , value )
1041+ : field === "apiKey" && editingProvider !== undefined
1042+ ? "leave blank to keep existing"
1043+ : FIELD_HINTS [ field ] ;
1044+ // Reserve one cell for the caret so long values do not push it off-screen.
1045+ const fitted =
1046+ rawDisplay === null
1047+ ? null
1048+ : fitTrailingText ( rawDisplay , showCaret ? Math . max ( 1 , valueWidth - 1 ) : valueWidth ) ;
9641049 return (
965- < Box key = { field } flexDirection = "row" gap = { 1 } >
966- < Box width = { 16 } flexShrink = { 0 } >
1050+ < Box
1051+ key = { field }
1052+ flexDirection = { stackFields ? "column" : "row" }
1053+ gap = { stackFields ? 0 : 1 }
1054+ marginBottom = { stackFields ? 1 : 0 }
1055+ >
1056+ < Box width = { stackFields ? undefined : providerLabelWidth } flexShrink = { 0 } >
9671057 < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
9681058 { FIELD_LABELS [ field ] }
9691059 </ Text >
9701060 </ Box >
971- { field === "keyless" || field === "bifrostVirtualKey" ? (
972- < Text color = { value === "yes" ? color ( "accent" ) : color ( "muted" ) } >
973- { isCursor ? "< " : " " }
974- { value === "yes" ? "yes" : "no" }
975- { isCursor ? " >" : "" }
976- </ Text >
977- ) : field === "apiKey" && isKeyless ? (
978- < Text color = { color ( "muted" ) } > (disabled — keyless provider)</ Text >
979- ) : (
980- < Text color = { value . length > 0 ? color ( "text" ) : color ( "muted" ) } >
981- { value . length > 0
982- ? maskInput ( field , value )
983- : field === "apiKey" && editingProvider !== undefined
984- ? "leave blank to keep existing"
985- : FIELD_HINTS [ field ] }
986- </ Text >
987- ) }
988- { isCursor && field !== "keyless" && field !== "bifrostVirtualKey" && ! ( field === "apiKey" && isKeyless ) && (
989- < Text color = { color ( "accent" ) } > |</ Text >
990- ) }
1061+ < Box flexDirection = "row" gap = { 0 } >
1062+ { field === "keyless" || field === "bifrostVirtualKey" ? (
1063+ < Text color = { value === "yes" ? color ( "accent" ) : color ( "muted" ) } >
1064+ { isCursor ? "< " : " " }
1065+ { value === "yes" ? "yes" : "no" }
1066+ { isCursor ? " >" : "" }
1067+ </ Text >
1068+ ) : (
1069+ < Text
1070+ color = {
1071+ field === "apiKey" && isKeyless
1072+ ? color ( "muted" )
1073+ : value . length > 0
1074+ ? color ( "text" )
1075+ : color ( "muted" )
1076+ }
1077+ >
1078+ { fitted }
1079+ </ Text >
1080+ ) }
1081+ { showCaret && < Text color = { color ( "accent" ) } > |</ Text > }
1082+ </ Box >
9911083 </ Box >
9921084 ) ;
9931085 } ) }
9941086 { formError !== null && (
9951087 < Box marginTop = { 1 } >
996- < Text color = { color ( "danger" ) } > { formError } </ Text >
1088+ < Text color = { color ( "danger" ) } > { fitTrailingText ( formError , contentWidth ) } </ Text >
9971089 </ Box >
9981090 ) }
9991091 </ Box >
@@ -1006,18 +1098,23 @@ export function AgentModal({
10061098 ) }
10071099 { profiles . map ( ( p , i ) => {
10081100 const isCursor = i === profileIndex ;
1101+ const meta = `${ p . tier !== undefined ? `[${ p . tier } ]` : "" } ${ p . description !== undefined ? ` ${ p . description } ` : "" } ` . trim ( ) ;
10091102 return (
1010- < Box key = { p . id } flexDirection = "row" gap = { 2 } >
1011- < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
1012- { isCursor ? ">" : " " }
1013- </ Text >
1014- < Box width = { 20 } flexShrink = { 0 } >
1015- < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } > { p . id } </ Text >
1103+ < Box key = { p . id } flexDirection = { stackFields ? "column" : "row" } gap = { stackFields ? 0 : 2 } >
1104+ < Box flexDirection = "row" gap = { 1 } >
1105+ < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
1106+ { isCursor ? ">" : " " }
1107+ </ Text >
1108+ < Text color = { isCursor ? color ( "accent" ) : color ( "text" ) } >
1109+ { fitTrailingText ( p . id , stackFields ? contentWidth - 2 : 20 ) }
1110+ </ Text >
10161111 </ Box >
1017- < Text color = { color ( "muted" ) } >
1018- { p . tier !== undefined ? `[${ p . tier } ]` : "" }
1019- { p . description !== undefined ? ` ${ p . description } ` : "" }
1020- </ Text >
1112+ { meta . length > 0 && (
1113+ < Text color = { color ( "muted" ) } >
1114+ { stackFields ? " " : "" }
1115+ { fitTrailingText ( meta , stackFields ? contentWidth - 2 : Math . max ( 8 , contentWidth - 24 ) ) }
1116+ </ Text >
1117+ ) }
10211118 </ Box >
10221119 ) ;
10231120 } ) }
@@ -1038,53 +1135,62 @@ export function AgentModal({
10381135 </ Text >
10391136 { PROFILE_FORM_FIELDS . map ( ( field , i ) => {
10401137 const isCursor = i === profileFormIndex ;
1138+ const showCaret = isCursor && field !== "tier" ;
1139+ const raw =
1140+ field === "tier"
1141+ ? null
1142+ : profileFormValues [ field ] . length > 0
1143+ ? profileFormValues [ field ]
1144+ : PROFILE_FIELD_HINTS [ field ] ;
1145+ const fitted =
1146+ raw === null
1147+ ? null
1148+ : fitTrailingText ( raw , showCaret ? Math . max ( 1 , valueWidth - 1 ) : valueWidth ) ;
10411149 return (
1042- < Box key = { field } flexDirection = "row" gap = { 1 } >
1043- < Box width = { 14 } flexShrink = { 0 } >
1150+ < Box
1151+ key = { field }
1152+ flexDirection = { stackFields ? "column" : "row" }
1153+ gap = { stackFields ? 0 : 1 }
1154+ marginBottom = { stackFields ? 1 : 0 }
1155+ >
1156+ < Box width = { stackFields ? undefined : profileLabelWidth } flexShrink = { 0 } >
10441157 < Text color = { isCursor ? color ( "accent" ) : color ( "muted" ) } bold = { isCursor } >
10451158 { PROFILE_FIELD_LABELS [ field ] }
10461159 </ Text >
10471160 </ Box >
1048- { field === "tier" ? (
1049- < Text color = { profileFormValues . tier . length > 0 ? color ( "text" ) : color ( "muted" ) } >
1050- { isCursor ? "< " : " " }
1051- { profileFormValues . tier . length > 0 ? profileFormValues . tier : "none" }
1052- { isCursor ? " >" : "" }
1053- </ Text >
1054- ) : (
1055- < >
1056- < Text color = { profileFormValues [ field ] . length > 0 ? color ( "text" ) : color ( "muted" ) } >
1057- { profileFormValues [ field ] . length > 0 ? profileFormValues [ field ] : PROFILE_FIELD_HINTS [ field ] }
1161+ < Box flexDirection = "row" gap = { 0 } >
1162+ { field === "tier" ? (
1163+ < Text color = { profileFormValues . tier . length > 0 ? color ( "text" ) : color ( "muted" ) } >
1164+ { isCursor ? "< " : " " }
1165+ { profileFormValues . tier . length > 0 ? profileFormValues . tier : "none" }
1166+ { isCursor ? " >" : "" }
10581167 </ Text >
1059- { isCursor && < Text color = { color ( "accent" ) } > |</ Text > }
1060- </ >
1061- ) }
1168+ ) : (
1169+ < Text
1170+ color = { profileFormValues [ field ] . length > 0 ? color ( "text" ) : color ( "muted" ) }
1171+ >
1172+ { fitted }
1173+ </ Text >
1174+ ) }
1175+ { showCaret && < Text color = { color ( "accent" ) } > |</ Text > }
1176+ </ Box >
10621177 </ Box >
10631178 ) ;
10641179 } ) }
10651180 { profileFormError !== null && (
10661181 < Box marginTop = { 1 } >
1067- < Text color = { color ( "danger" ) } > { profileFormError } </ Text >
1182+ < Text color = { color ( "danger" ) } > { fitTrailingText ( profileFormError , contentWidth ) } </ Text >
10681183 </ Box >
10691184 ) }
10701185 </ Box >
10711186 ) }
10721187
1073- < Box marginTop = { 1 } >
1074- < Text dimColor >
1075- { step === "provider" && "Up/Down navigate · Enter models · a add · e edit · x remove · t tiers · p profiles · Esc close" }
1076- { step === "tiers" &&
1077- "Up/Down navigate · Enter add · e edit chain · m mode · c clear · Esc back" }
1078- { step === "tier-chain" &&
1079- "Up/Down leg · a/Enter add · x remove · u/d reorder · m mode · Esc back" }
1080- { step === "profiles" && "Up/Down navigate · a add · e edit · x remove · Esc back" }
1081- { step === "profile-form" && "Up/Down fields · Left/Right for tier · Enter next/save · Esc cancel" }
1082- { step === "profile-delete" && "y remove · n cancel · Esc back" }
1083- { step === "model" && "Up/Down navigate · Enter effort · Esc back" }
1084- { step === "effort" && "Up/Down navigate · Enter use now · d set as default · Esc back" }
1085- { step === "form" && "Up/Down fields · Left/Right toggle keyless · Enter next/save · Esc cancel" }
1086- { step === "delete" && "y remove · n cancel · Esc back" }
1087- </ Text >
1188+ < Box marginTop = { 1 } flexDirection = "column" >
1189+ { helpLines . map ( ( line , i ) => (
1190+ < Text key = { i } dimColor >
1191+ { line }
1192+ </ Text >
1193+ ) ) }
10881194 </ Box >
10891195 </ Box >
10901196 ) ;
0 commit comments