@zswarm/pi 0.1.3 → 0.1.4

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.
@@ -73,8 +73,8 @@ function defaultServers(): Record<string, ServerSpec> {
73
73
 
74
74
  /** How long to wait for a server to answer initialize/tools-list before giving up. */
75
75
  const HANDSHAKE_MS = 20_000;
76
- /** Tool calls can legitimately block — `wait` holds until a pane goes idle. */
77
- const CALL_MS = 15 * 60_000;
76
+ /** Core wait max is 15 minutes; slack covers framing so the client does not give up first. */
77
+ const CALL_MS = 16 * 60_000;
78
78
 
79
79
  function readServers(): Record<string, ServerSpec> {
80
80
  const raw = process.env.ZSWARM_MCP_SERVERS?.trim();
@@ -189,20 +189,34 @@ class McpClient {
189
189
  method: string,
190
190
  params: unknown,
191
191
  timeoutMs: number,
192
+ signal?: AbortSignal,
192
193
  ): Promise<unknown> {
193
194
  const id = this.nextId++;
194
195
  return new Promise<unknown>((resolve, reject) => {
196
+ if (signal?.aborted) {
197
+ reject(new Error("Cancelled"));
198
+ return;
199
+ }
200
+ const onAbort = () => {
201
+ this.pending.delete(id);
202
+ clearTimeout(timer);
203
+ reject(new Error("Cancelled"));
204
+ };
195
205
  const timer = setTimeout(() => {
196
206
  this.pending.delete(id);
207
+ signal?.removeEventListener("abort", onAbort);
197
208
  reject(new Error(`${this.name} ${method} timed out`));
198
209
  }, timeoutMs);
210
+ signal?.addEventListener("abort", onAbort, { once: true });
199
211
  this.pending.set(id, {
200
212
  resolve: (value) => {
201
213
  clearTimeout(timer);
214
+ signal?.removeEventListener("abort", onAbort);
202
215
  resolve(value);
203
216
  },
204
217
  reject: (error) => {
205
218
  clearTimeout(timer);
219
+ signal?.removeEventListener("abort", onAbort);
206
220
  reject(error);
207
221
  },
208
222
  });
@@ -210,11 +224,16 @@ class McpClient {
210
224
  });
211
225
  }
212
226
 
213
- async call(tool: string, args: Record<string, unknown>): Promise<string> {
227
+ async call(
228
+ tool: string,
229
+ args: Record<string, unknown>,
230
+ signal?: AbortSignal,
231
+ ): Promise<string> {
214
232
  const result = (await this.request(
215
233
  "tools/call",
216
234
  { name: tool, arguments: args },
217
235
  CALL_MS,
236
+ signal,
218
237
  )) as { content?: Array<{ type?: string; text?: string }> };
219
238
  const text = (result.content ?? [])
220
239
  .filter((part) => part.type === "text" && typeof part.text === "string")
@@ -280,16 +299,21 @@ export default function (pi: ExtensionAPI) {
280
299
  properties: {},
281
300
  }) as never,
282
301
  async execute(_toolCallId, params, signal) {
283
- if (signal?.aborted) {
284
- return { content: [{ type: "text", text: "Cancelled" }], details: {} };
285
- }
302
+ const cancelled = () => ({
303
+ content: [{ type: "text" as const, text: "Cancelled" }],
304
+ details: {},
305
+ });
306
+ if (signal?.aborted) return cancelled();
286
307
  try {
287
308
  const text = await client.call(
288
309
  tool.name,
289
310
  (params ?? {}) as Record<string, unknown>,
311
+ signal,
290
312
  );
313
+ if (signal?.aborted) return cancelled();
291
314
  return { content: [{ type: "text", text }], details: {} };
292
315
  } catch (err) {
316
+ if (signal?.aborted) return cancelled();
293
317
  const message = err instanceof Error ? err.message : String(err);
294
318
  return {
295
319
  content: [{ type: "text", text: `MCP ${name} error: ${message}` }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zswarm/pi",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Bridge stdio MCP servers into pi as native tools",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@zswarm/mcp": "0.1.3"
37
+ "@zswarm/mcp": "0.1.4"
38
38
  },
39
39
  "scripts": {}
40
40
  }