@axiom-lattice/cli-a2a 0.1.5 → 0.1.6

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.
Files changed (65) hide show
  1. package/.turbo/turbo-build.log +34 -32
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +85 -2
  4. package/__tests__/opencode-executor.test.ts +631 -31
  5. package/__tests__/session-store-path.test.ts +40 -0
  6. package/dist/{chunk-NQIDRU47.mjs → chunk-54SKDK3D.mjs} +78 -32
  7. package/dist/chunk-54SKDK3D.mjs.map +1 -0
  8. package/dist/chunk-BSNQOP2W.mjs +350 -0
  9. package/dist/chunk-BSNQOP2W.mjs.map +1 -0
  10. package/dist/chunk-DRFFQJII.mjs +195 -0
  11. package/dist/chunk-DRFFQJII.mjs.map +1 -0
  12. package/dist/chunk-URJDRXJW.mjs +378 -0
  13. package/dist/chunk-URJDRXJW.mjs.map +1 -0
  14. package/dist/{chunk-G7AGL2QA.mjs → chunk-WZB7FBSX.mjs} +23 -5
  15. package/dist/chunk-WZB7FBSX.mjs.map +1 -0
  16. package/dist/{chunk-LXL47XMZ.mjs → chunk-YGUPSPZO.mjs} +9 -1
  17. package/dist/chunk-YGUPSPZO.mjs.map +1 -0
  18. package/dist/{chunk-35NFMGMS.mjs → chunk-ZP3JNJQJ.mjs} +3 -3
  19. package/dist/chunk-ZP3JNJQJ.mjs.map +1 -0
  20. package/dist/cli.js +769 -156
  21. package/dist/cli.js.map +1 -1
  22. package/dist/cli.mjs +7 -6
  23. package/dist/cli.mjs.map +1 -1
  24. package/dist/executor-LLE5VEFJ.mjs +12 -0
  25. package/dist/executor-LO7P3KUW.mjs +12 -0
  26. package/dist/{executor-RVBGAWUF.mjs → executor-OOLGGXHS.mjs} +4 -3
  27. package/dist/{executors-QIIKBUMJ.mjs → executors-AQHOPGSR.mjs} +2 -2
  28. package/dist/index.d.mts +92 -21
  29. package/dist/index.d.ts +92 -21
  30. package/dist/index.js +731 -123
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +15 -7
  33. package/package.json +10 -3
  34. package/runtime/cli-path.cjs +3 -0
  35. package/runtime/cli-path.d.ts +1 -0
  36. package/runtime/cli-path.mjs +5 -0
  37. package/src/config/defaults.ts +3 -1
  38. package/src/config/types.ts +8 -3
  39. package/src/executors/claude/client.ts +44 -14
  40. package/src/executors/claude/executor.ts +65 -30
  41. package/src/executors/codex/client.ts +239 -16
  42. package/src/executors/codex/executor.ts +70 -37
  43. package/src/executors/events.ts +15 -1
  44. package/src/executors/index.ts +13 -6
  45. package/src/executors/opencode/client.ts +192 -18
  46. package/src/executors/opencode/executor.ts +65 -30
  47. package/src/index.ts +8 -0
  48. package/src/local-state.ts +53 -0
  49. package/src/server/agent-card.ts +1 -0
  50. package/src/server/index.ts +22 -7
  51. package/src/session-store.ts +262 -0
  52. package/dist/chunk-35NFMGMS.mjs.map +0 -1
  53. package/dist/chunk-G7AGL2QA.mjs.map +0 -1
  54. package/dist/chunk-LXL47XMZ.mjs.map +0 -1
  55. package/dist/chunk-NQIDRU47.mjs.map +0 -1
  56. package/dist/chunk-VSZ3DACI.mjs +0 -179
  57. package/dist/chunk-VSZ3DACI.mjs.map +0 -1
  58. package/dist/chunk-WNCDOYZS.mjs +0 -187
  59. package/dist/chunk-WNCDOYZS.mjs.map +0 -1
  60. package/dist/executor-OWPVDUXH.mjs +0 -11
  61. package/dist/executor-XWHWUVQ3.mjs +0 -11
  62. /package/dist/{executor-OWPVDUXH.mjs.map → executor-LLE5VEFJ.mjs.map} +0 -0
  63. /package/dist/{executor-RVBGAWUF.mjs.map → executor-LO7P3KUW.mjs.map} +0 -0
  64. /package/dist/{executor-XWHWUVQ3.mjs.map → executor-OOLGGXHS.mjs.map} +0 -0
  65. /package/dist/{executors-QIIKBUMJ.mjs.map → executors-AQHOPGSR.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/executors/codex/client.ts","../src/executors/codex/executor.ts"],"sourcesContent":["/**\n * Codex CLI client wrapper.\n *\n * Spawns the OpenAI Codex CLI as a child process, sends prompts via stdin,\n * captures stdout as the response. Supports session persistence: on first\n * call the thread_id is extracted from JSONL output, and subsequent calls\n * use `codex exec resume <sessionId>` for multi-turn continuation.\n */\n\nimport { spawn } from 'node:child_process';\nimport { logger } from '../../logger.js';\n\nconst log = logger.child('codex:client');\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface CodexClientConfig {\n /** Path to the codex binary (default: \"codex\") */\n cliPath: string;\n /** Working directory for the codex process */\n workdir: string;\n /** Model identifier (e.g. \"gpt-4o\") — passed as CODELLM env or --model flag */\n model?: string;\n /** OpenAI API key — passed as OPENAI_API_KEY env */\n apiKey?: string;\n /** Timeout in ms (default: 300_000 = 5 min) */\n timeout?: number;\n}\n\nexport interface CodexExecuteResult {\n text: string;\n sessionId: string;\n}\n\n// ─── Client ─────────────────────────────────────────────────────────────────\n\nexport class CodexClient {\n private currentChild: ReturnType<typeof spawn> | null = null;\n\n constructor(private config: CodexClientConfig) {}\n\n abort(): void {\n if (this.currentChild) {\n this.currentChild.kill('SIGTERM');\n setTimeout(() => {\n if (this.currentChild?.exitCode === null) {\n this.currentChild.kill('SIGKILL');\n }\n }, 5000);\n this.currentChild = null;\n }\n }\n\n /**\n * Execute a prompt via the Codex CLI.\n *\n * @param prompt - The user prompt text.\n * @param sessionId - If provided, resumes an existing session.\n * Otherwise creates a new session and extracts the thread_id from JSONL.\n * @param workingDirectory - Optional per-request working directory override.\n */\n async execute(prompt: string, sessionId?: string, workingDirectory?: string): Promise<CodexExecuteResult> {\n if (sessionId) {\n return this.executeResume(prompt, sessionId, workingDirectory);\n }\n return this.executeNew(prompt, workingDirectory);\n }\n\n private resolveWorkdir(override?: string): string {\n return override || this.config.workdir || process.cwd();\n }\n\n // ── New session (first turn) ──────────────────────────────────────────\n\n private async executeNew(prompt: string, workingDirectory?: string): Promise<CodexExecuteResult> {\n const cliPath = this.config.cliPath || 'codex';\n const timeout = this.config.timeout ?? 300_000;\n const MAX_PROMPT = 100_000;\n\n if (prompt.length > MAX_PROMPT) {\n throw new Error(`Prompt too large (${prompt.length} chars, max ${MAX_PROMPT}). Split into smaller messages.`);\n }\n\n const env: Record<string, string> = {\n PATH: process.env.PATH ?? '',\n HOME: process.env.HOME ?? '',\n };\n for (const key of ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'http_proxy', 'https_proxy', 'no_proxy']) {\n if (process.env[key]) env[key] = process.env[key];\n }\n if (this.config.apiKey) {\n env['OPENAI_API_KEY'] = this.config.apiKey;\n }\n\n const args: string[] = ['exec', '--json'];\n if (this.config.model) {\n args.push('--model', this.config.model);\n }\n args.push(\n '--dangerously-bypass-approvals-and-sandbox',\n '--skip-git-repo-check',\n prompt,\n );\n\n const workdir = this.resolveWorkdir(workingDirectory);\n log.info('Spawning codex (new session)', { cliPath, workdir, model: this.config.model });\n\n return new Promise<CodexExecuteResult>((resolve, reject) => {\n const child = spawn(cliPath, args, {\n cwd: workdir,\n env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n this.currentChild = child;\n\n let stdout = '';\n let stderr = '';\n const MAX_OUTPUT = 10_000_000;\n\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n const forceTimer = setTimeout(() => {\n if (child.exitCode === null) child.kill('SIGKILL');\n }, 5000);\n child.on('close', () => clearTimeout(forceTimer));\n reject(new Error(`Codex execution timed out after ${timeout}ms`));\n }, timeout);\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n if (stdout.length > MAX_OUTPUT) {\n child.kill('SIGTERM');\n setTimeout(() => { if (child.exitCode === null) child.kill('SIGKILL'); }, 5000);\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n log.debug('Codex stderr', { text: chunk.toString().trim() });\n });\n\n child.on('close', (code) => {\n clearTimeout(timer);\n this.currentChild = null;\n\n if (code !== 0) {\n const errMsg = stderr.trim() || stdout.trim() || `Codex exited with code ${code}`;\n log.warn('Codex non-zero exit', { code, stderr: errMsg });\n reject(new Error(errMsg));\n return;\n }\n\n try {\n const { text, sessionId } = this.parseJsonl(stdout);\n resolve({ text, sessionId });\n } catch (err) {\n reject(new Error(`Failed to parse Codex JSONL output: ${(err as Error).message}`));\n }\n });\n\n child.on('error', (err) => {\n clearTimeout(timer);\n log.error('Codex spawn failed', { error: err.message });\n reject(new Error(`Failed to start codex: ${err.message}. Is it installed? (npm i -g @openai/codex)`));\n });\n });\n }\n\n // ── Resume session (subsequent turns) ─────────────────────────────────\n\n private async executeResume(prompt: string, sessionId: string, workingDirectory?: string): Promise<CodexExecuteResult> {\n const cliPath = this.config.cliPath || 'codex';\n const timeout = this.config.timeout ?? 300_000;\n const MAX_PROMPT = 100_000;\n\n if (prompt.length > MAX_PROMPT) {\n throw new Error(`Prompt too large (${prompt.length} chars, max ${MAX_PROMPT}). Split into smaller messages.`);\n }\n\n const env: Record<string, string> = {\n PATH: process.env.PATH ?? '',\n HOME: process.env.HOME ?? '',\n };\n for (const key of ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'http_proxy', 'https_proxy', 'no_proxy']) {\n if (process.env[key]) env[key] = process.env[key];\n }\n if (this.config.apiKey) {\n env['OPENAI_API_KEY'] = this.config.apiKey;\n }\n\n const args: string[] = ['exec', 'resume', sessionId];\n if (this.config.model) {\n args.push('--model', this.config.model);\n }\n args.push(\n '--dangerously-bypass-approvals-and-sandbox',\n '--skip-git-repo-check',\n prompt,\n );\n\n const workdir = this.resolveWorkdir(workingDirectory);\n log.info('Spawning codex (resume)', { sessionId, workdir });\n\n return new Promise<CodexExecuteResult>((resolve, reject) => {\n const child = spawn(cliPath, args, {\n cwd: workdir,\n env,\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n\n this.currentChild = child;\n\n let stdout = '';\n let stderr = '';\n const MAX_OUTPUT = 10_000_000;\n\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n const forceTimer = setTimeout(() => {\n if (child.exitCode === null) child.kill('SIGKILL');\n }, 5000);\n child.on('close', () => clearTimeout(forceTimer));\n reject(new Error(`Codex execution timed out after ${timeout}ms`));\n }, timeout);\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n if (stdout.length > MAX_OUTPUT) {\n child.kill('SIGTERM');\n setTimeout(() => { if (child.exitCode === null) child.kill('SIGKILL'); }, 5000);\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n log.debug('Codex stderr', { text: chunk.toString().trim() });\n });\n\n child.on('close', (code) => {\n clearTimeout(timer);\n this.currentChild = null;\n\n if (code !== 0) {\n const errMsg = stderr.trim() || stdout.trim() || `Codex exited with code ${code}`;\n log.warn('Codex non-zero exit', { code, stderr: errMsg });\n reject(new Error(errMsg));\n return;\n }\n\n // Resume output: the CLI prints session metadata header + agent response.\n // Strip the header lines (first 2+ lines before the actual output).\n // The header looks like:\n // OpenAI Codex v0.142.0\n // --------\n // workdir: ...\n // ...\n // --------\n // user\n // ...\n // codex\n // <actual response>\n const text = this.extractResumeText(stdout);\n resolve({ text, sessionId });\n });\n\n child.on('error', (err) => {\n clearTimeout(timer);\n log.error('Codex spawn failed', { error: err.message });\n reject(new Error(`Failed to start codex: ${err.message}. Is it installed? (npm i -g @openai/codex)`));\n });\n });\n }\n\n // ── Parsers ───────────────────────────────────────────────────────────\n\n /**\n * Parse JSONL output to extract session thread_id and agent response text.\n */\n private parseJsonl(stdout: string): { text: string; sessionId: string } {\n const lines = stdout.split('\\n').filter((l) => l.trim());\n let sessionId = '';\n const textParts: string[] = [];\n\n for (const line of lines) {\n let event: Record<string, unknown>;\n try {\n event = JSON.parse(line);\n } catch {\n continue;\n }\n\n // Extract thread_id from thread.started event\n if (event.type === 'thread.started' && event.thread_id) {\n sessionId = event.thread_id as string;\n }\n\n // Extract text from agent messages in item.completed events\n if (event.type === 'item.completed') {\n const item = event.item as Record<string, unknown> | undefined;\n if (item && item.type === 'agent_message' && item.text) {\n textParts.push(item.text as string);\n }\n }\n }\n\n if (!sessionId) {\n throw new Error('No thread_id found in Codex JSONL output');\n }\n\n return {\n text: textParts.join('\\n').trim() || 'No response from Codex.',\n sessionId,\n };\n }\n\n /**\n * Extract the agent response text from the resume mode output.\n *\n * The resume output includes a CLI header followed by the conversation.\n * We extract everything after the last \"codex\" marker line as the\n * latest agent response.\n */\n private extractResumeText(stdout: string): string {\n const lines = stdout.split('\\n');\n\n // Find the separator: the last \"codex\" line marks the start of the response\n let responseStart = -1;\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].trim() === 'codex') {\n responseStart = i;\n }\n }\n\n if (responseStart >= 0 && responseStart + 1 < lines.length) {\n return lines.slice(responseStart + 1).join('\\n').trim();\n }\n\n // Fallback: strip known header lines\n let skipHeader = true;\n const resultLines: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (skipHeader) {\n if (trimmed === '--------' || trimmed === 'codex') {\n skipHeader = false;\n }\n continue;\n }\n if (trimmed === 'user' || trimmed === 'codex') {\n continue;\n }\n if (trimmed.startsWith('tokens used')) {\n if (resultLines.length > 0) resultLines.pop();\n break;\n }\n resultLines.push(line);\n }\n\n return resultLines.join('\\n').trim() || stdout.trim();\n }\n}\n","/**\n * Codex A2A Executor\n *\n * Bridges the local Codex CLI to the A2A protocol. Spawns Codex as a\n * child process for each request. Supports multi-turn conversation via\n * contextId → sessionId binding through SessionBindingStore.\n */\n\nimport type { A2AExecutor } from '../index.js';\nimport type { RequestContext, ExecutionEventBus } from '@a2a-js/sdk/server';\n\nimport type { AgentConfig } from '../../config/types.js';\nimport type { SessionBindingStore } from '../../session-store.js';\nimport { generateContextId } from '../../session-store.js';\nimport { logger } from '../../logger.js';\nimport { CodexClient } from './client.js';\nimport {\n publishTask,\n publishStatus,\n publishFinalArtifact,\n extractText,\n} from '../events.js';\n\nconst log = logger.child('codex:executor');\n\n// ─── Executor ───────────────────────────────────────────────────────────────\n\nexport class CodexExecutor implements A2AExecutor {\n private config: Required<AgentConfig>;\n private client: CodexClient | null = null;\n private initialized = false;\n private sessionStore: SessionBindingStore;\n\n constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore) {\n this.config = config;\n this.sessionStore = sessionStore;\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n const cx = this.config.codex;\n this.client = new CodexClient({\n cliPath: cx.cliPath!,\n workdir: cx.workdir!,\n model: cx.model || undefined,\n apiKey: cx.apiKey || undefined,\n timeout: this.config.timeouts.prompt ?? 600_000,\n });\n\n this.initialized = true;\n log.info('Executor initialized', { cliPath: cx.cliPath, workdir: cx.workdir });\n }\n\n async shutdown(): Promise<void> {\n this.client = null;\n this.initialized = false;\n log.info('Executor shut down');\n }\n\n async execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void> {\n const { taskId, userMessage } = ctx;\n await this.initialize();\n\n const reuseByContext = this.config.session?.reuseByContext ?? true;\n\n // Resolve contextId: use provided one or generate new\n let contextId = ctx.contextId;\n if (!contextId) {\n contextId = generateContextId();\n log.info('Generated new contextId', { contextId, taskId });\n }\n\n // Look up existing session binding\n const binding = reuseByContext\n ? this.sessionStore.get(contextId, 'codex')\n : null;\n\n const sessionId = binding?.sessionId;\n\n try {\n // Register task (always include contextId so client can track)\n const existingTask = ctx.task;\n if (!existingTask) {\n publishTask(bus, taskId, contextId);\n publishStatus(bus, taskId, contextId, 'submitted');\n }\n\n publishStatus(bus, taskId, contextId, 'working');\n\n const promptText = extractText(userMessage);\n\n // Extract per-request workingDirectory from A2A message metadata\n const userMsg = userMessage as unknown as Record<string, unknown>;\n const workingDirectory = userMsg.metadata &&\n typeof userMsg.metadata === 'object'\n ? (userMsg.metadata as Record<string, unknown>).workingDirectory as string | undefined\n : undefined;\n\n log.info('Sending prompt to Codex', {\n taskId,\n contextId,\n sessionId: sessionId || '(new)',\n len: promptText.length,\n workingDirectory: workingDirectory || '(default)',\n });\n\n const result = await this.client!.execute(promptText, sessionId, workingDirectory);\n\n // Save or update session binding\n this.sessionStore.set({\n provider: 'codex',\n contextId,\n sessionId: result.sessionId,\n activeTaskId: undefined,\n activeTaskState: undefined,\n createdAt: binding?.createdAt ?? new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n expiresAt: new Date(Date.now() + (this.config.session?.ttl ?? 24 * 60 * 60 * 1000)).toISOString(),\n });\n\n // Finalize\n publishFinalArtifact(bus, taskId, contextId, result.text || 'No response from Codex.');\n publishStatus(bus, taskId, contextId, 'completed', undefined, true);\n bus.finished();\n log.info('Task completed', { taskId, contextId, sessionId: result.sessionId });\n\n } catch (error) {\n const msg = (error as Error).message ?? String(error);\n log.error('Execution failed', { taskId, contextId, error: msg });\n publishStatus(bus, taskId, contextId, 'failed', `Error: ${msg}`, true);\n bus.finished();\n }\n }\n\n async cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void> {\n log.info('Cancel requested for Codex task', { taskId });\n this.client?.abort();\n publishStatus(bus, taskId, '', 'canceled', 'Codex task cancelled', true);\n bus.finished();\n }\n}\n\n// ─── Factory ────────────────────────────────────────────────────────────────\n\nexport function createCodexExecutor(\n config: Required<AgentConfig>,\n sessionStore: SessionBindingStore,\n): A2AExecutor {\n return new CodexExecutor(config, sessionStore);\n}\n"],"mappings":"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","names":["log"]}
@@ -1,6 +1,10 @@
1
1
  import {
2
2
  createExecutor
3
- } from "./chunk-35NFMGMS.mjs";
3
+ } from "./chunk-ZP3JNJQJ.mjs";
4
+ import {
5
+ SessionBindingStore,
6
+ resolveSessionStorePath
7
+ } from "./chunk-DRFFQJII.mjs";
4
8
  import {
5
9
  logger
6
10
  } from "./chunk-VZEH3EPJ.mjs";
@@ -49,6 +53,8 @@ var DEFAULTS = Object.freeze({
49
53
  session: {
50
54
  titlePrefix: "A2A Session",
51
55
  reuseByContext: true,
56
+ persist: true,
57
+ storePath: "",
52
58
  ttl: 36e5,
53
59
  cleanupInterval: 3e5
54
60
  },
@@ -67,7 +73,7 @@ var DEFAULTS = Object.freeze({
67
73
  level: "info"
68
74
  },
69
75
  opencode: {
70
- baseUrl: "http://localhost:4096",
76
+ baseUrl: "",
71
77
  projectDirectory: "",
72
78
  model: "",
73
79
  agent: "",
@@ -195,7 +201,8 @@ function buildAgentCard(config) {
195
201
  skills,
196
202
  capabilities: {
197
203
  streaming: agentCard.streaming ?? true,
198
- pushNotifications: agentCard.pushNotifications ?? false
204
+ pushNotifications: agentCard.pushNotifications ?? false,
205
+ stateTransitionHistory: true
199
206
  },
200
207
  // Additional interfaces advertised to orchestrators
201
208
  additionalInterfaces: [
@@ -215,7 +222,17 @@ async function createA2AServer(config) {
215
222
  const hostname = srv.hostname ?? "0.0.0.0";
216
223
  const advertiseHost = srv.advertiseHost ?? "localhost";
217
224
  const advertiseProto = srv.advertiseProtocol ?? "http";
218
- const executor = createExecutor(config);
225
+ const sessionConf = config.session;
226
+ const sessionStore = new SessionBindingStore({
227
+ persist: sessionConf.persist ?? true,
228
+ storePath: resolveSessionStorePath({
229
+ configuredPath: sessionConf.storePath,
230
+ provider: config.provider,
231
+ port
232
+ }),
233
+ cleanupIntervalMs: sessionConf.cleanupInterval
234
+ });
235
+ const executor = createExecutor(config, sessionStore);
219
236
  await executor.initialize();
220
237
  const agentCard = buildAgentCard(config);
221
238
  const taskStore = new InMemoryTaskStore();
@@ -271,6 +288,7 @@ async function createA2AServer(config) {
271
288
  async shutdown() {
272
289
  httpServer.close();
273
290
  await executor.shutdown();
291
+ sessionStore.shutdown();
274
292
  log3.info("Server shut down");
275
293
  }
276
294
  };
@@ -281,4 +299,4 @@ export {
281
299
  resolveConfig,
282
300
  createA2AServer
283
301
  };
284
- //# sourceMappingURL=chunk-G7AGL2QA.mjs.map
302
+ //# sourceMappingURL=chunk-WZB7FBSX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/loader.ts","../src/config/defaults.ts","../src/server/index.ts","../src/server/agent-card.ts"],"sourcesContent":["/**\n * Config loader — reads JSON config files and resolves the final config\n * by merging layers: defaults ← config file ← env overrides ← CLI args.\n */\n\nimport { readFileSync, existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { resolveDefaults } from './defaults.js';\nimport type { AgentConfig } from './types.js';\nimport { logger } from '../logger.js';\n\nconst log = logger.child('config');\n\n/**\n * Read and parse a JSON config file.\n */\nexport function loadConfigFile(filePath: string): Partial<AgentConfig> {\n const absPath = resolve(filePath);\n if (!existsSync(absPath)) {\n throw new Error(`Config file not found: ${absPath}`);\n }\n try {\n const raw = readFileSync(absPath, 'utf-8');\n return JSON.parse(raw) as Partial<AgentConfig>;\n } catch (err) {\n const msg = err instanceof SyntaxError\n ? `Invalid JSON in config file: ${err.message}`\n : `Failed to read config file: ${(err as Error).message}`;\n throw new Error(msg);\n }\n}\n\n/**\n * Load env overrides for provider configs.\n */\nfunction loadEnvOverrides(): Partial<AgentConfig> {\n const overrides: Partial<AgentConfig> = {\n opencode: {},\n codex: {},\n claude: {},\n };\n\n // OpenCode\n if (process.env.OPENCODE_URL) overrides.opencode!.baseUrl = process.env.OPENCODE_URL;\n if (process.env.OPENCODE_DIRECTORY) overrides.opencode!.projectDirectory = process.env.OPENCODE_DIRECTORY;\n if (process.env.OPENCODE_MODEL) overrides.opencode!.model = process.env.OPENCODE_MODEL;\n if (process.env.OPENCODE_AGENT) overrides.opencode!.agent = process.env.OPENCODE_AGENT;\n if (process.env.OPENCODE_SYSTEM_PROMPT) overrides.opencode!.systemPrompt = process.env.OPENCODE_SYSTEM_PROMPT;\n\n // Codex\n if (process.env.OPENAI_API_KEY) overrides.codex!.apiKey = process.env.OPENAI_API_KEY;\n if (process.env.CODEX_MODEL) overrides.codex!.model = process.env.CODEX_MODEL;\n\n // Claude Code\n if (process.env.ANTHROPIC_API_KEY) overrides.claude!.apiKey = process.env.ANTHROPIC_API_KEY;\n if (process.env.CLAUDE_MODEL) overrides.claude!.model = process.env.CLAUDE_MODEL;\n\n return overrides;\n}\n\n/**\n * Resolve full config from defaults + file + env.\n */\nexport function resolveConfig(\n configPath?: string,\n cliOverrides?: Partial<AgentConfig>,\n): Required<AgentConfig> {\n // Layer 1: File\n let fileConfig: Partial<AgentConfig> = {};\n if (configPath) {\n fileConfig = loadConfigFile(configPath);\n log.info('Loaded config file', { path: configPath });\n }\n\n // Layer 2: Env\n const envOverrides = loadEnvOverrides();\n\n // Layer 3: CLI\n const cliConfig = cliOverrides ?? {};\n\n // Deep merge: defaults ← file ← env ← CLI\n // Start with a proper deep copy of merged defaults+file to avoid mutating the frozen defaults\n const cloned = structuredClone(resolveDefaults(fileConfig)) as Required<AgentConfig>;\n const base = cloned;\n\n // Then merge env overrides\n mergeOverrides(base, envOverrides);\n\n // Then merge CLI overrides\n mergeOverrides(base, cliConfig);\n\n // Populate configDir\n if (configPath) {\n base.configDir = dirname(resolve(configPath));\n }\n\n return base;\n}\n\nfunction mergeOverrides(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key of Object.keys(source)) {\n const srcVal = source[key];\n const tgtVal = target[key];\n if (\n srcVal !== undefined &&\n srcVal !== null &&\n typeof srcVal === 'object' &&\n !Array.isArray(srcVal) &&\n tgtVal !== undefined &&\n typeof tgtVal === 'object' &&\n !Array.isArray(tgtVal)\n ) {\n // Do not merge empty override objects\n if (Object.keys(srcVal as Record<string, unknown>).length > 0) {\n mergeOverrides(tgtVal as Record<string, unknown>, srcVal as Record<string, unknown>);\n }\n } else if (srcVal !== undefined && srcVal !== null) {\n target[key] = srcVal;\n }\n }\n}\n","/**\n * Default configuration values.\n *\n * Every field has a sensible default so the agent runs without a config file.\n */\n\nimport type { AgentConfig } from './types.js';\n\nfunction withDefaults<T extends Record<string, unknown>>(\n partial: Partial<T>,\n defaults: Required<T>,\n): Required<T> {\n const result = { ...defaults } as Record<string, unknown>;\n for (const key of Object.keys(partial) as Array<keyof T>) {\n const val = partial[key] as unknown;\n if (val !== undefined && val !== null) {\n if (\n typeof val === 'object' &&\n !Array.isArray(val) &&\n typeof defaults[key] === 'object' &&\n !Array.isArray(defaults[key])\n ) {\n result[key as string] = {\n ...(defaults[key] as Record<string, unknown>),\n ...(val as Record<string, unknown>),\n };\n } else {\n result[key as string] = val;\n }\n }\n }\n return result as unknown as Required<T>;\n}\n\ntype ResolvedConfig = Omit<Required<AgentConfig>, 'opencode' | 'codex' | 'claude' | 'configDir'> & {\n opencode: Required<Required<AgentConfig>['opencode']>;\n codex: Required<Required<AgentConfig>['codex']>;\n claude: Required<Required<AgentConfig>['claude']>;\n configDir: string | undefined;\n};\n\nconst DEFAULTS: Readonly<ResolvedConfig> = Object.freeze({\n provider: 'opencode' as const,\n agentCard: {\n name: 'CLI A2A Agent',\n description: 'A multi-provider A2A agent driven by local CLI coding tools.',\n protocolVersion: '0.3.0',\n version: '0.1.0',\n skills: [],\n defaultInputModes: ['text'],\n defaultOutputModes: ['text'],\n streaming: true,\n pushNotifications: false,\n },\n server: {\n port: 3000,\n hostname: '0.0.0.0',\n advertiseHost: 'localhost',\n advertiseProtocol: 'http',\n },\n session: {\n titlePrefix: 'A2A Session',\n reuseByContext: true,\n persist: true,\n storePath: '',\n ttl: 3_600_000,\n cleanupInterval: 300_000,\n },\n features: {\n autoApprovePermissions: true,\n autoAnswerQuestions: true,\n streamArtifactChunks: false,\n enablePollingFallback: true,\n },\n timeouts: {\n prompt: 600_000,\n pollingInterval: 2_000,\n healthCheck: 30_000,\n },\n logging: {\n level: 'info',\n },\n opencode: {\n baseUrl: '',\n projectDirectory: '',\n model: '',\n agent: '',\n systemPrompt: '',\n systemPromptMode: 'append',\n contextFile: 'context.md',\n contextPrompt: '',\n },\n codex: {\n cliPath: 'codex',\n workdir: process.cwd(),\n model: '',\n apiKey: '',\n },\n claude: {\n cliPath: 'claude',\n workdir: process.cwd(),\n model: '',\n apiKey: '',\n },\n configDir: undefined,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n} as any);\n\nexport function resolveDefaults(overrides: Partial<AgentConfig>): Required<AgentConfig> {\n return withDefaults(overrides, DEFAULTS) as unknown as Required<AgentConfig>;\n}\n","/**\n * A2A HTTP Server\n *\n * Creates an Express server with standard A2A endpoints:\n * - GET /.well-known/agent-card.json → Agent Card\n * - POST /a2a/jsonrpc → JSON-RPC transport\n * - POST /a2a/rest → REST transport\n * - GET /health → Health check\n */\n\nimport express, { type RequestHandler } from 'express';\nimport { AGENT_CARD_PATH } from '@a2a-js/sdk';\nimport { DefaultRequestHandler, InMemoryTaskStore } from '@a2a-js/sdk/server';\nimport {\n jsonRpcHandler,\n restHandler,\n UserBuilder,\n} from '@a2a-js/sdk/server/express';\n\nimport type { AgentConfig } from '../config/types.js';\nimport { buildAgentCard } from './agent-card.js';\nimport { createExecutor } from '../executors/index.js';\nimport { SessionBindingStore, resolveSessionStorePath } from '../session-store.js';\nimport { logger } from '../logger.js';\n\nconst log = logger.child('server');\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface ServerHandle {\n app: ReturnType<typeof express>;\n server: ReturnType<ReturnType<typeof express>['listen']>;\n shutdown(): Promise<void>;\n}\n\n// ─── Server Factory ─────────────────────────────────────────────────────────\n\nexport async function createA2AServer(config: Required<AgentConfig>): Promise<ServerHandle> {\n const srv = config.server;\n const port = srv.port ?? 3000;\n const hostname = srv.hostname ?? '0.0.0.0';\n const advertiseHost = srv.advertiseHost ?? 'localhost';\n const advertiseProto = srv.advertiseProtocol ?? 'http';\n\n const sessionConf = config.session;\n\n // 1. Session store\n const sessionStore = new SessionBindingStore({\n persist: sessionConf.persist ?? true,\n storePath: resolveSessionStorePath({\n configuredPath: sessionConf.storePath,\n provider: config.provider,\n port,\n }),\n cleanupIntervalMs: sessionConf.cleanupInterval,\n });\n\n // 2. Create executor\n const executor = createExecutor(config, sessionStore);\n await executor.initialize();\n\n // 3. Build agent card\n const agentCard = buildAgentCard(config);\n\n // 4. A2A request handler\n const taskStore = new InMemoryTaskStore();\n const requestHandler = new DefaultRequestHandler(agentCard, taskStore, executor);\n\n // 5. Express app\n const app = express();\n\n // A2A-Version header\n app.use((_req, res, next) => {\n res.setHeader('A2A-Version', '0.3');\n next();\n });\n\n // Health check\n app.get('/health', (_req, res) => {\n res.json({ status: 'healthy', agent: agentCard.name, provider: config.provider });\n });\n\n // Agent card — dynamic URL rewriting for reverse proxy support\n const serveAgentCard: RequestHandler = (req, res) => {\n const host = req.headers.host || `${advertiseHost}:${port}`;\n const proto = (req.headers['x-forwarded-proto'] as string) || advertiseProto;\n const dynamicBase = `${proto}://${host}`;\n res.json({\n ...agentCard,\n url: `${dynamicBase}/a2a/jsonrpc`,\n additionalInterfaces: [\n { transport: 'JSONRPC', url: `${dynamicBase}/a2a/jsonrpc` },\n { transport: 'REST', url: `${dynamicBase}/a2a/rest` },\n ],\n });\n };\n\n app.get(`/${AGENT_CARD_PATH}`, serveAgentCard);\n app.get('/.well-known/agent.json', serveAgentCard);\n app.get('/.well-known/agent-json', serveAgentCard);\n\n // A2A transport handlers\n app.use('/a2a/jsonrpc', jsonRpcHandler({ requestHandler, userBuilder: UserBuilder.noAuthentication }));\n app.use('/a2a/rest', restHandler({ requestHandler, userBuilder: UserBuilder.noAuthentication }));\n\n // 6. Start listening\n const httpServer = app.listen(port, hostname, () => {\n log.info('A2A server started', { bind: hostname, port, proto: advertiseProto });\n\n const banner = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n `║ CLI A2A Gateway — ${config.provider.padEnd(28)}║`,\n '╠══════════════════════════════════════════════════════════════╣',\n `║ Agent: ${agentCard.name}`,\n `║ Bind: ${hostname}:${port}`,\n `║ Agent Card: ${advertiseProto}://${advertiseHost}:${port}/${AGENT_CARD_PATH}`,\n `║ JSON-RPC: ${advertiseProto}://${advertiseHost}:${port}/a2a/jsonrpc`,\n `║ REST: ${advertiseProto}://${advertiseHost}:${port}/a2a/rest`,\n `║ Health: ${advertiseProto}://${advertiseHost}:${port}/health`,\n '╠══════════════════════════════════════════════════════════════╣',\n '║ Ready. Press Ctrl+C to stop. ║',\n '╚══════════════════════════════════════════════════════════════╝',\n ].join('\\n');\n console.log(banner);\n });\n\n // 7. Return handle\n return {\n app,\n server: httpServer,\n async shutdown() {\n httpServer.close();\n await executor.shutdown();\n sessionStore.shutdown();\n log.info('Server shut down');\n },\n };\n}\n","/**\n * Agent Card builder.\n *\n * Builds an A2A-compliant AgentCard from the resolved config.\n */\n\nimport type { AgentCard, AgentSkill } from '@a2a-js/sdk';\nimport type { AgentConfig } from '../config/types.js';\nimport { logger } from '../logger.js';\n\nconst log = logger.child('agent-card');\n\nexport function buildAgentCard(config: Required<AgentConfig>): AgentCard {\n const { agentCard, server } = config;\n const proto = server.advertiseProtocol ?? 'http';\n const host = server.advertiseHost ?? 'localhost';\n const port = server.port ?? 3000;\n const baseUrl = `${proto}://${host}:${port}`;\n\n const skills: AgentSkill[] = (agentCard.skills ?? []).map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n tags: s.tags ?? [],\n examples: s.examples ?? [],\n }));\n\n const card: AgentCard = {\n name: agentCard.name,\n description: agentCard.description,\n protocolVersion: agentCard.protocolVersion ?? '0.3.0',\n version: agentCard.version ?? '1.0.0',\n url: `${baseUrl}/a2a/jsonrpc`,\n // Default input/output modes (A2A v1.0 normalized names)\n defaultInputModes: (agentCard.defaultInputModes as Array<'text' | 'file' | 'image' | 'audio'>) ?? ['text'],\n defaultOutputModes: (agentCard.defaultOutputModes as Array<'text' | 'file' | 'image' | 'audio'>) ?? ['text'],\n skills,\n capabilities: {\n streaming: agentCard.streaming ?? true,\n pushNotifications: agentCard.pushNotifications ?? false,\n stateTransitionHistory: true,\n },\n // Additional interfaces advertised to orchestrators\n additionalInterfaces: [\n { transport: 'JSONRPC', url: `${baseUrl}/a2a/jsonrpc` },\n { transport: 'REST', url: `${baseUrl}/a2a/rest` },\n ],\n };\n\n log.info('Agent card built', { name: card.name, url: card.url, skills: card.skills?.length ?? 0 });\n return card;\n}\n"],"mappings":"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","names":["log","log"]}
@@ -1,5 +1,12 @@
1
1
  // src/executors/events.ts
2
2
  import { v4 as uuidv4 } from "uuid";
3
+ function extractText(message) {
4
+ return message.parts.filter((p) => {
5
+ const part = p;
6
+ const text = part.text;
7
+ return text !== void 0 && text !== null;
8
+ }).map((p) => p.text).join("\n");
9
+ }
3
10
  function publishTask(bus, taskId, contextId) {
4
11
  bus.publish({
5
12
  kind: "task",
@@ -36,8 +43,9 @@ function publishFinalArtifact(bus, taskId, contextId, text) {
36
43
  }
37
44
 
38
45
  export {
46
+ extractText,
39
47
  publishTask,
40
48
  publishStatus,
41
49
  publishFinalArtifact
42
50
  };
43
- //# sourceMappingURL=chunk-LXL47XMZ.mjs.map
51
+ //# sourceMappingURL=chunk-YGUPSPZO.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/executors/events.ts"],"sourcesContent":["/**\n * A2A event publishing helpers.\n *\n * Thin wrappers around ExecutionEventBus.publish() that construct\n * spec-compliant A2A task status and artifact update events.\n */\n\nimport { TaskState } from '@a2a-js/sdk';\nimport type { TaskStatusUpdateEvent, TaskArtifactUpdateEvent, Message as A2AMessage } from '@a2a-js/sdk';\nimport type { ExecutionEventBus } from '@a2a-js/sdk/server';\nimport { v4 as uuidv4 } from 'uuid';\n\n/**\n * Extract plain text content from an A2A message's parts.\n */\nexport function extractText(message: A2AMessage): string {\n return message.parts\n .filter((p) => {\n const part = p as unknown as Record<string, unknown>;\n const text = part.text as string | undefined;\n return text !== undefined && text !== null;\n })\n .map((p) => (p as unknown as { text: string }).text)\n .join('\\n');\n}\n\n/**\n * Register a task with the execution event bus before publishing any events.\n */\nexport function publishTask(bus: ExecutionEventBus, taskId: string, contextId: string): void {\n bus.publish({\n kind: 'task',\n taskId,\n contextId,\n } as unknown as TaskStatusUpdateEvent);\n}\n\n/**\n * Publish a task status update.\n */\nexport function publishStatus(\n bus: ExecutionEventBus,\n taskId: string,\n contextId: string,\n state: TaskState | string,\n messageText?: string,\n final?: boolean,\n): void {\n const event: TaskStatusUpdateEvent = {\n kind: 'task-status-update',\n taskId,\n contextId,\n status: {\n state: state as TaskState,\n message: messageText\n ? { role: 'agent', parts: [{ kind: 'text', text: messageText }] }\n : undefined,\n },\n final: final ?? false,\n } as unknown as TaskStatusUpdateEvent;\n bus.publish(event);\n}\n\n/**\n * Publish a complete artifact (non-streaming).\n */\nexport function publishFinalArtifact(\n bus: ExecutionEventBus,\n taskId: string,\n contextId: string,\n text: string,\n): void {\n const artifactId = uuidv4();\n const event: TaskArtifactUpdateEvent = {\n kind: 'task-artifact-update',\n taskId,\n contextId,\n artifact: {\n artifactId,\n parts: [{ kind: 'text', text }],\n },\n lastChunk: true,\n } as unknown as TaskArtifactUpdateEvent;\n bus.publish(event);\n}\n\n/**\n * Publish a streaming artifact chunk.\n */\nexport function publishStreamingChunk(\n bus: ExecutionEventBus,\n taskId: string,\n contextId: string,\n artifactId: string,\n chunkText: string,\n): void {\n const event: TaskArtifactUpdateEvent = {\n kind: 'task-artifact-update',\n taskId,\n contextId,\n artifact: {\n artifactId,\n parts: [{ kind: 'text', text: chunkText }],\n },\n lastChunk: false,\n } as unknown as TaskArtifactUpdateEvent;\n bus.publish(event);\n}\n\n/**\n * Publish the final streaming chunk with full accumulated text.\n */\nexport function publishLastChunkMarker(\n bus: ExecutionEventBus,\n taskId: string,\n contextId: string,\n artifactId: string,\n fullText: string,\n): void {\n const event: TaskArtifactUpdateEvent = {\n kind: 'task-artifact-update',\n taskId,\n contextId,\n artifact: {\n artifactId,\n parts: [{ kind: 'text', text: fullText }],\n },\n lastChunk: true,\n } as unknown as TaskArtifactUpdateEvent;\n bus.publish(event);\n}\n"],"mappings":";AAUA,SAAS,MAAM,cAAc;AAKtB,SAAS,YAAY,SAA6B;AACvD,SAAO,QAAQ,MACZ,OAAO,CAAC,MAAM;AACb,UAAM,OAAO;AACb,UAAM,OAAO,KAAK;AAClB,WAAO,SAAS,UAAa,SAAS;AAAA,EACxC,CAAC,EACA,IAAI,CAAC,MAAO,EAAkC,IAAI,EAClD,KAAK,IAAI;AACd;AAKO,SAAS,YAAY,KAAwB,QAAgB,WAAyB;AAC3F,MAAI,QAAQ;AAAA,IACV,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,CAAqC;AACvC;AAKO,SAAS,cACd,KACA,QACA,WACA,OACA,aACA,OACM;AACN,QAAM,QAA+B;AAAA,IACnC,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,MACA,SAAS,cACL,EAAE,MAAM,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,YAAY,CAAC,EAAE,IAC9D;AAAA,IACN;AAAA,IACA,OAAO,SAAS;AAAA,EAClB;AACA,MAAI,QAAQ,KAAK;AACnB;AAKO,SAAS,qBACd,KACA,QACA,WACA,MACM;AACN,QAAM,aAAa,OAAO;AAC1B,QAAM,QAAiC;AAAA,IACrC,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU;AAAA,MACR;AAAA,MACA,OAAO,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,IAChC;AAAA,IACA,WAAW;AAAA,EACb;AACA,MAAI,QAAQ,KAAK;AACnB;","names":[]}
@@ -8,13 +8,13 @@ function registerExecutor(provider, factory) {
8
8
  function getExecutor(provider) {
9
9
  return registry.get(provider);
10
10
  }
11
- function createExecutor(config) {
11
+ function createExecutor(config, sessionStore) {
12
12
  const factory = registry.get(config.provider);
13
13
  if (!factory) {
14
14
  const available = Array.from(registry.keys()).join(", ");
15
15
  throw new Error(`Unknown provider: ${config.provider}. Available: ${available}`);
16
16
  }
17
- return factory(config);
17
+ return factory(config, sessionStore);
18
18
  }
19
19
 
20
20
  export {
@@ -24,4 +24,4 @@ export {
24
24
  TaskState,
25
25
  v4
26
26
  };
27
- //# sourceMappingURL=chunk-35NFMGMS.mjs.map
27
+ //# sourceMappingURL=chunk-ZP3JNJQJ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/executors/index.ts"],"sourcesContent":["/**\n * Executor types and common interfaces for CLI A2A providers.\n *\n * Each provider (OpenCode, Codex, Claude) implements its own executor\n * conforming to the A2AExecutor interface which extends the SDK's\n * AgentExecutor with lifecycle methods (initialize, shutdown).\n */\n\nimport type { AgentExecutor } from '@a2a-js/sdk/server';\nimport type { SessionBindingStore } from '../session-store.js';\nimport type { AgentConfig, ProviderType } from '../config/types.js';\n\n/**\n * Extended executor interface with lifecycle methods.\n *\n * The base AgentExecutor from @a2a-js/sdk only defines execute() and\n * cancelTask(). We add initialize() for server setup and shutdown()\n * for graceful cleanup.\n */\nexport interface A2AExecutor extends AgentExecutor {\n initialize(): Promise<void>;\n shutdown(): Promise<void>;\n}\n\nexport type { AgentExecutor, RequestContext, ExecutionEventBus } from '@a2a-js/sdk/server';\nexport { TaskState } from '@a2a-js/sdk';\nexport { v4 as uuidv4 } from 'uuid';\n\n/**\n * Factory function type: given resolved config and a session store,\n * produce an executor.\n */\nexport type ExecutorFactory = (\n config: Required<AgentConfig>,\n sessionStore: SessionBindingStore,\n) => A2AExecutor;\n\n/**\n * Map provider type to executor factory.\n */\nconst registry = new Map<ProviderType, ExecutorFactory>();\n\nexport function registerExecutor(provider: ProviderType, factory: ExecutorFactory): void {\n registry.set(provider, factory);\n}\n\nexport function getExecutor(provider: ProviderType): ExecutorFactory | undefined {\n return registry.get(provider);\n}\n\nexport function createExecutor(\n config: Required<AgentConfig>,\n sessionStore: SessionBindingStore,\n): A2AExecutor {\n const factory = registry.get(config.provider);\n if (!factory) {\n const available = Array.from(registry.keys()).join(', ');\n throw new Error(`Unknown provider: ${config.provider}. Available: ${available}`);\n }\n return factory(config, sessionStore);\n}\n"],"mappings":";AAyBA,SAAS,iBAAiB;AAC1B,SAAe,UAAc;AAc7B,IAAM,WAAW,oBAAI,IAAmC;AAEjD,SAAS,iBAAiB,UAAwB,SAAgC;AACvF,WAAS,IAAI,UAAU,OAAO;AAChC;AAEO,SAAS,YAAY,UAAqD;AAC/E,SAAO,SAAS,IAAI,QAAQ;AAC9B;AAEO,SAAS,eACd,QACA,cACa;AACb,QAAM,UAAU,SAAS,IAAI,OAAO,QAAQ;AAC5C,MAAI,CAAC,SAAS;AACZ,UAAM,YAAY,MAAM,KAAK,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI;AACvD,UAAM,IAAI,MAAM,qBAAqB,OAAO,QAAQ,gBAAgB,SAAS,EAAE;AAAA,EACjF;AACA,SAAO,QAAQ,QAAQ,YAAY;AACrC;","names":[]}