@modelprofile.com/mcp-crossharness 5.0.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.
@@ -0,0 +1,246 @@
1
+ import * as plugins from './plugins.js';
2
+ import { OpencodeConnection } from './classes.connection.opencode.js';
3
+ import { CodexConnection } from './classes.connection.codex.js';
4
+ export class ConnectionRegistry {
5
+ connections = new Map();
6
+ connecting = new Map();
7
+ closingConnections = new Map();
8
+ allowedServerUrls;
9
+ maxConnections;
10
+ openCodeCredentials;
11
+ closing = false;
12
+ closingTasks = new Map();
13
+ shutdownPromise;
14
+ constructor(optionsArg = {}) {
15
+ const configured = optionsArg.allowedServerUrls ??
16
+ (process.env.CROSSHARNESS_ALLOWED_SERVER_URLS ?? '')
17
+ .split(',')
18
+ .map((entry) => entry.trim())
19
+ .filter(Boolean);
20
+ this.allowedServerUrls = new Set(configured.map((entry) => this.normalizeUrl(entry).toString()));
21
+ this.maxConnections = optionsArg.maxConnections ?? 32;
22
+ if (!Number.isInteger(this.maxConnections) || this.maxConnections < 1) {
23
+ throw new Error('maxConnections must be a positive integer');
24
+ }
25
+ if (optionsArg.openCodeCredentials) {
26
+ const { serverUrl, username, password } = optionsArg.openCodeCredentials;
27
+ const credentialUrl = this.normalizeUrl(serverUrl);
28
+ if (serverUrl.length > 2048
29
+ || serverUrl.includes('?')
30
+ || serverUrl.includes('#')
31
+ || credentialUrl.username
32
+ || credentialUrl.password
33
+ || credentialUrl.search
34
+ || credentialUrl.hash
35
+ || credentialUrl.pathname !== '/'
36
+ || !['http:', 'https:'].includes(credentialUrl.protocol)
37
+ || !this.allowedServerUrls.has(credentialUrl.toString())
38
+ || (credentialUrl.protocol === 'http:'
39
+ && !['127.0.0.1', '[::1]', '::1', 'localhost'].includes(credentialUrl.hostname))
40
+ || typeof password !== 'string'
41
+ || password.length === 0
42
+ || Buffer.byteLength(password, 'utf8') > 1024
43
+ || password.includes('\r')
44
+ || password.includes('\n')
45
+ || (username !== undefined && (typeof username !== 'string'
46
+ || username.length === 0
47
+ || Buffer.byteLength(username, 'utf8') > 1024
48
+ || username.includes('\r')
49
+ || username.includes('\n'))))
50
+ throw new Error('openCodeCredentials are invalid');
51
+ this.openCodeCredentials = {
52
+ serverUrl: credentialUrl.toString(),
53
+ password,
54
+ ...(username === undefined ? {} : { username }),
55
+ };
56
+ }
57
+ }
58
+ async connect(harnessArg, serverUrlArg, directoryArg, signalArg) {
59
+ if (signalArg?.aborted)
60
+ throw this.abortError(signalArg.reason);
61
+ if (this.closing) {
62
+ throw new Error('connection registry is closing');
63
+ }
64
+ if (harnessArg === 'claudecode') {
65
+ throw new Error('Claude Code 2.1.219 exposes no URL-addressable session server; connection-first Crossharness cannot connect to it');
66
+ }
67
+ if (!directoryArg.startsWith('/')) {
68
+ throw new Error('connection directory must be an absolute path on the harness server');
69
+ }
70
+ if (directoryArg.length > 4096) {
71
+ throw new Error('connection directory exceeds 4096 characters');
72
+ }
73
+ if (serverUrlArg.length > 2048) {
74
+ throw new Error('server URL exceeds 2048 characters');
75
+ }
76
+ const url = this.validateAllowedUrl(harnessArg, serverUrlArg);
77
+ if (this.connections.size + this.connecting.size + this.closingConnections.size >=
78
+ this.maxConnections) {
79
+ throw new Error(`connection registry is full (maximum ${this.maxConnections})`);
80
+ }
81
+ const duplicate = [
82
+ ...this.connections.values(),
83
+ ...this.connecting.values(),
84
+ ...this.closingConnections.values(),
85
+ ].find((connection) => connection.harness === harnessArg &&
86
+ connection.serverUrl === url.toString() &&
87
+ connection.directory === directoryArg);
88
+ if (duplicate) {
89
+ throw new Error(`a ${harnessArg} connection already exists for ${url.toString()} and ${directoryArg}`);
90
+ }
91
+ const connectionId = `c-${plugins.crypto.randomBytes(8).toString('hex')}`;
92
+ const markClosingConnection = () => {
93
+ this.connections.delete(connectionId);
94
+ this.connecting.delete(connectionId);
95
+ this.closingConnections.set(connectionId, connection);
96
+ };
97
+ const removeClosedConnection = () => {
98
+ this.connections.delete(connectionId);
99
+ this.connecting.delete(connectionId);
100
+ this.closingConnections.delete(connectionId);
101
+ };
102
+ const connection = harnessArg === 'opencode'
103
+ ? new OpencodeConnection(connectionId, url.toString(), directoryArg, markClosingConnection, removeClosedConnection, this.openCodeCredentials?.serverUrl === url.toString()
104
+ ? this.openCodeCredentials
105
+ : undefined)
106
+ : new CodexConnection(connectionId, url.toString(), directoryArg, markClosingConnection, removeClosedConnection);
107
+ this.connecting.set(connectionId, connection);
108
+ let abortCleanupTask;
109
+ const abortHandler = signalArg
110
+ ? () => {
111
+ abortCleanupTask ??= this.closeConnection(connection, this.abortError(signalArg.reason).message);
112
+ void abortCleanupTask.catch(() => undefined);
113
+ }
114
+ : undefined;
115
+ if (abortHandler)
116
+ signalArg.addEventListener('abort', abortHandler, { once: true });
117
+ try {
118
+ await connection.connect();
119
+ if (signalArg?.aborted)
120
+ throw this.abortError(signalArg.reason);
121
+ if (this.closing) {
122
+ throw new Error('connection registry closed during setup');
123
+ }
124
+ this.connections.set(connectionId, connection);
125
+ return connection.getInfo();
126
+ }
127
+ catch (errorArg) {
128
+ const operationError = signalArg?.aborted ? this.abortError(signalArg.reason) : errorArg;
129
+ try {
130
+ await (abortCleanupTask ?? this.closeConnection(connection, 'connection setup failed'));
131
+ }
132
+ catch (cleanupErrorArg) {
133
+ throw new AggregateError([operationError, cleanupErrorArg], 'Connection setup failed and cleanup is incomplete.');
134
+ }
135
+ throw operationError;
136
+ }
137
+ finally {
138
+ if (abortHandler)
139
+ signalArg.removeEventListener('abort', abortHandler);
140
+ this.connecting.delete(connectionId);
141
+ }
142
+ }
143
+ get(connectionIdArg) {
144
+ const connection = this.connections.get(connectionIdArg);
145
+ if (!connection) {
146
+ throw new Error(`unknown connectionId ${connectionIdArg}`);
147
+ }
148
+ return connection;
149
+ }
150
+ list() {
151
+ return [...this.connections.values()].map((connection) => connection.getInfo());
152
+ }
153
+ async disconnect(connectionIdArg) {
154
+ const connection = this.connections.get(connectionIdArg)
155
+ ?? this.closingConnections.get(connectionIdArg);
156
+ if (!connection)
157
+ throw new Error(`unknown connectionId ${connectionIdArg}`);
158
+ await this.closeConnection(connection, 'connection explicitly disconnected');
159
+ return connection.getInfo();
160
+ }
161
+ async closeAll() {
162
+ if (this.shutdownPromise)
163
+ return this.shutdownPromise;
164
+ this.closing = true;
165
+ const connections = [
166
+ ...new Set([
167
+ ...this.connections.values(),
168
+ ...this.connecting.values(),
169
+ ...this.closingConnections.values(),
170
+ ]),
171
+ ];
172
+ const shutdownPromise = Promise.allSettled(connections.map((connection) => this.closeConnection(connection, 'Crossharness MCP transport closed'))).then((results) => {
173
+ const errors = results.flatMap((result) => (result.status === 'rejected' ? [result.reason] : []));
174
+ if (errors.length === 1)
175
+ throw errors[0];
176
+ if (errors.length > 1) {
177
+ throw new AggregateError(errors, 'Closing Crossharness connections failed.');
178
+ }
179
+ });
180
+ this.shutdownPromise = shutdownPromise;
181
+ try {
182
+ await shutdownPromise;
183
+ }
184
+ finally {
185
+ if (this.shutdownPromise === shutdownPromise)
186
+ this.shutdownPromise = undefined;
187
+ }
188
+ }
189
+ closeConnection(connectionArg, reasonArg) {
190
+ const connectionId = connectionArg.connectionId;
191
+ const existing = this.closingTasks.get(connectionId);
192
+ if (existing)
193
+ return existing;
194
+ this.connections.delete(connectionId);
195
+ this.connecting.delete(connectionId);
196
+ this.closingConnections.set(connectionId, connectionArg);
197
+ let task;
198
+ task = Promise.resolve().then(() => connectionArg.close(reasonArg)).then(() => {
199
+ if (this.closingConnections.get(connectionId) === connectionArg) {
200
+ this.closingConnections.delete(connectionId);
201
+ }
202
+ }, (errorArg) => {
203
+ this.connections.delete(connectionId);
204
+ this.connecting.delete(connectionId);
205
+ this.closingConnections.set(connectionId, connectionArg);
206
+ throw errorArg;
207
+ }).finally(() => {
208
+ if (this.closingTasks.get(connectionId) === task)
209
+ this.closingTasks.delete(connectionId);
210
+ });
211
+ this.closingTasks.set(connectionId, task);
212
+ return task;
213
+ }
214
+ validateAllowedUrl(harnessArg, valueArg) {
215
+ const url = this.normalizeUrl(valueArg);
216
+ if (url.username || url.password || url.search || url.hash) {
217
+ throw new Error('server URL must not contain credentials, query parameters, or a fragment');
218
+ }
219
+ if (url.pathname !== '/') {
220
+ throw new Error('server URL must be an origin with no path');
221
+ }
222
+ const protocols = harnessArg === 'opencode' ? ['http:', 'https:'] : ['ws:', 'wss:'];
223
+ if (!protocols.includes(url.protocol)) {
224
+ throw new Error(`${harnessArg} server URL must use ${protocols.join(' or ')}`);
225
+ }
226
+ if (!this.allowedServerUrls.has(url.toString())) {
227
+ throw new Error(`server URL ${url.toString()} is not in CROSSHARNESS_ALLOWED_SERVER_URLS`);
228
+ }
229
+ return url;
230
+ }
231
+ normalizeUrl(valueArg) {
232
+ let url;
233
+ try {
234
+ url = new URL(valueArg);
235
+ }
236
+ catch {
237
+ throw new Error(`invalid server URL: ${valueArg}`);
238
+ }
239
+ url.pathname = url.pathname || '/';
240
+ return url;
241
+ }
242
+ abortError(reasonArg) {
243
+ return reasonArg instanceof Error ? reasonArg : new Error('connection cancelled');
244
+ }
245
+ }
246
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb25uZWN0aW9ucmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNvbm5lY3Rpb25yZWdpc3RyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFlaEUsTUFBTSxPQUFPLGtCQUFrQjtJQUNyQixXQUFXLEdBQUcsSUFBSSxHQUFHLEVBQXlDLENBQUM7SUFDL0QsVUFBVSxHQUFHLElBQUksR0FBRyxFQUF5QyxDQUFDO0lBQzlELGtCQUFrQixHQUFHLElBQUksR0FBRyxFQUF5QyxDQUFDO0lBQ3RFLGlCQUFpQixDQUFjO0lBQy9CLGNBQWMsQ0FBUztJQUN2QixtQkFBbUIsQ0FBbUM7SUFDdEQsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUNoQixZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7SUFDaEQsZUFBZSxDQUE0QjtJQUVuRCxZQUFZLGFBQXlDLEVBQUU7UUFDckQsTUFBTSxVQUFVLEdBQ2QsVUFBVSxDQUFDLGlCQUFpQjtZQUM1QixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLElBQUksRUFBRSxDQUFDO2lCQUNqRCxLQUFLLENBQUMsR0FBRyxDQUFDO2lCQUNWLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO2lCQUM1QixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDckIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxF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
@@ -0,0 +1,39 @@
1
+ import type * as interfaces from './interfaces.js';
2
+ export type TDispatchStatus = 'working' | 'completed' | 'failed';
3
+ export interface IDispatchRecord {
4
+ dispatchId: string;
5
+ connectionId: string;
6
+ harness: interfaces.THarnessName;
7
+ chatId: string;
8
+ startedAt: string;
9
+ completedAt?: string;
10
+ status: TDispatchStatus;
11
+ reply?: string;
12
+ via?: string;
13
+ error?: string;
14
+ }
15
+ export interface IDispatchRegistryOptions {
16
+ maxRecords?: number;
17
+ completedTtlMs?: number;
18
+ }
19
+ export declare class DispatchRegistry {
20
+ private options;
21
+ private records;
22
+ private expiryTimers;
23
+ private waiters;
24
+ private waiterCount;
25
+ private counter;
26
+ private instancePrefix;
27
+ private disposed;
28
+ constructor(options?: IDispatchRegistryOptions);
29
+ track(connectionIdArg: string, harnessArg: interfaces.THarnessName, chatIdArg: string, sendFactoryArg: () => Promise<interfaces.ISendResult>): IDispatchRecord;
30
+ get(connectionIdArg: string, dispatchIdArg: string): IDispatchRecord | undefined;
31
+ waitFor(connectionIdArg: string, dispatchIdArg: string, waitMsArg: number, signalArg?: AbortSignal): Promise<IDispatchRecord | undefined>;
32
+ dispose(): void;
33
+ private prune;
34
+ private scheduleExpiry;
35
+ private reserveCapacity;
36
+ private forget;
37
+ private notifyWaiters;
38
+ private removeWaiter;
39
+ }
@@ -0,0 +1,177 @@
1
+ export class DispatchRegistry {
2
+ options;
3
+ records = new Map();
4
+ expiryTimers = new Map();
5
+ waiters = new Map();
6
+ waiterCount = 0;
7
+ counter = 0;
8
+ instancePrefix = Math.random().toString(36).slice(2, 7);
9
+ disposed = false;
10
+ constructor(options = {}) {
11
+ this.options = options;
12
+ if (!Number.isInteger(options.maxRecords ?? 100) || (options.maxRecords ?? 100) < 1) {
13
+ throw new Error('dispatch maxRecords must be a positive integer');
14
+ }
15
+ if ((options.completedTtlMs ?? 2 * 60 * 60 * 1000) < 0) {
16
+ throw new Error('dispatch completedTtlMs must not be negative');
17
+ }
18
+ }
19
+ track(connectionIdArg, harnessArg, chatIdArg, sendFactoryArg) {
20
+ if (this.disposed)
21
+ throw new Error('dispatch registry is closed');
22
+ this.reserveCapacity();
23
+ const record = {
24
+ dispatchId: `d-${this.instancePrefix}-${++this.counter}`,
25
+ connectionId: connectionIdArg,
26
+ harness: harnessArg,
27
+ chatId: chatIdArg,
28
+ startedAt: new Date().toISOString(),
29
+ status: 'working',
30
+ };
31
+ this.records.set(record.dispatchId, record);
32
+ Promise.resolve().then(sendFactoryArg).then((result) => {
33
+ if (this.disposed || record.status !== 'working')
34
+ return;
35
+ record.status = 'completed';
36
+ record.completedAt = new Date().toISOString();
37
+ record.reply = result.reply.slice(0, 100000);
38
+ record.via = result.via;
39
+ this.notifyWaiters(record.dispatchId, record);
40
+ this.scheduleExpiry(record.dispatchId);
41
+ this.prune();
42
+ }, (error) => {
43
+ if (this.disposed || record.status !== 'working')
44
+ return;
45
+ record.status = 'failed';
46
+ record.completedAt = new Date().toISOString();
47
+ record.error = (error instanceof Error ? error.message : String(error)).slice(0, 4000);
48
+ this.notifyWaiters(record.dispatchId, record);
49
+ this.scheduleExpiry(record.dispatchId);
50
+ this.prune();
51
+ });
52
+ return record;
53
+ }
54
+ get(connectionIdArg, dispatchIdArg) {
55
+ this.prune();
56
+ const record = this.records.get(dispatchIdArg);
57
+ return record?.connectionId === connectionIdArg ? record : undefined;
58
+ }
59
+ async waitFor(connectionIdArg, dispatchIdArg, waitMsArg, signalArg) {
60
+ const deadline = Date.now() + waitMsArg;
61
+ const record = this.get(connectionIdArg, dispatchIdArg);
62
+ if (!record || record.status !== 'working' || waitMsArg <= 0)
63
+ return record;
64
+ if (signalArg?.aborted)
65
+ return record;
66
+ if (this.waiterCount >= 1000)
67
+ return record;
68
+ return new Promise((resolve) => {
69
+ const waiter = {
70
+ resolve,
71
+ timer: setTimeout(() => {
72
+ this.removeWaiter(dispatchIdArg, waiter);
73
+ resolve(this.get(connectionIdArg, dispatchIdArg));
74
+ }, Math.max(0, deadline - Date.now())),
75
+ signal: signalArg,
76
+ };
77
+ if (signalArg) {
78
+ waiter.abortHandler = () => {
79
+ this.removeWaiter(dispatchIdArg, waiter);
80
+ resolve(this.get(connectionIdArg, dispatchIdArg));
81
+ };
82
+ signalArg.addEventListener('abort', waiter.abortHandler, { once: true });
83
+ }
84
+ const dispatchWaiters = this.waiters.get(dispatchIdArg) ?? new Set();
85
+ dispatchWaiters.add(waiter);
86
+ this.waiterCount++;
87
+ this.waiters.set(dispatchIdArg, dispatchWaiters);
88
+ const current = this.get(connectionIdArg, dispatchIdArg);
89
+ if (!current || current.status !== 'working') {
90
+ this.notifyWaiters(dispatchIdArg, current);
91
+ }
92
+ });
93
+ }
94
+ dispose() {
95
+ if (this.disposed)
96
+ return;
97
+ this.disposed = true;
98
+ for (const timer of this.expiryTimers.values())
99
+ clearTimeout(timer);
100
+ this.expiryTimers.clear();
101
+ for (const dispatchId of [...this.waiters.keys()]) {
102
+ this.notifyWaiters(dispatchId, undefined);
103
+ }
104
+ this.records.clear();
105
+ }
106
+ prune() {
107
+ const completedTtlMs = this.options.completedTtlMs ?? 2 * 60 * 60 * 1000;
108
+ const now = Date.now();
109
+ for (const [dispatchId, record] of this.records) {
110
+ if (record.status !== 'working' &&
111
+ record.completedAt &&
112
+ now - Date.parse(record.completedAt) > completedTtlMs) {
113
+ this.forget(dispatchId);
114
+ }
115
+ }
116
+ }
117
+ scheduleExpiry(dispatchIdArg) {
118
+ const existingTimer = this.expiryTimers.get(dispatchIdArg);
119
+ if (existingTimer)
120
+ clearTimeout(existingTimer);
121
+ const timer = setTimeout(() => {
122
+ this.expiryTimers.delete(dispatchIdArg);
123
+ this.records.delete(dispatchIdArg);
124
+ }, this.options.completedTtlMs ?? 2 * 60 * 60 * 1000);
125
+ this.expiryTimers.set(dispatchIdArg, timer);
126
+ timer.unref();
127
+ }
128
+ reserveCapacity() {
129
+ this.prune();
130
+ const maxRecords = this.options.maxRecords ?? 100;
131
+ for (const [dispatchId, record] of this.records) {
132
+ if (this.records.size < maxRecords)
133
+ break;
134
+ if (record.status !== 'working')
135
+ this.forget(dispatchId);
136
+ }
137
+ if (this.records.size >= maxRecords) {
138
+ throw new Error('dispatch registry is full of active sends');
139
+ }
140
+ }
141
+ forget(dispatchIdArg) {
142
+ this.records.delete(dispatchIdArg);
143
+ const timer = this.expiryTimers.get(dispatchIdArg);
144
+ if (timer)
145
+ clearTimeout(timer);
146
+ this.expiryTimers.delete(dispatchIdArg);
147
+ this.notifyWaiters(dispatchIdArg, undefined);
148
+ }
149
+ notifyWaiters(dispatchIdArg, recordArg) {
150
+ const dispatchWaiters = this.waiters.get(dispatchIdArg);
151
+ if (!dispatchWaiters)
152
+ return;
153
+ this.waiters.delete(dispatchIdArg);
154
+ this.waiterCount -= dispatchWaiters.size;
155
+ for (const waiter of dispatchWaiters) {
156
+ clearTimeout(waiter.timer);
157
+ if (waiter.abortHandler)
158
+ waiter.signal?.removeEventListener('abort', waiter.abortHandler);
159
+ waiter.resolve(recordArg);
160
+ }
161
+ }
162
+ removeWaiter(dispatchIdArg, waiterArg) {
163
+ const dispatchWaiters = this.waiters.get(dispatchIdArg);
164
+ if (!dispatchWaiters)
165
+ return;
166
+ if (dispatchWaiters.delete(waiterArg)) {
167
+ this.waiterCount--;
168
+ clearTimeout(waiterArg.timer);
169
+ if (waiterArg.abortHandler) {
170
+ waiterArg.signal?.removeEventListener('abort', waiterArg.abortHandler);
171
+ }
172
+ }
173
+ if (dispatchWaiters.size === 0)
174
+ this.waiters.delete(dispatchIdArg);
175
+ }
176
+ }
177
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kaXNwYXRjaHJlZ2lzdHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5kaXNwYXRjaHJlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTZCQSxNQUFNLE9BQU8sZ0JBQWdCO0lBU1A7SUFSWixPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQTJCLENBQUM7SUFDN0MsWUFBWSxHQUFHLElBQUksR0FBRyxFQUF5QyxDQUFDO0lBQ2hFLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBZ0MsQ0FBQztJQUNsRCxXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLE9BQU8sR0FBRyxDQUFDLENBQUM7SUFDWixjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3hELFFBQVEsR0FBRyxLQUFLLENBQUM7SUFFekIsWUFBb0IsVUFBb0MsRUFBRTtRQUF0QyxZQUFPLEdBQVAsT0FBTyxDQUErQjtRQUN4RCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsVUFBVSxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwRixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUNELElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQUMsOENBQThDLENBQUMsQ0FBQztRQUNsRSxDQUFDO0lBQ0gsQ0FBQztJQUVNLEtBQUssQ0FDVixlQUF1QixFQUN2QixVQUFtQyxFQUNuQyxTQUFpQixFQUNqQixjQUFxRDtR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
@@ -0,0 +1,21 @@
1
+ import * as plugins from './plugins.js';
2
+ import { ConnectionRegistry } from './classes.connectionregistry.js';
3
+ import { DispatchRegistry } from './classes.dispatchregistry.js';
4
+ export declare class CrossHarnessMcpServer {
5
+ readonly connections: ConnectionRegistry;
6
+ readonly dispatches: DispatchRegistry;
7
+ private activeServer;
8
+ private stdinEndHandler;
9
+ private stdinEndSource;
10
+ private closePromise;
11
+ private resourceShutdownPromise;
12
+ private startCalled;
13
+ constructor(connectionsArg?: ConnectionRegistry, dispatchesArg?: DispatchRegistry);
14
+ start(transportArg?: plugins.Transport, stdinArg?: NodeJS.ReadableStream): Promise<void>;
15
+ close(): Promise<void>;
16
+ private triggerClose;
17
+ private ensureResourceShutdown;
18
+ private clearTransportReferences;
19
+ private describeConnection;
20
+ private wrapToolCall;
21
+ }