char-slop/berry
multipurpose self-modifiable agentic harness
git clone https://git.t4t.associates/char-slop/berry
3339f51
main
1import { assertEquals } from "@std/assert" ; 2import { TERMINAL_PALETTE } from "@berry/util/palette.ts" ; 3import type { ToolCall } from "@berry/api/web.ts" ; 4import { withDom } from "@berry/util/dom.ts" ; 5import { bashRenderer , bashView } from "./bash-view.tsx" ; 6 7Deno . test ( "bash colors live raw output before completion and keeps older streams working" , async () => { 8await withDom (() => { 9const view = bashView (); 10const call :ToolCall = { 11name :"bash" , 12args :{ command :"printf colors" }, 13status :"running" , 14output :null , 15details :null , 16result :null , 17error :null , 18startedAt :null , 19durationMs :null , 20}; 21// the raw stream carries colour that the sanitized output has lost 22view . update ({ ...call , output :"[31mred" , details :{ rawOutput :"\x1b[31mred" } }); 23const output = view . element . querySelector < HTMLPreElement >( "pre:not(.code)" ) ! ; 24assertEquals ( output . textContent , "red" ); 25const red = output . firstElementChild as HTMLElement ; 26const color = document . createElement ( "span" ); 27color . style . color = TERMINAL_PALETTE [ 1 ]; 28assertEquals ( red . style . color , color . style . color ); 29const rawOutput = "\x1b[31mredder\x1b[0m plain" ; 30view . update ({ ...call , status :"ok" , result :` ${ rawOutput } \n\n[exit code 0]` }); 31assertEquals ( output . firstElementChild , red ); 32assertEquals ( output . textContent , "redder plain\n\n[exit code 0]" ); 33 34const legacy = bashView (); 35legacy . update ({ ...call , output :"\x1b[31mred" }); 36const legacyOutput = legacy . element . querySelector ( "pre:not(.code)" ) ! ; 37assertEquals ( legacyOutput . textContent , "red" ); 38assertEquals (( legacyOutput . firstElementChild as HTMLElement ). style . color , color . style . color ); 39legacy . update ({ ...call , status :"ok" , result :{ output :"final" , exitCode :3 } }); 40assertEquals ( legacyOutput . textContent , "final" ); 41assertEquals ( legacy . element . querySelector ( ".exit" ) ! . textContent , "exit 3" ); 42legacy . update ({ ...call , output :"" , details :{ rawOutput :"" } }); 43assertEquals (( legacyOutput as HTMLElement ). hidden , true ); 44}); 45}); 46 47Deno . test ( "bash keeps timeout metadata out of the command summary" , () => { 48const args = { command :"echo one\necho two" , timeout :60 }; 49assertEquals ( bashRenderer . summary ?.( args ), "echo one" ); 50assertEquals ( bashRenderer . timeout ?.( args ), 60 ); 51assertEquals ( bashRenderer . timeout ?.({ command :"sleep 5" , timeout :0.2 }), 0.2 ); 52assertEquals ( bashRenderer . summary ?.({ command :"pwd" }), "pwd" ); 53assertEquals ( bashRenderer . timeout ?.({ command :"pwd" }), null ); 54assertEquals ( bashRenderer . summary ?.( null ), null ); 55assertEquals ( bashRenderer . timeout ?.( null ), null ); 56}); 57 58Deno . test ( "a nonzero exit is a bash call's outcome, from the text a model saw or a script's result" , () => { 59const call = ( result :ToolCall [ "result" ]) :ToolCall => ({ 60name :"bash" , 61args :{ command :"false" }, 62status :"ok" , 63output :null , 64details :null , 65 result, 66error :null , 67startedAt :null , 68durationMs :null , 69}); 70assertEquals ( bashRenderer . outcome ?.( call ( "failed\n\n[exit code 3]" )), "exit 3" ); 71assertEquals ( 72bashRenderer . outcome ?.( call ( "long\n\n[exit code 2; full output: /tmp/out]" )), 73"exit 2" , 74); 75assertEquals ( bashRenderer . outcome ?.( call ({ output :"" , exitCode :1 })), "exit 1" ); 76assertEquals ( bashRenderer . outcome ?.( call ( "fine\n\n[exit code 0]" )), null ); 77assertEquals ( bashRenderer . outcome ?.( call ({ output :"" , exitCode :0 })), null ); 78assertEquals ( bashRenderer . outcome ?.( call ( "mentions [exit code 9] in passing\nthen more" )), null ); 79});