@@ -756,7 +756,7 @@ private static string ExtractResponseText(AgentResponse response)
756756 : messageText ;
757757 }
758758
759- private string BuildConsolePrompt ( ) => $ "{ BuildConsolePromptLabel ( ) } { _powerShellCurrentLocation } > ";
759+ private string BuildConsolePrompt ( ) => $ "{ BuildConsolePromptLabel ( ) } { FormatPromptLocation ( _powerShellCurrentLocation ) } > ";
760760
761761 private string BuildConsolePromptLabel ( ) => $ "{ BuildConsolePromptLeadSegment ( ) } [{ _verbosity } ]";
762762
@@ -771,6 +771,44 @@ private string BuildConsolePromptLeadSegment()
771771 return "PS" ;
772772 }
773773
774+ /// <summary>
775+ /// Condenses a filesystem location for display in the interactive prompt.
776+ /// Keeps the prompt short even when the user has cd'd deep inside the workspace
777+ /// or when the absolute path is long, so there is always room to type.
778+ /// </summary>
779+ private string FormatPromptLocation ( string location )
780+ {
781+ if ( string . IsNullOrWhiteSpace ( location ) )
782+ return string . Empty ;
783+
784+ var trimmed = location . TrimEnd ( '\\ ' , '/' ) ;
785+
786+ // If the current location is inside the workspace, show it as ~/<relative>.
787+ var workspace = _settings . WorkspacePath ? . TrimEnd ( '\\ ' , '/' ) ;
788+ if ( ! string . IsNullOrWhiteSpace ( workspace )
789+ && trimmed . StartsWith ( workspace , StringComparison . OrdinalIgnoreCase ) )
790+ {
791+ if ( trimmed . Length == workspace . Length )
792+ return "~" ;
793+
794+ var relative = trimmed [ workspace . Length ..] . TrimStart ( '\\ ' , '/' ) ;
795+ return $ "~/{ relative . Replace ( '\\ ' , '/' ) } ";
796+ }
797+
798+ // Otherwise, middle-ellipsis very long paths so the prompt stays usable.
799+ const int maxLength = 40 ;
800+ if ( trimmed . Length <= maxLength )
801+ return trimmed ;
802+
803+ var tailLength = maxLength - 4 ; // reserve "...<sep>" prefix
804+ var tail = trimmed [ ^ tailLength ..] ;
805+ var separatorIndex = tail . IndexOfAny ( [ '\\ ' , '/' ] ) ;
806+ if ( separatorIndex > 0 )
807+ tail = tail [ separatorIndex ..] ;
808+
809+ return $ "...{ tail } ";
810+ }
811+
774812 private void ClosePowerShellSession ( )
775813 {
776814 if ( string . IsNullOrWhiteSpace ( _powerShellSessionId ) )
@@ -1093,44 +1131,119 @@ private static bool WriteConsoleBlock(string? value, TextWriter writer)
10931131
10941132 private void WriteBanner ( )
10951133 {
1096- Console . WriteLine ( "MCP Agent host (Director)" ) ;
1097- Console . WriteLine ( "-----------------------------------" ) ;
1098- Console . WriteLine ( $ "MCP server : { _settings . BaseUrl } ") ;
1099- Console . WriteLine ( $ "Workspace : { _settings . WorkspacePath } ") ;
1100- Console . WriteLine ( $ "Model : { _settings . ModelId } ") ;
1134+ var rows = new List < ( string Label , string Value ) >
1135+ {
1136+ ( "MCP server" , _settings . BaseUrl . ToString ( ) ) ,
1137+ ( "Workspace" , _settings . WorkspacePath ) ,
1138+ ( "Model" , _settings . ModelId ) ,
1139+ } ;
1140+
11011141 if ( _settings . ModelEndpoint is not null )
1102- Console . WriteLine ( $ "Model URL : { _settings . ModelEndpoint } ") ;
1103- Console . WriteLine ( $ "SourceType : { _settings . SourceType } ") ;
1104- Console . WriteLine ( $ "Tools : { string . Join ( ", " , _hostedAgent . Registration . Tools . Select ( static tool => tool . Name ) ) } ") ;
1142+ rows . Add ( ( "Model URL" , _settings . ModelEndpoint . ToString ( ) ) ) ;
1143+
1144+ rows . Add ( ( "SourceType" , _settings . SourceType ) ) ;
1145+ rows . Add ( ( "Auth" , DescribeAuthMode ( ) ) ) ;
1146+
1147+ var labelWidth = rows . Max ( static r => r . Label . Length ) ;
1148+
1149+ const string title = "MCP Agent host (Director)" ;
1150+ Console . WriteLine ( title ) ;
1151+ Console . WriteLine ( new string ( '-' , title . Length ) ) ;
1152+
1153+ foreach ( var ( label , value ) in rows )
1154+ Console . WriteLine ( $ "{ label . PadRight ( labelWidth ) } : { value } ") ;
1155+
1156+ var toolNames = _hostedAgent . Registration . Tools
1157+ . Select ( static tool => tool . Name )
1158+ . ToList ( ) ;
1159+ var toolHeader = $ "Tools ({ toolNames . Count } )". PadRight ( labelWidth ) ;
1160+ WriteWrappedList ( toolHeader , labelWidth , toolNames ) ;
1161+
11051162 Console . WriteLine ( ) ;
11061163 }
11071164
1165+ private string DescribeAuthMode ( )
1166+ {
1167+ if ( ! string . IsNullOrWhiteSpace ( _settings . BearerToken ) )
1168+ return "bearer token" ;
1169+ if ( ! string . IsNullOrWhiteSpace ( _settings . ApiKey ) )
1170+ return "api-key (workspace marker)" ;
1171+ return "(none \u2014 requests will fail)" ;
1172+ }
1173+
1174+ private static void WriteWrappedList ( string header , int labelWidth , IReadOnlyList < string > items )
1175+ {
1176+ if ( items . Count == 0 )
1177+ {
1178+ Console . WriteLine ( $ "{ header } : (none)") ;
1179+ return ;
1180+ }
1181+
1182+ var targetWidth = 80 ;
1183+ try
1184+ {
1185+ if ( Console . WindowWidth > 20 )
1186+ targetWidth = Console . WindowWidth - 1 ;
1187+ }
1188+ catch ( IOException )
1189+ {
1190+ // Console.WindowWidth can throw on some hosted terminals; fall back to 80.
1191+ }
1192+
1193+ var indent = new string ( ' ' , labelWidth + 3 ) ;
1194+ var maxLineLength = Math . Max ( 20 , targetWidth - ( labelWidth + 3 ) ) ;
1195+
1196+ var buffer = new StringBuilder ( ) ;
1197+ var first = true ;
1198+ foreach ( var item in items )
1199+ {
1200+ var separator = buffer . Length == 0 ? string . Empty : ", " ;
1201+ if ( buffer . Length + separator . Length + item . Length > maxLineLength && buffer . Length > 0 )
1202+ {
1203+ Console . WriteLine ( $ "{ ( first ? header : new string ( ' ' , labelWidth ) ) } : { buffer } ") ;
1204+ first = false ;
1205+ buffer . Clear ( ) ;
1206+ }
1207+ else if ( separator . Length > 0 )
1208+ {
1209+ buffer . Append ( separator ) ;
1210+ }
1211+
1212+ buffer . Append ( item ) ;
1213+ }
1214+
1215+ if ( buffer . Length > 0 )
1216+ Console . WriteLine ( $ "{ ( first ? header : new string ( ' ' , labelWidth ) ) } : { buffer } ") ;
1217+ }
1218+
11081219 private void WriteHelp ( )
11091220 {
1110- Console . WriteLine ( "Commands:" ) ;
1111- Console . WriteLine ( " /help Show this help text." ) ;
1112- Console . WriteLine ( " /tools List the MCP-backed tools attached to the hosted agent." ) ;
1113- Console . WriteLine ( " /session Show the current MCP session-log identifier." ) ;
1114- Console . WriteLine ( " /v N Set verbosity level (1=concise, 2=balanced, 3=detailed)." ) ;
1115- Console . WriteLine ( " /new Start a fresh conversation and session log." ) ;
1116- Console . WriteLine ( " /exit Exit the Director agent host." ) ;
1221+ Console . WriteLine ( "Session commands:" ) ;
1222+ Console . WriteLine ( " /help Show this help text." ) ;
1223+ Console . WriteLine ( " /tools List the MCP-backed tools and REPL workflow tools attached to the agent." ) ;
1224+ Console . WriteLine ( " /session Show the current session id, agent name, and source type." ) ;
1225+ Console . WriteLine ( $ " /v <1|2|3> Set verbosity: 1=concise, 2=balanced, 3=detailed (currently: { _verbosity } ).") ;
1226+ Console . WriteLine ( " /new (alias: /reset) Start a fresh conversation and session log." ) ;
1227+ Console . WriteLine ( " /exit (alias: /quit) Exit the Director agent host." ) ;
1228+ Console . WriteLine ( ) ;
1229+ Console . WriteLine ( "Workspace commands:" ) ;
1230+ Console . WriteLine ( " /todo List all TODO items." ) ;
1231+ Console . WriteLine ( " /todo <keyword> Search TODOs by keyword." ) ;
1232+ Console . WriteLine ( " /todo select <id> Select a TODO as the active context." ) ;
1233+ Console . WriteLine ( " /todo get <id> Show TODO details." ) ;
1234+ Console . WriteLine ( " /requirements (/reqs) List functional requirements summary." ) ;
1235+ Console . WriteLine ( " /client <c>.<m> [json] Invoke McpServerClient sub-client method (e.g. /client context.SearchAsync)." ) ;
11171236 Console . WriteLine ( ) ;
1118- Console . WriteLine ( "REPL workflow commands:" ) ;
1119- Console . WriteLine ( " /todo List all TODO items." ) ;
1120- Console . WriteLine ( " /todo <keyword> Search TODOs by keyword." ) ;
1121- Console . WriteLine ( " /todo select <id> Select a TODO as the active context." ) ;
1122- Console . WriteLine ( " /todo get <id> Show TODO details." ) ;
1123- Console . WriteLine ( " /requirements List functional requirements summary." ) ;
1124- Console . WriteLine ( " /reqs Alias for /requirements." ) ;
1125- Console . WriteLine ( " /client <c>.<m> Invoke McpServerClient sub-client method (e.g. /client context.SearchAsync)." ) ;
1237+ Console . WriteLine ( "Input:" ) ;
1238+ Console . WriteLine ( " <text> Sent to the hosted agent as a chat prompt." ) ;
1239+ Console . WriteLine ( " ! <command> Runs the rest of the line in the local PowerShell session." ) ;
1240+ Console . WriteLine ( " \u2191 / \u2193 Recall previous inputs from history." ) ;
1241+ Console . WriteLine ( " Ctrl+C Cancel the active PowerShell command; press again to exit." ) ;
11261242 Console . WriteLine ( ) ;
1127- Console . WriteLine ( "Prompt behavior:" ) ;
1128- Console . WriteLine ( " - The prompt shows model [verbosity] <location>> (model id from MCP_AGENT_MODEL_NAME or default)." ) ;
1129- Console . WriteLine ( " - ↑ / ↓ recall previous inputs; history and verbosity persist in .mcpServer/director-agent-console-state.json." ) ;
1130- Console . WriteLine ( " - Prefix a line with ! to run it directly in the local PowerShell session." ) ;
1131- Console . WriteLine ( " - Any line without ! is sent to the hosted agent as a normal chat prompt." ) ;
1243+ Console . WriteLine ( "Persistence:" ) ;
1244+ Console . WriteLine ( " History and verbosity persist at .mcpServer/director-agent-console-state.json in the workspace." ) ;
11321245 Console . WriteLine ( ) ;
1133- Console . WriteLine ( "You can also execute a single prompt non-interactively :" ) ;
1246+ Console . WriteLine ( "Non-interactive mode — pass a single prompt as an argument :" ) ;
11341247 Console . WriteLine ( @" director agent ""List open TODO items""" ) ;
11351248 Console . WriteLine ( @" director agent ""! Get-Location""" ) ;
11361249 Console . WriteLine ( ) ;
0 commit comments