@axiom-lattice/cli-a2a 0.1.4 → 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 +26 -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 +11 -4
  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
package/dist/cli.mjs CHANGED
@@ -2,8 +2,9 @@
2
2
  import {
3
3
  createA2AServer,
4
4
  resolveConfig
5
- } from "./chunk-G7AGL2QA.mjs";
6
- import "./chunk-35NFMGMS.mjs";
5
+ } from "./chunk-WZB7FBSX.mjs";
6
+ import "./chunk-ZP3JNJQJ.mjs";
7
+ import "./chunk-DRFFQJII.mjs";
7
8
  import {
8
9
  logger
9
10
  } from "./chunk-VZEH3EPJ.mjs";
@@ -229,10 +230,10 @@ async function main() {
229
230
  agent: config.agentCard.name,
230
231
  port: config.server?.port
231
232
  });
232
- const { registerExecutor } = await import("./executors-QIIKBUMJ.mjs");
233
- const { createOpenCodeExecutor } = await import("./executor-RVBGAWUF.mjs");
234
- const { createCodexExecutor } = await import("./executor-XWHWUVQ3.mjs");
235
- const { createClaudeExecutor } = await import("./executor-OWPVDUXH.mjs");
233
+ const { registerExecutor } = await import("./executors-AQHOPGSR.mjs");
234
+ const { createOpenCodeExecutor } = await import("./executor-OOLGGXHS.mjs");
235
+ const { createCodexExecutor } = await import("./executor-LLE5VEFJ.mjs");
236
+ const { createClaudeExecutor } = await import("./executor-LO7P3KUW.mjs");
236
237
  registerExecutor("opencode", createOpenCodeExecutor);
237
238
  registerExecutor("codex", createCodexExecutor);
238
239
  registerExecutor("claude", createClaudeExecutor);
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI A2A Gateway — Entry Point\n *\n * Usage:\n * npx @axiom-lattice/cli-a2a --provider opencode --config agents/example.json\n * npx @axiom-lattice/cli-a2a --provider opencode --port 3000 --opencode-url http://localhost:4096\n *\n * Run with --help for full usage.\n */\n\nimport { parseArgs } from 'node:util';\nimport { dirname, resolve } from 'node:path';\nimport { resolveConfig } from './config/loader.js';\nimport type { AgentConfig, ProviderType } from './config/types.js';\nimport { createA2AServer } from './server/index.js';\nimport { logger, LogLevel } from './logger.js';\n\nconst log = logger.child('cli');\n\n// ─── Version ────────────────────────────────────────────────────────────────\n\nconst PKG_VERSION = '0.1.0';\n\n// ─── Usage ──────────────────────────────────────────────────────────────────\n\nfunction printUsage(): void {\n console.log(`\nUsage: cli-a2a [options]\n\nOptions:\n --provider <name> Provider: opencode | codex | claude\n --config, -c <path> Path to agent JSON config file\n --port, -p <number> A2A server port (default: 3000)\n --hostname <addr> Bind address (default: 0.0.0.0)\n --advertise-host <host> Hostname for agent card URLs\n --agent-name <name> Agent display name\n --agent-description <desc> Agent description\n --log-level <level> debug | info | warn | error (default: info)\n\nGateway Registration:\n --register-url <url> Gateway URL to register this agent with\n --register-key <key> API key for gateway authentication\n --unregister-on-shutdown Remove agent from gateway on exit\n\nBridge (NAT traversal):\n --bridge-url <url> Gateway WebSocket bridge (ws://gateway:8080/api/a2a/bridge)\n --bridge-key <key> API key for bridge authentication\n\nOpenCode Options:\n --opencode-url <url> OpenCode server URL (default: http://localhost:4096)\n --directory, -d <path> Project directory\n --model, -m <provider/model> LLM model (e.g. anthropic/claude-sonnet-4)\n --agent <name> OpenCode agent preset\n\nCodex Options:\n --codex-model <model> Codex model ID\n --codex-api-key <key> OpenAI API key\n\nClaude Options:\n --claude-model <model> Claude Code model ID\n --claude-api-key <key> Anthropic API key\n\n --help, -h Show this help\n --version, -v Show version\n\nExamples:\n npx @axiom-lattice/cli-a2a --provider opencode\n npx @axiom-lattice/cli-a2a --provider opencode --port 3001 --opencode-url http://localhost:4096\n npx @axiom-lattice/cli-a2a --config ./my-agent.json\n npx @axiom-lattice/cli-a2a --provider opencode --model anthropic/claude-sonnet-4\n npx @axiom-lattice/cli-a2a --provider opencode --register-url http://gateway:8080 --register-key sk-xxx --unregister-on-shutdown\n npx @axiom-lattice/cli-a2a --provider opencode --bridge-url ws://gateway:8080/api/a2a/bridge --bridge-key sk-xxx\n`);\n}\n\n// ─── CLI Args ───────────────────────────────────────────────────────────────\n\nfunction parseCliArgs(): {\n configPath?: string;\n overrides: Partial<AgentConfig>;\n registerUrl?: string;\n registerKey?: string;\n unregisterOnShutdown: boolean;\n bridgeUrl?: string;\n bridgeKey?: string;\n} {\n const { values } = parseArgs({\n options: {\n provider: { type: 'string' },\n config: { type: 'string', short: 'c' },\n port: { type: 'string', short: 'p' },\n hostname: { type: 'string' },\n 'advertise-host': { type: 'string' },\n 'agent-name': { type: 'string' },\n 'agent-description':{ type: 'string' },\n 'opencode-url': { type: 'string' },\n directory: { type: 'string', short: 'd' },\n model: { type: 'string', short: 'm' },\n agent: { type: 'string' },\n 'codex-model': { type: 'string' },\n 'codex-api-key': { type: 'string' },\n 'claude-model': { type: 'string' },\n 'claude-api-key': { type: 'string' },\n 'log-level': { type: 'string' },\n 'register-url': { type: 'string' },\n 'register-key': { type: 'string' },\n 'unregister-on-shutdown': { type: 'boolean' },\n 'bridge-url': { type: 'string' },\n 'bridge-key': { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n strict: false,\n });\n\n if (values.help) {\n printUsage();\n process.exit(0);\n }\n\n if (values.version) {\n console.log(PKG_VERSION);\n process.exit(0);\n }\n\n const overrides: Partial<AgentConfig> = {};\n\n // Provider\n if (values.provider) {\n overrides.provider = values.provider as ProviderType;\n }\n\n // Server\n if (values.port || values.hostname || values['advertise-host']) {\n overrides.server = {};\n if (values.port) overrides.server.port = parseInt(values.port as string, 10);\n if (values.hostname) overrides.server.hostname = values.hostname as string;\n if (values['advertise-host']) overrides.server.advertiseHost = values['advertise-host'] as string;\n }\n\n // Agent card\n const agentCardOverrides: Partial<AgentConfig['agentCard']> = {};\n if (values['agent-name']) agentCardOverrides.name = values['agent-name'] as string;\n if (values['agent-description']) agentCardOverrides.description = values['agent-description'] as string;\n if (Object.keys(agentCardOverrides).length > 0) {\n overrides.agentCard = agentCardOverrides as AgentConfig['agentCard'];\n }\n\n // OpenCode\n const hasOpenCode = !!(values['opencode-url'] || values.directory || values.model || values.agent);\n if (hasOpenCode) {\n overrides.opencode = {};\n if (values['opencode-url']) overrides.opencode.baseUrl = values['opencode-url'] as string;\n if (values.directory) overrides.opencode.projectDirectory = values.directory as string;\n if (values.model) overrides.opencode.model = values.model as string;\n if (values.agent) overrides.opencode.agent = values.agent as string;\n }\n\n // Codex\n const hasCodex = !!(values['codex-model'] || values['codex-api-key']);\n if (hasCodex) {\n overrides.codex = {};\n if (values['codex-model']) overrides.codex.model = values['codex-model'] as string;\n if (values['codex-api-key']) overrides.codex.apiKey = values['codex-api-key'] as string;\n }\n\n // Claude\n const hasClaude = !!(values['claude-model'] || values['claude-api-key']);\n if (hasClaude) {\n overrides.claude = {};\n if (values['claude-model']) overrides.claude.model = values['claude-model'] as string;\n if (values['claude-api-key']) overrides.claude.apiKey = values['claude-api-key'] as string;\n }\n\n // Logging\n if (values['log-level']) {\n overrides.logging = { level: values['log-level'] as 'debug' | 'info' | 'warn' | 'error' };\n }\n\n const configPath = (values.config) as string | undefined;\n const registerUrl = values['register-url'] as string | undefined;\n const registerKey = values['register-key'] as string | undefined;\n const unregisterOnShutdown = (values['unregister-on-shutdown'] as boolean) ?? false;\n const bridgeUrl = values['bridge-url'] as string | undefined;\n const bridgeKey = values['bridge-key'] as string | undefined;\n return { configPath, overrides, registerUrl, registerKey, unregisterOnShutdown, bridgeUrl, bridgeKey };\n}\n\n// ─── Gateway Registration ───────────────────────────────────────────────────\n\nasync function registerWithGateway(\n registerUrl: string,\n registerKey: string,\n config: Required<AgentConfig>,\n agentCardUrl: string,\n): Promise<{ assistantId: string; agentCardUrl: string } | null> {\n const body = {\n name: config.agentCard.name,\n description: config.agentCard.description,\n graphDefinition: {\n type: 'a2a_remote',\n key: `a2a-${config.provider}-${config.agentCard.name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n name: config.agentCard.name,\n description: config.agentCard.description,\n prompt: config.agentCard.description,\n agentCardUrl,\n timeout: config.timeouts.prompt,\n },\n };\n\n try {\n const url = registerUrl.replace(/\\/$/, '') + '/api/assistants';\n log.info('Registering with gateway', { url, agentCardUrl });\n\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${registerKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n const text = await resp.text().catch(() => '');\n log.error('Gateway registration failed', { status: resp.status, body: text });\n return null;\n }\n\n const result = await resp.json() as { data?: { id: string } };\n const assistantId = result.data?.id ?? body.graphDefinition.key;\n\n log.info('Registered with gateway', { assistantId, agentCardUrl });\n console.log(`Registered as agent: ${assistantId}`);\n console.log(`Agent card: ${agentCardUrl}`);\n\n return { assistantId, agentCardUrl };\n } catch (err) {\n log.error('Gateway registration error', { error: (err as Error).message });\n return null;\n }\n}\n\nasync function unregisterFromGateway(\n registerUrl: string,\n registerKey: string,\n assistantId: string,\n): Promise<void> {\n try {\n const url = `${registerUrl.replace(/\\/$/, '')}/api/assistants/${assistantId}`;\n log.info('Unregistering from gateway', { assistantId });\n\n const resp = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${registerKey}`,\n },\n });\n\n if (!resp.ok && resp.status !== 404) {\n log.warn('Gateway unregistration failed', { status: resp.status });\n } else {\n log.info('Unregistered from gateway', { assistantId });\n }\n } catch (err) {\n log.warn('Gateway unregistration error', { error: (err as Error).message });\n }\n}\n\n// ─── Main ───────────────────────────────────────────────────────────────────\n\nasync function main(): Promise<void> {\n const { configPath, overrides, registerUrl, registerKey, unregisterOnShutdown, bridgeUrl, bridgeKey } = parseCliArgs();\n\n // Resolve config\n const config = resolveConfig(configPath, overrides);\n\n // Set configDir for relative path resolution\n if (configPath) {\n config.configDir = dirname(resolve(configPath));\n }\n\n // Apply log level\n const levelStr = config.logging.level ?? 'info';\n const levelMap: Record<string, LogLevel> = {\n debug: LogLevel.DEBUG,\n info: LogLevel.INFO,\n warn: LogLevel.WARN,\n error: LogLevel.ERROR,\n };\n logger.setLevel(levelMap[levelStr] ?? LogLevel.INFO);\n\n if (!configPath) {\n log.info('No --config provided — running with defaults + CLI args.');\n }\n\n log.info('Starting CLI A2A Gateway', {\n provider: config.provider,\n config: configPath ?? '(defaults)',\n agent: config.agentCard.name,\n port: config.server?.port,\n });\n\n // Register executors\n const { registerExecutor } = await import('./executors/index.js');\n const { createOpenCodeExecutor } = await import('./executors/opencode/executor.js');\n const { createCodexExecutor } = await import('./executors/codex/executor.js');\n const { createClaudeExecutor } = await import('./executors/claude/executor.js');\n registerExecutor('opencode', createOpenCodeExecutor);\n registerExecutor('codex', createCodexExecutor);\n registerExecutor('claude', createClaudeExecutor);\n\n // Start server\n const server = await createA2AServer(config);\n\n const listenPort = config.server?.port ?? 3000;\n const agentId = `a2a-${config.provider}-${listenPort}`;\n\n // Connect bridge to gateway (NAT traversal)\n let bridgeClient: { start(): Promise<void>; stop(): void } | null = null;\n if (bridgeUrl && bridgeKey) {\n const { BridgeClient } = await import('./bridge.js');\n const agentCardUrl = `${config.server?.advertiseProtocol ?? 'http'}://${config.server?.advertiseHost ?? 'localhost'}:${listenPort}/.well-known/agent-card.json`;\n\n bridgeClient = new BridgeClient({\n bridgeUrl: bridgeUrl.replace(/^http/, 'ws'),\n apiKey: bridgeKey,\n agentId,\n agentCard: {\n name: config.agentCard.name,\n description: config.agentCard.description,\n url: agentCardUrl,\n },\n localBaseUrl: `http://localhost:${listenPort}`,\n });\n\n bridgeClient.start().then(() => {\n log.info('Bridge connected — agent reachable via gateway proxy');\n console.log(`Bridge: ws://gateway → localhost:${listenPort}`);\n }).catch((err: Error) => {\n log.error('Bridge connection failed', { error: err.message });\n });\n }\n\n // Register with gateway (HTTP-based self-registration)\n let registeredAssistantId: string | null = null;\n if (registerUrl && registerKey) {\n // When bridge is active, the agent card URL must point to the gateway proxy\n // so the orchestrator reaches the agent through the WebSocket bridge, not directly.\n const agentCardUrl = bridgeUrl\n ? `${registerUrl.replace(/\\/$/, '')}/api/a2a/bridge/proxy/${agentId}/.well-known/agent-card.json`\n : `${config.server?.advertiseProtocol ?? 'http'}://${config.server?.advertiseHost ?? 'localhost'}:${listenPort}/.well-known/agent-card.json`;\n\n const reg = await registerWithGateway(\n registerUrl,\n registerKey,\n config,\n agentCardUrl,\n );\n if (reg) {\n registeredAssistantId = reg.assistantId;\n }\n }\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n log.info(`${signal} received, shutting down...`);\n bridgeClient?.stop();\n if (registeredAssistantId && registerUrl && registerKey && unregisterOnShutdown) {\n await unregisterFromGateway(registerUrl, registerKey, registeredAssistantId);\n }\n await server.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', () => shutdown('SIGINT'));\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n}\n\nmain().catch((err) => {\n log.error('Fatal error', { error: (err as Error).message, stack: (err as Error).stack });\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI A2A Gateway — Entry Point\n *\n * Usage:\n * npx @axiom-lattice/cli-a2a --provider opencode --config agents/example.json\n * npx @axiom-lattice/cli-a2a --provider opencode --port 3000 --opencode-url http://localhost:4096\n *\n * Run with --help for full usage.\n */\n\nimport { parseArgs } from 'node:util';\nimport { dirname, resolve } from 'node:path';\nimport { resolveConfig } from './config/loader.js';\nimport type { AgentConfig, ProviderType } from './config/types.js';\nimport { createA2AServer } from './server/index.js';\nimport { logger, LogLevel } from './logger.js';\n\nconst log = logger.child('cli');\n\n// ─── Version ────────────────────────────────────────────────────────────────\n\nconst PKG_VERSION = '0.1.0';\n\n// ─── Usage ──────────────────────────────────────────────────────────────────\n\nfunction printUsage(): void {\n console.log(`\nUsage: cli-a2a [options]\n\nOptions:\n --provider <name> Provider: opencode | codex | claude\n --config, -c <path> Path to agent JSON config file\n --port, -p <number> A2A server port (default: 3000)\n --hostname <addr> Bind address (default: 0.0.0.0)\n --advertise-host <host> Hostname for agent card URLs\n --agent-name <name> Agent display name\n --agent-description <desc> Agent description\n --log-level <level> debug | info | warn | error (default: info)\n\nGateway Registration:\n --register-url <url> Gateway URL to register this agent with\n --register-key <key> API key for gateway authentication\n --unregister-on-shutdown Remove agent from gateway on exit\n\nBridge (NAT traversal):\n --bridge-url <url> Gateway WebSocket bridge (ws://gateway:8080/api/a2a/bridge)\n --bridge-key <key> API key for bridge authentication\n\nOpenCode Options:\n --opencode-url <url> OpenCode server URL (default: http://localhost:4096)\n --directory, -d <path> Project directory\n --model, -m <provider/model> LLM model (e.g. anthropic/claude-sonnet-4)\n --agent <name> OpenCode agent preset\n\nCodex Options:\n --codex-model <model> Codex model ID\n --codex-api-key <key> OpenAI API key\n\nClaude Options:\n --claude-model <model> Claude Code model ID\n --claude-api-key <key> Anthropic API key\n\n --help, -h Show this help\n --version, -v Show version\n\nExamples:\n npx @axiom-lattice/cli-a2a --provider opencode\n npx @axiom-lattice/cli-a2a --provider opencode --port 3001 --opencode-url http://localhost:4096\n npx @axiom-lattice/cli-a2a --config ./my-agent.json\n npx @axiom-lattice/cli-a2a --provider opencode --model anthropic/claude-sonnet-4\n npx @axiom-lattice/cli-a2a --provider opencode --register-url http://gateway:8080 --register-key sk-xxx --unregister-on-shutdown\n npx @axiom-lattice/cli-a2a --provider opencode --bridge-url ws://gateway:8080/api/a2a/bridge --bridge-key sk-xxx\n`);\n}\n\n// ─── CLI Args ───────────────────────────────────────────────────────────────\n\nfunction parseCliArgs(): {\n configPath?: string;\n overrides: Partial<AgentConfig>;\n registerUrl?: string;\n registerKey?: string;\n unregisterOnShutdown: boolean;\n bridgeUrl?: string;\n bridgeKey?: string;\n} {\n const { values } = parseArgs({\n options: {\n provider: { type: 'string' },\n config: { type: 'string', short: 'c' },\n port: { type: 'string', short: 'p' },\n hostname: { type: 'string' },\n 'advertise-host': { type: 'string' },\n 'agent-name': { type: 'string' },\n 'agent-description':{ type: 'string' },\n 'opencode-url': { type: 'string' },\n directory: { type: 'string', short: 'd' },\n model: { type: 'string', short: 'm' },\n agent: { type: 'string' },\n 'codex-model': { type: 'string' },\n 'codex-api-key': { type: 'string' },\n 'claude-model': { type: 'string' },\n 'claude-api-key': { type: 'string' },\n 'log-level': { type: 'string' },\n 'register-url': { type: 'string' },\n 'register-key': { type: 'string' },\n 'unregister-on-shutdown': { type: 'boolean' },\n 'bridge-url': { type: 'string' },\n 'bridge-key': { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n strict: false,\n });\n\n if (values.help) {\n printUsage();\n process.exit(0);\n }\n\n if (values.version) {\n console.log(PKG_VERSION);\n process.exit(0);\n }\n\n const overrides: Partial<AgentConfig> = {};\n\n // Provider\n if (values.provider) {\n overrides.provider = values.provider as ProviderType;\n }\n\n // Server\n if (values.port || values.hostname || values['advertise-host']) {\n overrides.server = {};\n if (values.port) overrides.server.port = parseInt(values.port as string, 10);\n if (values.hostname) overrides.server.hostname = values.hostname as string;\n if (values['advertise-host']) overrides.server.advertiseHost = values['advertise-host'] as string;\n }\n\n // Agent card\n const agentCardOverrides: Partial<AgentConfig['agentCard']> = {};\n if (values['agent-name']) agentCardOverrides.name = values['agent-name'] as string;\n if (values['agent-description']) agentCardOverrides.description = values['agent-description'] as string;\n if (Object.keys(agentCardOverrides).length > 0) {\n overrides.agentCard = agentCardOverrides as AgentConfig['agentCard'];\n }\n\n // OpenCode\n const hasOpenCode = !!(values['opencode-url'] || values.directory || values.model || values.agent);\n if (hasOpenCode) {\n overrides.opencode = {};\n if (values['opencode-url']) overrides.opencode.baseUrl = values['opencode-url'] as string;\n if (values.directory) overrides.opencode.projectDirectory = values.directory as string;\n if (values.model) overrides.opencode.model = values.model as string;\n if (values.agent) overrides.opencode.agent = values.agent as string;\n }\n\n // Codex\n const hasCodex = !!(values['codex-model'] || values['codex-api-key']);\n if (hasCodex) {\n overrides.codex = {};\n if (values['codex-model']) overrides.codex.model = values['codex-model'] as string;\n if (values['codex-api-key']) overrides.codex.apiKey = values['codex-api-key'] as string;\n }\n\n // Claude\n const hasClaude = !!(values['claude-model'] || values['claude-api-key']);\n if (hasClaude) {\n overrides.claude = {};\n if (values['claude-model']) overrides.claude.model = values['claude-model'] as string;\n if (values['claude-api-key']) overrides.claude.apiKey = values['claude-api-key'] as string;\n }\n\n // Logging\n if (values['log-level']) {\n overrides.logging = { level: values['log-level'] as 'debug' | 'info' | 'warn' | 'error' };\n }\n\n const configPath = (values.config) as string | undefined;\n const registerUrl = values['register-url'] as string | undefined;\n const registerKey = values['register-key'] as string | undefined;\n const unregisterOnShutdown = (values['unregister-on-shutdown'] as boolean) ?? false;\n const bridgeUrl = values['bridge-url'] as string | undefined;\n const bridgeKey = values['bridge-key'] as string | undefined;\n return { configPath, overrides, registerUrl, registerKey, unregisterOnShutdown, bridgeUrl, bridgeKey };\n}\n\n// ─── Gateway Registration ───────────────────────────────────────────────────\n\nasync function registerWithGateway(\n registerUrl: string,\n registerKey: string,\n config: Required<AgentConfig>,\n agentCardUrl: string,\n): Promise<{ assistantId: string; agentCardUrl: string } | null> {\n const body = {\n name: config.agentCard.name,\n description: config.agentCard.description,\n graphDefinition: {\n type: 'a2a_remote',\n key: `a2a-${config.provider}-${config.agentCard.name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`,\n name: config.agentCard.name,\n description: config.agentCard.description,\n prompt: config.agentCard.description,\n agentCardUrl,\n timeout: config.timeouts.prompt,\n },\n };\n\n try {\n const url = registerUrl.replace(/\\/$/, '') + '/api/assistants';\n log.info('Registering with gateway', { url, agentCardUrl });\n\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${registerKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!resp.ok) {\n const text = await resp.text().catch(() => '');\n log.error('Gateway registration failed', { status: resp.status, body: text });\n return null;\n }\n\n const result = await resp.json() as { data?: { id: string } };\n const assistantId = result.data?.id ?? body.graphDefinition.key;\n\n log.info('Registered with gateway', { assistantId, agentCardUrl });\n console.log(`Registered as agent: ${assistantId}`);\n console.log(`Agent card: ${agentCardUrl}`);\n\n return { assistantId, agentCardUrl };\n } catch (err) {\n log.error('Gateway registration error', { error: (err as Error).message });\n return null;\n }\n}\n\nasync function unregisterFromGateway(\n registerUrl: string,\n registerKey: string,\n assistantId: string,\n): Promise<void> {\n try {\n const url = `${registerUrl.replace(/\\/$/, '')}/api/assistants/${assistantId}`;\n log.info('Unregistering from gateway', { assistantId });\n\n const resp = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${registerKey}`,\n },\n });\n\n if (!resp.ok && resp.status !== 404) {\n log.warn('Gateway unregistration failed', { status: resp.status });\n } else {\n log.info('Unregistered from gateway', { assistantId });\n }\n } catch (err) {\n log.warn('Gateway unregistration error', { error: (err as Error).message });\n }\n}\n\n// ─── Main ───────────────────────────────────────────────────────────────────\n\nasync function main(): Promise<void> {\n const { configPath, overrides, registerUrl, registerKey, unregisterOnShutdown, bridgeUrl, bridgeKey } = parseCliArgs();\n\n // Resolve config\n const config = resolveConfig(configPath, overrides);\n\n // Set configDir for relative path resolution\n if (configPath) {\n config.configDir = dirname(resolve(configPath));\n }\n\n // Apply log level\n const levelStr = config.logging.level ?? 'info';\n const levelMap: Record<string, LogLevel> = {\n debug: LogLevel.DEBUG,\n info: LogLevel.INFO,\n warn: LogLevel.WARN,\n error: LogLevel.ERROR,\n };\n logger.setLevel(levelMap[levelStr] ?? LogLevel.INFO);\n\n if (!configPath) {\n log.info('No --config provided — running with defaults + CLI args.');\n }\n\n log.info('Starting CLI A2A Gateway', {\n provider: config.provider,\n config: configPath ?? '(defaults)',\n agent: config.agentCard.name,\n port: config.server?.port,\n });\n\n // Register executors\n const { registerExecutor } = await import('./executors/index.js');\n const { createOpenCodeExecutor } = await import('./executors/opencode/executor.js');\n const { createCodexExecutor } = await import('./executors/codex/executor.js');\n const { createClaudeExecutor } = await import('./executors/claude/executor.js');\n registerExecutor('opencode', createOpenCodeExecutor);\n registerExecutor('codex', createCodexExecutor);\n registerExecutor('claude', createClaudeExecutor);\n\n // Start server\n const server = await createA2AServer(config);\n\n const listenPort = config.server?.port ?? 3000;\n const agentId = `a2a-${config.provider}-${listenPort}`;\n\n // Connect bridge to gateway (NAT traversal)\n let bridgeClient: { start(): Promise<void>; stop(): void } | null = null;\n if (bridgeUrl && bridgeKey) {\n const { BridgeClient } = await import('./bridge.js');\n const agentCardUrl = `${config.server?.advertiseProtocol ?? 'http'}://${config.server?.advertiseHost ?? 'localhost'}:${listenPort}/.well-known/agent-card.json`;\n\n bridgeClient = new BridgeClient({\n bridgeUrl: bridgeUrl.replace(/^http/, 'ws'),\n apiKey: bridgeKey,\n agentId,\n agentCard: {\n name: config.agentCard.name,\n description: config.agentCard.description,\n url: agentCardUrl,\n },\n localBaseUrl: `http://localhost:${listenPort}`,\n });\n\n bridgeClient.start().then(() => {\n log.info('Bridge connected — agent reachable via gateway proxy');\n console.log(`Bridge: ws://gateway → localhost:${listenPort}`);\n }).catch((err: Error) => {\n log.error('Bridge connection failed', { error: err.message });\n });\n }\n\n // Register with gateway (HTTP-based self-registration)\n let registeredAssistantId: string | null = null;\n if (registerUrl && registerKey) {\n // When bridge is active, the agent card URL must point to the gateway proxy\n // so the orchestrator reaches the agent through the WebSocket bridge, not directly.\n const agentCardUrl = bridgeUrl\n ? `${registerUrl.replace(/\\/$/, '')}/api/a2a/bridge/proxy/${agentId}/.well-known/agent-card.json`\n : `${config.server?.advertiseProtocol ?? 'http'}://${config.server?.advertiseHost ?? 'localhost'}:${listenPort}/.well-known/agent-card.json`;\n\n const reg = await registerWithGateway(\n registerUrl,\n registerKey,\n config,\n agentCardUrl,\n );\n if (reg) {\n registeredAssistantId = reg.assistantId;\n }\n }\n\n // Graceful shutdown\n const shutdown = async (signal: string) => {\n log.info(`${signal} received, shutting down...`);\n bridgeClient?.stop();\n if (registeredAssistantId && registerUrl && registerKey && unregisterOnShutdown) {\n await unregisterFromGateway(registerUrl, registerKey, registeredAssistantId);\n }\n await server.shutdown();\n process.exit(0);\n };\n\n process.on('SIGINT', () => shutdown('SIGINT'));\n process.on('SIGTERM', () => shutdown('SIGTERM'));\n}\n\nmain().catch((err) => {\n log.error('Fatal error', { error: (err as Error).message, stack: (err as Error).stack });\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,12 @@
1
+ import {
2
+ CodexExecutor,
3
+ createCodexExecutor
4
+ } from "./chunk-URJDRXJW.mjs";
5
+ import "./chunk-YGUPSPZO.mjs";
6
+ import "./chunk-DRFFQJII.mjs";
7
+ import "./chunk-VZEH3EPJ.mjs";
8
+ export {
9
+ CodexExecutor,
10
+ createCodexExecutor
11
+ };
12
+ //# sourceMappingURL=executor-LLE5VEFJ.mjs.map
@@ -0,0 +1,12 @@
1
+ import {
2
+ ClaudeExecutor,
3
+ createClaudeExecutor
4
+ } from "./chunk-54SKDK3D.mjs";
5
+ import "./chunk-YGUPSPZO.mjs";
6
+ import "./chunk-DRFFQJII.mjs";
7
+ import "./chunk-VZEH3EPJ.mjs";
8
+ export {
9
+ ClaudeExecutor,
10
+ createClaudeExecutor
11
+ };
12
+ //# sourceMappingURL=executor-LO7P3KUW.mjs.map
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  OpenCodeExecutor,
3
3
  createOpenCodeExecutor
4
- } from "./chunk-WNCDOYZS.mjs";
5
- import "./chunk-LXL47XMZ.mjs";
4
+ } from "./chunk-BSNQOP2W.mjs";
5
+ import "./chunk-YGUPSPZO.mjs";
6
+ import "./chunk-DRFFQJII.mjs";
6
7
  import "./chunk-VZEH3EPJ.mjs";
7
8
  export {
8
9
  OpenCodeExecutor,
9
10
  createOpenCodeExecutor
10
11
  };
11
- //# sourceMappingURL=executor-RVBGAWUF.mjs.map
12
+ //# sourceMappingURL=executor-OOLGGXHS.mjs.map
@@ -4,7 +4,7 @@ import {
4
4
  getExecutor,
5
5
  registerExecutor,
6
6
  v4
7
- } from "./chunk-35NFMGMS.mjs";
7
+ } from "./chunk-ZP3JNJQJ.mjs";
8
8
  export {
9
9
  TaskState,
10
10
  createExecutor,
@@ -12,4 +12,4 @@ export {
12
12
  registerExecutor,
13
13
  v4 as uuidv4
14
14
  };
15
- //# sourceMappingURL=executors-QIIKBUMJ.mjs.map
15
+ //# sourceMappingURL=executors-AQHOPGSR.mjs.map
package/dist/index.d.mts CHANGED
@@ -54,11 +54,16 @@ interface ServerConfig {
54
54
  interface SessionConfig {
55
55
  /** Session title prefix */
56
56
  titlePrefix?: string;
57
- /** Reuse sessions by A2A contextId */
57
+ /** Reuse sessions by A2A contextId (default: true) */
58
58
  reuseByContext?: boolean;
59
- /** Session TTL in ms */
59
+ /** Persist session bindings to disk (default: true) */
60
+ persist?: boolean;
61
+ /** Path to session binding store file.
62
+ * Default: ~/Library/Application Support/axiom-lattice/cli-a2a/sessions-<provider>-<port>.json */
63
+ storePath?: string;
64
+ /** Session TTL in ms. Bindings older than this are cleaned up. (default: 24h) */
60
65
  ttl?: number;
61
- /** Cleanup interval in ms */
66
+ /** Cleanup interval in ms (default: 1h) */
62
67
  cleanupInterval?: number;
63
68
  }
64
69
  interface FeatureFlags {
@@ -176,6 +181,70 @@ interface ServerHandle {
176
181
  }
177
182
  declare function createA2AServer(config: Required<AgentConfig>): Promise<ServerHandle>;
178
183
 
184
+ /**
185
+ * SessionBindingStore
186
+ *
187
+ * Persists A2A contextId → CLI sessionId mappings so that multi-turn
188
+ * conversations survive process restarts. Supports atomic file writes,
189
+ * in-memory caching, TTL-based cleanup, and corrupted-file recovery.
190
+ */
191
+
192
+ interface SessionBinding {
193
+ provider: ProviderType;
194
+ contextId: string;
195
+ sessionId: string;
196
+ activeTaskId?: string;
197
+ activeTaskState?: string;
198
+ createdAt: string;
199
+ updatedAt: string;
200
+ expiresAt?: string;
201
+ }
202
+ declare function resolveSessionStorePath(options: {
203
+ configuredPath?: string;
204
+ provider: ProviderType;
205
+ port: number;
206
+ storeDir?: string;
207
+ }): string;
208
+ declare class SessionBindingStore {
209
+ private cache;
210
+ private storePath;
211
+ private persist;
212
+ private cleanupTimer;
213
+ private dirty;
214
+ private flushTimeout;
215
+ constructor(opts?: {
216
+ storePath?: string;
217
+ persist?: boolean;
218
+ cleanupIntervalMs?: number;
219
+ });
220
+ get(contextId: string, provider: ProviderType): SessionBinding | null;
221
+ set(binding: SessionBinding): void;
222
+ delete(contextId: string, provider: ProviderType): boolean;
223
+ clearActiveTask(contextId: string, provider: ProviderType): void;
224
+ /**
225
+ * Remove all expired entries.
226
+ * Called automatically on the cleanup interval; call manually before shutdown.
227
+ */
228
+ cleanup(): number;
229
+ /**
230
+ * Graceful shutdown: stop cleanup timer, flush pending writes.
231
+ */
232
+ shutdown(): void;
233
+ /** For testing: return the number of cached bindings. */
234
+ get size(): number;
235
+ private makeKey;
236
+ private isExpired;
237
+ private startCleanup;
238
+ private markDirty;
239
+ private flushToFile;
240
+ private writeAtomically;
241
+ private loadFromFile;
242
+ }
243
+ /**
244
+ * Generate a new contextId for use when the A2A client doesn't provide one.
245
+ */
246
+ declare function generateContextId(): string;
247
+
179
248
  /**
180
249
  * Executor types and common interfaces for CLI A2A providers.
181
250
  *
@@ -197,74 +266,76 @@ interface A2AExecutor extends AgentExecutor {
197
266
  }
198
267
 
199
268
  /**
200
- * Factory function type: given resolved config, produce an executor.
269
+ * Factory function type: given resolved config and a session store,
270
+ * produce an executor.
201
271
  */
202
- type ExecutorFactory = (config: Required<AgentConfig>) => A2AExecutor;
272
+ type ExecutorFactory = (config: Required<AgentConfig>, sessionStore: SessionBindingStore) => A2AExecutor;
203
273
  declare function registerExecutor(provider: ProviderType, factory: ExecutorFactory): void;
204
274
  declare function getExecutor(provider: ProviderType): ExecutorFactory | undefined;
205
- declare function createExecutor(config: Required<AgentConfig>): A2AExecutor;
275
+ declare function createExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
206
276
 
207
277
  /**
208
278
  * OpenCode A2A Executor
209
279
  *
210
280
  * Bridges the local OpenCode CLI to the A2A protocol. Spawns `opencode run`
211
- * as a child process for each request and captures stdout as the response.
212
- * Same spawn pattern as Codex and Claude Code executors.
281
+ * as a child process for each request. Supports multi-turn conversation
282
+ * via contextId sessionId binding through SessionBindingStore.
213
283
  */
214
284
 
215
285
  declare class OpenCodeExecutor implements A2AExecutor {
216
286
  private config;
217
287
  private client;
218
288
  private initialized;
219
- constructor(config: Required<AgentConfig>);
289
+ private sessionStore;
290
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
220
291
  initialize(): Promise<void>;
221
292
  shutdown(): Promise<void>;
222
293
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
223
294
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
224
- private extractText;
225
295
  }
226
- declare function createOpenCodeExecutor(config: Required<AgentConfig>): A2AExecutor;
296
+ declare function createOpenCodeExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
227
297
 
228
298
  /**
229
299
  * Codex A2A Executor
230
300
  *
231
301
  * Bridges the local Codex CLI to the A2A protocol. Spawns Codex as a
232
- * child process for each request and captures stdout as the response.
302
+ * child process for each request. Supports multi-turn conversation via
303
+ * contextId → sessionId binding through SessionBindingStore.
233
304
  */
234
305
 
235
306
  declare class CodexExecutor implements A2AExecutor {
236
307
  private config;
237
308
  private client;
238
309
  private initialized;
239
- constructor(config: Required<AgentConfig>);
310
+ private sessionStore;
311
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
240
312
  initialize(): Promise<void>;
241
313
  shutdown(): Promise<void>;
242
314
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
243
315
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
244
- private extractText;
245
316
  }
246
- declare function createCodexExecutor(config: Required<AgentConfig>): A2AExecutor;
317
+ declare function createCodexExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
247
318
 
248
319
  /**
249
320
  * Claude Code A2A Executor
250
321
  *
251
322
  * Bridges the local Claude Code CLI to the A2A protocol. Spawns Claude Code
252
- * in non-interactive print mode (`-p`) for each request and captures stdout
253
- * as the response.
323
+ * in non-interactive print mode (`-p`) for each request. Supports multi-turn
324
+ * conversation via contextId → sessionId binding through SessionBindingStore.
254
325
  */
255
326
 
256
327
  declare class ClaudeExecutor implements A2AExecutor {
257
328
  private config;
258
329
  private client;
259
330
  private initialized;
260
- constructor(config: Required<AgentConfig>);
331
+ private sessionStore;
332
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
261
333
  initialize(): Promise<void>;
262
334
  shutdown(): Promise<void>;
263
335
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
264
336
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
265
- private extractText;
266
337
  }
267
- declare function createClaudeExecutor(config: Required<AgentConfig>): A2AExecutor;
338
+ declare function createClaudeExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
268
339
 
269
340
  /**
270
341
  * Lightweight structured logger for the CLI A2A gateway.
@@ -292,4 +363,4 @@ declare class Logger {
292
363
  }
293
364
  declare const logger: Logger;
294
365
 
295
- export { type A2AExecutor, type AgentCardConfig, type AgentConfig, type ClaudeCodeConfig, ClaudeExecutor, type CodexConfig, CodexExecutor, type ExecutorFactory, type FeatureFlags, LogLevel, type LoggingConfig, type OpenCodeConfig, OpenCodeExecutor, type ProviderType, type ServerConfig, type ServerHandle, type SessionConfig, type SkillConfig, type TimeoutConfig, createA2AServer, createClaudeExecutor, createCodexExecutor, createExecutor, createOpenCodeExecutor, getExecutor, loadConfigFile, logger, registerExecutor, resolveConfig };
366
+ export { type A2AExecutor, type AgentCardConfig, type AgentConfig, type ClaudeCodeConfig, ClaudeExecutor, type CodexConfig, CodexExecutor, type ExecutorFactory, type FeatureFlags, LogLevel, type LoggingConfig, type OpenCodeConfig, OpenCodeExecutor, type ProviderType, type ServerConfig, type ServerHandle, type SessionBinding, SessionBindingStore, type SessionConfig, type SkillConfig, type TimeoutConfig, createA2AServer, createClaudeExecutor, createCodexExecutor, createExecutor, createOpenCodeExecutor, generateContextId, getExecutor, loadConfigFile, logger, registerExecutor, resolveConfig, resolveSessionStorePath };
package/dist/index.d.ts CHANGED
@@ -54,11 +54,16 @@ interface ServerConfig {
54
54
  interface SessionConfig {
55
55
  /** Session title prefix */
56
56
  titlePrefix?: string;
57
- /** Reuse sessions by A2A contextId */
57
+ /** Reuse sessions by A2A contextId (default: true) */
58
58
  reuseByContext?: boolean;
59
- /** Session TTL in ms */
59
+ /** Persist session bindings to disk (default: true) */
60
+ persist?: boolean;
61
+ /** Path to session binding store file.
62
+ * Default: ~/Library/Application Support/axiom-lattice/cli-a2a/sessions-<provider>-<port>.json */
63
+ storePath?: string;
64
+ /** Session TTL in ms. Bindings older than this are cleaned up. (default: 24h) */
60
65
  ttl?: number;
61
- /** Cleanup interval in ms */
66
+ /** Cleanup interval in ms (default: 1h) */
62
67
  cleanupInterval?: number;
63
68
  }
64
69
  interface FeatureFlags {
@@ -176,6 +181,70 @@ interface ServerHandle {
176
181
  }
177
182
  declare function createA2AServer(config: Required<AgentConfig>): Promise<ServerHandle>;
178
183
 
184
+ /**
185
+ * SessionBindingStore
186
+ *
187
+ * Persists A2A contextId → CLI sessionId mappings so that multi-turn
188
+ * conversations survive process restarts. Supports atomic file writes,
189
+ * in-memory caching, TTL-based cleanup, and corrupted-file recovery.
190
+ */
191
+
192
+ interface SessionBinding {
193
+ provider: ProviderType;
194
+ contextId: string;
195
+ sessionId: string;
196
+ activeTaskId?: string;
197
+ activeTaskState?: string;
198
+ createdAt: string;
199
+ updatedAt: string;
200
+ expiresAt?: string;
201
+ }
202
+ declare function resolveSessionStorePath(options: {
203
+ configuredPath?: string;
204
+ provider: ProviderType;
205
+ port: number;
206
+ storeDir?: string;
207
+ }): string;
208
+ declare class SessionBindingStore {
209
+ private cache;
210
+ private storePath;
211
+ private persist;
212
+ private cleanupTimer;
213
+ private dirty;
214
+ private flushTimeout;
215
+ constructor(opts?: {
216
+ storePath?: string;
217
+ persist?: boolean;
218
+ cleanupIntervalMs?: number;
219
+ });
220
+ get(contextId: string, provider: ProviderType): SessionBinding | null;
221
+ set(binding: SessionBinding): void;
222
+ delete(contextId: string, provider: ProviderType): boolean;
223
+ clearActiveTask(contextId: string, provider: ProviderType): void;
224
+ /**
225
+ * Remove all expired entries.
226
+ * Called automatically on the cleanup interval; call manually before shutdown.
227
+ */
228
+ cleanup(): number;
229
+ /**
230
+ * Graceful shutdown: stop cleanup timer, flush pending writes.
231
+ */
232
+ shutdown(): void;
233
+ /** For testing: return the number of cached bindings. */
234
+ get size(): number;
235
+ private makeKey;
236
+ private isExpired;
237
+ private startCleanup;
238
+ private markDirty;
239
+ private flushToFile;
240
+ private writeAtomically;
241
+ private loadFromFile;
242
+ }
243
+ /**
244
+ * Generate a new contextId for use when the A2A client doesn't provide one.
245
+ */
246
+ declare function generateContextId(): string;
247
+
179
248
  /**
180
249
  * Executor types and common interfaces for CLI A2A providers.
181
250
  *
@@ -197,74 +266,76 @@ interface A2AExecutor extends AgentExecutor {
197
266
  }
198
267
 
199
268
  /**
200
- * Factory function type: given resolved config, produce an executor.
269
+ * Factory function type: given resolved config and a session store,
270
+ * produce an executor.
201
271
  */
202
- type ExecutorFactory = (config: Required<AgentConfig>) => A2AExecutor;
272
+ type ExecutorFactory = (config: Required<AgentConfig>, sessionStore: SessionBindingStore) => A2AExecutor;
203
273
  declare function registerExecutor(provider: ProviderType, factory: ExecutorFactory): void;
204
274
  declare function getExecutor(provider: ProviderType): ExecutorFactory | undefined;
205
- declare function createExecutor(config: Required<AgentConfig>): A2AExecutor;
275
+ declare function createExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
206
276
 
207
277
  /**
208
278
  * OpenCode A2A Executor
209
279
  *
210
280
  * Bridges the local OpenCode CLI to the A2A protocol. Spawns `opencode run`
211
- * as a child process for each request and captures stdout as the response.
212
- * Same spawn pattern as Codex and Claude Code executors.
281
+ * as a child process for each request. Supports multi-turn conversation
282
+ * via contextId sessionId binding through SessionBindingStore.
213
283
  */
214
284
 
215
285
  declare class OpenCodeExecutor implements A2AExecutor {
216
286
  private config;
217
287
  private client;
218
288
  private initialized;
219
- constructor(config: Required<AgentConfig>);
289
+ private sessionStore;
290
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
220
291
  initialize(): Promise<void>;
221
292
  shutdown(): Promise<void>;
222
293
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
223
294
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
224
- private extractText;
225
295
  }
226
- declare function createOpenCodeExecutor(config: Required<AgentConfig>): A2AExecutor;
296
+ declare function createOpenCodeExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
227
297
 
228
298
  /**
229
299
  * Codex A2A Executor
230
300
  *
231
301
  * Bridges the local Codex CLI to the A2A protocol. Spawns Codex as a
232
- * child process for each request and captures stdout as the response.
302
+ * child process for each request. Supports multi-turn conversation via
303
+ * contextId → sessionId binding through SessionBindingStore.
233
304
  */
234
305
 
235
306
  declare class CodexExecutor implements A2AExecutor {
236
307
  private config;
237
308
  private client;
238
309
  private initialized;
239
- constructor(config: Required<AgentConfig>);
310
+ private sessionStore;
311
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
240
312
  initialize(): Promise<void>;
241
313
  shutdown(): Promise<void>;
242
314
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
243
315
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
244
- private extractText;
245
316
  }
246
- declare function createCodexExecutor(config: Required<AgentConfig>): A2AExecutor;
317
+ declare function createCodexExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
247
318
 
248
319
  /**
249
320
  * Claude Code A2A Executor
250
321
  *
251
322
  * Bridges the local Claude Code CLI to the A2A protocol. Spawns Claude Code
252
- * in non-interactive print mode (`-p`) for each request and captures stdout
253
- * as the response.
323
+ * in non-interactive print mode (`-p`) for each request. Supports multi-turn
324
+ * conversation via contextId → sessionId binding through SessionBindingStore.
254
325
  */
255
326
 
256
327
  declare class ClaudeExecutor implements A2AExecutor {
257
328
  private config;
258
329
  private client;
259
330
  private initialized;
260
- constructor(config: Required<AgentConfig>);
331
+ private sessionStore;
332
+ constructor(config: Required<AgentConfig>, sessionStore: SessionBindingStore);
261
333
  initialize(): Promise<void>;
262
334
  shutdown(): Promise<void>;
263
335
  execute(ctx: RequestContext, bus: ExecutionEventBus): Promise<void>;
264
336
  cancelTask(taskId: string, bus: ExecutionEventBus): Promise<void>;
265
- private extractText;
266
337
  }
267
- declare function createClaudeExecutor(config: Required<AgentConfig>): A2AExecutor;
338
+ declare function createClaudeExecutor(config: Required<AgentConfig>, sessionStore: SessionBindingStore): A2AExecutor;
268
339
 
269
340
  /**
270
341
  * Lightweight structured logger for the CLI A2A gateway.
@@ -292,4 +363,4 @@ declare class Logger {
292
363
  }
293
364
  declare const logger: Logger;
294
365
 
295
- export { type A2AExecutor, type AgentCardConfig, type AgentConfig, type ClaudeCodeConfig, ClaudeExecutor, type CodexConfig, CodexExecutor, type ExecutorFactory, type FeatureFlags, LogLevel, type LoggingConfig, type OpenCodeConfig, OpenCodeExecutor, type ProviderType, type ServerConfig, type ServerHandle, type SessionConfig, type SkillConfig, type TimeoutConfig, createA2AServer, createClaudeExecutor, createCodexExecutor, createExecutor, createOpenCodeExecutor, getExecutor, loadConfigFile, logger, registerExecutor, resolveConfig };
366
+ export { type A2AExecutor, type AgentCardConfig, type AgentConfig, type ClaudeCodeConfig, ClaudeExecutor, type CodexConfig, CodexExecutor, type ExecutorFactory, type FeatureFlags, LogLevel, type LoggingConfig, type OpenCodeConfig, OpenCodeExecutor, type ProviderType, type ServerConfig, type ServerHandle, type SessionBinding, SessionBindingStore, type SessionConfig, type SkillConfig, type TimeoutConfig, createA2AServer, createClaudeExecutor, createCodexExecutor, createExecutor, createOpenCodeExecutor, generateContextId, getExecutor, loadConfigFile, logger, registerExecutor, resolveConfig, resolveSessionStorePath };