@stdiobus/workers-registry 1.5.0-beta.1 → 1.5.0-beta.3

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/README.md CHANGED
@@ -21,9 +21,15 @@ Worker implementations for [stdio Bus kernel](https://github.com/stdiobus/stdiob
21
21
  npm install @stdiobus/workers-registry
22
22
  ```
23
23
 
24
+ For embedded usage (no Docker/binary needed):
25
+
26
+ ```bash
27
+ npm install @stdiobus/node @stdiobus/workers-registry
28
+ ```
29
+
24
30
  **Requirements:**
25
31
  - Node.js ≥20.0.0
26
- - [stdio Bus kernel](https://github.com/stdiobus/stdiobus) (Docker or binary)
32
+ - [stdio Bus kernel](https://github.com/stdiobus/stdiobus) (Docker or binary) — or [`@stdiobus/node`](https://www.npmjs.com/package/@stdiobus/node) for embedded mode
27
33
 
28
34
  **Keywords:** `stdiobus`, `protocol`, `acp`, `mcp`, `agent`, `transport`, `json-rpc`, `stdio-bus`, `worker`
29
35
 
@@ -61,22 +67,26 @@ graph TB
61
67
 
62
68
  ## Prerequisites
63
69
 
64
- - stdio Bus kernel - available via [Docker](https://hub.docker.com/r/stdiobus/stdiobus) or [build from source](https://github.com/stdiobus/stdiobus)
65
- - Node.js 20.0.0 or later (for building workers)
70
+ - Node.js 20.0.0 or later
71
+ - One of:
72
+ - [`@stdiobus/node`](https://www.npmjs.com/package/@stdiobus/node) — embedded mode, no external dependencies
73
+ - [stdio Bus kernel via Docker](https://hub.docker.com/r/stdiobus/stdiobus) — TCP/Unix socket mode
74
+ - [stdio Bus kernel binary](https://github.com/stdiobus/stdiobus) — build from source
66
75
 
67
76
  ## Workers
68
77
 
69
78
  | Worker | Description | Protocol | Command |
70
79
  |--------|-------------|----------|---------|
71
- | `acp-registry` | Registry Launcher worker that routes to ACP Registry agents (requires `api-keys.json`) | ACP | `node ./node_modules/@stdiobus/workers-registry/launch acp-registry` |
72
- | `acp-worker` | Full ACP protocol implementation (standalone agent; does **not** route to ACP Registry) | ACP | `node ./node_modules/@stdiobus/workers-registry/launch acp-worker` |
80
+ | `acp-registry` | Registry Launcher worker that routes to ACP Registry agents (requires `api-keys.json`) | ACP | `npx @stdiobus/workers-registry acp-registry` |
81
+ | `acp-worker` | Full ACP protocol implementation (standalone agent; does **not** route to ACP Registry) | ACP | `npx @stdiobus/workers-registry acp-worker` |
73
82
  | `registry-launcher` | Registry Launcher implementation module used by `acp-registry` (not a launch target) | ACP | Use `acp-registry` |
74
- | `mcp-to-acp-proxy` | Bridges MCP clients (like IDEs) to ACP agents | MCP → ACP | `node ./node_modules/@stdiobus/workers-registry/launch mcp-to-acp-proxy` |
75
- | `echo-worker` | Simple echo worker for testing NDJSON protocol | NDJSON | `node ./node_modules/@stdiobus/workers-registry/launch echo-worker` |
76
- | `mcp-echo-server` | MCP server example for testing | MCP | `node ./node_modules/@stdiobus/workers-registry/launch mcp-echo-server` |
83
+ | `openai-agent` | OpenAI Chat Completions API agent (bridges ACP to any OpenAI-compatible endpoint) | ACP | `npx @stdiobus/workers-registry openai-agent` |
84
+ | `mcp-to-acp-proxy` | Bridges MCP clients (like IDEs) to ACP agents | MCP → ACP | `npx @stdiobus/workers-registry mcp-to-acp-proxy` |
85
+ | `echo-worker` | Simple echo worker for testing NDJSON protocol | NDJSON | `npx @stdiobus/workers-registry echo-worker` |
86
+ | `mcp-echo-server` | MCP server example for testing | MCP | `npx @stdiobus/workers-registry mcp-echo-server` |
77
87
 
78
- **Note:** The universal launcher is `@stdiobus/workers-registry/launch`. In this repo, use
79
- `node ./launch/index.js <worker-name>` after `npm run build`.
88
+ **Note:** The universal launcher is `@stdiobus/workers-registry/launch`. For local
89
+ development in this repo, use `node ./launch/index.js <worker-name>` after `npm run build`.
80
90
 
81
91
  ## Package API
82
92
 
@@ -111,13 +121,75 @@ import type { MCPServer } from '@stdiobus/workers-registry/workers/mcp-echo-serv
111
121
 
112
122
  ## Quick Start
113
123
 
114
- ### 1. Install Package
124
+ ### Option A: Embedded via `@stdiobus/node` (simplest)
125
+
126
+ No Docker, no binary, no TCP — just npm packages. The bus runs inside your Node.js process.
127
+
128
+ ```bash
129
+ npm install @stdiobus/node @stdiobus/workers-registry
130
+ ```
131
+
132
+ Create `config.json`:
133
+
134
+ ```json
135
+ {
136
+ "pools": [
137
+ {
138
+ "id": "openai-agent",
139
+ "command": "npx",
140
+ "args": ["@stdiobus/workers-registry", "openai-agent"],
141
+ "instances": 1
142
+ }
143
+ ]
144
+ }
145
+ ```
146
+
147
+ Use it in code:
148
+
149
+ ```javascript
150
+ import { StdioBus } from '@stdiobus/node';
151
+
152
+ const bus = new StdioBus({ configPath: './config.json' });
153
+ await bus.start();
154
+
155
+ // Send ACP initialize request
156
+ const result = await bus.request('initialize', {
157
+ protocolVersion: 1,
158
+ clientInfo: { name: 'my-app', version: '1.0.0' },
159
+ });
160
+
161
+ console.log(result.agentInfo.name); // 'openai-agent'
162
+ console.log(result.authMethods); // [{ id: 'oauth2', ... }]
163
+
164
+ await bus.stop();
165
+ ```
166
+
167
+ Or run any other worker the same way — just change the pool config:
168
+
169
+ ```json
170
+ {
171
+ "pools": [
172
+ {
173
+ "id": "acp-registry",
174
+ "command": "npx",
175
+ "args": ["@stdiobus/workers-registry", "acp-registry"],
176
+ "instances": 1
177
+ }
178
+ ]
179
+ }
180
+ ```
181
+
182
+ See [`@stdiobus/node` on npm](https://www.npmjs.com/package/@stdiobus/node) for TCP mode, Unix socket mode, Docker backend, and full API reference.
183
+
184
+ ### Option B: Docker / Binary (TCP mode)
185
+
186
+ #### 1. Install Package
115
187
 
116
188
  ```bash
117
189
  npm install @stdiobus/workers-registry
118
190
  ```
119
191
 
120
- ### 2. Get stdio Bus kernel
192
+ #### 2. Get stdio Bus kernel
121
193
 
122
194
  **Option A: Using Docker (recommended)**
123
195
 
@@ -129,7 +201,7 @@ docker pull stdiobus/stdiobus:latest
129
201
 
130
202
  See [stdio Bus kernel repository](https://github.com/stdiobus/stdiobus) for build instructions.
131
203
 
132
- ### 3. Run with ACP Registry (recommended for real agents)
204
+ #### 3. Run with ACP Registry (recommended for real agents)
133
205
 
134
206
  **Create config.json:**
135
207
  ```json
@@ -155,7 +227,7 @@ or pass a custom config file (third arg to `launch acp-registry`) with an absolu
155
227
  Use the same Docker/binary commands below (they run `config.json`), and ensure
156
228
  `api-keys.json` is mounted into the container when using Docker.
157
229
 
158
- ### 4. Run with ACP Worker
230
+ #### 4. Run with ACP Worker
159
231
 
160
232
  **Note:** `acp-worker` is a standalone ACP agent for SDK/protocol testing. It does **not**
161
233
  route to the ACP Registry. Use `acp-registry` when you need real registry agents.
@@ -191,7 +263,7 @@ docker run -p 9000:9000 \
191
263
  ./stdio_bus --config config.json --tcp 0.0.0.0:9000
192
264
  ```
193
265
 
194
- ### 5. Test Connection
266
+ #### 5. Test Connection
195
267
 
196
268
  ```bash
197
269
  # ACP worker (standalone)
@@ -210,8 +282,8 @@ echo '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"agentId":"claud
210
282
  The simplest way to run any worker:
211
283
 
212
284
  ```bash
213
- # Run any worker by name (package install)
214
- node ./node_modules/@stdiobus/workers-registry/launch <worker-name>
285
+ # Run any worker by name (recommended)
286
+ npx @stdiobus/workers-registry <worker-name>
215
287
 
216
288
  # Run any worker by name (this repo, after build)
217
289
  node ./launch/index.js <worker-name>
@@ -222,9 +294,10 @@ node ./launch/index.js <worker-name>
222
294
  # - echo-worker
223
295
  # - mcp-echo-server
224
296
  # - mcp-to-acp-proxy
297
+ # - openai-agent
225
298
 
226
299
  # Example: Run echo worker for testing
227
- node ./node_modules/@stdiobus/workers-registry/launch echo-worker
300
+ npx @stdiobus/workers-registry echo-worker
228
301
  ```
229
302
 
230
303
  ### Using in stdio Bus Configuration
@@ -814,14 +887,35 @@ rl.on('close', () => process.exit(0));
814
887
 
815
888
  ```
816
889
  workers-registry/
890
+ ├── index.ts # Package entry point
891
+ ├── launch/ # Universal launcher (npx entry point)
817
892
  ├── acp-worker/ # Full ACP protocol implementation
818
893
  │ ├── src/
819
894
  │ │ ├── agent.ts # ACP Agent implementation
820
895
  │ │ ├── index.ts # Main entry point
896
+ │ │ ├── acp/ # ACP protocol layer
821
897
  │ │ ├── mcp/ # MCP server integration
898
+ │ │ ├── mcp-proxy/ # MCP-to-ACP proxy logic
822
899
  │ │ ├── session/ # Session management
823
- │ │ └── registry-launcher/ # Registry Launcher implementation
900
+ │ │ ├── stdio/ # Session ID routing
901
+ │ │ └── test-utils/ # Testing utilities
824
902
  │ └── tests/ # Test suites
903
+ ├── registry-launcher/ # Registry Launcher (agent discovery + routing)
904
+ │ └── src/
905
+ │ ├── auth/ # OAuth 2.1 authentication
906
+ │ ├── config/ # Configuration management
907
+ │ ├── registry/ # ACP Registry resolution
908
+ │ ├── router/ # Message routing
909
+ │ ├── runtime/ # Agent runtime management
910
+ │ ├── stream/ # NDJSON stream handling
911
+ │ └── test-utils/ # Testing utilities
912
+ ├── openai-agent/ # OpenAI Chat Completions API agent
913
+ │ └── src/
914
+ │ ├── agent.ts # ACP Agent bridging to OpenAI API
915
+ │ ├── client.ts # Chat Completions HTTP + SSE client
916
+ │ ├── sse-parser.ts # SSE line parser
917
+ │ ├── session.ts # Session state management
918
+ │ └── config.ts # Environment-based configuration
825
919
  ├── acp-registry/ # ACP Registry worker entrypoint + configs
826
920
  ├── echo-worker/ # Simple echo worker example
827
921
  ├── mcp-echo-server/ # MCP server example
@@ -884,8 +978,8 @@ nvm install 20 # If using nvm
884
978
  **Permission errors:**
885
979
  ```bash
886
980
  npm install -g @stdiobus/workers-registry # Global install (may need sudo)
887
- # Or use a local install
888
- node ./node_modules/@stdiobus/workers-registry/launch acp-worker
981
+ # Or use npx
982
+ npx @stdiobus/workers-registry acp-worker
889
983
  ```
890
984
 
891
985
  ### Runtime Issues
@@ -958,27 +1052,27 @@ Registry Launcher supports OAuth 2.1 with PKCE for secure browser-based authenti
958
1052
 
959
1053
  | Provider | OAuth 2.1 | API Key | Status |
960
1054
  |----------|-----------|---------|--------|
961
- | OpenAI | | | Production |
962
- | Anthropic | | | Production |
963
- | GitHub | | | Production |
964
- | Google | | | Production |
965
- | Azure AD | | | Production |
966
- | AWS Cognito | | | Production |
1055
+ | OpenAI | | | Production |
1056
+ | Anthropic | | | Production |
1057
+ | GitHub | | | Production |
1058
+ | Google | | | Production |
1059
+ | Azure AD | | | Production |
1060
+ | AWS Cognito | | | Production |
967
1061
 
968
1062
  ### Quick Start
969
1063
 
970
1064
  ```bash
971
1065
  # Check current authentication status
972
- node ./launch/index.js acp-registry --auth-status
1066
+ npx @stdiobus/workers-registry acp-registry --auth-status
973
1067
 
974
1068
  # Login with browser OAuth (opens browser)
975
- node ./launch/index.js acp-registry --login openai
1069
+ npx @stdiobus/workers-registry acp-registry --login openai
976
1070
 
977
1071
  # Interactive setup wizard
978
- node ./launch/index.js acp-registry --setup
1072
+ npx @stdiobus/workers-registry acp-registry --setup
979
1073
 
980
1074
  # Logout from all providers
981
- node ./launch/index.js acp-registry --logout
1075
+ npx @stdiobus/workers-registry acp-registry --logout
982
1076
  ```
983
1077
 
984
1078
  ### Backward Compatibility
@@ -1001,7 +1095,7 @@ echo '{"claude-acp":{"apiKey":"sk-..."}}' > api-keys.json
1001
1095
  export ANTHROPIC_API_KEY=sk-...
1002
1096
 
1003
1097
  # Option 3: Interactive setup (if TTY available)
1004
- node ./launch/index.js acp-registry --setup
1098
+ npx @stdiobus/workers-registry acp-registry --setup
1005
1099
  ```
1006
1100
 
1007
1101
  ### Documentation
@@ -1018,6 +1112,7 @@ node ./launch/index.js acp-registry --setup
1018
1112
  ## Resources
1019
1113
 
1020
1114
  - [stdio Bus kernel](https://github.com/stdiobus/stdiobus) - Core protocol and daemon (source code)
1115
+ - [`@stdiobus/node`](https://www.npmjs.com/package/@stdiobus/node) - Embedded Node.js binding (no Docker/binary needed)
1021
1116
  - [stdio Bus on Docker Hub](https://hub.docker.com/r/stdiobus/stdiobus) - Docker images for easy deployment
1022
1117
  - [stdio Bus Full Documentation](https://stdiobus.com) – Core protocol documentation
1023
1118
  - [ACP Registry](https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json) - Available ACP agents
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  var __getOwnPropNames=Object.getOwnPropertyNames;var __esm=(fn,res)=>function __init(){return fn&&(res=(0,fn[__getOwnPropNames(fn)[0]])(fn=0)),res};var DEFAULT_CONFIG;var init_types=__esm({"workers-registry/registry-launcher/src/config/types.ts"(){"use strict";DEFAULT_CONFIG={registryUrl:"https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json",apiKeysPath:"./api-keys.json",shutdownTimeoutSec:5}}});import{readFileSync}from"node:fs";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}var ENV_REGISTRY_URL,ENV_API_KEYS_PATH,ENV_CUSTOM_AGENTS_PATH;var init_config=__esm({"workers-registry/registry-launcher/src/config/config.ts"(){"use strict";init_types();ENV_REGISTRY_URL="ACP_REGISTRY_URL";ENV_API_KEYS_PATH="ACP_API_KEYS_PATH";ENV_CUSTOM_AGENTS_PATH="ACP_CUSTOM_AGENTS_PATH"}});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 init_api_keys=__esm({"workers-registry/registry-launcher/src/config/api-keys.ts"(){"use strict"}});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)}var PlatformNotSupportedError,NoDistributionError;var init_resolver=__esm({"workers-registry/registry-launcher/src/registry/resolver.ts"(){"use strict";PlatformNotSupportedError=class extends Error{constructor(agentId,platform){super(`Platform not supported: ${platform} for agent ${agentId}`);this.agentId=agentId;this.platform=platform;this.name="PlatformNotSupportedError"}};NoDistributionError=class extends Error{constructor(agentId){super(`No supported distribution type for agent ${agentId}`);this.agentId=agentId;this.name="NoDistributionError"}}}});import{readFileSync as readFileSync3}from"node:fs";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}`)}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}}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}var ENV_REGISTRY_URL2,RegistryFetchError,RegistryParseError,AgentNotFoundError,VALID_AUTH_METHOD_TYPES,RegistryIndex,CustomAgentsLoadError;var init_registry=__esm({"workers-registry/registry-launcher/src/registry/index.ts"(){"use strict";init_resolver();init_resolver();ENV_REGISTRY_URL2="ACP_REGISTRY_URL";RegistryFetchError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="RegistryFetchError"}};RegistryParseError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="RegistryParseError"}};AgentNotFoundError=class extends Error{constructor(agentId){super(`Agent not found: ${agentId}`);this.agentId=agentId;this.name="AgentNotFoundError"}};VALID_AUTH_METHOD_TYPES=["oauth2","api-key"];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)`)}};CustomAgentsLoadError=class extends Error{constructor(message,cause){super(message);this.cause=cause;this.name="CustomAgentsLoadError"}}}});function logError2(message){const timestamp=new Date().toISOString();console.error(`[${timestamp}] [ERROR] [ndjson] ${message}`)}var NDJSONHandler;var init_ndjson_handler=__esm({"workers-registry/registry-launcher/src/stream/ndjson-handler.ts"(){"use strict";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,AgentRuntimeImpl;var init_agent_runtime=__esm({"workers-registry/registry-launcher/src/runtime/agent-runtime.ts"(){"use strict";DEFAULT_TERMINATE_TIMEOUT_MS=5e3;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,AgentRuntimeManager;var init_manager=__esm({"workers-registry/registry-launcher/src/runtime/manager.ts"(){"use strict";init_agent_runtime();DEFAULT_SHUTDOWN_TIMEOUT_MS=5e3;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)}}}});function isValidAuthMethodType(value){return typeof value==="string"&&VALID_AUTH_METHOD_TYPES2.includes(value)}function isValidProviderId(value){return typeof value==="string"&&VALID_PROVIDER_IDS.includes(value)}var VALID_AUTH_METHOD_TYPES2,DEFAULT_AUTH_METHOD_PRECEDENCE,VALID_PROVIDER_IDS,AUTH_METHOD_ID_TO_PROVIDER_ID,VALID_AUTH_METHOD_IDS;var init_types2=__esm({"workers-registry/registry-launcher/src/auth/types.ts"(){"use strict";VALID_AUTH_METHOD_TYPES2=["oauth2","api-key"];DEFAULT_AUTH_METHOD_PRECEDENCE={methodPrecedence:["oauth2","api-key"],failFastOnUnsupported:true,failFastOnAmbiguous:true};VALID_PROVIDER_IDS=["github","google","cognito","azure","oidc"];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"};VALID_AUTH_METHOD_IDS=Object.keys(AUTH_METHOD_ID_TO_PROVIDER_ID)}});import{spawn as spawn2}from"node:child_process";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")}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 RoutingErrorCodes,AUTH_METHOD_ID_TO_PROVIDER,MAX_AUTH_METHODS,MAX_METHOD_ID_LENGTH,VALID_AUTH_METHOD_TYPES3,AGENT_AUTH_TIMEOUT_MS,TERMINAL_AUTH_TIMEOUT_MS,QUEUED_REQUEST_TIMEOUT_MS,MessageRouter;var init_message_router=__esm({"workers-registry/registry-launcher/src/router/message-router.ts"(){"use strict";init_registry();init_api_keys();init_types2();RoutingErrorCodes={MISSING_AGENT_ID:-32600,AGENT_NOT_FOUND:-32001,PLATFORM_NOT_SUPPORTED:-32002,SPAWN_FAILED:-32003,AUTH_REQUIRED:-32004};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"};MAX_AUTH_METHODS=50;MAX_METHOD_ID_LENGTH=128;VALID_AUTH_METHOD_TYPES3=["oauth2","agent","terminal","api-key"];AGENT_AUTH_TIMEOUT_MS=5*60*1e3;TERMINAL_AUTH_TIMEOUT_MS=10*60*1e3;QUEUED_REQUEST_TIMEOUT_MS=5*60*1e3;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&&currentAuthState!=="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}`)}}}});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)}var LOG_CONTEXT;var init_log=__esm({"workers-registry/registry-launcher/src/log.ts"(){"use strict";LOG_CONTEXT="registry-launcher"}});import*as readline from"readline";var PROVIDER_INFO,TerminalAuthFlow;var init_terminal_auth_flow=__esm({"workers-registry/registry-launcher/src/auth/flows/terminal-auth-flow.ts"(){"use strict";init_types2();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}];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,AgentRuntimeManager;var init_manager=__esm({"workers-registry/registry-launcher/src/runtime/manager.ts"(){"use strict";init_agent_runtime();DEFAULT_SHUTDOWN_TIMEOUT_MS=5e3;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)}}}});function isValidAuthMethodType(value){return typeof value==="string"&&VALID_AUTH_METHOD_TYPES2.includes(value)}function isValidProviderId(value){return typeof value==="string"&&VALID_PROVIDER_IDS.includes(value)}var VALID_AUTH_METHOD_TYPES2,DEFAULT_AUTH_METHOD_PRECEDENCE,VALID_PROVIDER_IDS,AUTH_METHOD_ID_TO_PROVIDER_ID,VALID_AUTH_METHOD_IDS;var init_types2=__esm({"workers-registry/registry-launcher/src/auth/types.ts"(){"use strict";VALID_AUTH_METHOD_TYPES2=["oauth2","api-key"];DEFAULT_AUTH_METHOD_PRECEDENCE={methodPrecedence:["oauth2","api-key"],failFastOnUnsupported:true,failFastOnAmbiguous:true};VALID_PROVIDER_IDS=["github","google","cognito","azure","oidc"];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"};VALID_AUTH_METHOD_IDS=Object.keys(AUTH_METHOD_ID_TO_PROVIDER_ID)}});import{spawn as spawn2}from"node:child_process";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")}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 RoutingErrorCodes,AUTH_METHOD_ID_TO_PROVIDER,MAX_AUTH_METHODS,MAX_METHOD_ID_LENGTH,VALID_AUTH_METHOD_TYPES3,AGENT_AUTH_TIMEOUT_MS,TERMINAL_AUTH_TIMEOUT_MS,QUEUED_REQUEST_TIMEOUT_MS,MessageRouter;var init_message_router=__esm({"workers-registry/registry-launcher/src/router/message-router.ts"(){"use strict";init_registry();init_api_keys();init_types2();RoutingErrorCodes={MISSING_AGENT_ID:-32600,AGENT_NOT_FOUND:-32001,PLATFORM_NOT_SUPPORTED:-32002,SPAWN_FAILED:-32003,AUTH_REQUIRED:-32004};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"};MAX_AUTH_METHODS=50;MAX_METHOD_ID_LENGTH=128;VALID_AUTH_METHOD_TYPES3=["oauth2","agent","terminal","api-key"];AGENT_AUTH_TIMEOUT_MS=5*60*1e3;TERMINAL_AUTH_TIMEOUT_MS=10*60*1e3;QUEUED_REQUEST_TIMEOUT_MS=5*60*1e3;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&&currentAuthState!=="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}`)}}}});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)}var LOG_CONTEXT;var init_log=__esm({"workers-registry/registry-launcher/src/log.ts"(){"use strict";LOG_CONTEXT="registry-launcher"}});import*as readline from"readline";var PROVIDER_INFO,TerminalAuthFlow;var init_terminal_auth_flow=__esm({"workers-registry/registry-launcher/src/auth/flows/terminal-auth-flow.ts"(){"use strict";init_types2();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}];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(`