char-slop/berry
multipurpose self-modifiable agentic harness
git clone https://git.t4t.associates/char-slop/berry
ac8e0a3
main
1import type { Environment } from "@berry/api" ; 2import * as posix from "@std/path/posix" ; 3import * as windows from "@std/path/windows" ; 4import { 5McpClient , 6McpConnectionClosedError , 7McpSessionExpiredError , 8StreamableHttpTransport , 9} from "@earendil-works/pi-mcp" ; 10import type { Server } from "./config.ts" ; 11import { EnvironmentStdio } from "./stdio.ts" ; 12 13type Connection = { 14id :string ; 15initialization :ReturnType < typeof setTimeout >; 16client :McpClient ; 17ready :Promise < unknown >; 18stop :AbortController ; 19backend ?:AbortSignal ; 20disconnected :() => void ; 21stdio ?:EnvironmentStdio ; 22failure ?:Error ; 23retired :boolean ; 24users :number ; 25idle ?:ReturnType < typeof setTimeout >; 26closing ?:Promise < void >; 27}; 28 29/** Lazy clients shared only within the same machine, working directory, and resolved configuration. */ 30export class Connections { 31private readonly clients = new Map < string , Connection >(); 32private readonly owned = new Set < Connection >(); 33private disposed = false ; 34 35private close ( connection :Connection ) :Promise < void > { 36return connection . closing ??= ( async () => { 37connection . retired = true ; 38clearTimeout ( connection . idle ); 39clearTimeout ( connection . initialization ); 40if ( this . clients . get ( connection . id ) === connection ) this . clients . delete ( connection . id ); 41connection . backend ?. removeEventListener ( "abort" , connection . disconnected ); 42try { 43await connection . client . close (); 44} finally { 45connection . stop . abort (); 46this . owned . delete ( connection ); 47} 48})(); 49} 50 51async use < T > ( 52env :Environment , 53name :string , 54config :Server , 55signal :AbortSignal , 56run :( client :McpClient ) => Promise < T >, 57) :Promise < T > { 58signal . throwIfAborted (); 59env . lifetime ?. throwIfAborted (); 60if ( this . disposed ) throw new Error ( "MCP extension has been disposed" ); 61if ( ! config . enabled ) throw new Error ( `MCP server " ${ name } " is disabled` ); 62const id = JSON . stringify ([ env . id , env . cwd , name , config ]); 63let connection = this . clients . get ( id ); 64if ( 65! connection || connection . retired || connection . client . connectionState === "closed" || 66connection . backend !== env . lifetime 67) { 68const previous = connection ; 69if ( previous ) previous . retired = true ; 70const stop = new AbortController (); 71const path = env . platform === "win32" ?windows :posix ; 72const client = new McpClient ({ 73name :"berry" , 74version :"1" , 75requestTimeoutMs :config . timeout , 76roots :[{ uri :path . toFileUrl ( config . cwd ). href , name :"workspace" }], 77}); 78let stdio :EnvironmentStdio | undefined ; 79const transport = "command" in config 80 ?( stdio = new EnvironmentStdio ( env , config , stop . signal )) 81 :new StreamableHttpTransport ({ 82url :config . url , 83headers :config . headers , 84fetch :async ( input , init ) => { 85try { 86return await env . fetch ( input , { 87 ...init , 88redirect :"error" , 89signal :AbortSignal . any ([ 90stop . signal , 91 ...( env . lifetime ?[ env . lifetime ] :[]), 92 ...( init ?. signal ?[ init . signal ] :[]), 93]), 94}); 95} catch ( error ) { 96if ( error instanceof TypeError ) created . retired = true ; 97throw error ; 98} 99}, 100}); 101const initializationTimeout = Math . min ( config . timeout , 30_000 ); 102const timer = setTimeout (() => { 103created . failure = new Error ( 104`MCP server " ${ name } " did not initialize within ${ initializationTimeout } ms` , 105); 106void this . close ( created ); 107}, initializationTimeout ); 108const ready = ( previous && previous . users === 0 ?this . close ( previous ) :Promise . resolve ()) 109. then (() => { 110stop . signal . throwIfAborted (); 111return client . connect ( transport ); 112}). finally (() => clearTimeout ( timer )); 113const disconnected = () => { 114created . failure = env . lifetime ?. reason ; 115void this . close ( created ); 116}; 117const created :Connection = { 118 id, 119initialization :timer , 120 client, 121 ready, 122 stop, 123backend :env . lifetime , 124 disconnected, 125 stdio, 126retired :false , 127users :0 , 128}; 129connection = created ; 130this . clients . set ( id , created ); 131this . owned . add ( created ); 132env . lifetime ?. addEventListener ( "abort" , disconnected , { once :true }); 133if ( env . lifetime ?. aborted ) disconnected (); 134void ready . catch (() => {}); 135} 136const current = connection ; 137clearTimeout ( current . idle ); 138current . users ++ ; 139try { 140await new Promise < void >(( resolve , reject ) => { 141const finish = ( error ?:unknown ) => { 142signal . removeEventListener ( "abort" , abort ); 143current . stop . signal . removeEventListener ( "abort" , stopped ); 144if ( error ) reject ( error ); 145else resolve (); 146}; 147const abort = () => finish ( signal . reason ); 148const stopped = () => finish ( current . failure ?? new McpConnectionClosedError ()); 149signal . addEventListener ( "abort" , abort , { once :true }); 150current . stop . signal . addEventListener ( "abort" , stopped , { once :true }); 151void current . ready . then (() => finish (), finish ); 152if ( signal . aborted ) abort (); 153else if ( current . stop . signal . aborted ) stopped (); 154}); 155signal . throwIfAborted (); 156return await run ( current . client ); 157} catch ( error ) { 158// retire a failed session without replaying calls or interrupting its other active users 159if ( error instanceof McpSessionExpiredError ) current . retired = true ; 160if ( error instanceof McpConnectionClosedError && current . stdio ) await current . stdio . close (); 161signal . throwIfAborted (); 162if ( current . failure ) throw current . failure ; 163if ( error instanceof McpConnectionClosedError && current . stdio ?. failure ) { 164throw current . stdio . failure ; 165} 166throw error ; 167} finally { 168current . users -- ; 169if ( current . users === 0 ) { 170if ( current . retired || current . client . connectionState === "closed" ) { 171void this . close ( current ); 172} else if ( ! this . disposed && ! current . stop . signal . aborted ) { 173current . idle = setTimeout (() => { 174if ( this . clients . get ( id ) === current ) this . clients . delete ( id ); 175void this . close ( current ); 176}, 5 * 60_000 ); 177} 178} 179} 180} 181 182async dispose () { 183this . disposed = true ; 184this . clients . clear (); 185await Promise . all ([ ...this . owned ]. map (( connection ) => this . close ( connection ))); 186} 187}