@stdiobus/workers-registry 1.5.0-beta.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/dist/workers-registry/acp-registry/index.js +1 -1
- package/out/dist/workers-registry/acp-registry/index.js.map +2 -2
- package/out/dist/workers-registry/registry-launcher/index.js +1 -1
- package/out/dist/workers-registry/registry-launcher/index.js.map +2 -2
- package/out/tsc/workers-registry/registry-launcher/src/auth/types.d.ts +11 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{readFileSync}from"node:fs";var DEFAULT_CONFIG={registryUrl:"https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json",apiKeysPath:"./api-keys.json",shutdownTimeoutSec:5};var ENV_REGISTRY_URL="ACP_REGISTRY_URL";var ENV_API_KEYS_PATH="ACP_API_KEYS_PATH";var ENV_CUSTOM_AGENTS_PATH="ACP_CUSTOM_AGENTS_PATH";function logWarning(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [WARN] [config] ${message}`)}function isNonEmptyString(value){return typeof value==="string"&&value.length>0}function isPositiveNumber(value){return typeof value==="number"&&value>0&&Number.isFinite(value)}function parseConfigObject(obj){const config={...DEFAULT_CONFIG};if(obj===null||typeof obj!=="object"){logWarning("Config file does not contain a valid object, using defaults");return config}const rawConfig=obj;if("registryUrl"in rawConfig){if(isNonEmptyString(rawConfig.registryUrl)){config.registryUrl=rawConfig.registryUrl}else{logWarning('Config field "registryUrl" is not a valid string, using default')}}if("apiKeysPath"in rawConfig){if(isNonEmptyString(rawConfig.apiKeysPath)){config.apiKeysPath=rawConfig.apiKeysPath}else{logWarning('Config field "apiKeysPath" is not a valid string, using default')}}if("shutdownTimeoutSec"in rawConfig){if(isPositiveNumber(rawConfig.shutdownTimeoutSec)){config.shutdownTimeoutSec=rawConfig.shutdownTimeoutSec}else{logWarning('Config field "shutdownTimeoutSec" is not a valid positive number, using default')}}if("customAgentsPath"in rawConfig){if(isNonEmptyString(rawConfig.customAgentsPath)){config.customAgentsPath=rawConfig.customAgentsPath}else{logWarning('Config field "customAgentsPath" is not a valid string, ignoring')}}return config}function applyEnvironmentOverrides(config){const envRegistryUrl=process.env[ENV_REGISTRY_URL];const envApiKeysPath=process.env[ENV_API_KEYS_PATH];const envCustomAgentsPath=process.env[ENV_CUSTOM_AGENTS_PATH];const overrides={};if(isNonEmptyString(envRegistryUrl)){overrides.registryUrl=envRegistryUrl}if(isNonEmptyString(envApiKeysPath)){overrides.apiKeysPath=envApiKeysPath}if(isNonEmptyString(envCustomAgentsPath)){overrides.customAgentsPath=envCustomAgentsPath}return{...config,...overrides}}function loadConfig(configPath){let config={...DEFAULT_CONFIG};if(configPath){try{const fileContent=readFileSync(configPath,"utf-8");const parsed=JSON.parse(fileContent);config=parseConfigObject(parsed)}catch(error){if(error instanceof SyntaxError){logWarning(`Config file "${configPath}" contains malformed JSON, using defaults`)}else if(error.code==="ENOENT"){logWarning(`Config file "${configPath}" not found, using defaults`)}else if(error.code==="EACCES"){logWarning(`Config file "${configPath}" is not readable, using defaults`)}else{logWarning(`Failed to read config file "${configPath}": ${error.message}, using defaults`)}}}config=applyEnvironmentOverrides(config);return config}import{readFileSync as readFileSync2}from"node:fs";function logWarning2(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [WARN] [api-keys] ${message}`)}function logInfo(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [INFO] [api-keys] ${message}`)}function loadApiKeys(apiKeysPath){try{const fileContent=readFileSync2(apiKeysPath,"utf-8");const parsed=JSON.parse(fileContent);if(!parsed.agents||typeof parsed.agents!=="object"){logWarning2(`API keys file "${apiKeysPath}" does not contain valid "agents" object`);return{}}const agentsWithKeys=Object.entries(parsed.agents).filter(([_,keys])=>keys.apiKey&&keys.apiKey.length>0);logInfo(`Loaded API keys for ${agentsWithKeys.length} agents from "${apiKeysPath}"`);return parsed.agents}catch(error){if(error.code==="ENOENT"){logWarning2(`API keys file "${apiKeysPath}" not found, agents will not be authenticated`)}else if(error instanceof SyntaxError){logWarning2(`API keys file "${apiKeysPath}" contains malformed JSON`)}else{logWarning2(`Failed to read API keys file "${apiKeysPath}": ${error.message}`)}return{}}}function getAgentApiKey(apiKeys,agentId){const keys=apiKeys[agentId];if(!keys||!keys.apiKey||keys.apiKey.length===0){return void 0}return keys.apiKey}function getAgentEnv(apiKeys,agentId){const keys=apiKeys[agentId];if(!keys||!keys.env){return{}}return keys.env}var PlatformNotSupportedError=class extends Error{constructor(agentId,platform){super(`Platform not supported: ${platform} for agent ${agentId}`);this.agentId=agentId;this.platform=platform;this.name="PlatformNotSupportedError"}};var NoDistributionError=class extends Error{constructor(agentId){super(`No supported distribution type for agent ${agentId}`);this.agentId=agentId;this.name="NoDistributionError"}};function getCurrentPlatform(){const platform=process.platform;const arch=process.arch;if(platform==="darwin"&&arch==="arm64")return"darwin-aarch64";if(platform==="darwin"&&arch==="x64")return"darwin-x86_64";if(platform==="linux"&&arch==="arm64")return"linux-aarch64";if(platform==="linux"&&arch==="x64")return"linux-x86_64";if(platform==="win32"&&arch==="arm64")return"windows-aarch64";if(platform==="win32"&&arch==="x64")return"windows-x86_64";return"linux-x86_64"}function resolveBinary(distribution,agentId){const currentPlatform=getCurrentPlatform();const target=distribution[currentPlatform];if(!target){throw new PlatformNotSupportedError(agentId,currentPlatform)}return{command:target.cmd,args:target.args??[],env:target.env}}function resolveNpx(distribution){return{command:"npx",args:[distribution.package,...distribution.args??[]],env:distribution.env}}function resolveUvx(distribution){return{command:"uvx",args:[distribution.package,...distribution.args??[]],env:distribution.env}}function resolve(distribution,agentId){if(distribution.npx){return resolveNpx(distribution.npx)}if(distribution.uvx){return resolveUvx(distribution.uvx)}if(distribution.binary){return resolveBinary(distribution.binary,agentId)}throw new NoDistributionError(agentId)}import{readFileSync as readFileSync3}from"node:fs";var ENV_REGISTRY_URL2="ACP_REGISTRY_URL";var RegistryFetchError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="RegistryFetchError"}};var RegistryParseError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="RegistryParseError"}};var AgentNotFoundError=class extends Error{constructor(agentId){super(`Agent not found: ${agentId}`);this.agentId=agentId;this.name="AgentNotFoundError"}};function logError(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [ERROR] [registry] ${message}`)}function logInfo2(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [INFO] [registry] ${message}`)}function isNonEmptyString2(value){return typeof value==="string"&&value.length>0}function isValidDistribution(value){if(value===null||typeof value!=="object"){return false}const dist=value;const hasBinary=dist.binary!==void 0&&typeof dist.binary==="object";const hasNpx=dist.npx!==void 0&&typeof dist.npx==="object";const hasUvx=dist.uvx!==void 0&&typeof dist.uvx==="object";if(!hasBinary&&!hasNpx&&!hasUvx){return false}if(hasNpx){const npx=dist.npx;if(!isNonEmptyString2(npx.package)){return false}}if(hasUvx){const uvx=dist.uvx;if(!isNonEmptyString2(uvx.package)){return false}}return true}function parseMcpServer(value,agentIndex,serverIndex){if(value===null||typeof value!=="object"){logWarning3(`Agent at index ${agentIndex}: mcpServers[${serverIndex}] is not an object, skipping`);return null}const raw=value;if(!isNonEmptyString2(raw.name)){logWarning3(`Agent at index ${agentIndex}: mcpServers[${serverIndex}] has invalid or missing "name" field, skipping`);return null}if(!isNonEmptyString2(raw.command)){logWarning3(`Agent at index ${agentIndex}: mcpServers[${serverIndex}] has invalid or missing "command" field, skipping`);return null}const server={name:raw.name,command:raw.command};if(Array.isArray(raw.args)){server.args=raw.args.filter(a=>typeof a==="string")}if(raw.env!==null&&typeof raw.env==="object"&&!Array.isArray(raw.env)){const env={};for(const[key,val]of Object.entries(raw.env)){if(typeof val==="string"){env[key]=val}}if(Object.keys(env).length>0){server.env=env}}return server}function parseMcpServers(servers,agentIndex){const result=[];for(let i=0;i<servers.length;i++){const server=parseMcpServer(servers[i],agentIndex,i);if(server!==null){result.push(server)}}return result}function logWarning3(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [WARN] [registry] ${message}`)}var VALID_AUTH_METHOD_TYPES=["oauth2","api-key"];function parseAuthMethod(value,agentIndex,methodIndex){if(value===null||typeof value!=="object"){logWarning3(`Agent at index ${agentIndex}: authMethods[${methodIndex}] is not an object, skipping`);return null}const raw=value;if(!isNonEmptyString2(raw.id)){logWarning3(`Agent at index ${agentIndex}: authMethods[${methodIndex}] has invalid or missing "id" field, skipping`);return null}if(!isNonEmptyString2(raw.type)||!VALID_AUTH_METHOD_TYPES.includes(raw.type)){logWarning3(`Agent at index ${agentIndex}: authMethods[${methodIndex}] has invalid or missing "type" field (must be 'oauth2' or 'api-key'), skipping`);return null}const method={id:raw.id,type:raw.type};if(isNonEmptyString2(raw.providerId)){method.providerId=raw.providerId}return method}function parseAuthMethods(methods,agentIndex){const result=[];for(let i=0;i<methods.length;i++){const method=parseAuthMethod(methods[i],agentIndex,i);if(method!==null){result.push(method)}}return result}function parseAgent(value,index){if(value===null||typeof value!=="object"){throw new RegistryParseError(`Agent at index ${index} is not an object`)}const raw=value;if(!isNonEmptyString2(raw.id)){throw new RegistryParseError(`Agent at index ${index} has invalid or missing "id" field`)}if(!isNonEmptyString2(raw.name)){throw new RegistryParseError(`Agent at index ${index} has invalid or missing "name" field`)}if(!isNonEmptyString2(raw.version)){throw new RegistryParseError(`Agent at index ${index} has invalid or missing "version" field`)}if(!isValidDistribution(raw.distribution)){throw new RegistryParseError(`Agent at index ${index} has invalid or missing "distribution" field`)}const agent={id:raw.id,name:raw.name,version:raw.version,distribution:raw.distribution};if(typeof raw.description==="string"){agent.description=raw.description}if(typeof raw.repository==="string"){agent.repository=raw.repository}if(Array.isArray(raw.authors)){agent.authors=raw.authors.filter(a=>typeof a==="string")}if(typeof raw.license==="string"){agent.license=raw.license}if(typeof raw.icon==="string"){agent.icon=raw.icon}if(Array.isArray(raw.mcpServers)){const mcpServers=parseMcpServers(raw.mcpServers,index);if(mcpServers.length>0){agent.mcpServers=mcpServers}}if(typeof raw.authRequired==="boolean"){agent.authRequired=raw.authRequired}if(Array.isArray(raw.authMethods)){const authMethods=parseAuthMethods(raw.authMethods,index);if(authMethods.length>0){agent.authMethods=authMethods}}return agent}function parseRegistry(data){if(data===null||typeof data!=="object"){throw new RegistryParseError("Registry data is not an object")}const raw=data;if(!isNonEmptyString2(raw.version)){throw new RegistryParseError('Registry has invalid or missing "version" field')}if(!Array.isArray(raw.agents)){throw new RegistryParseError('Registry has invalid or missing "agents" field')}const agents=[];for(let i=0;i<raw.agents.length;i++){agents.push(parseAgent(raw.agents[i],i))}return{version:raw.version,agents}}var RegistryIndex=class{registryUrl;registry=null;agentMap=new Map;authRequirementsCache=new Map;constructor(registryUrl){const envUrl=process.env[ENV_REGISTRY_URL2];this.registryUrl=isNonEmptyString2(envUrl)?envUrl:registryUrl}async fetch(){logInfo2(`Fetching registry from ${this.registryUrl}`);let response;try{response=await fetch(this.registryUrl)}catch(error){const message=`Failed to fetch registry from ${this.registryUrl}: ${error.message}`;logError(message);throw new RegistryFetchError(message,error)}if(!response.ok){const message=`Failed to fetch registry from ${this.registryUrl}: HTTP ${response.status} ${response.statusText}`;logError(message);throw new RegistryFetchError(message)}let text;try{text=await response.text()}catch(error){const message=`Failed to read registry response body: ${error.message}`;logError(message);throw new RegistryFetchError(message,error)}let data;try{data=JSON.parse(text)}catch(error){const message=`Failed to parse registry JSON: ${error.message}`;logError(message);throw new RegistryParseError(message,error)}try{this.registry=parseRegistry(data)}catch(error){if(error instanceof RegistryParseError){logError(error.message);throw error}const message=`Failed to validate registry data: ${error.message}`;logError(message);throw new RegistryParseError(message,error)}this.agentMap.clear();this.authRequirementsCache.clear();for(const agent of this.registry.agents){this.agentMap.set(agent.id,agent)}logInfo2(`Registry loaded: version ${this.registry.version}, ${this.registry.agents.length} agents`)}lookup(agentId){return this.agentMap.get(agentId)}resolve(agentId){const agent=this.lookup(agentId);if(!agent){throw new AgentNotFoundError(agentId)}return resolve(agent.distribution,agentId)}getRegistry(){return this.registry}getAuthRequirements(agentId){const cached=this.authRequirementsCache.get(agentId);if(cached!==void 0){return cached}const agent=this.lookup(agentId);if(!agent){return void 0}const authMethods=agent.authMethods??[];const hasOAuthMethods=authMethods.some(m=>m.type==="oauth2");const authRequired=agent.authRequired??hasOAuthMethods;let primaryOAuthProviderId;for(const method of authMethods){if(method.type==="oauth2"&&method.providerId){primaryOAuthProviderId=method.providerId;break}}const requirements={authRequired,authMethods,primaryOAuthProviderId};this.authRequirementsCache.set(agentId,requirements);if(authRequired){logInfo2(`Agent "${agentId}" requires authentication${primaryOAuthProviderId?` (OAuth provider: ${primaryOAuthProviderId})`:""}`)}return requirements}clearAuthRequirementsCache(agentId){if(agentId){this.authRequirementsCache.delete(agentId);logInfo2(`Cleared auth requirements cache for agent "${agentId}"`)}else{this.authRequirementsCache.clear();logInfo2("Cleared all auth requirements cache")}}mergeCustomAgents(agents){if(agents.length===0){return}if(!this.registry){this.registry={version:"custom",agents:[]}}for(const agent of agents){const existingIndex=this.registry.agents.findIndex(a=>a.id===agent.id);if(existingIndex!==-1){this.registry.agents[existingIndex]=agent;logInfo2(`Custom agent "${agent.id}" overrides remote registry entry`)}else{this.registry.agents.push(agent);logInfo2(`Custom agent "${agent.id}" added to registry`)}this.agentMap.set(agent.id,agent);this.authRequirementsCache.delete(agent.id)}logInfo2(`Registry now contains ${this.registry.agents.length} agents (${agents.length} custom)`)}};var CustomAgentsLoadError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="CustomAgentsLoadError"}};function loadCustomAgents(filePath){let fileContent;try{fileContent=readFileSync3(filePath,"utf-8")}catch(error){if(error.code==="ENOENT"){throw new CustomAgentsLoadError(`Custom agents file not found: ${filePath}`)}if(error.code==="EACCES"){throw new CustomAgentsLoadError(`Custom agents file not readable: ${filePath}`)}throw new CustomAgentsLoadError(`Failed to read custom agents file "${filePath}": ${error.message}`,error)}let data;try{data=JSON.parse(fileContent)}catch(error){throw new CustomAgentsLoadError(`Custom agents file "${filePath}" contains malformed JSON: ${error.message}`,error)}if(data===null||typeof data!=="object"){throw new CustomAgentsLoadError(`Custom agents file "${filePath}" does not contain a valid object`)}const raw=data;if(!Array.isArray(raw.agents)){throw new CustomAgentsLoadError(`Custom agents file "${filePath}" does not contain a valid "agents" array`)}const registryData={version:"custom",agents:raw.agents};const parsed=parseRegistry(registryData);return parsed.agents}function logError2(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [ERROR] [ndjson] ${message}`)}var NDJSONHandler=class{buffer="";output;messageCallback=null;errorCallback=null;constructor(output){this.output=output}onMessage(callback){this.messageCallback=callback}onError(callback){this.errorCallback=callback}write(message){if(!this.output.writable){return false}try{const json=JSON.stringify(message);this.output.write(json+"\n");return true}catch{return false}}processChunk(chunk){this.buffer+=chunk.toString("utf-8");this.processBuffer()}processBuffer(){let newlineIndex;while((newlineIndex=this.buffer.indexOf("\n"))!==-1){const line=this.buffer.slice(0,newlineIndex);this.buffer=this.buffer.slice(newlineIndex+1);if(line.trim().length===0){continue}this.parseLine(line)}}parseLine(line){try{const message=JSON.parse(line);if(message===null||typeof message!=="object"){const error=new Error("Parsed JSON is not an object");logError2(`Malformed NDJSON line (not an object): ${this.truncateLine(line)}`);this.errorCallback?.(error,line);return}this.messageCallback?.(message)}catch(error){logError2(`Failed to parse NDJSON line: ${this.truncateLine(line)}`);this.errorCallback?.(error,line)}}truncateLine(line,maxLength=100){if(line.length<=maxLength){return line}return line.slice(0,maxLength)+"..."}};import{spawn}from"child_process";var DEFAULT_TERMINATE_TIMEOUT_MS=5e3;var AgentRuntimeImpl=class _AgentRuntimeImpl{agentId;state;process;onExitCallback;constructor(agentId,process2,onExit){this.agentId=agentId;this.process=process2;this.state="starting";this.onExitCallback=onExit;this.setupProcessHandlers()}static spawn(agentId,spawnCommand,onExit){const childProcess=spawn(spawnCommand.command,spawnCommand.args,{stdio:["pipe","pipe","pipe"],env:{...process.env,...spawnCommand.env},detached:false});if(childProcess.stdout){childProcess.stdout.setEncoding("utf8")}if(childProcess.stderr){childProcess.stderr.setEncoding("utf8")}return new _AgentRuntimeImpl(agentId,childProcess,onExit)}setupProcessHandlers(){this.process.on("spawn",()=>{if(this.state==="starting"){this.state="running"}});this.process.on("error",error=>{this.state="stopped";process.stderr.write(`[${new Date().toISOString()}] ERROR: Agent ${this.agentId} process error: ${error.message}
|
|
3
3
|
`)});this.process.on("exit",(code,signal)=>{this.state="stopped";if(this.onExitCallback){this.onExitCallback(code,signal)}});if(this.process.stdin){this.process.stdin.on("error",error=>{process.stderr.write(`[${new Date().toISOString()}] WARN: Agent ${this.agentId} stdin error: ${error.message}
|
|
4
|
-
`)})}}write(message){if(this.state!=="running"&&this.state!=="starting"){return false}if(!this.process.stdin||this.process.stdin.destroyed){return false}try{const ndjsonLine=JSON.stringify(message)+"\n";return this.process.stdin.write(ndjsonLine)}catch{return false}}async terminate(timeout=DEFAULT_TERMINATE_TIMEOUT_MS){if(this.state==="stopped"){return}if(this.state==="stopping"){return this.waitForExit()}this.state="stopping";if(this.process.stdin&&!this.process.stdin.destroyed){this.process.stdin.end()}this.process.kill("SIGTERM");const exitPromise=this.waitForExit();const timeoutPromise=new Promise(resolve2=>{setTimeout(()=>resolve2("timeout"),timeout)});const result=await Promise.race([exitPromise,timeoutPromise]);if(result==="timeout"&&!this.process.killed&&this.process.exitCode===null){this.process.kill("SIGKILL");await this.waitForExit()}}waitForExit(){if(this.state==="stopped"){return Promise.resolve()}return new Promise(resolve2=>{this.process.once("exit",()=>{resolve2()})})}};var DEFAULT_SHUTDOWN_TIMEOUT_MS=5e3;var AgentRuntimeManager=class{runtimes=new Map;exitCallbacks=[];async getOrSpawn(agentId,spawnCommand){const existing=this.runtimes.get(agentId);if(existing&&existing.state!=="stopped"){return existing}const runtime=AgentRuntimeImpl.spawn(agentId,spawnCommand,(code,_signal)=>{this.handleAgentExit(agentId,code)});this.runtimes.set(agentId,runtime);return runtime}get(agentId){return this.runtimes.get(agentId)}async terminate(agentId,timeout=DEFAULT_SHUTDOWN_TIMEOUT_MS){const runtime=this.runtimes.get(agentId);if(!runtime){return}await runtime.terminate(timeout);this.runtimes.delete(agentId)}async terminateAll(timeout=DEFAULT_SHUTDOWN_TIMEOUT_MS){const terminatePromises=[];for(const[agentId,runtime]of this.runtimes){if(runtime.state!=="stopped"){terminatePromises.push(runtime.terminate(timeout).then(()=>{this.runtimes.delete(agentId)}))}}await Promise.all(terminatePromises)}onAgentExit(callback){this.exitCallbacks.push(callback)}handleAgentExit(agentId,code){this.runtimes.delete(agentId);for(const callback of this.exitCallbacks){try{callback(agentId,code)}catch{}}}get size(){return this.runtimes.size}has(agentId){return this.runtimes.has(agentId)}};import{spawn as spawn2}from"node:child_process";var VALID_AUTH_METHOD_TYPES2=["oauth2","api-key"];function isValidAuthMethodType(value){return typeof value==="string"&&VALID_AUTH_METHOD_TYPES2.includes(value)}var DEFAULT_AUTH_METHOD_PRECEDENCE={methodPrecedence:["oauth2","api-key"],failFastOnUnsupported:true,failFastOnAmbiguous:true};var VALID_PROVIDER_IDS=["github","google","cognito","azure","oidc"];function isValidProviderId(value){return typeof value==="string"&&VALID_PROVIDER_IDS.includes(value)}var AUTH_METHOD_ID_TO_PROVIDER_ID={"oauth2-github":"github","oauth2-google":"google","oauth2-cognito":"cognito","oauth2-azure":"azure","oauth2-oidc":"oidc","github":"github","google":"google","cognito":"cognito","azure":"azure","oidc":"oidc"};var VALID_AUTH_METHOD_IDS=Object.keys(AUTH_METHOD_ID_TO_PROVIDER_ID);var RoutingErrorCodes={MISSING_AGENT_ID:-32600,AGENT_NOT_FOUND:-32001,PLATFORM_NOT_SUPPORTED:-32002,SPAWN_FAILED:-32003,AUTH_REQUIRED:-32004};var AUTH_METHOD_ID_TO_PROVIDER={"oauth2-github":"github","oauth2-google":"google","oauth2-cognito":"cognito","oauth2-azure":"azure","agent-github":"github","agent-google":"google","agent-cognito":"cognito","agent-azure":"azure","github-api-key":"github","google-api-key":"google","azure-api-key":"azure","cognito-api-key":"cognito"};var MAX_AUTH_METHODS=50;var MAX_METHOD_ID_LENGTH=128;var VALID_AUTH_METHOD_TYPES3=["oauth2","agent","terminal","api-key"];function parseAuthMethods2(raw){if(!Array.isArray(raw)){logError3("authMethods is not an array, skipping parsing");return[]}const methods=raw.slice(0,MAX_AUTH_METHODS);const parsed=[];const seenIds=new Set;for(const method of methods){const result=parseAuthMethod2(method,seenIds);if(result){parsed.push(result);seenIds.add(result.id)}}logInfo3(`Parsed ${parsed.length} valid auth methods from ${methods.length} raw methods`);return parsed}function parseAuthMethod2(method,seenIds){if(method===null||typeof method!=="object"){return null}const obj=method;const id=obj.id;if(typeof id!=="string"||id.length===0||id.length>MAX_METHOD_ID_LENGTH){logError3(`Invalid auth method id: ${typeof id==="string"?id.substring(0,50):typeof id}`);return null}if(seenIds.has(id)){logInfo3(`Skipping duplicate auth method id: ${id}`);return null}const type=obj.type;if(typeof type!=="string"||!VALID_AUTH_METHOD_TYPES3.includes(type)){logError3(`Invalid auth method type for id ${id}: ${type}`);return null}const rawProviderId=obj.providerId;let providerId;if(rawProviderId!==void 0){if(isValidProviderId(rawProviderId)){providerId=rawProviderId}else{logError3(`Invalid providerId in auth method ${id}: ${rawProviderId}`)}}const mappedProviderId=AUTH_METHOD_ID_TO_PROVIDER[id];if(providerId&&mappedProviderId&&providerId!==mappedProviderId){logError3(`Conflict: auth method ${id} has providerId ${providerId} but maps to ${mappedProviderId}, rejecting`);return null}const resolvedProviderId=providerId??mappedProviderId;if(type==="oauth2"){if(!resolvedProviderId){logError3(`OAuth auth method ${id} has no valid providerId, skipping`);return null}return{kind:"oauth2",id,providerId:resolvedProviderId}}if(type==="agent"){return{kind:"agent",id,providerId:resolvedProviderId}}if(type==="terminal"){const args=Array.isArray(obj.args)?obj.args.filter(a=>typeof a==="string"):void 0;const env=obj.env&&typeof obj.env==="object"&&!Array.isArray(obj.env)?Object.fromEntries(Object.entries(obj.env).filter(([,v])=>typeof v==="string")):void 0;return{kind:"terminal",id,args,env}}if(type==="api-key"){return{kind:"api-key",id,providerId:resolvedProviderId}}return null}function getOAuthMethods(methods){return methods.filter(m=>m.kind==="oauth2")}function getAgentAuthMethods(methods){return methods.filter(m=>m.kind==="agent")}function getTerminalAuthMethods(methods){return methods.filter(m=>m.kind==="terminal")}function getApiKeyMethods(methods){return methods.filter(m=>m.kind==="api-key")}var AGENT_AUTH_TIMEOUT_MS=5*60*1e3;var TERMINAL_AUTH_TIMEOUT_MS=10*60*1e3;var QUEUED_REQUEST_TIMEOUT_MS=5*60*1e3;function logError3(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [ERROR] [router] ${message}`)}function logInfo3(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [INFO] [router] ${message}`)}function createErrorResponse(id,code,message,data){const response={jsonrpc:"2.0",id,error:{code,message}};if(data!==void 0){response.error.data=data}return response}function extractAgentId(message){const msg=message;const agentId=msg.agentId;if(typeof agentId==="string"&&agentId.length>0){return agentId}return void 0}function extractId(message){const msg=message;const id=msg.id;if(typeof id==="string"||typeof id==="number"){return id}return null}function transformMessage(message){const{agentId:_,...rest}=message;return rest}var MessageRouter=class{registry;runtimeManager;writeCallback;apiKeys;spawnFn;isStdinTTY;isStdoutTTY;authManager;pendingRequests=new Map;authState=new Map;agentOAuthRequirements=new Map;requestQueue=new Map;pendingAuthenticateRequests=new Map;sessionIdMap=new Map;autoOAuth;constructor(registry,runtimeManager,writeCallback,apiKeys={},authManager,autoOAuth,deps){this.registry=registry;this.runtimeManager=runtimeManager;this.writeCallback=writeCallback;this.apiKeys=apiKeys;this.authManager=authManager;this.autoOAuth=autoOAuth??this.getAutoOAuthFromEnv();this.spawnFn=deps?.spawnFn??spawn2;this.isStdinTTY=deps?.isStdinTTY??(()=>process.stdin.isTTY??false);this.isStdoutTTY=deps?.isStdoutTTY??(()=>process.stdout.isTTY??false)}getAutoOAuthFromEnv(){const envValue=process.env.AUTH_AUTO_OAUTH;return envValue==="true"||envValue==="1"||envValue==="yes"}getSupportedAuthMethods(){const methods=[{id:"api-key",type:"api-key"}];if(this.authManager){methods.push({id:"oauth2-github",type:"oauth2",providerId:"github"},{id:"oauth2-google",type:"oauth2",providerId:"google"},{id:"oauth2-cognito",type:"oauth2",providerId:"cognito"},{id:"oauth2-azure",type:"oauth2",providerId:"azure"},{id:"oauth2-oidc",type:"oauth2",providerId:"oidc"})}return methods}async hasAuthenticationForAgent(agentId){if(this.authManager){const token=await this.authManager.getTokenForAgent(agentId);if(token){return true}}const apiKey=getAgentApiKey(this.apiKeys,agentId);return apiKey!==void 0}hasCredentialsForAgent(agentId){const apiKey=getAgentApiKey(this.apiKeys,agentId);return apiKey!==void 0}createAuthRequiredError(id,agentId,requiredMethod){const remediation={type:"login_required",commands:["npx @stdiobus/workers-registry acp-registry --setup","stdiobus acp-registry --setup"],hint:"Run: npx @stdiobus/workers-registry acp-registry --setup",docsUrl:"https://github.com/stdiobus/workers-registry/blob/main/docs/oauth/user-guide.md"};return createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication required",{agentId,requiredMethod:requiredMethod??"api-key",supportedMethods:this.getSupportedAuthMethods().map(m=>m.id),remediation})}async injectAuthentication(agentId,message){if(this.authManager){return this.authManager.injectAuth(agentId,message)}return message}injectMcpServers(message,agentId){const agent=this.registry.lookup(agentId);if(!agent?.mcpServers||agent.mcpServers.length===0){return message}const msg=message;const params=msg.params||{};const existingServers=Array.isArray(params.mcpServers)?params.mcpServers:[];const registryServers=agent.mcpServers.map(server=>({name:server.name,command:server.command,args:server.args,env:server.env?Object.entries(server.env).map(([name,value])=>({name,value})):void 0}));const existingNames=new Set(existingServers.filter(s=>s!==null&&typeof s==="object").map(s=>s.name).filter(n=>typeof n==="string"));const mergedServers=[...registryServers.filter(s=>!existingNames.has(s.name)),...existingServers];logInfo3(`Injecting ${registryServers.length} MCP servers from registry for agent ${agentId}`);return{...msg,params:{...params,mcpServers:mergedServers}}}async route(message){const id=extractId(message);const agentId=extractAgentId(message);if(agentId===void 0){logError3("Missing agentId in request");return createErrorResponse(id,RoutingErrorCodes.MISSING_AGENT_ID,"Missing agentId")}const currentAuthState=this.getAuthState(agentId);if(currentAuthState==="pending"){logInfo3(`OAuth flow pending for agent ${agentId}, queueing request (id=${id})`);return this.queueRequest(agentId,message)}if(currentAuthState==="failed"){logError3(`Authentication failed for agent ${agentId}, returning AUTH_REQUIRED`);const requiredProviderId2=this.agentOAuthRequirements.get(agentId);return this.createAuthRequiredErrorWithProvider(id,agentId,requiredProviderId2)}const requiredProviderId=this.agentOAuthRequirements.get(agentId);if(requiredProviderId&¤tAuthState!=="authenticated"){const hasCredentials=await this.hasOAuthCredentialsForAgent(agentId,requiredProviderId);if(!hasCredentials){logError3(`Agent ${agentId} requires OAuth (provider: ${requiredProviderId}) but credentials not available`);return this.createAuthRequiredErrorWithProvider(id,agentId,requiredProviderId)}}return this.routeInternal(message,agentId,id)}async hasOAuthCredentialsForAgent(agentId,providerId){if(!this.authManager){return false}const token=await this.authManager.getTokenForAgent(agentId,providerId);return token!==null&&token!==void 0}createAuthRequiredErrorWithProvider(id,agentId,providerId){const supportedMethods=this.getSupportedAuthMethods();const remediation={type:"login_required",provider:providerId||"unknown",commands:providerId?[`npx @stdiobus/workers-registry acp-registry --login ${providerId}`,`stdiobus acp-registry --login ${providerId}`]:["npx @stdiobus/workers-registry acp-registry --setup","stdiobus acp-registry --setup"],hint:providerId?`Run: npx @stdiobus/workers-registry acp-registry --login ${providerId}`:"Run: npx @stdiobus/workers-registry acp-registry --setup",docsUrl:"https://github.com/stdiobus/workers-registry/blob/main/docs/oauth/user-guide.md"};return createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication required",{agentId,requiredMethod:providerId?`oauth2-${providerId}`:"oauth2",supportedMethods:supportedMethods.map(m=>m.id),providerId,remediation})}async routeInternal(message,agentId,id){let spawnCommand;try{spawnCommand=this.registry.resolve(agentId)}catch(error){if(error instanceof AgentNotFoundError){logError3(`Agent not found: ${agentId}`);return createErrorResponse(id,RoutingErrorCodes.AGENT_NOT_FOUND,"Agent not found",{agentId})}if(error instanceof PlatformNotSupportedError){logError3(`Platform not supported for agent: ${agentId}`);return createErrorResponse(id,RoutingErrorCodes.PLATFORM_NOT_SUPPORTED,"Platform not supported",{agentId,platform:error.platform})}throw error}const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}};logInfo3(`Injected ${Object.keys(agentEnv).length} env vars from api-keys.json for agent ${agentId}`)}let runtime;try{runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to spawn agent ${agentId}: ${error.message}`);return createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Agent spawn failed",{agentId,error:error.message})}if(id!==null){const msg2=message;const clientSessionId=typeof msg2.sessionId==="string"?msg2.sessionId:void 0;const method=typeof msg2.method==="string"?msg2.method:void 0;this.pendingRequests.set(id,{id,agentId,timestamp:Date.now(),method,clientSessionId})}let transformedMessage=transformMessage(message);const msg=message;if(msg.method==="session/new"){transformedMessage=this.injectMcpServers(transformedMessage,agentId)}transformedMessage=await this.injectAuthentication(agentId,transformedMessage);const success=runtime.write(transformedMessage);if(!success){logError3(`Failed to write to agent ${agentId}`);if(id!==null){this.pendingRequests.delete(id)}}else{logInfo3(`Routed message to agent ${agentId}`)}return void 0}getAuthState(agentId){return this.authState.get(agentId)??"none"}setAuthState(agentId,newState){const oldState=this.getAuthState(agentId);if(oldState===newState){return}logInfo3(`Auth state transition for ${agentId}: ${oldState} \u2192 ${newState}`);this.authState.set(agentId,newState);if(newState==="authenticated"&&oldState==="pending"){void this.processQueuedRequests(agentId)}else if(newState==="failed"&&oldState==="pending"){void this.rejectQueuedRequests(agentId)}}queueRequest(agentId,message){return new Promise(resolve2=>{const queuedRequest={message,queuedAt:Date.now(),resolve:resolve2};let queue=this.requestQueue.get(agentId);if(!queue){queue=[];this.requestQueue.set(agentId,queue)}queue.push(queuedRequest);logInfo3(`Queued request for agent ${agentId}, queue size: ${queue.length}`);setTimeout(()=>{this.handleQueuedRequestTimeout(agentId,queuedRequest)},QUEUED_REQUEST_TIMEOUT_MS)})}handleQueuedRequestTimeout(agentId,queuedRequest){const queue=this.requestQueue.get(agentId);if(!queue){return}const index=queue.indexOf(queuedRequest);if(index===-1){return}queue.splice(index,1);logError3(`Queued request timed out for agent ${agentId}`);const id=extractId(queuedRequest.message);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication timeout",{agentId,reason:"OAuth flow timed out while request was queued"}))}async processQueuedRequests(agentId){const queue=this.requestQueue.get(agentId);if(!queue||queue.length===0){return}logInfo3(`Processing ${queue.length} queued requests for agent ${agentId}`);this.requestQueue.delete(agentId);for(const queuedRequest of queue){try{const id=extractId(queuedRequest.message);const result=await this.routeInternal(queuedRequest.message,agentId,id);queuedRequest.resolve(result)}catch(error){const id=extractId(queuedRequest.message);logError3(`Error processing queued request for ${agentId}: ${error.message}`);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Failed to process queued request",{agentId,error:error.message}))}}logInfo3(`Completed processing queued requests for agent ${agentId}`)}async rejectQueuedRequests(agentId){const queue=this.requestQueue.get(agentId);if(!queue||queue.length===0){return}logInfo3(`Rejecting ${queue.length} queued requests for agent ${agentId} due to auth failure`);this.requestQueue.delete(agentId);for(const queuedRequest of queue){const id=extractId(queuedRequest.message);queuedRequest.resolve(this.createAuthRequiredError(id,agentId,"oauth2"))}}getQueuedRequestCount(agentId){const queue=this.requestQueue.get(agentId);return queue?.length??0}getTotalQueuedRequestCount(){let total=0;for(const queue of this.requestQueue.values()){total+=queue.length}return total}handleAgentResponse(agentId,response){const id=extractId(response);let msg=response;const method=typeof msg.method==="string"?msg.method:void 0;if(id!==null&&typeof id==="string"){const pendingAuth=this.pendingAuthenticateRequests.get(id);if(pendingAuth&&pendingAuth.agentId===agentId){this.handleAuthenticateResponse(pendingAuth,msg);return}}if(id!==null&&method){this.handleAgentRequest(agentId,id,method,msg);return}if(id!==null){const pending=this.pendingRequests.get(id);if(pending&&pending.agentId===agentId){const result=msg.result;const isInitializeResponse=pending.method==="initialize"&&result!==void 0;if(isInitializeResponse){const ourAuthMethods=this.getSupportedAuthMethods();const existingAuthMethods=Array.isArray(result.authMethods)?result.authMethods:[];const mergedAuthMethods=[...ourAuthMethods,...existingAuthMethods.filter(m=>!ourAuthMethods.some(our=>our.id===m.id))];msg={...msg,result:{...result,authMethods:mergedAuthMethods}};logInfo3(`Injected ${ourAuthMethods.length} auth methods into initialize response for ${agentId}`)}if(isInitializeResponse&&result&&Array.isArray(result.authMethods)&&result.authMethods.length>0){const parsedMethods=parseAuthMethods2(result.authMethods);if(parsedMethods.length>0){const oauthMethods=getOAuthMethods(parsedMethods);const apiKeyMethods=getApiKeyMethods(parsedMethods);const hasApiKeyCredentials=this.hasCredentialsForAgent(agentId);if(oauthMethods.length>0&&!(apiKeyMethods.length>0&&hasApiKeyCredentials)){const requiredProviderId=oauthMethods[0].providerId;this.agentOAuthRequirements.set(agentId,requiredProviderId);logInfo3(`Agent ${agentId} requires OAuth authentication with provider: ${requiredProviderId}`)}else if(apiKeyMethods.length>0&&hasApiKeyCredentials){logInfo3(`Agent ${agentId} supports OAuth but api-key credentials available, using api-key`)}if(this.autoOAuth){logInfo3(`Agent ${agentId} requires authentication, attempting auto-auth with ${parsedMethods.length} valid methods`);this.setAuthState(agentId,"pending");void this.attemptAuthentication(agentId,parsedMethods)}else{logInfo3(`Agent ${agentId} requires authentication but AUTH_AUTO_OAUTH is disabled. Use --login to authenticate.`)}}else{logError3(`Agent ${agentId} has authMethods but none are valid after parsing`);this.setAuthState(agentId,"none")}}if(result&&typeof result.sessionId==="string"){const agentSessionId=result.sessionId;const clientSessionId=pending.clientSessionId;if(clientSessionId){this.sessionIdMap.set(agentSessionId,clientSessionId);logInfo3(`Mapped agent sessionId ${agentSessionId} to client sessionId ${clientSessionId}`)}}this.pendingRequests.delete(id)}}if(id===null&&method){logInfo3(`Received notification: ${method}`);const params=msg.params;if(params&&typeof params.sessionId==="string"){const agentSessionId=params.sessionId;const clientSessionId=this.sessionIdMap.get(agentSessionId);if(clientSessionId){const enriched={...msg,sessionId:clientSessionId,params:{...params,sessionId:agentSessionId}};logInfo3(`Forwarding notification with mapped sessionId: ${clientSessionId}`);this.writeCallback(enriched);return}else{logError3(`Notification with unmapped agentSessionId: ${agentSessionId}, using default sessionId`);const enriched={...msg,sessionId:"global-notifications",params:{...params,sessionId:agentSessionId}};this.writeCallback(enriched);return}}else{const topLevelSessionId=msg.sessionId;if(topLevelSessionId){this.writeCallback(response);return}else{logError3(`Notification without sessionId: ${method}, adding default sessionId for routing`);const enriched={...msg,sessionId:"global-notifications"};this.writeCallback(enriched);return}}}this.writeCallback(msg)}handleAgentRequest(agentId,id,method,msg){logInfo3(`Agent ${agentId} sent request: ${method} (id=${id}), auto-responding`);let result;if(method==="session/request_permission"){result=this.buildPermissionResponse(msg)}else{logInfo3(`Unknown agent request method: ${method}, sending generic success`);result={}}const response={jsonrpc:"2.0",id,result};this.sendToAgent(agentId,response)}buildPermissionResponse(msg){const params=msg.params;const options=params?.options;if(!options||options.length===0){return{optionId:"approved"}}const allowAlways=options.find(o=>o.kind==="allow_always");if(allowAlways&&typeof allowAlways.optionId==="string"){logInfo3(`Auto-approving permission with option: ${allowAlways.optionId} (allow_always)`);return{optionId:allowAlways.optionId}}const allowOnce=options.find(o=>o.kind==="allow_once");if(allowOnce&&typeof allowOnce.optionId==="string"){logInfo3(`Auto-approving permission with option: ${allowOnce.optionId} (allow_once)`);return{optionId:allowOnce.optionId}}const firstOption=options[0];const optionId=typeof firstOption.optionId==="string"?firstOption.optionId:"approved";logInfo3(`Auto-approving permission with fallback option: ${optionId}`);return{optionId}}handleAuthenticateResponse(pendingAuth,response){const{agentId,authMethodId,requestId}=pendingAuth;if(response.error){const error=response.error;const errorCode=error.code??"UNKNOWN";const errorMessage=typeof error.message==="string"?error.message:"Unknown error";logError3(`Agent Auth failed for ${agentId}: [${errorCode}] ${errorMessage}`);pendingAuth.resolve(false,errorMessage);return}if(response.result!==void 0){logInfo3(`Agent Auth succeeded for ${agentId} (method: ${authMethodId}, request: ${requestId})`);pendingAuth.resolve(true);return}logError3(`Unexpected authenticate response format for ${agentId}: ${JSON.stringify(response)}`);pendingAuth.resolve(false,"Unexpected response format")}sendToAgent(agentId,message){let runtime;try{runtime=this.runtimeManager.get(agentId)}catch{logError3(`Failed to get runtime for agent ${agentId} to send response`);return}if(!runtime){logError3(`No runtime found for agent ${agentId}, cannot send response`);return}const success=runtime.write(message);if(!success){logError3(`Failed to write response to agent ${agentId}`)}else{logInfo3(`Sent auto-response to agent ${agentId}`)}}async attemptAuthentication(agentId,authMethods){const agentAuthMethods=getAgentAuthMethods(authMethods);if(agentAuthMethods.length>0){await this.attemptAgentAuthentication(agentId,agentAuthMethods);return}const terminalAuthMethods=getTerminalAuthMethods(authMethods);if(terminalAuthMethods.length>0){await this.attemptTerminalAuthentication(agentId,terminalAuthMethods);return}const oauthMethods=getOAuthMethods(authMethods);if(oauthMethods.length>0){await this.attemptOAuthAuthentication(agentId,oauthMethods);return}await this.attemptApiKeyAuthentication(agentId,authMethods)}async attemptAgentAuthentication(agentId,agentAuthMethods){const selectedMethod=agentAuthMethods[0];logInfo3(`Agent ${agentId} requires Agent Auth with method: ${selectedMethod.id}`);logInfo3(`Calling authenticate method on agent - agent will handle OAuth flow internally`);this.setAuthState(agentId,"pending");try{let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for Agent Auth: ${error.message}`);this.setAuthState(agentId,"failed");return}const success=await this.callAgentAuthenticate(agentId,selectedMethod.id,runtime);if(success){logInfo3(`Agent Auth successful for agent ${agentId}`);this.setAuthState(agentId,"authenticated")}else{logError3(`Agent Auth failed for agent ${agentId}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Agent Auth error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}callAgentAuthenticate(agentId,authMethodId,runtime){return new Promise(resolve2=>{const requestId=`agent-auth-${agentId}-${Date.now()}`;const authenticateRequest={jsonrpc:"2.0",id:requestId,method:"authenticate",params:{id:authMethodId}};const pendingRequest={requestId,agentId,authMethodId,sentAt:Date.now(),resolve:(success2,error)=>{this.pendingAuthenticateRequests.delete(requestId);if(error){logError3(`Agent Auth response error: ${error}`)}resolve2(success2)}};this.pendingAuthenticateRequests.set(requestId,pendingRequest);setTimeout(()=>{const pending=this.pendingAuthenticateRequests.get(requestId);if(pending){logError3(`Agent Auth timeout for agent ${agentId} (method: ${authMethodId})`);this.pendingAuthenticateRequests.delete(requestId);resolve2(false)}},AGENT_AUTH_TIMEOUT_MS);const success=runtime.write(authenticateRequest);if(!success){logError3(`Failed to send authenticate request to agent ${agentId}`);this.pendingAuthenticateRequests.delete(requestId);resolve2(false)}else{logInfo3(`Sent authenticate request to agent ${agentId} (id: ${requestId}, method: ${authMethodId})`)}})}async attemptTerminalAuthentication(agentId,terminalAuthMethods){const selectedMethod=terminalAuthMethods[0];logInfo3(`Agent ${agentId} requires Terminal Auth with method: ${selectedMethod.id}`);if(!this.isStdinTTY()||!this.isStdoutTTY()){logError3(`Terminal Auth requires interactive terminal (TTY). Run in a terminal with stdin/stdout connected.`);this.setAuthState(agentId,"failed");return}this.setAuthState(agentId,"pending");try{const existingRuntime=this.runtimeManager.get(agentId);if(existingRuntime){logInfo3(`Stopping existing runtime for agent ${agentId} before Terminal Auth`);await this.runtimeManager.terminate(agentId)}const baseSpawnCommand=this.registry.resolve(agentId);const terminalArgs=selectedMethod.args??[];const terminalEnv={...process.env,...selectedMethod.env??{}};logInfo3(`Launching Terminal Auth for ${agentId}: ${baseSpawnCommand.command} ${terminalArgs.join(" ")}`);const exitCode=await this.runTerminalAuthProcess(baseSpawnCommand.command,terminalArgs,terminalEnv);if(exitCode===0){logInfo3(`Terminal Auth process exited successfully for ${agentId}`);const authVerified=await this.verifyTerminalAuthSuccess(agentId);if(authVerified){logInfo3(`Terminal Auth verified for ${agentId}`);this.setAuthState(agentId,"authenticated")}else{logError3(`Terminal Auth completed but verification failed for ${agentId}`);this.setAuthState(agentId,"failed")}}else{logError3(`Terminal Auth process exited with code ${exitCode} for ${agentId}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Terminal Auth error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}runTerminalAuthProcess(command,args,env){return new Promise((resolve2,reject)=>{logInfo3(`Spawning Terminal Auth process: ${command} ${args.join(" ")}`);const child=this.spawnFn(command,args,{env,stdio:"inherit",shell:false});const timeoutId=setTimeout(()=>{logError3(`Terminal Auth process timed out after ${TERMINAL_AUTH_TIMEOUT_MS}ms`);child.kill("SIGTERM");setTimeout(()=>{if(!child.killed){child.kill("SIGKILL")}},5e3)},TERMINAL_AUTH_TIMEOUT_MS);child.on("error",error=>{clearTimeout(timeoutId);reject(error)});child.on("exit",(code,signal)=>{clearTimeout(timeoutId);if(signal){logError3(`Terminal Auth process killed by signal: ${signal}`);resolve2(1)}else{resolve2(code??1)}})})}async verifyTerminalAuthSuccess(agentId){try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}const runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand);return runtime.state==="running"}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Failed to verify Terminal Auth for ${agentId}: ${errorMessage}`);return false}}async attemptOAuthAuthentication(agentId,oauthMethods){if(!this.authManager){logError3(`OAuth authentication required for agent ${agentId}, but AuthManager not available`);this.setAuthState(agentId,"failed");return}const selectedMethod=oauthMethods[0];const providerId=selectedMethod.providerId;logInfo3(`Agent ${agentId} requires OAuth authentication with provider: ${providerId}`);logInfo3(`Initiating OAuth 2.1 Authorization Code flow with PKCE for ${providerId}`);this.setAuthState(agentId,"pending");try{const result=await this.authManager.authenticateAgent(providerId);if(result.success){logInfo3(`OAuth authentication successful for agent ${agentId} with provider ${providerId}`);this.setAuthState(agentId,"authenticated");await this.sendOAuthCredentialsToAgent(agentId,selectedMethod)}else{const errorMsg=result.error?.message??"Unknown error";const errorCode=result.error?.code??"UNKNOWN";logError3(`OAuth authentication failed for agent ${agentId}: [${errorCode}] ${errorMsg}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`OAuth authentication error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}async sendOAuthCredentialsToAgent(agentId,method){if(!this.authManager){logError3(`Cannot send OAuth credentials: AuthManager not available`);return}const token=await this.authManager.getTokenForAgent(agentId,method.providerId);if(!token){logError3(`No OAuth token available for agent ${agentId} after successful auth`);return}let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for OAuth credential injection: ${error.message}`);return}const authRequest={jsonrpc:"2.0",id:`auth-${agentId}-${Date.now()}`,method:"authenticate",params:{methodId:method.id,credentials:{accessToken:token}}};const transformed=transformMessage(authRequest);const serialized=JSON.stringify(transformed)+"\n";if(runtime.process.stdin){runtime.process.stdin.write(serialized,error=>{if(error){logError3(`Failed to send OAuth authenticate request to ${agentId}: ${error.message}`)}else{logInfo3(`Sent OAuth authenticate request to agent ${agentId}`)}})}}async attemptApiKeyAuthentication(agentId,authMethods){const apiKey=getAgentApiKey(this.apiKeys,agentId);if(!apiKey){logError3(`No API key found for agent ${agentId}, authentication will fail`);this.setAuthState(agentId,"failed");return}const apiKeyMethods=getApiKeyMethods(authMethods);const SAFE_API_KEY_METHODS=["api-key","openai-api-key","github-api-key","google-api-key","azure-api-key","cognito-api-key"];const selectedMethod=apiKeyMethods.find(m=>SAFE_API_KEY_METHODS.includes(m.id));if(!selectedMethod){logError3(`No safe API key method available for agent ${agentId}, skipping auto-auth`);this.setAuthState(agentId,"failed");return}logInfo3(`Authenticating agent ${agentId} with API key method: ${selectedMethod.id} (providerId: ${selectedMethod.providerId??"none"})`);let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for authentication: ${error.message}`);this.setAuthState(agentId,"failed");return}const authRequest={jsonrpc:"2.0",id:`auth-${agentId}-${Date.now()}`,method:"authenticate",params:{methodId:selectedMethod.id,credentials:{apiKey}}};const transformed=transformMessage(authRequest);const serialized=JSON.stringify(transformed)+"\n";if(runtime.process.stdin){runtime.process.stdin.write(serialized,error=>{if(error){logError3(`Failed to send authenticate request to ${agentId}: ${error.message}`);this.setAuthState(agentId,"failed")}else{logInfo3(`Sent authenticate request to agent ${agentId}`);this.setAuthState(agentId,"authenticated")}})}}get pendingCount(){return this.pendingRequests.size}isPending(id){return this.pendingRequests.has(id)}clearPending(){this.pendingRequests.clear()}clearQueues(){for(const[agentId,queue]of this.requestQueue.entries()){for(const queuedRequest of queue){const id=extractId(queuedRequest.message);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Router shutdown",{agentId,reason:"Router is shutting down"}))}}this.requestQueue.clear();this.authState.clear();this.agentOAuthRequirements.clear();logInfo3("Cleared all request queues, auth state, and OAuth requirements")}resetAuthState(agentId){this.setAuthState(agentId,"none")}getAgentOAuthRequirement(agentId){return this.agentOAuthRequirements.get(agentId)}setAgentOAuthRequirement(agentId,providerId){this.agentOAuthRequirements.set(agentId,providerId);logInfo3(`Set OAuth requirement for agent ${agentId}: provider ${providerId}`)}clearAgentOAuthRequirement(agentId){this.agentOAuthRequirements.delete(agentId);logInfo3(`Cleared OAuth requirement for agent ${agentId}`)}};var LOG_CONTEXT="registry-launcher";function formatLogMessage(level,message,context=LOG_CONTEXT){const timestamp=new Date().toISOString();return`[${timestamp}] [${level}] [${context}] ${message}`}function log(level,message,context){const formatted=formatLogMessage(level,message,context);console.error(formatted)}function logExit(agentId,exitCode,signal){if(signal){log("INFO",`Agent "${agentId}" exited with signal ${signal}`)}else if(exitCode!==null){log("INFO",`Agent "${agentId}" exited with code ${exitCode}`)}else{log("INFO",`Agent "${agentId}" exited`)}}function logInfo4(message,context){log("INFO",message,context)}function logWarn(message,context){log("WARN",message,context)}function logError4(message,context){log("ERROR",message,context)}import*as readline from"readline";var PROVIDER_INFO=[{id:"github",name:"GitHub",requiresClientSecret:true,requiresCustomEndpoints:false,supportsApiKey:true,supportsOAuth:true,apiKeyLabel:"Personal Access Token",apiKeyEnvVar:"GITHUB_TOKEN"},{id:"google",name:"Google",requiresClientSecret:true,requiresCustomEndpoints:false,supportsApiKey:false,supportsOAuth:true},{id:"cognito",name:"AWS Cognito",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true},{id:"azure",name:"Microsoft Entra ID",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true},{id:"oidc",name:"Generic OIDC",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true}];var TerminalAuthFlow=class{credentialStore;validateCredentials;input;output;rl=null;constructor(dependencies){this.credentialStore=dependencies.credentialStore;this.validateCredentials=dependencies.validateCredentials;this.input=dependencies.input??process.stdin;this.output=dependencies.output??process.stderr}async execute(providerId){this.rl=readline.createInterface({input:this.input,output:this.output});try{this.writeLine("\n=== OAuth Authentication Setup ===\n");const selectedProvider=providerId??await this.selectProvider();const providerInfo=PROVIDER_INFO.find(p=>p.id===selectedProvider);if(!providerInfo){return{useBrowserOAuth:false,authResult:{success:false,providerId:selectedProvider,error:{code:"UNSUPPORTED_PROVIDER",message:`Provider '${selectedProvider}' is not supported.`,details:{supportedProviders:VALID_PROVIDER_IDS}}}}}this.writeLine(`
|
|
4
|
+
`)})}}write(message){if(this.state!=="running"&&this.state!=="starting"){return false}if(!this.process.stdin||this.process.stdin.destroyed){return false}try{const ndjsonLine=JSON.stringify(message)+"\n";return this.process.stdin.write(ndjsonLine)}catch{return false}}async terminate(timeout=DEFAULT_TERMINATE_TIMEOUT_MS){if(this.state==="stopped"){return}if(this.state==="stopping"){return this.waitForExit()}this.state="stopping";if(this.process.stdin&&!this.process.stdin.destroyed){this.process.stdin.end()}this.process.kill("SIGTERM");const exitPromise=this.waitForExit();const timeoutPromise=new Promise(resolve2=>{setTimeout(()=>resolve2("timeout"),timeout)});const result=await Promise.race([exitPromise,timeoutPromise]);if(result==="timeout"&&!this.process.killed&&this.process.exitCode===null){this.process.kill("SIGKILL");await this.waitForExit()}}waitForExit(){if(this.state==="stopped"){return Promise.resolve()}return new Promise(resolve2=>{this.process.once("exit",()=>{resolve2()})})}};var DEFAULT_SHUTDOWN_TIMEOUT_MS=5e3;var AgentRuntimeManager=class{runtimes=new Map;exitCallbacks=[];async getOrSpawn(agentId,spawnCommand){const existing=this.runtimes.get(agentId);if(existing&&existing.state!=="stopped"){return existing}const runtime=AgentRuntimeImpl.spawn(agentId,spawnCommand,(code,_signal)=>{this.handleAgentExit(agentId,code)});this.runtimes.set(agentId,runtime);return runtime}get(agentId){return this.runtimes.get(agentId)}async terminate(agentId,timeout=DEFAULT_SHUTDOWN_TIMEOUT_MS){const runtime=this.runtimes.get(agentId);if(!runtime){return}await runtime.terminate(timeout);this.runtimes.delete(agentId)}async terminateAll(timeout=DEFAULT_SHUTDOWN_TIMEOUT_MS){const terminatePromises=[];for(const[agentId,runtime]of this.runtimes){if(runtime.state!=="stopped"){terminatePromises.push(runtime.terminate(timeout).then(()=>{this.runtimes.delete(agentId)}))}}await Promise.all(terminatePromises)}onAgentExit(callback){this.exitCallbacks.push(callback)}handleAgentExit(agentId,code){this.runtimes.delete(agentId);for(const callback of this.exitCallbacks){try{callback(agentId,code)}catch{}}}get size(){return this.runtimes.size}has(agentId){return this.runtimes.has(agentId)}};import{spawn as spawn2}from"node:child_process";var VALID_AUTH_METHOD_TYPES2=["oauth2","api-key"];function isValidAuthMethodType(value){return typeof value==="string"&&VALID_AUTH_METHOD_TYPES2.includes(value)}var DEFAULT_AUTH_METHOD_PRECEDENCE={methodPrecedence:["oauth2","api-key"],failFastOnUnsupported:true,failFastOnAmbiguous:true};var VALID_PROVIDER_IDS=["github","google","cognito","azure","oidc"];function isValidProviderId(value){return typeof value==="string"&&VALID_PROVIDER_IDS.includes(value)}var AUTH_METHOD_ID_TO_PROVIDER_ID={"oauth2-github":"github","oauth2-google":"google","oauth2-cognito":"cognito","oauth2-azure":"azure","oauth2-oidc":"oidc","github":"github","google":"google","cognito":"cognito","azure":"azure","oidc":"oidc"};var VALID_AUTH_METHOD_IDS=Object.keys(AUTH_METHOD_ID_TO_PROVIDER_ID);var RoutingErrorCodes={MISSING_AGENT_ID:-32600,AGENT_NOT_FOUND:-32001,PLATFORM_NOT_SUPPORTED:-32002,SPAWN_FAILED:-32003,AUTH_REQUIRED:-32004};var AUTH_METHOD_ID_TO_PROVIDER={"oauth2-github":"github","oauth2-google":"google","oauth2-cognito":"cognito","oauth2-azure":"azure","agent-github":"github","agent-google":"google","agent-cognito":"cognito","agent-azure":"azure","github-api-key":"github","google-api-key":"google","azure-api-key":"azure","cognito-api-key":"cognito"};var MAX_AUTH_METHODS=50;var MAX_METHOD_ID_LENGTH=128;var VALID_AUTH_METHOD_TYPES3=["oauth2","agent","terminal","api-key"];function parseAuthMethods2(raw){if(!Array.isArray(raw)){logError3("authMethods is not an array, skipping parsing");return[]}const methods=raw.slice(0,MAX_AUTH_METHODS);const parsed=[];const seenIds=new Set;for(const method of methods){const result=parseAuthMethod2(method,seenIds);if(result){parsed.push(result);seenIds.add(result.id)}}logInfo3(`Parsed ${parsed.length} valid auth methods from ${methods.length} raw methods`);return parsed}function parseAuthMethod2(method,seenIds){if(method===null||typeof method!=="object"){return null}const obj=method;const id=obj.id;if(typeof id!=="string"||id.length===0||id.length>MAX_METHOD_ID_LENGTH){logError3(`Invalid auth method id: ${typeof id==="string"?id.substring(0,50):typeof id}`);return null}if(seenIds.has(id)){logInfo3(`Skipping duplicate auth method id: ${id}`);return null}const type=obj.type;if(typeof type!=="string"||!VALID_AUTH_METHOD_TYPES3.includes(type)){logError3(`Invalid auth method type for id ${id}: ${type}`);return null}const rawProviderId=obj.providerId;let providerId;if(rawProviderId!==void 0){if(isValidProviderId(rawProviderId)){providerId=rawProviderId}else{logError3(`Invalid providerId in auth method ${id}: ${rawProviderId}`)}}const mappedProviderId=AUTH_METHOD_ID_TO_PROVIDER[id];if(providerId&&mappedProviderId&&providerId!==mappedProviderId){logError3(`Conflict: auth method ${id} has providerId ${providerId} but maps to ${mappedProviderId}, rejecting`);return null}const resolvedProviderId=providerId??mappedProviderId;if(type==="oauth2"){if(!resolvedProviderId){logError3(`OAuth auth method ${id} has no valid providerId, skipping`);return null}return{kind:"oauth2",id,providerId:resolvedProviderId}}if(type==="agent"){return{kind:"agent",id,providerId:resolvedProviderId}}if(type==="terminal"){const args=Array.isArray(obj.args)?obj.args.filter(a=>typeof a==="string"):void 0;const env=obj.env&&typeof obj.env==="object"&&!Array.isArray(obj.env)?Object.fromEntries(Object.entries(obj.env).filter(([,v])=>typeof v==="string")):void 0;return{kind:"terminal",id,args,env}}if(type==="api-key"){return{kind:"api-key",id,providerId:resolvedProviderId}}return null}function getOAuthMethods(methods){return methods.filter(m=>m.kind==="oauth2")}function getAgentAuthMethods(methods){return methods.filter(m=>m.kind==="agent")}function getTerminalAuthMethods(methods){return methods.filter(m=>m.kind==="terminal")}function getApiKeyMethods(methods){return methods.filter(m=>m.kind==="api-key")}var AGENT_AUTH_TIMEOUT_MS=5*60*1e3;var TERMINAL_AUTH_TIMEOUT_MS=10*60*1e3;var QUEUED_REQUEST_TIMEOUT_MS=5*60*1e3;function logError3(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [ERROR] [router] ${message}`)}function logInfo3(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [INFO] [router] ${message}`)}function createErrorResponse(id,code,message,data){const response={jsonrpc:"2.0",id,error:{code,message}};if(data!==void 0){response.error.data=data}return response}function extractAgentId(message){const msg=message;const agentId=msg.agentId;if(typeof agentId==="string"&&agentId.length>0){return agentId}return void 0}function extractId(message){const msg=message;const id=msg.id;if(typeof id==="string"||typeof id==="number"){return id}return null}function transformMessage(message){const{agentId:_,...rest}=message;return rest}var MessageRouter=class{registry;runtimeManager;writeCallback;apiKeys;spawnFn;isStdinTTY;isStdoutTTY;authManager;pendingRequests=new Map;authState=new Map;agentOAuthRequirements=new Map;requestQueue=new Map;pendingAuthenticateRequests=new Map;sessionIdMap=new Map;autoOAuth;constructor(registry,runtimeManager,writeCallback,apiKeys={},authManager,autoOAuth,deps){this.registry=registry;this.runtimeManager=runtimeManager;this.writeCallback=writeCallback;this.apiKeys=apiKeys;this.authManager=authManager;this.autoOAuth=autoOAuth??this.getAutoOAuthFromEnv();this.spawnFn=deps?.spawnFn??spawn2;this.isStdinTTY=deps?.isStdinTTY??(()=>process.stdin.isTTY??false);this.isStdoutTTY=deps?.isStdoutTTY??(()=>process.stdout.isTTY??false)}getAutoOAuthFromEnv(){const envValue=process.env.AUTH_AUTO_OAUTH;return envValue==="true"||envValue==="1"||envValue==="yes"}getSupportedAuthMethods(){const methods=[{id:"api-key",type:"api-key"}];if(this.authManager){methods.push({id:"agent-oauth",type:"agent"});methods.push({id:"terminal-setup",type:"terminal",args:["--setup"]});methods.push({id:"oauth2-github",type:"oauth2",providerId:"github"},{id:"oauth2-google",type:"oauth2",providerId:"google"},{id:"oauth2-cognito",type:"oauth2",providerId:"cognito"},{id:"oauth2-azure",type:"oauth2",providerId:"azure"},{id:"oauth2-oidc",type:"oauth2",providerId:"oidc"})}return methods}async hasAuthenticationForAgent(agentId){if(this.authManager){const token=await this.authManager.getTokenForAgent(agentId);if(token){return true}}const apiKey=getAgentApiKey(this.apiKeys,agentId);return apiKey!==void 0}hasCredentialsForAgent(agentId){const apiKey=getAgentApiKey(this.apiKeys,agentId);return apiKey!==void 0}createAuthRequiredError(id,agentId,requiredMethod){const remediation={type:"login_required",commands:["npx @stdiobus/workers-registry acp-registry --setup","stdiobus acp-registry --setup"],hint:"Run: npx @stdiobus/workers-registry acp-registry --setup",docsUrl:"https://github.com/stdiobus/workers-registry/blob/main/docs/oauth/user-guide.md"};return createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication required",{agentId,requiredMethod:requiredMethod??"api-key",supportedMethods:this.getSupportedAuthMethods().map(m=>m.id),remediation})}async injectAuthentication(agentId,message){if(this.authManager){return this.authManager.injectAuth(agentId,message)}return message}injectMcpServers(message,agentId){const agent=this.registry.lookup(agentId);if(!agent?.mcpServers||agent.mcpServers.length===0){return message}const msg=message;const params=msg.params||{};const existingServers=Array.isArray(params.mcpServers)?params.mcpServers:[];const registryServers=agent.mcpServers.map(server=>({name:server.name,command:server.command,args:server.args,env:server.env?Object.entries(server.env).map(([name,value])=>({name,value})):void 0}));const existingNames=new Set(existingServers.filter(s=>s!==null&&typeof s==="object").map(s=>s.name).filter(n=>typeof n==="string"));const mergedServers=[...registryServers.filter(s=>!existingNames.has(s.name)),...existingServers];logInfo3(`Injecting ${registryServers.length} MCP servers from registry for agent ${agentId}`);return{...msg,params:{...params,mcpServers:mergedServers}}}async route(message){const id=extractId(message);const agentId=extractAgentId(message);if(agentId===void 0){logError3("Missing agentId in request");return createErrorResponse(id,RoutingErrorCodes.MISSING_AGENT_ID,"Missing agentId")}const currentAuthState=this.getAuthState(agentId);if(currentAuthState==="pending"){logInfo3(`OAuth flow pending for agent ${agentId}, queueing request (id=${id})`);return this.queueRequest(agentId,message)}if(currentAuthState==="failed"){logError3(`Authentication failed for agent ${agentId}, returning AUTH_REQUIRED`);const requiredProviderId2=this.agentOAuthRequirements.get(agentId);return this.createAuthRequiredErrorWithProvider(id,agentId,requiredProviderId2)}const requiredProviderId=this.agentOAuthRequirements.get(agentId);if(requiredProviderId&¤tAuthState!=="authenticated"){const hasCredentials=await this.hasOAuthCredentialsForAgent(agentId,requiredProviderId);if(!hasCredentials){logError3(`Agent ${agentId} requires OAuth (provider: ${requiredProviderId}) but credentials not available`);return this.createAuthRequiredErrorWithProvider(id,agentId,requiredProviderId)}}return this.routeInternal(message,agentId,id)}async hasOAuthCredentialsForAgent(agentId,providerId){if(!this.authManager){return false}const token=await this.authManager.getTokenForAgent(agentId,providerId);return token!==null&&token!==void 0}createAuthRequiredErrorWithProvider(id,agentId,providerId){const supportedMethods=this.getSupportedAuthMethods();const remediation={type:"login_required",provider:providerId||"unknown",commands:providerId?[`npx @stdiobus/workers-registry acp-registry --login ${providerId}`,`stdiobus acp-registry --login ${providerId}`]:["npx @stdiobus/workers-registry acp-registry --setup","stdiobus acp-registry --setup"],hint:providerId?`Run: npx @stdiobus/workers-registry acp-registry --login ${providerId}`:"Run: npx @stdiobus/workers-registry acp-registry --setup",docsUrl:"https://github.com/stdiobus/workers-registry/blob/main/docs/oauth/user-guide.md"};return createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication required",{agentId,requiredMethod:providerId?`oauth2-${providerId}`:"oauth2",supportedMethods:supportedMethods.map(m=>m.id),providerId,remediation})}async routeInternal(message,agentId,id){let spawnCommand;try{spawnCommand=this.registry.resolve(agentId)}catch(error){if(error instanceof AgentNotFoundError){logError3(`Agent not found: ${agentId}`);return createErrorResponse(id,RoutingErrorCodes.AGENT_NOT_FOUND,"Agent not found",{agentId})}if(error instanceof PlatformNotSupportedError){logError3(`Platform not supported for agent: ${agentId}`);return createErrorResponse(id,RoutingErrorCodes.PLATFORM_NOT_SUPPORTED,"Platform not supported",{agentId,platform:error.platform})}throw error}const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}};logInfo3(`Injected ${Object.keys(agentEnv).length} env vars from api-keys.json for agent ${agentId}`)}let runtime;try{runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to spawn agent ${agentId}: ${error.message}`);return createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Agent spawn failed",{agentId,error:error.message})}if(id!==null){const msg2=message;const clientSessionId=typeof msg2.sessionId==="string"?msg2.sessionId:void 0;const method=typeof msg2.method==="string"?msg2.method:void 0;this.pendingRequests.set(id,{id,agentId,timestamp:Date.now(),method,clientSessionId})}let transformedMessage=transformMessage(message);const msg=message;if(msg.method==="session/new"){transformedMessage=this.injectMcpServers(transformedMessage,agentId)}transformedMessage=await this.injectAuthentication(agentId,transformedMessage);const success=runtime.write(transformedMessage);if(!success){logError3(`Failed to write to agent ${agentId}`);if(id!==null){this.pendingRequests.delete(id)}}else{logInfo3(`Routed message to agent ${agentId}`)}return void 0}getAuthState(agentId){return this.authState.get(agentId)??"none"}setAuthState(agentId,newState){const oldState=this.getAuthState(agentId);if(oldState===newState){return}logInfo3(`Auth state transition for ${agentId}: ${oldState} \u2192 ${newState}`);this.authState.set(agentId,newState);if(newState==="authenticated"&&oldState==="pending"){void this.processQueuedRequests(agentId)}else if(newState==="failed"&&oldState==="pending"){void this.rejectQueuedRequests(agentId)}}queueRequest(agentId,message){return new Promise(resolve2=>{const queuedRequest={message,queuedAt:Date.now(),resolve:resolve2};let queue=this.requestQueue.get(agentId);if(!queue){queue=[];this.requestQueue.set(agentId,queue)}queue.push(queuedRequest);logInfo3(`Queued request for agent ${agentId}, queue size: ${queue.length}`);setTimeout(()=>{this.handleQueuedRequestTimeout(agentId,queuedRequest)},QUEUED_REQUEST_TIMEOUT_MS)})}handleQueuedRequestTimeout(agentId,queuedRequest){const queue=this.requestQueue.get(agentId);if(!queue){return}const index=queue.indexOf(queuedRequest);if(index===-1){return}queue.splice(index,1);logError3(`Queued request timed out for agent ${agentId}`);const id=extractId(queuedRequest.message);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.AUTH_REQUIRED,"Authentication timeout",{agentId,reason:"OAuth flow timed out while request was queued"}))}async processQueuedRequests(agentId){const queue=this.requestQueue.get(agentId);if(!queue||queue.length===0){return}logInfo3(`Processing ${queue.length} queued requests for agent ${agentId}`);this.requestQueue.delete(agentId);for(const queuedRequest of queue){try{const id=extractId(queuedRequest.message);const result=await this.routeInternal(queuedRequest.message,agentId,id);queuedRequest.resolve(result)}catch(error){const id=extractId(queuedRequest.message);logError3(`Error processing queued request for ${agentId}: ${error.message}`);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Failed to process queued request",{agentId,error:error.message}))}}logInfo3(`Completed processing queued requests for agent ${agentId}`)}async rejectQueuedRequests(agentId){const queue=this.requestQueue.get(agentId);if(!queue||queue.length===0){return}logInfo3(`Rejecting ${queue.length} queued requests for agent ${agentId} due to auth failure`);this.requestQueue.delete(agentId);for(const queuedRequest of queue){const id=extractId(queuedRequest.message);queuedRequest.resolve(this.createAuthRequiredError(id,agentId,"oauth2"))}}getQueuedRequestCount(agentId){const queue=this.requestQueue.get(agentId);return queue?.length??0}getTotalQueuedRequestCount(){let total=0;for(const queue of this.requestQueue.values()){total+=queue.length}return total}handleAgentResponse(agentId,response){const id=extractId(response);let msg=response;const method=typeof msg.method==="string"?msg.method:void 0;if(id!==null&&typeof id==="string"){const pendingAuth=this.pendingAuthenticateRequests.get(id);if(pendingAuth&&pendingAuth.agentId===agentId){this.handleAuthenticateResponse(pendingAuth,msg);return}}if(id!==null&&method){this.handleAgentRequest(agentId,id,method,msg);return}if(id!==null){const pending=this.pendingRequests.get(id);if(pending&&pending.agentId===agentId){const result=msg.result;const isInitializeResponse=pending.method==="initialize"&&result!==void 0;if(isInitializeResponse){const ourAuthMethods=this.getSupportedAuthMethods();const existingAuthMethods=Array.isArray(result.authMethods)?result.authMethods:[];const mergedAuthMethods=[...ourAuthMethods,...existingAuthMethods.filter(m=>!ourAuthMethods.some(our=>our.id===m.id))];msg={...msg,result:{...result,authMethods:mergedAuthMethods}};logInfo3(`Injected ${ourAuthMethods.length} auth methods into initialize response for ${agentId}`)}if(isInitializeResponse&&result&&Array.isArray(result.authMethods)&&result.authMethods.length>0){const parsedMethods=parseAuthMethods2(result.authMethods);if(parsedMethods.length>0){const oauthMethods=getOAuthMethods(parsedMethods);const apiKeyMethods=getApiKeyMethods(parsedMethods);const hasApiKeyCredentials=this.hasCredentialsForAgent(agentId);if(oauthMethods.length>0&&!(apiKeyMethods.length>0&&hasApiKeyCredentials)){const requiredProviderId=oauthMethods[0].providerId;this.agentOAuthRequirements.set(agentId,requiredProviderId);logInfo3(`Agent ${agentId} requires OAuth authentication with provider: ${requiredProviderId}`)}else if(apiKeyMethods.length>0&&hasApiKeyCredentials){logInfo3(`Agent ${agentId} supports OAuth but api-key credentials available, using api-key`)}if(this.autoOAuth){logInfo3(`Agent ${agentId} requires authentication, attempting auto-auth with ${parsedMethods.length} valid methods`);this.setAuthState(agentId,"pending");void this.attemptAuthentication(agentId,parsedMethods)}else{logInfo3(`Agent ${agentId} requires authentication but AUTH_AUTO_OAUTH is disabled. Use --login to authenticate.`)}}else{logError3(`Agent ${agentId} has authMethods but none are valid after parsing`);this.setAuthState(agentId,"none")}}if(result&&typeof result.sessionId==="string"){const agentSessionId=result.sessionId;const clientSessionId=pending.clientSessionId;if(clientSessionId){this.sessionIdMap.set(agentSessionId,clientSessionId);logInfo3(`Mapped agent sessionId ${agentSessionId} to client sessionId ${clientSessionId}`)}}this.pendingRequests.delete(id)}}if(id===null&&method){logInfo3(`Received notification: ${method}`);const params=msg.params;if(params&&typeof params.sessionId==="string"){const agentSessionId=params.sessionId;const clientSessionId=this.sessionIdMap.get(agentSessionId);if(clientSessionId){const enriched={...msg,sessionId:clientSessionId,params:{...params,sessionId:agentSessionId}};logInfo3(`Forwarding notification with mapped sessionId: ${clientSessionId}`);this.writeCallback(enriched);return}else{logError3(`Notification with unmapped agentSessionId: ${agentSessionId}, using default sessionId`);const enriched={...msg,sessionId:"global-notifications",params:{...params,sessionId:agentSessionId}};this.writeCallback(enriched);return}}else{const topLevelSessionId=msg.sessionId;if(topLevelSessionId){this.writeCallback(response);return}else{logError3(`Notification without sessionId: ${method}, adding default sessionId for routing`);const enriched={...msg,sessionId:"global-notifications"};this.writeCallback(enriched);return}}}this.writeCallback(msg)}handleAgentRequest(agentId,id,method,msg){logInfo3(`Agent ${agentId} sent request: ${method} (id=${id}), auto-responding`);let result;if(method==="session/request_permission"){result=this.buildPermissionResponse(msg)}else{logInfo3(`Unknown agent request method: ${method}, sending generic success`);result={}}const response={jsonrpc:"2.0",id,result};this.sendToAgent(agentId,response)}buildPermissionResponse(msg){const params=msg.params;const options=params?.options;if(!options||options.length===0){return{optionId:"approved"}}const allowAlways=options.find(o=>o.kind==="allow_always");if(allowAlways&&typeof allowAlways.optionId==="string"){logInfo3(`Auto-approving permission with option: ${allowAlways.optionId} (allow_always)`);return{optionId:allowAlways.optionId}}const allowOnce=options.find(o=>o.kind==="allow_once");if(allowOnce&&typeof allowOnce.optionId==="string"){logInfo3(`Auto-approving permission with option: ${allowOnce.optionId} (allow_once)`);return{optionId:allowOnce.optionId}}const firstOption=options[0];const optionId=typeof firstOption.optionId==="string"?firstOption.optionId:"approved";logInfo3(`Auto-approving permission with fallback option: ${optionId}`);return{optionId}}handleAuthenticateResponse(pendingAuth,response){const{agentId,authMethodId,requestId}=pendingAuth;if(response.error){const error=response.error;const errorCode=error.code??"UNKNOWN";const errorMessage=typeof error.message==="string"?error.message:"Unknown error";logError3(`Agent Auth failed for ${agentId}: [${errorCode}] ${errorMessage}`);pendingAuth.resolve(false,errorMessage);return}if(response.result!==void 0){logInfo3(`Agent Auth succeeded for ${agentId} (method: ${authMethodId}, request: ${requestId})`);pendingAuth.resolve(true);return}logError3(`Unexpected authenticate response format for ${agentId}: ${JSON.stringify(response)}`);pendingAuth.resolve(false,"Unexpected response format")}sendToAgent(agentId,message){let runtime;try{runtime=this.runtimeManager.get(agentId)}catch{logError3(`Failed to get runtime for agent ${agentId} to send response`);return}if(!runtime){logError3(`No runtime found for agent ${agentId}, cannot send response`);return}const success=runtime.write(message);if(!success){logError3(`Failed to write response to agent ${agentId}`)}else{logInfo3(`Sent auto-response to agent ${agentId}`)}}async attemptAuthentication(agentId,authMethods){const agentAuthMethods=getAgentAuthMethods(authMethods);if(agentAuthMethods.length>0){await this.attemptAgentAuthentication(agentId,agentAuthMethods);return}const terminalAuthMethods=getTerminalAuthMethods(authMethods);if(terminalAuthMethods.length>0){await this.attemptTerminalAuthentication(agentId,terminalAuthMethods);return}const oauthMethods=getOAuthMethods(authMethods);if(oauthMethods.length>0){await this.attemptOAuthAuthentication(agentId,oauthMethods);return}await this.attemptApiKeyAuthentication(agentId,authMethods)}async attemptAgentAuthentication(agentId,agentAuthMethods){const selectedMethod=agentAuthMethods[0];logInfo3(`Agent ${agentId} requires Agent Auth with method: ${selectedMethod.id}`);logInfo3(`Calling authenticate method on agent - agent will handle OAuth flow internally`);this.setAuthState(agentId,"pending");try{let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for Agent Auth: ${error.message}`);this.setAuthState(agentId,"failed");return}const success=await this.callAgentAuthenticate(agentId,selectedMethod.id,runtime);if(success){logInfo3(`Agent Auth successful for agent ${agentId}`);this.setAuthState(agentId,"authenticated")}else{logError3(`Agent Auth failed for agent ${agentId}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Agent Auth error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}callAgentAuthenticate(agentId,authMethodId,runtime){return new Promise(resolve2=>{const requestId=`agent-auth-${agentId}-${Date.now()}`;const authenticateRequest={jsonrpc:"2.0",id:requestId,method:"authenticate",params:{id:authMethodId}};const pendingRequest={requestId,agentId,authMethodId,sentAt:Date.now(),resolve:(success2,error)=>{this.pendingAuthenticateRequests.delete(requestId);if(error){logError3(`Agent Auth response error: ${error}`)}resolve2(success2)}};this.pendingAuthenticateRequests.set(requestId,pendingRequest);setTimeout(()=>{const pending=this.pendingAuthenticateRequests.get(requestId);if(pending){logError3(`Agent Auth timeout for agent ${agentId} (method: ${authMethodId})`);this.pendingAuthenticateRequests.delete(requestId);resolve2(false)}},AGENT_AUTH_TIMEOUT_MS);const success=runtime.write(authenticateRequest);if(!success){logError3(`Failed to send authenticate request to agent ${agentId}`);this.pendingAuthenticateRequests.delete(requestId);resolve2(false)}else{logInfo3(`Sent authenticate request to agent ${agentId} (id: ${requestId}, method: ${authMethodId})`)}})}async attemptTerminalAuthentication(agentId,terminalAuthMethods){const selectedMethod=terminalAuthMethods[0];logInfo3(`Agent ${agentId} requires Terminal Auth with method: ${selectedMethod.id}`);if(!this.isStdinTTY()||!this.isStdoutTTY()){logError3(`Terminal Auth requires interactive terminal (TTY). Run in a terminal with stdin/stdout connected.`);this.setAuthState(agentId,"failed");return}this.setAuthState(agentId,"pending");try{const existingRuntime=this.runtimeManager.get(agentId);if(existingRuntime){logInfo3(`Stopping existing runtime for agent ${agentId} before Terminal Auth`);await this.runtimeManager.terminate(agentId)}const baseSpawnCommand=this.registry.resolve(agentId);const terminalArgs=selectedMethod.args??[];const terminalEnv={...process.env,...selectedMethod.env??{}};logInfo3(`Launching Terminal Auth for ${agentId}: ${baseSpawnCommand.command} ${terminalArgs.join(" ")}`);const exitCode=await this.runTerminalAuthProcess(baseSpawnCommand.command,terminalArgs,terminalEnv);if(exitCode===0){logInfo3(`Terminal Auth process exited successfully for ${agentId}`);const authVerified=await this.verifyTerminalAuthSuccess(agentId);if(authVerified){logInfo3(`Terminal Auth verified for ${agentId}`);this.setAuthState(agentId,"authenticated")}else{logError3(`Terminal Auth completed but verification failed for ${agentId}`);this.setAuthState(agentId,"failed")}}else{logError3(`Terminal Auth process exited with code ${exitCode} for ${agentId}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Terminal Auth error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}runTerminalAuthProcess(command,args,env){return new Promise((resolve2,reject)=>{logInfo3(`Spawning Terminal Auth process: ${command} ${args.join(" ")}`);const child=this.spawnFn(command,args,{env,stdio:"inherit",shell:false});const timeoutId=setTimeout(()=>{logError3(`Terminal Auth process timed out after ${TERMINAL_AUTH_TIMEOUT_MS}ms`);child.kill("SIGTERM");setTimeout(()=>{if(!child.killed){child.kill("SIGKILL")}},5e3)},TERMINAL_AUTH_TIMEOUT_MS);child.on("error",error=>{clearTimeout(timeoutId);reject(error)});child.on("exit",(code,signal)=>{clearTimeout(timeoutId);if(signal){logError3(`Terminal Auth process killed by signal: ${signal}`);resolve2(1)}else{resolve2(code??1)}})})}async verifyTerminalAuthSuccess(agentId){try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}const runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand);return runtime.state==="running"}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`Failed to verify Terminal Auth for ${agentId}: ${errorMessage}`);return false}}async attemptOAuthAuthentication(agentId,oauthMethods){if(!this.authManager){logError3(`OAuth authentication required for agent ${agentId}, but AuthManager not available`);this.setAuthState(agentId,"failed");return}const selectedMethod=oauthMethods[0];const providerId=selectedMethod.providerId;logInfo3(`Agent ${agentId} requires OAuth authentication with provider: ${providerId}`);logInfo3(`Initiating OAuth 2.1 Authorization Code flow with PKCE for ${providerId}`);this.setAuthState(agentId,"pending");try{const result=await this.authManager.authenticateAgent(providerId);if(result.success){logInfo3(`OAuth authentication successful for agent ${agentId} with provider ${providerId}`);this.setAuthState(agentId,"authenticated");await this.sendOAuthCredentialsToAgent(agentId,selectedMethod)}else{const errorMsg=result.error?.message??"Unknown error";const errorCode=result.error?.code??"UNKNOWN";logError3(`OAuth authentication failed for agent ${agentId}: [${errorCode}] ${errorMsg}`);this.setAuthState(agentId,"failed")}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);logError3(`OAuth authentication error for agent ${agentId}: ${errorMessage}`);this.setAuthState(agentId,"failed")}}async sendOAuthCredentialsToAgent(agentId,method){if(!this.authManager){logError3(`Cannot send OAuth credentials: AuthManager not available`);return}const token=await this.authManager.getTokenForAgent(agentId,method.providerId);if(!token){logError3(`No OAuth token available for agent ${agentId} after successful auth`);return}let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for OAuth credential injection: ${error.message}`);return}const authRequest={jsonrpc:"2.0",id:`auth-${agentId}-${Date.now()}`,method:"authenticate",params:{methodId:method.id,credentials:{accessToken:token}}};const transformed=transformMessage(authRequest);const serialized=JSON.stringify(transformed)+"\n";if(runtime.process.stdin){runtime.process.stdin.write(serialized,error=>{if(error){logError3(`Failed to send OAuth authenticate request to ${agentId}: ${error.message}`)}else{logInfo3(`Sent OAuth authenticate request to agent ${agentId}`)}})}}async attemptApiKeyAuthentication(agentId,authMethods){const apiKey=getAgentApiKey(this.apiKeys,agentId);if(!apiKey){logError3(`No API key found for agent ${agentId}, authentication will fail`);this.setAuthState(agentId,"failed");return}const apiKeyMethods=getApiKeyMethods(authMethods);const SAFE_API_KEY_METHODS=["api-key","openai-api-key","github-api-key","google-api-key","azure-api-key","cognito-api-key"];const selectedMethod=apiKeyMethods.find(m=>SAFE_API_KEY_METHODS.includes(m.id));if(!selectedMethod){logError3(`No safe API key method available for agent ${agentId}, skipping auto-auth`);this.setAuthState(agentId,"failed");return}logInfo3(`Authenticating agent ${agentId} with API key method: ${selectedMethod.id} (providerId: ${selectedMethod.providerId??"none"})`);let runtime;try{let spawnCommand=this.registry.resolve(agentId);const agentEnv=getAgentEnv(this.apiKeys,agentId);if(Object.keys(agentEnv).length>0){spawnCommand={...spawnCommand,env:{...spawnCommand.env,...agentEnv}}}runtime=await this.runtimeManager.getOrSpawn(agentId,spawnCommand)}catch(error){logError3(`Failed to get runtime for authentication: ${error.message}`);this.setAuthState(agentId,"failed");return}const authRequest={jsonrpc:"2.0",id:`auth-${agentId}-${Date.now()}`,method:"authenticate",params:{methodId:selectedMethod.id,credentials:{apiKey}}};const transformed=transformMessage(authRequest);const serialized=JSON.stringify(transformed)+"\n";if(runtime.process.stdin){runtime.process.stdin.write(serialized,error=>{if(error){logError3(`Failed to send authenticate request to ${agentId}: ${error.message}`);this.setAuthState(agentId,"failed")}else{logInfo3(`Sent authenticate request to agent ${agentId}`);this.setAuthState(agentId,"authenticated")}})}}get pendingCount(){return this.pendingRequests.size}isPending(id){return this.pendingRequests.has(id)}clearPending(){this.pendingRequests.clear()}clearQueues(){for(const[agentId,queue]of this.requestQueue.entries()){for(const queuedRequest of queue){const id=extractId(queuedRequest.message);queuedRequest.resolve(createErrorResponse(id,RoutingErrorCodes.SPAWN_FAILED,"Router shutdown",{agentId,reason:"Router is shutting down"}))}}this.requestQueue.clear();this.authState.clear();this.agentOAuthRequirements.clear();logInfo3("Cleared all request queues, auth state, and OAuth requirements")}resetAuthState(agentId){this.setAuthState(agentId,"none")}getAgentOAuthRequirement(agentId){return this.agentOAuthRequirements.get(agentId)}setAgentOAuthRequirement(agentId,providerId){this.agentOAuthRequirements.set(agentId,providerId);logInfo3(`Set OAuth requirement for agent ${agentId}: provider ${providerId}`)}clearAgentOAuthRequirement(agentId){this.agentOAuthRequirements.delete(agentId);logInfo3(`Cleared OAuth requirement for agent ${agentId}`)}};var LOG_CONTEXT="registry-launcher";function formatLogMessage(level,message,context=LOG_CONTEXT){const timestamp=new Date().toISOString();return`[${timestamp}] [${level}] [${context}] ${message}`}function log(level,message,context){const formatted=formatLogMessage(level,message,context);console.error(formatted)}function logExit(agentId,exitCode,signal){if(signal){log("INFO",`Agent "${agentId}" exited with signal ${signal}`)}else if(exitCode!==null){log("INFO",`Agent "${agentId}" exited with code ${exitCode}`)}else{log("INFO",`Agent "${agentId}" exited`)}}function logInfo4(message,context){log("INFO",message,context)}function logWarn(message,context){log("WARN",message,context)}function logError4(message,context){log("ERROR",message,context)}import*as readline from"readline";var PROVIDER_INFO=[{id:"github",name:"GitHub",requiresClientSecret:true,requiresCustomEndpoints:false,supportsApiKey:true,supportsOAuth:true,apiKeyLabel:"Personal Access Token",apiKeyEnvVar:"GITHUB_TOKEN"},{id:"google",name:"Google",requiresClientSecret:true,requiresCustomEndpoints:false,supportsApiKey:false,supportsOAuth:true},{id:"cognito",name:"AWS Cognito",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true},{id:"azure",name:"Microsoft Entra ID",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true},{id:"oidc",name:"Generic OIDC",requiresClientSecret:true,requiresCustomEndpoints:true,supportsApiKey:false,supportsOAuth:true}];var TerminalAuthFlow=class{credentialStore;validateCredentials;input;output;rl=null;constructor(dependencies){this.credentialStore=dependencies.credentialStore;this.validateCredentials=dependencies.validateCredentials;this.input=dependencies.input??process.stdin;this.output=dependencies.output??process.stderr}async execute(providerId){this.rl=readline.createInterface({input:this.input,output:this.output});try{this.writeLine("\n=== OAuth Authentication Setup ===\n");const selectedProvider=providerId??await this.selectProvider();const providerInfo=PROVIDER_INFO.find(p=>p.id===selectedProvider);if(!providerInfo){return{useBrowserOAuth:false,authResult:{success:false,providerId:selectedProvider,error:{code:"UNSUPPORTED_PROVIDER",message:`Provider '${selectedProvider}' is not supported.`,details:{supportedProviders:VALID_PROVIDER_IDS}}}}}this.writeLine(`
|
|
5
5
|
Configuring ${providerInfo.name}...
|
|
6
6
|
`);if(providerInfo.supportsOAuth){const authMode=await this.selectAuthenticationMode(providerInfo);if(authMode==="browser-oauth"){this.writeLine("\nBrowser OAuth selected. Launching browser authentication flow...\n");return{useBrowserOAuth:true,providerId:selectedProvider}}}const result=await this.collectAndValidateWithRetry(selectedProvider,providerInfo);return{useBrowserOAuth:false,authResult:result}}catch(error){const errorMessage=error instanceof Error?error.message:String(error);console.error(`[TerminalAuthFlow] Error: ${errorMessage}`);const errorProviderId=providerId||"github";return{useBrowserOAuth:false,authResult:{success:false,providerId:errorProviderId,error:{code:"PROVIDER_ERROR",message:`Terminal auth flow failed: ${errorMessage}`}}}}finally{this.cleanup()}}async selectAuthenticationMode(providerInfo){this.writeLine(`${providerInfo.name} supports multiple authentication methods:
|
|
7
7
|
`);this.writeLine(" 1. Browser OAuth (recommended) - Opens browser for secure authentication");this.writeLine(" 2. Manual API Key - Enter credentials directly in terminal\n");const selection=await this.promptSelection("Select authentication method (1-2) [default: 1]: ",1,2,1);return selection===1?"browser-oauth":"manual-api-key"}async collectAndValidateWithRetry(selectedProvider,providerInfo){let credentials=null;let validationResult=null;let attempts=0;const maxAttempts=3;const useApiKey=providerInfo.supportsApiKey;while(attempts<maxAttempts){attempts++;if(useApiKey){credentials=await this.collectApiKeyCredentials(providerInfo)}else{credentials=await this.collectCredentials(providerInfo)}this.writeLine("\nValidating credentials...");validationResult=await this.validateCredentials(selectedProvider,credentials);if(validationResult.valid){break}this.writeLine(`
|