Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457const std = @import("std");const builtin = @import("builtin");const build_options = @import("build_options");const io_mod = @import("core/shared/io.zig");
pub const version = "0.0.10";
const app_lifecycle = @import("core/app/app_lifecycle.zig");const provider_runtime = @import("core/app/provider_runtime.zig");const auth_runtime = @import("core/auth/auth_runtime.zig");const api_key_validator = @import("core/auth/api_key_validator.zig");const oauth_transport = @import("core/auth/oauth_transport.zig");const js_host_auth = @import("core/auth/js_host_auth.zig");const js_host_clipboard = @import("core/hosts/js_host_clipboard.zig");const credentials = @import("core/auth/credentials.zig");const secret = @import("core/auth/secret.zig");const model_cache_runtime = @import("core/app/model_cache_runtime.zig");const usage_dashboard_runtime = @import("core/app/usage_dashboard_runtime.zig");const app_auth_runtime = @import("core/app/app_auth_runtime.zig");const app_host_config_runtime = @import("core/app/app_host_config_runtime.zig");const app_entry_runtime = @import("core/app/app_entry_runtime.zig");const acp_runner = @import("core/cli/acp_runner.zig");const acp_server = @import("acp/server.zig");const app_input_runtime = @import("core/app/app_input_runtime.zig");const input_full_transcript_runtime = @import("core/app/input_full_transcript_runtime.zig");const input_submit_runtime = @import("core/app/input_submit_runtime.zig");const core_input_runtime = @import("core/input/runtime.zig");const app_bootstrap_runtime = @import("core/app/app_bootstrap_runtime.zig");const app_notification_runtime = @import("core/app/app_notification_runtime.zig");const app_permission_runtime = @import("core/app/app_permission_runtime.zig");const app_process_runtime = @import("core/app/app_process_runtime.zig");const managed_execution = @import("core/execution/managed_execution.zig");const prompt_history_runtime = @import("core/app/prompt_history_runtime.zig");const app_agent_runtime = @import("core/app/app_agent_runtime.zig");const app_runtime_setup = @import("core/app/app_runtime_setup.zig");const app_render_runtime = @import("core/app/app_render_runtime.zig");const app_session_runtime = @import("core/app/app_session_runtime.zig");const app_upgrade_runtime = @import("core/app/app_upgrade_runtime.zig");const app_worker_runtime = @import("core/app/app_worker_runtime.zig");const app_workspace_runtime = @import("core/app/app_workspace_runtime.zig");const app_callbacks = @import("core/app/app_callbacks.zig");const app_commands = @import("core/app/app_commands.zig");const change_tracker_mod = @import("core/workspace/change_tracker.zig");const context_contract = @import("core/workspace/context_contract.zig");const statusline_identity = @import("core/workspace/statusline_identity.zig");const collections = @import("core/shared/collections.zig");const agent_steps = @import("core/config/agent_steps.zig");const config_runtime = @import("core/config/config_runtime.zig");const model_provider = @import("core/config/model_provider.zig");const js_host_prompt_history = @import("core/session/js_host_prompt_history.zig");const model_capabilities = @import("core/config/model_capabilities.zig");const prompt_policy = @import("core/config/prompt_policy.zig");const builtin_commands = @import("builtins/commands.zig");const command_specs = @import("core/slash_commands/command_specs.zig");const builtin_context = @import("builtins/context.zig");const builtin_gateway = @import("builtins/gateway.zig");const builtin_providers = @import("builtins/providers.zig");const gateway_provider = @import("core/gateway/gateway_provider.zig");const provider_set = @import("core/gateway/provider_set.zig");const provider_catalog = @import("core/auth/provider_catalog.zig");const vercel_model_policy = @import("gateway/vercel_model_policy.zig");const model_catalog = @import("core/gateway/model_catalog.zig");const agent_stream_provider = @import("core/agent/stream_provider.zig");const builtin_hooks = @import("builtins/hooks.zig");const builtin_mcp = @import("builtins/mcp.zig");const builtin_modes = @import("builtins/modes.zig");const builtin_skills = @import("builtins/skills.zig");const host = @import("core/hosts/host.zig");const host_runtime_profile = @import("core/hosts/runtime_profile.zig");const js_host_url_opener = @import("core/hosts/js_host_url_opener.zig");const js_host_workspace = @import("core/hosts/js_host_workspace.zig");const host_target = @import("core/hosts/target.zig");const native_host = @import("core/hosts/native.zig");const debug_trace = @import("core/shared/debug_trace.zig");const display_width = @import("core/shared/display_width.zig");const file_index_mod = @import("core/workspace/file_index.zig");const mcp_command_provider = @import("core/mcp/command_provider.zig");const mcp_runtime_mod = @import("core/mcp/mcp_runtime.zig");const mcp_model_catalog = @import("core/mcp/model_catalog.zig");const mcp_access_policy = @import("core/mcp/access_policy.zig");const mcp_menu_state = @import("core/mcp/menu_state.zig");const app_mcp_runtime = @import("core/app/app_mcp_runtime.zig");const app_mcp_menu_runtime = @import("core/app/app_mcp_menu_runtime.zig");const skill_commands = @import("core/skills/skill_commands.zig");const skill_runtime = @import("core/skills/skill_runtime.zig");const cli_surface = @import("core/cli/cli_surface.zig");const hooks = @import("core/hooks/hooks.zig");const github_publish = @import("core/github/github_publish.zig");const subagent_domain = @import("core/subagent/domain.zig");const subagent_execution = @import("core/subagent/execution.zig");const types = @import("core/shared/types.zig");const image_attachments = @import("core/images/image_attachments.zig");const permissions = @import("core/permissions/permissions.zig");const command_runner = @import("core/execution/command_runner.zig");const command_admission = @import("core/permissions/command_admission.zig");const permission_auto_classifier = @import("core/permissions/auto_classifier.zig");const auto_classifier_context = @import("core/permissions/auto_classifier_context.zig");const agent_runtime = @import("core/agent/agent_runtime.zig");const assistant_presentation = @import("core/agent/assistant_presentation.zig");const auto_upgrade = @import("core/upgrade/auto_upgrade.zig");const update_target = @import("core/upgrade/update_target.zig");
const compiled_update_channel = update_target.Channel.parse(build_options.update_channel) orelse @compileError("invalid compiled update channel");const shell_process_provider = @import("tools/shell/process_provider.zig");const process_provider = @import("core/execution/process_provider.zig");const terminal_client_runtime = @import("core/terminal/client.zig");const terminal_host = @import("core/terminal/host.zig");const terminal_native_session = @import("core/terminal/native_session.zig");const terminal_tmux_session = @import("core/terminal/tmux_session.zig");const session_runtime = @import("core/session/session.zig");const session_codec = @import("core/session/session_codec.zig");const session_child_store = @import("core/session/session_child_store.zig");const session_log = @import("core/session/session_log.zig");const builtin_tools = @import("builtins/tools.zig");const browser_workspace_tools = @import("builtins/browser_workspace_tools.zig");const browser_capabilities = @import("core/hosts/browser_capabilities.zig");const tool_admission = @import("core/tooling/tool_admission.zig");const tool_projection = @import("core/tooling/tool_projection.zig");const command_output_content = @import("core/tooling/command_output_content.zig");const tool_dispatch = @import("core/tooling/tool_dispatch.zig");const tool_set_contract = @import("core/tooling/tool_set.zig");const tool_mcp_runtime = @import("core/tooling/tool_mcp_runtime.zig");const tool_runtime = @import("core/tooling/tool_runtime.zig");const web_fetch_runtime = @import("core/tooling/web_fetch_runtime.zig");const web_search_runtime = @import("core/tooling/web_search_runtime.zig");const worker_runtime = @import("core/agent/worker_runtime.zig");const question_prompt = @import("core/agent/question_prompt.zig");const gateway_client = @import("gateway/client.zig");const js_host_stream_provider = @import("gateway/js_host_stream_provider.zig");const js_host_model_catalog = @import("gateway/js_host_model_catalog.zig");const url_opener = @import("core/hosts/url_opener.zig");const event_loop = @import("ui/event_loop.zig");const footer_runtime = @import("ui/footer/runtime.zig");const question_ui = @import("ui/footer/question_ui.zig");const ui_input = @import("ui/input/runtime.zig");const input_action = @import("core/input/input_action.zig");const paste_framing = @import("core/input/paste_framing.zig");const registered_entities = @import("core/input/registered_entities.zig");const ui_render = @import("ui/render.zig");const shell_runtime = @import("ui/shell_runtime.zig");const ui_terminal = @import("ui/terminal/terminal.zig");const cursor_probe = @import("ui/terminal/cursor_probe.zig");const transcript_runtime = @import("ui/transcript/runtime.zig");const resume_projection = @import("ui/transcript/resume_projection.zig");const assistant_pacer = @import("ui/assistant/pacer.zig");const approval_prompt = @import("core/permissions/approval_prompt.zig");
const Allocator = std.mem.Allocator;const Layout = types.Layout;const Metrics = types.Metrics;const StreamState = types.StreamState;const ToolCall = types.ToolCall;const ChatMessage = types.ChatMessage;const PermissionMode = types.PermissionMode;const ReasoningEffort = types.ReasoningEffort;const ToolPermissionDecision = types.ToolPermissionDecision;const PermissionGrant = types.PermissionGrant;const PermissionEngine = permissions.PermissionEngine;const QueuedPrompt = worker_runtime.QueuedPrompt;const WorkItem = worker_runtime.WorkItem;const WorkerRuntime = worker_runtime.WorkerRuntime;const SessionRuntime = session_runtime.SessionRuntime;const PromptHistoryRuntime = prompt_history_runtime.PromptHistoryRuntime;const ToolExecutionResult = agent_runtime.ToolExecutionResult;const ApprovalPrompt = approval_prompt.ApprovalPrompt;const ApprovalScreenState = footer_runtime.ApprovalScreenState;const QuestionPrompt = question_prompt.QuestionPrompt;const InputRuntime = core_input_runtime.Runtime;const TerminalInputRuntime = ui_input.Runtime;const TerminalState = shell_runtime.TerminalState;const TranscriptRuntime = transcript_runtime.TranscriptRuntime;const ResumeProjection = resume_projection.ResumeProjection;const RawEnviron = io_mod.RawEnviron;
const footer_rows: u16 = 4;const active_poll_timeout_ms: i32 = 8;const focused_ui_worker_poll_timeout_ms: i32 = 1;const idle_wasm_poll_timeout_ms: i32 = 16;const resize_debounce_ms: i64 = 100;const max_transcript_bytes: usize = 256 * 1024;const default_max_agent_steps: usize = agent_steps.default_max_agent_steps;const native_gateway_provider = builtin_gateway.provider;const max_history_turns: usize = 8;const max_list_entries: usize = 100;const max_read_file_bytes: usize = 50 * 1024;const max_read_file_lines: usize = 400;const max_read_file_line_len: usize = 2000;const max_command_output_bytes: usize = 64 * 1024;const input_escape_timeout_ms: i64 = 30;
fn nativeLoopPollTimeoutMs( default_timeout_ms: i32, auth_refresh_active: bool, skills_refresh_active: bool, transcript_page_work_active: bool,) i32 { return if (auth_refresh_active or skills_refresh_active or transcript_page_work_active) @min(default_timeout_ms, focused_ui_worker_poll_timeout_ms) else default_timeout_ms;}
const max_prompt_history: usize = 100;
const ignored_list_entries = [_][]const u8{ ".git", ".zig-cache", "zig-out", "node_modules", ".next", "dist", "build", "coverage",};
fn dupeUniqueSkillBindingsFromTokens( alloc: Allocator, skill_tokens: []const registered_entities.SkillTokenSpan,) ![]worker_runtime.SkillBinding { if (skill_tokens.len == 0) return &.{};
var bindings: std.ArrayList(worker_runtime.SkillBinding) = .empty; errdefer { for (bindings.items) |binding| { alloc.free(binding.name); alloc.free(binding.path); } bindings.deinit(alloc); }
for (skill_tokens) |token| { if (token.name.len == 0 or token.path.len == 0) continue; if (skillBindingPathSeen(bindings.items, token.path)) continue;
const name_copy = try alloc.dupe(u8, token.name); var path_copy: []u8 = &.{}; var appended = false; errdefer if (!appended) { alloc.free(name_copy); if (path_copy.len > 0) alloc.free(path_copy); };
path_copy = try alloc.dupe(u8, token.path); try bindings.append(alloc, .{ .name = name_copy, .path = path_copy, }); appended = true; }
if (bindings.items.len == 0) { bindings.deinit(alloc); return &.{}; } return try bindings.toOwnedSlice(alloc);}
fn skillBindingPathSeen(bindings: []const worker_runtime.SkillBinding, path: []const u8) bool { for (bindings) |binding| { if (std.mem.eql(u8, binding.path, path)) return true; } return false;}
fn dupeSkillDisplaySpansFromTokens( alloc: Allocator, skill_tokens: []const registered_entities.SkillTokenSpan,) ![]worker_runtime.SkillDisplaySpan { if (skill_tokens.len == 0) return &.{};
var spans: std.ArrayList(worker_runtime.SkillDisplaySpan) = .empty; errdefer { for (spans.items) |span| { alloc.free(span.name); alloc.free(span.path); } spans.deinit(alloc); }
for (skill_tokens) |token| { if (token.name.len == 0 or token.path.len == 0) continue;
const name_copy = try alloc.dupe(u8, token.name); var path_copy: []u8 = &.{}; var appended = false; errdefer if (!appended) { alloc.free(name_copy); if (path_copy.len > 0) alloc.free(path_copy); };
path_copy = try alloc.dupe(u8, token.path); try spans.append(alloc, .{ .raw_start = token.raw_start, .raw_end = token.raw_end, .name = name_copy, .path = path_copy, .display_source = token.display_source, .owns_trailing_separator = token.owns_trailing_separator, }); appended = true; }
if (spans.items.len == 0) { spans.deinit(alloc); return &.{}; } return try spans.toOwnedSlice(alloc);}
fn promptCardSkillTokensFromDisplaySpans( alloc: Allocator, skill_display_spans: []const worker_runtime.SkillDisplaySpan,) ![]registered_entities.SkillTokenSpan { if (skill_display_spans.len == 0) return &.{}; const tokens = try alloc.alloc(registered_entities.SkillTokenSpan, skill_display_spans.len); errdefer alloc.free(tokens); for (skill_display_spans, 0..) |span, i| { tokens[i] = .{ .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, }; } return tokens;}
test "skill submit snapshot keeps display spans exact while agent bindings dedupe" { const alloc = std.testing.allocator; const tokens = [_]registered_entities.SkillTokenSpan{ .{ .raw_start = "raw $review then ".len, .raw_end = "raw $review then $review".len, .name = "review", .path = "/tmp/.codex/skills/review", }, .{ .raw_start = "raw $review then $review and ".len, .raw_end = "raw $review then $review and $review".len, .name = "review", .path = "/tmp/.codex/skills/review", }, };
const bindings = try dupeUniqueSkillBindingsFromTokens(alloc, &tokens); defer worker_runtime.freeSkillBindings(alloc, bindings); const display_spans = try dupeSkillDisplaySpansFromTokens(alloc, &tokens); defer worker_runtime.freeSkillDisplaySpans(alloc, display_spans);
try std.testing.expectEqual(@as(usize, 1), bindings.len); try std.testing.expectEqualStrings("review", bindings[0].name); try std.testing.expectEqual(@as(usize, 2), display_spans.len); try std.testing.expectEqual(tokens[0].raw_start, display_spans[0].raw_start); try std.testing.expectEqual(tokens[1].raw_start, display_spans[1].raw_start);}
var resize_interlock = shell_runtime.ResizeApprovalInterlock{};const default_context_registry = context_contract.Registry{ .default_provider = builtin_context.provider };const WorkspaceHostRuntime = if (host_target.is_wasm) js_host_workspace.Runtime else struct {};const selected_host_profile = if (host_target.is_wasm) host_runtime_profile.wasm else host_runtime_profile.native;const app_api_key_validator = if (host_target.is_wasm) api_key_validator.unavailable_providerelse builtin_gateway.api_key_validator;const app_oauth_transport = if (selected_host_profile.js_host_auth) js_host_auth.oauth_providerelse if (selected_host_profile.native_auth) builtin_gateway.oauth_transport_providerelse oauth_transport.unavailable_provider;const app_secret_store = if (host_target.is_wasm) host.unavailable_secret_storeelse native_host.secret_store;const wasm_skill_root_policy: @import("core/skills/skill_contract.zig").RootPolicy = .{ .managed_root_source = null,};fn currentBuild() update_target.CurrentBuild { return .{ .channel = compiled_update_channel, .version = version, .revision = build_options.git_commit, };}
const App = struct { pub const app_version = version; pub const host_profile = selected_host_profile; pub const input_limits = paste_framing.default_input_limits; pub const build_update_channel = compiled_update_channel; pub const build_revision = build_options.git_commit; const Self = @This(); const AgentAppRuntime = app_agent_runtime.Runtime(Self); const AuthAppRuntime = app_auth_runtime.Runtime(Self); const HostConfigAppRuntime = app_host_config_runtime.Runtime(Self); const BootstrapAppRuntime = app_bootstrap_runtime.Runtime(Self); const InputAppRuntime = app_input_runtime.Runtime(Self); const InputFullTranscriptRuntime = input_full_transcript_runtime.Runtime(Self); const InputSubmitRuntime = input_submit_runtime.SubmitRuntime(Self); const NotificationAppRuntime = app_notification_runtime.Runtime( Self, builtin_hooks.notifications.provider(Self), ); const HerdrAppRuntime = builtin_hooks.Runtime(Self); const RenderAppRuntime = app_render_runtime.Runtime(Self); const SessionAppRuntime = app_session_runtime.Runtime(Self); const UpgradeAppRuntime = app_upgrade_runtime.Runtime(Self); const WorkerAppRuntime = app_worker_runtime.Runtime(Self); const WorkspaceAppRuntime = app_workspace_runtime.Runtime(Self);
pub fn contextRegistry(_: *const Self) context_contract.Registry { return default_context_registry; }
pub fn workspaceHostInfo(self: *const Self) ?*const js_host_workspace.Info { if (comptime host_profile.js_host_workspace) return self.workspace_host.info(); return null; }
pub fn workspaceExecutor(self: *const Self) ?js_host_workspace.Executor { if (comptime host_profile.js_host_workspace) return self.workspace_host.executor(); return null; }
pub fn promptPolicy(_: *const Self) prompt_policy.Policy { return builtin_context.prompt_policy; }
pub fn slashRegistry(_: *const Self) command_specs.SlashRegistry { return builtin_commands.slash_registry; }
pub fn mcpCommandProvider(_: *const Self) mcp_command_provider.Provider { return builtin_mcp.command_provider; }
pub fn skillsCommandProvider(_: *const Self) skill_commands.Provider { return builtin_skills.command_provider; }
pub fn urlOpener(_: *const Self) host.UrlOpener { return if (comptime host_profile.url_opening) url_opener.native_opener else if (comptime host_profile.js_host_url_open) js_host_url_opener.opener else host.unavailable_url_opener; }
pub fn creditsProvider(self: *const Self) gateway_provider.CreditsProvider { return self.providerSet() .select(self.provider_selection.selection().provider) .credits orelse gateway_provider.unavailable_credits_provider; }
pub fn agentStreamProvider(self: *const Self) agent_stream_provider.Provider { return self.providerSet() .select(self.provider_selection.selection().provider) .agent_stream_or_unavailable(); }
/// Fixed low-cost model the active provider uses for session title /// generation; null when the provider does not support generated titles. pub fn sessionTitleModel(self: *const Self) ?[]const u8 { return self.providerSet() .select(self.provider_selection.selection().provider) .title_model; }
pub fn providerCatalog(self: *Self, provider: model_provider.ProviderId) ?model_catalog.Provider { return self.providerSet().select(provider).model_catalog; }
pub fn cooperativeTransportPulse(self: *Self) !void { if (comptime !host_target.is_wasm) return; if (try event_loop.pump_ready_input( self.terminal, &self.should_exit, RenderAppRuntime.eventLoopCallbacks(self), )) |exit_cause| { if (exit_cause == .input_closed) self.should_exit = true; return; } try WorkerAppRuntime.tick( self, app_callbacks.Bindings(App).workerEventHandlers(self), ); try self.flushRequestedFrame(); }
pub fn secretStore(self: *const Self) host.SecretStore { return self.auth.secret_store; }
pub fn clipboard(_: *const Self) host.Clipboard { return if (comptime host_profile.clipboard) native_host.clipboard else if (comptime host_profile.js_host_clipboard) js_host_clipboard.clipboard else host.unavailable_clipboard; }
pub fn terminalTitle(self: *const Self) host.TerminalTitle { return ui_render.terminalTitleFor(&self.shell.stdout_file); }
alloc: Allocator, terminal: TerminalState = .{},
auth: auth_runtime.Runtime = auth_runtime.Runtime.init( app_api_key_validator, app_oauth_transport, app_secret_store, ), provider_selection: provider_runtime.Runtime = provider_runtime.Runtime.init(std.heap.c_allocator), model_cache: model_cache_runtime.Runtime = model_cache_runtime.Runtime.init(std.heap.c_allocator, builtin_gateway.models_path), usage_dashboard: usage_dashboard_runtime.Runtime = usage_dashboard_runtime.Runtime.init(std.heap.c_allocator), workspace_root: []u8 = &.{}, workspace_identity: statusline_identity.Runtime = .{}, workspace_host: WorkspaceHostRuntime = .{}, workspace: app_workspace_runtime.State = .{}, permission_engine: PermissionEngine = .{}, permission_state: app_permission_runtime.State = .{}, agent_step_limit: usize = default_max_agent_steps, web_fetch_runtime: web_fetch_runtime.Runtime = web_fetch_runtime.Runtime.init(.{}), web_search_runtime: web_search_runtime.Runtime = web_search_runtime.Runtime.init(.{ .provider = if (host_profile.web_search) builtin_providers.native.gateway.fx_search else null, }), web_search_models_path: []const u8 = builtin_gateway.models_path, lifecycle_runtime: hooks.Runtime = hooks.Runtime.init(std.heap.c_allocator), lifecycle_view: hooks.RuntimeView = hooks.RuntimeView.empty(), notifications: builtin_hooks.notifications.State = .{}, herdr: builtin_hooks.Client = .{},
session: SessionRuntime = SessionRuntime.initWithProviders( max_history_turns, if (host_profile.generation_usage) builtin_providers.native.deferredUsageProviders() else .{}, ), session_persistence: app_session_runtime.Persistence = .{}, prompt_history: PromptHistoryRuntime = .{}, requested_resume: ?cli_surface.ResumeTarget = null, approval_prompt: ApprovalPrompt = .{}, approval_screen: ApprovalScreenState = .{}, question_prompt: QuestionPrompt = .{},
should_exit: bool = false, input_runtime: InputRuntime = .{}, terminal_input_runtime: TerminalInputRuntime = .{}, submission: input_submit_runtime.State = .{}, pending_images: std.ArrayList(types.ImageAttachment) = .empty, next_image_id: usize = 1, shell: TranscriptRuntime = .{}, pacer: assistant_pacer.AssistantPacer = .{},
worker_thread: ?std.Thread = null, worker: WorkerRuntime = .{}, terminal_client: terminal_client_runtime.Runtime = .{}, managed_executions: managed_execution.Runtime = managed_execution.Runtime.init(std.heap.c_allocator), legacy_process_provider: process_provider.Provider = process_provider.unavailable_provider, upgrader: auto_upgrade.AutoUpgrade = .{}, change_tracker: change_tracker_mod.ChangeTracker = .{}, mcp: app_mcp_runtime.State = .{}, skills: skill_runtime.Runtime = .{}, context_snapshot: context_contract.GatheredContextSnapshot = .{}, file_index: file_index_mod.FileIndex = .{}, context_enabled: bool = true, context_limits: config_runtime.context_limits.Values = .{}, fast_mode: bool = false, auto_upgrade_enabled: bool = true, effort: ReasoningEffort = .auto, /// Resolved review-model override for automatic permission review /// (`review_model` setting or FX_REVIEW_MODEL). Owned; empty keeps the /// reviewer's compiled default. review_model: []u8 = &.{}, diff_entries: std.ArrayList(@import("core/output/diff.zig").DiffEntry) = .empty, next_diff_id: u32 = 1,
statusline_context: bool = false, statusline_session: bool = false, /// Resolved `session_titles` preference: generate a model-written session /// title from the first prompt of a fresh session. session_title_generation: bool = true, /// Resolved display title for the active session. App owns these bytes; /// empty means no title has been derived or restored yet. session_title: std.ArrayList(u8) = .empty, total_input_tokens: u64 = 0, total_output_tokens: u64 = 0, total_web_search_requests: u64 = 0,
stream: StreamState = .{}, metrics: Metrics = .{}, fn loadNoMcpRuntime( _: Allocator, _: []const u8, _: @import("core/mcp/elicitation.zig").Capabilities, ) !?*mcp_runtime_mod.McpRuntime { return null; }
pub fn init( alloc: Allocator, launch: *cli_surface.InteractiveLaunch, auth_mode: credentials.AuthMode, ) !Self { var app = Self{ .alloc = alloc, .auth = undefined, .usage_dashboard = undefined, .session_persistence = undefined, .shell = TranscriptRuntime.init(), .lifecycle_runtime = hooks.Runtime.init(alloc), .terminal_client = terminal_client_runtime.Runtime.init(if (comptime host_target.is_wasm) process_provider.unavailable_provider else shell_process_provider.provider), .legacy_process_provider = if (comptime host_target.is_wasm) process_provider.unavailable_provider else shell_process_provider.provider, }; auth_runtime.Runtime.initIntoWithMode( &app.auth, app_api_key_validator, app_oauth_transport, app_secret_store, auth_mode, ); usage_dashboard_runtime.Runtime.initInto(&app.usage_dashboard, std.heap.c_allocator); app_session_runtime.Persistence.initInto(&app.session_persistence); if (comptime host_profile.js_host_workspace) { app.workspace_host = js_host_workspace.Runtime.init(alloc) catch |err| blk: { if (err != error.WorkspaceUnavailable) { debug_trace.logf("workspace", "js host workspace unavailable err={s}", .{@errorName(err)}); } break :blk .{}; }; } if (comptime host_profile.js_host_prompt_history) { if (js_host_prompt_history.available()) { _ = app.prompt_history.initializeWithProvider( app.prompt_history.enabled, js_host_prompt_history.provider, ); } } app.shell.max_transcript_bytes = max_transcript_bytes; if (launch.requested_resume) |target| { app.requested_resume = target; launch.requested_resume = null; } errdefer if (app.requested_resume) |*target| target.deinit(alloc); try BootstrapAppRuntime.bootstrap( &app, footer_rows, builtin_gateway.default_model, default_max_agent_steps, handle_sigwinch, .{ .load_mcp_runtime = if (comptime host_target.is_wasm) loadNoMcpRuntime else builtin_mcp.loadRuntime, .skill_root_policy = if (comptime host_target.is_wasm) wasm_skill_root_policy else builtin_skills.root_policy, .terminal_title = app.terminalTitle(), }, .{ .provider = launch.modifiers.provider_override, .model = launch.modifiers.model_override, .effort = launch.modifiers.effort_override, .fast = launch.modifiers.fast_override, }, ); errdefer app.deinit(); try WorkspaceAppRuntime.applyLaunch( &app, launch.modifiers.additional_directories, launch.modifiers.saved_directories_suppressed, ); if (comptime !host_target.is_wasm) { app.provider_selection.ensureGatewayHttpPool(); if (app.provider_selection.selection().provider == .gateway) { if (app.provider_selection.gateway_http_pool) |pool| { pool.warmAsync(gateway_client.resolveChatUrlForWarmup(builtin_gateway.agentChatUrl())); } } } app.context_limits.applyCommandLine(launch.modifiers.context_limit_overrides); if (comptime host_profile.durable_sessions or host_profile.js_host_sessions) { if (app.requested_resume != null) { if (launch.upgrade_relaunch != null) { try SessionAppRuntime.resumeRequestedSessionAfterUpgrade( &app, app_version, build_update_channel, launch.upgrade_relaunch.?.previous_revision orelse "", build_revision, ); } else { try SessionAppRuntime.resumeRequestedSession(&app); } SessionAppRuntime.syncTerminalTitle(&app); } } const env_disabled = if (io_mod.getenv("FX_AUTO_UPGRADE")) |val| std.mem.eql(u8, val, "0") or std.ascii.eqlIgnoreCase(val, "false") else false; if (env_disabled or !auto_upgrade.shouldEnableForCurrentExecutable()) { app.auto_upgrade_enabled = false; } if (comptime !host_profile.auto_upgrade) app.auto_upgrade_enabled = false; try HostConfigAppRuntime.restore(&app, builtin_modes.registry); SessionAppRuntime.syncTerminalTitle(&app); return app; }
pub fn persistAcceptedModel(self: *App, model: []const u8) !void { HostConfigAppRuntime.persistModel(self, model); }
pub fn persistAcceptedPermissionMode(self: *App, mode: PermissionMode) !void { HostConfigAppRuntime.persistPermissionMode(self, mode); }
pub fn configureNotifications(self: *App) !void { // Register herdr hooks before NotificationAppRuntime.configure freezes // the lifecycle runtime (its call to freeze() is the sole freeze site). try HerdrAppRuntime.configure(self, SessionAppRuntime.activeSessionId(self)); try NotificationAppRuntime.configure(self); }
pub fn rebindAfterInit(self: *App) void { SessionAppRuntime.rebindSubagentHost(self); }
pub fn setNotificationPreferences( self: *App, turn_end: bool, attention_required: bool, max: bool, ) void { NotificationAppRuntime.setPreferences(self, .{ .turn_end = turn_end, .attention_required = attention_required, .max = max, }); }
pub fn notificationPreferences(self: *const App) app_notification_runtime.Preferences { return NotificationAppRuntime.preferences(self); }
pub fn soundMaxEnabled(self: *const App) bool { return NotificationAppRuntime.maxEnabled(self); }
pub fn queueNotification( self: *App, notification: app_notification_runtime.Notification, ) void { NotificationAppRuntime.queue(self, notification); }
pub fn notificationPresentationFinished(self: *App) void { NotificationAppRuntime.presentationFinished(self); }
pub fn flushNotifications(self: *App) void { NotificationAppRuntime.flush(self); }
pub fn playStartupSound(self: *App) void { NotificationAppRuntime.playCue(self, .bloom); }
pub fn playCancelSound(self: *App) void { NotificationAppRuntime.playCue(self, .press); }
pub fn playInteractionSound(self: *App) void { NotificationAppRuntime.playCue(self, .click); }
pub fn playInputClearedSound(self: *App) void { NotificationAppRuntime.playMaxCue(self, .release); }
pub fn playSlashMenuSound(self: *App) void { NotificationAppRuntime.playMaxCue(self, .toggle); }
pub fn dispatchAttentionRequired( self: *App, turn_id: u64, kind: hooks.AttentionKind, ) void { NotificationAppRuntime.dispatchAttentionRequired(self, turn_id, kind); }
/// Must be called after init() returns so the AutoUpgrade thread /// captures a pointer to the final App location (not a temporary). pub fn startAutoUpgrade(self: *App) void { if (self.auto_upgrade_enabled) { self.upgrader.start(self.alloc, currentBuild()); } }
pub fn applyReadyUpgradeShortcut(self: *App) !void { try UpgradeAppRuntime.applyReadyUpgrade(self); }
pub fn prepareResumeHandoffForUpgrade(self: *App) !void { try SessionAppRuntime.prepareResumeHandoff(self); }
pub fn requestUpgradeRelaunch( self: *App, executable_path: []const u8, ) !void { try self.upgrader.requestRelaunch(executable_path); }
pub fn requestResumeHandoffForUpgrade(self: *App) void { SessionAppRuntime.requestUpgradeResumeHandoff(self); }
pub fn takeUpgradeRelaunchRequest( self: *App, ) ?auto_upgrade.RelaunchRequest { return self.upgrader.takeRelaunchRequest(); }
pub fn deinit(self: *App) void { _ = self.deinitImpl(false); }
/// Returns an owned handoff only after all interactive state is torn down. pub fn deinitWithResumeHandoff(self: *App) app_session_runtime.ShutdownOutcome { return self.deinitImpl(true); }
pub fn resumeHandoffColumns(self: *const App) u16 { return self.shell.layout.cols; }
pub fn formatResumeHandoff( buffer: []u8, session_id: []const u8, terminal_cols: u16, ) ![]const u8 { return ui_render.formatResumeHandoff(buffer, session_id, terminal_cols); }
fn deinitImpl(self: *App, capture_resume_handoff: bool) app_session_runtime.ShutdownOutcome { var shutdown_trace = app_lifecycle.ShutdownStageTrace.init(); // Only real interactive sessions earn a shutdown report; failed // startups (no TTY, too small) reach deinit through errdefer and must // not write to the profile directory. const was_interactive = self.terminal.raw_enabled or self.terminal.signal_handler_installed; self.auth.stopProviderPreparation(); // Client.deinit releases the herdr pane (clear agent + label) when enabled. self.herdr.deinit(); self.stopStream(); shutdown_trace.mark("stop_stream");
self.worker.requestShutdown(); SessionAppRuntime.requestPersistenceShutdown(self); self.managed_executions.shutdown(); self.upgrader.stop(); self.file_index.requestStop(); WorkspaceAppRuntime.requestStop(self); shutdown_trace.mark("background_stops_requested");
self.releaseTerminal(); if (self.worker_thread) |thread| thread.join(); shutdown_trace.mark("worker_thread_joined"); WorkerAppRuntime.settleFinishedPromptsForShutdown(self) catch |err| { SessionAppRuntime.recordShutdownFailure(self, err); }; self.terminal_client.deinit(); self.managed_executions.deinit(); self.model_cache.deinit(); self.usage_dashboard.deinit(); InputSubmitRuntime.clearPendingSubmission(self, "shutdown"); const resume_handoff = if (capture_resume_handoff) SessionAppRuntime.finalizePersistenceWithResumeHandoff(self) else blk: { SessionAppRuntime.finalizePersistence(self); break :blk null; }; shutdown_trace.mark("persistence_finalized"); const shutdown_failure = self.session_persistence.shutdown_failure; self.worker.deinit(std.heap.c_allocator); self.web_fetch_runtime.deinit(self.alloc); self.web_search_runtime.deinit(); self.prompt_history.deinit(self.alloc); self.clearPendingImages(); self.pending_images.deinit(self.alloc); self.input_runtime.deinit(self.alloc); self.terminal_input_runtime.deinit(self.alloc); self.shell.deinit(self.alloc); self.pacer.deinit(self.alloc); self.session_title.deinit(self.alloc); SessionAppRuntime.deinitPersistence(self); self.provider_selection.deinit(); if (self.requested_resume) |*target| { target.deinit(self.alloc); self.requested_resume = null; } self.session.deinit(self.alloc); self.permission_engine.deinit(self.alloc); self.approval_prompt.deinit(self.alloc); self.question_prompt.deinit(self.alloc);
self.change_tracker.deinit(std.heap.c_allocator); for (self.diff_entries.items) |*entry| entry.deinit(std.heap.c_allocator); self.diff_entries.deinit(std.heap.c_allocator); self.mcp.deinit(self.alloc); shutdown_trace.mark("mcp_deinit"); self.skills.deinit(std.heap.c_allocator); self.context_snapshot.deinit(self.alloc); self.file_index.deinit(std.heap.c_allocator); self.lifecycle_runtime.deinit();
self.auth.deinit(self.alloc); WorkspaceAppRuntime.deinit(self); self.workspace_identity.deinit(self.alloc); if (self.workspace_root.len > 0) self.alloc.free(self.workspace_root); if (self.review_model.len > 0) self.alloc.free(self.review_model); shutdown_trace.mark("complete"); if (was_interactive) app_lifecycle.writeLastShutdownReport(self.alloc, &shutdown_trace); return .{ .handoff = resume_handoff, .failure = shutdown_failure }; }
pub fn releaseTerminal(self: *App) void { if (!self.terminal.raw_enabled and !self.terminal.signal_handler_installed) return; app_lifecycle.shutdownInteractiveShell( &self.terminal, &self.shell, &self.metrics, self.terminalTitle(), ); }
pub fn runExternalInteractive(self: *App, argv: []const []const u8) !void { try self.flushBeforeBlockingExternalWork();
self.terminal.disableRawMode(); var raw_restored = false; defer if (!raw_restored) { self.terminal.enableRawMode() catch {}; };
const io = io_mod.getIo(); try std.Io.File.stdout().writeStreamingAll(io, "\n"); var child = std.process.spawn(io, .{ .argv = argv, .stdin = .inherit, .stdout = .inherit, .stderr = .inherit, }) catch return error.ExternalInteractiveFailed; const term = child.wait(io) catch return error.ExternalInteractiveFailed; try std.Io.File.stdout().writeStreamingAll(io, "\n");
try self.terminal.captureOriginalTermios(); try self.terminal.enableRawMode(); raw_restored = true; self.shell.layout = self.terminal.queryLayout(footer_rows) catch self.shell.layout; try self.shell.requestTerminalReset(&self.metrics); self.shell.render_requests.request(.first_frame);
switch (term) { .exited => |code| if (code != 0) return error.ExternalInteractiveFailed, else => return error.ExternalInteractiveFailed, } }
pub fn flushBeforeBlockingExternalWork(self: *App) !void { try self.flushRequestedFrame(); }
pub fn suspendToJobControl(self: *App) !void { try self.flushBeforeBlockingExternalWork(); try SessionAppRuntime.suspendToJobControl(self, footer_rows); }
pub fn ensurePromptCredential(self: *App) !bool { return AuthAppRuntime.admitPromptCredential(self); }
pub fn restoreSessionCredential(self: *App, previous_provider: model_provider.ProviderId) !void { try AuthAppRuntime.restoreSessionCredential(self, previous_provider); }
pub fn startPromptCredentialPrewarm(self: *App) void { if (comptime !host_target.is_wasm) { AuthAppRuntime.startPromptCredentialPrewarm(self); } }
pub fn collectPendingPromptCredential( self: *App, ) !app_auth_runtime.PendingPromptCredentialReadiness { return AuthAppRuntime.collectPendingPromptCredential(self); }
pub fn retryPendingPromptCredential( self: *App, ) !app_auth_runtime.PendingPromptCredentialReadiness { return AuthAppRuntime.retryPendingPromptCredential(self); }
pub fn runProviderCommand(self: *App) !void { try AuthAppRuntime.runProviderCommand(self); }
pub fn requestPromptRetryAfterAuth(self: *App) void { InputSubmitRuntime.requestPromptRetryAfterAuth(self); }
pub fn cancelPromptRetryAfterAuth(self: *App) void { InputSubmitRuntime.cancelPromptRetryAfterAuth(self); }
pub fn resumePromptAfterAuth(self: *App) !void { try InputSubmitRuntime.resumePromptAfterAuth(self, max_prompt_history); }
pub fn runLoginCommand(self: *App) !void { try AuthAppRuntime.runLoginCommand(self); }
pub fn runLogoutCommand(self: *App, target: []const u8) !void { try AuthAppRuntime.runLogoutCommand(self, target); }
pub fn applyAuthPickerChoice(self: *App, choice: auth_runtime.Choice) !void { try AuthAppRuntime.applyPickerChoice(self, choice); }
pub fn selectCredentialSource(self: *App, source: credentials.Source) !bool { return AuthAppRuntime.selectCredentialSource(self, source); }
pub fn run(self: *App) !void { const callbacks = RenderAppRuntime.eventLoopCallbacks(self); while (true) { const exit_cause = try event_loop.run( self.terminal, &self.should_exit, active_poll_timeout_ms, callbacks, ); switch (exit_cause) { .requested_exit => return, .input_closed => return error.TerminalInputClosed, } } }
pub fn loopPollTimeoutMs(ctx: *anyopaque, default_timeout_ms: i32) i32 { const self: *App = @ptrCast(@alignCast(ctx)); if (comptime !host_target.is_wasm) { return nativeLoopPollTimeoutMs( default_timeout_ms, self.auth.sourceInventoryRefreshActive(), self.skills.refreshActive(), self.fullTranscriptFocusedWorkActive(), ); } return if (self.pacer.hasPending()) default_timeout_ms else idle_wasm_poll_timeout_ms; }
fn fullTranscriptFocusedWorkActive(self: *App) bool { return self.shell.fullTranscriptFocusedWorkActive(); }
fn processNextCooperativePrompt(self: *App) !void { if (comptime !host_target.is_wasm) return; try app_process_runtime.Runtime(App).processNextCooperativePrompt( self, app_callbacks.Bindings(App).workerEventHandlers(self), flushRequestedFrame, ); try SessionAppRuntime.settlePendingLiveSessionTransition(self); }
fn flushRequestedFrame(self: *App) !void { try RenderAppRuntime.flushRequestedFrame(self); }
pub fn handleCommand(self: *App, cmd: []const u8) !void { try app_commands.Handlers(App).route(self, cmd); }
pub fn clearPendingImages(self: *App) void { InputAppRuntime.clearPendingImages(self); }
pub fn releasePendingImages(self: *App) void { InputAppRuntime.releasePendingImages(self); }
pub fn nextImageId(self: *App) usize { return image_attachments.allocateImageId(&self.next_image_id); }
pub fn peekNextImageId(self: *const App) usize { return self.next_image_id; }
pub fn captureImageAttachment(self: *App, attachment: *types.ImageAttachment) !void { try SessionAppRuntime.captureImageAttachment(self, attachment); }
pub fn enqueuePrompt(self: *App, prompt: []const u8) !bool { return self.enqueuePromptWithSkillBindings(prompt, &.{}); }
pub fn enqueuePromptWithSkillBindings(self: *App, prompt: []const u8, skill_tokens: []const registered_entities.SkillTokenSpan) !bool { const context_targets = if (self.context_enabled) try context_contract.applicableTargetsForImages(self.alloc, self.pending_images.items) else &.{}; defer if (context_targets.len > 0) self.alloc.free(context_targets);
try AgentAppRuntime.refreshProjectContext(self, context_targets); self.session.setConversationLanguageFromUserMessage(prompt);
debug_trace.logf( "prompt", "enqueue bytes={d} stream_active={s} queued_before={d} preview=\"{s}\"", .{ prompt.len, if (self.stream.active) "true" else "false", self.worker.queuedPromptCount(), debug_trace.preview(prompt, 120), }, ); if (!try self.snapshotAndAdmitInteractivePromptWithSkillBindings( prompt, skill_tokens, )) return false; WorkerAppRuntime.syncState( self, app_callbacks.Bindings(App).worker_tool_lifecycle_presenter(self), ); return true; }
pub fn adoptPendingUserPrompt( self: *App, draft: *const input_submit_runtime.PendingPromptDraft, ) !void { try self.writeUserPromptCardWithSkillBindings( .{ .text = draft.prompt, .images = draft.images }, &.{}, draft.skill_display_spans, ); }
pub fn finalizePendingSubmission( self: *App, draft: *const input_submit_runtime.PendingPromptDraft, ) !void { const context_targets = if (self.context_enabled) try context_contract.applicableTargetsForImages(self.alloc, draft.images) else &.{}; defer if (context_targets.len > 0) self.alloc.free(context_targets); try AgentAppRuntime.refreshProjectContext(self, context_targets); self.session.setConversationLanguageFromUserMessage(draft.prompt);
const skill_tokens = try promptCardSkillTokensFromDisplaySpans( self.alloc, draft.skill_display_spans, ); defer if (skill_tokens.len > 0) self.alloc.free(skill_tokens); if (!try self.snapshotAndQueuePrompt( draft.prompt, skill_tokens, null, draft.images, draft.turn_id, true, )) return error.PendingPromptQueueRejected; WorkerAppRuntime.syncState( self, app_callbacks.Bindings(App).worker_tool_lifecycle_presenter(self), ); }
pub fn notePendingFrameCommitted(self: *App) void { InputSubmitRuntime.noteCommittedFrame(self); }
pub fn acceptPresentedPrompt(self: *App, turn_id: u64) !void { try InputSubmitRuntime.acceptPresentedPrompt(self, turn_id); }
pub fn cancelPendingSubmission(self: *App) bool { return InputSubmitRuntime.cancelPendingSubmission(self); }
pub fn clearPendingSubmission(self: *App, reason: []const u8) void { InputSubmitRuntime.clearPendingSubmission(self, reason); }
pub fn clearPendingSubmissionForSessionTransition(self: *App) void { InputSubmitRuntime.clearPendingSubmissionForSessionTransition(self); }
pub fn writeUserPromptCard(self: *App, user: types.UserTurn) !void { try self.writeUserPromptCardWithSpacing(user, self.session.historyLen() > 0); }
pub fn writeUserPromptCardWithSkillBindings( self: *App, user: types.UserTurn, skill_bindings: []const worker_runtime.SkillBinding, skill_display_spans: []const worker_runtime.SkillDisplaySpan, ) !void { _ = skill_bindings; const skill_tokens = try promptCardSkillTokensFromDisplaySpans(self.alloc, skill_display_spans); defer if (skill_tokens.len > 0) self.alloc.free(skill_tokens); try self.writeUserPromptCardWithSpacingAndSkillTokens(user, self.session.historyLen() > 0, skill_tokens); }
pub fn writeUserPromptCardWithSpacing(self: *App, user: types.UserTurn, has_prior_turns: bool) !void { try self.writeUserPromptCardWithSpacingAndSkillTokens(user, has_prior_turns, &.{}); }
fn writeUserPromptCardWithSpacingAndSkillTokens( self: *App, user: types.UserTurn, has_prior_turns: bool, skill_tokens: []const registered_entities.SkillTokenSpan, ) !void { _ = try self.shell.writeUserPromptCard( self.alloc, &self.metrics, user, has_prior_turns, skill_tokens, ); }
pub fn stopStream(self: *App) void { self.stream = .{}; self.shell.resetCommandOutputDisplay(self.alloc, "stream stopped"); self.shell.render_requests.request(.footer); }
pub fn clearSession(self: *App) !void { try SessionAppRuntime.clearSession(self); }
pub fn newSession(self: *App) !void { try SessionAppRuntime.newSession(self); }
pub fn resetSession(self: *App) !void { try SessionAppRuntime.resetSession(self); }
pub fn prepareLiveSessionResume(self: *App) !void { try SessionAppRuntime.prepareLiveSessionResume(self); }
pub fn finishLiveSessionResume(self: *App) !void { try SessionAppRuntime.finishLiveSessionResume(self); }
pub fn startResumedSessionReconciliation(self: *App) void { SessionAppRuntime.startResumedSessionReconciliation(self); }
pub fn resumeSelectedSession(self: *App) !bool { return SessionAppRuntime.resumeSelectedSession(self); }
pub fn startSessionCatalogPreload(self: *App) void { SessionAppRuntime.preloadSessionCatalog(self); }
pub fn loadMoreSessionPicker(self: *App) !bool { return SessionAppRuntime.loadMoreSessionPicker(self); }
pub fn beginResumeProjection(self: *App) !ResumeProjection { return ResumeProjection.init( self.alloc, &self.shell, io_mod.milliTimestamp(), self.next_diff_id, ); }
pub fn installResumeProjection( self: *App, projection: *ResumeProjection, ) !void { const c_alloc = std.heap.c_allocator; try self.diff_entries.ensureUnusedCapacity( c_alloc, projection.pending_diffs.items.len, ); for (projection.pending_diffs.items) |entry| { self.diff_entries.appendAssumeCapacity(entry); } projection.pending_diffs.clearRetainingCapacity(); self.next_diff_id = projection.next_diff_id; projection.install(&self.shell); }
pub fn historicalToolActivityKind( self: *App, call: types.ToolCall, ) types.ToolActivityKind { return tool_dispatch.toolActivityKindForCall(self.alloc, self.toolRegistry(), call); }
pub fn commitStartupResumeReplayAnchor(self: *App) !void { try self.flushRequestedFrame(); }
pub fn flushDirectTerminalShutdownOutcome(self: *App) !void { try RenderAppRuntime.flushRequestedFrame(@as(*Self, self)); }
fn snapshotAndAdmitInteractivePromptWithSkillBindings( self: *App, prompt: []const u8, skill_tokens: []const registered_entities.SkillTokenSpan, ) !bool { const queued = try self.snapshotPrompt( prompt, skill_tokens, null, null, 0, false, ); errdefer worker_runtime.freeQueuedPrompt(std.heap.c_allocator, queued); try self.worker.admitInteractivePrompt(std.heap.c_allocator, queued); HerdrAppRuntime.reportWorking(self); return true; }
pub fn queueRecoveryCheckpoint( self: *App, checkpoint: *const session_codec.RecoveryCheckpoint, ) !bool { if (!try self.snapshotAndQueuePrompt( checkpoint.user.text, &.{}, checkpoint, null, checkpoint.turn_id, false, )) return false; WorkerAppRuntime.beginRecoveryPresentation(self); WorkerAppRuntime.syncState( self, app_callbacks.Bindings(App).worker_tool_lifecycle_presenter(self), ); return true; }
fn snapshotAndQueuePrompt( self: *App, prompt: []const u8, skill_tokens: []const registered_entities.SkillTokenSpan, recovery_checkpoint: ?*const session_codec.RecoveryCheckpoint, prompt_images: ?[]const types.ImageAttachment, turn_id: u64, user_prompt_already_presented: bool, ) !bool { const queued = try self.snapshotPrompt( prompt, skill_tokens, recovery_checkpoint, prompt_images, turn_id, user_prompt_already_presented, ); errdefer worker_runtime.freeQueuedPrompt(std.heap.c_allocator, queued); try self.worker.enqueuePrompt(std.heap.c_allocator, queued); HerdrAppRuntime.reportWorking(self); return true; }
// Caller owns the returned prompt until worker admission succeeds. fn snapshotPrompt( self: *App, prompt: []const u8, skill_tokens: []const registered_entities.SkillTokenSpan, recovery_checkpoint: ?*const session_codec.RecoveryCheckpoint, prompt_images: ?[]const types.ImageAttachment, turn_id: u64, user_prompt_already_presented: bool, ) !worker_runtime.QueuedPrompt { if (recovery_checkpoint == null) { SessionAppRuntime.maybeStartSessionTitleGeneration(self, prompt); } const source_images = if (recovery_checkpoint) |checkpoint| checkpoint.user.images else if (prompt_images) |images| images else self.pending_images.items;
const prompt_copy = try std.heap.c_allocator.dupe(u8, prompt); errdefer std.heap.c_allocator.free(prompt_copy);
const model_copy = try std.heap.c_allocator.dupe(u8, self.provider_selection.selection().model); errdefer std.heap.c_allocator.free(model_copy);
const gateway_credential = self.auth.gatewayCredential() orelse return error.MissingApiKey; const api_key_copy = if (gateway_credential.api_key) |api_key| try std.heap.c_allocator.dupe(u8, api_key) else @constCast(&[_]u8{}); errdefer secret.zeroAndFree(std.heap.c_allocator, api_key_copy);
const gateway_team_copy = if (gateway_credential.gateway_team) |team| try std.heap.c_allocator.dupe(u8, team) else null; errdefer if (gateway_team_copy) |team| std.heap.c_allocator.free(team); const account_id_copy = if (self.auth.accountId()) |account_id| try std.heap.c_allocator.dupe(u8, account_id) else null; errdefer if (account_id_copy) |account_id| std.heap.c_allocator.free(account_id);
const authorized_image_catalog = if (recovery_checkpoint) |checkpoint| blk: { const history_catalog = try self.session.snapshotImageCatalog(std.heap.c_allocator, &.{}); defer types.freeImageAttachmentSlice(std.heap.c_allocator, history_catalog); break :blk try session_runtime.merge_image_catalog_history_turn( std.heap.c_allocator, history_catalog, checkpoint.interruptedTurn(), ); } else try self.session.snapshotImageCatalog(std.heap.c_allocator, source_images); errdefer types.freeImageAttachmentSlice(std.heap.c_allocator, authorized_image_catalog);
const history_copy = try self.session.snapshotHistory(std.heap.c_allocator); errdefer types.freeHistoryTurnSlice(std.heap.c_allocator, history_copy); const root_user_intent_context = try auto_classifier_context.buildCanonicalRootUserContext( std.heap.c_allocator, prompt_copy, self.session.agent.history.items, ); errdefer std.heap.c_allocator.free(root_user_intent_context);
const images_copy = try types.dupeImageAttachmentSlice( std.heap.c_allocator, source_images, ); errdefer types.freeImageAttachmentSlice(std.heap.c_allocator, images_copy);
var recovery_checkpoint_copy = if (recovery_checkpoint) |checkpoint| try checkpoint.dupe(std.heap.c_allocator) else null; errdefer if (recovery_checkpoint_copy) |*checkpoint| checkpoint.deinit(std.heap.c_allocator);
const grants_copy = try types.dupePermissionGrantSlice(std.heap.c_allocator, self.permission_engine.grants.items); errdefer types.freePermissionGrantSlice(std.heap.c_allocator, grants_copy);
var context_snapshot_copy = if (self.context_enabled) try self.context_snapshot.dupe(std.heap.c_allocator) else context_contract.GatheredContextSnapshot{}; errdefer context_snapshot_copy.deinit(std.heap.c_allocator);
const skill_bindings = try dupeUniqueSkillBindingsFromTokens(std.heap.c_allocator, skill_tokens); errdefer worker_runtime.freeSkillBindings(std.heap.c_allocator, skill_bindings);
const skill_display_spans = try dupeSkillDisplaySpansFromTokens(std.heap.c_allocator, skill_tokens); errdefer worker_runtime.freeSkillDisplaySpans(std.heap.c_allocator, skill_display_spans);
return .{ .turn_id = if (recovery_checkpoint) |checkpoint| checkpoint.turn_id else turn_id, .prompt = prompt_copy, .images = images_copy, .authorized_image_catalog = authorized_image_catalog, .model = model_copy, .provider = self.provider_selection.selection().provider, .api_key = api_key_copy, .gateway_team = gateway_team_copy, .credential_source = gateway_credential.source, .account_id = account_id_copy, .permission_mode = self.permission_engine.mode, .history = history_copy, .unversioned_history_count = self.session.unversionedHistoryEnd(), .root_user_intent_context = root_user_intent_context, .grants = grants_copy, .skill_bindings = skill_bindings, .skill_display_spans = skill_display_spans, .context_snapshot = context_snapshot_copy, .recovery_checkpoint = recovery_checkpoint_copy, .recovery_source_already_presented = recovery_checkpoint != null, .user_prompt_already_presented = user_prompt_already_presented, }; }
pub fn request_context_compaction(self: *App) !void { try InputSubmitRuntime.request_context_compaction(self); }
pub fn enqueueContextCompaction(self: *App, operation_id: @import("core/output/compaction_activity.zig").OperationId) !bool { if (self.worker.isProcessing() or self.worker.queuedPromptCount() > 0) return false; const selection = self.provider_selection.selection(); const model = try std.heap.c_allocator.dupe(u8, selection.model); errdefer std.heap.c_allocator.free(model); const credential = self.auth.gatewayCredential() orelse return error.MissingApiKey; const api_key = if (credential.api_key) |value| try std.heap.c_allocator.dupe(u8, value) else @constCast(&[_]u8{}); errdefer secret.zeroAndFree(std.heap.c_allocator, api_key); const gateway_team = if (credential.gateway_team) |team| try std.heap.c_allocator.dupe(u8, team) else null; errdefer if (gateway_team) |team| std.heap.c_allocator.free(team); const account_id = if (self.auth.accountId()) |id| try std.heap.c_allocator.dupe(u8, id) else null; errdefer if (account_id) |id| std.heap.c_allocator.free(id); const history = try self.session.snapshotHistory(std.heap.c_allocator); errdefer types.freeHistoryTurnSlice(std.heap.c_allocator, history);
try self.worker.enqueueContextCompaction(.{ .operation_id = operation_id, .model = model, .provider = selection.provider, .api_key = api_key, .gateway_team = gateway_team, .credential_source = credential.source, .account_id = account_id, .history = history, .unversioned_history_count = self.session.unversionedHistoryEnd(), }); HerdrAppRuntime.reportWorking(self); return true; }
pub fn hasContextToCompact(self: *const App) bool { return self.session.hasContextToCompact(); }
pub fn installInitialMcpRuntime(self: *App, runtime: ?*mcp_runtime_mod.McpRuntime) void { self.mcp.installInitial(runtime); }
pub fn acquireMcpRuntime(self: *App) ?app_mcp_runtime.Lease { return self.mcp.acquire(); }
pub fn snapshotMcpModelCatalog( self: *App, alloc: Allocator, permission_rules: types.PermissionRuleSet, include_ask_deferred: bool, ) !mcp_model_catalog.Snapshot { return self.mcp.snapshotModelCatalog( alloc, permission_rules, include_ask_deferred, ); }
pub fn waitForRequiredMcp( self: *App, alloc: Allocator, cancel_flag: ?*std.atomic.Value(bool), ) !?[]u8 { return self.mcp.waitForRequired( alloc, cancel_flag, @intCast(@max(io_mod.milliTimestamp(), 0)), ); }
pub fn beginMcpReload(self: *App) !void { return self.mcp.beginReload( self.alloc, self.workspace_root, .{ .form = true, .url = true }, if (comptime host_target.is_wasm) loadNoMcpRuntime else builtin_mcp.loadRuntime, builtin_mcp.previewNativeWorkspaceAuthority, self.toolRegistry(), @intCast(@max(io_mod.milliTimestamp(), 0)), ); }
pub fn beginMcpMenuReload(self: *App, generation: u64) !void { return self.mcp.beginMenuReload( self.alloc, self.workspace_root, .{ .form = true, .url = true }, if (comptime host_target.is_wasm) loadNoMcpRuntime else builtin_mcp.loadRuntime, builtin_mcp.previewNativeWorkspaceAuthority, self.toolRegistry(), @intCast(@max(io_mod.milliTimestamp(), 0)), generation, ); }
pub fn beginMcpAuthorityReduction(self: *App, rebuild: bool) !void { return self.mcp.beginAuthorityReduction( self.alloc, self.workspace_root, .{ .form = true, .url = true }, if (comptime host_target.is_wasm) loadNoMcpRuntime else builtin_mcp.loadRuntime, self.toolRegistry(), @intCast(@max(io_mod.milliTimestamp(), 0)), rebuild, ) catch |err| { self.mcp.retireAuthoritySynchronously(self.alloc); return err; }; }
pub fn beginMcpMenuAuthorityReduction( self: *App, rebuild: bool, generation: u64, ) !void { return self.mcp.beginMenuAuthorityReduction( self.alloc, self.workspace_root, .{ .form = true, .url = true }, if (comptime host_target.is_wasm) loadNoMcpRuntime else builtin_mcp.loadRuntime, self.toolRegistry(), @intCast(@max(io_mod.milliTimestamp(), 0)), rebuild, generation, ) catch |err| { self.mcp.retireAuthoritySynchronously(self.alloc); return err; }; }
pub fn startMcpAuthentication( self: *App, server_name: []const u8, ) !mcp_command_provider.AuthenticationStart { return self.mcp.startAuthentication( self.alloc, server_name, self.urlOpener(), ); }
pub fn beginMcpMenuAuthentication(self: *App, generation: u64) !void { const server_name = self.mcp.selectedMenuServerName() orelse return error.McpServerNotFound; const started = try self.mcp.startMenuAuthentication( self.alloc, server_name, self.urlOpener(), generation, ); if (started == .busy) return error.McpAuthenticationBusy; }
pub fn takeMcpAuthenticationCompletion( self: *App, ) !?app_mcp_runtime.AuthenticationCompletion { return self.mcp.takeAuthenticationCompletion(); }
pub fn mcpAuthenticationCompletionOrigin(self: *const App) app_mcp_runtime.PresentationOrigin { return self.mcp.authenticationCompletionOrigin(); }
pub fn applyMcpMenuAuthenticationCompletion( self: *App, generation: u64, completion: *const app_mcp_runtime.AuthenticationCompletion, ) !void { _ = try self.mcp.applyMenuAuthenticationCompletion(self.alloc, generation, completion); self.shell.render_requests.request(.footer); }
pub fn mcpAuthenticationPending( self: *App, server_name: []const u8, ) bool { return self.mcp.authenticationPending(server_name); }
pub fn takeMcpReloadCompletion(self: *App) !?app_mcp_runtime.ReloadCompletion { return self.mcp.takeReloadCompletion(); }
pub fn mcpReloadCompletionOrigin(self: *const App) app_mcp_runtime.PresentationOrigin { return self.mcp.reloadCompletionOrigin(); }
pub fn applyMcpMenuReloadCompletion( self: *App, generation: u64, completion: *const app_mcp_runtime.ReloadCompletion, ) !void { try self.mcp.applyMenuReloadCompletion( self.alloc, generation, completion, @intCast(@max(io_mod.milliTimestamp(), 0)), ); self.shell.render_requests.request(.footer); }
pub fn startMcpDiscovery(self: *App) void { self.mcp.startDiscovery(self.toolRegistry()); }
pub fn presentProjectMcpPrompt(self: *App) !void { const name = (try self.mcp.projectPromptDisplayName(self.alloc)) orelse return; defer self.alloc.free(name); var notice: std.Io.Writer.Allocating = .init(self.alloc); defer notice.deinit(); try notice.writer.print( "Project MCP server '{s}' is defined in .mcp.json.\n [1] approve [2] approve all [3] reject [esc] dismiss remaining prompts\n", .{name}, ); try self.writeTranscriptClassified( notice.writer.buffered(), true, .unknown_raw, ); }
pub fn projectMcpPromptActive(self: *App) bool { return self.mcp.projectPromptActive(); }
pub fn projectMcpPromptName(self: *App, alloc: Allocator) !?[]u8 { return self.mcp.projectPromptName(alloc); }
pub fn suppressProjectMcpPrompts(self: *App) void { self.mcp.suppressProjectPrompts(); }
fn effectiveToolSet(self: *const App) tool_set_contract.ToolSet { if (comptime host_profile.tools) { return builtin_tools.advertisement_set; } return browser_workspace_tools.selectToolSet( false, self.workspaceHostInfo() != null, ); }
pub fn toolRegistry(self: *const App) tool_dispatch.Registry { return self.effectiveToolSet().registry; }
pub fn toolAdvertisementSet(self: *const App) tool_set_contract.ToolSet { return self.effectiveToolSet(); }
pub fn hasMcpTool(self: *App, name: []const u8, access: tool_mcp_runtime.Access) bool { return self.mcp.hasTool(name, access); }
pub fn validateMcpTool( self: *App, arena: Allocator, name: []const u8, arguments_json: []const u8, access: tool_mcp_runtime.Access, ) !tool_mcp_runtime.ValidationResult { return self.mcp.validateTool(arena, name, arguments_json, access); }
pub fn callMcpTool( self: *App, arena: Allocator, name: []const u8, arguments_json: []const u8, max_tool_result_bytes: usize, options: tool_mcp_runtime.CallOptions, ) !?tool_mcp_runtime.CallResult { return self.mcp.callTool(arena, name, arguments_json, max_tool_result_bytes, options); }
pub fn searchMcpTools(self: *App, arena: Allocator, request: tool_mcp_runtime.SearchRequest, permission_rules: types.PermissionRuleSet, access: tool_mcp_runtime.Access, cancel_flag: ?*std.atomic.Value(bool)) !tool_mcp_runtime.SearchResult { return self.mcp.searchTools(arena, request, permission_rules, self.context_limits, access, cancel_flag); }
pub fn mcpToolSchemaJson(self: *App, arena: Allocator, name: []const u8, permission_rules: types.PermissionRuleSet, access: tool_mcp_runtime.Access, cancel_flag: ?*std.atomic.Value(bool)) !?tool_mcp_runtime.ToolSchemaResult { return self.mcp.toolSchema(arena, name, permission_rules, self.context_limits, access, cancel_flag); }
pub fn listMcpServersAndTools(self: *App, alloc: Allocator) ![]u8 { return self.mcp.renderHealth(alloc); }
pub fn openMcpMenu(self: *App) !void { try self.mcp.openMenu( self.alloc, @intCast(@max(io_mod.milliTimestamp(), 0)), ); }
pub fn closeMcpMenu(self: *App) void { self.mcp.closeMenu(self.alloc); }
pub fn beginMcpMenuEffect(self: *App, effect: mcp_menu_state.Effect) !void { return self.mcp.beginMenuEffect( self.alloc, effect, self.permission_engine.rules, self.context_limits, ); }
pub fn recordMcpMenuEffectFailure( self: *App, generation: u64, err: anyerror, ) !void { return self.mcp.recordMenuEffectFailure(self.alloc, generation, err); }
pub fn saveMcpMenuAdd( self: *App, generation: u64, transport: mcp_menu_state.AddTransport, ) !void { return app_mcp_menu_runtime.Runtime(App).saveAdd(self, generation, transport); }
pub fn removeMcpMenuServer(self: *App, generation: u64) !void { return app_mcp_menu_runtime.Runtime(App).removeServer(self, generation); }
pub fn applyMcpMenuTrustAction( self: *App, generation: u64, action: mcp_menu_state.Action, ) !void { return app_mcp_menu_runtime.Runtime(App).applyTrustAction(self, generation, action); }
pub fn summarizeMcpServers(self: *App, alloc: Allocator) ![]u8 { return self.mcp.renderHealthSummary(alloc); }
pub fn snapshotMcpDefinition(self: *App, alloc: Allocator, name: []const u8, known: tool_mcp_runtime.Binding) !tool_mcp_runtime.DefinitionSnapshot { return self.mcp.snapshotToolDefinition(alloc, name, known, self.permission_engine.rules, self.context_limits, .unrestricted); }
pub fn snapshotMcpToolNames(self: *App, alloc: Allocator) ![][]u8 { return self.mcp.snapshotToolNames(alloc, self.permission_engine.rules); }
pub fn snapshotMcpAccessView( self: *App, alloc: Allocator, owner_id: []const u8, parent_id: []const u8, permission_rules: types.PermissionRuleSet, features_visible: bool, ) !?mcp_access_policy.View { return self.mcp.snapshotAccessView( alloc, owner_id, parent_id, permission_rules, features_visible, ); }
pub fn snapshotModelToolProjection( self: *App, alloc: Allocator, permission_mode: types.PermissionMode, ) !tool_projection.EffectiveToolProjection { self.permission_state.authority_mutex.lockUncancelable(io_mod.getIo()); defer self.permission_state.authority_mutex.unlock(io_mod.getIo()); return self.snapshotModelToolProjectionForRules( alloc, permission_mode, self.permission_engine.rules, ); }
pub fn snapshotSubagentModelToolProjection( self: *App, alloc: Allocator, permission_mode: types.PermissionMode, permission_rules: types.PermissionRuleSet, ) !tool_projection.EffectiveToolProjection { return self.snapshotModelToolProjectionForRules( alloc, permission_mode, permission_rules, ); }
fn snapshotModelToolProjectionForRules( self: *App, alloc: Allocator, permission_mode: types.PermissionMode, permission_rules: types.PermissionRuleSet, ) !tool_projection.EffectiveToolProjection { return tool_projection.buildModelToolProjectionForSet(alloc, self.toolAdvertisementSet(), .{ .permission_mode = permission_mode, .permission_rules = permission_rules, .subagent_available = self.session_persistence.subagent_host != null, }); }
pub fn subagentToolContextForAdmission( self: *App, admission: subagent_domain.AdmissionSnapshot, ) tool_runtime.Context { return AgentAppRuntime.toolContextForSubagent(self, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl(), admission); }
pub fn runSubagentChild( raw: ?*anyopaque, turn: *subagent_execution.TurnContext, message: subagent_domain.QueuedMessage, admission: subagent_domain.AdmissionSnapshot, cancel: *std.atomic.Value(bool), ) subagent_execution.ServiceError!subagent_execution.RunOutcome { return AgentAppRuntime.runSubagentChild(raw, turn, message, admission, cancel); }
pub fn requestSkillsRefresh(self: *App) !u64 { const home = try app_runtime_setup.resolveSkillsHome(std.heap.c_allocator); defer if (home) |value| std.heap.c_allocator.free(value); return self.skills.requestRefresh( std.heap.c_allocator, self.workspace_root, home, builtin_skills.root_policy, ); }
pub fn collectPendingSkillRefresh( self: *App, pending: *input_submit_runtime.PendingSubmission, ) !input_submit_runtime.PendingSkillRefresh { if (comptime host_target.is_wasm) return .current; const generation = pending.skill_refresh_generation orelse blk: { const requested = try self.requestSkillsRefresh(); pending.skill_refresh_generation = requested; break :blk requested; }; return switch (self.skills.generationStatus(generation)) { .pending => .pending, .current => .current, .failed => error.SkillCatalogRefreshFailed, }; }
fn pollSkillsRefresh(self: *App) !skill_runtime.RefreshCompletion { const completion = try self.skills.pollRefresh( std.heap.c_allocator, self.workspace_root, builtin_skills.root_policy, ); if (completion == .adopted) { skill_runtime.traceDiagnostics( "interactive_refresh", self.skills.diagnostics, ); } return completion; }
pub fn allowToolForSession(self: *App, tool_name: []const u8, target_path: []const u8) !void { self.permission_state.authority_mutex.lockUncancelable(io_mod.getIo()); defer self.permission_state.authority_mutex.unlock(io_mod.getIo()); try self.permission_engine.allow(self.alloc, tool_name, target_path); }
pub fn permissionReviewerProvider(self: *const App) ?permission_auto_classifier.Provider { return self.providerSet() .select(self.provider_selection.selection().provider) .permission_reviewer; }
pub fn providerSet(self: *const App) provider_set.Set { if (self.provider_selection.model_requests_blocked) return .{ .gateway = .{}, .codex = .{}, .grok = .{} }; if (comptime host_target.is_wasm) { return provider_set.gateway_only(.{ .capabilities = .{ .gateway_prompt_caching = true, .vision_fallback = host_profile.tools, }, .presentation = provider_catalog.find(.gateway), .auth_strategy = .vercel, .fallback_model_capabilities_fn = vercel_model_policy.capabilitiesForModel, .agent_stream = js_host_stream_provider.provider(), .model_catalog = js_host_model_catalog.provider, .permission_reviewer = if (comptime host_profile.tools) builtin_gateway.permission_reviewer.provider else null, }); } var providers = builtin_providers.native; providers.definitions = self.provider_selection.definitions.definitions; if (self.provider_selection.gateway_http_pool) |pool| { // Rebind the gateway stream provider to the process-long pooled // client so chat requests reuse warm keep-alive connections. if (providers.gateway.agent_stream) |stream| { var stamped = stream; stamped.context = pool; providers.gateway.agent_stream = stamped; } } if (comptime !host_profile.tools) { providers.gateway.permission_reviewer = null; providers.codex.permission_reviewer = null; providers.grok.permission_reviewer = null; } return providers; }
pub fn describeToolAction(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return AgentAppRuntime.describeToolAction(self, arena, call, display_target, advertised_dynamic_tool_names, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn resolveToolActionDisplayTarget(self: *App, arena: Allocator, call: ToolCall) !?[]const u8 { return AgentAppRuntime.resolveToolActionDisplayTarget(self, arena, call, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn describeToolActionWithAdvertised(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return self.describeToolAction(arena, call, display_target, advertised_dynamic_tool_names); }
pub fn describeToolActionCompleted(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return AgentAppRuntime.describeToolActionCompleted(self, arena, call, display_target, advertised_dynamic_tool_names, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn describeToolActionCompletedWithAdvertised(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return self.describeToolActionCompleted(arena, call, display_target, advertised_dynamic_tool_names); }
pub fn describeToolActionDenied(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, label: []const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return AgentAppRuntime.describeToolActionDenied(self, arena, call, display_target, label, advertised_dynamic_tool_names, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn describeToolActionDeniedWithAdvertised(self: *App, arena: Allocator, call: ToolCall, display_target: ?[]const u8, label: []const u8, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return self.describeToolActionDenied(arena, call, display_target, label, advertised_dynamic_tool_names); }
pub fn requestToolPermissionSync(self: *App, arena: Allocator, call: ToolCall, review_turn: permission_auto_classifier.ReviewTurnContext, permission_mode: PermissionMode, local_grants: []const PermissionGrant, live_authority: ?agent_runtime.LiveToolAuthority, revalidation: ?agent_runtime.LivePermissionRevalidation, advertised_dynamic_tool_names: []const []const u8, mcp_review_schema_json: ?[]const u8) !command_admission.PermissionOutcome { return AgentAppRuntime.requestToolPermissionSync(self, arena, call, review_turn, permission_mode, local_grants, live_authority, revalidation, advertised_dynamic_tool_names, mcp_review_schema_json, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn requestToolPermissionSyncWithAdvertised(self: *App, arena: Allocator, call: ToolCall, review_turn: permission_auto_classifier.ReviewTurnContext, permission_mode: PermissionMode, local_grants: []const PermissionGrant, live_authority: ?agent_runtime.LiveToolAuthority, revalidation: ?agent_runtime.LivePermissionRevalidation, advertised_dynamic_tool_names: []const []const u8, mcp_review_schema_json: ?[]const u8) !command_admission.PermissionOutcome { return self.requestToolPermissionSync(arena, call, review_turn, permission_mode, local_grants, live_authority, revalidation, advertised_dynamic_tool_names, mcp_review_schema_json); }
pub fn requestPreparedFileMutationPermissionSyncWithAdvertised(self: *App, arena: Allocator, call: ToolCall, prepared: *tool_admission.PreparedFileMutationCall, review_turn: permission_auto_classifier.ReviewTurnContext, permission_mode: PermissionMode, local_grants: []const PermissionGrant, live_authority: ?agent_runtime.LiveToolAuthority, advertised_dynamic_tool_names: []const []const u8) !command_admission.PermissionOutcome { return AgentAppRuntime.requestPreparedFileMutationPermissionSync(self, arena, call, prepared, review_turn, permission_mode, local_grants, live_authority, advertised_dynamic_tool_names, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn validateToolCall(self: *App, arena: Allocator, call: ToolCall) !agent_runtime.ToolCallValidationResult { return AgentAppRuntime.validateToolCall(self, arena, call, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn checkToolAvailability(self: *App, arena: Allocator, call: ToolCall) !?[]const u8 { return AgentAppRuntime.checkToolAvailability(self, arena, call, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn permissionTargetForCall(self: *App, arena: Allocator, call: ToolCall, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return AgentAppRuntime.permissionTargetForCall(self, arena, call, advertised_dynamic_tool_names, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn permissionTargetForCallWithAdvertised(self: *App, arena: Allocator, call: ToolCall, advertised_dynamic_tool_names: []const []const u8) ![]const u8 { return self.permissionTargetForCall(arena, call, advertised_dynamic_tool_names); }
pub fn preparePermissionStateAction( self: *App, arena: Allocator, call: ToolCall, ) !tool_admission.PreparedPermissionStateAction { const ctx = AgentAppRuntime.toolContext( self, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl(), ); return tool_admission.preparePermissionStateAction( ctx.admissionInput(), arena, call, ); }
pub fn fetchModelIds(self: *App) !std.ArrayList([]u8) { return AgentAppRuntime.fetchModelIds( self, if (comptime host_target.is_wasm) js_host_model_catalog.provider else self.providerSet().select(self.provider_selection.selection().provider).model_catalog orelse return error.ModelCatalogUnavailable, builtin_gateway.models_path, ); }
pub fn startModelCacheWarmup(self: *App) void { if (comptime host_profile.cooperative_agent) { if (self.auth.credentialNeedsRefresh()) { debug_trace.logf("auth", "model_cache_warmup_deferred reason=credential_refresh_required", .{}); return; } self.model_cache.loadCooperative( js_host_model_catalog.provider, self.auth.modelCatalogAccess(), ); } else { self.model_cache.startWarmup( self.providerSet().select(self.provider_selection.selection().provider).model_catalog orelse return, self.auth.modelCatalogAccess(), ); } }
pub fn ensureModelCache(self: *App) void { self.startModelCacheWarmup(); }
pub fn isModelCacheLoading(self: *App) bool { return self.model_cache.isLoading(); }
pub fn isModelCacheFailed(self: *App) bool { return self.model_cache.isFailed(); }
pub fn snapshotCachedModelIds(self: *App, alloc: Allocator) !?std.ArrayList([]u8) { return self.model_cache.snapshotCachedModelIds(alloc); }
pub fn resolvedModelCapabilities(self: *App, model: []const u8) model_capabilities.Capabilities { const bundle = self.providerSet().select(self.provider_selection.selection().provider); return model_capabilities.mergeCapabilities( bundle.fallbackModelCapabilities(model), self.model_cache.metadataForModel(model), ); }
pub fn resolveModelCapabilitiesForRequest(self: *App, model: []const u8) model_capabilities.ResolveError!model_capabilities.Capabilities { _ = try self.model_cache.resolveForRequest(model, &self.worker.worker_cancel_requested); return self.resolvedModelCapabilities(model); }
/// Must be called after init() returns so the loader thread captures /// a pointer to the final App location (not a temporary). Same hazard /// as `startAutoUpgrade` above. pub fn startFileIndex(self: *App) void { WorkspaceAppRuntime.startFileIndex(self); }
pub fn fileCompletions( self: *App, query: []const u8, out: []file_index_mod.SearchResult, match_spans: []file_index_mod.MatchSpan, path_storage: []u8, ) app_workspace_runtime.FileCompletionError!usize { return WorkspaceAppRuntime.fileCompletions(self, query, out, match_spans, path_storage); }
pub fn fileCompletionsAtRevision( self: *App, revision: file_index_mod.ReadableRevision, query: []const u8, out: []file_index_mod.SearchResult, match_spans: []file_index_mod.MatchSpan, path_storage: []u8, ) app_workspace_runtime.FileCompletionError!usize { return WorkspaceAppRuntime.fileCompletionsAtRevision(self, revision, query, out, match_spans, path_storage); }
pub fn reconcileDirectoryCompletion(self: *App, eligible: bool) void { WorkspaceAppRuntime.reconcileDirectoryCompletion(self, eligible); }
pub fn prepareDirectoryCompletion(self: *App) void { WorkspaceAppRuntime.prepareDirectoryCompletion(self); }
pub fn harvestDirectoryCompletion(self: *App, eligible: bool) void { WorkspaceAppRuntime.harvestDirectoryCompletion(self, eligible); }
pub fn fileCompletionRevision(self: *const App) file_index_mod.ReadableRevision { return WorkspaceAppRuntime.fileCompletionRevision(self); }
pub fn fileCompletionScopeEpoch(self: *const App) u64 { return WorkspaceAppRuntime.fileCompletionScopeEpoch(self); }
pub fn fileCompletionsDependOnIndex(self: *const App, query: []const u8) bool { return WorkspaceAppRuntime.fileCompletionsDependOnIndex(self, query); }
pub fn isFileIndexLoading(self: *App) bool { return self.file_index.currentState() == .loading; }
pub fn isFileIndexFailed(self: *App) bool { return self.file_index.currentState() == .failed; }
pub fn refreshFileIndex(self: *App) void { if (comptime !host_profile.file_index) return; WorkspaceAppRuntime.refreshFileIndex(self); }
pub fn workspaceAccess(self: *App) *app_workspace_runtime.Access { return WorkspaceAppRuntime.access(self); }
pub fn workspaceAccessScope(self: *const App) app_workspace_runtime.AccessScope { return WorkspaceAppRuntime.scope(self); }
pub fn adoptWorkspaceAccess(self: *App, access: app_workspace_runtime.Access) void { WorkspaceAppRuntime.adopt(self, access); }
pub fn installWorkspaceAccess(self: *App, access: *app_workspace_runtime.Access) bool { return WorkspaceAppRuntime.install(self, access); }
pub fn refreshWorkspaceAccess(self: *App) app_workspace_runtime.Error!bool { return WorkspaceAppRuntime.refreshAvailability(self); }
pub fn isCurrentFileCompletion( self: *App, query: []const u8, path: []const u8, kind: file_index_mod.CandidateKind, ) bool { return WorkspaceAppRuntime.isCurrentFileCompletion(self, query, path, kind); }
pub fn modelCompletions(self: *App, query: []const u8, out: [][]const u8) usize { self.ensureModelCache(); return self.model_cache.modelCompletions(query, out); }
pub fn catalogModelCompletion(self: *App, model: []const u8) ?[]const u8 { self.ensureModelCache(); return self.model_cache.catalogModelCompletion(model); }
pub fn pushText(self: *App, text: []const u8) !void { try self.worker.pushEvent(std.heap.c_allocator, .{ .assistant_presentation = .{ .text = @constCast(text), } }); if (comptime host_profile.cooperative_agent) { try WorkerAppRuntime.tick(self, app_callbacks.Bindings(App).workerEventHandlers(self)); try self.flushRequestedFrame(); } }
pub fn processQueuedWork(self: *App, work: WorkItem, failure_provenance: *?@import("core/output/compaction_activity.zig").ErrorProvenance) !void { const result = switch (work) { .prompt => |job| AgentAppRuntime.processQueuedPrompt( self, job, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl(), failure_provenance, ), .compact_context => |task| AgentAppRuntime.processContextCompaction( self, task, builtin_gateway.retry_count, failure_provenance, ), }; result catch |err| { if (err == error.TurnFinalizationDeliveryFailed) return; return err; }; }
pub fn executeToolCall(self: *App, request: agent_runtime.ToolExecutionRequest) !ToolExecutionResult { if (comptime !host_profile.tools) { if (comptime !host_profile.js_host_workspace) { return agent_runtime.unavailableHostToolResult(request.result_allocator); } if (self.workspaceHostInfo() == null) { return agent_runtime.unavailableHostToolResult(request.result_allocator); } } return AgentAppRuntime.executeToolCall(self, request, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn executeToolCallWithAdvertised(self: *App, request: agent_runtime.ToolExecutionRequest) !ToolExecutionResult { return self.executeToolCall(request); }
pub fn releaseAgentTerminalLease(self: *App, session_id: []const u8) !void { return AgentAppRuntime.releaseAgentTerminalLease( self, session_id, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl(), ); }
pub fn formatToolExecutionErrorForAgent(self: *App, arena: Allocator, tool_name: []const u8, err: anyerror) ![]const u8 { _ = self; return app_process_runtime.Runtime(App).formatToolExecutionError(arena, tool_name, err); }
pub fn appendRuntimeContextMessage(self: *App, arena: Allocator, messages: *std.ArrayList(ChatMessage)) !void { try AgentAppRuntime.appendTransientRuntimeContextMessage(self, arena, messages, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); }
pub fn appendStaticContextMessage(self: *App, arena: Allocator, project_context: ?[]const u8, messages: *std.ArrayList(ChatMessage)) !void { try AgentAppRuntime.appendStaticContextMessage(self, arena, project_context, messages, &ignored_list_entries, max_list_entries, max_read_file_bytes, max_read_file_lines, max_read_file_line_len, max_command_output_bytes, builtin_gateway.retry_count, builtin_gateway.defaultChatUrl()); if (comptime host_target.is_wasm) { try messages.append(arena, .{ .role = .system, .content = browser_capabilities.model_context, }); } }
pub fn writeTranscript(self: *App, text: []const u8, record: bool) !void { try self.shell.writeTranscript(self.alloc, &self.metrics, text, record); }
pub fn writeTranscriptClassified(self: *App, text: []const u8, record: bool, class: transcript_runtime.RawEntryClass) !void { try self.shell.writeTranscriptClassified(self.alloc, &self.metrics, text, record, class); }
pub fn writeCompletedToolStatus( self: *App, kind: types.ToolOutcomeKind, text: []const u8, record: bool, ) !void { try self.shell.writeCompletedToolStatus(self.alloc, &self.metrics, kind, text, record); }
pub fn writeCompletedToolStatusReturningEntryId( self: *App, kind: types.ToolOutcomeKind, text: []const u8, record: bool, ) !u32 { return self.shell.writeCompletedToolStatusReturningEntryId( self.alloc, &self.metrics, kind, text, record, ); }
pub fn attachHistoricalToolDetail( self: *App, entry_id: u32, call: types.ToolCall, result: types.PersistedToolResult, ) !void { const activity_kind = tool_dispatch.toolActivityKindForCall(self.alloc, self.toolRegistry(), call); try self.shell.attachHistoricalToolDetail(self.alloc, entry_id, call, activity_kind, result); }
pub fn attachHistoricalToolDetailWithLifecycle( self: *App, entry_id: u32, call: types.ToolCall, result: types.PersistedToolResult, lifecycle_id: types.ToolLifecycleId, ) !void { const activity_kind = tool_dispatch.toolActivityKindForCall(self.alloc, self.toolRegistry(), call); try self.shell.attachHistoricalToolDetailWithLifecycle( self.alloc, entry_id, call, activity_kind, result, lifecycle_id, ); }
pub fn attachHistoricalToolDetailAfterCommandOutput( self: *App, entry_id: u32, call: types.ToolCall, result: types.PersistedToolResult, ) !void { const activity_kind = tool_dispatch.toolActivityKindForCall(self.alloc, self.toolRegistry(), call); try self.shell.attachHistoricalToolDetailAfterCommandOutput( self.alloc, entry_id, call, activity_kind, result, ); }
pub fn writeHistoricalQuestionResolution( self: *App, answers: []const types.QuestionAnswer, ) !u32 { const text = try question_ui.composeResolvedQuestionAnswers( self.alloc, answers, self.shell.layout.cols, ); defer self.alloc.free(text); return self.appendReplaceableTranscriptLine(text); }
pub fn prepareHistoricalQuestionResolution( self: *App, answers: []const types.QuestionAnswer, ) ![]u8 { return question_ui.composeResolvedQuestionAnswers( self.alloc, answers, self.shell.layout.cols, ); }
pub fn attachHistoricalToolCallWithoutResult( self: *App, entry_id: u32, call: types.ToolCall, ) !void { try self.shell.attachHistoricalToolCallWithoutResult(self.alloc, entry_id, call); }
pub fn attachHistoricalCommandOutput(self: *App, entry_id: u32) void { self.shell.attachHistoricalCommandOutput(self.alloc, entry_id); }
pub fn attachHistoricalCancelledCommandDetail( self: *App, entry_id: u32, call: types.ToolCall, command_artifact_handle: ?[]const u8, replayed_output: bool, ) !void { try self.shell.attachHistoricalCancelledCommandDetail( self.alloc, entry_id, call, command_artifact_handle, replayed_output, ); }
pub fn appendReplaceableTranscriptLine(self: *App, text: []const u8) !u32 { return self.shell.appendReplaceableTranscriptLine(self.alloc, &self.metrics, text); }
pub fn appendReplaceableTranscriptLineClassified(self: *App, text: []const u8, class: transcript_runtime.RawEntryClass) !u32 { return self.shell.appendReplaceableTranscriptLineClassified(self.alloc, &self.metrics, text, class); }
pub fn appendReplaceableTranscriptLineSilent(self: *App, text: []const u8) !u32 { return self.shell.appendReplaceableTranscriptLineSilent(self.alloc, text); }
pub fn appendReplaceableTranscriptLineSilentClassified(self: *App, text: []const u8, class: transcript_runtime.RawEntryClass) !u32 { return self.shell.appendReplaceableTranscriptLineSilentClassified(self.alloc, text, class); }
pub fn replaceTrailingTranscriptLine(self: *App, text: []const u8) !bool { return self.shell.replaceTrailingTranscriptLine(self.alloc, &self.metrics, text); }
pub fn replaceTrailingTranscriptLineSilent(self: *App, text: []const u8) !bool { return self.shell.replaceTrailingTranscriptLineSilent(self.alloc, text); }
pub fn writeDomainNotice(self: *App, notice: types.SemanticNotice, record: bool) !void { try self.shell.writeNotice(self.alloc, &self.metrics, notice, record); }
pub fn appendDomainNotice(self: *App, notice: types.SemanticNotice) !u32 { return self.shell.appendSemanticNotice(self.alloc, notice); }
pub fn appendReplaceableDomainNotice(self: *App, notice: types.SemanticNotice) !u32 { return self.shell.appendReplaceableSemanticNotice(self.alloc, notice); }
pub fn replaceDomainNotice(self: *App, entry_id: u32, notice: types.SemanticNotice) !bool { return self.shell.replaceSemanticNotice(self.alloc, entry_id, notice); }
pub fn writeCommandOutputChunk(self: *App, stream: command_output_content.Stream, text: []const u8, record: bool) !void { try self.shell.writeCommandOutputChunk(self.alloc, &self.metrics, RenderAppRuntime.shellStyles(), stream, text, record); }
pub fn writeCommandOutputChunkForLifecycle( self: *App, lifecycle_id: ?types.ToolLifecycleId, stream: command_output_content.Stream, text: []const u8, record: bool, ) !void { try self.shell.writeCommandOutputChunkForLifecycle( self.alloc, &self.metrics, RenderAppRuntime.shellStyles(), lifecycle_id, stream, text, record, ); }
pub fn flushCommandOutputSummary(self: *App, record: bool) !void { try self.shell.flushCommandOutputSummary(self.alloc, &self.metrics, RenderAppRuntime.shellStyles(), record); }
pub fn flushCommandOutputSummaryForLifecycle(self: *App, lifecycle_id: ?types.ToolLifecycleId, record: bool) !void { try self.shell.flushCommandOutputSummaryForLifecycle( self.alloc, &self.metrics, RenderAppRuntime.shellStyles(), lifecycle_id, record, ); }
pub fn preparePersistedFileDiff( self: *App, presentation: types.CommittedFilePresentation, ) !agent_runtime.DiffEntryPayload { _ = self; const diff_mod = @import("core/output/diff.zig"); return diff_mod.formatPersistedFileChangePayload( std.heap.c_allocator, presentation, .{ .added_fg = ui_render.diff_added_style, .removed_fg = ui_render.diff_removed_style, .context_fg = ui_render.dim_style, .added_marker_fg = ui_render.diff_added_marker_style, .removed_marker_fg = ui_render.diff_removed_marker_style, .reset = ui_render.reset_style, }, ); }
pub fn registerAndEmitDiffBlock(self: *App, payload: agent_runtime.DiffEntryPayload) !void { const diff_mod = @import("core/output/diff.zig"); const c_alloc = std.heap.c_allocator;
const id = self.next_diff_id; var appended = false; errdefer if (!appended) diff_mod.freeDiffEntryPayload(c_alloc, payload);
try self.diff_entries.append(c_alloc, .{ .id = id, .full = payload.full, }); appended = true; self.next_diff_id += 1;
defer c_alloc.free(payload.preview); const wrapped = try diff_mod.wrapWithMarkers(c_alloc, id, payload.preview); defer c_alloc.free(wrapped); try self.writeTranscriptClassified(wrapped, true, .diff_block); }
pub fn fullTranscriptDiffResolver(self: *App) @import("ui/full_transcript_screen.zig").FullDiffResolver { return .{ .context = self, .full_for_marker = fullDiffForMarker, .has_full_for_lifecycle = hasFullDiffForLifecycle, }; }
fn fullDiffForMarker(ctx: *anyopaque, id: u32) ?[]const u8 { const self: *App = @ptrCast(@alignCast(ctx)); for (self.diff_entries.items) |entry| { if (entry.id != id) continue; const full = entry.full orelse return null; return full.content; } return null; }
fn hasFullDiffForLifecycle( ctx: *anyopaque, lifecycle_id: types.ToolLifecycleId, ) bool { const self: *App = @ptrCast(@alignCast(ctx)); for (self.diff_entries.items) |entry| { const full = entry.full orelse continue; if (full.lifecycle_id.turn_id != lifecycle_id.turn_id) continue; if (std.mem.eql(u8, full.lifecycle_id.call_id, lifecycle_id.call_id)) return true; } return false; }
pub fn fullTranscriptSidecarCapability(self: *App) ?*session_child_store.SessionChildCapability { return SessionAppRuntime.childCapability(self); }
pub fn pacerEmit(ctx: *anyopaque, text: []const u8) anyerror!void { const self: *App = @ptrCast(@alignCast(ctx)); _ = try self.shell.streamAssistantChunk(self.alloc, &self.metrics, text); }
pub fn appendAssistantTable(self: *App, table: assistant_presentation.TablePayload) !void { _ = try self.shell.appendAssistantTableOwned(self.alloc, table); }
pub fn appendAssistantCodeBlock(self: *App, block: assistant_presentation.CodeBlockPayload) !void { _ = try self.shell.appendAssistantCodeBlockOwned(self.alloc, block); }
pub fn appendAssistantThematicRule(self: *App) !void { _ = try self.shell.appendAssistantThematicRule(self.alloc); }
pub fn appendHistoryTurn(self: *App, turn: types.HistoryTurn) !void { try SessionAppRuntime.appendHistoryTurn(self, turn); }
pub fn persistRuntimePreferences( self: *App, patch: app_session_runtime.SessionPreferencePatch, ) app_session_runtime.PreferenceCommitResult { return SessionAppRuntime.commitRuntimePreferences(self, patch); }
pub fn fastModeModelBound(self: *const App) bool { return SessionAppRuntime.fastModeModelBound(self); }
pub fn finishPromptPresentation(self: *App, finished: types.FinishedPrompt) !assistant_pacer.FinishResult { return app_callbacks.Bindings(App).finishPromptPresentation(self, finished); }
pub fn pacerFinish(ctx: *anyopaque, finished: types.FinishedPrompt) anyerror!assistant_pacer.FinishResult { const self: *App = @ptrCast(@alignCast(ctx)); const result = try app_callbacks.Bindings(App).finishPromptPresentation(self, finished); if (result == .committed) self.notificationPresentationFinished(); return result; }
pub fn pacerCallbacks(self: *App) assistant_pacer.TickCallbacks { return .{ .emit_ctx = self, .emit_fn = App.pacerEmit, .finish_ctx = self, .finish_fn = App.pacerFinish, }; }
fn nativeClearProbeEligible(self: *const App, byte: u8) bool { if (byte < 32 or byte == 127) return false; if (io_mod.getenv("TMUX") != null) return false; // An alternate-screen surface (full transcript, approval review, // catalog menu) owns the terminal cursor. The probe compares against // the main-grid footer row, so any response from the alternate screen // is a guaranteed false mismatch; never begin while one is active. if (self.terminal.alternate_screen_owner != .none) return false; if (self.terminal_input_runtime.native_clear_probe.disabled() or self.terminal_input_runtime.native_clear_probe.active() or self.input_runtime.paste.active() or self.terminal_input_runtime.hasPendingTerminalAction() or self.question_prompt.isActive() or self.approval_prompt.isActive() or @constCast(&self.mcp).projectPromptActive() or self.auth.apiKeyEntryActive() or !self.shell.has_committed_frame or !self.shell.footer_viewport.has_frame or self.shell.footer_viewport.cursor.row == 0 or self.shell.layout.cols < cursor_probe.confirmation_tag_column or !shell_runtime.resizeLifecycleIdle(&self.shell) or resize_interlock.resizePending() or !self.terminal_input_runtime.terminal_cursor_probe.canBegin()) { return false; } return true; }
pub fn prepareApiKeyInputBoundary(self: *App) void { if (self.terminal_input_runtime.native_clear_probe.active()) { const discarded = self.terminal_input_runtime.native_clear_probe.settle().len; self.terminal_input_runtime.native_clear_probe.clearSettledInput(); debug_trace.logf( "auth", "api key stage discarded native-clear probe input bytes={d}", .{discarded}, ); }
self.terminal_input_runtime.terminal_cursor_probe.cancel(); var discarded: usize = 0; while (self.terminal_input_runtime.terminal_cursor_probe.takeDeferredByte()) |byte| { _ = byte; std.debug.assert(self.terminal_input_runtime.terminal_cursor_probe.consumeDeferredInputDispatch()); discarded += 1; } if (discarded > 0) { debug_trace.logf( "auth", "api key stage discarded cursor-probe input bytes={d}", .{discarded}, ); } }
fn replayNativeClearProbeInput(self: *App) !void { const retained = self.terminal_input_runtime.native_clear_probe.settle(); defer self.terminal_input_runtime.native_clear_probe.clearSettledInput(); for (retained) |retained_byte| { try self.handleTerminalInputByte(retained_byte); if (self.should_exit) return; } }
fn handleTerminalInputByte(self: *App, byte: u8) !void { const context = try InputAppRuntime.prepareTerminalDecode(self) orelse return; const ingress = self.terminal_input_runtime.decodeTerminalByte( byte, context, ); try self.routeTerminalInputIngress(ingress); }
fn routeTerminalInputIngress( self: *App, initial_ingress: input_action.TerminalInputIngress, ) !void { var ingress = initial_ingress; while (true) { const replay_byte = try InputAppRuntime.handleTerminalInputIngressWithLimits( self, ingress, input_limits, max_prompt_history, ); const replay = replay_byte orelse return; const context = try InputAppRuntime.prepareTerminalDecode(self) orelse return; ingress = self.terminal_input_runtime.decodeTerminalByte(replay, context); } }
fn finishNativeClearProbe(self: *App, reset_visual_epoch: bool) !void { if (reset_visual_epoch) { _ = try RenderAppRuntime.resetVisualEpoch(self, .native_clear_probe); } try self.replayNativeClearProbeInput(); }
fn retainDeferredNativeClearProbeInput(self: *App) !bool { while (self.terminal_input_runtime.terminal_cursor_probe.takeDeferredByte()) |deferred| { if (!self.terminal_input_runtime.native_clear_probe.canRetainBytes(1)) { std.debug.assert(self.terminal_input_runtime.terminal_cursor_probe.consumeDeferredInputDispatch()); try self.finishNativeClearProbe(false); try self.handleTerminalInputByte(deferred); while (self.terminal_input_runtime.terminal_cursor_probe.takeDeferredByte()) |remaining| { std.debug.assert(self.terminal_input_runtime.terminal_cursor_probe.consumeDeferredInputDispatch()); try self.handleTerminalInputByte(remaining); if (self.should_exit) break; } return false; } try self.terminal_input_runtime.native_clear_probe.retainBytes(self.alloc, &.{deferred}); std.debug.assert(self.terminal_input_runtime.terminal_cursor_probe.consumeDeferredInputDispatch()); } return true; }
fn beginNativeClearProbe(self: *App, byte: u8) !bool { if (!self.nativeClearProbeEligible(byte)) return false;
const expected_row = self.shell.footer_viewport.cursor.row; try self.terminal_input_runtime.native_clear_probe.begin(self.alloc, expected_row, byte); self.terminal_input_runtime.terminal_cursor_probe.begin( .ansi_tagged, io_mod.milliTimestamp() + cursor_probe.response_idle_timeout_ms, ) catch { try self.replayNativeClearProbeInput(); return true; }; self.terminal.requestResizeCursorPosition(.ansi_tagged) catch |err| { self.terminal_input_runtime.terminal_cursor_probe.cancel(); self.terminal_input_runtime.native_clear_probe.disable(false); debug_trace.logf("native_clear", "native_clear_probe_write_failed err={s}", .{@errorName(err)}); try self.replayNativeClearProbeInput(); return true; }; debug_trace.logf( "native_clear", "native_clear_probe requested expected_row={d}", .{expected_row}, ); return true; }
fn handleNativeClearProbeInput(self: *App, byte: u8) !void { self.terminal_input_runtime.terminal_cursor_probe.noteInputActivity(io_mod.milliTimestamp()); switch (self.terminal_input_runtime.terminal_cursor_probe.feed(byte)) { .pending => {}, .position => |position| { const expected_row = self.terminal_input_runtime.native_clear_probe.expectedRow(); const reset_visual_epoch = position.row != expected_row; debug_trace.logf( "native_clear", "native_clear_probe {s} expected_row={d} observed_row={d}", .{ if (reset_visual_epoch) "mismatch" else "match", expected_row, position.row }, ); try self.finishNativeClearProbe(reset_visual_epoch); }, .late_response => { debug_trace.logf("native_clear", "native_clear_probe_late_response_discarded", .{}); }, .forward => |forwarded| { if (self.terminal_input_runtime.native_clear_probe.canRetainBytes(forwarded.slice().len)) { try self.terminal_input_runtime.native_clear_probe.retainBytes(self.alloc, forwarded.slice()); return; }
_ = self.terminal_input_runtime.terminal_cursor_probe.expire(io_mod.milliTimestamp()); self.terminal_input_runtime.native_clear_probe.disable(true); debug_trace.logf("native_clear", "native_clear_probe_overflow", .{}); if (try self.retainDeferredNativeClearProbeInput()) { try self.finishNativeClearProbe(false); } for (forwarded.slice()) |forwarded_byte| { try self.handleTerminalInputByte(forwarded_byte); if (self.should_exit) return; } }, } }
fn collectNativeClearProbeFacts(self: *App) !void { switch (self.terminal_input_runtime.terminal_cursor_probe.poll(io_mod.milliTimestamp())) { .none => {}, .probe_timed_out => { self.terminal_input_runtime.native_clear_probe.disable(true); debug_trace.logf("native_clear", "native_clear_probe_timeout", .{}); if (!try self.retainDeferredNativeClearProbeInput()) { debug_trace.logf("native_clear", "native_clear_probe_overflow", .{}); return; } try self.finishNativeClearProbe(false); }, .late_window_expired => { self.terminal_input_runtime.native_clear_probe.finishLateResponse(); debug_trace.logf("native_clear", "native_clear_probe_late_window_expired", .{}); }, } }
fn collectThemeFacts(self: *App) !void { const now_ms = io_mod.milliTimestamp(); self.terminal_input_runtime.terminal_theme_monitor.poll(now_ms);
// A configured light|dark pin (FX_THEME or the settings "theme" key) // locks the variant; keep owning protocol bytes (monitor started) but // never query or apply live theme updates. Custom theme files stay // live: updates re-resolve the theme pair. if (ui_render.themeInputLocked()) { _ = self.terminal_input_runtime.terminal_theme_monitor.takeSettledUpdate(); return; }
if (self.terminal_input_runtime.terminal_theme_monitor.takeSettledUpdate()) |update| { debug_trace.logf("theme", "theme_update_settled light={s} rgb={s}", .{ if (update.light) "true" else "false", if (update.rgb == null) "fallback" else "terminal", }); try RenderAppRuntime.applyThemeUpdate(self, update.light, update.rgb); } if (InputAppRuntime.terminalPasteActive(self) or self.terminal_input_runtime.native_clear_probe.active() or self.terminal_input_runtime.native_clear_probe.awaitingLateResponse()) { return; } if (self.terminal_input_runtime.terminal_theme_monitor.takeQueryRequest(now_ms)) |request| { debug_trace.logf("theme", "theme_query_requested kind={s}", .{@tagName(request)}); const query_result = switch (request) { .response_fence => self.terminal.requestThemeResponseFence(), .background => self.terminal.requestThemeBackground(), }; query_result catch |err| { self.terminal_input_runtime.terminal_theme_monitor.failQuery(now_ms); debug_trace.logf("theme", "theme_query_failed kind={s} err={s}", .{ @tagName(request), @errorName(err), }); }; } }
pub fn loopCollectFacts(ctx: *anyopaque) !void { const self: *App = @ptrCast(@alignCast(ctx)); if (!try WorkerAppRuntime.authorizeInteractiveAdmission(self)) return;
if (comptime !host_target.is_wasm) { if (self.file_index.joinThreadIfDone(std.heap.c_allocator)) { self.shell.render_requests.request(.footer); } switch (try self.pollSkillsRefresh()) { .none, .unchanged => {}, .adopted, .failed => self.shell.render_requests.request(.footer), } try app_commands.Handlers(App).collectSkillsRefreshFacts(self); } InputSubmitRuntime.collectPendingSubmissionFacts(self); InputAppRuntime.collectFilePickerFacts(self);
try self.collectThemeFacts();
if (comptime !host_target.is_wasm) { UpgradeAppRuntime.collectUpgradeFacts(self); } app_permission_runtime.Runtime(App).tick( self, app_permission_runtime.monotonicMillis(), );
if (try self.model_cache.pollLoadTransition()) { RenderAppRuntime.requestActiveSurfaceFrame(self, .footer); } if (try app_commands.Handlers(App).collectUsageDashboardFacts(self)) { RenderAppRuntime.requestActiveSurfaceFrame(self, .footer); } switch (try self.mcp.collectMenuCompletion(self.alloc)) { .none => {}, .repaint => RenderAppRuntime.requestActiveSurfaceFrame(self, .footer), } try app_commands.Handlers(App).collectMcpAuthenticationFacts(self); try app_commands.Handlers(App).collectMcpReloadFacts(self); if (try self.mcp.refreshMenuHealth(self.alloc, @intCast(@max(io_mod.milliTimestamp(), 0)))) { RenderAppRuntime.requestActiveSurfaceFrame(self, .footer); } if (comptime host_profile.native_auth or host_profile.js_host_auth) { try AuthAppRuntime.collectProviderPreparationFacts(self); try AuthAppRuntime.collectSourceInventoryFacts(self); try AuthAppRuntime.collectSignInFacts(self); } if (comptime host_profile.native_auth) { try AuthAppRuntime.collectApiKeySaveFacts(self); } try self.processNextCooperativePrompt();
const cols_before_resize = self.shell.layout.cols; if (self.terminal_input_runtime.native_clear_probe.active() or self.terminal_input_runtime.native_clear_probe.awaitingLateResponse()) { try self.collectNativeClearProbeFacts(); } else { shell_runtime.collectResizeFacts( self.terminal, &self.shell, &self.metrics, &self.terminal_input_runtime.terminal_cursor_probe, &resize_interlock, footer_rows, resize_debounce_ms, !InputAppRuntime.terminalPasteActive(self) and !self.auth.apiKeyEntryActive(), ) catch |err| { if (err != error.TerminalTooSmall and err != error.UnableToReadTerminalSize) { return err; } }; } // Terminal width changed with the modal open, so the footer // panel needs to re-wrap labels and descriptions. if (self.question_prompt.isActive() and cols_before_resize != self.shell.layout.cols) { self.shell.render_requests.request(.modal); } if (cols_before_resize != self.shell.layout.cols) { self.input_runtime.vertical_navigation.reset(); }
if (comptime !host_target.is_wasm) { try SessionAppRuntime.pollSessionPicker(self); if (try SessionAppRuntime.pollSessionTitleGeneration(self)) { RenderAppRuntime.requestActiveSurfaceFrame(self, .footer); } } try self.shell.prewarmFullTranscriptPage( self.fullTranscriptSidecarCapability(), self.fullTranscriptDiffResolver(), ); if (try self.shell.pollFullTranscriptPageLoad()) { RenderAppRuntime.requestActiveSurfaceFrame(self, .modal); } if (!self.shell.fullTranscriptActive() and self.shell.takeReadyFullTranscriptOpen() and self.terminal.alternate_screen_owner == .none and !self.approval_prompt.isActive()) { try app_lifecycle.openFullTranscript( self.alloc, &self.terminal, &self.shell, &self.metrics, ); debug_trace.logf( "full_transcript", "depth_transition from=inline to=full route=root trigger=ctrl_o", .{}, ); RenderAppRuntime.requestActiveSurfaceFrame(self, .modal); } if (self.shell.takeFullTranscriptPreparationFailure()) { if (self.shell.fullTranscriptActive()) { try app_lifecycle.closeFullTranscript( self.alloc, &self.terminal, &self.shell, &self.metrics, ); } try self.writeDomainNotice(.{ .topic = "transcript", .tone = .@"error", .body = "Full transcript preparation failed. The reader was closed instead of showing stale content.", }, true); } const input_now_ms = io_mod.milliTimestamp(); InputAppRuntime.expireTerminalInputGestures(self, input_now_ms); const terminal_input = self.terminal_input_runtime.flushTerminalAction( input_now_ms, input_escape_timeout_ms, InputAppRuntime.terminalPasteActive(self), ); try self.routeTerminalInputIngress(terminal_input); try WorkerAppRuntime.tick(self, app_callbacks.Bindings(App).workerEventHandlers(self)); const now_ns = io_mod.nanoTimestamp(); if (!self.approval_prompt.isActive() and !self.question_prompt.isActive() and !self.auth.apiKeyEntryActive()) { try self.pacer.tick(self.alloc, now_ns, self.pacerCallbacks()); } else { self.pacer.pause(now_ns); } }
pub fn loopCommitFrame(ctx: *anyopaque) !void { const self: *App = @ptrCast(@alignCast(ctx)); if (!try WorkerAppRuntime.authorizeInteractiveAdmission(self)) return; if (self.terminal_input_runtime.native_clear_probe.active()) return; _ = self.admitPendingResizeSignal("post_input"); InputAppRuntime.prepareFilePicker(self); try self.flushRequestedFrame(); }
pub fn admitPendingApprovalResize(self: *App) bool { return self.admitPendingResizeSignal("approval_input"); }
pub fn claimApprovalAffirmative(_: *App) bool { return resize_interlock.claimAffirmative(); }
pub fn releaseApprovalAffirmative(_: *App) void { resize_interlock.releaseAffirmative(); }
fn admitPendingResizeSignal(self: *App, source: []const u8) bool { return shell_runtime.admitResizeSignal( &self.shell, &resize_interlock, io_mod.milliTimestamp(), resize_debounce_ms, source, ); }
fn handleCursorDeferredInputByte(self: *App, byte: u8) !void { if (self.terminal_input_runtime.native_clear_probe.active()) { if (self.terminal_input_runtime.native_clear_probe.canRetainBytes(1)) { try self.terminal_input_runtime.native_clear_probe.retainBytes(self.alloc, &.{byte}); return; }
_ = self.terminal_input_runtime.terminal_cursor_probe.expire(io_mod.milliTimestamp()); self.terminal_input_runtime.native_clear_probe.disable(true); debug_trace.logf("native_clear", "native_clear_probe_overflow", .{}); try self.finishNativeClearProbe(false); } try self.handleTerminalInputByte(byte); }
fn routeActivePasteTransportByte(self: *App, byte: u8) !bool { return InputAppRuntime.routeActivePasteIngressByteWithLimits( self, byte, input_limits, max_prompt_history, ); }
fn handleAfterThemeMonitorByte(self: *App, byte: u8) !void { if (try self.routeActivePasteTransportByte(byte)) return; if (!self.terminal_input_runtime.terminal_cursor_probe.interceptsInput()) { if (try self.beginNativeClearProbe(byte)) return; try self.handleTerminalInputByte(byte); return; }
if (self.terminal_input_runtime.native_clear_probe.active()) { try self.handleNativeClearProbeInput(byte); return; }
self.terminal_input_runtime.terminal_cursor_probe.noteInputActivity(io_mod.milliTimestamp()); switch (self.terminal_input_runtime.terminal_cursor_probe.feed(byte)) { .pending => {}, .position => |position| { shell_runtime.completeResizeCursorProbe(&self.shell, position); }, .late_response => { if (self.terminal_input_runtime.native_clear_probe.awaitingLateResponse()) { self.terminal_input_runtime.native_clear_probe.finishLateResponse(); debug_trace.logf("native_clear", "native_clear_probe_late_response_discarded", .{}); } else { debug_trace.logf("resize", "cursor_measure_late_response_discarded", .{}); } }, .forward => |forwarded| { for (forwarded.slice()) |forwarded_byte| { try self.handleTerminalInputByte(forwarded_byte); if (self.should_exit) return; } }, } }
fn handleThemeMonitorByte(self: *App, byte: u8) !void { switch (self.terminal_input_runtime.terminal_theme_monitor.feed( byte, io_mod.milliTimestamp(), )) { .pending, .consumed => {}, .forward => |forwarded| { for (forwarded.slice()) |forwarded_byte| { try self.handleAfterThemeMonitorByte(forwarded_byte); if (self.should_exit) return; } }, } }
pub fn loopHandleByte(ctx: *anyopaque, byte: u8) !void { const self: *App = @ptrCast(@alignCast(ctx)); if (!try WorkerAppRuntime.authorizeInteractiveAdmission(self)) return; const deferred_source = self.terminal_input_runtime.consumeDeferredTerminalInputDispatch();
if (deferred_source) |source| { switch (source) { .cursor_probe => { if (try self.routeActivePasteTransportByte(byte)) return; try self.handleCursorDeferredInputByte(byte); }, .theme_monitor => try self.handleAfterThemeMonitorByte(byte), } return; }
switch (ui_input.terminalInputOwner( &self.terminal_input_runtime.terminal_theme_monitor, InputAppRuntime.terminalPasteActive(self), )) { .theme_monitor => { try self.handleThemeMonitorByte(byte); return; }, .paste => { const routed = try self.routeActivePasteTransportByte(byte); std.debug.assert(routed); return; }, .fx_input => {}, }
if (self.terminal_input_runtime.terminal_theme_monitor.enabled) { try self.handleThemeMonitorByte(byte); return; } try self.handleAfterThemeMonitorByte(byte); }
pub fn loopSettleInputDeliveryEpoch(ctx: *anyopaque) !void { const self: *App = @ptrCast(@alignCast(ctx)); if (!InputAppRuntime.terminalPasteActive(self)) return; try InputAppRuntime.settleTerminalPasteDeliveryEpochWithLimits( self, input_limits, ); }
pub fn loopNextCollectedByte(ctx: *anyopaque) ?u8 { const self: *App = @ptrCast(@alignCast(ctx)); return self.terminal_input_runtime.takeDeferredTerminalInputByte(); }};
comptime { if (!builtin.is_test and !host_target.is_wasm) { @export(&main, .{ .name = "main" }); }}
pub fn runWasmTerminal(init: std.process.Init) !void { if (comptime !host_target.is_wasm or build_options.wasm_surface != .term) { @compileError("runWasmTerminal requires -Dwasm-surface=term"); } io_mod.setIo(init.io); io_mod.setEnvironMap(init.environ_map); const alloc = std.heap.c_allocator; var args = try std.process.Args.Iterator.initAllocator(init.minimal.args, alloc); defer args.deinit(); _ = args.skip(); var cli_args: std.ArrayList([:0]const u8) = .empty; defer cli_args.deinit(alloc); while (args.next()) |arg| try cli_args.append(alloc, arg);
const parsed = try cli_surface.parseInteractiveLaunch( alloc, cli_args.items, builtin_commands.top_level_registry, ); var launch = switch (parsed) { .interactive => |value| value, .noninteractive => |value| { var noninteractive = value; defer noninteractive.deinit(alloc); return error.WasmTerminalInteractiveLaunchRequired; }, }; defer launch.deinit(alloc); const outcome = try app_entry_runtime.runInteractiveCooperative(App, alloc, &launch, .local); switch (outcome) { .returned => {}, .exit => |code| if (code != 0) return error.WasmTerminalExited, }}
pub fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) callconv(.c) c_int { mainC(c_argc, c_argv, c_envp) catch return 1; return 0;}
fn mainC(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) !void { const raw_args = rawArgs(c_argc, c_argv); const raw_env: RawEnviron = @ptrCast(c_envp);
if (comptime terminal_host.isSupported()) { if (terminal_tmux_session.isCaptureModeRaw(raw_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); try terminal_tmux_session.runCapture(raw_args); return; } if (terminal_tmux_session.isLauncherModeRaw(raw_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); try terminal_tmux_session.runLauncher( processAllocator(), shell_process_provider.provider, raw_args, ); return; } if (terminal_native_session.isControlModeRaw(raw_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); try terminal_native_session.runControlMarker(raw_args); return; } if (terminal_native_session.isLauncherModeRaw(raw_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); try terminal_native_session.runLauncher(processAllocator()); return; } if (terminal_host.isInternalModeRaw(raw_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); defer debug_trace.shutdown(); debug_trace.configureFromEnv(processAllocator(), "."); try terminal_host.run( processAllocator(), try terminal_host.Config.fromEnvironment( shell_process_provider.provider, ), ); return; } }
if (shouldRunBenchmarkNoArgRaw(raw_args, raw_env)) { switch (cli_surface.parse(builtin_commands.top_level_registry, &.{})) { .interactive => exitFast(0), else => exitFast(1), } }
var cli_arg_buf: [64][:0]const u8 = undefined; const cli_args = if (raw_args.len <= 1) &.{} else try cliArgsFromRaw(raw_args, &cli_arg_buf); if (command_runner.isForegroundSessionInvocation(cli_args)) { io_mod.setRawEnviron(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(processAllocator(), .{ .argv0 = .init(process_args), .environ = .{ .block = environBlockFromRaw(raw_env) }, }); defer threaded.deinit(); io_mod.setIo(threaded.io()); try command_runner.runForegroundSessionBootstrap(cli_args); return; } if (cli_args.len > 0 and isTopLevelHelp(cli_args)) { try writeTopLevelHelpFast(raw_env); exitFast(0); } try runNonBenchmark(raw_args, raw_env, cli_args);}
fn writeTopLevelHelpFast(raw_env: RawEnviron) !void { const columns = topLevelHelpColumns(raw_env); const style = topLevelHelpStyle(raw_env); var buffer: [builtin_commands.top_level_help_fast_buffer_bytes]u8 = undefined; var fixed: std.heap.FixedBufferAllocator = .init(&buffer); const text = try command_specs.renderTopLevelHelpWithStyle( fixed.allocator(), builtin_commands.top_level_registry, columns, version, style, ); try writeStdoutFast(text);}
fn runNonBenchmark(raw_args: []const [*:0]const u8, raw_env: RawEnviron, cli_args: []const [:0]const u8) !void { io_mod.setRawEnviron(raw_env);
const alloc = processAllocator(); const auth_mode = credentials.parseAuthMode(rawEnvValue(raw_env, "FX_AUTH_MODE")) catch { try writeStderrFast("fx: FX_AUTH_MODE must be local or host-managed\n"); exitFast(1); }; const cfg = if (cli_args.len == 0) emptyEntryConfig(auth_mode) else if (needsFullEntryConfig(cli_args)) fullEntryConfig(auth_mode) else localEntryConfig(auth_mode);
var early_threaded: ?std.Io.Threaded = null; defer if (early_threaded) |*threaded| threaded.deinit(); if (needsEarlyThreadedIo(cli_args)) { const env_block = environBlockFromRaw(raw_env); const process_args = argsFromRaw(raw_args); early_threaded = std.Io.Threaded.init(alloc, .{ .argv0 = .init(process_args), .environ = .{ .block = env_block }, }); if (early_threaded) |*threaded| io_mod.setIo(threaded.io()); }
const before = try app_entry_runtime.runBeforeInteractive(alloc, cli_args, cfg); switch (before) { .interactive => |launch| { const env_block = environBlockFromRaw(raw_env); const process_args = argsFromRaw(raw_args); var threaded = std.Io.Threaded.init(alloc, .{ .argv0 = .init(process_args), .environ = .{ .block = env_block }, }); defer threaded.deinit(); io_mod.setIo(threaded.io());
var owned_launch = launch; defer owned_launch.deinit(alloc); defer debug_trace.shutdown();
const outcome = try app_entry_runtime.runInteractive(App, alloc, &owned_launch, auth_mode); switch (outcome) { .returned => return, .exit => |code| std.process.exit(code), } }, .returned => exitFast(0), .exit => |code| exitFast(code), }}
fn rawArgs(c_argc: c_int, c_argv: [*][*:0]c_char) []const [*:0]const u8 { const argc: usize = @intCast(c_argc); const argv: [*][*:0]const u8 = @ptrCast(c_argv); return argv[0..argc];}
fn argsFromRaw(raw_args: []const [*:0]const u8) std.process.Args { return .{ .vector = raw_args };}
fn environBlockFromRaw(raw_env: RawEnviron) std.process.Environ.Block { var count: usize = 0; while (raw_env[count] != null) : (count += 1) {} return .{ .slice = raw_env[0..count :null] };}
fn shouldRunBenchmarkNoArgRaw(raw_args: []const [*:0]const u8, raw_env: RawEnviron) bool { return raw_args.len <= 1 and benchmarkEnvPresent(raw_env);}
fn benchmarkEnvPresent(raw_env: RawEnviron) bool { if (comptime builtin.link_libc) { if (std.c.getenv("FX_BENCH") != null) return true; } return rawEnvHas(raw_env, "FX_BENCH");}
fn rawEnvHas(raw_env: RawEnviron, comptime key: []const u8) bool { return rawEnvValue(raw_env, key) != null;}
fn rawEnvValue(raw_env: RawEnviron, comptime key: []const u8) ?[]const u8 { @setRuntimeSafety(false); var i: usize = 0; while (raw_env[i]) |entry_z| : (i += 1) { const entry = std.mem.sliceTo(entry_z, 0); if (entry.len <= key.len or entry[key.len] != '=') continue; if (std.mem.eql(u8, entry[0..key.len], key)) return entry[key.len + 1 ..]; } return null;}
fn topLevelHelpColumns(raw_env: RawEnviron) usize { if (stdoutTerminalColumns()) |columns| return columns; if (rawEnvValue(raw_env, "COLUMNS")) |value| { if (parseColumnCount(value)) |columns| return columns; } if (comptime builtin.link_libc) { if (std.c.getenv("COLUMNS")) |value_z| { if (parseColumnCount(std.mem.sliceTo(value_z, 0))) |columns| return columns; } } return command_specs.top_level_help_default_width;}
fn topLevelHelpStyle(raw_env: RawEnviron) command_specs.HelpStyle { const no_color = rawEnvHas(raw_env, "NO_COLOR"); const dumb_terminal = if (rawEnvValue(raw_env, "TERM")) |term| std.mem.eql(u8, term, "dumb") else false; return topLevelHelpStyleForValues(stdoutIsTerminal(), no_color, dumb_terminal);}
fn topLevelHelpStyleForValues(is_terminal: bool, no_color: bool, dumb_terminal: bool) command_specs.HelpStyle { return if (is_terminal and !no_color and !dumb_terminal) .ansi else .plain;}
fn stdoutIsTerminal() bool { if (comptime builtin.os.tag == .windows or !builtin.link_libc) return false; return std.c.isatty(std.posix.STDOUT_FILENO) != 0;}
fn stdoutTerminalColumns() ?usize { if (comptime builtin.os.tag == .windows or !builtin.link_libc) return null;
var ws: std.posix.winsize = .{ .row = 0, .col = 0, .xpixel = 0, .ypixel = 0 }; const req: c_int = @intCast(std.c.T.IOCGWINSZ); const rc = std.c.ioctl(std.posix.STDOUT_FILENO, req, &ws); if (rc == -1 or ws.col == 0) return null; return @intCast(ws.col);}
fn parseColumnCount(value: []const u8) ?usize { const trimmed = std.mem.trim(u8, value, " \t"); if (trimmed.len == 0) return null; const columns = std.fmt.parseUnsigned(usize, trimmed, 10) catch return null; return if (columns == 0) null else columns;}
fn cliArgsFromRaw(raw_args: []const [*:0]const u8, stack_buf: [][:0]const u8) ![]const [:0]const u8 { @setRuntimeSafety(false); if (comptime hasPosixArgVector()) { if (raw_args.len <= 1) return &.{}; const cli_len = raw_args.len - 1; if (cli_len <= stack_buf.len) { for (raw_args[1..], 0..) |arg, i| { stack_buf[i] = std.mem.sliceTo(arg, 0); } return stack_buf[0..cli_len]; } }
const args = try argsFromRaw(raw_args).toSlice(processAllocator()); return if (args.len > 0) args[1..] else args[0..0];}
fn isTopLevelHelp(args: []const [:0]const u8) bool { if (args.len == 0) return false; return command_specs.matchesTopLevel(builtin_commands.top_level_registry, args[0], .help);}
fn processAllocator() Allocator { if (comptime builtin.link_libc) return std.heap.c_allocator; return std.heap.page_allocator;}
fn writeStdoutFast(text: []const u8) !void { @setRuntimeSafety(false); if (comptime builtin.os.tag != .windows) { var remaining = text; while (remaining.len > 0) { const written = std.c.write(std.posix.STDOUT_FILENO, remaining.ptr, remaining.len); if (written <= 0) return error.WriteFailed; remaining = remaining[@intCast(written)..]; } return; } try std.Io.File.stdout().writeStreamingAll(io_mod.getIo(), text);}
fn writeStderrFast(text: []const u8) !void { @setRuntimeSafety(false); if (comptime builtin.os.tag != .windows) { var remaining = text; while (remaining.len > 0) { const written = std.c.write(std.posix.STDERR_FILENO, remaining.ptr, remaining.len); if (written <= 0) return error.WriteFailed; remaining = remaining[@intCast(written)..]; } return; } try std.Io.File.stderr().writeStreamingAll(io_mod.getIo(), text);}
fn exitFast(code: u8) noreturn { if (comptime builtin.link_libc and builtin.os.tag != .windows and builtin.os.tag != .wasi) { std.c._exit(@intCast(code)); } std.process.exit(code);}
fn hasPosixArgVector() bool { return switch (builtin.os.tag) { .windows, .freestanding, .other => false, .wasi => builtin.link_libc, else => true, };}
fn needsFullEntryConfig(args: []const [:0]const u8) bool { const command = cli_surface.commandAfterGlobalLaunchArgs(args) orelse return false; return std.mem.eql(u8, command, "ask") or std.mem.eql(u8, command, "acp") or std.mem.eql(u8, command, "pr") or std.mem.eql(u8, command, "issue");}
fn needsEarlyThreadedIo(args: []const [:0]const u8) bool { if (needsFullEntryConfig(args)) return true; const effective_args = cli_surface.argsAfterGlobalLaunchArgs(args); if (effective_args.len == 0) return false; const command = effective_args[0]; if (std.mem.eql(u8, command, "mcp")) { if (effective_args.len < 2) return false; return std.mem.eql(u8, effective_args[1], "auth") or std.mem.eql(u8, effective_args[1], "list") or std.mem.eql(u8, effective_args[1], "logout"); } return std.mem.eql(u8, command, "login") or std.mem.eql(u8, command, "logout") or std.mem.eql(u8, command, "teams") or std.mem.eql(u8, command, "provider") or std.mem.eql(u8, command, "setup") or std.mem.eql(u8, command, "upgrade") or // Resolve a stored credential, which reads the platform key store out of process. std.mem.eql(u8, command, "status") or std.mem.eql(u8, command, "doctor") or std.mem.eql(u8, command, "models") or std.mem.eql(u8, command, "credits");}
test "auth and upgrade commands use early threaded io without full entry config" { const args = &.{@as([:0]const u8, "upgrade")}; try std.testing.expect(!needsFullEntryConfig(args)); try std.testing.expect(needsEarlyThreadedIo(args)); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "login")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "logout")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "teams")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "provider")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "setup")}));}
test "credential-reading commands use early threaded io without full entry config" { for ([_][:0]const u8{ "status", "doctor", "models", "credits" }) |command| { const args = &.{command}; try std.testing.expect(!needsFullEntryConfig(args)); try std.testing.expect(needsEarlyThreadedIo(args)); }}
test "MCP credential commands use early threaded io" { for ([_][:0]const u8{ "auth", "list", "logout" }) |operation| { try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "mcp"), operation, @as([:0]const u8, "fixture"), })); } for ([_][:0]const u8{ "add", "path", "remove" }) |operation| { try std.testing.expect(!needsEarlyThreadedIo(&.{ @as([:0]const u8, "mcp"), operation, })); }}
test "early threaded io is resolved after global launch args" { try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--add-dir"), @as([:0]const u8, "/tmp/shared"), @as([:0]const u8, "status"), })); try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--no-additional-dirs"), @as([:0]const u8, "login"), })); try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--model"), @as([:0]const u8, "provider/model"), @as([:0]const u8, "--fast"), @as([:0]const u8, "status"), })); try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--provider"), @as([:0]const u8, "grok"), @as([:0]const u8, "login"), })); try std.testing.expect(needsFullEntryConfig(&.{ @as([:0]const u8, "--provider=grok"), @as([:0]const u8, "ask"), })); try std.testing.expect(needsFullEntryConfig(&.{ @as([:0]const u8, "--effort=high"), @as([:0]const u8, "--no-fast"), @as([:0]const u8, "ask"), }));}
test "full entry config commands also use early threaded io" { try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "ask")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "acp")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "pr")})); try std.testing.expect(needsEarlyThreadedIo(&.{@as([:0]const u8, "issue")})); try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--add-dir"), @as([:0]const u8, "/tmp/shared"), @as([:0]const u8, "ask"), })); try std.testing.expect(needsEarlyThreadedIo(&.{ @as([:0]const u8, "--context-limit=project_bytes=2048"), @as([:0]const u8, "--no-additional-dirs"), @as([:0]const u8, "acp"), }));}
test "lightweight local commands do not request early threaded io" { try std.testing.expect(!needsEarlyThreadedIo(&.{})); for ([_][:0]const u8{ "help", "sessions", "tasks", "permissions" }) |command| { try std.testing.expect(!needsEarlyThreadedIo(&.{command})); }}
test "focused UI workers retain a bounded native poll timeout" { try std.testing.expectEqual(@as(i32, 8), nativeLoopPollTimeoutMs(8, false, false, false)); try std.testing.expectEqual(@as(i32, 1), nativeLoopPollTimeoutMs(8, true, false, false)); try std.testing.expectEqual(@as(i32, 1), nativeLoopPollTimeoutMs(8, false, true, false)); try std.testing.expectEqual(@as(i32, 1), nativeLoopPollTimeoutMs(8, false, false, true)); try std.testing.expectEqual(@as(i32, 1), nativeLoopPollTimeoutMs(8, true, true, true));}
test "footer runtime compatibility facade exports composeFooterFrame" { _ = footer_runtime.composeFooterFrame;}
test "interactive app keeps notification handlers registered for live preference changes" { var app = App{ .alloc = std.testing.allocator }; defer app.lifecycle_runtime.deinit();
try app.configureNotifications();
try std.testing.expect(app.lifecycle_view.hasPostTurnEnd()); try std.testing.expect(app.lifecycle_view.hasAttentionRequired());
app.setNotificationPreferences(true, true, true); const preferences = app.notificationPreferences(); try std.testing.expect(preferences.turn_end); try std.testing.expect(preferences.attention_required); try std.testing.expect(preferences.max); try std.testing.expect(app.soundMaxEnabled()); try std.testing.expect(!@hasField(App, "notification_player"));}
test "native app preserves the built-in tool set without workspace metadata" { var app = App{ .alloc = std.testing.allocator }; try std.testing.expect(app.workspaceHostInfo() == null);
const registry = app.toolRegistry(); try std.testing.expect(registry.tools.ptr == builtin_tools.registry.tools.ptr); try std.testing.expectEqual(builtin_tools.registry.tools.len, registry.tools.len);
const advertised = app.toolAdvertisementSet(); try std.testing.expect(advertised.order.ptr == builtin_tools.advertisement_set.order.ptr); try std.testing.expectEqual(builtin_tools.advertisement_set.order.len, advertised.order.len);}
fn fullEntryConfig(auth_mode: credentials.AuthMode) app_entry_runtime.Config { return .{ .version = version, .revision = build_options.git_commit, .build_channel = compiled_update_channel, .auth_mode = auth_mode, .command_catalog = builtin_commands.top_level_registry, .default_model = builtin_gateway.default_model, .default_agent_step_limit = default_max_agent_steps, .models_path = builtin_gateway.models_path, .gateway_retry_count = builtin_gateway.retry_count, .gateway_chat_url = builtin_gateway.default_chat_url, .gateway_provider = native_gateway_provider, .provider_set = builtin_providers.native, .process_provider = shell_process_provider.provider, .url_opener = url_opener.native_opener, .secret_store = native_host.secret_store, .prompt_policy = builtin_context.prompt_policy, .skill_root_policy = builtin_skills.root_policy, .ignored_list_entries = &ignored_list_entries, .max_list_entries = max_list_entries, .max_read_file_bytes = max_read_file_bytes, .max_read_file_lines = max_read_file_lines, .max_read_file_line_len = max_read_file_line_len, .max_command_output_bytes = max_command_output_bytes, .max_tool_result_bytes = @import("core/tooling/tool_result_limits.zig").default_max_tool_result_bytes, .max_history_turns = max_history_turns, .context_registry = default_context_registry, .mode_registry = builtin_modes.registry, .tool_set = builtin_tools.advertisement_set, .inspect_mcp_profile_config = builtin_mcp.inspectProfileConfig, .inspect_mcp_local_config = builtin_mcp.inspectLocalConfig, .load_mcp_runtime = builtin_mcp.loadRuntime, .add_mcp_profile_server = builtin_mcp.addProfileServer, .remove_mcp_profile_server = builtin_mcp.removeProfileServer, .acp_runner = .{ .run_fn = runAcpServer }, };}
fn localEntryConfig(auth_mode: credentials.AuthMode) app_entry_runtime.Config { return .{ .version = version, .revision = build_options.git_commit, .build_channel = compiled_update_channel, .auth_mode = auth_mode, .command_catalog = builtin_commands.top_level_registry, .default_model = builtin_gateway.default_model, .default_agent_step_limit = default_max_agent_steps, .models_path = builtin_gateway.models_path, .gateway_retry_count = builtin_gateway.retry_count, .gateway_chat_url = builtin_gateway.default_chat_url, .gateway_provider = native_gateway_provider, .provider_set = builtin_providers.native, .process_provider = shell_process_provider.provider, .url_opener = url_opener.native_opener, .secret_store = native_host.secret_store, .prompt_policy = .{ .system_prompt = "" }, .skill_root_policy = builtin_skills.root_policy, .ignored_list_entries = &.{}, .max_list_entries = 0, .max_read_file_bytes = 0, .max_read_file_lines = 0, .max_read_file_line_len = 0, .max_command_output_bytes = 0, .max_tool_result_bytes = 0, .max_history_turns = 0, .context_registry = default_context_registry, .mode_registry = builtin_modes.registry, .tool_set = builtin_tools.advertisement_set, .inspect_mcp_profile_config = builtin_mcp.inspectProfileConfig, .inspect_mcp_local_config = builtin_mcp.inspectLocalConfig, .load_mcp_runtime = builtin_mcp.loadRuntime, .add_mcp_profile_server = builtin_mcp.addProfileServer, .remove_mcp_profile_server = builtin_mcp.removeProfileServer, .acp_runner = .{ .run_fn = runAcpServer }, };}
fn emptyEntryConfig(auth_mode: credentials.AuthMode) app_entry_runtime.Config { return .{ .version = version, .revision = build_options.git_commit, .build_channel = compiled_update_channel, .auth_mode = auth_mode, .command_catalog = builtin_commands.top_level_registry, .default_model = "", .default_agent_step_limit = 0, .models_path = "", .gateway_retry_count = 0, .gateway_chat_url = "", .gateway_provider = native_gateway_provider, .provider_set = builtin_providers.native, .process_provider = shell_process_provider.provider, .url_opener = url_opener.native_opener, .secret_store = native_host.secret_store, .prompt_policy = .{ .system_prompt = "" }, .skill_root_policy = builtin_skills.root_policy, .ignored_list_entries = &.{}, .max_list_entries = 0, .max_read_file_bytes = 0, .max_read_file_lines = 0, .max_read_file_line_len = 0, .max_command_output_bytes = 0, .max_tool_result_bytes = 0, .max_history_turns = 0, .context_registry = default_context_registry, .mode_registry = builtin_modes.registry, .tool_set = builtin_tools.advertisement_set, .inspect_mcp_profile_config = builtin_mcp.inspectProfileConfig, .inspect_mcp_local_config = builtin_mcp.inspectLocalConfig, .load_mcp_runtime = builtin_mcp.loadRuntime, .add_mcp_profile_server = builtin_mcp.addProfileServer, .remove_mcp_profile_server = builtin_mcp.removeProfileServer, .acp_runner = .{ .run_fn = runAcpServer }, };}
fn runAcpServer(_: ?*anyopaque, alloc: Allocator, cfg: acp_runner.Config) anyerror!void { return acp_server.run(alloc, cfg);}
fn handleSigWinchNative(_: std.posix.SIG) callconv(.c) void { resize_interlock.noteResizeSignal();}
fn handleSigWinchWeb() callconv(.c) void { resize_interlock.noteResizeSignal();}
const handle_sigwinch: app_lifecycle.ResizeHandler = if (host_target.is_wasm) handleSigWinchWebelse handleSigWinchNative;
test "interactive startup does not begin with synthetic resize pending" { try std.testing.expect(!resize_interlock.resizePending());}
test "session reset traces and clears active paste state" { 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, "session-reset-paste.log" }); defer alloc.free(trace_path);
debug_trace.resetForTest(); defer debug_trace.resetForTest(); try debug_trace.configureForTestWithScopes(alloc, trace_path, "input");
var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = alloc, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer app.deinit(); try app.shell.enableShadowVt(alloc); app.input_runtime.paste.owner = .decision_prompt; app.input_runtime.paste.decision_bytes = 4; try app.input_runtime.edit_state.input.appendSlice(alloc, "normal input");
try app.clearSession();
try std.testing.expectEqual(paste_framing.Owner.none, app.input_runtime.paste.owner); try std.testing.expectEqual(@as(usize, 0), app.input_runtime.paste.decision_bytes); try std.testing.expectEqual(@as(usize, 0), app.input_runtime.edit_state.input.items.len); debug_trace.shutdown();
var trace_file = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), trace_path, .{}); defer trace_file.close(io_mod.getIo()); const trace = try io_mod.readFileToEnd(alloc, &trace_file, 8192); defer alloc.free(trace); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, trace, "decision prompt paste dropped bytes=4 reason=session_reset"));}
test "raw benchmark preflight matches no-arg FX_BENCH presence" { const no_args = [_][*:0]const u8{"fx"}; const help_args = [_][*:0]const u8{ "fx", "help" }; const bench_env = [_:null]?[*:0]const u8{"FX_BENCH=1"}; const empty_env = [_:null]?[*:0]const u8{};
try std.testing.expect(shouldRunBenchmarkNoArgRaw(no_args[0..], @ptrCast(&bench_env))); try std.testing.expect(!shouldRunBenchmarkNoArgRaw(help_args[0..], @ptrCast(&bench_env))); try std.testing.expect(!shouldRunBenchmarkNoArgRaw(no_args[0..], @ptrCast(&empty_env)));}
test "terminal help styling respects terminal capability and color opt-outs" { try std.testing.expectEqual(command_specs.HelpStyle.ansi, topLevelHelpStyleForValues(true, false, false)); try std.testing.expectEqual(command_specs.HelpStyle.plain, topLevelHelpStyleForValues(false, false, false)); try std.testing.expectEqual(command_specs.HelpStyle.plain, topLevelHelpStyleForValues(true, true, false)); try std.testing.expectEqual(command_specs.HelpStyle.plain, topLevelHelpStyleForValues(true, false, true));}
test "follow up prompt card top margin is renderer-owned" { var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = std.testing.allocator, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer { app.shell.deinit(std.testing.allocator); app.session.deinit(std.testing.allocator); }
try app.session.appendAssistantHistoryTurn(std.testing.allocator, "hi", "hello"); try app.writeTranscript("hello\n", true); try app.writeUserPromptCard(.{ .text = @constCast("follow up") });
try std.testing.expect(std.mem.find(u8, app.shell.transcript.items, "hello\n\n") == null);
const rendered = try transcript_runtime.renderEntriesToBytes(std.testing.allocator, app.shell.entries.items, app.shell.layout.cols, .{}); defer std.testing.allocator.free(rendered);
try std.testing.expect(std.mem.find(u8, rendered, "hello\n\n") != null);}
test "follow up prompt card does not over-pad when assistant ends with blank row" { var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = std.testing.allocator, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer { app.shell.deinit(std.testing.allocator); app.session.deinit(std.testing.allocator); }
try app.session.appendAssistantHistoryTurn(std.testing.allocator, "hi", "hello"); try app.writeTranscript("hello\n\n", true); try app.writeUserPromptCard(.{ .text = @constCast("follow up") });
try std.testing.expect(std.mem.find(u8, app.shell.transcript.items, "hello\n\n\n") == null); try std.testing.expect(std.mem.find(u8, app.shell.transcript.items, "hello\n\n") != null);}
test "diff block writes are classified" { const alloc = std.testing.allocator; const c_alloc = std.heap.c_allocator; const diff_mod = @import("core/output/diff.zig");
var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = alloc, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer { for (app.diff_entries.items) |*entry| entry.deinit(c_alloc); app.diff_entries.deinit(c_alloc); app.shell.deinit(alloc); app.session.deinit(alloc); }
const payload = agent_runtime.DiffEntryPayload{ .preview = try c_alloc.dupe(u8, "diff preview"), }; errdefer diff_mod.freeDiffEntryPayload(c_alloc, payload);
try app.registerAndEmitDiffBlock(payload);
try std.testing.expect(app.shell.entries.items.len > 0); try std.testing.expectEqual( transcript_runtime.RawEntryClass.diff_block, app.shell.entries.items[app.shell.entries.items.len - 1].raw_bytes.class, );}
test "prompt card wraps image badges in OSC 8 hyperlinks" { var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = std.testing.allocator, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer { app.shell.deinit(std.testing.allocator); app.session.deinit(std.testing.allocator); }
var images = [_]types.ImageAttachment{ .{ .id = 1, .path = @constCast("/tmp/a.png"), .media_type = @constCast("image/png") }, }; try app.writeUserPromptCard(.{ .text = @constCast("[Image #1]"), .images = &images });
try std.testing.expect(std.mem.find(u8, app.shell.transcript.items, "\x1b]8;;file:///tmp/a.png\x1b\\[Image 1]\x1b]8;;\x1b\\") != null); const reconstructed = try transcript_runtime.renderEntriesToBytes(std.testing.allocator, app.shell.entries.items, app.shell.layout.cols, .{}); defer std.testing.allocator.free(reconstructed); try std.testing.expect(std.mem.find(u8, reconstructed, "\x1b]8;;file:///tmp/a.png\x1b\\[Image 1]\x1b]8;;\x1b\\") != null);}
test "/version command writes version to transcript" { var sink = try std.Io.Dir.openFileAbsolute(std.testing.io, "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var app = App{ .alloc = std.testing.allocator, .shell = .{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }, }; defer app.shell.deinit(std.testing.allocator);
try app.handleCommand("/version");
try std.testing.expectEqual(@as(usize, 1), app.shell.entries.items.len); try std.testing.expect(app.shell.entries.items[0] == .semantic_notice); const notice = app.shell.entries.items[0].semantic_notice; try std.testing.expectEqualStrings("version", notice.topic); try std.testing.expectEqual(types.NoticeTone.neutral, notice.tone); try std.testing.expect(std.mem.find(u8, notice.body, version) != null);}
test "normalize assistant text removes markdown emphasis and leading blank lines" { const normalized = try agent_runtime.normalizeAssistantTextForDisplay(std.testing.allocator, "\n\n**Hola** `mundo`"); defer std.testing.allocator.free(normalized);
try std.testing.expectEqualStrings("Hola mundo", normalized);}
test "semantic code block preserves indentation on wrapped continuation rows" { const alloc = std.testing.allocator; var entries: std.ArrayList(transcript_runtime.TranscriptEntry) = .empty; defer { for (entries.items) |*entry| entry.deinit(alloc); entries.deinit(alloc); }
const block = assistant_presentation.CodeBlockPayload{ .language = try alloc.dupe(u8, "text"), .code = try alloc.dupe(u8, " abcdefghijkl\n"), }; try entries.append(alloc, .{ .assistant_code_block = .{ .id = 1, .block = block } });
const wide = try transcript_runtime.renderEntriesToBytes(alloc, entries.items, 80, .{}); defer alloc.free(wide); try std.testing.expect(std.mem.find(u8, wide, "text") != null); try std.testing.expect(std.mem.find(u8, wide, "─") != null); try std.testing.expect(std.mem.find(u8, wide, "│") == null); try std.testing.expect(std.mem.find(u8, wide, " abcdefghijkl") != null);
const narrow = try transcript_runtime.renderEntriesToBytes(alloc, entries.items, 12, .{}); defer alloc.free(narrow); try std.testing.expect(std.mem.find(u8, narrow, "\n ijkl\n") != null); var lines = std.mem.splitScalar(u8, narrow, '\n'); while (lines.next()) |line| { try std.testing.expect(display_width.visibleWidthIgnoringAnsi(line) <= 12); }
const tiny = try transcript_runtime.renderEntriesToBytes(alloc, entries.items, 1, .{}); defer alloc.free(tiny); try std.testing.expect(std.mem.find(u8, tiny, "┌") == null); lines = std.mem.splitScalar(u8, tiny, '\n'); while (lines.next()) |line| { try std.testing.expect(display_width.visibleWidthIgnoringAnsi(line) <= 1); }
var wide_rune_entries: std.ArrayList(transcript_runtime.TranscriptEntry) = .empty; defer { for (wide_rune_entries.items) |*entry| entry.deinit(alloc); wide_rune_entries.deinit(alloc); } const wide_rune_block = assistant_presentation.CodeBlockPayload{ .language = try alloc.dupe(u8, "text"), .code = try alloc.dupe(u8, " a\xf0\x9f\x98\x80\n"), }; try wide_rune_entries.append(alloc, .{ .assistant_code_block = .{ .id = 2, .block = wide_rune_block } });
const boxed_wide_rune = try transcript_runtime.renderEntriesToBytes(alloc, wide_rune_entries.items, 6, .{}); defer alloc.free(boxed_wide_rune); lines = std.mem.splitScalar(u8, boxed_wide_rune, '\n'); while (lines.next()) |line| { try std.testing.expect(display_width.visibleWidthIgnoringAnsi(line) <= 6); }
const unboxed_wide_rune = try transcript_runtime.renderEntriesToBytes(alloc, wide_rune_entries.items, 2, .{}); defer alloc.free(unboxed_wide_rune); lines = std.mem.splitScalar(u8, unboxed_wide_rune, '\n'); while (lines.next()) |line| { try std.testing.expect(display_width.visibleWidthIgnoringAnsi(line) <= 2); }}
test { _ = @import("napi_fetch_state.zig"); _ = @import("core/config/model_provider.zig"); _ = @import("core/config/configured_provider.zig"); _ = @import("gateway/chat_completions_protocol.zig"); _ = provider_runtime; _ = @import("acp/prompt.zig"); _ = @import("core/output/activity_status.zig"); _ = @import("core/agent/agent_runtime.zig"); _ = @import("core/agent/execution_memory.zig"); _ = @import("core/agent/runtime/assistant_stream.zig"); _ = @import("core/agent/runtime/execution_memory.zig"); _ = @import("core/agent/runtime/tool_admission.zig"); _ = @import("core/agent/runtime/prompt_context.zig"); _ = @import("core/app/app_agent_runtime.zig"); _ = @import("core/app/app_auth_runtime.zig"); _ = auth_runtime; _ = @import("core/auth/auth_transition.zig"); _ = @import("core/app/provider_picker_runtime.zig"); _ = @import("core/workspace/context_contract.zig"); _ = @import("core/workspace/workspace_access.zig"); _ = @import("core/workspace/workspace_commands.zig"); _ = @import("core/app/app_workspace_runtime.zig"); _ = @import("core/app/app_bootstrap_runtime.zig"); _ = @import("core/app/app_callbacks.zig"); _ = @import("core/app/app_commands.zig"); _ = @import("core/app/app_entry_runtime.zig"); _ = @import("core/app/app_input_runtime.zig"); _ = input_submit_runtime; _ = @import("core/app/app_lifecycle.zig"); _ = @import("core/app/model_cache_runtime.zig"); _ = @import("core/app/usage_dashboard_runtime.zig"); _ = @import("core/app/app_process_runtime.zig"); _ = @import("core/app/app_render_runtime.zig"); _ = @import("core/app/input_interrupt_runtime.zig"); _ = @import("ui/footer/render_input.zig"); _ = @import("ui/footer/surface_frame.zig"); _ = @import("ui/render_request.zig"); _ = @import("core/app/app_runtime_setup.zig"); _ = @import("core/app/app_session_runtime.zig"); _ = @import("core/app/app_upgrade_runtime.zig"); _ = @import("core/app/app_worker_runtime.zig"); _ = @import("ui/event_loop.zig"); _ = @import("ui/resize_tests.zig"); _ = @import("ui/render_engine/assistant_wrap.zig"); _ = @import("ui/render_engine/transcript_blocks.zig"); _ = @import("ui/render_engine/viewport_selection.zig"); _ = @import("core/agent/assistant_presentation.zig"); _ = @import("core/upgrade/auto_upgrade.zig"); _ = @import("core/cli/cli_ask.zig"); _ = @import("core/cli/cli_replay.zig"); _ = @import("core/cli/cli_surface.zig"); _ = @import("core/workspace/change_tracker.zig"); _ = @import("core/shared/collections.zig"); _ = @import("core/slash_commands/command_router.zig"); _ = @import("core/slash_commands/command_specs.zig"); _ = @import("core/config/config_runtime.zig"); _ = @import("core/config/settings_store.zig"); _ = @import("core/session/session_title_generation.zig"); _ = @import("ui/footer/compact_command_menu_presentation.zig"); _ = @import("ui/footer/settings_menu_presentation.zig"); _ = @import("builtins/context.zig"); _ = @import("builtins/gateway.zig"); _ = @import("core/shared/debug_trace.zig"); _ = @import("core/output/diff.zig"); _ = @import("core/shared/display_width.zig"); _ = @import("core/cli/doctor_runtime.zig"); _ = @import("core/auth/login_flow.zig"); _ = @import("core/auth/chatgpt_oauth.zig"); _ = @import("core/auth/provider_catalog.zig"); _ = @import("gateway/openai_codex_models.zig"); _ = @import("gateway/openai_codex.zig"); _ = @import("gateway/responses_protocol.zig"); _ = @import("gateway/openai_codex_permission_reviewer.zig"); _ = @import("core/auth/grok_session.zig"); _ = @import("core/auth/grok_oauth.zig"); _ = @import("gateway/xai_grok_models.zig"); _ = @import("gateway/xai_grok.zig"); _ = @import("gateway/xai_grok_permission_reviewer.zig"); _ = credentials; _ = @import("core/auth/oauth.zig"); _ = @import("core/auth/oauth_session.zig"); _ = @import("core/workspace/file_index.zig"); _ = @import("core/workspace/path_completion.zig"); _ = @import("core/workspace/directory_completion_job.zig"); _ = @import("core/input/file_completion_state.zig"); _ = @import("gateway/vercel_protocol.zig"); _ = @import("core/gateway/provider_set.zig"); _ = @import("core/gateway/model_catalog.zig"); _ = @import("gateway/chat_completions.zig"); _ = @import("core/github/git_context.zig"); _ = @import("core/github/github_publish.zig"); _ = @import("core/github/github_workflows.zig"); _ = @import("core/hosts/host.zig"); _ = @import("core/hooks/common.zig"); _ = @import("core/hooks/definitions.zig"); _ = @import("core/hooks/prompt.zig"); _ = @import("core/hooks/runtime.zig"); _ = @import("core/images/image_attachments.zig"); _ = @import("core/images/image_commands.zig"); _ = @import("core/shared/io.zig"); _ = @import("core/shared/message.zig"); _ = @import("core/shared/token_estimate.zig"); _ = @import("core/shell_command/command_effect.zig"); _ = @import("core/execution/router.zig"); _ = @import("core/permissions/direct_command.zig"); _ = @import("core/permissions/auto_classifier.zig"); _ = @import("core/permissions/command_admission.zig"); _ = @import("core/mcp/mcp_runtime.zig"); _ = @import("core/mcp/elicitation_interaction.zig"); _ = @import("core/mcp/features/common.zig"); _ = @import("core/mcp/features/resources.zig"); _ = @import("core/mcp/features/prompts.zig"); _ = @import("core/mcp/features/completion.zig"); _ = @import("core/config/model_capabilities.zig"); _ = @import("core/output/output_contracts.zig"); _ = @import("core/workspace/pathing.zig"); _ = @import("core/workspace/current_branch.zig"); _ = @import("core/permissions/permission_gate.zig"); _ = @import("core/permissions/permissions.zig"); _ = @import("core/execution/process_identity.zig"); _ = @import("core/execution/process_provider.zig"); _ = @import("core/execution/managed_execution_contract.zig"); _ = @import("core/execution/managed_execution.zig"); _ = @import("core/execution/process_tree.zig"); _ = @import("core/config/prompt_policy.zig"); _ = @import("core/workspace/record_tape.zig"); _ = @import("core/session/session.zig"); _ = @import("core/session/session_commands.zig"); _ = @import("core/session/session_json.zig"); _ = @import("core/session/session_store.zig"); _ = @import("core/session/legacy_background_migration.zig"); _ = @import("core/session/prompt_history_store.zig"); _ = @import("core/app/prompt_history_runtime.zig"); _ = @import("core/session/web_fetch_artifacts.zig"); _ = @import("core/skills/skill_runtime.zig"); _ = @import("core/subagent/domain.zig"); _ = @import("core/subagent/child_state.zig"); _ = @import("core/subagent/managed_owner.zig"); _ = @import("core/subagent/resume_admission.zig"); _ = @import("core/subagent/execution.zig"); _ = @import("core/subagent/agent_adapter.zig"); _ = @import("core/subagent/tool_host.zig"); _ = @import("core/subagent/authority.zig"); _ = @import("core/subagent/approval_registry.zig"); _ = @import("core/terminal/contracts.zig"); _ = @import("core/terminal/operation.zig"); _ = @import("core/terminal/protocol.zig"); _ = @import("core/terminal/host_policy.zig"); _ = @import("core/terminal/shell_resolver.zig"); _ = @import("core/terminal/native_session.zig"); _ = @import("core/terminal/recovery.zig"); _ = @import("core/terminal/store.zig"); _ = @import("core/terminal/host.zig"); _ = @import("core/terminal/tmux_session.zig"); _ = @import("core/terminal/client.zig"); _ = @import("core/terminal/managed_observer.zig"); _ = @import("tools/shell/shell.zig"); _ = @import("tools/shell/process_provider.zig"); _ = @import("core/app/input_approval_runtime.zig"); _ = @import("acp/sessions.zig"); _ = @import("core/shared/text_utils.zig"); _ = @import("core/tooling/tool_projection.zig"); _ = @import("core/tooling/tool_dispatch.zig"); _ = @import("core/tooling/tool_set.zig"); _ = @import("core/hosts/js_host_workspace.zig"); _ = @import("core/tooling/tool_args.zig"); _ = @import("core/tooling/tool_result_errors.zig"); _ = @import("core/tooling/tool_runtime.zig"); _ = @import("core/tooling/tool_specs.zig"); _ = @import("builtins/commands.zig"); _ = @import("builtins/mcp.zig"); _ = @import("builtins/modes.zig"); _ = @import("builtins/tools.zig"); _ = @import("tools/agent/ask_user_question.zig"); _ = @import("builtins/browser_workspace_tools.zig"); _ = @import("core/tooling/model_request_budget.zig"); _ = @import("core/tooling/web_fetch_runtime.zig"); _ = @import("core/tooling/web_search_policy.zig"); _ = @import("core/tooling/web_search_runtime.zig"); _ = @import("gateway/web_search.zig"); _ = @import("gateway/web_search_types.zig"); _ = @import("tools/web/content.zig"); _ = @import("tools/web/html_to_markdown.zig"); _ = @import("tools/filesystem/read_file.zig"); _ = @import("tools/session/read_tool_result.zig"); _ = @import("tools/skills/install_skill.zig"); _ = @import("tools/skills/skill.zig"); _ = @import("core/upgrade/upgrade_helpers.zig"); _ = @import("core/upgrade/upgrade_runtime.zig"); _ = @import("core/shared/types.zig"); _ = @import("core/input/composer_history.zig"); _ = @import("core/input/kill_ring.zig"); _ = @import("core/input/horizontal_navigation.zig"); _ = @import("core/input/edit_history.zig"); _ = @import("core/input/vertical_navigation.zig"); _ = @import("core/app/input_selection_runtime.zig"); _ = @import("ui/input/native_clear_probe.zig"); _ = @import("ui/input/terminal_action_decoder.zig"); _ = @import("ui/input/visual_layout.zig"); _ = @import("ui/input/runtime.zig"); _ = @import("ui/approval_screen.zig"); _ = @import("ui/ask_presentation.zig"); _ = @import("ui/footer/approval_ui.zig"); _ = @import("ui/footer/surface_invalidation.zig"); _ = @import("ui/full_transcript_screen.zig"); _ = @import("ui/render_engine/frame_fixed_point.zig"); _ = @import("ui/render_engine/terminal_diff.zig"); _ = @import("ui/transcript/runtime.zig"); _ = @import("ui/transcript/runtime_tests.zig"); _ = @import("core/agent/worker_runtime.zig"); _ = @import("gateway/client.zig"); _ = @import("gateway/host_stream_provider.zig");}