@@ -55,6 +55,9 @@ setSpinnerAccessor(() => currentSpinner);
5555// Pending choice promise — main loop awaits this before showing next prompt
5656let pendingChoicePromise : Promise < void > | null = null ;
5757
58+ // Active custom prompt renderer (set by questionWithCompletion)
59+ let activePromptRenderer : PromptRenderer | null = null ;
60+
5861// Track the active request for cancellation support
5962let currentRequestId : string | undefined ;
6063let isProcessing = false ;
@@ -290,6 +293,28 @@ export function createEnhancedClientIO(
290293 currentSpinner . flushStream ( ) ;
291294 currentSpinner . writeAbove ( displayText ) ;
292295 }
296+ } else if ( activePromptRenderer ) {
297+ // Custom prompt (questionWithCompletion) is active.
298+ // Clear the prompt rows, write content above, then re-render.
299+ const rows = activePromptRenderer . rows ( ) ;
300+ for ( let i = 0 ; i < rows ; i ++ ) {
301+ process . stdout . write ( "\x1b[1A\x1b[2K" ) ;
302+ }
303+ if ( appendMode !== "inline" ) {
304+ if ( lastAppendMode === "inline" ) {
305+ process . stdout . write ( "\n" ) ;
306+ }
307+ process . stdout . write ( displayText ) ;
308+ process . stdout . write ( "\n" ) ;
309+ } else {
310+ process . stdout . write ( displayText ) ;
311+ }
312+ // Also re-render any collapsed debug panel summary
313+ const dp = getDebugPanel ( ) ;
314+ if ( dp && dp . lineCount > 0 ) {
315+ dp . renderStaticSummary ( ) ;
316+ }
317+ activePromptRenderer . redraw ( ) ;
293318 } else if ( rl ) {
294319 // Readline is active - write above the prompt
295320 // Clear current line, write content, then let readline redraw prompt
@@ -979,14 +1004,22 @@ async function questionWithCompletion(
9791004 // Initial render
9801005 render ( ) ;
9811006
982- // Register prompt renderer so debug panel can render above the input
983- const PROMPT_ROWS = 3 ; // input line + bottom rule + hint
1007+ // Register prompt renderer so debug panel and displayContent
1008+ // can render above the input.
1009+ // PROMPT_ROWS = separator + input line + bottom rule + hint
1010+ const PROMPT_ROWS = 4 ;
9841011 const panel = getDebugPanel ( ) ;
1012+ const renderWithSeparator = ( ) => {
1013+ const w = process . stdout . columns || 80 ;
1014+ stdout . write ( ANSI . dim + "─" . repeat ( w ) + ANSI . reset + "\n" ) ;
1015+ render ( ) ;
1016+ } ;
9851017 const promptRenderer : PromptRenderer = {
9861018 rows : ( ) => PROMPT_ROWS ,
987- redraw : ( ) => render ( ) ,
1019+ redraw : ( ) => renderWithSeparator ( ) ,
9881020 } ;
9891021 panel ?. setPromptRenderer ( promptRenderer ) ;
1022+ activePromptRenderer = promptRenderer ;
9901023
9911024 // Handle keypresses
9921025 const onData = async ( chunk : Buffer ) => {
@@ -1075,12 +1108,12 @@ async function questionWithCompletion(
10751108 // Ctrl+D — dump debug buffer above the prompt
10761109 const dp = getDebugPanel ( ) ;
10771110 if ( dp && dp . lineCount > 0 ) {
1078- // Clear prompt lines, dump buffer, re-render prompt
1111+ // Clear prompt lines (including separator) , dump buffer, re-render
10791112 for ( let i = 0 ; i < PROMPT_ROWS ; i ++ ) {
10801113 stdout . write ( "\x1b[1A\x1b[2K" ) ;
10811114 }
10821115 dp . dumpBuffer ( ) ;
1083- render ( ) ;
1116+ renderWithSeparator ( ) ;
10841117 }
10851118 return ;
10861119 } else if ( code === 13 ) {
@@ -1186,6 +1219,7 @@ async function questionWithCompletion(
11861219
11871220 const cleanup = ( ) => {
11881221 panel ?. setPromptRenderer ( null ) ;
1222+ activePromptRenderer = null ;
11891223 stdin . removeListener ( "data" , onData ) ;
11901224 if ( stdin . isTTY ) {
11911225 stdin . setRawMode ( wasRaw || false ) ;
@@ -1254,6 +1288,80 @@ function initializeEnhancedConsole(
12541288
12551289let usingEnhancedConsole = false ;
12561290
1291+ // ── Startup Banner ──────────────────────────────────────────────────────
1292+
1293+ // Logo mark — hexagonal badge with floating "T" (4 lines tall, 12 chars wide)
1294+ const LOGO_LINES = [
1295+ " ╱▔▔▔▔▔╲ " ,
1296+ " ╱ ▀▀█▀▀ ╲ " ,
1297+ " ╲ █ ╱ " ,
1298+ " ╲▁▁▁▁▁╱ " ,
1299+ ] ;
1300+ const LOGO_WIDTH = 12 ;
1301+
1302+ function renderStartupBanner ( ) : void {
1303+ const width = process . stdout . columns || 80 ;
1304+ const innerWidth = width - 4 ; // "│ " + " │"
1305+ const version = "0.0.1" ;
1306+
1307+ // Content lines to render alongside the logo
1308+ const contentLines = [
1309+ chalk . cyan . bold ( "TypeAgent" ) + chalk . dim ( ` v${ version } ` ) ,
1310+ chalk . dim ( "Your personal AI assistant" ) ,
1311+ "" ,
1312+ chalk . dim ( "Type a request or use /help to see commands." ) ,
1313+ ] ;
1314+
1315+ const hintLine =
1316+ " " +
1317+ chalk . dim (
1318+ "/help commands · /verbose debug · ctrl+d debug · ctrl+c exit" ,
1319+ ) ;
1320+
1321+ // Build the box
1322+ const top = chalk . dim ( "╭" + "─" . repeat ( width - 2 ) + "╮" ) ;
1323+ const bottom = chalk . dim ( "╰" + "─" . repeat ( width - 2 ) + "╯" ) ;
1324+
1325+ const lines : string [ ] = [ ] ;
1326+ lines . push ( top ) ;
1327+
1328+ // Render logo + content side by side
1329+ const totalRows = Math . max ( LOGO_LINES . length , contentLines . length ) ;
1330+ for ( let i = 0 ; i < totalRows ; i ++ ) {
1331+ const logo =
1332+ i < LOGO_LINES . length ? LOGO_LINES [ i ] : " " . repeat ( LOGO_WIDTH ) ;
1333+ const coloredLogo = chalk . cyan ( logo ) ;
1334+ const content = i < contentLines . length ? contentLines [ i ] : "" ;
1335+ const contentVisible = content . replace (
1336+ // eslint-disable-next-line no-control-regex
1337+ / \x1b \[ [ 0 - 9 ; ] * m / g,
1338+ "" ,
1339+ ) ;
1340+ const padding = Math . max (
1341+ 0 ,
1342+ innerWidth - LOGO_WIDTH - contentVisible . length ,
1343+ ) ;
1344+ lines . push (
1345+ chalk . dim ( "│" ) +
1346+ " " +
1347+ coloredLogo +
1348+ content +
1349+ " " . repeat ( padding ) +
1350+ chalk . dim ( "│" ) ,
1351+ ) ;
1352+ }
1353+
1354+ // Empty line before close
1355+ lines . push ( chalk . dim ( "│" ) + " " . repeat ( width - 2 ) + chalk . dim ( "│" ) ) ;
1356+ lines . push ( bottom ) ;
1357+ lines . push ( hintLine ) ;
1358+ lines . push ( "" ) ;
1359+
1360+ for ( const line of lines ) {
1361+ process . stdout . write ( line + "\n" ) ;
1362+ }
1363+ }
1364+
12571365/**
12581366 * Wrapper for using enhanced console ClientIO
12591367 */
@@ -1273,15 +1381,8 @@ export async function withEnhancedConsoleClientIO(
12731381 const dispatcherRef : { current ?: Dispatcher } = { } ;
12741382 initializeEnhancedConsole ( rl , dispatcherRef ) ;
12751383
1276- // Show welcome header
1277- const width = process . stdout . columns || 80 ;
1278- console . log ( ANSI . dim + "═" . repeat ( width ) + ANSI . reset ) ;
1279- console . log (
1280- chalk . bold ( " TypeAgent Interactive Mode " ) +
1281- chalk . dim ( "(Enhanced UI)" ) ,
1282- ) ;
1283- console . log ( ANSI . dim + "═" . repeat ( width ) + ANSI . reset ) ;
1284- console . log ( "" ) ;
1384+ // Show welcome banner
1385+ renderStartupBanner ( ) ;
12851386 await callback (
12861387 createEnhancedClientIO ( rl , dispatcherRef ) ,
12871388 ( d : Dispatcher ) => {
0 commit comments