donsetch 4.1.2 → 4.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 (2) hide show
  1. package/package.json +1 -1
  2. package/pi-extension.ts +44 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donsetch",
3
- "version": "4.1.2",
3
+ "version": "4.2.0",
4
4
  "description": "Web fetch, search and crawl for AI agents. Zero API keys. Chrome-true TLS.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Bishesh Bhandari",
package/pi-extension.ts CHANGED
@@ -31,6 +31,33 @@ const INIT_TIMEOUT_MS = 30_000;
31
31
  const CALL_TIMEOUT_MS = 120_000;
32
32
  const SHUTDOWN_GRACE_MS = 2_000;
33
33
 
34
+ // The client timeout must outlive the server's OWN budget, or a call the
35
+ // binary still considers legal gets killed here first. web_crawl accepts
36
+ // deadline_s up to 600 and web_fetch deadline_ms up to 600000, so a fixed
37
+ // 120s client cap cut legal crawls off at exactly the binary's default
38
+ // deadline (deadline_s defaults to 120 : the two raced). Derive it from
39
+ // the call's own budget plus slack instead, capped at the largest budget
40
+ // the schemas allow so a hostile arg cannot hold a slot forever.
41
+ const CALL_DEADLINE_SLACK_MS = 20_000;
42
+ const MAX_CALL_TIMEOUT_MS = 620_000; // 600s budget + slack
43
+
44
+ function num(v: unknown): number | null {
45
+ const n = typeof v === "string" ? Number(v) : typeof v === "number" ? v : NaN;
46
+ return Number.isFinite(n) && n > 0 ? n : null;
47
+ }
48
+
49
+ function callTimeoutFor(name: string, args: any): number {
50
+ let budgetMs: number | null = null;
51
+ if (name === "web_crawl") {
52
+ const secs = num(args?.deadline_s);
53
+ budgetMs = secs !== null ? secs * 1000 : 120_000; // the binary's default
54
+ } else if (name === "web_fetch") {
55
+ budgetMs = num(args?.deadline_ms);
56
+ }
57
+ if (budgetMs === null) return CALL_TIMEOUT_MS;
58
+ return Math.min(budgetMs + CALL_DEADLINE_SLACK_MS, MAX_CALL_TIMEOUT_MS);
59
+ }
60
+
34
61
  // A raw process.stderr.write bypasses pi's TUI paint cycle and
35
62
  // corrupts the viewport (worse across parallel agents). Gate it here.
36
63
  const DEBUG_MODE =
@@ -56,6 +83,7 @@ const ICONS: Record<string, string> = {
56
83
  web_fetch: "\u{1F310}", // 🌐
57
84
  web_search: "\u{1F50E}", // 🔎
58
85
  web_crawl: "\u{1F577}\u{FE0F}", // 🕷️
86
+ web_screenshot: "\u{1F4F7}", // 📷
59
87
  };
60
88
 
61
89
  // ── MCP client state ──
@@ -312,8 +340,13 @@ function sendNotification(method: string, params: any): void {
312
340
  }
313
341
  }
314
342
 
315
- async function callMcpTool(name: string, args: any, signal?: AbortSignal): Promise<any> {
316
- return sendRequest("tools/call", { name, arguments: args ?? {} }, CALL_TIMEOUT_MS, signal);
343
+ async function callMcpTool(
344
+ name: string,
345
+ args: any,
346
+ signal?: AbortSignal,
347
+ timeoutMs = CALL_TIMEOUT_MS
348
+ ): Promise<any> {
349
+ return sendRequest("tools/call", { name, arguments: args ?? {} }, timeoutMs, signal);
317
350
  }
318
351
 
319
352
  function killServer(): void {
@@ -477,13 +510,21 @@ export default function (pi: ExtensionAPI) {
477
510
  } catch (err: any) {
478
511
  return {
479
512
  content: [{ type: "text", text: `donsetch MCP server crashed and could not restart: ${err.message}` }],
513
+ // Every other result path carries `details`; pi's
514
+ // AgentToolResult requires it, and renderResult reads it.
515
+ details: { mcpTool: toolName, isError: true, error: err.message },
480
516
  isError: true,
481
517
  };
482
518
  }
483
519
  }
484
520
 
485
521
  try {
486
- const result = await callMcpTool(toolName, params, _signal);
522
+ const result = await callMcpTool(
523
+ toolName,
524
+ params,
525
+ _signal,
526
+ callTimeoutFor(toolName, params)
527
+ );
487
528
  // Join all content text blocks, skipping [meta] blocks.
488
529
  // [meta] blocks contain compact metadata for clients
489
530
  // (Claude Code, VSCode) that drop text when