@a2a-wrapper/core 1.2.0

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 (50) hide show
  1. package/README.md +186 -0
  2. package/dist/cli/scaffold.d.ts +237 -0
  3. package/dist/cli/scaffold.d.ts.map +1 -0
  4. package/dist/cli/scaffold.js +241 -0
  5. package/dist/cli/scaffold.js.map +1 -0
  6. package/dist/config/loader.d.ts +100 -0
  7. package/dist/config/loader.d.ts.map +1 -0
  8. package/dist/config/loader.js +130 -0
  9. package/dist/config/loader.js.map +1 -0
  10. package/dist/config/types.d.ts +317 -0
  11. package/dist/config/types.d.ts.map +1 -0
  12. package/dist/config/types.js +17 -0
  13. package/dist/config/types.js.map +1 -0
  14. package/dist/events/event-publisher.d.ts +205 -0
  15. package/dist/events/event-publisher.d.ts.map +1 -0
  16. package/dist/events/event-publisher.js +317 -0
  17. package/dist/events/event-publisher.js.map +1 -0
  18. package/dist/executor/types.d.ts +164 -0
  19. package/dist/executor/types.d.ts.map +1 -0
  20. package/dist/executor/types.js +30 -0
  21. package/dist/executor/types.js.map +1 -0
  22. package/dist/index.d.ts +37 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +34 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/server/agent-card.d.ts +66 -0
  27. package/dist/server/agent-card.d.ts.map +1 -0
  28. package/dist/server/agent-card.js +114 -0
  29. package/dist/server/agent-card.js.map +1 -0
  30. package/dist/server/factory.d.ts +159 -0
  31. package/dist/server/factory.d.ts.map +1 -0
  32. package/dist/server/factory.js +167 -0
  33. package/dist/server/factory.js.map +1 -0
  34. package/dist/session/base-session-manager.d.ts +218 -0
  35. package/dist/session/base-session-manager.d.ts.map +1 -0
  36. package/dist/session/base-session-manager.js +222 -0
  37. package/dist/session/base-session-manager.js.map +1 -0
  38. package/dist/utils/deep-merge.d.ts +83 -0
  39. package/dist/utils/deep-merge.d.ts.map +1 -0
  40. package/dist/utils/deep-merge.js +108 -0
  41. package/dist/utils/deep-merge.js.map +1 -0
  42. package/dist/utils/deferred.d.ts +97 -0
  43. package/dist/utils/deferred.d.ts.map +1 -0
  44. package/dist/utils/deferred.js +83 -0
  45. package/dist/utils/deferred.js.map +1 -0
  46. package/dist/utils/logger.d.ts +186 -0
  47. package/dist/utils/logger.d.ts.map +1 -0
  48. package/dist/utils/logger.js +244 -0
  49. package/dist/utils/logger.js.map +1 -0
  50. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # @a2a-wrapper/core
2
+
3
+ Shared infrastructure core for [A2A protocol](https://github.com/google/A2A) wrapper projects. Provides logging, configuration loading, event publishing, agent card building, server bootstrapping, session management, and CLI scaffolding — so each wrapper only needs to implement its backend-specific executor.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @a2a-wrapper/core
9
+ ```
10
+
11
+ Peer dependencies (your wrapper project must install these):
12
+
13
+ ```bash
14
+ npm install @a2a-js/sdk express uuid
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ A minimal wrapper project using `createCli`:
20
+
21
+ ```typescript
22
+ import {
23
+ createCli,
24
+ type BaseAgentConfig,
25
+ type A2AExecutor,
26
+ } from "@a2a-wrapper/core";
27
+
28
+ // 1. Define your backend-specific config
29
+ interface MyBackendConfig {
30
+ apiUrl: string;
31
+ }
32
+ type MyConfig = BaseAgentConfig<MyBackendConfig>;
33
+
34
+ // 2. Implement the executor interface
35
+ class MyExecutor implements A2AExecutor {
36
+ constructor(private config: Required<MyConfig>) {}
37
+ async initialize() { /* connect to backend */ }
38
+ async shutdown() { /* cleanup */ }
39
+ async execute(context: any, event: any) { /* handle A2A tasks */ }
40
+ }
41
+
42
+ // 3. Wire it up with createCli
43
+ createCli<MyConfig>({
44
+ packageName: "my-a2a-wrapper",
45
+ version: "1.0.0",
46
+ defaults: { /* full default config */ } as Required<MyConfig>,
47
+ usage: "Usage: my-a2a-wrapper [options]",
48
+ executorFactory: (config) => new MyExecutor(config),
49
+ parseBackendArgs: (values) => ({
50
+ backend: { apiUrl: values["api-url"] as string },
51
+ }),
52
+ loadEnvOverrides: () => ({
53
+ backend: { apiUrl: process.env.MY_API_URL },
54
+ }),
55
+ extraArgDefs: {
56
+ "api-url": { type: "string" },
57
+ },
58
+ });
59
+ ```
60
+
61
+ Run it:
62
+
63
+ ```bash
64
+ node dist/cli.js --port 3000 --log-level debug --api-url http://localhost:8080
65
+ ```
66
+
67
+ ## API Reference
68
+
69
+ All public symbols are exported from the package root (`@a2a-wrapper/core`). Imports from internal module paths are not supported.
70
+
71
+ ### Utils
72
+
73
+ | Export | Description |
74
+ |---|---|
75
+ | `createLogger(rootName)` | Factory that returns a new `Logger` instance with the given root name. |
76
+ | `Logger` | Structured logger with `debug`, `info`, `warn`, `error` methods and `child(name)` for hierarchical naming. |
77
+ | `LogLevel` | Enum — `DEBUG`, `INFO`, `WARN`, `ERROR`. |
78
+ | `createDeferred<T>()` | Returns a `Deferred<T>` with externally-resolvable `promise`, `resolve`, and `reject`. |
79
+ | `sleep(ms)` | Returns a Promise that resolves after `ms` milliseconds. |
80
+ | `deepMerge(target, source)` | Recursively merges objects. Arrays are replaced, inputs are not mutated. |
81
+ | `substituteEnvTokens(args)` | Replaces `$VAR_NAME` tokens in string arrays with matching env var values. |
82
+
83
+ ### Config
84
+
85
+ | Export | Description |
86
+ |---|---|
87
+ | `BaseAgentConfig<TBackend>` | Generic config interface — includes `agentCard`, `server`, `session`, `logging`, `timeouts`, and `backend: TBackend`. |
88
+ | `AgentCardConfig` | Agent card fields (name, description, skills, capabilities). |
89
+ | `ServerConfig` | Server fields (port, hostname, advertiseHost, advertiseProtocol). |
90
+ | `SessionConfig` | Session fields (reuseByContext, ttlMs, cleanupIntervalMs). |
91
+ | `BaseFeatureFlags` | Shared feature flags (`streamArtifactChunks`). |
92
+ | `TimeoutConfig` | Timeout settings. |
93
+ | `LoggingConfig` | Logging settings (level). |
94
+ | `BaseMcpServerConfig` | Common MCP server config pattern. |
95
+ | `SkillConfig` | Skill definition (id, name, description, tags, examples). |
96
+ | `loadConfigFile<T>(filePath)` | Reads and parses a JSON config file. Throws descriptive errors on failure. |
97
+ | `resolveConfig<T>(defaults, configFilePath?, envOverrides?, cliOverrides?)` | Merges config layers: defaults ← file ← env ← CLI. |
98
+
99
+ ### Events
100
+
101
+ | Export | Description |
102
+ |---|---|
103
+ | `publishStatus(bus, taskId, contextId, state, messageText?, final?)` | Publishes a `TaskStatusUpdateEvent`. |
104
+ | `publishFinalArtifact(bus, taskId, contextId, text)` | Publishes a complete artifact (`lastChunk: true`). |
105
+ | `publishStreamingChunk(bus, taskId, contextId, artifactId, chunkText)` | Publishes an appending artifact chunk. |
106
+ | `publishLastChunkMarker(bus, taskId, contextId, artifactId, fullText)` | Publishes the final streaming chunk. |
107
+ | `publishTraceArtifact(bus, taskId, contextId, traceKey, data)` | Publishes a structured `DataPart` trace artifact. |
108
+ | `publishThoughtArtifact(bus, taskId, contextId, traceKey, text)` | Publishes a `TextPart` trace artifact. |
109
+
110
+ ### Server
111
+
112
+ | Export | Description |
113
+ |---|---|
114
+ | `buildAgentCard(config)` | Constructs an A2A `AgentCard` from `AgentCardConfig` + `ServerConfig`. |
115
+ | `createA2AServer<T>(config, executorFactory, options?)` | Creates an Express app with standard A2A routes and starts listening. Returns a `ServerHandle`. |
116
+ | `ServerOptions` | Options for protocol version, custom route hooks. |
117
+ | `ServerHandle` | Returned by `createA2AServer` — contains `app`, `server`, `executor`, `shutdown()`. |
118
+
119
+ ### Session
120
+
121
+ | Export | Description |
122
+ |---|---|
123
+ | `BaseSessionManager<TSession>` | Abstract class managing contextId → session mapping with TTL cleanup and task tracking. Subclass and implement `getOrCreate(contextId)`. |
124
+ | `SessionEntry<TSession>` | Interface for session entries with `session` and `lastUsed` fields. |
125
+
126
+ ### Executor
127
+
128
+ | Export | Description |
129
+ |---|---|
130
+ | `A2AExecutor` | Interface contract for backend executors — `initialize()`, `shutdown()`, `execute()`, and optional `cancelTask()`, `getContextContent()`, `buildContext()`. |
131
+
132
+ ### CLI
133
+
134
+ | Export | Description |
135
+ |---|---|
136
+ | `createCli<T>(options)` | Main entry point for wrapper CLIs. Handles arg parsing, config resolution, server creation, and graceful shutdown. |
137
+ | `CliOptions<T>` | Configuration for `createCli` — package name, version, defaults, usage, executor factory, arg definitions. |
138
+ | `parseCommonArgs<T>(argv, extraArgDefs?)` | Parses common CLI flags (`--port`, `--hostname`, `--log-level`, etc.) into typed config overrides. |
139
+ | `CommonArgsResult<T>` | Result of `parseCommonArgs` — config path and partial overrides. |
140
+
141
+ ### A2A SDK Re-exports
142
+
143
+ | Export | Source |
144
+ |---|---|
145
+ | `AgentCard` | `@a2a-js/sdk` |
146
+ | `TaskState`, `TaskStatusUpdateEvent`, `TaskArtifactUpdateEvent` | `@a2a-js/sdk` |
147
+ | `ExecutionEventBus`, `RequestContext` | `@a2a-js/sdk/server` |
148
+
149
+ These re-exports isolate wrapper projects from direct SDK imports, so a major SDK upgrade only requires changes in `@a2a-wrapper/core`.
150
+
151
+ ## Contributing
152
+
153
+ ### Prerequisites
154
+
155
+ - Node.js ≥ 18
156
+ - npm
157
+
158
+ ### Development
159
+
160
+ ```bash
161
+ # Install dependencies
162
+ npm install
163
+
164
+ # Build
165
+ npm run build
166
+
167
+ # Run tests
168
+ npm test
169
+
170
+ # Type-check without emitting
171
+ npm run typecheck
172
+
173
+ # Clean build output
174
+ npm run clean
175
+ ```
176
+
177
+ ### Code Standards
178
+
179
+ - TypeScript with `strict: true`
180
+ - JSDoc on every exported symbol
181
+ - Property-based tests (fast-check) alongside unit tests (vitest)
182
+ - Follow [Keep a Changelog](https://keepachangelog.com/) for CHANGELOG.md
183
+
184
+ ## License
185
+
186
+ MIT
@@ -0,0 +1,237 @@
1
+ /**
2
+ * CLI Scaffold
3
+ *
4
+ * Provides a reusable, generic CLI entry-point factory for A2A wrapper
5
+ * projects. Each wrapper calls {@link createCli} once with its package
6
+ * metadata, default configuration, backend-specific argument parser, and
7
+ * executor factory. The scaffold handles everything else: common flag
8
+ * parsing, layered config resolution, log-level setup, server creation,
9
+ * and graceful shutdown on SIGINT / SIGTERM.
10
+ *
11
+ * This module is intentionally backend-agnostic. Wrapper-specific flags
12
+ * (e.g. `--cli-url`, `--opencode-url`) are injected via
13
+ * {@link CliOptions.extraArgDefs} and parsed by the wrapper's
14
+ * {@link CliOptions.parseBackendArgs} callback.
15
+ *
16
+ * The exported {@link parseCommonArgs} helper is also available for unit
17
+ * and property-based testing of the common flag parsing logic without
18
+ * triggering the full main-loop side effects.
19
+ *
20
+ * @module cli/scaffold
21
+ */
22
+ import type { BaseAgentConfig } from "../config/types.js";
23
+ import type { ServerOptions, A2AExecutor } from "../server/factory.js";
24
+ /**
25
+ * Configuration object accepted by {@link createCli}.
26
+ *
27
+ * Each wrapper project constructs a `CliOptions` value that wires together
28
+ * its package metadata, default configuration, backend-specific argument
29
+ * parsing, environment variable loading, and executor factory. The CLI
30
+ * scaffold uses these to implement the full main-loop without any
31
+ * backend-specific knowledge.
32
+ *
33
+ * @typeParam T - The full configuration type for the wrapper project.
34
+ * Must extend {@link BaseAgentConfig} so that the shared config sections
35
+ * (agentCard, server, session, logging, etc.) are guaranteed to exist.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * import { createCli, type CliOptions } from "@a2a-wrapper/core";
40
+ * import type { AgentConfig } from "./config/types.js";
41
+ *
42
+ * const options: CliOptions<AgentConfig> = {
43
+ * packageName: "a2a-copilot",
44
+ * version: "1.0.0",
45
+ * defaults: DEFAULTS,
46
+ * usage: "Usage: a2a-copilot [options]\n...",
47
+ * parseBackendArgs: (values) => ({ ... }),
48
+ * loadEnvOverrides: () => ({ ... }),
49
+ * executorFactory: (config) => new CopilotExecutor(config),
50
+ * };
51
+ *
52
+ * createCli(options);
53
+ * ```
54
+ */
55
+ export interface CliOptions<T extends BaseAgentConfig<unknown>> {
56
+ /**
57
+ * Package name used in `--help` output and log messages.
58
+ *
59
+ * @example "a2a-copilot"
60
+ */
61
+ packageName: string;
62
+ /**
63
+ * Package version printed by `--version`.
64
+ *
65
+ * @example "1.2.3"
66
+ */
67
+ version: string;
68
+ /**
69
+ * Complete default configuration object with every field populated.
70
+ *
71
+ * This serves as the base layer in the config merge pipeline
72
+ * (defaults ← file ← env ← CLI).
73
+ */
74
+ defaults: Required<T>;
75
+ /**
76
+ * Usage text printed when `--help` is passed.
77
+ *
78
+ * Should include all common and wrapper-specific flags with descriptions
79
+ * and examples.
80
+ */
81
+ usage: string;
82
+ /**
83
+ * Parse wrapper-specific CLI arguments into config overrides.
84
+ *
85
+ * Called after common flags (`--port`, `--hostname`, etc.) have been
86
+ * extracted. The `values` parameter contains the raw parsed values from
87
+ * `node:util/parseArgs`, including both common and extra arg definitions.
88
+ * The callback should return a partial config containing only the
89
+ * backend-specific fields derived from wrapper-specific flags.
90
+ *
91
+ * @param values - Raw parsed argument values from `parseArgs`.
92
+ * @returns Partial configuration with backend-specific overrides.
93
+ */
94
+ parseBackendArgs: (values: Record<string, unknown>) => Partial<T>;
95
+ /**
96
+ * Load wrapper-specific environment variable overrides.
97
+ *
98
+ * Called during config resolution to inject environment-based overrides
99
+ * into the merge pipeline (layer 2: env overrides).
100
+ *
101
+ * @returns Partial configuration with environment-derived overrides.
102
+ */
103
+ loadEnvOverrides: () => Partial<T>;
104
+ /**
105
+ * Factory function that creates the backend-specific executor.
106
+ *
107
+ * Called with the fully resolved configuration after all merge layers
108
+ * have been applied. The returned executor is passed to
109
+ * {@link createA2AServer} for initialization and request handling.
110
+ *
111
+ * @param config - The fully resolved configuration.
112
+ * @returns A new {@link A2AExecutor} instance.
113
+ */
114
+ executorFactory: (config: Required<T>) => A2AExecutor;
115
+ /**
116
+ * Optional server customization options.
117
+ *
118
+ * Passed through to {@link createA2AServer} for protocol version
119
+ * overrides and custom route registration hooks.
120
+ */
121
+ serverOptions?: ServerOptions;
122
+ /**
123
+ * Additional `parseArgs` option definitions for wrapper-specific flags.
124
+ *
125
+ * These are merged with the common flag definitions before calling
126
+ * `node:util/parseArgs`. Keys are flag names (without `--` prefix),
127
+ * values specify the type and optional short alias.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * extraArgDefs: {
132
+ * "cli-url": { type: "string" },
133
+ * "model": { type: "string", short: "m" },
134
+ * "workspace": { type: "string", short: "w" },
135
+ * }
136
+ * ```
137
+ */
138
+ extraArgDefs?: Record<string, {
139
+ type: "string" | "boolean";
140
+ short?: string;
141
+ }>;
142
+ }
143
+ /**
144
+ * Result of parsing common CLI flags via {@link parseCommonArgs}.
145
+ *
146
+ * Contains the config file path (if specified) and a partial config object
147
+ * with overrides derived from the common flags. This type is intentionally
148
+ * generic so that the partial config can be merged with wrapper-specific
149
+ * overrides before being passed to {@link resolveConfig}.
150
+ *
151
+ * @typeParam T - The full configuration type (extends {@link BaseAgentConfig}).
152
+ */
153
+ export interface CommonArgsResult<T extends BaseAgentConfig<unknown>> {
154
+ /** Path to the JSON config file, if `--agent-json` or `--config` was provided. */
155
+ configPath?: string;
156
+ /** Partial config overrides derived from common CLI flags. */
157
+ overrides: Partial<T>;
158
+ }
159
+ /**
160
+ * Extract common CLI overrides from raw parsed argument values.
161
+ *
162
+ * This pure function maps the shared CLI flags (`--port`, `--hostname`,
163
+ * `--advertise-host`, `--agent-name`, `--agent-description`,
164
+ * `--stream-artifacts` / `--no-stream-artifacts`, `--log-level`) into a
165
+ * partial {@link BaseAgentConfig} structure suitable for merging into the
166
+ * config resolution pipeline.
167
+ *
168
+ * Exported separately from {@link createCli} so that property-based tests
169
+ * can validate flag-to-config mapping without triggering the full
170
+ * main-loop side effects (server creation, signal handlers, etc.).
171
+ *
172
+ * @typeParam T - The full configuration type (extends {@link BaseAgentConfig}).
173
+ *
174
+ * @param values - Raw parsed argument values from `node:util/parseArgs`.
175
+ * Expected to contain string/boolean entries keyed by flag name (without
176
+ * the `--` prefix).
177
+ * @returns A {@link CommonArgsResult} with the config file path and
178
+ * partial config overrides.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * import { parseCommonArgs } from "@a2a-wrapper/core";
183
+ *
184
+ * const result = parseCommonArgs({ port: "3001", "agent-name": "Test" });
185
+ * // result.overrides.server?.port === 3001
186
+ * // result.overrides.agentCard?.name === "Test"
187
+ * ```
188
+ */
189
+ export declare function parseCommonArgs<T extends BaseAgentConfig<unknown>>(values: Record<string, unknown>): CommonArgsResult<T>;
190
+ /**
191
+ * Create and run the CLI entry point for an A2A wrapper project.
192
+ *
193
+ * Implements the standard main-loop pattern shared by all wrappers:
194
+ *
195
+ * 1. **Parse arguments** — merges common flag definitions with any
196
+ * wrapper-specific {@link CliOptions.extraArgDefs}, then calls
197
+ * `node:util/parseArgs`. Handles `--help` (print usage, exit 0) and
198
+ * `--version` (print version, exit 0) immediately.
199
+ * 2. **Resolve configuration** — calls {@link parseCommonArgs} for shared
200
+ * flags, {@link CliOptions.parseBackendArgs} for wrapper-specific flags,
201
+ * and {@link CliOptions.loadEnvOverrides} for environment variables.
202
+ * Merges all layers via {@link resolveConfig}: defaults ← file ← env ← CLI.
203
+ * 3. **Set log level** — parses the resolved `logging.level` string and
204
+ * applies it to the root logger.
205
+ * 4. **Create server** — calls {@link createA2AServer} with the resolved
206
+ * config, executor factory, and optional server options.
207
+ * 5. **Register signal handlers** — installs SIGINT and SIGTERM handlers
208
+ * that call `handle.shutdown()` and exit cleanly.
209
+ * 6. **Fatal error handling** — wraps the entire main-loop in a catch
210
+ * that logs the error with stack trace and exits with code 1.
211
+ *
212
+ * @typeParam T - The full configuration type for the wrapper project.
213
+ * Must extend {@link BaseAgentConfig} so that the shared config sections
214
+ * are guaranteed to exist.
215
+ *
216
+ * @param options - CLI configuration specifying package metadata, defaults,
217
+ * argument parsers, and the executor factory.
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * import { createCli } from "@a2a-wrapper/core";
222
+ * import { DEFAULTS } from "./config/defaults.js";
223
+ * import { CopilotExecutor } from "./copilot/executor.js";
224
+ *
225
+ * createCli({
226
+ * packageName: "a2a-copilot",
227
+ * version: "1.0.0",
228
+ * defaults: DEFAULTS,
229
+ * usage: "Usage: a2a-copilot [options]\n...",
230
+ * parseBackendArgs: (values) => { ... },
231
+ * loadEnvOverrides: () => { ... },
232
+ * executorFactory: (config) => new CopilotExecutor(config),
233
+ * });
234
+ * ```
235
+ */
236
+ export declare function createCli<T extends BaseAgentConfig<unknown>>(options: CliOptions<T>): void;
237
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../src/cli/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA6BvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,eAAe,CAAC,OAAO,CAAC;IAC5D;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;;;;;;OAWG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAElE;;;;;;;OAOG;IACH,gBAAgB,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnC;;;;;;;;;OASG;IACH,eAAe,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC;IAEtD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAE9B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/E;AAID;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,eAAe,CAAC,OAAO,CAAC;IAClE,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CACvB;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,eAAe,CAAC,OAAO,CAAC,EAChE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,gBAAgB,CAAC,CAAC,CAAC,CAiDrB;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,eAAe,CAAC,OAAO,CAAC,EAC1D,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GACrB,IAAI,CAuGN"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * CLI Scaffold
3
+ *
4
+ * Provides a reusable, generic CLI entry-point factory for A2A wrapper
5
+ * projects. Each wrapper calls {@link createCli} once with its package
6
+ * metadata, default configuration, backend-specific argument parser, and
7
+ * executor factory. The scaffold handles everything else: common flag
8
+ * parsing, layered config resolution, log-level setup, server creation,
9
+ * and graceful shutdown on SIGINT / SIGTERM.
10
+ *
11
+ * This module is intentionally backend-agnostic. Wrapper-specific flags
12
+ * (e.g. `--cli-url`, `--opencode-url`) are injected via
13
+ * {@link CliOptions.extraArgDefs} and parsed by the wrapper's
14
+ * {@link CliOptions.parseBackendArgs} callback.
15
+ *
16
+ * The exported {@link parseCommonArgs} helper is also available for unit
17
+ * and property-based testing of the common flag parsing logic without
18
+ * triggering the full main-loop side effects.
19
+ *
20
+ * @module cli/scaffold
21
+ */
22
+ import { parseArgs } from "node:util";
23
+ import { resolveConfig } from "../config/loader.js";
24
+ import { createLogger, Logger } from "../utils/logger.js";
25
+ import { createA2AServer } from "../server/factory.js";
26
+ // ─── Common Arg Definitions ────────────────────────────────────────────────
27
+ /**
28
+ * `parseArgs` option definitions for the flags shared across all wrappers.
29
+ *
30
+ * These are merged with any wrapper-specific {@link CliOptions.extraArgDefs}
31
+ * before calling `node:util/parseArgs`.
32
+ *
33
+ * @internal
34
+ */
35
+ const COMMON_ARG_DEFS = {
36
+ "agent-json": { type: "string" },
37
+ config: { type: "string", short: "c" },
38
+ port: { type: "string", short: "p" },
39
+ hostname: { type: "string" },
40
+ "advertise-host": { type: "string" },
41
+ "agent-name": { type: "string" },
42
+ "agent-description": { type: "string" },
43
+ "stream-artifacts": { type: "boolean" },
44
+ "no-stream-artifacts": { type: "boolean" },
45
+ "log-level": { type: "string" },
46
+ help: { type: "boolean", short: "h" },
47
+ version: { type: "boolean", short: "v" },
48
+ };
49
+ // ─── parseCommonArgs ───────────────────────────────────────────────────────
50
+ /**
51
+ * Extract common CLI overrides from raw parsed argument values.
52
+ *
53
+ * This pure function maps the shared CLI flags (`--port`, `--hostname`,
54
+ * `--advertise-host`, `--agent-name`, `--agent-description`,
55
+ * `--stream-artifacts` / `--no-stream-artifacts`, `--log-level`) into a
56
+ * partial {@link BaseAgentConfig} structure suitable for merging into the
57
+ * config resolution pipeline.
58
+ *
59
+ * Exported separately from {@link createCli} so that property-based tests
60
+ * can validate flag-to-config mapping without triggering the full
61
+ * main-loop side effects (server creation, signal handlers, etc.).
62
+ *
63
+ * @typeParam T - The full configuration type (extends {@link BaseAgentConfig}).
64
+ *
65
+ * @param values - Raw parsed argument values from `node:util/parseArgs`.
66
+ * Expected to contain string/boolean entries keyed by flag name (without
67
+ * the `--` prefix).
68
+ * @returns A {@link CommonArgsResult} with the config file path and
69
+ * partial config overrides.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { parseCommonArgs } from "@a2a-wrapper/core";
74
+ *
75
+ * const result = parseCommonArgs({ port: "3001", "agent-name": "Test" });
76
+ * // result.overrides.server?.port === 3001
77
+ * // result.overrides.agentCard?.name === "Test"
78
+ * ```
79
+ */
80
+ export function parseCommonArgs(values) {
81
+ const overrides = {};
82
+ // Config file path (--agent-json or --config)
83
+ const configPath = (values["agent-json"] ?? values["config"]);
84
+ // Server overrides
85
+ const port = values["port"];
86
+ const hostname = values["hostname"];
87
+ const advertiseHost = values["advertise-host"];
88
+ if (port !== undefined || hostname !== undefined || advertiseHost !== undefined) {
89
+ const server = {};
90
+ if (port !== undefined)
91
+ server.port = parseInt(port, 10);
92
+ if (hostname !== undefined)
93
+ server.hostname = hostname;
94
+ if (advertiseHost !== undefined)
95
+ server.advertiseHost = advertiseHost;
96
+ overrides.server = server;
97
+ }
98
+ // Agent card overrides
99
+ const agentName = values["agent-name"];
100
+ const agentDescription = values["agent-description"];
101
+ if (agentName !== undefined || agentDescription !== undefined) {
102
+ const agentCard = {};
103
+ if (agentName !== undefined)
104
+ agentCard.name = agentName;
105
+ if (agentDescription !== undefined)
106
+ agentCard.description = agentDescription;
107
+ overrides.agentCard = agentCard;
108
+ }
109
+ // Feature flag overrides
110
+ const streamArtifacts = values["stream-artifacts"];
111
+ const noStreamArtifacts = values["no-stream-artifacts"];
112
+ const features = {};
113
+ if (streamArtifacts === true)
114
+ features.streamArtifactChunks = true;
115
+ if (noStreamArtifacts === true)
116
+ features.streamArtifactChunks = false;
117
+ if (Object.keys(features).length > 0) {
118
+ overrides.features = features;
119
+ }
120
+ // Logging overrides
121
+ const logLevel = values["log-level"];
122
+ if (logLevel !== undefined) {
123
+ overrides.logging = { level: logLevel };
124
+ }
125
+ return { configPath, overrides: overrides };
126
+ }
127
+ // ─── createCli ─────────────────────────────────────────────────────────────
128
+ /**
129
+ * Create and run the CLI entry point for an A2A wrapper project.
130
+ *
131
+ * Implements the standard main-loop pattern shared by all wrappers:
132
+ *
133
+ * 1. **Parse arguments** — merges common flag definitions with any
134
+ * wrapper-specific {@link CliOptions.extraArgDefs}, then calls
135
+ * `node:util/parseArgs`. Handles `--help` (print usage, exit 0) and
136
+ * `--version` (print version, exit 0) immediately.
137
+ * 2. **Resolve configuration** — calls {@link parseCommonArgs} for shared
138
+ * flags, {@link CliOptions.parseBackendArgs} for wrapper-specific flags,
139
+ * and {@link CliOptions.loadEnvOverrides} for environment variables.
140
+ * Merges all layers via {@link resolveConfig}: defaults ← file ← env ← CLI.
141
+ * 3. **Set log level** — parses the resolved `logging.level` string and
142
+ * applies it to the root logger.
143
+ * 4. **Create server** — calls {@link createA2AServer} with the resolved
144
+ * config, executor factory, and optional server options.
145
+ * 5. **Register signal handlers** — installs SIGINT and SIGTERM handlers
146
+ * that call `handle.shutdown()` and exit cleanly.
147
+ * 6. **Fatal error handling** — wraps the entire main-loop in a catch
148
+ * that logs the error with stack trace and exits with code 1.
149
+ *
150
+ * @typeParam T - The full configuration type for the wrapper project.
151
+ * Must extend {@link BaseAgentConfig} so that the shared config sections
152
+ * are guaranteed to exist.
153
+ *
154
+ * @param options - CLI configuration specifying package metadata, defaults,
155
+ * argument parsers, and the executor factory.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * import { createCli } from "@a2a-wrapper/core";
160
+ * import { DEFAULTS } from "./config/defaults.js";
161
+ * import { CopilotExecutor } from "./copilot/executor.js";
162
+ *
163
+ * createCli({
164
+ * packageName: "a2a-copilot",
165
+ * version: "1.0.0",
166
+ * defaults: DEFAULTS,
167
+ * usage: "Usage: a2a-copilot [options]\n...",
168
+ * parseBackendArgs: (values) => { ... },
169
+ * loadEnvOverrides: () => { ... },
170
+ * executorFactory: (config) => new CopilotExecutor(config),
171
+ * });
172
+ * ```
173
+ */
174
+ export function createCli(options) {
175
+ const { packageName, version, defaults, usage, parseBackendArgs, loadEnvOverrides, executorFactory, serverOptions, extraArgDefs, } = options;
176
+ const logger = createLogger(packageName);
177
+ const log = logger.child("cli");
178
+ // ── Async main loop ───────────────────────────────────────────────────
179
+ async function main() {
180
+ // 1. Parse CLI arguments
181
+ const allArgDefs = { ...COMMON_ARG_DEFS, ...extraArgDefs };
182
+ const { values } = parseArgs({
183
+ options: allArgDefs,
184
+ strict: false,
185
+ });
186
+ // Handle --help
187
+ if (values.help) {
188
+ console.log(usage);
189
+ process.exit(0);
190
+ }
191
+ // Handle --version
192
+ if (values.version) {
193
+ console.log(version);
194
+ process.exit(0);
195
+ }
196
+ // 2. Build config overrides from common + backend args
197
+ const commonResult = parseCommonArgs(values);
198
+ const backendOverrides = parseBackendArgs(values);
199
+ // Merge common overrides with backend overrides for the CLI layer
200
+ const cliOverrides = {
201
+ ...commonResult.overrides,
202
+ ...backendOverrides,
203
+ };
204
+ // Load environment variable overrides
205
+ const envOverrides = loadEnvOverrides();
206
+ // 3. Resolve config: defaults ← file ← env ← CLI
207
+ const config = resolveConfig(defaults, commonResult.configPath, envOverrides, cliOverrides);
208
+ // 4. Set log level
209
+ const levelStr = config.logging?.level ?? "info";
210
+ logger.setLevel(Logger.parseLevel(levelStr));
211
+ if (!commonResult.configPath) {
212
+ log.info("No --agent-json provided — running with built-in defaults. " +
213
+ "Pass --agent-json <path> to load a custom agent.");
214
+ }
215
+ log.info(`Starting ${packageName}`, {
216
+ config: commonResult.configPath ?? "(built-in defaults)",
217
+ agent: config.agentCard?.name,
218
+ port: config.server?.port,
219
+ });
220
+ // 5. Create and start the A2A server
221
+ const handle = await createA2AServer(config, executorFactory, serverOptions);
222
+ // 6. Register graceful shutdown handlers
223
+ const shutdown = async (signal) => {
224
+ log.info(`${signal} received, shutting down...`);
225
+ await handle.shutdown();
226
+ process.exit(0);
227
+ };
228
+ process.on("SIGINT", () => shutdown("SIGINT"));
229
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
230
+ }
231
+ // Fatal error handler — log with stack trace and exit 1
232
+ main().catch((err) => {
233
+ const error = err instanceof Error ? err : new Error(String(err));
234
+ log.error("Fatal error", {
235
+ error: error.message,
236
+ stack: error.stack,
237
+ });
238
+ process.exit(1);
239
+ });
240
+ }
241
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/cli/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,EAAY,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,eAAe,GAAmE;IACtF,YAAY,EAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,MAAM,EAAiB,EAAE,IAAI,EAAE,QAAQ,EAAG,KAAK,EAAE,GAAG,EAAE;IACtD,IAAI,EAAmB,EAAE,IAAI,EAAE,QAAQ,EAAG,KAAK,EAAE,GAAG,EAAE;IACtD,QAAQ,EAAe,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,gBAAgB,EAAO,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,YAAY,EAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,mBAAmB,EAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,kBAAkB,EAAK,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1C,qBAAqB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1C,WAAW,EAAY,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzC,IAAI,EAAmB,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACtD,OAAO,EAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;CACvD,CAAC;AAoJF,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,eAAe,CAC7B,MAA+B;IAE/B,MAAM,SAAS,GAA4B,EAAE,CAAC;IAE9C,8CAA8C;IAC9C,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAuB,CAAC;IAEpF,mBAAmB;IACnB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAuB,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAuB,CAAC;IAC1D,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAuB,CAAC;IAErE,IAAI,IAAI,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChF,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACvD,IAAI,aAAa,KAAK,SAAS;YAAE,MAAM,CAAC,aAAa,GAAG,aAAa,CAAC;QACtE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC;IAC5B,CAAC;IAED,uBAAuB;IACvB,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAuB,CAAC;IAC7D,MAAM,gBAAgB,GAAG,MAAM,CAAC,mBAAmB,CAAuB,CAAC;IAE3E,IAAI,SAAS,KAAK,SAAS,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAC9D,MAAM,SAAS,GAA4B,EAAE,CAAC;QAC9C,IAAI,SAAS,KAAK,SAAS;YAAE,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC;QACxD,IAAI,gBAAgB,KAAK,SAAS;YAAE,SAAS,CAAC,WAAW,GAAG,gBAAgB,CAAC;QAC7E,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC;IAClC,CAAC;IAED,yBAAyB;IACzB,MAAM,eAAe,GAAG,MAAM,CAAC,kBAAkB,CAAwB,CAAC;IAC1E,MAAM,iBAAiB,GAAG,MAAM,CAAC,qBAAqB,CAAwB,CAAC;IAE/E,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,IAAI,eAAe,KAAK,IAAI;QAAE,QAAQ,CAAC,oBAAoB,GAAG,IAAI,CAAC;IACnE,IAAI,iBAAiB,KAAK,IAAI;QAAE,QAAQ,CAAC,oBAAoB,GAAG,KAAK,CAAC;IAEtE,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAChC,CAAC;IAED,oBAAoB;IACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAuB,CAAC;IAC3D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,SAAS,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAuB,EAAE,CAAC;AAC5D,CAAC;AAED,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,UAAU,SAAS,CACvB,OAAsB;IAEtB,MAAM,EACJ,WAAW,EACX,OAAO,EACP,QAAQ,EACR,KAAK,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,YAAY,GACb,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAW,YAAY,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,GAAG,GAAW,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAExC,yEAAyE;IACzE,KAAK,UAAU,IAAI;QACjB,yBAAyB;QACzB,MAAM,UAAU,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,YAAY,EAAE,CAAC;QAE3D,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;YAC3B,OAAO,EAAE,UAAU;YACnB,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,gBAAgB;QAChB,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,mBAAmB;QACnB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,uDAAuD;QACvD,MAAM,YAAY,GAAG,eAAe,CAAI,MAAiC,CAAC,CAAC;QAC3E,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAiC,CAAC,CAAC;QAE7E,kEAAkE;QAClE,MAAM,YAAY,GAAe;YAC/B,GAAG,YAAY,CAAC,SAAS;YACzB,GAAG,gBAAgB;SACpB,CAAC;QAEF,sCAAsC;QACtC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;QAExC,iDAAiD;QACjD,MAAM,MAAM,GAAG,aAAa,CAC1B,QAAQ,EACR,YAAY,CAAC,UAAU,EACvB,YAAY,EACZ,YAAY,CACb,CAAC;QAEF,mBAAmB;QACnB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,MAAM,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;YAC7B,GAAG,CAAC,IAAI,CACN,6DAA6D;gBAC7D,kDAAkD,CACnD,CAAC;QACJ,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,YAAY,WAAW,EAAE,EAAE;YAClC,MAAM,EAAE,YAAY,CAAC,UAAU,IAAI,qBAAqB;YACxD,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI;YAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI;SAC1B,CAAC,CAAC;QAEH,qCAAqC;QACrC,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC,MAAM,EACN,eAAe,EACf,aAAa,CACd,CAAC;QAEF,yCAAyC;QACzC,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;YACvD,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,6BAA6B,CAAC,CAAC;YACjD,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,wDAAwD;IACxD,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE;YACvB,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}