Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587const std = @import("std");const question_prompt = @import("../agent/question_prompt.zig");const input_completion_runtime = @import("input_completion_runtime.zig");const app_commands = @import("app_commands.zig");const app_lifecycle = @import("app_lifecycle.zig");const app_permission_runtime = @import("app_permission_runtime.zig");const app_session_runtime = @import("app_session_runtime.zig");const terminal_ui_projection = @import("../terminal/ui_projection.zig");const worker_runtime = @import("../agent/worker_runtime.zig");const auth_runtime = @import("../auth/auth_runtime.zig");const provider_picker_runtime = @import("provider_picker_runtime.zig");const model_capabilities = @import("../config/model_capabilities.zig");const picker_state = @import("../input/picker_state.zig");const core_input_runtime = @import("../input/runtime.zig");const command_specs = @import("../slash_commands/command_specs.zig");const model_cache_runtime = @import("model_cache_runtime.zig");const provider_runtime = @import("provider_runtime.zig");const debug_trace = @import("../shared/debug_trace.zig");const diff_mod = @import("../output/diff.zig");const io_mod = @import("../shared/io.zig");const text_utils = @import("../shared/text_utils.zig");const permission_request = @import("../permissions/permission_request.zig");const skill_runtime = @import("../skills/skill_runtime.zig");const types = @import("../shared/types.zig");const file_index = @import("../workspace/file_index.zig");const statusline_identity = @import("../workspace/statusline_identity.zig");const activity_runtime = @import("../output/activity_runtime.zig");const transcript_presentation = @import("../output/transcript_presentation.zig");const event_loop = @import("../../ui/event_loop.zig");const surface_frame = @import("../../ui/footer/surface_frame.zig");const surface_invalidation = @import("../../ui/footer/surface_invalidation.zig");const interaction_state = @import("../../ui/footer/interaction_state.zig");const approval_prompt = @import("../permissions/approval_prompt.zig");const render_input = @import("../../ui/footer/render_input.zig");const input_presentation = @import("../../ui/footer/input_presentation.zig");const footer_viewport = @import("../../ui/footer/viewport.zig");const render_request = @import("../../ui/render_request.zig");const ui_input = @import("../../ui/input/runtime.zig");const input_visual_layout = @import("../../ui/input/visual_layout.zig");const registered_entities = @import("../input/registered_entities.zig");const approval_screen = @import("../../ui/approval_screen.zig");const full_transcript_screen = @import("../../ui/full_transcript_screen.zig");const session_child_store = @import("../session/session_child_store.zig");const render_engine = @import("../../ui/render_engine.zig");const build_checkpoint = @import("../../ui/render_engine/build_checkpoint.zig");const shell_runtime = @import("../../ui/shell_runtime.zig");const shimmer_runtime = @import("../../ui/transcript/shimmer_runtime.zig");const ui_terminal = @import("../../ui/terminal/terminal.zig");const vt_emulator = @import("../terminal/engine.zig");const transcript_painter = @import("../../ui/transcript/painter.zig");const command_output_runtime = @import("../../ui/transcript/command_output_runtime.zig");const resume_projection = @import("../../ui/transcript/resume_projection.zig");const transcript_runtime = @import("../../ui/transcript/runtime.zig");const ui_render = @import("../../ui/render.zig");const shared_theme = @import("../shared/theme.zig");const assistant_pacer = @import("../../ui/assistant/pacer.zig");const user_message_card = @import("../../ui/assistant/user_message_card.zig");
fn set_transcript_assistant_tail_writable( runtime: *transcript_runtime.TranscriptRuntime, writable: bool,) void { if (runtime.transcript_release.assistant_tail_writable == writable) return; runtime.transcript_release = runtime.transcript_release.with_assistant_tail_writable(writable); debug_trace.logf( "scroll", "assistant tail writability changed writable={s}", .{if (writable) "true" else "false"}, );}
pub const VisualEpochResetTrigger = enum { native_clear_probe, ctrl_l,};
const FrameAttemptResult = struct { shadow_state: render_engine.terminal_diff.ShadowCommitState, animation_visible: bool, yolo_warning_visible: bool = false, pending_prompt_presented: bool = false, file_picker_receipt: ?input_completion_runtime.FilePickerReceipt = null,
fn is_committed(self: FrameAttemptResult) bool { return self.shadow_state.is_committed(); }};
const InlineRenderReconciliation = struct { alternate_screen_owns_rendering: bool = false, terminal_transition: render_engine.terminal_diff.FrameTerminalTransition = .none,};
/// Couples the physical terminal buffer with the logical presentation that/// owns retry invalidations.const SurfaceFrameShell = struct { output: *transcript_runtime.TranscriptRuntime, invalidation_owner: *transcript_runtime.TranscriptRuntime, shadow_vt: ?*vt_emulator.Grid, committed_frame_layout: render_engine.frame_layout.CommittedLayoutSnapshot, history_reset_uses_ris: bool,
fn init( output: *transcript_runtime.TranscriptRuntime, invalidation_owner: *transcript_runtime.TranscriptRuntime, committed_frame_layout: render_engine.frame_layout.CommittedLayoutSnapshot, ) SurfaceFrameShell { return .{ .output = output, .invalidation_owner = invalidation_owner, .shadow_vt = output.shadow_vt, .committed_frame_layout = committed_frame_layout, .history_reset_uses_ris = output.history_reset_uses_ris, }; }
pub fn frameSink( self: *SurfaceFrameShell, ) render_engine.terminal_diff.FrameSink { return self.output.frameSink(); }
pub fn recordFrameInvalidation( self: *SurfaceFrameShell, range: render_engine.paint_plan.FrameInvalidationRange, ) !void { try self.invalidation_owner.recordFrameInvalidation(range); }};
const RenderReconciliation = union(enum) { inline_render: InlineRenderReconciliation, file_approval_screen, frame_result: FrameAttemptResult,};
const SteeringProjection = struct { messages: [][]u8 = &.{}, pending_feedback: [][]u8 = &.{}, waits_for_boundary: bool = false,
fn deinit(self: *SteeringProjection, alloc: std.mem.Allocator) void { for (self.messages) |message| alloc.free(message); if (self.messages.len > 0) alloc.free(self.messages); for (self.pending_feedback) |message| alloc.free(message); if (self.pending_feedback.len > 0) alloc.free(self.pending_feedback); self.* = .{}; }};
const PendingCardProjection = struct { bytes: []u8, row_count: u16, paint_row_count: u16, leading_advance_rows: u16,
fn overlaps_flow_endpoint(self: PendingCardProjection, cursor_col: u16) bool { return self.leading_advance_rows == 0 and cursor_col > 1; }
fn deinit(self: *PendingCardProjection, alloc: std.mem.Allocator) void { alloc.free(self.bytes); self.* = undefined; }};
const PendingCardPaintContext = struct { bytes: []const u8, row: u16, max_rows: u16,
fn init( card: PendingCardProjection, band: render_engine.paint_plan.FrameBand, canonical_cursor_row: ?u16, activity_visible: bool, ) ?PendingCardPaintContext { if (band.isEmpty()) return null; const row = if (canonical_cursor_row) |base| @max(base +| card.leading_advance_rows, band.top) else band.top; if (row > band.bottom) return null; const blank_rows: u16 = @intFromBool(activity_visible and band.bottom > row); const bottom = band.bottom - blank_rows; const max_rows = @min(card.paint_row_count, bottom - row + 1); if (max_rows == 0) return null; var lines = std.mem.splitScalar(u8, card.bytes, '\n'); for (0..card.paint_row_count - max_rows) |_| _ = lines.next(); return .{ .bytes = lines.rest(), .row = row, .max_rows = max_rows }; }
fn paint( raw: *anyopaque, surface: *render_engine.frame_surface.FrameSurface, ) anyerror!void { const self: *PendingCardPaintContext = @ptrCast(@alignCast(raw)); _ = try surface.writeAnsiBandNoWrap( self.row, self.max_rows, self.bytes, .transcript, .same_owner, ); }};
fn pendingCardLeadingAdvanceRows( cursor_row: u16, cursor_col: u16, content_bottom: u16,) u16 { if (cursor_col == 1 or cursor_row >= content_bottom) return 0; const canonical_rows = render_engine.transcript_blocks.blockSeparatorNewlineCount( .unknown_raw, .user_turn, ); return @min(canonical_rows, content_bottom - cursor_row);}
fn buildPendingCardProjection( comptime App: type, app: *App, presentation_shell: *const transcript_runtime.TranscriptRuntime, checkpoint: ?*build_checkpoint.BuildCheckpoint,) !?PendingCardProjection { if (comptime !@hasField(App, "submission")) return null; const pending = app.submission.pending orelse return null; switch (pending.phase) { .awaiting_frame, .awaiting_adoption => {}, .adopted, .awaiting_auth, .queued => return null, }
const spans = pending.draft.skill_display_spans; const skill_tokens: []registered_entities.SkillTokenSpan = if (spans.len == 0) &.{} else try app.alloc.alloc(registered_entities.SkillTokenSpan, spans.len); defer if (skill_tokens.len > 0) app.alloc.free(skill_tokens); for (spans, 0..) |span, index| { skill_tokens[index] = .{ .raw_start = span.raw_start, .raw_end = span.raw_end, .name = span.name, .path = span.path, .display_source = span.display_source, .owns_trailing_separator = span.owns_trailing_separator, }; }
const cursor_row = @min( @max(presentation_shell.cursor_row, 1), presentation_shell.layout.content_bottom, ); const leading_advance_rows = pendingCardLeadingAdvanceRows( cursor_row, presentation_shell.cursor_col, presentation_shell.layout.content_bottom, ); const available_rows = presentation_shell.layout.content_bottom - cursor_row + 1 -| leading_advance_rows; const card = try user_message_card.buildUserPromptCardTailForTerminalPresentationInterruptible( app.alloc, pending.draft.prompt, pending.draft.images, presentation_shell.layout.cols, skill_tokens, @max(available_rows, 1), checkpoint, ); defer app.alloc.free(card); if (card.len == 0) return null; const bytes = try pendingCardTerminalWireBytes(app.alloc, card); const rendered_line_count: u16 = @intCast(@min( std.mem.count(u8, card, "\n"), @as(usize, std.math.maxInt(u16)), )); const paint_row_count = rendered_line_count; const row_count = rendered_line_count +| leading_advance_rows; if (row_count == 0) { app.alloc.free(bytes); return error.EmptyPendingPromptCard; } return .{ .bytes = bytes, .row_count = row_count, .paint_row_count = paint_row_count, .leading_advance_rows = leading_advance_rows, };}
fn pendingPromptActivityVisible(app: anytype) bool { if (comptime !@hasField(@TypeOf(app.*), "submission")) return false; const pending = app.submission.pending orelse return false; return pending.phase != .awaiting_auth;}
fn buildPendingSteeringCardProjection( alloc: std.mem.Allocator, shell: *const transcript_runtime.TranscriptRuntime, steering: SteeringProjection, checkpoint: ?*build_checkpoint.BuildCheckpoint,) !?PendingCardProjection { const queued_count = if (steering.waits_for_boundary) 0 else steering.messages.len; var index = steering.pending_feedback.len + queued_count; if (index == 0) return null;
var card_bytes: std.ArrayList(u8) = .empty; defer card_bytes.deinit(alloc); var row_count: u16 = 0; const row_limit = @max(shell.layout.content_bottom, 1); while (index > 0 and row_count < row_limit) { index -= 1; const message = if (index < steering.pending_feedback.len) steering.pending_feedback[index] else steering.messages[index - steering.pending_feedback.len]; const gap: u16 = @intFromBool(card_bytes.items.len > 0); const remaining_rows = row_limit - row_count -| gap; if (remaining_rows == 0) break; const card = try user_message_card.buildUserPromptCardTailForTerminalPresentationInterruptible( alloc, message, &.{}, shell.layout.cols, &.{}, remaining_rows, checkpoint, ); defer alloc.free(card); if (card.len == 0) continue; if (gap > 0) try card_bytes.insert(alloc, 0, '\n'); try card_bytes.insertSlice(alloc, 0, card); row_count += @as(u16, @intCast(std.mem.count(u8, card, "\n"))) + gap; } if (row_count == 0) return null; const leading_rows = pendingCardLeadingAdvanceRows( @min(@max(shell.cursor_row, 1), shell.layout.content_bottom), shell.cursor_col, shell.layout.content_bottom, ); return .{ .bytes = try pendingCardTerminalWireBytes(alloc, card_bytes.items), .row_count = row_count +| leading_rows, .paint_row_count = row_count, .leading_advance_rows = leading_rows, };}
fn pendingCardTerminalWireBytes( alloc: std.mem.Allocator, logical: []const u8,) ![]u8 { var logical_end = logical.len; if (logical_end > 0 and logical[logical_end - 1] == '\n') logical_end -= 1; if (logical_end > 0 and logical[logical_end - 1] == '\r') logical_end -= 1; const source = logical[0..logical_end]; var missing_carriage_returns: usize = 0; for (source, 0..) |byte, index| { if (byte == '\n' and (index == 0 or source[index - 1] != '\r')) { missing_carriage_returns += 1; } } const wire_len = try std.math.add( usize, source.len, missing_carriage_returns, ); const wire = try alloc.alloc(u8, wire_len); var written: usize = 0; for (source, 0..) |byte, index| { if (byte == '\n' and (index == 0 or source[index - 1] != '\r')) { wire[written] = '\r'; written += 1; } wire[written] = byte; written += 1; } std.debug.assert(written == wire.len); return wire;}
fn previewWithPendingCard( preview: render_engine.frame_layout.TranscriptFlowPreview, pending: ?PendingCardProjection,) render_engine.frame_layout.TranscriptFlowPreview { const card = pending orelse return preview; var next = preview; next.natural_visual_rows +|= card.row_count; next.cursor_row +|= card.row_count; next.cursor_col = 1; next.replaceable_row = next.cursor_row; next.tail_kind = .user_turn; next.replaceable_active = false; next.trailing_boundary_blank_rows = 0; next.footer_boundary_gap_rows = 0; return next;}
// Every steering slice in the result is owned for one render frame.fn buildSteeringProjection(comptime App: type, app: *App) !SteeringProjection { var projection: SteeringProjection = .{}; errdefer projection.deinit(app.alloc); if (comptime @hasDecl(@TypeOf(app.worker), "snapshotSteeringPresentation")) { var snapshot = try app.worker.snapshotSteeringPresentation(app.alloc); defer snapshot.deinit(app.alloc); projection.waits_for_boundary = snapshot.waits_for_boundary; projection.messages = snapshot.messages; snapshot.messages = &.{}; projection.pending_feedback = snapshot.pending_feedback; snapshot.pending_feedback = &.{}; } return projection;}
noinline fn approvalScreenNeedsClear( screen_active: bool, request: permission_request.PermissionRequest, layout: types.Layout, commit: ?interaction_state.ApprovalScreenCommit,) bool { if (!screen_active) return true; const prior = commit orelse return true; return prior.request_id != request.id or prior.rows != layout.rows or prior.cols != layout.cols;}
pub fn Runtime(comptime App: type) type { return struct { fn appendDeferredHistoryForVisualEpoch( ctx: *anyopaque, finished: *const types.FinishedPrompt, ) anyerror!assistant_pacer.DeferredFinishCommit { const app: *App = @ptrCast(@alignCast(ctx)); return switch (try app_session_runtime.Runtime(App).appendFinishedPromptForVisualEpoch( app, finished.*, )) { .uncommitted => .uncommitted, .committed => .committed, }; }
pub fn resetVisualEpoch( app: *App, trigger: VisualEpochResetTrigger, ) !bool { const welcome = try ui_render.welcomeMessage(app.alloc); defer app.alloc.free(welcome);
const committed = try app.pacer.discardDeferredPresentationForVisualEpoch( app.alloc, .{ .ctx = app, .append_history = appendDeferredHistoryForVisualEpoch, }, ); if (!committed) { switch (trigger) { .native_clear_probe => debug_trace.logf( "native_clear", "native_clear_recovery_skipped reason=history_uncommitted", .{}, ), .ctrl_l => debug_trace.logf( "render", "visual_epoch_reset_skipped trigger=ctrl_l reason=history_uncommitted", .{}, ), } return false; }
try app.shell.resetVisualEpoch(app.alloc, welcome); try app.shell.requestTerminalReset(&app.metrics); switch (trigger) { .native_clear_probe => debug_trace.logf( "native_clear", "native_clear_recovery_requested", .{}, ), .ctrl_l => debug_trace.logf( "render", "visual_epoch_reset_requested trigger=ctrl_l", .{}, ), } return true; }
pub fn applyThemeUpdate(app: *App, light: bool, rgb: ?ui_render.TerminalRgb) !void { if (!ui_render.themeNeedsUpdate(light, rgb)) return;
const prior_light = ui_render.is_light; app.shell.retintEntriesForTheme(app.alloc, prior_light, light) catch |err| { debug_trace.logf("theme", "theme_transcript_retint_failed err={s}", .{@errorName(err)}); return; }; app.pacer.rethemeInlineCode(light); if (shared_theme.sourceName() orelse ui_render.explicitThemeName()) |name| { // Custom themes re-resolve on live flips: sibling swap or // builtin fallback, same rule as startup. const custom = shared_theme.resolveNamed(app.alloc, name, light, .{ .truecolor = ui_render.truecolorIsEnabled() }) catch |err| blk: { debug_trace.logf("theme", "live_theme_resolve_failed name={s} err={s}", .{ name, @errorName(err) }); break :blk null; }; if (custom) |resolved| { ui_render.applyTheme(resolved, rgb); } else { ui_render.initTheme(light, rgb); } } else { ui_render.initTheme(light, rgb); } app.shell.setCommandOutputRenderPolicy(shellStyles()); try app.shell.requestTerminalReset(&app.metrics); app.shell.render_requests.request(.transcript); }
pub fn shellStyles() transcript_runtime.Styles { return .{ .system_notice_label_style = ui_render.system_notice_label_style, .system_notice_text_style = ui_render.system_notice_text_style, .reset_style = ui_render.reset_style, .dim_style = ui_render.dim_style, .red_style = ui_render.red_style, .notice_information_style = ui_render.system_notice_label_style, .notice_success_style = ui_render.green_style, .notice_warning_style = ui_render.warning_style, .notice_error_style = ui_render.red_style, .notice_cancelled_style = ui_render.dim_style, .code_highlight_theme = if (ui_render.is_light) .light else .dark, }; }
var model_completions_buf: [32][]const u8 = undefined; var effort_picker_values_buf: [types.ReasoningEffort.max_options + 1]types.ReasoningEffort = undefined; var effort_picker_labels_buf: [types.ReasoningEffort.max_options + 1][]const u8 = undefined; var fast_picker_labels_buf: [2][]const u8 = undefined; var provider_picker_column: provider_picker_runtime.ColumnBuffer = .{}; noinline fn footerContext( app: *App, upgrade_status_buf: *[64]u8, shimmer_pos: i16, steering: *const SteeringProjection, ) render_input.RenderContext { const model_query = app.input_runtime.picker.activeModelPickerQuery(&app.input_runtime.edit_state); const pending_model = if (app.input_runtime.picker.hasPendingModelPickerSelection()) app.input_runtime.picker.model_picker_pending_model.items else null; var model_picker_stage: picker_state.ModelPickerStage = .model; var picker_items: []const []const u8 = &.{}; var picker_index: usize = 0; var picker_window_start: usize = 0; var picker_anchor: usize = 0;
if (model_query) |picker_query| { model_picker_stage = picker_query.stage; picker_anchor = picker_query.token_start; switch (picker_query.stage) { .model => { const count = input_completion_runtime.CompletionRuntime(App).modelPickerCompletions(app, picker_query.query, &model_completions_buf); picker_items = model_completions_buf[0..count]; picker_index = input_completion_runtime.CompletionRuntime(App).modelPickerIndex(app, picker_items); picker_window_start = input_completion_runtime.CompletionRuntime(App).modelPickerWindowStart(app, count, picker_index); }, .effort => { const target = if (app.input_runtime.picker.hasPendingModelPickerSelection()) app.input_runtime.picker.model_picker_pending_model.items else provider_runtime.model(app); const capabilities = model_capabilities.resolveForApp(App, app, target); const effort_count = model_capabilities.reasoningEffortOptionCount(capabilities); for (0..effort_count) |i| { effort_picker_values_buf[i] = model_capabilities.reasoningEffortAtIndex(capabilities, i); effort_picker_labels_buf[i] = effort_picker_values_buf[i].displayLabel(); } const count = picker_state.filterCompletionLabels(picker_query.query, effort_picker_labels_buf[0..effort_count], effort_picker_labels_buf[0..]); picker_items = effort_picker_labels_buf[0..count]; picker_index = app.input_runtime.picker.model_picker_effort_index; picker_window_start = app.input_runtime.picker.model_picker_effort_window_start; }, .fast => { for (picker_state.model_picker_fast_options, 0..) |option, i| fast_picker_labels_buf[i] = option; const count = picker_state.filterCompletionLabels(picker_query.query, fast_picker_labels_buf[0..], fast_picker_labels_buf[0..]); picker_items = fast_picker_labels_buf[0..count]; picker_index = app.input_runtime.picker.model_picker_fast_index; picker_window_start = app.input_runtime.picker.model_picker_fast_window_start; }, } }
const provider_query = if (model_query == null) app.input_runtime.picker.activeProviderPickerQuery(&app.input_runtime.edit_state) else null; var provider_stage: picker_state.ProviderPickerStage = .provider; var provider_picker_items: []const []const u8 = &.{}; var provider_picker_annotations: []const []const u8 = &.{}; var provider_picker_index: usize = 0; var provider_picker_window_start: usize = 0; var provider_picker_anchor: usize = 0; if (provider_query) |picker_query| { provider_stage = picker_query.stage; provider_picker_anchor = picker_query.token_start; const count = provider_picker_runtime.Runtime(App).columnOptions(app, picker_query, &provider_picker_column); provider_picker_items = provider_picker_column.labels[0..count]; provider_picker_annotations = provider_picker_column.annotations[0..count]; switch (picker_query.stage) { .provider => { provider_picker_index = app.input_runtime.picker.provider_column_index; provider_picker_window_start = app.input_runtime.picker.provider_column_window_start; }, .method => { provider_picker_index = app.input_runtime.picker.method_column_index; provider_picker_window_start = app.input_runtime.picker.method_column_window_start; }, .team => { provider_picker_index = app.input_runtime.picker.team_column_index; provider_picker_window_start = app.input_runtime.picker.team_column_window_start; }, .key_source => { provider_picker_index = app.input_runtime.picker.key_source_column_index; provider_picker_window_start = app.input_runtime.picker.key_source_column_window_start; }, .api_key => {}, } }
const completion_rt = input_completion_runtime.CompletionRuntime(App); const file_query = if (model_query == null and provider_query == null and completion_rt.hasFileQuery(app)) app.input_runtime.picker.activeFilePickerQuery(&app.input_runtime.edit_state) else null; const file_view = completion_rt.filePickerView(app); const file_anchor = if (file_query) |fq| fq.at_offset else 0; const file_selection = if (file_view.receipt) |receipt| receipt.selected else null; const file_status: ?[]const u8 = switch (file_view.status) { .unavailable => if (app.input_runtime.picker.file_completion.indexed) "Files unavailable. tab to retry; esc to dismiss." else "Directory unavailable. tab to retry; esc to dismiss.", .stale => "Selection unavailable. navigate to choose; tab to retry.", .loading, .ready, .empty => null, }; const inline_completion = input_completion_runtime.CompletionRuntime(App).visibleInlineCompletion(app);
const visible_model = pending_model orelse provider_runtime.model(app); const visible_capabilities = model_capabilities.resolveForApp(App, app, visible_model); const active_capabilities_pending = pending_model == null and app.isModelCacheLoading(); const model_supports_fast = visible_capabilities.supports_fast_mode; const model_supports_effort = visible_capabilities.reasoning_efforts.len > 0 or (active_capabilities_pending and !app.effort.isDefault()); const visible_effort = if (pending_model != null and model_supports_effort) pendingPickerEffort(app, visible_model, model_query, app.input_runtime.picker.model_picker_effort_index) else if (active_capabilities_pending or model_capabilities.reasoningEffortSupported(visible_capabilities, app.effort)) app.effort else .auto; const active_fast_mode_model_bound = if (comptime @hasDecl(App, "fastModeModelBound")) app.fastModeModelBound() else true; const fast_indicator_active = if (pending_model != null) visible_capabilities.intrinsic_fast or (model_supports_fast and pendingPickerFastMode(model_query, app.input_runtime.picker.model_picker_fast_index)) else visible_capabilities.intrinsic_fast or (app.fast_mode and active_fast_mode_model_bound);
const upgrade_label = app.upgrader.statusLabel(upgrade_status_buf); const yolo_warning_active = if (comptime @hasField(App, "permission_state") and @hasField(App, "permission_engine")) app_permission_runtime.Runtime(App).yoloWarningActive(app) else false; const settings_snapshot = app_commands.settingsCatalogSnapshot(app); const now_ms = io_mod.milliTimestamp(); var visible_stream = app.stream; if (visible_stream.active) { const cancel_requested = if (comptime @hasField(App, "worker")) if (comptime @hasDecl(@TypeOf(app.worker), "isCancelRequested")) app.worker.isCancelRequested() else false else false; if (cancel_requested) { const stops_turn = if (comptime @hasDecl( @TypeOf(app.worker), "cancellationStopsTurn", )) app.worker.cancellationStopsTurn() else true; if (stops_turn) visible_stream.active = false; } } if (!visible_stream.active) { if (app.pacer.completedAssistantPresentationTokenProgress()) |progress| { visible_stream.token_progress = progress; } }
return .{ .slash_registry = app.slashRegistry(), .stream = visible_stream, .compaction = if (comptime @hasDecl(@TypeOf(app.worker), "compactionActivitySnapshot")) app.worker.compactionActivitySnapshot() else .{}, .pending_prompt_activity = pendingPromptActivityVisible(app), .completed_assistant_presentation_tail = app.pacer.hasCompletedAssistantPresentationTail(), .writing_response = app.pacer.hasPending(), .has_api_key = app.auth.credentialSource() != null, .model = visible_model, .pending_images = app.pending_images.items, .permission_mode = if (comptime @hasField(App, "permission_engine")) app.permission_engine.mode else .ask, .steering_messages = steering.messages, .steering_waits_for_boundary = steering.waits_for_boundary, .fast_indicator_active = fast_indicator_active, .effort = visible_effort, .model_supports_effort = model_supports_effort, .ctrl_c_pending = app.input_runtime.gestures.ctrlCExitArmed(), .shimmer_pos = shimmer_pos, .now_ms = now_ms, .model_query_active = model_query != null, .model_picker_stage = model_picker_stage, .model_completions_loading = if (model_query != null and model_picker_stage == .model) app.isModelCacheLoading() else false, .model_completions_failed = if (model_query != null and model_picker_stage == .model) app.isModelCacheFailed() else false, .model_completions = picker_items, .model_completion_index = picker_index, .model_completion_window_start = picker_window_start, .model_completion_anchor = picker_anchor, .provider_query_active = provider_query != null, .provider_picker_stage = provider_stage, .provider_picker_completions = provider_picker_items, .provider_picker_annotations = provider_picker_annotations, .provider_picker_completion_index = provider_picker_index, .provider_picker_completion_window_start = provider_picker_window_start, .provider_picker_completion_anchor = provider_picker_anchor, .file_query_active = file_query != null, .file_completions = file_view.items, .file_completion_index = file_selection orelse 0, .file_completion_has_selection = file_selection != null, .file_completion_status = file_status, .file_completion_window_start = app.input_runtime.picker.file_completion_window_start, .file_completion_anchor = file_anchor, .file_completions_loading = file_view.status == .loading, .file_completions_failed = file_view.status == .unavailable, .inline_completion_suffix = if (inline_completion) |completion| completion.suffix() else "", .auth_picker = app.auth.pickerView(), .skills_menu = if (comptime @hasField(App, "skills")) render_input.skillsMenuProjection(&app.skills) else .{}, .mcp_menu = if (comptime @hasField(App, "mcp")) blk: { const view = app.mcp.menuView(); break :blk .{ .state = view.state, .servers = if (view.health) |health| health.servers else &.{}, .tools = view.tools, .resources = if (view.resources) |catalog| catalog.resources.items else &.{}, .resource_templates = if (view.resources) |catalog| catalog.templates.items else &.{}, .prompts = if (view.prompts) |catalog| catalog.items else &.{}, .configuration_issue_count = if (view.health) |health| health.configuration_issues.len else 0, .preview = view.preview, .feedback = view.feedback, .add_name = view.add_form.name.items, .add_target = view.add_form.target.items, .add_arguments = view.add_form.arguments.items, .add_draft = app.input_runtime.edit_state.input.items, .arguments = view.argument_fields, .argument_draft = app.input_runtime.edit_state.input.items, }; } else .{}, .help_menu = render_input.helpMenuProjection( &app.input_runtime.help_menu, app.slashRegistry(), app.input_runtime.edit_state.input.items, ), .settings_menu = blk: { var projection = render_input.settingsMenuProjection( &app.input_runtime.settings_menu, settings_snapshot, app.input_runtime.edit_state.input.items, ); if (comptime @hasField(App, "model_cache")) { projection.models = render_input.modelMenuProjection(&app.model_cache); } break :blk projection; }, .model_menu = if (comptime @hasField(App, "model_cache")) render_input.modelMenuProjection(&app.model_cache) else .{}, .session_menu = if (comptime @hasField(App, "session_persistence")) .{ .active = app.session_persistence.session_picker.active, .load_state = app.session_persistence.session_picker.load_state, .summaries = app.session_persistence.session_picker.summaries.items, .has_more = app.session_persistence.session_picker.has_more, .loading_more = app.session_persistence.session_picker.loading_more, .scope = app.session_persistence.session_picker.scope, .selected_index = app.session_persistence.session_picker.selected, .window_start = app.session_persistence.session_picker.window_start, .query = app.session_persistence.session_picker.query(), .now_ms = now_ms, .selection_failure = app.session_persistence.session_picker.selection_failure, } else .{}, .statusline_menu = render_input.statuslineMenuProjection( &app.input_runtime.statusline_menu, settings_snapshot, ), .usage_menu = render_input.usageMenuProjection( &app.input_runtime.usage_menu, ), .workspace_menu = if (comptime @hasDecl(App, "workspaceAccess")) render_input.workspaceMenuProjection( &app.input_runtime.workspace_menu, app.workspace_root, app.workspaceAccess(), ) else .{}, .upgrade_status = upgrade_label, .danger_status = if (yolo_warning_active) app_permission_runtime.yolo_warning_text else "", .danger_status_compact = if (yolo_warning_active) app_permission_runtime.yolo_warning_compact_text else "", .esc_clear_armed = app.input_runtime.gestures.escapeClearArmed(), .esc_interrupt_armed = app.input_runtime.gestures.escapeInterruptArmed(), .question = app.question_prompt.projection(), .statusline = buildStatuslineItems( app, visible_model, ), .activity = activityProjection(app), .input = &app.input_runtime, }; }
fn pendingPickerEffort(app: *App, model: []const u8, query: ?picker_state.ModelPickerQuery, effort_index: usize) types.ReasoningEffort { const capabilities = model_capabilities.resolveForApp(App, app, model); if (query) |picker_query| { if (picker_query.stage == .effort) { const typed = std.mem.trim(u8, picker_query.query, " \t"); if (types.ReasoningEffort.parseDisplayLabel(typed)) |effort| { if (model_capabilities.reasoningEffortSupported(capabilities, effort)) return effort; } } } return model_capabilities.reasoningEffortAtIndex(capabilities, effort_index); }
fn buildStatuslineItems( app: *App, visible_model: []const u8, ) ui_render.StatuslineItems { var items: ui_render.StatuslineItems = .{}; if (comptime @hasField(App, "workspace_identity") and @hasField(App, "workspace_root")) { const identity = app.workspace_identity.refresh( app.alloc, app.workspace_root, ) catch app.workspace_identity.snapshot(); items.workspace_label = identity.workspace_label; items.git_branch = identity.git_branch; } if (app.statusline_context) { items.context_used = app.total_input_tokens; items.context_total = model_capabilities.resolveForApp(App, app, visible_model).context_window; } if (comptime @hasField(App, "statusline_session")) { if (app.statusline_session) { items.session_title = app_session_runtime.Runtime(App).cachedSessionTitle(app); } } return items; }
fn pendingPickerFastMode(query: ?picker_state.ModelPickerQuery, fast_index: usize) bool { if (query) |picker_query| { if (picker_query.stage == .fast) { const typed = std.mem.trim(u8, picker_query.query, " \t"); if (std.ascii.eqlIgnoreCase(typed, picker_state.model_picker_fast_options[0])) return false; if (std.ascii.eqlIgnoreCase(typed, picker_state.model_picker_fast_options[1])) return true; } } return fast_index % picker_state.model_picker_fast_options.len == 1; }
pub fn flushRequestedFrame(app: *App) !void { if (app.shell.terminal_dimensions_invalid or app.shell.layout.rows == 0 or app.shell.layout.cols == 0) return; const has_resize_lifecycle = @hasField(@TypeOf(app.shell), "pending_resize_observation"); if (comptime has_resize_lifecycle) { if (shell_runtime.resizeBlocksFrameCommit(&app.shell)) return; } const render_requests = activeRenderRequests(app); var attempt = (try render_requests.beginAttempt()) orelse return; const snapshot = attempt.snapshot; var reason_buf: [128]u8 = undefined; const reason_names = renderReasonNames(snapshot.reasons, &reason_buf); debug_trace.logf( "frame_schedule", "attempt_begin reasons={s} reason_count={d} invalidations={d} resize_blocked={s} animation_phase={d} animation_generation={d} animation_deadline_ms={d}", .{ reason_names, snapshot.reasons.count(), snapshot.invalidations.len, if (render_requests.blocksFrameCommit()) "true" else "false", render_requests.visibleAnimationPhase(), if (snapshot.animation_candidate) |candidate| candidate.generation else 0, render_requests.animation_next_deadline_ms, }, ); errdefer |err| { if (comptime @hasField(App, "terminal")) { _ = app_lifecycle.closeFullTranscriptIfActive( app.alloc, &app.terminal, &app.shell, &app.metrics, ) catch {}; } debug_trace.logf( "frame_schedule", "attempt_restore outcome=error err={s} reasons={s} reason_count={d} invalidations={d} pending_reason_count={d} animation_phase={d} animation_deadline_ms={d}", .{ @errorName(err), reason_names, snapshot.reasons.count(), snapshot.invalidations.len, render_requests.pendingReasonCount(), render_requests.visibleAnimationPhase(), render_requests.animation_next_deadline_ms, }, ); } defer attempt.deinit();
const resize_commit = if (comptime has_resize_lifecycle) shell_runtime.pendingResizeFrameCommit( &app.shell, snapshot.reasons.contains(.resize), ) else shell_runtime.ResizeFrameCommit.none; const result = (try attemptRequestedFrame(app, snapshot)) orelse { attempt.restore(); render_requests.noteInputPendingAbort(); debug_trace.logf( "frame_schedule", "attempt_restore outcome=input_pending reasons={s} reason_count={d} invalidations={d} consecutive_aborts={d}", .{ reason_names, snapshot.reasons.count(), snapshot.invalidations.len, render_requests.consecutive_input_pending_aborts, }, ); return; };
if (!result.is_committed()) { input_completion_runtime.CompletionRuntime(App).distrustFilePicker(app); render_requests.resetInputPendingAbortStreak(); attempt.restore(); debug_trace.logf( "frame_schedule", "attempt_restore outcome={s} reasons={s} reason_count={d} invalidations={d} pending_reason_count={d} animation_phase={d} animation_deadline_ms={d}", .{ @tagName(result.shadow_state), reason_names, snapshot.reasons.count(), snapshot.invalidations.len, render_requests.pendingReasonCount(), render_requests.visibleAnimationPhase(), render_requests.animation_next_deadline_ms, }, ); return; }
if (result.file_picker_receipt) |receipt| { input_completion_runtime.CompletionRuntime(App).acknowledgeFilePicker(app, receipt); } else { input_completion_runtime.CompletionRuntime(App).distrustFilePicker(app); } const committed_at_ms = io_mod.milliTimestamp(); attempt.commit( committed_at_ms, render_request.animation_interval_ms, result.animation_visible, ); if (comptime @hasDecl(App, "startPromptCredentialPrewarm")) { if (snapshot.reasons.contains(.first_frame)) { App.startPromptCredentialPrewarm(app); } } if (comptime @hasDecl(App, "notePendingFrameCommitted")) { if (result.pending_prompt_presented) { App.notePendingFrameCommitted(app); } } if (comptime @hasField(App, "permission_state") and @hasField(App, "permission_engine")) { app_permission_runtime.Runtime(App).noteFrameCommitted( app, app_permission_runtime.monotonicMillis(), result.yolo_warning_visible, ); } if (comptime has_resize_lifecycle) { shell_runtime.acknowledgeResizeFrameCommit(&app.shell, resize_commit); } if (comptime @hasDecl(App, "flushNotifications")) { if (snapshot.reasons.contains(.notification)) { app.flushNotifications(); } } if (comptime @hasField(@TypeOf(app.shell), "resize_history_row_delta")) { if (snapshot.reasons.contains(.resize) and !app.shell.render_requests.hasReason(.resize)) { app.shell.resize_history_row_delta = null; } } debug_trace.logf( "frame_schedule", "attempt_end outcome=committed reasons={s} reason_count={d} invalidations={d} pending_reason_count={d} animation_phase={d} animation_deadline_ms={d}", .{ reason_names, snapshot.reasons.count(), snapshot.invalidations.len, render_requests.pendingReasonCount(), render_requests.visibleAnimationPhase(), render_requests.animation_next_deadline_ms, }, ); }
fn attemptRequestedFrame( app: *App, snapshot: render_request.AttemptSnapshot, ) !?FrameAttemptResult { const result = (if (comptime @hasDecl(App, "renderFrameAttemptForTest")) App.renderFrameAttemptForTest(app, snapshot) else renderFrameAttempt(app, snapshot)) catch |err| { if (err == error.InputPending) return null; return err; }; return result; }
fn transcriptInputPending(context: *anyopaque) bool { const app: *App = @ptrCast(@alignCast(context)); if (app.terminal_input_runtime.hasPendingTerminalInput()) return true; const state = app.terminal.pollInput(0) catch |err| { debug_trace.logf( "frame_schedule", "input_poll_failed err={s}", .{@errorName(err)}, ); return true; }; return state.readable or state.closed(); }
fn transcriptBuildCheckpoint(app: *App) ?build_checkpoint.BuildCheckpoint { if (comptime !@hasField(App, "terminal")) return null; if (comptime @hasField(App, "shell")) { const render_requests = activeRenderRequests(app); if (!render_requests.permitsInputPendingAbort()) { debug_trace.logf( "frame_schedule", "input_cancellation_suppressed consecutive_aborts={d} bound={d}", .{ render_requests.consecutive_input_pending_aborts, render_request.max_consecutive_input_pending_aborts, }, ); return null; } } return .init(app, transcriptInputPending); }
fn reconcileBeforeFrameRender(app: *App, queued_rows: usize) !RenderReconciliation { if (comptime !@hasField(App, "terminal")) return .{ .inline_render = .{} };
if (try app_lifecycle.recoverFullTranscriptDriftBeforeRender( app.alloc, &app.terminal, &app.shell, &app.metrics, )) { try requestNormalViewportRecovery(app); }
const question_active = app.question_prompt.isActive(); if (question_active) { if (try app_lifecycle.closeFullTranscriptIfActive( app.alloc, &app.terminal, &app.shell, &app.metrics, )) { try requestNormalViewportRecovery(app); } if (app.terminal.catalogMenuScreenActive()) { try app_lifecycle.leaveCatalogMenuScreen(&app.terminal, &app.shell, &app.metrics); try requestNormalViewportRecovery(app); } }
const approval = app.approval_prompt.projection(); if (approval) |projection| { const approval_screen_active = try approval_screen.needsScreen( app.alloc, projection.request, app.shell.layout, queued_rows, ); if (app.terminal.catalogMenuScreenActive()) { try app_lifecycle.leaveCatalogMenuScreen(&app.terminal, &app.shell, &app.metrics); if (!approval_screen_active) try requestNormalViewportRecovery(app); } switch (try app_lifecycle.transitionFullTranscriptForApproval( app.alloc, &app.terminal, &app.shell, &app.metrics, approval_screen_active, )) { .inactive, .handed_off => {}, .closed => { try requestNormalViewportRecovery(app); }, } if (approval_screen_active) return .file_approval_screen; }
const terminal_transition = app_lifecycle.approvalInlineRestoreTransition( &app.terminal, ); switch (terminal_transition) { .none => {}, .restore_normal_screen => { if (!question_active and approval == null and (settingsMenuActive(app) or helpMenuActive(app) or skillsMenuActive(app) or modelMenuActive(app) or sessionMenuActive(app))) { app.shell.render_requests.request(.footer); } return .{ .inline_render = .{ .terminal_transition = terminal_transition, } }; }, }
if (!question_active and approval == null and (settingsMenuActive(app) or helpMenuActive(app) or skillsMenuActive(app) or modelMenuActive(app) or sessionMenuActive(app))) { if (try app_lifecycle.closeFullTranscriptIfActive( app.alloc, &app.terminal, &app.shell, &app.metrics, )) { try requestNormalViewportRecovery(app); } }
if (app.terminal.catalogMenuScreenActive()) { try app_lifecycle.leaveCatalogMenuScreen(&app.terminal, &app.shell, &app.metrics); try requestNormalViewportRecovery(app); }
return .{ .inline_render = .{ .alternate_screen_owns_rendering = app.terminal.alternate_screen_owner != .none, } }; }
fn renderFrameAttempt(app: *App, snapshot: render_request.AttemptSnapshot) !FrameAttemptResult { var checkpoint_storage = transcriptBuildCheckpoint(app); const checkpoint = if (checkpoint_storage) |*value| value else null; // Frame-fresh producer fact for the finality floor: the trailing // assistant entry stays non-final while the stream is open or // the pacer still holds undelivered output. set_transcript_assistant_tail_writable( &app.shell, app.stream.active or app.pacer.hasPending(), ); const presentation_shell: *transcript_runtime.TranscriptRuntime = &app.shell; const render_requests = activeRenderRequests(app); var upgrade_status_buf: [64]u8 = undefined; var steering = try buildSteeringProjection(App, app); defer steering.deinit(app.alloc); const shimmer_pos = if (snapshot.animation_candidate) |candidate| candidate.phase else render_requests.visibleAnimationPhase(); const main_footer_ctx = footerContext( app, &upgrade_status_buf, shimmer_pos, &steering, ); const file_picker_receipt = input_completion_runtime.CompletionRuntime(App).filePickerView(app).receipt; var footer_ctx = main_footer_ctx; const render_reconciliation = switch (try reconcileBeforeFrameRender(app, render_input.steeringBannerRows(footer_ctx, app.shell.layout.cols))) { .inline_render => |inline_render| inline_render, .file_approval_screen => return renderApprovalScreen(app), .frame_result => |result| return result, }; const presentation_commits_transcript = !render_reconciliation.alternate_screen_owns_rendering; const active_committed_layout = if (render_reconciliation.alternate_screen_owns_rendering) app.terminal.alternate_frame_layout else app.shell.committed_frame_layout; var pending_card = if (!render_reconciliation.alternate_screen_owns_rendering) try buildPendingCardProjection(App, app, presentation_shell, checkpoint) else null; const pending_submission_card = pending_card != null; if (pending_card == null and !render_reconciliation.alternate_screen_owns_rendering) { pending_card = try buildPendingSteeringCardProjection(app.alloc, presentation_shell, steering, checkpoint); } defer if (pending_card) |*card| card.deinit(app.alloc);
var attempt_invalidations = snapshot.invalidations; presentation_shell.normalizeFrameInvalidations(&attempt_invalidations); var frame_redraw = snapshot.reasons.count() > 0 or !attempt_invalidations.isEmpty();
const body_rows: usize = presentation_shell.layout.content_bottom;
var prepared_transcript: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (prepared_transcript) |*prepared| prepared.deinit(app.alloc); var owned_transcript_source: ?transcript_runtime.TranscriptPreparationSource = null; defer if (owned_transcript_source) |*source| source.deinit(app.alloc); var transcript_source: ?*transcript_runtime.TranscriptPreparationSource = null; var full_transcript_projection: ?*full_transcript_screen.Projection = null; var full_transcript_capability: ?*session_child_store.SessionChildCapability = if (comptime @hasDecl( App, "fullTranscriptSidecarCapability", )) app.fullTranscriptSidecarCapability() else null; var transcript_transition: ?transcript_runtime.TranscriptTransition = null; defer if (transcript_transition) |*transition| transition.deinit(app.alloc); var footer_measurement: ?surface_frame.SurfaceFooterMeasurement = null; defer if (footer_measurement) |*measurement| measurement.deinit(app.alloc); const extra_input_rows_before_footer_prepare = presentation_shell.extra_input_rows; const footer_reserved_base_rows_before_footer_prepare = presentation_shell.footer_reserved_base_rows; var restore_footer_prepare_state = true; defer { if (restore_footer_prepare_state) { presentation_shell.extra_input_rows = extra_input_rows_before_footer_prepare; presentation_shell.footer_reserved_base_rows = footer_reserved_base_rows_before_footer_prepare; } } const visible_approval = app.approval_prompt.projection(); { footer_ctx.transcript_depth = presentation_shell.transcriptPresentationDepth(); if (presentation_shell.fullTranscriptActive()) { const full_diff_resolver: ?full_transcript_screen.FullDiffResolver = if (comptime @hasDecl(App, "fullTranscriptDiffResolver")) app.fullTranscriptDiffResolver() else null; full_transcript_projection = try presentation_shell.preparedFullTranscriptPageProjectionInterruptible( full_diff_resolver, full_transcript_capability, checkpoint, ); if (presentation_shell.preparedFullTranscriptPageCapability()) |capability| { full_transcript_capability = capability; } } footer_measurement = try surface_frame.measureSurfaceFooter( app.alloc, presentation_shell, visible_approval, footer_ctx, ); const omitted_entry_id: ?u32 = if (!presentation_shell.fullTranscriptActive() and footer_measurement != null) switch (footer_measurement.?.activity_projection) { .tool_slot => |slot| if (slot.active) slot.entry_id else null, .none, .turn_thinking => null, } else null; if (!presentation_shell.fullTranscriptActive()) { if (try presentation_shell.pendingResumeSourceInterruptible( app.alloc, checkpoint, )) |source| { transcript_source = source; } else if (omitted_entry_id) |entry_id| { owned_transcript_source = try presentation_shell.prepareTranscriptSourceForFrameInterruptible( app.alloc, entry_id, null, checkpoint, ); } else { owned_transcript_source = try presentation_shell.cachedTranscriptSourceInterruptible( app.alloc, checkpoint, ); } if (transcript_source == null) { transcript_source = &owned_transcript_source.?; } } } const footer_reservation_changed = if (footer_measurement) |*measurement| measurement.changesFooterReservation(presentation_shell) else false; const replay_displaced_footer_history = if (footer_measurement) |*measurement| measurement.replaysDisplacedTranscriptHistory(presentation_shell) else false;
var footer_frame: surface_frame.SurfaceFooterFrame = undefined; var footer_frame_initialized = false; defer if (footer_frame_initialized) footer_frame.deinit(app.alloc); var solved_layout: ?render_engine.frame_layout.FrameLayout = null; var resolved_transcript_target: ?transcript_runtime.TranscriptRuntime.ResolvedTranscriptTarget = null; var scroll_plan = render_engine.frame_scroll_plan.FrameScrollPlan.none( presentation_shell.layout.rows, presentation_shell.owned_top_row, ); var planned_scroll_next_start_line: usize = 0; { const canonical_transcript_preview = if (transcript_source) |source| source.preview else render_engine.frame_layout.TranscriptFlowPreview{ .natural_visual_rows = @intCast(@min(body_rows, @as(usize, std.math.maxInt(u16)))), .cursor_row = presentation_shell.cursor_row, .cursor_col = presentation_shell.cursor_col, .replaceable_row = presentation_shell.replaceable_row, }; const transcript_preview = previewWithPendingCard( canonical_transcript_preview, pending_card, ); const neutral_footer = if (footer_measurement) |*measurement| measurement.frameLayoutMeasurement() else footerMeasurementFromRows(footer_frame.paint.footer); var frame_activity = if (footer_measurement) |*measurement| frameActivityStateFromMeasurement(presentation_shell, measurement) else activityStateFromPlacement(footer_frame.paint.activity); if (pending_card != null and frame_activity == .thinking) { // The pending tail already includes the transcript cursor's blank row. frame_activity.thinking.gap_above_activity = render_engine.transcript_blocks.blockGapRowsBetween( .user_turn, .assistant_turn, ) -| 1; } const target_activity_projection: activity_runtime.ActivityProjection = if (footer_measurement) |*measurement| measurement.activity_projection else .{ .turn_thinking = .{ .label = footer_frame.label() } }; const prompt_turn_reservation = promptTurnReservation( app, presentation_shell, canonical_transcript_preview, pending_card, if (footer_measurement) |*measurement| measurement else null, frame_activity, ); var fixed_point_ctx = FixedPointTranscriptContext(App){ .app = app, .presentation_shell = presentation_shell, .prepare_transcript = !presentation_shell.fullTranscriptActive(), .source = transcript_source, .prepared_transcript = &prepared_transcript, .resolved_target = &resolved_transcript_target, .footer_reservation_changed = footer_reservation_changed, .replay_displaced_footer_history = replay_displaced_footer_history, .footer_measurement = if (footer_measurement) |*measurement| measurement else null, .fallback_footer_rows = if (footer_measurement == null) footer_frame.paint.footer else null, .activity_projection = target_activity_projection, .frame_activity = frame_activity, .base_invalidation = if (footer_measurement != null) render_engine.paint_plan.FrameInvalidationSet.empty() else footer_frame.paint.invalidation, .attempt_invalidations = attempt_invalidations, .pending_tail_rows = if (pending_card) |card| card.row_count else 0, }; const fixed_point = try render_engine.frame_fixed_point.solve( FixedPointTranscriptContext(App), &fixed_point_ctx, .{ .terminal = presentation_shell.layout, .owned_top = presentation_shell.owned_top_row, .footer = neutral_footer, .transcript = transcript_preview, .activity = frame_activity, .prompt_turn = prompt_turn_reservation, .body_mode = .transcript, .prior = active_committed_layout, }, FixedPointTranscriptContext(App).prepareCandidate, FixedPointTranscriptContext(App).resolveCandidate, ); const solved = fixed_point.layout; solved_layout = solved; scroll_plan = fixed_point.scroll_plan; debug_trace.logf( "frame_layout", "layout_id={x} solved_frame_height={d} footer_height={d} footer_top={d} owned_top={d} owned_bottom={d} prompt_turn_transcript_rows={d} prompt_turn_active={s} scroll_rows={d}", .{ solved.layout_id, solved.solved_frame_height, solved.footer_area.height(), solved.footer_area.top, solved.owned_top, solved.owned_band.bottom, prompt_turn_reservation.transcript_rows, if (prompt_turn_reservation.active()) "true" else "false", scroll_plan.terminal_scroll_rows, }, ); const solved_footer_rows = if (footer_measurement) |*measurement| measurement.frameLayoutRows(presentation_shell.layout.rows, solved.footer_area.top) else footer_frame.paint.footer; const solved_viewport = if (resolved_transcript_target) |target| target.selection() else if (prepared_transcript) |*prepared| prepared.selection else if (footer_measurement != null) surface_frame.currentSurfaceFooterTranscriptState(presentation_shell).selection else footer_frame.paint.viewport; const solved_projection = if (footer_measurement) |*measurement| measurement.activity_projection else .none; const solved_activity = if (footer_measurement != null) render_engine.activity_placement.resolve( solved_projection, frame_activity, solved, ) else render_engine.activity_placement.resolve( .{ .turn_thinking = .{ .label = footer_frame.label() } }, frame_activity, solved, ); const solved_cursor_visible = if (footer_measurement) |*measurement| measurement.input_visible else switch (solved_activity) { .transient_row => false, .none, .overlay_entry => true, }; const solved_cursor_target = if (resolved_transcript_target) |target| render_engine.paint_plan.FrameCursorTarget{ .row = target.cursorRow(), .col = target.cursorCol(), .visible = solved_cursor_visible, } else if (prepared_transcript) |*prepared| render_engine.paint_plan.FrameCursorTarget{ .row = prepared.cursor.cursor_row, .col = prepared.cursor.cursor_col, .visible = solved_cursor_visible, } else if (footer_measurement != null) render_engine.paint_plan.FrameCursorTarget{ .row = solved_footer_rows.input_base, .col = 1, .visible = solved_cursor_visible, } else footer_frame.paint.cursor_target; const solved_plan = solved.toPaintPlan(.{ .footer_rows = solved_footer_rows, .viewport = solved_viewport, .activity = solved_activity, .invalidation = if (footer_measurement != null) render_engine.paint_plan.FrameInvalidationSet.empty() else footer_frame.paint.invalidation, .synchronized_update = app.shell.sync_updates_enabled, .cursor_target = solved_cursor_target, .preserve_scrollback = if (footer_measurement != null) !presentation_shell.pending_scroll_compact else footer_frame.paint.preserve_scrollback, .reset_terminal = shouldResetPhysicalTerminal( render_reconciliation.alternate_screen_owns_rendering, app.shell.terminal_reset_pending, ), }); if (footer_measurement) |*measurement| { footer_frame = try surface_frame.prepareMeasuredSurfaceFooterFrameForPlan( app.alloc, presentation_shell, &frame_redraw, visible_approval, footer_ctx, measurement, solved_plan, attempt_invalidations, ); footer_frame_initialized = true; } else { surface_frame.retargetSurfaceFooterFrame(&footer_frame, solved_plan); } if (!framePlanBandsEqual(footer_frame.paint, solved_plan)) { debug_trace.logf( "frame_layout", "migration_mismatch old_transcript={d}..{d} old_activity={d}..{d} old_footer={d}..{d} solved_transcript={d}..{d} solved_activity={d}..{d} solved_footer={d}..{d}", .{ footer_frame.paint.transcript_band.top, footer_frame.paint.transcript_band.bottom, footer_frame.paint.activity_band.top, footer_frame.paint.activity_band.bottom, footer_frame.paint.footer_band.top, footer_frame.paint.footer_band.bottom, solved_plan.transcript_band.top, solved_plan.transcript_band.bottom, solved_plan.activity_band.top, solved_plan.activity_band.bottom, solved_plan.footer_band.top, solved_plan.footer_band.bottom, }, ); } try footer_frame.paint.validate(); if (prepared_transcript) |*prepared| { try validatePreparedTranscriptFitsPlan(prepared, footer_frame.paint); planned_scroll_next_start_line = if (resolved_transcript_target) |target| target.selection().start_line else prepared.selection.start_line; } if (full_transcript_projection) |projection| { const area = footer_frame.paint.transcript_band; if (!area.isEmpty()) { const staged = try presentation_shell.prepareFullTranscriptSurfacePaintInterruptible( app.alloc, &app.metrics, projection, full_transcript_capability, .{ .top = area.top, .bottom = area.bottom }, checkpoint, ); if (staged.owned_source) |source| { owned_transcript_source = source; transcript_source = &owned_transcript_source.?; } else { transcript_source = staged.borrowed_source.?; } prepared_transcript = staged.prepared; footer_frame.paint.viewport = prepared_transcript.?.selection; try validatePreparedTranscriptFitsPlan(&prepared_transcript.?, footer_frame.paint); } } } if (presentation_commits_transcript) { if (transcript_source) |source| { if (prepared_transcript) |*prepared| { if (presentation_shell.fullTranscriptActive()) { return error.InvalidFullTranscriptRoute; } else { const target = resolved_transcript_target orelse return error.MissingResolvedTranscriptTarget; transcript_transition = try presentation_shell.sealTranscriptTransition( app.alloc, source, prepared, &footer_frame.paint, target, ); } } } } const committed_layout = solved_layout orelse return error.MissingSolvedFrameLayout; const commit_diagnostic = presentation_shell.transcriptCommitDiagnostic(); debug_trace.logf( "scroll", "frame_builder_scroll terminal_scroll_rows={d} source_state={s} previous_committed_start_line={d} next_start_line={d}", .{ scroll_plan.terminal_scroll_rows, @tagName(commit_diagnostic.state), commit_diagnostic.stable_start_line orelse 0, planned_scroll_next_start_line, }, );
const observation_activity: activity_runtime.ActivityProjection = if (footer_measurement) |*measurement| measurement.activity_projection else .{ .turn_thinking = .{ .label = footer_frame.label() } }; var frame_ctx = FramePaintContext(App){ .app = app, .presentation_shell = presentation_shell, .body = .transcript, .prepared_transcript = if (prepared_transcript) |*prepared| prepared else null, .footer_frame = &footer_frame, .activity_style = switch (observation_activity) { .tool_slot => |slot| if (slot.thinking_label != null) .thinking else .tool_marker, .turn_thinking => |thinking| switch (thinking.tone) { .thinking => .thinking, .neutral => .neutral, .warning => .warning, .success => .success, .danger => .danger, }, .none => .thinking, }, .activity_result = .{ .painted = false, .row = 0, .overlay = false }, }; const document_append = if (transcript_transition) |*transition| transition.document_append else render_engine.frame_scroll_plan.FrameDocumentAppend{}; var transcript_body: render_engine.frame_builder.TranscriptBodyDisposition = if (transcript_transition) |*transition| switch (transition.body_disposition) { .paint => .paint, .retain_committed => |retained| .{ .retain = retained }, } else .paint; const pending_preview_deferred = pending_submission_card and if (prepared_transcript) |prepared| pending_card.?.overlaps_flow_endpoint(prepared.cursor.cursor_col) else false; var pending_paint_ctx = if (pending_preview_deferred) null else if (pending_card) |card| PendingCardPaintContext.init( card, footer_frame.paint.transcript_band, if (prepared_transcript) |*prepared| prepared.cursor.cursor_row else null, !footer_frame.paint.activity_band.isEmpty(), ) else null; if (pending_paint_ctx) |paint_ctx| switch (transcript_body) { .paint => {}, .retain => |retained_source| { const first_changed_row = paint_ctx.row; if (first_changed_row <= retained_source.source_area.top) { transcript_body = .paint; } else if (first_changed_row <= retained_source.source_area.bottom) { var narrowed = retained_source; narrowed.source_area.bottom = first_changed_row - 1; narrowed.occupied_last_row = @min( narrowed.occupied_last_row, narrowed.source_area.bottom, ); transcript_body = .{ .retain = narrowed }; } }, }; if (pending_paint_ctx) |paint_ctx| { debug_trace.logf( "frame_plan", "pending_prompt_tail start={d} paint_rows={d} layout_rows={d} bytes={d} transcript={d}..{d} body={s}", .{ paint_ctx.row, paint_ctx.max_rows, pending_card.?.row_count, paint_ctx.bytes.len, footer_frame.paint.transcript_band.top, footer_frame.paint.transcript_band.bottom, @tagName(transcript_body), }, ); } const observation_rows = if (transcript_transition) |*transition| switch (transition.body_disposition) { .paint => transition.row_provenance, .retain_committed => presentation_shell.committedRowProvenance(), } else presentation_shell.committedRowProvenance(); var counters: render_engine.frame_builder.TraceCounters = .{}; try build_checkpoint.poll(checkpoint); if (footer_frame.paint.reset_terminal) { if (comptime @hasField(App, "terminal")) { if (app.terminal.alternate_screen_owner == .none) { app.terminal.clearTmuxScreenAndHistory(app.alloc); } } } var frame_shell = SurfaceFrameShell.init( &app.shell, presentation_shell, active_committed_layout, ); const result = try render_engine.frame_builder.buildAndFlushFrame( app.alloc, &frame_shell, &app.metrics, .{ .plan = footer_frame.paint, .committed_layout = active_committed_layout, .body = frame_ctx.body, .transcript_body = transcript_body, .scroll_plan = scroll_plan, .document_append = document_append, .terminal_transition = render_reconciliation.terminal_transition, .body_painter = .{ .ctx = &frame_ctx, .paint = FramePaintContext(App).paintBody }, .transcript_tail_painter = if (pending_paint_ctx) |*paint_ctx| .{ .ctx = paint_ctx, .paint = PendingCardPaintContext.paint, } else null, .footer_painter = .{ .ctx = &frame_ctx, .paint = FramePaintContext(App).paintFooter }, .activity_painter = .{ .ctx = &frame_ctx, .paint = FramePaintContext(App).paintActivity }, .trace_counters = &counters, .observation = .{ .observer = &presentation_shell.ui_observer, .row_provenance = observation_rows, .activity = observation_activity, .stream_active = footer_ctx.stream.active, .completed_assistant_presentation_tail = footer_ctx.completed_assistant_presentation_tail, }, }, ); const scroll_commit = result.scrollCommit(scroll_plan); debug_trace.logf( "frame_diff", "attempt_result transcript_body={s} body_paints={d} retained_changed_cells={d} document_append_bytes={d} planned_scroll_rows={d} committed_scroll_rows={d} accepted_scroll_rows={d} unplanned_scroll_rows={d} changed_cells={d} shadow_state={s}", .{ @tagName(transcript_body), counters.body_paints, counters.retained_transcript_changed_cells, document_append.bytes.len, scroll_commit.planned_terminal_scroll_rows, scroll_commit.physical_terminal_scroll_rows, scroll_commit.accepted_terminal_scroll_rows, scroll_commit.unplanned_terminal_scroll_rows, result.changed_cells, @tagName(result.state()), }, );
if (presentation_commits_transcript) { const transition_ptr: ?*transcript_runtime.TranscriptTransition = if (transcript_transition) |*transition| transition else null; presentation_shell.consumeFrameScrollCommit( app.alloc, scroll_plan, result, transition_ptr, ); } if (result.is_committed() and render_reconciliation.alternate_screen_owns_rendering) { app.terminal.alternate_frame_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(committed_layout); } if (result.is_committed()) { switch (render_reconciliation.terminal_transition) { .none => {}, .restore_normal_screen => app_lifecycle.commitApprovalInlineRestore( &app.terminal, ), } } if (result.is_committed() and presentation_commits_transcript) { restore_footer_prepare_state = false; presentation_shell.has_committed_frame = true; presentation_shell.terminal_reset_pending = false; if (footer_frame.paint.reset_terminal) { app.shell.terminal_reset_pending = false; } if (transcript_transition == null) { presentation_shell.committed_frame_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(committed_layout); presentation_shell.invalidateTranscriptAnchor("empty_transcript_commit"); } surface_frame.commitSurfaceFooterFrame( app.alloc, presentation_shell, &footer_frame, if (footer_measurement) |*measurement| measurement else null, ); presentation_shell.shimmer_active = frame_ctx.activity_result.painted; presentation_shell.shimmer_is_overlay = frame_ctx.activity_result.overlay; if (scroll_plan.remaining_inline_advance_rows > 0) { presentation_shell.markTranscriptDirty(); } else if (!render_requests.hasReason(.transcript)) { presentation_shell.transcript_band_dirty = false; } if (!render_requests.hasReason(.external_damage)) { presentation_shell.footer_viewport.clearExternalInvalidation(); } } return .{ .shadow_state = result.state(), .animation_visible = frame_ctx.activity_result.painted, .yolo_warning_visible = !render_reconciliation.alternate_screen_owns_rendering and footer_frame.composed.danger_status_visible, // The committed pending UI permits adoption even when its preview // would overwrite the flow endpoint. Adoption writes the real card. .pending_prompt_presented = pending_submission_card and (pending_paint_ctx != null or pending_preview_deferred), .file_picker_receipt = if (result.is_committed() and presentation_commits_transcript and footer_measurement != null and footer_measurement.?.show_picker and footer_measurement.?.picker_kind == .file and footer_measurement.?.picker_rows > 0) file_picker_receipt else null, }; }
fn renderApprovalScreen(app: *App) !FrameAttemptResult { const approval = app.approval_prompt.projection() orelse return error.MissingApprovalRequest; const request = approval.request; const clear_display = approvalScreenNeedsClear( app.terminal.fileApprovalScreenActive(), request, app.shell.layout, app.approval_screen.screen_commit, ); app.approval_screen.invalidateScreenCommit(); app_lifecycle.enterApprovalScreen( &app.terminal, &app.shell, &app.metrics, ) catch |err| return failApprovalScreen(app, request.id, err); if (app.shell.shadow_vt) |grid| { if (grid.cols != app.shell.layout.cols or grid.rows != app.shell.layout.rows) { grid.resize( app.shell.layout.cols, app.shell.layout.rows, ) catch |err| return failApprovalScreen(app, request.id, err); } }
var transcript_source: ?transcript_runtime.TranscriptPreparationSource = null; defer if (transcript_source) |*source| source.deinit(app.alloc); const transcript_document: approval_screen.TranscriptDocument = switch (approval_screen.transcriptDocumentPlan( approval, &app.approval_screen, app.shell.entries.items, app.shell.layout, ) catch |err| return failApprovalScreen(app, request.id, err)) { .none => .none, .progressive => |present| .{ .progressive = present }, .projected => blk: { transcript_source = app.shell.cachedTranscriptSource(app.alloc) catch |err| return failApprovalScreen(app, request.id, err); break :blk .{ .projected = transcript_source.?.bytes }; }, };
var screen = approval_screen.paint( app.alloc, approval, &app.approval_screen, transcript_document, app.shell.layout, clear_display, ) catch |err| return failApprovalScreen(app, request.id, err); defer screen.deinit(app.alloc);
app_lifecycle.setApprovalScreenMouseTracking( &app.terminal, &app.shell, &app.metrics, request.file != null or screen.document_scrollable, ) catch |err| return failApprovalScreen(app, request.id, err);
app_lifecycle.writeLifecycleTerminalBytes( &app.shell, &app.metrics, screen.bytes, ) catch |err| return failApprovalScreen(app, request.id, err);
app.approval_screen.recordScreenCommit(request.id, .{ .request_id = request.id, .rows = app.shell.layout.rows, .cols = app.shell.layout.cols, .file_identity_visible = screen.file_identity_visible, .all_decision_controls_visible = screen.all_decision_controls_visible, .changed_or_notice_visible = screen.changed_or_notice_visible, .document_scrollable = screen.document_scrollable, }); app.shell.ui_observer.observeAlternateScreen(app.alloc, .{ .request_id = request.id, .rows = app.shell.layout.rows, .cols = app.shell.layout.cols, .file_identity_visible = screen.file_identity_visible, .all_decision_controls_visible = screen.all_decision_controls_visible, .changed_or_notice_visible = screen.changed_or_notice_visible, .document_scrollable = screen.document_scrollable, }); if (screen.needs_full_file_projection) { app.shell.render_requests.request(.modal); } return .{ .shadow_state = .committed, .animation_visible = false, }; }
fn failApprovalScreen( app: *App, request_id: u64, err: anyerror, ) !FrameAttemptResult { debug_trace.logf( "permission", "approval_screen_failed request_id={d} err={s}", .{ request_id, @errorName(err) }, ); _ = app_lifecycle.leaveApprovalScreen( &app.terminal, &app.shell, &app.metrics, ) catch |leave_err| { debug_trace.logf( "permission", "approval_screen_leave_failed reason=screen_failure err={s}", .{@errorName(leave_err)}, ); }; switch (app.worker.submitPermissionResponse( request_id, permission_request.OwnedPermissionResponse.init(app.alloc, .deny, null), )) { .accepted => { app.approval_prompt.clearWithReason(app.alloc, "screen_failure"); app.approval_screen.clear(); }, .stale, .no_pending => {}, } app.shell.render_requests.request(.modal); return .{ .shadow_state = .committed, .animation_visible = false, }; }
pub noinline fn requestNormalViewportRecovery(app: *App) !void { if (comptime @hasField(App, "terminal")) { if (app.terminal.alternate_screen_owner != .none) return; try shell_runtime.requestRedraw(&app.shell, &app.metrics, .replay_viewport); } }
fn skillsMenuActive(app: *const App) bool { if (comptime @hasField(App, "skills")) return app.skills.menuVisible(); return false; }
fn modelMenuActive(app: *const App) bool { if (comptime @hasField(App, "model_cache")) return app.model_cache.menu.active; return false; }
fn sessionMenuActive(app: *const App) bool { if (comptime @hasField(App, "session_persistence")) return app.session_persistence.session_picker.active; return false; }
fn helpMenuActive(app: *const App) bool { if (comptime @hasField(App, "input_runtime")) return app.input_runtime.help_menu.active; return false; }
fn settingsMenuActive(app: *const App) bool { if (comptime @hasField(App, "input_runtime")) return app.input_runtime.settings_menu.active; return false; }
fn catalogMenuActive(app: *const App) bool { return modelMenuActive(app) and !settingsMenuActive(app); }
fn activityProjection(app: *const App) activity_runtime.ActivityProjection { return shell_runtime.activityProjection(&app.shell); }
fn activeRenderRequests(app: *App) *render_request.RenderRequestState { return &app.shell.render_requests; }
pub fn requestActiveSurfaceFrame( app: *App, reason: render_request.Reason, ) void { activeRenderRequests(app).request(reason); }
pub fn eventLoopCallbacks(app: *App) event_loop.EventLoopCallbacks { return .{ .ctx = @ptrCast(app), .collect_facts = App.loopCollectFacts, .next_collected_byte = App.loopNextCollectedByte, .handle_byte = App.loopHandleByte, .settle_delivery_epoch = App.loopSettleInputDeliveryEpoch, .commit_frame = App.loopCommitFrame, .poll_timeout_ms = if (comptime @hasDecl(App, "loopPollTimeoutMs")) App.loopPollTimeoutMs else null, }; } };}
fn renderReasonNames( reasons: render_request.ReasonSet, buf: *[128]u8,) []const u8 { var len: usize = 0; for (std.meta.tags(render_request.Reason)) |reason| { if (!reasons.contains(reason)) continue; if (len > 0) { if (len == buf.len) break; buf[len] = ','; len += 1; } const name = @tagName(reason); const copy_len = @min(name.len, buf.len - len); @memcpy(buf[len..][0..copy_len], name[0..copy_len]); len += copy_len; if (copy_len < name.len) break; } if (len == 0) return "none"; return buf[0..len];}
fn FixedPointTranscriptContext(comptime App: type) type { return struct { app: *App, presentation_shell: *transcript_runtime.TranscriptRuntime, prepare_transcript: bool, source: ?*const transcript_runtime.TranscriptPreparationSource, prepared_transcript: *?transcript_painter.PreparedTranscriptSurfacePaint, resolved_target: *?transcript_runtime.TranscriptRuntime.ResolvedTranscriptTarget, footer_reservation_changed: bool, replay_displaced_footer_history: bool, footer_measurement: ?*const surface_frame.SurfaceFooterMeasurement, fallback_footer_rows: ?render_engine.footer_layout.FooterRows, activity_projection: activity_runtime.ActivityProjection, frame_activity: render_engine.frame_layout.ActivityState, base_invalidation: render_engine.paint_plan.FrameInvalidationSet, attempt_invalidations: render_engine.paint_plan.FrameInvalidationSet, pending_tail_rows: u16 = 0, scroll_facts: ?transcript_runtime.TranscriptScrollFacts = null,
fn prepareCandidate( self: *@This(), candidate: render_engine.frame_layout.FrameLayout, ) !render_engine.frame_fixed_point.CandidatePreparation { if (self.prepared_transcript.*) |*prepared| { prepared.deinit(self.app.alloc); self.prepared_transcript.* = null; } self.resolved_target.* = null; self.scroll_facts = null; if (!self.prepare_transcript or candidate.transcript_area.isEmpty()) return .{ .inline_advance_rows = 0, .occupied_transcript_rows = candidate.transcript_area.height(), }; const source = self.source orelse return error.MissingTranscriptPreparationSource; const canonical_area = transcriptAreaBeforePendingTail( candidate.transcript_area, self.pending_tail_rows, ); if (canonical_area.isEmpty()) return .{ .inline_advance_rows = 0, .occupied_transcript_rows = @min( self.pending_tail_rows, candidate.transcript_area.height(), ), };
self.prepared_transcript.* = try self.presentation_shell.prepareTranscriptSurfacePaintFromSourceForFrame( self.app.alloc, &self.app.metrics, source, canonical_area, self.footer_reservation_changed, ); const prepared = &self.prepared_transcript.*.?; const scroll_facts = try self.presentation_shell.prepareTranscriptScrollFactsForFrame( self.app.alloc, source, prepared, self.footer_reservation_changed, self.replay_displaced_footer_history, ); self.scroll_facts = scroll_facts; const canonical_occupied_rows = if (prepared.selection.last_visible_row >= canonical_area.top) prepared.selection.last_visible_row - canonical_area.top + 1 else 0; return .{ .inline_advance_rows = scroll_facts.planned_rows, .occupied_transcript_rows = @min( canonical_occupied_rows +| self.pending_tail_rows, candidate.transcript_area.height(), ), }; }
fn resolveCandidate( self: *@This(), candidate: render_engine.frame_layout.FrameLayout, scroll_plan: render_engine.frame_scroll_plan.FrameScrollPlan, ) !render_engine.frame_fixed_point.CandidateResolution { const candidate_rows = candidate.transcript_area.height(); if (!self.prepare_transcript or candidate.transcript_area.isEmpty()) { return .{ .occupied_transcript_rows = candidate_rows }; } if (transcriptAreaBeforePendingTail( candidate.transcript_area, self.pending_tail_rows, ).isEmpty()) { return .{ .occupied_transcript_rows = @min( self.pending_tail_rows, candidate_rows, ) }; } const source = self.source orelse return error.MissingTranscriptPreparationSource; const prepared = if (self.prepared_transcript.*) |*value| value else return error.MissingTranscriptPaint; const scroll_facts = self.scroll_facts orelse return error.MissingTranscriptScrollFacts; const footer_rows = if (self.footer_measurement) |measurement| measurement.frameLayoutRows( self.presentation_shell.layout.rows, candidate.footer_area.top, ) else self.fallback_footer_rows orelse return error.MissingFooterRows; const activity = render_engine.activity_placement.resolve( self.activity_projection, self.frame_activity, candidate, ); var candidate_plan = candidate.toPaintPlan(.{ .footer_rows = footer_rows, .viewport = prepared.selection, .activity = activity, .invalidation = self.base_invalidation, .cursor_target = .{ .row = prepared.cursor.cursor_row, .col = prepared.cursor.cursor_col, .visible = true, }, }); candidate_plan.invalidation = try surface_invalidation.resolveCandidateFrameInvalidations( self.presentation_shell, candidate_plan, if (self.footer_measurement) |measurement| measurement.frameInvalidationUpdate() else null, self.attempt_invalidations, ); const destructive_invalidation = render_engine.frame_retention.transcriptAreaHasDestructiveInvalidation( self.presentation_shell.committed_frame_layout.transcript_area, candidate_plan.invalidation, ); const target = try self.presentation_shell.resolveTranscriptTransitionTargetForFrameInArea( self.app.alloc, source, prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(candidate), transcriptAreaBeforePendingTail( candidate.transcript_area, self.pending_tail_rows, ), scroll_plan, scroll_facts, destructive_invalidation, activity == .overlay_entry, ); self.resolved_target.* = target; return .{ .occupied_transcript_rows = @min( target.occupiedTranscriptRows() +| self.pending_tail_rows, candidate.transcript_area.height(), ) }; } };}
fn transcriptAreaBeforePendingTail( area: render_engine.frame_layout.FrameRect, tail_rows: u16,) render_engine.frame_layout.FrameRect { if (area.isEmpty() or tail_rows == 0) return area; if (tail_rows >= area.height()) return .empty(); return .{ .top = area.top, .bottom = area.bottom - tail_rows };}
fn FramePaintContext(comptime App: type) type { return struct { app: *App, presentation_shell: *transcript_runtime.TranscriptRuntime, body: render_engine.frame_builder.FrameBody, prepared_transcript: ?*const transcript_painter.PreparedTranscriptSurfacePaint, footer_frame: *const surface_frame.SurfaceFooterFrame, activity_style: shimmer_runtime.ActivityPaintStyle, activity_result: render_engine.paint_plan.ActivityPaintResult,
fn paintBody(ctx: *anyopaque, surface: *render_engine.frame_surface.FrameSurface) anyerror!void { const self: *@This() = @ptrCast(@alignCast(ctx)); switch (self.body) { .transcript => { if (surface.plan.transcript_band.isEmpty()) return; if (self.prepared_transcript) |prepared| { _ = try self.presentation_shell.paintPreparedTranscriptIntoSurface(self.app.alloc, surface, prepared); } }, .subagent_panel => |text| { if (surface.plan.transcript_band.isEmpty() or text.len == 0) return; const rows = surface.plan.transcript_band.bottom - surface.plan.transcript_band.top + 1; _ = try surface.writeAnsiBand(surface.plan.transcript_band.top, rows, text, .transcript, .same_owner); }, .none => {}, } }
fn paintFooter(ctx: *anyopaque, surface: *render_engine.frame_surface.FrameSurface) anyerror!void { const self: *@This() = @ptrCast(@alignCast(ctx)); _ = try footer_viewport.paintFooterIntoSurface(surface, &self.footer_frame.composed); }
fn paintActivity(ctx: *anyopaque, surface: *render_engine.frame_surface.FrameSurface) anyerror!void { const self: *@This() = @ptrCast(@alignCast(ctx)); self.activity_result = try shimmer_runtime.paintActivityIntoSurface(surface, .{ .label = self.footer_frame.label(), .tool_label = self.footer_frame.toolLabel(), .shimmer_pos = self.footer_frame.shimmer_pos, .style = self.activity_style, .thinking_blink = self.footer_frame.thinking_blink, }); } };}
fn validatePreparedTranscriptFitsPlan( prepared: *const transcript_painter.PreparedTranscriptSurfacePaint, plan: render_engine.paint_plan.PaintPlan,) !void { const selection = prepared.selection; const has_prepared_rows = prepared.total_lines > 0 or selection.last_visible_row > 0; if (!has_prepared_rows) return;
if (plan.transcript_band.isEmpty() or selection.top_row < plan.transcript_band.top or selection.bottom_row > plan.transcript_band.bottom or selection.last_visible_row > plan.transcript_band.bottom) { debug_trace.logf( "frame_plan", "prepared_transcript_outside_band selection={d}..{d} last_visible={d} transcript_band={d}..{d} total_lines={d}", .{ selection.top_row, selection.bottom_row, selection.last_visible_row, plan.transcript_band.top, plan.transcript_band.bottom, prepared.total_lines, }, ); return error.InvalidPaintPlan; }}
fn promptTurnReservation( app: anytype, shell: *const transcript_runtime.TranscriptRuntime, canonical_preview: render_engine.frame_layout.TranscriptFlowPreview, pending_card: ?PendingCardProjection, footer_measurement: ?*const surface_frame.SurfaceFooterMeasurement, frame_activity: render_engine.frame_layout.ActivityState,) render_engine.frame_layout.PromptTurnReservation { if (frame_activity != .none) return .{}; const measurement = footer_measurement orelse return .{}; if (!measurement.input_visible or measurement.show_picker or measurement.picker_rows > 0 or measurement.banner_active or measurement.footer_gap_active or app.stream.active or shell.fullTranscriptActive()) return .{}; if (comptime @hasField(@TypeOf(app.*), "skills")) { if (comptime @hasDecl(@TypeOf(app.skills), "menuVisible")) { if (app.skills.menuVisible()) return .{}; } }
const future_activity = render_engine.frame_layout.ActivityState.thinkingAfterUserTurn(); const pending_submission_active = if (comptime @hasField(@TypeOf(app.*), "submission")) app.submission.pending != null else false; if (pending_card != null or pending_submission_active) { const canonical_rows = if (pending_card) |card| canonical_preview.natural_visual_rows +| (card.row_count -| 1) else canonical_preview.natural_visual_rows; return .{ .transcript_rows = canonical_rows, .activity = future_activity }; } return .{};}
fn footerMeasurementFromRows(rows: render_engine.footer_layout.FooterRows) render_engine.frame_layout.FooterMeasurement { return .{ .natural_rows = rows.total_rows, .min_rows = 1, .max_rows = rows.total_rows, .input_rows = 1, .picker_rows = if (rows.picker_start <= rows.bottom_divider and rows.bottom_divider > rows.picker_divider) rows.bottom_divider - rows.picker_divider - 1 else 0, .banner_rows = rows.banner_rows, };}
fn activityStateFromPlacement(activity: render_engine.activity_overlay.ActivityPlacement) render_engine.frame_layout.ActivityState { return switch (activity) { .transient_row => |transient| .{ .thinking = .{ .gap_above_activity = transient.gap_above_rows, .activity_rows = transient.row_count, .footer_gap_after_activity = transient.footer_clearance_rows, .tool_before_activity = transient.tool_row != null, } }, .overlay_entry => |row| .{ .overlay_entry = row }, .none => .none, };}
noinline fn frameActivityStateFromMeasurement( shell: *const transcript_runtime.TranscriptRuntime, measurement: *const surface_frame.SurfaceFooterMeasurement,) render_engine.frame_layout.ActivityState { return switch (measurement.activity_projection) { .none => .none, .tool_slot => |slot| if (slot.active) transientActivityState(shell, measurement.activity_projection, slot.thinking_label != null) else .none, .turn_thinking => transientActivityState(shell, measurement.activity_projection, false), };}
fn transientActivityState( shell: *const transcript_runtime.TranscriptRuntime, projection: activity_runtime.ActivityProjection, tool_before_activity: bool,) render_engine.frame_layout.ActivityState { return .{ .thinking = .{ .gap_above_activity = render_input.transientActivityGapRows(shell, tool_before_activity), .activity_rows = render_input.activityProjectionRows(projection, shell.layout.cols), .footer_gap_after_activity = render_engine.transcript_blocks.footerBoundaryGapRowsForTail(.turn_summary), .tool_before_activity = tool_before_activity, } };}
fn framePlanBandsEqual( old: render_engine.paint_plan.PaintPlan, solved: render_engine.paint_plan.PaintPlan,) bool { return frameBandsEqual(old.transcript_band, solved.transcript_band) and frameBandsEqual(old.blank_band, solved.blank_band) and frameBandsEqual(old.activity_band, solved.activity_band) and frameBandsEqual(old.footer_gap_band, solved.footer_gap_band) and frameBandsEqual(old.footer_band, solved.footer_band);}
noinline fn frameBandsEqual( a: render_engine.paint_plan.FrameBand, b: render_engine.paint_plan.FrameBand,) bool { return a.top == b.top and a.bottom == b.bottom and a.owner == b.owner;}
const FixedPointTestContext = struct { inline_advance_rows: u16 = 0, prepared_occupied_rows: ?u16 = null,
fn prepareCandidate( self: *FixedPointTestContext, layout: render_engine.frame_layout.FrameLayout, ) !render_engine.frame_fixed_point.CandidatePreparation { return .{ .inline_advance_rows = self.inline_advance_rows, .occupied_transcript_rows = layout.transcript_area.height(), }; }
fn resolveCandidate( self: *FixedPointTestContext, layout: render_engine.frame_layout.FrameLayout, scroll_plan: render_engine.frame_scroll_plan.FrameScrollPlan, ) !render_engine.frame_fixed_point.CandidateResolution { _ = scroll_plan; return .{ .occupied_transcript_rows = self.prepared_occupied_rows orelse layout.transcript_area.height(), }; }};
fn fixedPointTestInput( terminal_rows: u16, owned_top: u16, transcript_rows: u16, footer_rows: u16, body_mode: render_engine.frame_layout.BodyMode,) render_engine.frame_layout.SolveInput { return .{ .terminal = .{ .rows = terminal_rows, .cols = 80, .content_bottom = terminal_rows -| 4, .divider_top_row = terminal_rows -| 3, .input_row = terminal_rows -| 2, .divider_bottom_row = terminal_rows -| 1, .hint_row = terminal_rows, }, .owned_top = owned_top, .footer = .{ .natural_rows = footer_rows, .min_rows = footer_rows, .max_rows = footer_rows, }, .transcript = .{ .natural_visual_rows = transcript_rows }, .body_mode = body_mode, };}
fn solveFixedPointForTest( ctx: *FixedPointTestContext, input: render_engine.frame_layout.SolveInput,) !render_engine.frame_fixed_point.FramePlan { return render_engine.frame_fixed_point.solve( FixedPointTestContext, ctx, input, FixedPointTestContext.prepareCandidate, FixedPointTestContext.resolveCandidate, );}
test "pending prompt projection waits for a paintable terminal width" { const alloc = std.testing.allocator; const input_submit_runtime = @import("input_submit_runtime.zig"); const TestApp = struct { alloc: std.mem.Allocator, submission: input_submit_runtime.State, }; const prompt = try alloc.dupe(u8, "visible prompt"); var app = TestApp{ .alloc = alloc, .submission = .{ .pending = .{ .draft = .{ .turn_id = 1, .prompt = prompt, .images = &.{}, .skill_display_spans = &.{}, } } }, }; defer app.submission.pending.?.deinit(alloc);
for ([_]u16{ 1, 2 }) |cols| { var shell = transcript_runtime.TranscriptRuntime{ .layout = .{ .rows = 4, .cols = cols, .content_bottom = 1, .divider_top_row = 2, .input_row = 2, .divider_bottom_row = 3, .hint_row = 4, }, .cursor_row = 1, .cursor_col = 1, }; defer shell.deinit(alloc);
try std.testing.expect((try buildPendingCardProjection( TestApp, &app, &shell, null, )) == null); try std.testing.expectEqual( input_submit_runtime.PendingPhase.awaiting_frame, app.submission.pending.?.phase, ); }
var resized_shell = transcript_runtime.TranscriptRuntime{ .layout = .{ .rows = 4, .cols = 80, .content_bottom = 1, .divider_top_row = 2, .input_row = 2, .divider_bottom_row = 3, .hint_row = 4, }, .cursor_row = 1, .cursor_col = 1, }; defer resized_shell.deinit(alloc); var projection = (try buildPendingCardProjection( TestApp, &app, &resized_shell, null, )).?; defer projection.deinit(alloc); try std.testing.expect(projection.paint_row_count > 0);}
test "pending steering cards preserve feedback order and tool waiting placement" { const alloc = std.testing.allocator; var shell = transcript_runtime.TranscriptRuntime{ .layout = .{ .cols = 40, .rows = 12, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .cursor_row = 3, .cursor_col = 1, }; defer shell.deinit(alloc); var feedback = [_][]u8{@constCast("accepted earlier")}; var queued = [_][]u8{@constCast("accepted later")}; var steering = SteeringProjection{ .messages = &queued, .pending_feedback = &feedback }; var card = (try buildPendingSteeringCardProjection(alloc, &shell, steering, null)).?; defer card.deinit(alloc); const first = std.mem.find(u8, card.bytes, "accepted earlier").?; const second = std.mem.find(u8, card.bytes, "accepted later").?; try std.testing.expect(first < second); try std.testing.expectEqual(@as(usize, 2), std.mem.count(u8, card.bytes, "┃")); try std.testing.expect(std.mem.find(u8, card.bytes, "┋") == null);
steering.waits_for_boundary = true; var waiting = (try buildPendingSteeringCardProjection(alloc, &shell, steering, null)).?; defer waiting.deinit(alloc); try std.testing.expect(std.mem.find(u8, waiting.bytes, "accepted earlier") != null); try std.testing.expect(std.mem.find(u8, waiting.bytes, "accepted later") == null); steering.pending_feedback = &.{}; try std.testing.expect((try buildPendingSteeringCardProjection(alloc, &shell, steering, null)) == null);
steering.waits_for_boundary = false; shell.layout.content_bottom = 1; var clipped = (try buildPendingSteeringCardProjection(alloc, &shell, steering, null)).?; defer clipped.deinit(alloc); try std.testing.expectEqual(@as(u16, 1), clipped.paint_row_count); for ([_]u16{ 1, 2 }) |cols| { shell.layout.cols = cols; try std.testing.expect((try buildPendingSteeringCardProjection(alloc, &shell, steering, null)) == null); }}
test "pending prompt at an occupied band bottom preserves the summary through adoption" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "pending-paste.log", .{ .read = true }); defer file.close(std.testing.io); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .cols = 168, .rows = 75, .content_bottom = 71, .divider_top_row = 72, .input_row = 73, .divider_bottom_row = 74, .hint_row = 75 } }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); var physical = try vt_emulator.Grid.init(alloc, 168, 75); defer physical.deinit(); physical.defer_sync_updates = false; var history: std.ArrayList(u8) = .empty; defer history.deinit(alloc); var offset: u64 = 0; _ = try app.shell.appendRawTranscriptEntryClassified(alloc, "previous answer\n" ** 235, .unknown_raw); const summary = " 10m 31s (↑177 ↓21k)"; _ = try app.shell.appendRawTranscriptEntryClassified(alloc, summary, .turn_summary); app.shell.render_requests.request(.first_frame); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const first = try readCoordinatorFrameBytes(alloc, file, &offset); defer alloc.free(first); try feedRewritePublicationFrame(alloc, &physical, &history, first); for (0..3) |_| _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expect(app.shell.cursor_col > 1); try std.testing.expect(app.shell.cursor_row >= app.shell.layout.content_bottom); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, history.items, "↑177")); const initial = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(initial); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, initial, summary));
const last_line = "- evidence gaps that could still change the design."; const prompt = ("PASTE_BODY\n" ** 383) ++ last_line; app.submission.pending = .{ .draft = .{ .turn_id = 1, .prompt = try alloc.dupe(u8, prompt), .images = &.{}, .skill_display_spans = &.{}, } }; _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); const preview = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(preview); const preview_summary_count = std.mem.count(u8, preview, summary); const preview_card_count = std.mem.count(u8, preview, last_line); const preview_row = app.shell.transcript_commit_state.stable.cursor_row; const preview_col = app.shell.transcript_commit_state.stable.cursor_col; try std.testing.expectEqual(@as(usize, 1), app.pending_frame_commits);
app.submission.pending.?.phase = .adopted; _ = try app.shell.writeUserPromptCard(alloc, &app.metrics, .{ .text = app.submission.pending.?.draft.prompt }, true, &.{}); const scroll = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); const adopted = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(adopted); errdefer std.debug.print("pending paste preview cursor={d},{d} summary={d} card_tail={d}; adoption scroll={d} summary={d} tail_prefix={d} full_tail={d}\n", .{ preview_row, preview_col, preview_summary_count, preview_card_count, scroll, std.mem.count(u8, adopted, summary), std.mem.count(u8, adopted, "┃ - evidence gaps"), std.mem.count(u8, adopted, last_line), }); try std.testing.expect(scroll > preview_row); try std.testing.expectEqual(@as(usize, 1), preview_summary_count); try std.testing.expectEqual(@as(usize, 0), preview_card_count); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, history.items, summary)); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, adopted, summary)); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, adopted, "┃ - evidence gaps")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, adopted, last_line)); try std.testing.expectEqual(@as(usize, 0), publicationLineCount(adopted, "┃ - evidence gaps tha")); _ = try app.shell.appendRawTranscriptEntryClassified(alloc, "FOLLOWUP\n" ** 80, .unknown_raw); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, history.items, summary)); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, history.items, last_line)); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, history.items, "┃ - evidence gaps")); const finished = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(finished); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, finished, last_line)); try std.testing.expect(std.mem.find(u8, finished, summary).? < std.mem.find(u8, finished, last_line).?); try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); const quiet = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(quiet); try std.testing.expectEqualStrings(finished, quiet);}
test "pending prompt preview preserves blank bottom rows and canonical leading space" { const alloc = std.testing.allocator; const TestApp = struct { alloc: std.mem.Allocator, submission: @import("input_submit_runtime.zig").State, }; var app = TestApp{ .alloc = alloc, .submission = .{ .pending = .{ .draft = .{ .turn_id = 1, .prompt = try alloc.dupe(u8, "line\n" ** 30), .images = &.{}, .skill_display_spans = &.{}, } } }, }; defer app.submission.pending.?.deinit(alloc); const cases = [_]struct { row: u16, col: u16, advance: u16, deferred: bool }{ .{ .row = 20, .col = 1, .advance = 0, .deferred = false }, .{ .row = 8, .col = 47, .advance = 2, .deferred = false }, .{ .row = 19, .col = 47, .advance = 1, .deferred = false }, .{ .row = 20, .col = 47, .advance = 0, .deferred = true }, .{ .row = 24, .col = 47, .advance = 0, .deferred = true }, }; for (cases) |case| { var shell = transcript_runtime.TranscriptRuntime{ .layout = .{ .cols = 80, .rows = 24, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24 }, .cursor_row = case.row, .cursor_col = case.col, }; defer shell.deinit(alloc); var card = (try buildPendingCardProjection(TestApp, &app, &shell, null)).?; defer card.deinit(alloc); try std.testing.expectEqual(case.advance, card.leading_advance_rows); try std.testing.expectEqual(case.deferred, card.overlaps_flow_endpoint(case.col)); if (case.deferred) continue; const context = PendingCardPaintContext.init(card, .{ .top = 1, .bottom = 20, .owner = .transcript }, case.row, false).?; try std.testing.expectEqual(case.row + case.advance, context.row); try std.testing.expect(context.max_rows > 0); }}
test "pending prompt uses the canonical user turn boundary" { try std.testing.expectEqual( @as(u16, 2), pendingCardLeadingAdvanceRows(8, 47, 20), ); try std.testing.expectEqual( @as(u16, 0), pendingCardLeadingAdvanceRows(8, 1, 20), ); try std.testing.expectEqual( @as(u16, 0), pendingCardLeadingAdvanceRows(20, 47, 20), ); try std.testing.expectEqual( @as(u16, 1), pendingCardLeadingAdvanceRows(19, 47, 20), );}
test "pending prompt painting fits the solved transcript band" { const card: PendingCardProjection = .{ .bytes = @constCast("first\r\nsecond\r\nlast"), .paint_row_count = 3, .row_count = 5, .leading_advance_rows = 2, }; const clipped = PendingCardPaintContext.init(card, .{ .top = 1, .bottom = 3, .owner = .transcript, }, null, true).?; try std.testing.expectEqual(@as(u16, 1), clipped.row); try std.testing.expectEqual(@as(u16, 2), clipped.max_rows); try std.testing.expectEqualStrings("second\r\nlast", clipped.bytes);
const tiny = PendingCardPaintContext.init(card, .{ .top = 1, .bottom = 1, .owner = .transcript, }, null, false).?; try std.testing.expectEqual(@as(u16, 1), tiny.max_rows); try std.testing.expectEqualStrings("last", tiny.bytes); try std.testing.expect(PendingCardPaintContext.init( card, .empty(.transcript), null, true, ) == null);
const following = PendingCardPaintContext.init(card, .{ .top = 1, .bottom = 8, .owner = .transcript, }, 3, true).?; try std.testing.expectEqual(@as(u16, 5), following.row); try std.testing.expectEqual(@as(u16, 3), following.max_rows); try std.testing.expectEqualStrings(card.bytes, following.bytes);
const last_row = PendingCardPaintContext.init(card, .{ .top = 1, .bottom = 8, .owner = .transcript, }, 6, true).?; try std.testing.expectEqual(@as(u16, 8), last_row.row); try std.testing.expectEqual(@as(u16, 1), last_row.max_rows); try std.testing.expectEqualStrings("last", last_row.bytes);}
test "assistant tail writability changes remain traceable" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const root = try io_mod.dirRealpathAlloc(alloc, tmp.dir, "."); defer alloc.free(root); const trace_path = try std.fs.path.join(alloc, &.{ root, "assistant-tail.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "scroll");
var runtime = transcript_runtime.TranscriptRuntime{}; set_transcript_assistant_tail_writable(&runtime, false); set_transcript_assistant_tail_writable(&runtime, true); debug_trace.shutdown();
var trace_file = try std.Io.Dir.openFileAbsolute(std.testing.io, trace_path, .{}); defer trace_file.close(std.testing.io); const trace = try io_mod.readFileToEnd(alloc, &trace_file, 4096); defer alloc.free(trace); try std.testing.expect(std.mem.find( u8, trace, "assistant tail writability changed writable=false", ) != null); try std.testing.expect(std.mem.find( u8, trace, "assistant tail writability changed writable=true", ) != null);}
test "core.app_render_runtime fixed point retry resumes after acknowledged release" { var first_ctx = FixedPointTestContext{ .inline_advance_rows = 3 }; const first = try solveFixedPointForTest(&first_ctx, fixedPointTestInput(12, 5, 1, 3, .transcript)); var shell = transcript_runtime.TranscriptRuntime{ .layout = fixedPointTestInput(12, 5, 1, 3, .transcript).terminal, .owned_top_row = 5, .viewport_top_row = 5, }; defer shell.deinit(std.testing.allocator); try shell.ackPreservedRowRelease(first.scroll_plan, first.scroll_plan.terminal_scroll_rows);
var retry_ctx = FixedPointTestContext{}; const retry = try solveFixedPointForTest(&retry_ctx, fixedPointTestInput(12, shell.owned_top_row, 1, 3, .transcript));
try std.testing.expectEqual(@as(u16, 1), shell.owned_top_row); try std.testing.expectEqual(@as(u16, 0), retry.scroll_plan.preserved_release_rows); try std.testing.expectEqual(@as(u16, 0), retry.scroll_plan.terminal_scroll_rows);}
test "core.app_render_runtime fixed point shrink acknowledgment resumes from normalized ownership" { var first_ctx = FixedPointTestContext{}; const first = try solveFixedPointForTest(&first_ctx, fixedPointTestInput(5, 9, 0, 5, .transcript)); var shell = transcript_runtime.TranscriptRuntime{ .layout = fixedPointTestInput(5, 9, 0, 5, .transcript).terminal, .owned_top_row = 9, .viewport_top_row = 9, }; defer shell.deinit(std.testing.allocator); try shell.ackPreservedRowRelease(first.scroll_plan, 2);
var retry_ctx = FixedPointTestContext{}; const retry = try solveFixedPointForTest(&retry_ctx, fixedPointTestInput(5, shell.owned_top_row, 0, 5, .transcript));
try std.testing.expectEqual(@as(u16, 3), shell.owned_top_row); try std.testing.expectEqual(@as(u16, 2), retry.scroll_plan.preserved_release_rows); try std.testing.expectEqual(@as(u16, 1), retry.scroll_plan.post_scroll_owned_top);}
test "core.app_render_runtime gives all transient activity the turn-summary footer gap" { var shell = transcript_runtime.TranscriptRuntime{}; defer shell.deinit(std.testing.allocator);
const inactive = surface_frame.SurfaceFooterMeasurement{}; try std.testing.expectEqual(render_engine.frame_layout.ActivityState.none, frameActivityStateFromMeasurement(&shell, &inactive));
const active = surface_frame.SurfaceFooterMeasurement{ .activity_projection = .{ .turn_thinking = .{ .label = "thinking", } }, }; switch (frameActivityStateFromMeasurement(&shell, &active)) { .thinking => |thinking| try std.testing.expectEqual(@as(u16, 1), thinking.footer_gap_after_activity), .none, .overlay_entry => return error.TestUnexpectedResult, }
const active_tool = surface_frame.SurfaceFooterMeasurement{ .activity_projection = .{ .tool_slot = .{ .entry_id = 9, .fallback_label = "Running", .active = true, .kind = .read, } }, }; switch (frameActivityStateFromMeasurement(&shell, &active_tool)) { .thinking => |thinking| try std.testing.expectEqual(@as(u16, 1), thinking.footer_gap_after_activity), .none, .overlay_entry => return error.TestUnexpectedResult, }}
test "core.app_render_runtime connects minimal focused tools to the transcript block" { var shell = transcript_runtime.TranscriptRuntime{}; defer shell.deinit(std.testing.allocator);
const active_tool = surface_frame.SurfaceFooterMeasurement{ .activity_projection = .{ .tool_slot = .{ .entry_id = 9, .fallback_label = "Running zig build", .thinking_label = "Thinking", .active = true, .kind = .command, } }, };
switch (frameActivityStateFromMeasurement(&shell, &active_tool)) { .thinking => |thinking| { try std.testing.expectEqual(@as(u16, 0), thinking.gap_above_activity); try std.testing.expect(thinking.tool_before_activity); }, .none, .overlay_entry => return error.TestUnexpectedResult, }}
test "core.app_render_runtime rejects prepared transcript outside final plan band" { const plan = render_engine.paint_plan.PaintPlan{ .layout = .{ .rows = 45, .cols = 168, .content_bottom = 41, .divider_top_row = 42, .input_row = 43, .divider_bottom_row = 44, .hint_row = 45, }, .viewport = .{ .top_row = 1, .bottom_row = 39, .start_line = 0, .partial_skip_rows = 0, .line_count = 40, .last_visible_row = 39, }, .footer = .{ .top = 42, .top_divider = 42, .banner = 42, .banner_active = false, .input_base = 43, .picker_divider = 44, .picker_start = 45, .bottom_divider = 44, .hint = 45, .total_rows = 4, }, .activity = .{ .transient_row = .{ .row = 41, .gap_above_rows = 1 } }, .preserved_band = render_engine.paint_plan.FrameBand.empty(.preserved_shell), .transcript_band = .{ .top = 1, .bottom = 39, .owner = .transcript }, .activity_band = .{ .top = 41, .bottom = 41, .owner = .activity }, .footer_band = .{ .top = 42, .bottom = 45, .owner = .footer }, .invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), .footer_clean_allowed = true, .synchronized_update = true, .cursor_target = .{ .row = 43, .col = 3, .visible = true }, .bottom_reserved_rows = 2, .preserve_scrollback = true, }; const prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .selection = .{ .top_row = 1, .bottom_row = 41, .start_line = 0, .partial_skip_rows = 0, .line_count = 40, .last_visible_row = 41, }, };
try std.testing.expectError(error.InvalidPaintPlan, validatePreparedTranscriptFitsPlan(&prepared, plan));}
noinline fn shouldResetPhysicalTerminal( alternate_screen_active: bool, main_reset_pending: bool,) bool { return !alternate_screen_active and main_reset_pending;}
test "core.app_render_runtime alternate presentation cannot reset primary scrollback" { try std.testing.expect(!shouldResetPhysicalTerminal(true, true)); try std.testing.expect(!shouldResetPhysicalTerminal(true, false)); try std.testing.expect(!shouldResetPhysicalTerminal(false, false)); try std.testing.expect(shouldResetPhysicalTerminal(false, true));}
const CoordinatorFault = enum { committed, preparation_error, input_pending, terminal_partial_write, shadow_feed_failed,};
const BufferedInputCheckpointTestApp = struct { const PollState = struct { readable: bool = false,
fn closed(_: PollState) bool { return false; } };
const Terminal = struct { fn pollInput(_: *Terminal, _: i32) !PollState { return .{}; } };
terminal: Terminal = .{}, input_runtime: core_input_runtime.Runtime = .{}, terminal_input_runtime: ui_input.Runtime = .{},};
test "transcript checkpoint sees input retained above an empty terminal" { var app = BufferedInputCheckpointTestApp{}; app.terminal_input_runtime.terminal_theme_monitor.start(); _ = app.terminal_input_runtime.terminal_theme_monitor.feed(0x1b, 0); var checkpoint = Runtime(BufferedInputCheckpointTestApp).transcriptBuildCheckpoint(&app).?;
try std.testing.expectError(error.InputPending, build_checkpoint.poll(&checkpoint));}
const CoordinatorFaultTestApp = struct { alloc: std.mem.Allocator = std.testing.allocator, input_runtime: core_input_runtime.Runtime = .{}, shell: struct { terminal_dimensions_invalid: bool = false, terminal_reset_pending: bool = false, resize_history_row_delta: ?i32 = null, pending_resize_observation: ?transcript_runtime.ResizeObservation = null, layout: struct { rows: u16 = 24, cols: u16 = 80, } = .{}, render_requests: render_request.RenderRequestState = .{}, } = .{}, fault: CoordinatorFault = .committed, attempts: usize = 0, injected_reason: ?render_request.Reason = null, inject_animation_reset: bool = false, animation_visible: bool = false, notification_flushes: usize = 0, file_picker_receipt: ?input_completion_runtime.FilePickerReceipt = null, last_snapshot: ?render_request.AttemptSnapshot = null,
fn flushNotifications(self: *CoordinatorFaultTestApp) void { self.notification_flushes += 1; }
fn renderFrameAttemptForTest( self: *CoordinatorFaultTestApp, snapshot: render_request.AttemptSnapshot, ) !FrameAttemptResult { self.attempts += 1; self.last_snapshot = snapshot; if (self.injected_reason) |reason| { self.shell.render_requests.request(reason); } if (self.inject_animation_reset) { self.shell.render_requests.requestAnimationReset(); }
return switch (self.fault) { .committed => blk: { self.shell.terminal_reset_pending = false; break :blk .{ .shadow_state = .committed, .animation_visible = self.animation_visible, .file_picker_receipt = self.file_picker_receipt, }; }, .preparation_error => error.TestPreparationFailure, .input_pending => error.InputPending, .terminal_partial_write => .{ .shadow_state = .terminal_partial_write, .animation_visible = self.animation_visible, }, .shadow_feed_failed => .{ .shadow_state = .shadow_feed_failed, .animation_visible = self.animation_visible, }, }; }};
test "file picker receipt aborts preserve authority and uncertain writes revoke it" { const state_mod = @import("../input/file_completion_state.zig"); const alloc = std.testing.allocator; for ([_]CoordinatorFault{ .preparation_error, .input_pending, .terminal_partial_write, .shadow_feed_failed }) |fault| { var app: CoordinatorFaultTestApp = .{}; defer app.input_runtime.deinit(alloc); try app.input_runtime.textReplacementState().replace(alloc, "@file"); const picker = &app.input_runtime.picker; _ = picker.file_completion.reconcile(picker.activeFilePickerQuery(&app.input_runtime.edit_state), 0, true); const values = [_]file_index.SearchResult{.{ .path = "file.txt", .kind = .file, .matched_spans = &.{} }}; picker.file_completion.stage(alloc, .{}, .ready, try state_mod.Rows.copy(alloc, &values)); app.file_picker_receipt = picker.file_completion.view(0, 0).receipt; app.shell.render_requests.request(.footer); try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expect(picker.file_completion.selected(0) != null); picker.file_completion.stage(alloc, .{}, .ready, try state_mod.Rows.copy(alloc, &values)); app.file_picker_receipt = picker.file_completion.view(0, 0).receipt; app.fault = fault; app.shell.render_requests.request(.footer); if (fault == .preparation_error) { try std.testing.expectError(error.TestPreparationFailure, Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app)); } else try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expect(picker.file_completion.prepared != null); try std.testing.expectEqual(fault == .preparation_error or fault == .input_pending, picker.file_completion.selected(0) != null); app.fault = .committed; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expect(picker.file_completion.prepared == null); try std.testing.expectEqualStrings("file.txt", picker.file_completion.selected(0).?.path); }}
test "core.app_render_runtime requested-frame flush skips absent and blocked work" { var app = CoordinatorFaultTestApp{};
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 0), app.attempts);
app.shell.render_requests.request(.footer); app.shell.terminal_dimensions_invalid = true; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 0), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.footer));
app.shell.terminal_dimensions_invalid = false; app.shell.render_requests.observeResizeSignal(100, 80); try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 0), app.attempts); try std.testing.expect(app.shell.render_requests.blocksFrameCommit());}
test "core.app_render_runtime requested-frame flush commits one coalesced snapshot" { var app = CoordinatorFaultTestApp{}; app.shell.render_requests.request(.first_frame); app.shell.render_requests.request(.footer); app.shell.render_requests.request(.modal);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expectEqual(@as(usize, 3), app.last_snapshot.?.reasons.count()); try std.testing.expect(!app.shell.render_requests.hasPending());}
test "core.app_render_runtime flushes notifications only after a committed frame" { for ([_]CoordinatorFault{ .terminal_partial_write, .shadow_feed_failed }) |fault| { var app = CoordinatorFaultTestApp{ .fault = fault }; app.shell.render_requests.request(.notification);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 0), app.notification_flushes); try std.testing.expect(app.shell.render_requests.hasReason(.notification));
app.fault = .committed; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 1), app.notification_flushes); try std.testing.expect(!app.shell.render_requests.hasReason(.notification)); }}
test "core.app_render_runtime requested-frame flush preserves work injected during commit" { var app = CoordinatorFaultTestApp{ .injected_reason = .modal, }; app.shell.render_requests.request(.footer);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(!app.shell.render_requests.hasReason(.footer)); try std.testing.expect(app.shell.render_requests.hasReason(.modal));}
test "core.app_render_runtime requested-frame flush restores preparation errors" { var app = CoordinatorFaultTestApp{ .fault = .preparation_error, .injected_reason = .modal, }; app.shell.render_requests.request(.footer); app.shell.render_requests.requestInvalidation(.{ .reason = .external_clear, .top = 3, .bottom = 4, });
try std.testing.expectError( error.TestPreparationFailure, Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app), );
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.footer)); try std.testing.expect(app.shell.render_requests.hasReason(.modal)); try std.testing.expect(app.shell.render_requests.hasReason(.external_damage)); try std.testing.expectEqual( @as(u8, 1), app.shell.render_requests.pendingInvalidations().len, );}
test "core.app_render_runtime requested-frame flush restores input-interrupted work" { var app = CoordinatorFaultTestApp{ .fault = .input_pending }; app.shell.render_requests.request(.modal);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.modal));
app.fault = .committed; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(usize, 2), app.attempts); try std.testing.expect(!app.shell.render_requests.hasPending());}
test "core.app_render_runtime requested-frame flush restores terminal recovery outcomes" { for ([_]CoordinatorFault{ .terminal_partial_write, .shadow_feed_failed }) |fault| { var app = CoordinatorFaultTestApp{ .fault = fault, .injected_reason = .modal, }; app.shell.render_requests.request(.transcript); app.shell.render_requests.requestInvalidation(.{ .reason = .partial_write, .top = 2, .bottom = 5, });
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.transcript)); try std.testing.expect(app.shell.render_requests.hasReason(.modal)); try std.testing.expect(app.shell.render_requests.hasReason(.external_damage)); try std.testing.expectEqual( @as(u8, 1), app.shell.render_requests.pendingInvalidations().len, ); }}
test "core.app_render_runtime failed resize reset accepts only the superseding reset commit" { var app = CoordinatorFaultTestApp{ .fault = .terminal_partial_write }; app.shell.render_requests.completeResizeGeometry(true); app.shell.pending_resize_observation = .{ .layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .apply_after_ms = 100, .expected_row = 13, .result = .{ .measured = 7 }, .phase = .reset_queued, }; app.shell.resize_history_row_delta = 7; app.shell.terminal_reset_pending = true; app.shell.render_requests.request(.resize);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expect(app.shell.terminal_reset_pending); try std.testing.expectEqual(@as(?i32, 7), app.shell.resize_history_row_delta); try std.testing.expect(app.shell.pending_resize_observation != null); try std.testing.expect(app.shell.render_requests.resizeLifecyclePending()); try std.testing.expect(app.shell.render_requests.hasReason(.resize));
app.shell.render_requests.observeResizeSignal(200, 80); try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(app.shell.terminal_reset_pending); try std.testing.expectEqual(@as(?i32, 7), app.shell.resize_history_row_delta);
app.shell.pending_resize_observation = .{ .layout = .{ .rows = 40, .cols = 120, .content_bottom = 36, .divider_top_row = 37, .input_row = 38, .divider_bottom_row = 39, .hint_row = 40, }, .apply_after_ms = 280, .expected_row = 16, .result = .{ .measured = 3 }, .phase = .reset_queued, }; app.shell.resize_history_row_delta = 3; app.shell.render_requests.completeResizeGeometry(false); app.fault = .committed; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 2), app.attempts); try std.testing.expect(!app.shell.terminal_reset_pending); try std.testing.expectEqual( @as(?transcript_runtime.ResizeObservation, null), app.shell.pending_resize_observation, ); try std.testing.expectEqual(@as(?i32, null), app.shell.resize_history_row_delta); try std.testing.expect(!app.shell.render_requests.resizeLifecyclePending());}
test "core.app_render_runtime awaiting resize observation blocks every flush caller" { var app = CoordinatorFaultTestApp{}; app.shell.pending_resize_observation = .{ .layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .apply_after_ms = 100, .expected_row = 13, .result = .awaiting, .phase = .live, }; app.shell.render_requests.request(.footer);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 0), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.footer));
app.shell.pending_resize_observation.?.result = .unavailable; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts);}
test "core.app_render_runtime committed resize light blocks intervening frames" { var app = CoordinatorFaultTestApp{}; app.shell.render_requests.completeResizeGeometry(true); app.shell.pending_resize_observation = .{ .layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .apply_after_ms = 100, .expected_row = 13, .result = .{ .measured = 3 }, .phase = .live, }; app.shell.resize_history_row_delta = 3; app.shell.render_requests.request(.resize);
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expectEqual( transcript_runtime.ResizeObservationPhase.settle_pending, app.shell.pending_resize_observation.?.phase, ); try std.testing.expectEqual(@as(?i32, null), app.shell.resize_history_row_delta);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 1), app.attempts); try std.testing.expect(app.shell.render_requests.hasReason(.footer));}
test "core.app_render_runtime animation retries the captured phase after every failure outcome" { for ([_]CoordinatorFault{ .preparation_error, .terminal_partial_write, .shadow_feed_failed, }) |fault| { var app = CoordinatorFaultTestApp{ .fault = fault, .animation_visible = true, }; app.shell.render_requests.animation_visible = true; app.shell.render_requests.animation_next_deadline_ms = 100; try std.testing.expect(app.shell.render_requests.requestAnimationDue(100));
if (fault == .preparation_error) { try std.testing.expectError( error.TestPreparationFailure, Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app), ); } else { try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); } const failed_candidate = app.last_snapshot.?.animation_candidate.?;
try std.testing.expectEqual( @as(i16, -8), app.shell.render_requests.visibleAnimationPhase(), ); try std.testing.expectEqual( @as(i64, 100), app.shell.render_requests.animation_next_deadline_ms, );
app.fault = .committed; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); const retry_candidate = app.last_snapshot.?.animation_candidate.?;
try std.testing.expectEqual(failed_candidate.generation, retry_candidate.generation); try std.testing.expectEqual(failed_candidate.phase, retry_candidate.phase); try std.testing.expectEqual( retry_candidate.phase, app.shell.render_requests.visibleAnimationPhase(), ); try std.testing.expect(app.shell.render_requests.animation_next_deadline_ms > 100); }}
test "core.app_render_runtime animation retry stays ahead of a newer fact" { var app = CoordinatorFaultTestApp{ .fault = .terminal_partial_write, .inject_animation_reset = true, .animation_visible = true, }; app.shell.render_requests.animation_visible = true; app.shell.render_requests.animation_next_deadline_ms = 100; try std.testing.expect(app.shell.render_requests.requestAnimationDue(100));
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); const failed_candidate = app.last_snapshot.?.animation_candidate.?; try std.testing.expectEqual( @as(i16, -8), app.shell.render_requests.visibleAnimationPhase(), );
app.fault = .committed; app.inject_animation_reset = false; try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); const retry_candidate = app.last_snapshot.?.animation_candidate.?; try std.testing.expectEqual(failed_candidate.generation, retry_candidate.generation); try std.testing.expect(app.shell.render_requests.hasReason(.animation));
try Runtime(CoordinatorFaultTestApp).flushRequestedFrame(&app); const newer_candidate = app.last_snapshot.?.animation_candidate.?; try std.testing.expect(newer_candidate.generation > retry_candidate.generation); try std.testing.expectEqual( newer_candidate.phase, app.shell.render_requests.visibleAnimationPhase(), ); try std.testing.expect(!app.shell.render_requests.hasPending());}
const CoordinatorTestWorker = struct { submitted_permission: ?types.ToolPermissionDecision = null, cancel_requested: bool = false, cancel_continues_turn: bool = false,
pub fn isCancelRequested(self: *const @This()) bool { return self.cancel_requested; }
pub fn cancellationStopsTurn(self: *const @This()) bool { return self.cancel_requested and !self.cancel_continues_turn; }
pub fn submitPermissionResponse( self: *@This(), _: u64, response: permission_request.OwnedPermissionResponse, ) @import("../agent/worker_runtime.zig").PermissionSubmissionResult { var owned = response; defer owned.deinit(); self.submitted_permission = owned.decision; return .accepted; }};
const CoordinatorTestUpgrader = struct { fn statusLabel(_: *@This(), _: []u8) []const u8 { return ""; }};
const CoordinatorTestPacer = struct { pending: bool = false, completed_token_progress: ?types.TurnTokenProgress = null,
fn hasCompletedAssistantPresentationTail(self: *const CoordinatorTestPacer) bool { return self.completed_token_progress != null; }
fn hasPending(self: *const CoordinatorTestPacer) bool { return self.pending; }
fn completedAssistantPresentationTokenProgress(self: *const CoordinatorTestPacer) ?types.TurnTokenProgress { return self.completed_token_progress; }};
const coordinator_test_slash_specs = [_]command_specs.SlashSpec{.{ .kind = .help, .command = "/help", .help_entry = "/help", .completion_description = "show available slash commands", .presentation_category = .general,}};const coordinator_test_slash_registry = command_specs.SlashRegistry{ .commands = coordinator_test_slash_specs[0..],};
const CoordinatorTestTerminalClient = struct { snapshot_alloc: std.mem.Allocator = std.testing.allocator, snapshot_count: usize = 0, source_running: bool = false,
fn terminalProjection( self: *CoordinatorTestTerminalClient, _: std.mem.Allocator, ) std.mem.Allocator.Error!terminal_ui_projection.Snapshot { self.snapshot_count += 1; const rows = try self.snapshot_alloc.alloc( terminal_ui_projection.Row, @intFromBool(self.source_running), ); errdefer self.snapshot_alloc.free(rows); if (self.source_running) { const session_id = try self.snapshot_alloc.dupe(u8, "terminal-test"); errdefer self.snapshot_alloc.free(session_id); rows[0] = .{ .session_id = session_id, .label = try self.snapshot_alloc.dupe(u8, "test command"), .lifecycle = .running, .attention = .{}, .backend = .native, }; } self.source_running = false; return .{ .alloc = self.snapshot_alloc, .rows = rows }; }};
const CoordinatorTestApp = struct { alloc: std.mem.Allocator, terminal: shell_runtime.TerminalState = .{}, shell: transcript_runtime.TranscriptRuntime, metrics: types.Metrics = .{}, input_runtime: core_input_runtime.Runtime = .{}, terminal_input_runtime: ui_input.Runtime = .{}, approval_prompt: approval_prompt.ApprovalPrompt = .{}, approval_screen: interaction_state.ApprovalScreenState = .{}, question_prompt: question_prompt.QuestionPrompt = .{}, session_persistence: app_session_runtime.Persistence = .{}, worker: CoordinatorTestWorker = .{}, selected_model: std.ArrayList(u8) = .empty, workspace_root: []const u8 = "", workspace_identity: statusline_identity.Runtime = .{}, pacer: CoordinatorTestPacer = .{}, auth: auth_runtime.Runtime = .{}, pending_images: std.ArrayList(types.ImageAttachment) = .empty, skills: skill_runtime.Runtime = .{}, model_cache: model_cache_runtime.Runtime = model_cache_runtime.Runtime.init(std.testing.allocator, "/v1/models"), model_cache_loading: bool = false, stream: types.StreamState = .{}, fast_mode: bool = false, effort: types.ReasoningEffort = .auto, statusline_context: bool = false, total_input_tokens: u64 = 0, intrinsic_fast_model: ?[]const u8 = null, gateway_metadata_model: ?[]const u8 = null, gateway_metadata: model_capabilities.GatewayMetadata = .{}, permission_state: app_permission_runtime.State = .{}, upgrader: CoordinatorTestUpgrader = .{}, terminal_client: CoordinatorTestTerminalClient = .{}, file_completion_values: []const file_index.SearchResult = &.{}, file_completion_calls: usize = 0, submission: @import("input_submit_runtime.zig").State = .{}, pending_frame_commits: usize = 0,
pub fn notePendingFrameCommitted(self: *CoordinatorTestApp) void { self.pending_frame_commits += 1; }
pub fn slashRegistry(_: *const CoordinatorTestApp) command_specs.SlashRegistry { return coordinator_test_slash_registry; }
fn deinit(self: *CoordinatorTestApp) void { if (self.submission.pending) |*pending| pending.deinit(self.alloc); self.shell.deinit(self.alloc); self.input_runtime.deinit(self.alloc); self.terminal_input_runtime.deinit(self.alloc); self.approval_prompt.deinit(self.alloc); self.question_prompt.deinit(self.alloc); self.selected_model.deinit(self.alloc); self.workspace_identity.deinit(self.alloc); self.pending_images.deinit(self.alloc); self.model_cache.deinit(); }
pub fn prepareDirectoryCompletion(self: *CoordinatorTestApp) void { const completion = @import("../input/file_completion_state.zig"); const state = &self.input_runtime.picker.file_completion; const rows = completion.Rows.copy(self.alloc, self.file_completion_values) catch { state.stage(self.alloc, .{ .state = .ready }, .unavailable, null); return; }; self.file_completion_calls += 1; state.stage(self.alloc, .{ .state = .ready }, if (rows.results.len == 0) .empty else .ready, rows); }
pub fn modelCompletions(_: *CoordinatorTestApp, _: []const u8, _: [][]const u8) usize { return 0; }
pub fn fileCompletions( self: *CoordinatorTestApp, _: []const u8, out: []file_index.SearchResult, _: []file_index.MatchSpan, _: []u8, ) file_index.SearchError!usize { self.file_completion_calls += 1; const count = @min(out.len, self.file_completion_values.len); @memcpy(out[0..count], self.file_completion_values[0..count]); return count; }
pub fn writeDomainNotice(_: *CoordinatorTestApp, _: types.SemanticNotice, _: bool) !void {}
fn isModelCacheLoading(self: *CoordinatorTestApp) bool { return self.model_cache_loading; }
fn isModelCacheFailed(_: *CoordinatorTestApp) bool { return false; }
pub fn resolvedModelCapabilities(self: *CoordinatorTestApp, model: []const u8) model_capabilities.Capabilities { var fallback = model_capabilities.Capabilities{ .context_window = 1_000_000, }; if (self.intrinsic_fast_model) |intrinsic_model| { fallback.intrinsic_fast = std.mem.eql(u8, intrinsic_model, model); } if (self.gateway_metadata_model) |metadata_model| { if (std.mem.eql(u8, metadata_model, model)) { return model_capabilities.mergeCapabilities( fallback, self.gateway_metadata, ); } } return fallback; }
fn isFileIndexLoading(_: *CoordinatorTestApp) bool { return false; }
fn isFileIndexFailed(_: *CoordinatorTestApp) bool { return false; }};
fn initCoordinatorProjectionTestApp( alloc: std.mem.Allocator, file: std.Io.File,) !CoordinatorTestApp { var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 12, .cols = 80, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .owned_top_row = 1, .viewport_top_row = 1, }, .terminal_client = .{ .source_running = true, }, }; errdefer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); return app;}
test "file picker real frame receipt promotes only visible rows and preserves prepared identity" { const alloc = std.testing.allocator; var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(std.testing.io); var app = try initCoordinatorProjectionTestApp(alloc, sink); defer app.deinit(); app.terminal_client.source_running = false; const completion = input_completion_runtime.CompletionRuntime(CoordinatorTestApp); const first = [_]file_index.SearchResult{ .{ .path = "b.txt", .kind = .file, .matched_spans = &.{} }, .{ .path = "c.txt", .kind = .file, .matched_spans = &.{} }, }; app.file_completion_values = &first; try app.input_runtime.textReplacementState().replace(alloc, "@txt"); completion.prepareFilePicker(&app); try std.testing.expect(app.input_runtime.picker.file_completion.selected(0) == null); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expectEqualStrings("b.txt", app.input_runtime.picker.file_completion.selected(0).?.path); var grid: std.ArrayList(u8) = .empty; defer grid.deinit(alloc); try app.shell.shadow_vt.?.snapshot(&grid); try std.testing.expect(std.mem.find(u8, grid.items, "c.txt") != null); const picker = &app.input_runtime.picker; picker.file_completion.navigate(&picker.file_completion_index, &picker.file_completion_window_start, 1); const next = [_]file_index.SearchResult{.{ .path = "a.txt", .kind = .file, .matched_spans = &.{} }} ++ first; app.file_completion_values = &next; picker.file_completion.retry(); completion.prepareFilePicker(&app); try std.testing.expectEqualStrings("c.txt", picker.file_completion.selected(picker.file_completion_index).?.path); // A catalog owns the frame while the completion stays staged. app.input_runtime.help_menu.active = true; completion.reconcileFilePicker(&app); const prepared_revision = completion.filePickerView(&app).receipt.?.revision; app.shell.render_requests.request(.footer); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(picker.file_completion.prepared != null); try std.testing.expect(picker.file_completion.selected(picker.file_completion_index) == null); app.input_runtime.help_menu.active = false; app.shell.render_requests.request(.footer); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(prepared_revision, completion.filePickerView(&app).receipt.?.revision); try std.testing.expectEqualStrings("c.txt", picker.file_completion.selected(picker.file_completion_index).?.path); try std.testing.expectEqual(@as(usize, 2), app.file_completion_calls);}
test "core.app_render_runtime keeps final token progress during paced response tail" { const alloc = std.testing.allocator; const progress: types.TurnTokenProgress = .{ .input_tokens = 50_000, .output_tokens = 20_000, }; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .pacer = .{ .pending = true, .completed_token_progress = progress, }, }; defer app.deinit();
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expectEqual(progress, ctx.stream.token_progress); var activity_buf: [128]u8 = undefined; switch (render_input.frameOwnedActivityProjection( &activity_buf, &app.shell, ctx, null, )) { .turn_thinking => |thinking| try std.testing.expectEqualStrings( " (↑50k ↓20k)", thinking.label, ), .none, .tool_slot => return error.TestUnexpectedResult, }}
test "core.app_render_runtime hides loading after active tool cancellation" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .stream = .{ .active = true }, }; defer app.deinit(); app.worker.cancel_requested = true; _ = try app.shell.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = .{ .turn_id = 1, .call_id = "command" }, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, } });
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expect(!ctx.stream.active); var activity_buf: [128]u8 = undefined; try std.testing.expect( render_input.frameOwnedActivityProjection( &activity_buf, &app.shell, ctx, null, ) == .none, );}
test "core.app_render_runtime keeps loading while cancellation continues the turn" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .stream = .{ .active = true }, }; defer app.deinit(); app.worker.cancel_requested = true; app.worker.cancel_continues_turn = true;
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expect(ctx.stream.active);}
test "core.app_render_runtime keeps configured controls visible while model capabilities load" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .model_cache_loading = true, .fast_mode = true, .effort = types.ReasoningEffort.literal("xhigh"), }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "anthropic/claude-opus-4.8");
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
var hint_buf: [128]u8 = undefined; const line = ui_render.buildHintLine( false, ctx.has_api_key, ctx.model, ctx.permission_mode, ctx.fast_indicator_active, ctx.effort, ctx.model_supports_effort, ctx.statusline, 80, &hint_buf, ); try std.testing.expectEqualStrings( "run /login · ask · opus 4.8 · xhigh · ⚡︎", line, );}
test "core.app_render_runtime keeps Kimi fast indicator stable across catalog hydration" { const cases = [_]struct { model: []const u8, fast_mode: bool, intrinsic_fast: bool, supports_fast_mode: bool, expected_indicator: bool, }{ .{ .model = "moonshotai/kimi-k3", .fast_mode = false, .intrinsic_fast = false, .supports_fast_mode = true, .expected_indicator = false }, .{ .model = "moonshotai/kimi-k3", .fast_mode = true, .intrinsic_fast = false, .supports_fast_mode = true, .expected_indicator = true }, .{ .model = "moonshotai/kimi-k3-fast", .fast_mode = false, .intrinsic_fast = true, .supports_fast_mode = false, .expected_indicator = true }, };
for (cases) |case| { for ([_]bool{ true, false }) |catalog_loading| { var app = CoordinatorTestApp{ .alloc = std.testing.allocator, .shell = .{}, .model_cache_loading = catalog_loading, .fast_mode = case.fast_mode, .intrinsic_fast_model = if (case.intrinsic_fast) case.model else null, .gateway_metadata_model = if (catalog_loading) null else case.model, .gateway_metadata = .{ .supports_fast_mode = case.supports_fast_mode }, }; defer app.deinit(); try app.selected_model.appendSlice(std.testing.allocator, case.model);
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expectEqual(case.expected_indicator, ctx.fast_indicator_active); } }}
test "core.app_render_runtime keeps a bound fast preference stable after catalog hydration" { var app = CoordinatorTestApp{ .alloc = std.testing.allocator, .shell = .{}, .fast_mode = true, .gateway_metadata_model = "anthropic/claude-fable-5", }; defer app.deinit(); try app.selected_model.appendSlice(std.testing.allocator, "anthropic/claude-fable-5");
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expect(ctx.fast_indicator_active);}
test "core.app_render_runtime projects only the visible inline completion suffix" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, }; defer app.deinit(); app.shell.layout.cols = 80; const skills = [_]skill_runtime.Skill{.{ .name = "managed-menu", .description = "", .path = "/tmp/managed-menu/SKILL.md", .source = .global_fx, }}; app.skills.items = @constCast(&skills); try app.input_runtime.textReplacementState().replace(alloc, "explain $man");
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expectEqualStrings("aged-menu", ctx.inline_completion_suffix); try std.testing.expectEqualStrings("explain $man", ctx.input.edit_state.input.items); try std.testing.expectEqual(@as(usize, 0), ctx.input.entities.skill_tokens.items.len);}
test "core.app_render_runtime projects an inline slash completion suffix after text" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, }; defer app.deinit(); app.shell.layout.cols = 80; try app.input_runtime.textReplacementState().replace(alloc, "explain /he");
var upgrade_status_buf: [64]u8 = undefined; const steering: SteeringProjection = .{}; const ctx = Runtime(CoordinatorTestApp).footerContext( &app, &upgrade_status_buf, 0, &steering, );
try std.testing.expectEqualStrings("/help", ctx.slash_registry.commands[0].command); try std.testing.expectEqualStrings("lp", ctx.inline_completion_suffix); try std.testing.expectEqualStrings("explain /he", ctx.input.edit_state.input.items);}
test "core.app_render_runtime projects Opus 4.8 one million token context to footer" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .statusline_context = true, .total_input_tokens = 43_000, }; defer app.deinit();
const statusline = Runtime(CoordinatorTestApp).buildStatuslineItems( &app, "anthropic/claude-opus-4.8", ); try std.testing.expectEqual(@as(u64, 43_000), statusline.context_used); try std.testing.expectEqual(@as(?u32, 1_000_000), statusline.context_total);
var buf: [128]u8 = undefined; const line = ui_render.buildHintLine( false, true, "anthropic/claude-opus-4.8", .ask, false, .auto, true, statusline, 100, &buf, ); try std.testing.expectEqualStrings("ask · opus 4.8 · 43k/1000k 4%", line);}
test "core.app_render_runtime uses Gateway context window from resolved capabilities" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .statusline_context = true, .total_input_tokens = 12_000, .gateway_metadata_model = "provider/new-long-context", .gateway_metadata = .{ .context_window = 750_000 }, }; defer app.deinit();
const statusline = Runtime(CoordinatorTestApp).buildStatuslineItems( &app, "provider/new-long-context", ); try std.testing.expectEqual(@as(u64, 12_000), statusline.context_used); try std.testing.expectEqual(@as(?u32, 750_000), statusline.context_total);}
test "core.app_render_runtime request owner authorizes explicit frame causes" { const alloc = std.testing.allocator; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{}, .stream = .{ .active = true }, }; defer app.deinit();
app.shell.shimmer_active = true; try std.testing.expect(!app.shell.render_requests.hasPending());
app.shell.markTranscriptDirty(); try std.testing.expect(app.shell.render_requests.hasReason(.transcript));
app.shell.render_requests.request(.footer); try std.testing.expect(app.shell.render_requests.hasReason(.footer));
try app.shell.recordFrameInvalidation(.{ .reason = .external_clear, .top = 1, .bottom = 1, }); try std.testing.expect(app.shell.render_requests.hasReason(.external_damage));}
test "core.app_render_runtime exposes one requested-frame flush boundary" { try std.testing.expect(@hasDecl(Runtime(CoordinatorTestApp), "flushRequestedFrame"));}
test "core.app_render_runtime requested-frame flush commits and acknowledges one snapshot" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "requested-frame.log", .{ .read = true }); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 12, .cols = 64, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "requested frame content\n", true); app.shell.terminal_reset_pending = true;
app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(app.shell.has_committed_frame); try std.testing.expect(!app.shell.terminal_reset_pending); try std.testing.expect(!app.shell.render_requests.hasPending()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "requested frame content"));}
test "core.app_render_runtime inline frame omits background terminal chrome and animation" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "terminal-projection.log", .{ .read = true }); defer file.close(io_mod.getIo()); var app = try initCoordinatorProjectionTestApp(alloc, file); defer app.deinit();
app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(@as(usize, 0), app.terminal_client.snapshot_count); try std.testing.expect(app.terminal_client.source_running); try std.testing.expect(!app.shell.render_requests.animation_visible); try std.testing.expect(!(try coordinatorGridContains( app.shell.shadow_vt.?.*, "background (", )));}
noinline fn readCoordinatorFrameBytes(alloc: std.mem.Allocator, file: std.Io.File, read_offset: *u64) ![]u8 { const total = try file.length(io_mod.getIo()); const want: usize = @intCast(total - read_offset.*); const bytes = try alloc.alloc(u8, want); errdefer alloc.free(bytes); const n = try file.readPositionalAll(io_mod.getIo(), bytes, read_offset.*); try std.testing.expectEqual(want, n); read_offset.* += n; return bytes;}
noinline fn coordinatorGridContains(grid: vt_emulator.Grid, needle: []const u8) !bool { var row: u16 = 1; var buf: std.ArrayList(u8) = .empty; defer buf.deinit(grid.alloc);
while (row <= grid.rows) : (row += 1) { buf.clearRetainingCapacity(); try grid.rowTextTrimmed(row, &buf); if (std.mem.find(u8, buf.items, needle) != null) return true; } return false;}
fn feedRewritePublicationFrame( alloc: std.mem.Allocator, physical: *vt_emulator.Grid, exported: *std.ArrayList(u8), bytes: []const u8,) !void { var rows: std.ArrayList(u8) = .empty; defer rows.deinit(alloc); const starts = try alloc.alloc(usize, @as(usize, physical.rows) + 1); defer alloc.free(starts); for (bytes) |byte| { rows.clearRetainingCapacity(); for (0..physical.rows) |index| { starts[index] = rows.items.len; try physical.rowTextTrimmed(@intCast(index + 1), &rows); try rows.append(alloc, '\n'); } starts[physical.rows] = rows.items.len; const normal_buffer = physical.saved_normal_screen == null; var stats: vt_emulator.FeedStats = .{}; try physical.feedWithStats(&.{byte}, &stats); if (normal_buffer and stats.scroll_rows > 0) { try exported.appendSlice(alloc, rows.items[0..starts[@min(stats.scroll_rows, physical.rows)]]); try exported.appendNTimes(alloc, '\n', stats.scroll_rows -| physical.rows); } }}
fn publicationLineCount(text: []const u8, label: []const u8) usize { var count: usize = 0; var lines = std.mem.splitScalar(u8, text, '\n'); while (lines.next()) |line| if (std.mem.eql(u8, std.mem.trim(u8, line, " \r"), label)) { count += 1; }; return count;}
fn rewritePublicationText(alloc: std.mem.Allocator, physical: *vt_emulator.Grid, exported: []const u8) ![]u8 { var text: std.ArrayList(u8) = .empty; errdefer text.deinit(alloc); try text.appendSlice(alloc, exported); for (0..physical.rows) |index| { try physical.rowTextTrimmed(@intCast(index + 1), &text); try text.append(alloc, '\n'); } return text.toOwnedSlice(alloc);}
fn flushRebasedPublicationFrame(app: *CoordinatorTestApp, file: std.Io.File, physical: *vt_emulator.Grid, history: *std.ArrayList(u8), offset: *u64) !u32 { const before = app.shell.transcriptCommitDiagnostic().history_visual_offset; const rows_before = std.mem.count(u8, history.items, "\n"); app.shell.render_requests.request(.transcript); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(app); const bytes = try readCoordinatorFrameBytes(app.alloc, file, offset); defer app.alloc.free(bytes); try feedRewritePublicationFrame(app.alloc, physical, history, bytes); const accepted = app.shell.transcriptCommitDiagnostic().history_visual_offset - before; try std.testing.expectEqual(@as(usize, accepted), std.mem.count(u8, history.items, "\n") - rows_before); return accepted;}
test "core.app_render_runtime consolidation rebases before publishing followup rows" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "consolidation-publication.log", .{ .read = true }); defer file.close(std.testing.io); var app = try initCoordinatorProjectionTestApp(alloc, file); defer app.deinit(); app.terminal_client.source_running = false; var physical = try vt_emulator.Grid.init(alloc, 80, 12); defer physical.deinit(); physical.defer_sync_updates = false; var history: std.ArrayList(u8) = .empty; defer history.deinit(alloc); var offset: u64 = 0; var prompt_text = "CONSOLIDATION_PROMPT".*; _ = try app.shell.writeUserPromptCard(alloc, &app.metrics, .{ .text = &prompt_text, .images = &.{} }, false, &.{}); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); var ids: [18]u32 = undefined; for (&ids, 0..) |*id, index| { var line: [48]u8 = undefined; id.* = try app.shell.appendRawTranscriptEntry(alloc, try std.fmt.bufPrint(&line, "CONSOLIDATION_OUTPUT_{d:0>2}\n", .{index})); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); } var old_text: std.Io.Writer.Allocating = .init(alloc); defer old_text.deinit(); for (0..24) |index| try old_text.writer.print("{d}. OLD_TABLE_{d:0>2}\n", .{ index + 1, index }); _ = try app.shell.streamAssistantChunk(alloc, &app.metrics, old_text.written()); for (0..3) |_| _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, history.items, "CONSOLIDATION_PROMPT")); const old_history = try alloc.dupe(u8, history.items); defer alloc.free(old_history); const before_mutation = try file.length(std.testing.io); for (ids) |id| { const index = for (app.shell.entries.items, 0..) |entry, index| { if (entry.id() == id) break index; } else return error.MissingConsolidationEntry; var removed = app.shell.entries.orderedRemove(index); removed.deinit(alloc); } const summary = try alloc.dupe(u8, "COMPACT_COMMAND_SUMMARY\n"); _ = try app.shell.appendRawBytesEntryClassified(alloc, summary, .unknown_raw); try app.shell.rebuildTranscriptCacheAfterStructuredRewrite(alloc, "command output consolidation"); try app.shell.writeTranscriptClassified(alloc, &app.metrics, "PERMISSION_ACCEPTED\n", true, .subagent_status); try std.testing.expectEqual(before_mutation, try file.length(std.testing.io)); try std.testing.expectEqualStrings(old_history, history.items); try std.testing.expect(std.mem.find(u8, app.shell.transcript_commit_state.stable.flow, "CONSOLIDATION_PROMPT") != null); var followup: std.Io.Writer.Allocating = .init(alloc); defer followup.deinit(); for (0..60) |index| try followup.writer.print("{d}. FOLLOWUP_TABLE_{d:0>2}\n", .{ index + 1, index }); _ = try app.shell.streamAssistantChunk(alloc, &app.metrics, followup.written()); try std.testing.expect(std.mem.find(u8, app.shell.transcript_commit_state.stable.flow, "FOLLOWUP_TABLE_") == null); var released: u32 = 0; for (0..4) |_| released += try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expect(released > 0); try std.testing.expect(std.mem.startsWith(u8, history.items, old_history)); const text = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(text); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, "CONSOLIDATION_PROMPT")); var previous = std.mem.find(u8, text, "CONSOLIDATION_PROMPT").?; for (0..18) |index| { var label_buffer: [48]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "CONSOLIDATION_OUTPUT_{d:0>2}", .{index}); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, label)); const at = std.mem.find(u8, text, label).?; try std.testing.expect(at > previous); previous = at; } for (0..84) |index| { var label_buffer: [48]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "{s}_TABLE_{d:0>2}", .{ if (index < 24) "OLD" else "FOLLOWUP", if (index < 24) index else index - 24 }); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, label)); const at = std.mem.find(u8, text, label).?; try std.testing.expect(at > previous); if ((index > 0 and index < 24) or index > 24) try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text[previous..at], "\n")); previous = at + label.len; } try std.testing.expect(std.mem.find(u8, text, "OLD_TABLE_23").? < std.mem.find(u8, text, "COMPACT_COMMAND_SUMMARY").?); try std.testing.expect(std.mem.find(u8, text, "COMPACT_COMMAND_SUMMARY").? < std.mem.find(u8, text, "PERMISSION_ACCEPTED").?); try std.testing.expect(std.mem.find(u8, text, "PERMISSION_ACCEPTED").? < std.mem.find(u8, text, "FOLLOWUP_TABLE_00").?); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, "COMPACT_COMMAND_SUMMARY")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, "PERMISSION_ACCEPTED")); try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); const quiet = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(quiet); try std.testing.expectEqualStrings(text, quiet);}
test "core.app_render_runtime paints a rebased terminal status after cancellation pin cleanup" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "cancel-publication.log", .{ .read = true }); defer file.close(std.testing.io); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .cols = 100, .rows = 30, .content_bottom = 26, .divider_top_row = 27, .input_row = 28, .divider_bottom_row = 29, .hint_row = 30 } }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); var physical = try vt_emulator.Grid.init(alloc, 100, 30); defer physical.deinit(); physical.defer_sync_updates = false; var history: std.ArrayList(u8) = .empty; defer history.deinit(alloc); var offset: u64 = 0; const id: types.ToolLifecycleId = .{ .turn_id = 1, .call_id = "call_mcp" }; _ = try app.shell.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "mcp_fixture_echo", .activity_kind = .command, } }); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expect(try app.shell.presentActiveToolCancellation(alloc)); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); const cancelled = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(cancelled); try std.testing.expect(std.mem.find(u8, cancelled, "Cancelled") != null); try std.testing.expect(std.mem.find(u8, cancelled, "Cancelled mcp_fixture_echo") == null);
_ = try app.shell.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .cancelled, .summary = "Cancelled mcp_fixture_echo" }, } }); _ = try app.shell.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = id.turn_id, .outcome = .interrupted, } }); try app.shell.finishLifecycleBatch(alloc); try std.testing.expect(!app.shell.transcript_commit_state.stable.flow_materialized); try std.testing.expectEqual(offset, try file.length(std.testing.io)); try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); const finished = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(finished); try std.testing.expect(std.mem.find(u8, finished, "Cancelled mcp_fixture_echo") != null); try std.testing.expect(app.shell.transcript_commit_state.stable.flow_materialized); try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); const quiet = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(quiet); try std.testing.expectEqualStrings(finished, quiet);}
test "core.app_render_runtime rebased notice preserves the pin and publishes the finished result" { try checkRebasedNoticePublication(80, 12); try checkRebasedNoticePublication(24, 10);}
fn checkRebasedNoticePublication(cols: u16, rows: u16) !void { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "notice-publication.log", .{ .read = true }); defer file.close(std.testing.io); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .cols = cols, .rows = rows, .content_bottom = rows - 4, .divider_top_row = rows - 3, .input_row = rows - 2, .divider_bottom_row = rows - 1, .hint_row = rows } }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); var physical = try vt_emulator.Grid.init(alloc, cols, rows); defer physical.deinit(); physical.defer_sync_updates = false; var history: std.ArrayList(u8) = .empty; defer history.deinit(alloc); var offset: u64 = 0; if (cols == 24) try app.input_runtime.textReplacementState().replace(alloc, "draft one\ndraft two\ndraft three\ndraft four"); for (0..4) |index| { var line: [48]u8 = undefined; _ = try app.shell.appendRawTranscriptEntry(alloc, try std.fmt.bufPrint(&line, "NOTICE_HISTORY_{d:0>2}\n", .{index})); _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); } _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); const notice_id = try app.shell.appendReplaceableSemanticNotice(alloc, .{ .topic = "feedback", .tone = .neutral, .body = "Preparing feedback report while external work is blocking", }); for (0..6) |index| { var line: [48]u8 = undefined; _ = try app.shell.appendRawTranscriptEntry(alloc, try std.fmt.bufPrint(&line, "NOTICE_LATER_{d:0>2}\n", .{index})); } _ = try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); const held = app.shell.transcriptCommitDiagnostic().history_visual_offset; var pinned = try app.shell.prepareTranscriptSource(alloc, null); defer pinned.deinit(alloc); try std.testing.expect(pinned.finality.mutation_pin_start != null); const blocked_history = try alloc.dupe(u8, history.items); defer alloc.free(blocked_history); for (0..3) |_| { try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); try std.testing.expectEqual(held, app.shell.transcriptCommitDiagnostic().history_visual_offset); try std.testing.expectEqualStrings(blocked_history, history.items); try std.testing.expect(std.mem.find(u8, history.items, "Preparing") == null); try std.testing.expect(std.mem.find(u8, history.items, "NOTICE_LATER_") == null); } const before_replacement = try file.length(std.testing.io); try std.testing.expect(try app.shell.replaceSemanticNotice(alloc, notice_id, .{ .topic = "feedback", .tone = .success, .body = "Feedback report ready", })); try std.testing.expectEqual(before_replacement, try file.length(std.testing.io)); try std.testing.expectEqualStrings(blocked_history, history.items); var finished = try app.shell.prepareTranscriptSource(alloc, null); defer finished.deinit(alloc); try std.testing.expect(finished.finality.mutation_pin_start == null); var released: u32 = 0; for (0..4) |_| released += try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset); try std.testing.expect(released > 0); const text = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(text); var previous: usize = 0; for (0..10) |index| { var label_buffer: [48]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "NOTICE_{s}_{d:0>2}", .{ if (index < 4) "HISTORY" else "LATER", if (index < 4) index else index - 4 }); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, label)); const at = std.mem.find(u8, text, label).?; try std.testing.expect(at >= previous); previous = at + label.len; } try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, "Feedback")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, text, "report ready")); try std.testing.expect(std.mem.find(u8, text, "Preparing") == null); try std.testing.expectEqual(@as(u32, 0), try flushRebasedPublicationFrame(&app, file, &physical, &history, &offset)); const quiet = try rewritePublicationText(alloc, &physical, history.items); defer alloc.free(quiet); try std.testing.expectEqualStrings(text, quiet);}
const RewritePublicationCase = enum { command_retention, status_retention, status_shrink, removed_conversation };
const PublicationRetry = struct { accepted_bytes: ?usize = null, mutate_before_frame: bool = false, mutate_before_retry: bool = false, resize_cols: ?u16 = null, drain: bool = false, drain_frames: usize = 24, update_status: bool = false, invalidate: bool = false, cancel: bool = false, viewer: bool = false, utf8: bool = false, reset: enum { none, clear, session_resume } = .none,};
const PublicationFaultSink = struct { file: std.Io.File, remaining: usize, calls: usize = 0, failed: bool = false, fn write(ctx: *anyopaque, _: *types.Metrics, bytes: []const u8) render_engine.terminal_diff.FrameSinkWriteResult { const self: *@This() = @ptrCast(@alignCast(ctx)); self.calls += 1; const count = if (self.failed) bytes.len else @min(self.remaining, bytes.len); var written: usize = 0; while (written < count) { const n = self.file.writeStreaming(std.testing.io, &.{}, &.{bytes[written..count]}, 1) catch return .{ .partial = .{ .accepted_bytes = written, .err = error.WriteFailed } }; if (n == 0) break; written += n; } if (!self.failed) self.remaining -= written; if (written == bytes.len) return .complete; self.failed = true; return .{ .partial = .{ .accepted_bytes = written, .err = error.WriteFailed } }; }};
fn checkRewritePublicationThroughCoordinator(case: RewritePublicationCase) !void { return checkRewritePublicationRetry(case, .{});}
fn checkRewritePublicationRetry(case: RewritePublicationCase, retry: PublicationRetry) !void { const store = @import("../../ui/transcript/store.zig"); const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "rewrite-publication.log", .{ .read = true }); defer file.close(std.testing.io); const rows: u16 = if (retry.utf8) 18 else 16; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = rows, .cols = 80, .content_bottom = rows - 4, .divider_top_row = rows - 3, .input_row = rows - 2, .divider_bottom_row = rows - 1, .hint_row = rows } }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); const prefix_id = try app.shell.appendRawTranscriptEntryClassified(alloc, ("\x1b[0m" ** 256) ++ ("prefix padding\n" ** 2), .subagent_status); const text = "1. earlier context\n2. earlier context\n3. earlier context\n4. earlier context\n5. RW_OLD_00\n6. RW_OLD_01\n7. RW_OLD_02\n8. RW_OLD_03\n9. RW_OLD_04\n10. RW_OLD_05\n\n"; const assistant_id = try app.shell.streamAssistantChunk(alloc, &app.metrics, if (retry.utf8) text ++ ("界é" ** 48) ++ "\n\nRW_ARTIFACTS\n" else text ++ "RW_ARTIFACTS\n"); const status_id = if (retry.cancel) blk: { const id: types.ToolLifecycleId = .{ .turn_id = 41, .call_id = "publication-cancel" }; _ = try app.shell.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command } }); break :blk app.shell.toolActivityRecord(id).?.entry_id; } else try store.appendPinnedToolStatusAtomic(&app.shell, alloc, "phase one\nphase two\nphase three\n"); const status_bytes = for (app.shell.entries.items) |entry| { if (entry.id() == status_id) break entry.raw_bytes.bytes.len; } else unreachable; var physical = try vt_emulator.Grid.init(alloc, 80, rows); defer physical.deinit(); physical.defer_sync_updates = false; var exported: std.ArrayList(u8) = .empty; defer exported.deinit(alloc); var read_offset: u64 = 0; app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const first = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(first); try feedRewritePublicationFrame(alloc, &physical, &exported, first); var initial_screen: std.ArrayList(u8) = .empty; defer initial_screen.deinit(alloc); try physical.snapshot(&initial_screen); for (0..6) |index| { var label_buffer: [32]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "RW_OLD_{d:0>2}", .{index}); const initial_count = std.mem.count(u8, exported.items, label) + std.mem.count(u8, initial_screen.items, label); if (initial_count != 1) std.debug.print("initial {s} {s} count={d}\nexported:\n{s}\nscreen:\n{s}\n", .{ @tagName(case), label, initial_count, exported.items, initial_screen.items }); try std.testing.expectEqual(@as(usize, 1), initial_count); } const before_text = try rewritePublicationText(alloc, &physical, exported.items); defer alloc.free(before_text); const before_gap_start = std.mem.find(u8, before_text, "RW_OLD_05").? + "RW_OLD_05".len; const gap_anchor = if (retry.utf8) "界" else "RW_ARTIFACTS"; if (retry.utf8) { try std.testing.expectEqual(@as(usize, 48), std.mem.count(u8, before_text, "界")); try std.testing.expectEqual(@as(usize, 48), std.mem.count(u8, before_text, "é")); var wrapped_rows: usize = 0; var lines = std.mem.splitScalar(u8, before_text, '\n'); while (lines.next()) |line| if (std.mem.find(u8, line, "界") != null) { wrapped_rows += 1; }; try std.testing.expect(wrapped_rows > 1); } const before_gap_end = std.mem.find(u8, before_text, gap_anchor).?; const before_gap = before_text[before_gap_start..before_gap_end]; try std.testing.expectEqual(@as(usize, 2), std.mem.count(u8, before_gap, "\n")); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, exported.items, "RW_OLD_00")); try std.testing.expectEqual(.stable, app.shell.transcriptCommitDiagnostic().state); try std.testing.expect(app.shell.transcriptCommitDiagnostic().history_visual_offset > 0); if (retry.viewer) { try std.testing.expectEqual(@as(usize, 0), app.shell.committedRetentionIdentity().?.publication_entries.len); try app_lifecycle.openFullTranscript(alloc, &app.terminal, &app.shell, &app.metrics); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const opened = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(opened); try feedRewritePublicationFrame(alloc, &physical, &exported, opened); try std.testing.expect(app.terminal.fullTranscriptScreenActive()); try std.testing.expect(physical.saved_normal_screen != null); } if (case != .status_shrink) app.shell.max_retained_transcript_bytes = store.retainedStructuredBytes(&app.shell); switch (case) { .command_retention => try app.shell.writeCommandOutputChunk(alloc, &app.metrics, .{}, .stdout, "NEW_COMMAND_OUTPUT\n", true), .status_retention => try std.testing.expect(try store.replacePinnedToolStatusAtomic(&app.shell, alloc, status_id, "phase replacement\nsecond phase\nthird phase\nfourth phase\nfifth phase\n")), .status_shrink => try std.testing.expect(try store.replacePinnedToolStatusAtomic(&app.shell, alloc, status_id, "ok\n")), .removed_conversation => { app.shell.max_retained_transcript_bytes = status_bytes + "NEW_NOTICE\n".len; if (retry.viewer) { try std.testing.expect(try store.replacePinnedToolStatusAtomic(&app.shell, alloc, status_id, "viewer status replacement\n")); } else { _ = try store.writeRecordedTranscriptClassifiedAtomic(&app.shell, alloc, &app.metrics, "NEW_NOTICE\n", .unknown_raw); } }, } const prefix_survives = for (app.shell.entries.items) |entry| { if (entry.id() == prefix_id) break true; } else false; try std.testing.expectEqual(case == .status_shrink, prefix_survives); try std.testing.expectEqual(case != .removed_conversation, app.shell.lookupAssistantSegments(assistant_id) != null); if (case == .status_retention) { app.stream.active = true; app.stream.phase = .running; } if (retry.viewer) { try std.testing.expect(app.terminal.fullTranscriptScreenActive()); try std.testing.expect(std.mem.findScalar(u32, app.shell.committedRetentionIdentity().?.publication_entries, assistant_id) != null); if (retry.resize_cols) |cols| { try physical.resize(cols, physical.rows); app.shell.layout.cols = cols; app.shell.render_requests.request(.resize); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); } try app_lifecycle.closeFullTranscript(alloc, &app.terminal, &app.shell, &app.metrics); const closed = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(closed); try feedRewritePublicationFrame(alloc, &physical, &exported, closed); try std.testing.expect(physical.saved_normal_screen == null); } if (retry.invalidate) { app.shell.invalidateTranscriptAnchor("external_projection_damage"); try std.testing.expect(app.shell.committedRetentionIdentity().?.publication_entries.len > 0); try app.shell.recordFrameInvalidation(.{ .reason = .external_clear, .top = app.shell.owned_top_row, .bottom = app.shell.layout.content_bottom }); try physical.feed("\x1b[2J"); } if (retry.reset != .none) { try std.testing.expect(app.shell.committedRetentionIdentity().?.publication_entries.len > 0); if (retry.reset == .clear) { app.shell.clearTranscript(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "RESET_SENTINEL\n", true); } else { var projection = try resume_projection.ResumeProjection.initEmpty(alloc, &app.shell, 0, 1); defer projection.deinit(); _ = try projection.appendRawClassified("RESET_SENTINEL\n", .unknown_raw); try projection.finalize(); projection.install(&app.shell); } try std.testing.expect(app.shell.committedRetentionIdentity() == null); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const frame = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(frame); try feedRewritePublicationFrame(alloc, &physical, &exported, frame); try std.testing.expect(try coordinatorGridContains(physical, "RESET_SENTINEL")); try std.testing.expect(!try coordinatorGridContains(physical, "RW_OLD_00")); return; } const publication_bound = app.shell.transcriptCommitDiagnostic().source_bytes + app.shell.max_retained_transcript_bytes; if (retry.update_status) { try std.testing.expect(try store.replacePinnedToolStatusAtomic(&app.shell, alloc, status_id, "phase new\nphase two\nphase end\n")); try std.testing.expectEqualStrings("phase new\nphase two\nphase end", store.toolStatusEntryLabel(&app.shell, status_id).?); try std.testing.expect(std.mem.findScalar(u32, app.shell.committedRetentionIdentity().?.publication_entries, status_id) == null); } if (retry.mutate_before_frame) { const held_bytes = app.shell.transcriptCommitDiagnostic().source_bytes; for (0..32) |_| { _ = try store.writeRecordedTranscriptClassifiedAtomic(&app.shell, alloc, &app.metrics, "P2\n", .unknown_raw); var committed = (try app.shell.prepareCommittedRetentionSource(alloc)).?; defer committed.deinit(alloc); try std.testing.expect(std.mem.find(u8, committed.bytes, "P2") == null); try std.testing.expectEqual(held_bytes, committed.bytes.len); try std.testing.expect(store.retainedStructuredBytes(&app.shell) <= app.shell.max_retained_transcript_bytes); } } if (retry.accepted_bytes) |cut| { const before_attempt = app.shell.transcriptCommitDiagnostic(); const exported_before_attempt = exported.items.len; var sink = PublicationFaultSink{ .file = file, .remaining = cut }; app.shell.test_frame_sink = .{ .ctx = &sink, .write_frame = PublicationFaultSink.write }; app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; Runtime(CoordinatorTestApp).flushRequestedFrame(&app) catch |err| { if (err != error.WriteFailed and err != error.DocumentAppendInterrupted) return err; }; app.shell.test_frame_sink = null; try std.testing.expect(sink.calls > 0 and sink.failed); const partial = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(partial); try feedRewritePublicationFrame(alloc, &physical, &exported, partial); if (cut == 0) try std.testing.expectEqual(before_attempt.history_visual_offset, app.shell.transcriptCommitDiagnostic().history_visual_offset); if (cut >= 64) { try std.testing.expect(app.shell.transcriptCommitDiagnostic().history_visual_offset > before_attempt.history_visual_offset); try std.testing.expect(exported.items.len > exported_before_attempt); } if (retry.cancel) { app.worker.cancel_requested = true; app.stream.active = false; _ = try app.shell.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 41, .outcome = .interrupted } }); try std.testing.expectEqual(.terminal, app.shell.toolActivityRecord(.{ .turn_id = 41, .call_id = "publication-cancel" }).?.phase); try app.shell.finishLifecycleBatch(alloc); try std.testing.expectEqual(@as(usize, 0), app.shell.lifecyclePinCount()); } if (retry.mutate_before_retry) _ = try store.writeRecordedTranscriptClassifiedAtomic(&app.shell, alloc, &app.metrics, "P3\n", .unknown_raw); if (cut == 0 and retry.mutate_before_retry) { var committed = (try app.shell.prepareCommittedRetentionSource(alloc)).?; defer committed.deinit(alloc); try std.testing.expect(std.mem.find(u8, committed.bytes, "NEW_NOTICE") == null); } } if (retry.resize_cols) |cols| { try physical.resize(cols, physical.rows); app.shell.layout.cols = cols; app.shell.render_requests.request(.resize); } for (0..8) |_| { app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const next = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(next); try feedRewritePublicationFrame(alloc, &physical, &exported, next); if (app.shell.transcript_commit_state == .stable and !app.shell.transcript_commit_state.stable.normal_buffer_recovery_pending and !app.shell.transcript_commit_state.stable.history_catchup_pending) break; } if (retry.drain) { const seen = try alloc.alloc(bool, retry.drain_frames); defer alloc.free(seen); @memset(seen, false); for (0..retry.drain_frames) |index| { var buffer: [32]u8 = undefined; const line = try std.fmt.bufPrint(&buffer, "N{d}\n", .{index}); _ = try store.writeRecordedTranscriptClassifiedAtomic(&app.shell, alloc, &app.metrics, line, .unknown_raw); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const next = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(next); try feedRewritePublicationFrame(alloc, &physical, &exported, next); const visible = try rewritePublicationText(alloc, &physical, exported.items); defer alloc.free(visible); for (0..index + 1) |prior| { var label_buffer: [32]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "N{d}", .{prior}); const count = publicationLineCount(visible, label); if (seen[prior] or count > 0) { try std.testing.expectEqual(@as(usize, 1), count); seen[prior] = true; } } try std.testing.expect(app.shell.transcriptCommitDiagnostic().source_bytes <= publication_bound); try std.testing.expect(store.retainedStructuredBytes(&app.shell) <= app.shell.max_retained_transcript_bytes); } try std.testing.expect(std.mem.findScalar(bool, seen, true) != null); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, exported.items, "RW_ARTIFACTS")); try std.testing.expect(std.mem.find(u8, exported.items, "phase one") == null); try std.testing.expect(std.mem.findScalar(u32, app.shell.committedRetentionIdentity().?.publication_entries, assistant_id) == null); } var screen: std.ArrayList(u8) = .empty; defer screen.deinit(alloc); try physical.snapshot(&screen); for (0..6) |index| { var label_buffer: [32]u8 = undefined; const label = try std.fmt.bufPrint(&label_buffer, "RW_OLD_{d:0>2}", .{index}); const count = std.mem.count(u8, exported.items, label) + std.mem.count(u8, screen.items, label); if (count != 1) std.debug.print("rewrite publication {s}: {s} count={d} cut={?d} resize={?d}\nexported:\n{s}\nscreen:\n{s}\n", .{ @tagName(case), label, count, retry.accepted_bytes, retry.resize_cols, exported.items, screen.items }); try std.testing.expectEqual(@as(usize, 1), count); } try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, exported.items, "RW_ARTIFACTS") + std.mem.count(u8, screen.items, "RW_ARTIFACTS")); const after_text = try rewritePublicationText(alloc, &physical, exported.items); defer alloc.free(after_text); const after_gap_start = std.mem.find(u8, after_text, "RW_OLD_05").? + "RW_OLD_05".len; const after_gap_end = std.mem.find(u8, after_text, gap_anchor).?; try std.testing.expectEqualStrings(before_gap, after_text[after_gap_start..after_gap_end]); if (retry.utf8) { try std.testing.expectEqual(@as(usize, 48), std.mem.count(u8, after_text, "界")); try std.testing.expectEqual(@as(usize, 48), std.mem.count(u8, after_text, "é")); const before_end = std.mem.findLast(u8, before_text, "é").? + "é".len; const after_end = std.mem.findLast(u8, after_text, "é").? + "é".len; try std.testing.expectEqualStrings(before_text[before_end..std.mem.find(u8, before_text, "RW_ARTIFACTS").?], after_text[after_end..std.mem.find(u8, after_text, "RW_ARTIFACTS").?]); }}
test "rewrite publication command retention preserves finalized rows through coordinator" { try checkRewritePublicationThroughCoordinator(.command_retention);}
test "rewrite publication lifecycle retention preserves finalized rows through coordinator" { try checkRewritePublicationThroughCoordinator(.status_retention);}
test "rewrite publication lifecycle shrink without pruning preserves finalized rows through coordinator" { try checkRewritePublicationThroughCoordinator(.status_shrink);}
test "rewrite publication exports pruned finalized conversation rows before replacement" { try checkRewritePublicationThroughCoordinator(.removed_conversation);}
test "rewrite publication retains finalized rows across mutations before the next frame" { try checkRewritePublicationRetry(.removed_conversation, .{ .mutate_before_frame = true, .drain = true });}
test "rewrite publication retries accepted prefixes without duplicating finalized rows" { for ([_]usize{ 0, 1, 16, 64, 128, 256 }) |cut| { errdefer std.debug.print("publication cut={d}\n", .{cut}); try checkRewritePublicationRetry(.removed_conversation, .{ .accepted_bytes = cut, .mutate_before_retry = true, .drain = true }); }}
test "rewrite publication pending rows survive width changes" { try checkRewritePublicationRetry(.removed_conversation, .{ .resize_cols = 60, .drain = true }); try checkRewritePublicationRetry(.removed_conversation, .{ .accepted_bytes = 64, .mutate_before_retry = true, .resize_cols = 100, .drain = true });}
test "rewrite publication cancellation follows accepted export without losing finalized rows" { try checkRewritePublicationRetry(.removed_conversation, .{ .cancel = true, .accepted_bytes = 64, .mutate_before_retry = true, .drain = true });}
test "rewrite publication first retirement survives the full transcript owner" { try checkRewritePublicationRetry(.removed_conversation, .{ .viewer = true, .drain = true }); try checkRewritePublicationRetry(.removed_conversation, .{ .viewer = true, .resize_cols = 100, .drain = true });}
test "rewrite publication preserves wrapped UTF8 through pending resize" { try checkRewritePublicationRetry(.removed_conversation, .{ .utf8 = true, .resize_cols = 40, .drain = true });}
test "rewrite publication survives generic projection invalidation" { try checkRewritePublicationRetry(.removed_conversation, .{ .invalidate = true, .drain = true });}
test "rewrite publication remains bounded while status stays mutable" { try checkRewritePublicationRetry(.removed_conversation, .{ .update_status = true, .drain = true, .drain_frames = 96 });}
test "rewrite publication does not delay explicit clear or resume" { try checkRewritePublicationRetry(.removed_conversation, .{ .reset = .clear }); try checkRewritePublicationRetry(.removed_conversation, .{ .reset = .session_resume });}
test "core.app_render_runtime resume publication preserves the pre-scroll origin through the coordinator" { const alloc = std.testing.allocator; const cases = [_]struct { origin: u16, rows: u16, post_top: u16 }{ .{ .origin = 1, .rows = 3, .post_top = 1 }, .{ .origin = 5, .rows = 3, .post_top = 5 }, .{ .origin = 5, .rows = 6, .post_top = 4 }, .{ .origin = 8, .rows = 6, .post_top = 4 }, .{ .origin = 1, .rows = 12, .post_top = 1 }, .{ .origin = 5, .rows = 12, .post_top = 1 }, .{ .origin = 1, .rows = 80, .post_top = 1 }, .{ .origin = 5, .rows = 80, .post_top = 1 }, }; for (cases) |case| { errdefer std.debug.panic("resume origin={d} rows={d}", .{ case.origin, case.rows }); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "resume-origin.log", .{ .read = true }); defer file.close(std.testing.io); var app = try initCoordinatorProjectionTestApp(alloc, file); defer app.deinit(); app.terminal_client.source_running = false; try app.shell.initViewport(&app.metrics, case.origin);
var projection = try resume_projection.ResumeProjection.initEmpty(alloc, &app.shell, 0, 1); defer projection.deinit(); var flow: std.ArrayList(u8) = .empty; defer flow.deinit(alloc); for (0..case.rows) |i| { var buf: [32]u8 = undefined; try flow.appendSlice(alloc, try std.fmt.bufPrint( &buf, "{s}ORIGIN_ROW_{d:0>3}", .{ if (i == 0) "" else "\n", i }, )); } _ = try projection.appendRawClassified(flow.items, .unknown_raw); try projection.finalize(); projection.install(&app.shell); try std.testing.expectEqual(.invalid, app.shell.transcriptCommitDiagnostic().state); var read_offset = try file.length(std.testing.io);
// Interrupt actual preparation, not the coordinator's synthetic receipt stub. app.terminal_input_runtime.terminal_action_decoder.stage = 2; app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(read_offset, try file.length(std.testing.io)); try std.testing.expectEqual(case.origin, app.shell.owned_top_row); try std.testing.expectEqual(.invalid, app.shell.transcriptCommitDiagnostic().state); try std.testing.expect(app.shell.pending_resume_source != null); try std.testing.expect(app.shell.render_requests.hasPending()); app.terminal_input_runtime.resetEscapeDecoder();
// A unit-test stdin can be closed; suppress that unrelated poll on retries. app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const first = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(first); const document_start = std.mem.find(u8, first, "ORIGIN_ROW_000") orelse return error.MissingResumeDocument; var physical = try vt_emulator.Grid.init(alloc, 80, 12); defer physical.deinit(); if (case.rows > 9) { var origin_buf: [32]u8 = undefined; const origin = try std.fmt.bufPrint(&origin_buf, "\x1b[{d};1H", .{case.origin}); try std.testing.expect(std.mem.find(u8, first[0..document_start], origin) != null); } var first_stats: vt_emulator.FeedStats = .{}; try physical.feedWithStats(first, &first_stats); var physical_scroll_rows = first_stats.scroll_rows; try std.testing.expectEqual(case.post_top, app.shell.owned_top_row); try std.testing.expectEqual(case.post_top, app.shell.committed_frame_layout.transcript_area.top);
const history_rows: u32 = case.rows -| 9; const first_history = @min(history_rows, 64); const diagnostic = app.shell.transcriptCommitDiagnostic(); if (history_rows > 64) { try std.testing.expectEqual(first_history, diagnostic.history_visual_offset); try std.testing.expectEqual(history_rows - first_history, diagnostic.remaining_inline_rows); } try std.testing.expectEqual(@as(u16, 0), diagnostic.remaining_unplanned_scroll_rows); var row: std.ArrayList(u8) = .empty; defer row.deinit(alloc); try physical.rowTextTrimmed(case.post_top, &row); var expected_buf: [32]u8 = undefined; try std.testing.expectEqualStrings(try std.fmt.bufPrint(&expected_buf, "ORIGIN_ROW_{d:0>3}", .{first_history}), row.items);
if (history_rows > 64) { try std.testing.expectEqual(.recovering, diagnostic.state); const receipt = app.shell.transcript_commit_state.recovering; try std.testing.expect(receipt.materialized_flow_len != null); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const next = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(next); // Recovery continues the materialized suffix instead of replaying row zero. try std.testing.expect(std.mem.find(u8, next, "ORIGIN_ROW_000") == null); const suffix_start = std.mem.find(u8, next, "ORIGIN_ROW_") orelse return error.MissingResumeSuffix; var receipt_cursor_buf: [32]u8 = undefined; const receipt_cursor = try std.fmt.bufPrint(&receipt_cursor_buf, "\x1b[{d};{d}H", .{ receipt.cursor_row, receipt.cursor_col }); try std.testing.expect(std.mem.find(u8, next[0..suffix_start], receipt_cursor) != null); var next_stats: vt_emulator.FeedStats = .{}; try physical.feedWithStats(next, &next_stats); physical_scroll_rows += next_stats.scroll_rows; row.clearRetainingCapacity(); try physical.rowTextTrimmed(case.post_top, &row); try std.testing.expectEqualStrings(try std.fmt.bufPrint(&expected_buf, "ORIGIN_ROW_{d:0>3}", .{history_rows}), row.items); try std.testing.expectEqual(@as(u32, 0), app.shell.transcriptCommitDiagnostic().remaining_inline_rows); } for (0..3) |_| { app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); } try std.testing.expectEqual(.stable, app.shell.transcriptCommitDiagnostic().state); try std.testing.expectEqual(history_rows, app.shell.transcriptCommitDiagnostic().history_visual_offset); try std.testing.expectEqual(history_rows + case.origin - case.post_top, physical_scroll_rows); try std.testing.expect(app.shell.pending_resume_source == null); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, try std.fmt.bufPrint(&expected_buf, "ORIGIN_ROW_{d:0>3}", .{case.rows - 1})));
const anchor = app.shell.transcript_commit_state.stable; read_offset = try file.length(std.testing.io); try app.shell.writeTranscript(alloc, &app.metrics, "\nAFTER_RESUME", true); app.shell.render_requests.request(.transcript); app.shell.render_requests.consecutive_input_pending_aborts = render_request.max_consecutive_input_pending_aborts; try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const appended = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(appended); var cursor_buf: [32]u8 = undefined; const append_cursor = try std.fmt.bufPrint(&cursor_buf, "\x1b[{d};{d}H", .{ anchor.cursor_row, anchor.cursor_col }); if (history_rows > 0) { const suffix_start = std.mem.find(u8, appended, "AFTER_RESUME") orelse return error.MissingAppend; try std.testing.expect(std.mem.find(u8, appended[0..suffix_start], append_cursor) != null); } try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "AFTER_RESUME")); }}
test "core.app_render_runtime first requested startup frame commits through the ordinary coordinator" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "first-startup-frame.log", .{ .read = true }); defer file.close(io_mod.getIo());
const layout: types.Layout = .{ .rows = 12, .cols = 64, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = layout, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "startup frame content\n", true);
app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(app.shell.has_committed_frame); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "startup frame content")); const first_len = try file.length(io_mod.getIo()); try std.testing.expect(first_len > 0);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(first_len, try file.length(io_mod.getIo()));}
test "core.app_render_runtime main skill menu origins share the inline footer" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "skills-screen.log", .{ .read = true }); defer file.close(io_mod.getIo());
const skills = [_]skill_runtime.Skill{.{ .name = "pure-core", .description = "Keep data transformations pure.", .path = "/skills/pure-core/SKILL.md", .source = .global_fx, }}; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 14, .cols = 72, .content_bottom = 10, .divider_top_row = 11, .input_row = 12, .divider_bottom_row = 13, .hint_row = 14, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.input_runtime.edit_state.input.appendSlice(alloc, "$pure"); app.input_runtime.edit_state.cursor = app.input_runtime.edit_state.input.items.len; app.skills.items = @constCast(&skills); app.skills.openMenuWithQuery(.dollar, .{ .start = 0, .end = app.input_runtime.edit_state.input.items.len }, "pure"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "transcript stays visible behind the picker\n", true);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "$pure")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "pure-core")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "transcript stays visible"));
try std.testing.expect(try app.approval_prompt.syncRequest(alloc, .{ .id = 42, .label = "web_search latest Zig release", })); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "Would you like to allow this action?", ));
app.approval_prompt.clear(alloc); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Skills 1"));
const options = [_]types.QuestionOption{ .{ .label = "Inspect repo state", .description = null }, .{ .label = "Keep going", .description = null }, }; const entries = [_]types.QuestionBatchEntry{ .{ .question = "What should fx do next?", .options = &options }, }; try app.question_prompt.syncFrom(alloc, &entries); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Inspect repo state"));
app.question_prompt.discard(alloc, "test_cleanup"); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Skills 1"));
try app.shell.writeTranscript(alloc, &app.metrics, "background transcript update\n", true); app.shell.render_requests.request(.transcript); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "background transcript update"));
app.shell.layout = .{ .rows = 10, .cols = 48, .content_bottom = 6, .divider_top_row = 7, .input_row = 8, .divider_bottom_row = 9, .hint_row = 10, }; app.shell.render_requests.request(.resize); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expectEqual(@as(u16, 48), app.shell.shadow_vt.?.cols); try std.testing.expectEqual(@as(u16, 10), app.shell.shadow_vt.?.rows); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "pure-core"));
app.skills.closeMenu(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "transcript stays visible")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "background transcript update"));
app.skills.openMenu(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "pure-core")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "transcript stays visible"));
app.skills.closeMenu(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive());
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049h")); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"));}
test "core.app_render_runtime settings help and resume menus share the inline footer" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "inline-catalog-menus.log", .{ .read = true }); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 100, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "catalog transcript remains visible\n", true);
app.input_runtime.settings_menu.open(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "catalog transcript remains visible")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Settings"));
app.input_runtime.settings_menu.close(); app.input_runtime.help_menu.open(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "catalog transcript remains visible")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Commands 1"));
app.input_runtime.help_menu.close(); app.session_persistence.session_picker.active = true; app.session_persistence.session_picker.load_state = .loading; app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "catalog transcript remains visible")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Loading sessions"));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049h")); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"));}
test "core.app_render_runtime roomy resume footer paints twenty VT session rows" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "resume-twenty-inline.log", .{ .read = true }); defer file.close(io_mod.getIo());
var summaries: [25]@import("../session/session_store.zig").SessionSummary = undefined; for (&summaries) |*summary| { summary.* = .{ .id = @constCast("session-id"), .workspace_root = @constCast("/workspace"), .title = @constCast("Responsive session title"), .created_at_ms = 1, .updated_at_ms = 1, .conversation_language = .literal("en"), .history_len = 1, }; } var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 32, .cols = 120, .content_bottom = 28, .divider_top_row = 29, .input_row = 30, .divider_bottom_row = 31, .hint_row = 32, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); app.session_persistence.session_picker.active = true; app.session_persistence.session_picker.load_state = .ready; app.session_persistence.session_picker.summaries.items = summaries[0..]; try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "twenty-row transcript remains visible\n", true);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
var matching_rows: usize = 0; var row_text_buf: std.ArrayList(u8) = .empty; defer row_text_buf.deinit(alloc); var row: u16 = 1; while (row <= app.shell.shadow_vt.?.rows) : (row += 1) { row_text_buf.clearRetainingCapacity(); try app.shell.shadow_vt.?.rowTextTrimmed(row, &row_text_buf); if (std.mem.find(u8, row_text_buf.items, "Responsive session title") != null) { matching_rows += 1; } } try std.testing.expectEqual(@as(usize, 20), matching_rows); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "twenty-row transcript remains visible")); try std.testing.expect(!app.terminal.catalogMenuScreenActive());
app.session_persistence.session_picker.active = false; app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Responsive session title"))); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "twenty-row transcript remains visible"));}
test "core.app_render_runtime inline menus survive the VT size and resize matrix" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "inline-menu-size-matrix.log", .{ .read = true }); defer file.close(io_mod.getIo());
const skills = [_]skill_runtime.Skill{ .{ .name = "one", .description = "", .path = "/skills/one/SKILL.md", .source = .global_fx }, .{ .name = "two", .description = "", .path = "/skills/two/SKILL.md", .source = .global_fx }, .{ .name = "three", .description = "", .path = "/skills/three/SKILL.md", .source = .global_fx }, .{ .name = "four", .description = "", .path = "/skills/four/SKILL.md", .source = .global_fx }, .{ .name = "five", .description = "", .path = "/skills/five/SKILL.md", .source = .global_fx }, .{ .name = "six", .description = "", .path = "/skills/six/SKILL.md", .source = .global_fx }, .{ .name = "seven", .description = "", .path = "/skills/seven/SKILL.md", .source = .global_fx }, }; var summaries: [25]@import("../session/session_store.zig").SessionSummary = undefined; for (&summaries) |*summary| { summary.* = .{ .id = @constCast("session-id"), .workspace_root = @constCast("/workspace"), .title = @constCast("Responsive session title"), .created_at_ms = 1, .updated_at_ms = 1, .conversation_language = .literal("en"), .history_len = 1, }; }
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 100, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); app.skills.items = @constCast(&skills); app.session_persistence.session_picker.summaries.items = summaries[0..]; app.session_persistence.session_picker.load_state = .ready; app.session_persistence.session_picker.has_more = true; for (0..25) |index| { const id = if (index == 24) "provider/selected-model" else "provider/model"; try app.model_cache.menu.items.append(alloc, .{ .id = try alloc.dupe(u8, id), .provider = "provider", .capabilities = .{}, }); } app.model_cache.menu.load_state = .ready; app.model_cache.menu.selected_index = 24; try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "inline menu matrix transcript\n", true);
const MenuKind = enum { slash, skills, settings, help, sessions, models }; const menu_cases = [_]struct { kind: MenuKind, visible_text: []const u8, }{ .{ .kind = .slash, .visible_text = "/help" }, .{ .kind = .skills, .visible_text = "one" }, .{ .kind = .settings, .visible_text = "Status line context" }, .{ .kind = .help, .visible_text = "/help" }, .{ .kind = .sessions, .visible_text = "Responsive" }, .{ .kind = .models, .visible_text = "selected-model" }, }; const geometries = [_]struct { cols: u16, rows: u16 }{ .{ .cols = 40, .rows = 6 }, .{ .cols = 60, .rows = 12 }, .{ .cols = 100, .rows = 24 }, .{ .cols = 140, .rows = 32 }, .{ .cols = 220, .rows = 60 }, .{ .cols = 60, .rows = 12 }, .{ .cols = 100, .rows = 24 }, };
for (menu_cases) |menu_case| { app.skills.closeMenu(); app.input_runtime.settings_menu.close(); app.input_runtime.help_menu.close(); app.session_persistence.session_picker.active = false; app.model_cache.menu.active = false; try app.input_runtime.textReplacementState().replace(alloc, ""); switch (menu_case.kind) { .slash => try app.input_runtime.textReplacementState().replace(alloc, "/"), .skills => app.skills.openMenu(), .settings => app.input_runtime.settings_menu.open(), .help => app.input_runtime.help_menu.open(), .sessions => app.session_persistence.session_picker.active = true, .models => app.model_cache.menu.active = true, }
for (geometries) |geometry| { app.shell.layout = .{ .rows = geometry.rows, .cols = geometry.cols, .content_bottom = geometry.rows -| 4, .divider_top_row = geometry.rows -| 3, .input_row = geometry.rows -| 2, .divider_bottom_row = geometry.rows -| 1, .hint_row = geometry.rows, }; app.shell.render_requests.request(.resize); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(geometry.cols, app.shell.shadow_vt.?.cols); try std.testing.expectEqual(geometry.rows, app.shell.shadow_vt.?.rows); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, menu_case.visible_text)); try std.testing.expect(app.shell.footer_viewport.geometry.top >= 1); try std.testing.expect(app.shell.footer_viewport.geometry.hint <= geometry.rows); if (geometry.rows >= 12) { try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "inline menu matrix transcript")); } } }
app.skills.closeMenu(); app.input_runtime.settings_menu.close(); app.input_runtime.help_menu.close(); app.session_persistence.session_picker.active = false; app.model_cache.menu.active = false; try app.input_runtime.textReplacementState().replace(alloc, ""); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(@as(u16, 0), app.shell.extra_input_rows); try std.testing.expect(!(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Responsive session title"))); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "inline menu matrix transcript"));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049h")); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"));}
test "core.app_render_runtime active setup hub stays on the inline transcript surface" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "setup-inline.log", .{ .read = true }); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 18, .cols = 90, .content_bottom = 14, .divider_top_row = 15, .input_row = 16, .divider_bottom_row = 17, .hint_row = 18, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); app.auth.openPicker(alloc); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "setup transcript stays behind\n", true);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Setup")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Connections")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Credential source")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "enter open")); try std.testing.expect(!(try coordinatorGridContains(app.shell.shadow_vt.?.*, "test-model"))); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "setup transcript stays behind"));
app.auth.closePicker(alloc); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "setup transcript stays behind")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "test-model"));}
test "core.app_render_runtime inline model catalog survives modal preemption and close" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "models-screen.log", .{ .read = true }); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 14, .cols = 72, .content_bottom = 10, .divider_top_row = 11, .input_row = 12, .divider_bottom_row = 13, .hint_row = 14, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "current/model"); app.model_cache.menu.active = true; app.model_cache.menu.load_state = .loading; try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "model catalog transcript stays behind\n", true);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Models 0")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Loading models")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "model catalog transcript stays behind"));
try std.testing.expect(try app.approval_prompt.syncRequest(alloc, .{ .id = 84, .label = "web_search latest model metadata", })); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Would you like to allow this action?"));
app.approval_prompt.clear(alloc); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Loading models"));
app.model_cache.closeMenu(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "model catalog transcript stays behind"));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049h")); try std.testing.expectEqual(@as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"));}
test "core.app_render_runtime file approval returns to the preserved inline skills menu" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "skills-file-approval.log", .{ .read = true }); defer file.close(io_mod.getIo());
const skills = [_]skill_runtime.Skill{.{ .name = "pure-core", .description = "Keep data transformations pure.", .path = "/skills/pure-core/SKILL.md", .source = .global_fx, }}; const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .addition, .new_line = 1, .text = "after" }, }; const request: permission_request.PermissionRequest = .{ .id = 44, .label = "write_file note.txt", .file = .{ .kind = .write, .intent = .mutation, .preview = .{ .path = "note.txt", .lines = &preview_lines, .additions = 1, .deletions = 0, .truncated = false, }, .scope = .workspace_files, }, }; var review = try diff_mod.FileReview.init(alloc, "", "after\n"); defer review.deinit(alloc); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 14, .cols = 72, .content_bottom = 10, .divider_top_row = 11, .input_row = 12, .divider_bottom_row = 13, .hint_row = 14, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.input_runtime.edit_state.input.appendSlice(alloc, "$pure"); app.input_runtime.edit_state.cursor = app.input_runtime.edit_state.input.items.len; app.skills.items = @constCast(&skills); app.skills.openMenuWithQuery(.dollar, .{ .start = 0, .end = app.input_runtime.edit_state.input.items.len }, "pure"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "transcript behind inline skills\n", true);
app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(!app.terminal.catalogMenuScreenActive());
try std.testing.expect(try app.approval_prompt.syncRequest(alloc, request)); try std.testing.expect(app.approval_prompt.syncReview(&review)); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(shell_runtime.AlternateScreenOwner.file_approval, app.terminal.alternate_screen_owner); try std.testing.expectEqualStrings("$pure", app.input_runtime.edit_state.input.items); try std.testing.expectEqualStrings("pure", app.skills.menu.query());
app.approval_prompt.clear(alloc); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(shell_runtime.AlternateScreenOwner.none, app.terminal.alternate_screen_owner); try std.testing.expectEqualStrings("$pure", app.input_runtime.edit_state.input.items); try std.testing.expectEqualStrings("pure", app.skills.menu.query()); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "Skills 1")); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "transcript behind inline skills"));
app.skills.closeMenu(); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expectEqual(shell_runtime.AlternateScreenOwner.none, app.terminal.alternate_screen_owner); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "transcript behind inline skills"));}
test "core.app_render_runtime file approvals commit the alternate screen for each request" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "identity-only-modal.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .deletion, .old_line = 2, .text = "before", }, .{ .op = .addition, .new_line = 2, .text = "after", }, }; const request_a: permission_request.PermissionRequest = .{ .id = 41, .label = "file_mutation", .file = .{ .kind = .edit, .intent = .mutation, .preview = .{ .path = "note.txt", .lines = &preview_lines, .additions = 1, .deletions = 1, .truncated = false, }, .scope = .workspace_files, }, }; var review = try diff_mod.FileReview.init(alloc, "before\n", "after\n"); defer review.deinit(alloc); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try std.testing.expect(try app.approval_prompt.syncRequest( alloc, request_a, )); try std.testing.expect(app.approval_prompt.syncReview(&review));
app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const first_len = try file.length(io_mod.getIo()); try std.testing.expect(first_len > 0); try std.testing.expect(app.terminal.fileApprovalScreenActive()); try std.testing.expect(!app.approval_screen.screen_commit.?.document_scrollable); try std.testing.expect(app.terminal.alternate_mouse_tracking_active); try std.testing.expect(approval_screen.fileApprovalAffirmativeReady( &app.shell, app.approval_prompt.projection().?, &app.approval_screen, )); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "after"));
app.shell.layout.rows = 20; app.shell.layout.cols = 80; app.shell.render_requests.request(.resize); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const resized_len = try file.length(io_mod.getIo()); try std.testing.expect(resized_len > first_len); try std.testing.expectEqual(@as(u16, 80), app.shell.shadow_vt.?.cols); try std.testing.expectEqual(@as(u16, 20), app.shell.shadow_vt.?.rows); try std.testing.expect(approval_screen.fileApprovalAffirmativeReady( &app.shell, app.approval_prompt.projection().?, &app.approval_screen, ));
var request_b = request_a; request_b.id = 42; try std.testing.expect(try app.approval_prompt.syncRequest( alloc, request_b, )); try std.testing.expect(app.approval_prompt.syncReview(&review)); app.shell.render_requests.request(.modal); try std.testing.expect(!approval_screen.fileApprovalAffirmativeReady( &app.shell, app.approval_prompt.projection().?, &app.approval_screen, ));
try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect((try file.length(io_mod.getIo())) > resized_len); try std.testing.expect(!app.shell.render_requests.hasPending()); try std.testing.expect(approval_screen.fileApprovalAffirmativeReady( &app.shell, app.approval_prompt.projection().?, &app.approval_screen, )); try std.testing.expectEqual(@as(u64, 42), app.approval_screen.screen_commit.?.request_id); try std.testing.expect(app.terminal.fileApprovalScreenActive()); try std.testing.expect(app.terminal.alternate_mouse_tracking_active);
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime restores file review before rendering a generic approval inline" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "file-to-generic-approval.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .addition, .new_line = 1, .text = "after" }, }; const file_request: permission_request.PermissionRequest = .{ .id = 41, .label = "file_mutation", .file = .{ .kind = .edit, .intent = .mutation, .preview = .{ .path = "note.txt", .lines = &preview_lines, .additions = 1, .deletions = 0, .truncated = false, }, .scope = .workspace_files, }, }; const generic_request: permission_request.PermissionRequest = .{ .id = 42, .label = "web_search latest Zig release", }; var review = try diff_mod.FileReview.init(alloc, "", "after\n"); defer review.deinit(alloc); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try std.testing.expect(try app.approval_prompt.syncRequest(alloc, file_request)); try std.testing.expect(app.approval_prompt.syncReview(&review));
app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(app.terminal.fileApprovalScreenActive()); try std.testing.expect(app.terminal.alternate_mouse_tracking_active);
try std.testing.expect(try app.approval_prompt.syncRequest(alloc, generic_request)); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fileApprovalScreenActive()); try std.testing.expect(!app.terminal.alternate_mouse_tracking_active); try std.testing.expect(!app.shell.render_requests.hasReason(.external_damage)); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "Would you like to allow this action?", ));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime generic approval exits the full transcript screen before rendering inline" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "full-transcript-to-generic-approval.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "prior transcript\n", true); try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics);
try std.testing.expect(try app.approval_prompt.syncRequest(alloc, .{ .id = 42, .label = "shell.run sh -c 'printf approval'", })); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fullTranscriptScreenActive()); try std.testing.expect(!app.shell.fullTranscriptActive()); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "Would you like to run the following command?", ));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime question prompt exits the full transcript screen before rendering inline" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "full-transcript-to-question.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "prior transcript\n", true); try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics);
const options = [_]types.QuestionOption{ .{ .label = "Inspect repo state", .description = null }, .{ .label = "Keep going", .description = null }, }; const entries = [_]types.QuestionBatchEntry{ .{ .question = "What should fx do next?", .options = &options }, }; try app.question_prompt.syncFrom(alloc, &entries);
app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fullTranscriptScreenActive()); try std.testing.expect(!app.shell.fullTranscriptActive()); try std.testing.expect(app.shell.has_committed_frame); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "Inspect repo state", ));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime file approval takes over the full transcript alternate screen" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "full-transcript-to-file-approval.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .addition, .new_line = 1, .text = "after" }, }; const request: permission_request.PermissionRequest = .{ .id = 43, .label = "write_file note.txt", .file = .{ .kind = .write, .intent = .mutation, .preview = .{ .path = "note.txt", .lines = &preview_lines, .additions = 1, .deletions = 0, .truncated = false, }, .scope = .workspace_files, }, }; var review = try diff_mod.FileReview.init(alloc, "", "after\n"); defer review.deinit(alloc); var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "prior transcript\n", true); try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); try std.testing.expect(try app.approval_prompt.syncRequest(alloc, request)); try std.testing.expect(app.approval_prompt.syncReview(&review));
app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fullTranscriptScreenActive()); try std.testing.expect(app.terminal.fileApprovalScreenActive()); try std.testing.expect(!app.shell.fullTranscriptActive()); try std.testing.expect(approval_screen.fileApprovalAffirmativeReady( &app.shell, app.approval_prompt.projection().?, &app.approval_screen, )); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "after"));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime lifecycle rewrite recovers normal buffer after file rejection" { const approval_input_runtime = @import("input_approval_runtime.zig"); const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "lifecycle-rewrite-file-rejection.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc);
try app.shell.writeTranscript(alloc, &app.metrics, "setup sentinel\n", true); const lifecycle_id = types.ToolLifecycleId{ .turn_id = 1, .call_id = "streaming-command" }; _ = try app.shell.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycle_id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"stream\"}", } }); try app.shell.writeTranscript( alloc, &app.metrics, "retained assistant history\n" ** 64, true, ); app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const committed_before = app.shell.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, committed_before.state, ); try std.testing.expect((committed_before.stable_start_line orelse 0) > 0);
try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try app.shell.writeTranscript(alloc, &app.metrics, "stream completed\n", true); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); _ = try shell_runtime.applyToolLifecyclePreservingNormalBufferAnchor( alloc, &app.shell, .{ .terminal = .{ .id = lifecycle_id, .outcome = .{ .kind = .completed, .summary = "Streaming command completed" }, .result = "stream completed", } }, ); const state_after_rewrite = app.shell.transcriptCommitDiagnostic().state;
const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .addition, .new_line = 1, .text = "pending" }, }; const request: permission_request.PermissionRequest = .{ .id = 72, .label = "write_file pending.txt", .file = .{ .kind = .write, .intent = .mutation, .preview = .{ .path = "pending.txt", .lines = &preview_lines, .additions = 1, .deletions = 0, .truncated = false, }, .scope = .workspace_files, }, }; var review = try diff_mod.FileReview.init(alloc, "", "pending\n"); defer review.deinit(alloc); try std.testing.expect(try app.approval_prompt.syncRequest(alloc, request)); try std.testing.expect(app.approval_prompt.syncReview(&review)); app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(app.terminal.fileApprovalScreenActive());
try std.testing.expect(try approval_input_runtime.ApprovalRuntime(CoordinatorTestApp).handlePermissionAction( &app, .{ .number = 2 }, )); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expectEqual(types.ToolPermissionDecision.deny, app.worker.submitted_permission.?); try std.testing.expect(!app.terminal.fileApprovalScreenActive()); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, state_after_rewrite, ); try std.testing.expect(try coordinatorGridContains(app.shell.shadow_vt.?.*, "stream completed"));}
test "core.app_render_runtime full transcript defers repaint until its page is ready" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "full-transcript-deferred-frame.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript( alloc, &app.metrics, ("historical transcript row\n" ** 512) ++ "FULL_ASYNC_SENTINEL\n", true, ); app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!try coordinatorGridContains( app.shell.shadow_vt.?.*, "Preparing full detail", ));
for (0..100_000) |_| { _ = try app.shell.pollFullTranscriptPageLoad(); if (app.shell.fullTranscriptPreparedForOpen()) break; std.Thread.yield() catch std.atomic.spinLoopHint(); } try std.testing.expect(app.shell.fullTranscriptPreparedForOpen()); app.shell.render_requests.request(.transcript); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "FULL_ASYNC_SENTINEL", ));}
test "core.app_render_runtime full transcript resize defers history reset until primary restoration" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "full-transcript-changed-resize-recovery.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc);
try app.shell.writeTranscript( alloc, &app.metrics, "old primary history\n" ** 256, true, ); app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); app.shell.layout = .{ .rows = 18, .cols = 72, .content_bottom = 14, .divider_top_row = 15, .input_row = 16, .divider_bottom_row = 17, .hint_row = 18, }; try app.shell.requestTerminalResetAfterResize(&app.metrics, null); var read_offset = try file.length(io_mod.getIo()); try app.shell.writeTranscript( alloc, &app.metrics, "new output while review is open\n", true, ); for (0..100_000) |_| { try app.shell.prewarmFullTranscriptPage(null, null); _ = try app.shell.pollFullTranscriptPageLoad(); if (app.shell.fullTranscriptPreparedForOpen()) break; std.Thread.yield() catch std.atomic.spinLoopHint(); } try std.testing.expect(app.shell.fullTranscriptPreparedForOpen()); app.shell.render_requests.request(.transcript); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const resize_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(resize_bytes); try std.testing.expect(app.terminal.fullTranscriptScreenActive()); try std.testing.expect(resize_bytes.len > 0); try std.testing.expect(std.mem.find(u8, resize_bytes, "\x1b[3J") == null);
try app_lifecycle.closeFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const close_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(close_bytes);
try std.testing.expect(std.mem.find(u8, close_bytes, "\x1b[3J") != null); try std.testing.expect(close_bytes.len < 16 * 1024); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "new output while review is open", )); try std.testing.expect(!app.shell.terminal_reset_pending); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, app.shell.transcriptCommitDiagnostic().state, );}
test "core.app_render_runtime exits terminal-only full transcript state before normal render" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "terminal-only-full-transcript.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try app.shell.writeTranscript(alloc, &app.metrics, "prior transcript\n", true); try app_lifecycle.openFullTranscript(app.alloc, &app.terminal, &app.shell, &app.metrics); app.shell.closeFullTranscriptState(); try std.testing.expect(app.terminal.fullTranscriptScreenActive()); try std.testing.expect(!app.shell.fullTranscriptActive());
app.shell.render_requests.request(.transcript); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fullTranscriptScreenActive()); try std.testing.expect(!app.shell.fullTranscriptActive()); try std.testing.expect(try coordinatorGridContains( app.shell.shadow_vt.?.*, "prior transcript", ));
var read_offset: u64 = 0; const terminal_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(terminal_bytes); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049h"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, terminal_bytes, "\x1b[?1049l"), );}
test "core.app_render_runtime approval screen failure denies after leaving alternate mode" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile( std.testing.io, "approval-screen-failure.log", .{ .read = true }, ); defer file.close(io_mod.getIo());
const preview_lines = [_]diff_mod.PreviewLine{ .{ .op = .addition, .new_line = 1, .text = "after" }, }; const request: permission_request.PermissionRequest = .{ .id = 73, .label = "file_mutation", .file = .{ .kind = .edit, .intent = .mutation, .preview = .{ .path = "note.txt", .lines = &preview_lines, .additions = 1, .deletions = 0, .truncated = false, }, .scope = .workspace_files, }, }; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = .{ .rows = 24, .cols = 96, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 1, .viewport_top_row = 1, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc); try std.testing.expect(try app.approval_prompt.syncRequest(alloc, request));
app.shell.render_requests.request(.modal); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app);
try std.testing.expect(!app.terminal.fileApprovalScreenActive()); try std.testing.expect(!app.approval_prompt.isActive()); try std.testing.expect(!app.shell.render_requests.hasReason(.external_damage)); try std.testing.expectEqual( types.ToolPermissionDecision.deny, app.worker.submitted_permission.?, );}
test "approval screen clear decision rebuilds first request replacements and resizes only" { const request_a: permission_request.PermissionRequest = .{ .id = 10, .label = "web_search latest Zig release", }; const request_b: permission_request.PermissionRequest = .{ .id = 11, .label = "web_search latest Zig release", }; const layout: types.Layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }; const commit: interaction_state.ApprovalScreenCommit = .{ .request_id = request_a.id, .rows = layout.rows, .cols = layout.cols, .file_identity_visible = false, .all_decision_controls_visible = false, .changed_or_notice_visible = false, .document_scrollable = false, };
try std.testing.expect(approvalScreenNeedsClear(false, request_a, layout, commit)); try std.testing.expect(!approvalScreenNeedsClear(true, request_a, layout, commit)); try std.testing.expect(approvalScreenNeedsClear(true, request_b, layout, commit));
var resized = layout; resized.cols = 48; try std.testing.expect(approvalScreenNeedsClear(true, request_a, resized, commit)); try std.testing.expect(approvalScreenNeedsClear(true, request_a, layout, null));}
fn coordinatorRowHasText(grid: vt_emulator.Grid, row: u16) !bool { var buf: std.ArrayList(u8) = .empty; defer buf.deinit(grid.alloc); try grid.rowTextTrimmed(row, &buf); return std.mem.trim(u8, buf.items, " \t\r\n").len > 0;}
test "core.app_render_runtime coordinator physically scrolls preserved shell rows for wrapped transcript growth" { const alloc = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var file = try tmp.dir.createFile(std.testing.io, "coordinator-scroll.log", .{ .read = true }); defer file.close(io_mod.getIo());
const layout: types.Layout = .{ .rows = 12, .cols = 32, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }; var app = CoordinatorTestApp{ .alloc = alloc, .shell = .{ .stdout_file = file, .layout = layout, .owned_top_row = 8, .viewport_top_row = 8, }, }; defer app.deinit(); try app.selected_model.appendSlice(alloc, "test-model"); try app.shell.initBacking(alloc); try app.shell.enableShadowVt(alloc);
var terminal = try vt_emulator.Grid.init(alloc, layout.cols, layout.rows); defer terminal.deinit(); const shell_markers = "\x1b[1;1HSHELL01\nSHELL02\nSHELL03\nSHELL04\nSHELL05\nSHELL06\nSHELL07\n$ fx"; try terminal.feed(shell_markers); try app.shell.shadow_vt.?.feed(shell_markers);
var read_offset: u64 = 0; app.shell.render_requests.request(.first_frame); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const initial_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(initial_bytes); try terminal.feed(initial_bytes); try std.testing.expectEqual(@as(u16, 8), app.shell.owned_top_row);
try app.shell.writeTranscript( alloc, &app.metrics, "wrapped-00 wrapped-01 wrapped-02 wrapped-03 wrapped-04 wrapped-05 wrapped-06 wrapped-07 wrapped-08 wrapped-09 wrapped-10 wrapped-11 wrapped-12 WRAPPED_TAIL", true, ); app.shell.render_requests.request(.footer); try Runtime(CoordinatorTestApp).flushRequestedFrame(&app); const growth_bytes = try readCoordinatorFrameBytes(alloc, file, &read_offset); defer alloc.free(growth_bytes);
var stats: vt_emulator.FeedStats = .{}; try terminal.feedWithStats(growth_bytes, &stats);
try std.testing.expect(stats.scrolled); try std.testing.expect(std.mem.find(u8, growth_bytes, "\x1b[12;1H\n") != null); try std.testing.expect(std.mem.find(u8, growth_bytes, "\x1b[3J") == null); try std.testing.expect(app.shell.owned_top_row < 8); try std.testing.expectEqual(app.shell.owned_top_row, app.shell.viewport_top_row); try std.testing.expect(!(try coordinatorGridContains(terminal, "SHELL01"))); try std.testing.expect(try coordinatorRowHasText(terminal, 1)); try std.testing.expect(try coordinatorGridContains(terminal, "WRAPPED_TAIL")); try std.testing.expect(try coordinatorGridContains(terminal, "run /login"));}