@stdiobus/workers-registry 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +932 -0
- package/out/dist/workers/acp-registry/registry-launcher-client.js +52 -0
- package/out/dist/workers/acp-registry/registry-launcher-client.js.map +7 -0
- package/out/dist/workers/acp-registry/registry-launcher-config.json +31 -0
- package/out/dist/workers/acp-worker/index.js +5 -0
- package/out/dist/workers/acp-worker/index.js.map +7 -0
- package/out/dist/workers/echo-worker/echo-worker-config.json +21 -0
- package/out/dist/workers/echo-worker/echo-worker.js +3 -0
- package/out/dist/workers/echo-worker/echo-worker.js.map +7 -0
- package/out/dist/workers/index.d.ts +15 -0
- package/out/dist/workers/index.js +33 -0
- package/out/dist/workers/mcp-echo-server/index.js +3 -0
- package/out/dist/workers/mcp-echo-server/index.js.map +7 -0
- package/out/dist/workers/mcp-echo-server/mcp-echo-server-config.json +21 -0
- package/out/dist/workers/mcp-to-acp-proxy/proxy.js +3 -0
- package/out/dist/workers/mcp-to-acp-proxy/proxy.js.map +7 -0
- package/out/tsc/workers/acp-worker/src/acp/client-capabilities.d.ts +131 -0
- package/out/tsc/workers/acp-worker/src/acp/content-mapper.d.ts +95 -0
- package/out/tsc/workers/acp-worker/src/acp/index.d.ts +13 -0
- package/out/tsc/workers/acp-worker/src/acp/tools.d.ts +119 -0
- package/out/tsc/workers/acp-worker/src/agent.d.ts +113 -0
- package/out/tsc/workers/acp-worker/src/index.d.ts +1 -0
- package/out/tsc/workers/acp-worker/src/mcp/connection.d.ts +54 -0
- package/out/tsc/workers/acp-worker/src/mcp/index.d.ts +10 -0
- package/out/tsc/workers/acp-worker/src/mcp/manager.d.ts +178 -0
- package/out/tsc/workers/acp-worker/src/mcp/types.d.ts +114 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/connection.d.ts +80 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/converter.d.ts +156 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/index.d.ts +2 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/state.d.ts +165 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/types.d.ts +163 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/api-keys.d.ts +41 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/config.d.ts +17 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/index.d.ts +10 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/types.d.ts +15 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/index.d.ts +2 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/log.d.ts +77 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/index.d.ts +109 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/resolver.d.ts +67 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/types.d.ts +105 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/router/index.d.ts +8 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/router/message-router.d.ts +150 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/agent-runtime.d.ts +58 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/index.d.ts +11 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/manager.d.ts +82 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/types.d.ts +20 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/stream/index.d.ts +8 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/stream/ndjson-handler.d.ts +119 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/test-utils/index.d.ts +234 -0
- package/out/tsc/workers/acp-worker/src/session/index.d.ts +12 -0
- package/out/tsc/workers/acp-worker/src/session/manager.d.ts +63 -0
- package/out/tsc/workers/acp-worker/src/session/session.d.ts +86 -0
- package/out/tsc/workers/acp-worker/src/session/types.d.ts +33 -0
- package/out/tsc/workers/acp-worker/src/test-utils/test-harness.d.ts +80 -0
- package/out/tsc/workers/mcp-echo-server/mcp-echo-server.d.ts +2 -0
- package/package.json +77 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Router for the Registry Launcher.
|
|
3
|
+
*
|
|
4
|
+
* Routes incoming JSON-RPC messages to the appropriate agent based on agentId.
|
|
5
|
+
* Handles agentId extraction, message transformation, and error response generation.
|
|
6
|
+
*
|
|
7
|
+
* @module router/message-router
|
|
8
|
+
*/
|
|
9
|
+
import type { IRegistryIndex } from '../registry/index.js';
|
|
10
|
+
import type { AgentRuntimeManager } from '../runtime/manager.js';
|
|
11
|
+
/**
|
|
12
|
+
* JSON-RPC error codes for routing errors.
|
|
13
|
+
*/
|
|
14
|
+
export declare const RoutingErrorCodes: {
|
|
15
|
+
/** Missing agentId in request */
|
|
16
|
+
readonly MISSING_AGENT_ID: -32600;
|
|
17
|
+
/** Agent not found in registry */
|
|
18
|
+
readonly AGENT_NOT_FOUND: -32001;
|
|
19
|
+
/** Platform not supported for binary distribution */
|
|
20
|
+
readonly PLATFORM_NOT_SUPPORTED: -32002;
|
|
21
|
+
/** Agent spawn failed */
|
|
22
|
+
readonly SPAWN_FAILED: -32003;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* JSON-RPC error response structure.
|
|
26
|
+
*/
|
|
27
|
+
export interface ErrorResponse {
|
|
28
|
+
jsonrpc: '2.0';
|
|
29
|
+
id: string | number | null;
|
|
30
|
+
error: {
|
|
31
|
+
code: number;
|
|
32
|
+
message: string;
|
|
33
|
+
data?: unknown;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Callback type for writing responses to stdout.
|
|
38
|
+
*/
|
|
39
|
+
export type WriteCallback = (message: object) => boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Create a JSON-RPC error response.
|
|
42
|
+
*
|
|
43
|
+
* @param id - Request ID (null for notifications or unknown)
|
|
44
|
+
* @param code - Error code
|
|
45
|
+
* @param message - Error message
|
|
46
|
+
* @param data - Optional additional error data
|
|
47
|
+
* @returns Error response object
|
|
48
|
+
*/
|
|
49
|
+
export declare function createErrorResponse(id: string | number | null, code: number, message: string, data?: unknown): ErrorResponse;
|
|
50
|
+
/**
|
|
51
|
+
* Extract the agentId field from a message.
|
|
52
|
+
*
|
|
53
|
+
* @param message - The message object to extract from
|
|
54
|
+
* @returns The agentId string or undefined if not present
|
|
55
|
+
*/
|
|
56
|
+
export declare function extractAgentId(message: object): string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Extract the JSON-RPC id field from a message.
|
|
59
|
+
*
|
|
60
|
+
* @param message - The message object to extract from
|
|
61
|
+
* @returns The id (string, number, or null)
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractId(message: object): string | number | null;
|
|
64
|
+
/**
|
|
65
|
+
* Transform a message for forwarding to an agent.
|
|
66
|
+
*
|
|
67
|
+
* Removes the agentId field while preserving all other fields.
|
|
68
|
+
*
|
|
69
|
+
* @param message - The original message
|
|
70
|
+
* @returns A new message object without the agentId field
|
|
71
|
+
*/
|
|
72
|
+
export declare function transformMessage(message: object): object;
|
|
73
|
+
/**
|
|
74
|
+
* Message Router implementation.
|
|
75
|
+
*
|
|
76
|
+
* Routes incoming JSON-RPC messages to the appropriate agent based on agentId.
|
|
77
|
+
* Handles message transformation, error generation, and request correlation.
|
|
78
|
+
*/
|
|
79
|
+
export declare class MessageRouter {
|
|
80
|
+
/** Registry index for agent lookup and resolution */
|
|
81
|
+
private readonly registry;
|
|
82
|
+
/** Runtime manager for agent process lifecycle */
|
|
83
|
+
private readonly runtimeManager;
|
|
84
|
+
/** Callback for writing responses to stdout */
|
|
85
|
+
private readonly writeCallback;
|
|
86
|
+
/** API keys for agent authentication */
|
|
87
|
+
private readonly apiKeys;
|
|
88
|
+
/** Map of request ID to pending request info for correlation */
|
|
89
|
+
private readonly pendingRequests;
|
|
90
|
+
/** Map of agent ID to authentication state */
|
|
91
|
+
private readonly authState;
|
|
92
|
+
/** Map of agent sessionId to client sessionId for notification routing */
|
|
93
|
+
private readonly sessionIdMap;
|
|
94
|
+
/**
|
|
95
|
+
* Create a new MessageRouter.
|
|
96
|
+
*
|
|
97
|
+
* @param registry - Registry index for agent lookup
|
|
98
|
+
* @param runtimeManager - Runtime manager for agent processes
|
|
99
|
+
* @param writeCallback - Callback for writing responses to stdout
|
|
100
|
+
* @param apiKeys - API keys for agent authentication (optional)
|
|
101
|
+
*/
|
|
102
|
+
constructor(registry: IRegistryIndex, runtimeManager: AgentRuntimeManager, writeCallback: WriteCallback, apiKeys?: Record<string, any>);
|
|
103
|
+
/**
|
|
104
|
+
* Route an incoming message to the appropriate agent.
|
|
105
|
+
*
|
|
106
|
+
* Extracts agentId, resolves spawn command, and forwards message.
|
|
107
|
+
*
|
|
108
|
+
* @param message - The incoming JSON-RPC message
|
|
109
|
+
* @returns Error response if routing fails, undefined on success
|
|
110
|
+
*/
|
|
111
|
+
route(message: object): Promise<ErrorResponse | undefined>;
|
|
112
|
+
/**
|
|
113
|
+
* Handle a response from an agent process.
|
|
114
|
+
*
|
|
115
|
+
* Intercepts initialize responses to trigger automatic authentication.
|
|
116
|
+
* Tracks sessionId mapping for proper notification routing.
|
|
117
|
+
* Forwards all responses to stdout.
|
|
118
|
+
*
|
|
119
|
+
* @param agentId - The agent that sent the response
|
|
120
|
+
* @param response - The response object from the agent
|
|
121
|
+
*/
|
|
122
|
+
handleAgentResponse(agentId: string, response: object): void;
|
|
123
|
+
/**
|
|
124
|
+
* Attempt automatic authentication for an agent.
|
|
125
|
+
*
|
|
126
|
+
* Selects the best authentication method and sends authenticate request.
|
|
127
|
+
*
|
|
128
|
+
* @param agentId - The agent to authenticate
|
|
129
|
+
* @param authMethods - Available authentication methods from initialize response
|
|
130
|
+
*/
|
|
131
|
+
private attemptAuthentication;
|
|
132
|
+
/**
|
|
133
|
+
* Get the number of pending requests.
|
|
134
|
+
*
|
|
135
|
+
* @returns The count of pending requests
|
|
136
|
+
*/
|
|
137
|
+
get pendingCount(): number;
|
|
138
|
+
/**
|
|
139
|
+
* Check if a request ID is pending.
|
|
140
|
+
*
|
|
141
|
+
* @param id - The request ID to check
|
|
142
|
+
* @returns true if the request is pending, false otherwise
|
|
143
|
+
*/
|
|
144
|
+
isPending(id: string | number): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Clear all pending requests.
|
|
147
|
+
* Useful for cleanup during shutdown.
|
|
148
|
+
*/
|
|
149
|
+
clearPending(): void;
|
|
150
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
import type { AgentRuntime, RuntimeState } from './types.js';
|
|
3
|
+
import type { SpawnCommand } from '../registry/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Implementation of AgentRuntime that manages a spawned agent process.
|
|
6
|
+
*
|
|
7
|
+
* Handles process spawning with non-blocking file descriptors,
|
|
8
|
+
* message writing to stdin, and graceful termination with SIGTERM/SIGKILL.
|
|
9
|
+
*/
|
|
10
|
+
export declare class AgentRuntimeImpl implements AgentRuntime {
|
|
11
|
+
readonly agentId: string;
|
|
12
|
+
state: RuntimeState;
|
|
13
|
+
readonly process: ChildProcess;
|
|
14
|
+
private readonly onExitCallback?;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new AgentRuntime by spawning a process.
|
|
17
|
+
*
|
|
18
|
+
* @param agentId - The agent identifier
|
|
19
|
+
* @param spawnCommand - The resolved spawn command
|
|
20
|
+
* @param onExit - Optional callback when process exits
|
|
21
|
+
*/
|
|
22
|
+
private constructor();
|
|
23
|
+
/**
|
|
24
|
+
* Spawn a new agent process and create an AgentRuntime instance.
|
|
25
|
+
*
|
|
26
|
+
* @param agentId - The agent identifier
|
|
27
|
+
* @param spawnCommand - The resolved spawn command with command, args, and optional env
|
|
28
|
+
* @param onExit - Optional callback when process exits
|
|
29
|
+
* @returns A new AgentRuntime instance
|
|
30
|
+
*/
|
|
31
|
+
static spawn(agentId: string, spawnCommand: SpawnCommand, onExit?: (code: number | null, signal: string | null) => void): AgentRuntimeImpl;
|
|
32
|
+
/**
|
|
33
|
+
* Set up event handlers for the child process.
|
|
34
|
+
*/
|
|
35
|
+
private setupProcessHandlers;
|
|
36
|
+
/**
|
|
37
|
+
* Write a message to the agent's stdin as NDJSON.
|
|
38
|
+
*
|
|
39
|
+
* @param message - The message object to send
|
|
40
|
+
* @returns true if the write was accepted, false if backpressure or error
|
|
41
|
+
*/
|
|
42
|
+
write(message: object): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Terminate the agent process gracefully.
|
|
45
|
+
*
|
|
46
|
+
* Sends SIGTERM first, then SIGKILL after timeout if process doesn't exit.
|
|
47
|
+
*
|
|
48
|
+
* @param timeout - Timeout in milliseconds before SIGKILL (default: 5000ms)
|
|
49
|
+
* @returns Promise that resolves when process has exited
|
|
50
|
+
*/
|
|
51
|
+
terminate(timeout?: number): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Wait for the process to exit.
|
|
54
|
+
*
|
|
55
|
+
* @returns Promise that resolves when process exits
|
|
56
|
+
*/
|
|
57
|
+
private waitForExit;
|
|
58
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime module barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the public API for agent runtime management.
|
|
5
|
+
*
|
|
6
|
+
* @module runtime
|
|
7
|
+
*/
|
|
8
|
+
export type { RuntimeState, AgentRuntime } from './types.js';
|
|
9
|
+
export { AgentRuntimeImpl } from './agent-runtime.js';
|
|
10
|
+
export { AgentRuntimeManager } from './manager.js';
|
|
11
|
+
export type { AgentExitCallback } from './manager.js';
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { AgentRuntime } from './types.js';
|
|
2
|
+
import type { SpawnCommand } from '../registry/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Callback type for agent exit events.
|
|
5
|
+
*/
|
|
6
|
+
export type AgentExitCallback = (agentId: string, code: number | null) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Manager for agent runtime lifecycle.
|
|
9
|
+
*
|
|
10
|
+
* Handles spawning, tracking, and terminating agent processes.
|
|
11
|
+
* Stores runtimes in a Map keyed by agentId.
|
|
12
|
+
*/
|
|
13
|
+
export declare class AgentRuntimeManager {
|
|
14
|
+
/** Map of agentId to AgentRuntime instances */
|
|
15
|
+
private readonly runtimes;
|
|
16
|
+
/** Registered callbacks for agent exit events */
|
|
17
|
+
private readonly exitCallbacks;
|
|
18
|
+
/**
|
|
19
|
+
* Get an existing runtime or spawn a new one for the given agentId.
|
|
20
|
+
*
|
|
21
|
+
* If a runtime already exists for the agentId, returns it.
|
|
22
|
+
* Otherwise, spawns a new agent process using the provided spawn command.
|
|
23
|
+
*
|
|
24
|
+
* @param agentId - The agent identifier
|
|
25
|
+
* @param spawnCommand - The resolved spawn command for spawning a new process
|
|
26
|
+
* @returns The existing or newly spawned AgentRuntime
|
|
27
|
+
*/
|
|
28
|
+
getOrSpawn(agentId: string, spawnCommand: SpawnCommand): Promise<AgentRuntime>;
|
|
29
|
+
/**
|
|
30
|
+
* Get an existing runtime without spawning.
|
|
31
|
+
*
|
|
32
|
+
* @param agentId - The agent identifier
|
|
33
|
+
* @returns The AgentRuntime if it exists, undefined otherwise
|
|
34
|
+
*/
|
|
35
|
+
get(agentId: string): AgentRuntime | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Terminate a specific agent runtime.
|
|
38
|
+
*
|
|
39
|
+
* Sends SIGTERM to the agent process and waits for it to exit.
|
|
40
|
+
* If the process doesn't exit within the timeout, sends SIGKILL.
|
|
41
|
+
*
|
|
42
|
+
* @param agentId - The agent identifier
|
|
43
|
+
* @param timeout - Timeout in milliseconds before SIGKILL (default: 5000ms)
|
|
44
|
+
*/
|
|
45
|
+
terminate(agentId: string, timeout?: number): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Terminate all agent runtimes for graceful shutdown.
|
|
48
|
+
*
|
|
49
|
+
* @param timeout - Timeout in milliseconds before SIGKILL (default: 5000ms)
|
|
50
|
+
*/
|
|
51
|
+
terminateAll(timeout?: number): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Register a callback for agent exit events.
|
|
54
|
+
*
|
|
55
|
+
* The callback is invoked when an agent process exits unexpectedly.
|
|
56
|
+
*
|
|
57
|
+
* @param callback - Function to call when an agent exits
|
|
58
|
+
*/
|
|
59
|
+
onAgentExit(callback: AgentExitCallback): void;
|
|
60
|
+
/**
|
|
61
|
+
* Handle agent process exit.
|
|
62
|
+
*
|
|
63
|
+
* Removes the runtime from the map and notifies registered callbacks.
|
|
64
|
+
*
|
|
65
|
+
* @param agentId - The agent identifier
|
|
66
|
+
* @param code - The exit code (null if terminated by signal)
|
|
67
|
+
*/
|
|
68
|
+
private handleAgentExit;
|
|
69
|
+
/**
|
|
70
|
+
* Get the number of active runtimes.
|
|
71
|
+
*
|
|
72
|
+
* @returns The count of runtimes currently in the map
|
|
73
|
+
*/
|
|
74
|
+
get size(): number;
|
|
75
|
+
/**
|
|
76
|
+
* Check if a runtime exists for the given agentId.
|
|
77
|
+
*
|
|
78
|
+
* @param agentId - The agent identifier
|
|
79
|
+
* @returns true if a runtime exists, false otherwise
|
|
80
|
+
*/
|
|
81
|
+
has(agentId: string): boolean;
|
|
82
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ChildProcess } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* State of an agent runtime.
|
|
4
|
+
*/
|
|
5
|
+
export type RuntimeState = 'starting' | 'running' | 'stopping' | 'stopped';
|
|
6
|
+
/**
|
|
7
|
+
* Agent runtime representing a spawned agent process.
|
|
8
|
+
*/
|
|
9
|
+
export interface AgentRuntime {
|
|
10
|
+
/** Agent identifier */
|
|
11
|
+
agentId: string;
|
|
12
|
+
/** Current state */
|
|
13
|
+
state: RuntimeState;
|
|
14
|
+
/** Child process reference */
|
|
15
|
+
process: ChildProcess;
|
|
16
|
+
/** Write a message to the agent's stdin */
|
|
17
|
+
write(message: object): boolean;
|
|
18
|
+
/** Terminate the agent process */
|
|
19
|
+
terminate(timeout?: number): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NDJSON (Newline-Delimited JSON) stream handler for the Registry Launcher.
|
|
3
|
+
*
|
|
4
|
+
* Handles buffering and parsing of NDJSON messages from stdin and writing
|
|
5
|
+
* NDJSON messages to stdout. Supports partial reads across multiple chunks.
|
|
6
|
+
*
|
|
7
|
+
* @module stream/ndjson-handler
|
|
8
|
+
*/
|
|
9
|
+
import { Writable } from 'node:stream';
|
|
10
|
+
/**
|
|
11
|
+
* Callback type for parsed messages.
|
|
12
|
+
*/
|
|
13
|
+
export type MessageCallback = (message: object) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Callback type for parse errors.
|
|
16
|
+
*/
|
|
17
|
+
export type ErrorCallback = (error: Error, line: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Interface for NDJSON stream handling.
|
|
20
|
+
*/
|
|
21
|
+
export interface INDJSONHandler {
|
|
22
|
+
/**
|
|
23
|
+
* Register a callback for parsed messages.
|
|
24
|
+
*/
|
|
25
|
+
onMessage(callback: MessageCallback): void;
|
|
26
|
+
/**
|
|
27
|
+
* Register a callback for parse errors.
|
|
28
|
+
*/
|
|
29
|
+
onError(callback: ErrorCallback): void;
|
|
30
|
+
/**
|
|
31
|
+
* Write a message to the output stream.
|
|
32
|
+
* @returns true if write was successful, false if stream is not writable
|
|
33
|
+
*/
|
|
34
|
+
write(message: object): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Process incoming data chunk (call from stdin 'data' event).
|
|
37
|
+
*/
|
|
38
|
+
processChunk(chunk: Buffer): void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* NDJSON stream handler implementation.
|
|
42
|
+
*
|
|
43
|
+
* This class handles:
|
|
44
|
+
* - Buffering incoming data until complete newline-delimited messages are received
|
|
45
|
+
* - Handling partial JSON messages that span multiple read operations
|
|
46
|
+
* - Appending newline characters after each JSON message when writing
|
|
47
|
+
* - Splitting on newline boundaries when reading
|
|
48
|
+
* - Logging errors and skipping malformed lines
|
|
49
|
+
*/
|
|
50
|
+
export declare class NDJSONHandler implements INDJSONHandler {
|
|
51
|
+
/** Buffer for accumulating partial data */
|
|
52
|
+
private buffer;
|
|
53
|
+
/** Output stream for writing messages */
|
|
54
|
+
private readonly output;
|
|
55
|
+
/** Registered message callback */
|
|
56
|
+
private messageCallback;
|
|
57
|
+
/** Registered error callback */
|
|
58
|
+
private errorCallback;
|
|
59
|
+
/**
|
|
60
|
+
* Create a new NDJSONHandler.
|
|
61
|
+
* @param output - Writable stream for output (typically process.stdout)
|
|
62
|
+
*/
|
|
63
|
+
constructor(output: Writable);
|
|
64
|
+
/**
|
|
65
|
+
* Register a callback for parsed messages.
|
|
66
|
+
* Only one callback can be registered at a time.
|
|
67
|
+
*
|
|
68
|
+
* @param callback - Function to call with each parsed message
|
|
69
|
+
*/
|
|
70
|
+
onMessage(callback: MessageCallback): void;
|
|
71
|
+
/**
|
|
72
|
+
* Register a callback for parse errors.
|
|
73
|
+
* Only one callback can be registered at a time.
|
|
74
|
+
*
|
|
75
|
+
* @param callback - Function to call with parse errors
|
|
76
|
+
*/
|
|
77
|
+
onError(callback: ErrorCallback): void;
|
|
78
|
+
/**
|
|
79
|
+
* Write a message to the output stream.
|
|
80
|
+
*
|
|
81
|
+
* Serializes the message as JSON and appends a newline character.
|
|
82
|
+
*
|
|
83
|
+
* @param message - Object to serialize and write
|
|
84
|
+
* @returns true if write was successful, false if stream is not writable
|
|
85
|
+
*/
|
|
86
|
+
write(message: object): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Process incoming data chunk.
|
|
89
|
+
*
|
|
90
|
+
* Buffers data and emits complete messages when newline boundaries are found.
|
|
91
|
+
* Handles partial messages that span multiple chunks.
|
|
92
|
+
*
|
|
93
|
+
* @param chunk - Buffer containing incoming data
|
|
94
|
+
*/
|
|
95
|
+
processChunk(chunk: Buffer): void;
|
|
96
|
+
/**
|
|
97
|
+
* Process the internal buffer, extracting and parsing complete lines.
|
|
98
|
+
*
|
|
99
|
+
* Splits on newline boundaries and parses each complete line as JSON.
|
|
100
|
+
* Incomplete lines remain in the buffer for the next chunk.
|
|
101
|
+
*/
|
|
102
|
+
private processBuffer;
|
|
103
|
+
/**
|
|
104
|
+
* Parse a single line as JSON and emit the message.
|
|
105
|
+
*
|
|
106
|
+
* If parsing fails, logs the error and invokes the error callback.
|
|
107
|
+
* Malformed lines are skipped.
|
|
108
|
+
*
|
|
109
|
+
* @param line - Line to parse as JSON
|
|
110
|
+
*/
|
|
111
|
+
private parseLine;
|
|
112
|
+
/**
|
|
113
|
+
* Truncate a line for logging purposes.
|
|
114
|
+
* @param line - Line to truncate
|
|
115
|
+
* @param maxLength - Maximum length (default: 100)
|
|
116
|
+
* @returns Truncated line with ellipsis if needed
|
|
117
|
+
*/
|
|
118
|
+
private truncateLine;
|
|
119
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Utilities for Registry Launcher
|
|
3
|
+
*
|
|
4
|
+
* Provides mock implementations and test helpers for unit and integration testing
|
|
5
|
+
* of the registry launcher components.
|
|
6
|
+
*
|
|
7
|
+
* @module registry-launcher/test-utils
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'node:events';
|
|
10
|
+
import { Readable, Writable } from 'node:stream';
|
|
11
|
+
import type { BinaryTarget, Distribution, Platform, Registry, RegistryAgent } from '../registry/types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Create a mock Registry with the specified agents.
|
|
14
|
+
*
|
|
15
|
+
* Fills in default values for any missing required fields in the agent definitions.
|
|
16
|
+
*
|
|
17
|
+
* @param agents - Partial agent definitions to include in the registry
|
|
18
|
+
* @returns A complete Registry object with the specified agents
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const registry = createMockRegistry([
|
|
23
|
+
* { id: 'agent-1', name: 'Test Agent 1' },
|
|
24
|
+
* { id: 'agent-2', name: 'Test Agent 2', distribution: { uvx: { package: 'my-agent' } } },
|
|
25
|
+
* ]);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function createMockRegistry(agents: Partial<RegistryAgent>[]): Registry;
|
|
29
|
+
/**
|
|
30
|
+
* Create a mock agent with a specific distribution type.
|
|
31
|
+
*
|
|
32
|
+
* Helper function for creating agents with different distribution configurations.
|
|
33
|
+
*
|
|
34
|
+
* @param id - Agent identifier
|
|
35
|
+
* @param distribution - Distribution configuration
|
|
36
|
+
* @param overrides - Additional agent properties to override
|
|
37
|
+
* @returns A complete RegistryAgent object
|
|
38
|
+
*/
|
|
39
|
+
export declare function createMockAgent(id: string, distribution: Distribution, overrides?: Partial<Omit<RegistryAgent, 'id' | 'distribution'>>): RegistryAgent;
|
|
40
|
+
/**
|
|
41
|
+
* Create a mock agent with binary distribution for a specific platform.
|
|
42
|
+
*
|
|
43
|
+
* @param id - Agent identifier
|
|
44
|
+
* @param platforms - Map of platform to binary target
|
|
45
|
+
* @param overrides - Additional agent properties
|
|
46
|
+
* @returns A RegistryAgent with binary distribution
|
|
47
|
+
*/
|
|
48
|
+
export declare function createMockBinaryAgent(id: string, platforms: Partial<Record<Platform, BinaryTarget>>, overrides?: Partial<Omit<RegistryAgent, 'id' | 'distribution'>>): RegistryAgent;
|
|
49
|
+
/**
|
|
50
|
+
* Create a mock agent with npx distribution.
|
|
51
|
+
*
|
|
52
|
+
* @param id - Agent identifier
|
|
53
|
+
* @param packageName - NPM package name (can include version like "pkg@1.0.0")
|
|
54
|
+
* @param args - Optional command-line arguments
|
|
55
|
+
* @param overrides - Additional agent properties
|
|
56
|
+
* @returns A RegistryAgent with npx distribution
|
|
57
|
+
*/
|
|
58
|
+
export declare function createMockNpxAgent(id: string, packageName: string, args?: string[], overrides?: Partial<Omit<RegistryAgent, 'id' | 'distribution'>>): RegistryAgent;
|
|
59
|
+
/**
|
|
60
|
+
* Create a mock agent with uvx distribution.
|
|
61
|
+
*
|
|
62
|
+
* @param id - Agent identifier
|
|
63
|
+
* @param packageName - Python package name (can include version like "pkg@latest")
|
|
64
|
+
* @param args - Optional command-line arguments
|
|
65
|
+
* @param overrides - Additional agent properties
|
|
66
|
+
* @returns A RegistryAgent with uvx distribution
|
|
67
|
+
*/
|
|
68
|
+
export declare function createMockUvxAgent(id: string, packageName: string, args?: string[], overrides?: Partial<Omit<RegistryAgent, 'id' | 'distribution'>>): RegistryAgent;
|
|
69
|
+
/**
|
|
70
|
+
* Mock ChildProcess interface for testing agent runtime management.
|
|
71
|
+
*
|
|
72
|
+
* Provides controllable stdin/stdout/stderr streams and process lifecycle events.
|
|
73
|
+
*/
|
|
74
|
+
export interface MockChildProcess extends EventEmitter {
|
|
75
|
+
/** Mock stdin stream for writing to the process */
|
|
76
|
+
stdin: Writable & {
|
|
77
|
+
destroyed: boolean;
|
|
78
|
+
};
|
|
79
|
+
/** Mock stdout stream for reading from the process */
|
|
80
|
+
stdout: Readable;
|
|
81
|
+
/** Mock stderr stream for reading error output */
|
|
82
|
+
stderr: Readable;
|
|
83
|
+
/** Process ID (mock value) */
|
|
84
|
+
pid: number;
|
|
85
|
+
/** Whether the process has been killed */
|
|
86
|
+
killed: boolean;
|
|
87
|
+
/** Exit code (null until process exits) */
|
|
88
|
+
exitCode: number | null;
|
|
89
|
+
/** Signal that caused exit (null if exited normally) */
|
|
90
|
+
signalCode: string | null;
|
|
91
|
+
/**
|
|
92
|
+
* Send a kill signal to the mock process.
|
|
93
|
+
* @param signal - Signal to send (default: 'SIGTERM')
|
|
94
|
+
* @returns true if signal was sent
|
|
95
|
+
*/
|
|
96
|
+
kill(signal?: string): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Simulate the process exiting with a specific code.
|
|
99
|
+
* @param code - Exit code (0 for success)
|
|
100
|
+
* @param signal - Optional signal that caused exit
|
|
101
|
+
*/
|
|
102
|
+
simulateExit(code: number, signal?: string | null): void;
|
|
103
|
+
/**
|
|
104
|
+
* Simulate the process spawning successfully.
|
|
105
|
+
*/
|
|
106
|
+
simulateSpawn(): void;
|
|
107
|
+
/**
|
|
108
|
+
* Simulate a spawn error.
|
|
109
|
+
* @param error - Error to emit
|
|
110
|
+
*/
|
|
111
|
+
simulateError(error: Error): void;
|
|
112
|
+
/**
|
|
113
|
+
* Write data to stdout as if the process produced it.
|
|
114
|
+
* @param data - Data to write
|
|
115
|
+
*/
|
|
116
|
+
writeToStdout(data: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Write data to stderr as if the process produced it.
|
|
119
|
+
* @param data - Data to write
|
|
120
|
+
*/
|
|
121
|
+
writeToStderr(data: string): void;
|
|
122
|
+
/**
|
|
123
|
+
* Get all data written to stdin.
|
|
124
|
+
* @returns Array of strings written to stdin
|
|
125
|
+
*/
|
|
126
|
+
getStdinWrites(): string[];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a mock ChildProcess for testing agent runtime management.
|
|
130
|
+
*
|
|
131
|
+
* The mock process provides controllable streams and lifecycle events,
|
|
132
|
+
* allowing tests to simulate various process behaviors.
|
|
133
|
+
*
|
|
134
|
+
* @param pid - Optional process ID (default: random)
|
|
135
|
+
* @returns A MockChildProcess instance
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const mockProcess = createMockAgentProcess();
|
|
140
|
+
*
|
|
141
|
+
* // Simulate successful spawn
|
|
142
|
+
* mockProcess.simulateSpawn();
|
|
143
|
+
*
|
|
144
|
+
* // Write to stdout as if the agent produced output
|
|
145
|
+
* mockProcess.writeToStdout('{"jsonrpc":"2.0","id":1,"result":{}}\n');
|
|
146
|
+
*
|
|
147
|
+
* // Simulate process exit
|
|
148
|
+
* mockProcess.simulateExit(0);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export declare function createMockAgentProcess(pid?: number): MockChildProcess;
|
|
152
|
+
/**
|
|
153
|
+
* Test NDJSON stream pair for testing stream handling.
|
|
154
|
+
*
|
|
155
|
+
* Provides connected input/output streams for testing NDJSON message flow.
|
|
156
|
+
*/
|
|
157
|
+
export interface TestNDJSONStream {
|
|
158
|
+
/** Writable stream to send data into the handler */
|
|
159
|
+
input: Writable;
|
|
160
|
+
/** Writable stream to capture data from the handler */
|
|
161
|
+
output: Writable;
|
|
162
|
+
/**
|
|
163
|
+
* Write a JSON message to the input stream.
|
|
164
|
+
* @param message - Object to serialize and write as NDJSON
|
|
165
|
+
*/
|
|
166
|
+
writeMessage(message: object): void;
|
|
167
|
+
/**
|
|
168
|
+
* Get all messages written to the output stream.
|
|
169
|
+
* @returns Array of parsed JSON objects
|
|
170
|
+
*/
|
|
171
|
+
getOutputMessages(): object[];
|
|
172
|
+
/**
|
|
173
|
+
* Get raw output data as string.
|
|
174
|
+
* @returns Concatenated output data
|
|
175
|
+
*/
|
|
176
|
+
getRawOutput(): string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Create a test NDJSON stream pair for testing stream handling.
|
|
180
|
+
*
|
|
181
|
+
* The input stream can be used to feed data into an NDJSON handler,
|
|
182
|
+
* while the output stream captures data written by the handler.
|
|
183
|
+
*
|
|
184
|
+
* @returns A TestNDJSONStream with connected input/output streams
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* const { input, output, writeMessage, getOutputMessages } = createTestNDJSONStream();
|
|
189
|
+
*
|
|
190
|
+
* // Create handler with the output stream
|
|
191
|
+
* const handler = new NDJSONHandler(output);
|
|
192
|
+
*
|
|
193
|
+
* // Feed data through input
|
|
194
|
+
* writeMessage({ jsonrpc: '2.0', method: 'test', id: 1 });
|
|
195
|
+
*
|
|
196
|
+
* // Check what was written to output
|
|
197
|
+
* const messages = getOutputMessages();
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
export declare function createTestNDJSONStream(): TestNDJSONStream;
|
|
201
|
+
/**
|
|
202
|
+
* Create a mock fetch function for testing registry fetching.
|
|
203
|
+
*
|
|
204
|
+
* @param responseData - Data to return from fetch
|
|
205
|
+
* @param options - Optional configuration for the mock
|
|
206
|
+
* @returns A mock fetch function
|
|
207
|
+
*/
|
|
208
|
+
export declare function createMockFetch(responseData: unknown, options?: {
|
|
209
|
+
/** HTTP status code (default: 200) */
|
|
210
|
+
status?: number;
|
|
211
|
+
/** Whether to simulate network error */
|
|
212
|
+
networkError?: boolean;
|
|
213
|
+
/** Error message for network error */
|
|
214
|
+
errorMessage?: string;
|
|
215
|
+
}): typeof fetch;
|
|
216
|
+
/**
|
|
217
|
+
* Wait for a specified number of milliseconds.
|
|
218
|
+
*
|
|
219
|
+
* Utility function for tests that need to wait for async operations.
|
|
220
|
+
*
|
|
221
|
+
* @param ms - Milliseconds to wait
|
|
222
|
+
* @returns Promise that resolves after the delay
|
|
223
|
+
*/
|
|
224
|
+
export declare function delay(ms: number): Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Create a deferred promise for testing async operations.
|
|
227
|
+
*
|
|
228
|
+
* @returns Object with promise and resolve/reject functions
|
|
229
|
+
*/
|
|
230
|
+
export declare function createDeferred<T>(): {
|
|
231
|
+
promise: Promise<T>;
|
|
232
|
+
resolve: (value: T) => void;
|
|
233
|
+
reject: (reason?: unknown) => void;
|
|
234
|
+
};
|