@@ -144,13 +144,14 @@ import { consumeStream } from "../session/stream-consumer.js";
144144import { createCycleTextRecorder } from "../session/stream-journal.js" ;
145145import { mountRunnerHost } from "../tui-opentui/runner-host.js" ;
146146import {
147- appendStreamRow ,
148147 attachClipboardImage ,
149148 setMentionSuggestionSource ,
150149 setPromptRecognitionSource ,
151150 setSentMessageHistory ,
152151 setShellRunState ,
152+ surfaceStartupNotice ,
153153} from "../tui-opentui/shell.js" ;
154+ import { flushStartupNotices } from "../tui-opentui/startup-notices.js" ;
154155import {
155156 classifyAgentSendFailure ,
156157 shouldSettleUiAfterSendFailure ,
@@ -434,8 +435,8 @@ export async function runTUI(initialConfig: Config): Promise<number> {
434435 // Fire-and-forget startup diagnostics (this + tool-plugin resolution below)
435436 // have no result channel back to an operator action, unlike verify/add-path/
436437 // trust-grant. A log-only summary is invisible — nobody watches
437- // ~/.corbits/logs/corbits.log — so these are also queued as transcript rows
438- // once the shell mounts (see `systemRow` calls after `mountRunnerHost`) .
438+ // ~/.corbits/logs/corbits.log — so these are queued and handed to
439+ // `flushStartupNotices` once the shell mounts.
439440 const startupPluginNotices : string [ ] = [ ] ;
440441 const discoveryNotice = formatPluginWarningsSummary ( pluginLoadDiag . warnings ) ;
441442 if ( discoveryNotice !== undefined ) startupPluginNotices . push ( discoveryNotice ) ;
@@ -1840,8 +1841,13 @@ export async function runTUI(initialConfig: Config): Promise<number> {
18401841 } ,
18411842 } ;
18421843
1843- const systemRow = ( text : string ) : void => {
1844- appendStreamRow ( host . shell , { role : "system" , text, meta : "command" } ) ;
1844+ // Routed through the shell's notice path rather than straight into the
1845+ // transcript: anything the runner says before the first turn arrives while
1846+ // the landing hero still owns the screen, and a transcript row there wipes
1847+ // the whole composition. Once a session row has ended the landing this is an
1848+ // ordinary system row, so there is no second behaviour to reason about.
1849+ const systemNotice = ( text : string ) : void => {
1850+ surfaceStartupNotice ( host . shell , text ) ;
18451851 } ;
18461852
18471853 /** Settle the shell after a rejected send so the run does not look live. */
@@ -1854,7 +1860,7 @@ export async function runTUI(initialConfig: Config): Promise<number> {
18541860 ) ;
18551861 if ( ! shouldSettleUiAfterSendFailure ( kind ) ) return ;
18561862 recordRunError ( err ) ;
1857- systemRow ( err instanceof Error ? err . message : String ( err ) ) ;
1863+ systemNotice ( err instanceof Error ? err . message : String ( err ) ) ;
18581864 setShellRunState ( host . shell , "idle" ) ;
18591865 } ;
18601866
@@ -1899,29 +1905,29 @@ export async function runTUI(initialConfig: Config): Promise<number> {
18991905 const applyCommandResult = ( result : CommandResult ) : void => {
19001906 switch ( result . type ) {
19011907 case "message" :
1902- systemRow ( result . text ) ;
1908+ systemNotice ( result . text ) ;
19031909 return ;
19041910 case "send" :
19051911 void agentProxy . send ( result . text ) . catch ( handleSendFailure ) ;
19061912 return ;
19071913 case "workflow" :
1908- systemRow ( workflowController . start ( result . name ) ) ;
1914+ systemNotice ( workflowController . start ( result . name ) ) ;
19091915 return ;
19101916 case "noop" :
19111917 return ;
19121918 case "overlay" :
19131919 if ( ! host . openSurface ( result . overlay ) ) {
1914- systemRow ( `No surface for /${ result . overlay } .` ) ;
1920+ systemNotice ( `No surface for /${ result . overlay } .` ) ;
19151921 }
19161922 return ;
19171923 case "modal" :
19181924 // /model is the only modal reachable from a command; provider login is
19191925 // reached from the picker itself.
19201926 if ( result . modal === "agent" && host . openSurface ( "models" ) ) return ;
1921- systemRow ( `${ result . modal } is not available in this renderer yet` ) ;
1927+ systemNotice ( `${ result . modal } is not available in this renderer yet` ) ;
19221928 return ;
19231929 case "view" :
1924- systemRow ( `${ result . view } is not available in this renderer yet` ) ;
1930+ systemNotice ( `${ result . view } is not available in this renderer yet` ) ;
19251931 return ;
19261932 case "paste-image" :
19271933 void attachClipboardImage ( host . shell ) ;
@@ -1958,7 +1964,7 @@ export async function runTUI(initialConfig: Config): Promise<number> {
19581964 const dispatchCommand = ( name : string , args : string ) : void => {
19591965 const command = getCommand ( name ) ;
19601966 if ( command === undefined ) {
1961- systemRow ( `Unknown command: ${ name } ` ) ;
1967+ systemNotice ( `Unknown command: ${ name } ` ) ;
19621968 return ;
19631969 }
19641970 applyCommandResult ( command . handler ( args , commandContext ) ) ;
@@ -2015,7 +2021,7 @@ export async function runTUI(initialConfig: Config): Promise<number> {
20152021 existing : config . settings ?? null ,
20162022 } ) ;
20172023 } catch ( err ) {
2018- systemRow (
2024+ systemNotice (
20192025 `Connecting ${ providerName } failed: ${ err instanceof Error ? err . message : String ( err ) } ` ,
20202026 ) ;
20212027 return ;
@@ -2040,7 +2046,7 @@ export async function runTUI(initialConfig: Config): Promise<number> {
20402046 providers ,
20412047 computeUnconnectedProviders ( providers ) ,
20422048 ) ;
2043- systemRow ( `Connected ${ result . providerName ?? providerName } . Open /model to pick a model.` ) ;
2049+ systemNotice ( `Connected ${ result . providerName ?? providerName } . Open /model to pick a model.` ) ;
20442050 } ) ( ) . catch ( ( err : unknown ) => {
20452051 tuiLogger . debug ( "provider connect failed: {error}" , {
20462052 error : err instanceof Error ? err . message : String ( err ) ,
@@ -2370,9 +2376,9 @@ export async function runTUI(initialConfig: Config): Promise<number> {
23702376 } ) ;
23712377 } ) ;
23722378
2373- // Surface fire-and-forget startup plugin diagnostics now that the shell has
2374- // a transcript to write into (queued above, before `host` existed).
2375- for ( const notice of startupPluginNotices ) systemRow ( notice ) ;
2379+ // Surface fire-and-forget startup plugin diagnostics now that there is a
2380+ // shell to say them to (queued above, before `host` existed).
2381+ flushStartupNotices ( host . shell , startupPluginNotices ) ;
23762382
23772383 await host . waitUntilExit ( ) ;
23782384 // Quitting mid-stream is an abnormal end for the in-flight cycle: nothing
0 commit comments