recker 1.0.79 → 1.0.80-next.70ea84d
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/dist/browser/browser/mini.d.ts +2 -2
- package/dist/browser/browser/recker-mini.d.ts +8 -8
- package/dist/browser/browser/recker.d.ts +11 -8
- package/dist/browser/browser/recker.js +54 -6
- package/dist/browser/core/client.d.ts +15 -10
- package/dist/browser/core/client.js +54 -38
- package/dist/browser/index.iife.min.js +129 -130
- package/dist/browser/index.min.js +129 -130
- package/dist/browser/index.mini.iife.js +5697 -636
- package/dist/browser/index.mini.iife.min.js +47 -48
- package/dist/browser/index.mini.min.js +47 -48
- package/dist/browser/index.mini.umd.js +5697 -636
- package/dist/browser/index.mini.umd.min.js +47 -48
- package/dist/browser/index.umd.min.js +129 -130
- package/dist/browser/mini.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.js +6 -28
- package/dist/browser/recker-mini.d.ts +8 -8
- package/dist/browser/recker.d.ts +11 -8
- package/dist/browser/recker.js +54 -6
- package/dist/browser/scrape/document.js +2 -2
- package/dist/browser/scrape/element.js +7 -1
- package/dist/browser/scrape/parser/nodes/html.js +1 -1
- package/dist/browser/scrape/spider.d.ts +52 -0
- package/dist/browser/scrape/spider.js +620 -38
- package/dist/browser/scrape/types.d.ts +2 -0
- package/dist/browser/search/google.d.ts +26 -1
- package/dist/browser/search/google.js +427 -45
- package/dist/browser/seo/analyzer.d.ts +1 -0
- package/dist/browser/seo/analyzer.js +144 -1
- package/dist/browser/seo/index.d.ts +1 -1
- package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/browser/seo/keyword-campaign-shared.js +59 -0
- package/dist/browser/seo/keyword-campaign.d.ts +4 -107
- package/dist/browser/seo/keyword-campaign.js +2 -380
- package/dist/browser/seo/keywords.js +5 -22
- package/dist/browser/seo/types.d.ts +19 -0
- package/dist/browser/transport/curl.d.ts +5 -1
- package/dist/browser/transport/curl.js +207 -50
- package/dist/browser/transport/undici.d.ts +4 -3
- package/dist/browser/transport/undici.js +123 -49
- package/dist/browser/types/index.d.ts +9 -3
- package/dist/browser/utils/binary-manager.js +26 -3
- package/dist/browser/utils/block-detector.d.ts +8 -0
- package/dist/browser/utils/block-detector.js +542 -7
- package/dist/cli/commands/hls-runner.js +5 -4
- package/dist/cli/commands/live-runner.js +5 -4
- package/dist/cli/commands/loadtest-runner.js +3 -2
- package/dist/cli/commands/search.d.ts +2 -0
- package/dist/cli/commands/search.js +105 -0
- package/dist/cli/commands/seo-runner.js +9 -7
- package/dist/cli/commands/seo.js +140 -1
- package/dist/cli/commands/serve.js +75 -131
- package/dist/cli/commands/server-runner.js +59 -82
- package/dist/cli/commands/spider-runner.d.ts +37 -1
- package/dist/cli/commands/spider-runner.js +134 -10
- package/dist/cli/commands/spider.d.ts +18 -1
- package/dist/cli/commands/spider.js +457 -27
- package/dist/cli/events/handlers/cli.js +30 -1
- package/dist/cli/events/handlers/tui.js +26 -0
- package/dist/cli/events/types.d.ts +27 -0
- package/dist/cli/handler.d.ts +2 -12
- package/dist/cli/handler.js +20 -15
- package/dist/cli/handlers/protocols.js +39 -12
- package/dist/cli/handlers/search.d.ts +2 -0
- package/dist/cli/handlers/search.js +171 -0
- package/dist/cli/handlers/seo-analyze.d.ts +1 -0
- package/dist/cli/handlers/seo-analyze.js +666 -0
- package/dist/cli/handlers/seo-robots.d.ts +1 -0
- package/dist/cli/handlers/seo-robots.js +76 -0
- package/dist/cli/handlers/seo-serp.d.ts +54 -0
- package/dist/cli/handlers/seo-serp.js +243 -0
- package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
- package/dist/cli/handlers/seo-sitemap.js +55 -0
- package/dist/cli/handlers/seo-spider.d.ts +1 -0
- package/dist/cli/handlers/seo-spider.js +334 -0
- package/dist/cli/handlers/seo.d.ts +8 -4
- package/dist/cli/handlers/seo.js +294 -442
- package/dist/cli/handlers/spider.js +94 -17
- package/dist/cli/handlers/streaming.js +5 -1
- package/dist/cli/index.js +11 -2
- package/dist/cli/presets.d.ts +1 -1
- package/dist/cli/presets.js +15 -4
- package/dist/cli/tui/app.js +6 -1
- package/dist/cli/tui/components/rich-response.d.ts +72 -0
- package/dist/cli/tui/components/rich-response.js +117 -0
- package/dist/cli/tui/executor-commands/background.js +30 -24
- package/dist/cli/tui/executor-commands/testing.js +3 -2
- package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
- package/dist/cli/tui/hooks/useHelp.js +15 -2
- package/dist/cli/tui/job-manager.d.ts +4 -4
- package/dist/cli/tui/job-manager.js +5 -1
- package/dist/cli/tui/spider-tui.d.ts +63 -0
- package/dist/cli/tui/spider-tui.js +120 -2
- package/dist/cli/types.d.ts +12 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utils/option-helpers.d.ts +10 -0
- package/dist/cli/utils/option-helpers.js +63 -0
- package/dist/cli/utils/score-color.d.ts +11 -0
- package/dist/cli/utils/score-color.js +11 -0
- package/dist/cli/utils/serp-campaign.d.ts +53 -0
- package/dist/cli/utils/serp-campaign.js +53 -0
- package/dist/cli/utils/serp-config.d.ts +26 -0
- package/dist/cli/utils/serp-config.js +125 -0
- package/dist/core/client.d.ts +15 -10
- package/dist/core/client.js +54 -38
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/cli.js +35 -34
- package/dist/mcp/client.d.ts +2 -2
- package/dist/mcp/client.js +20 -2
- package/dist/mcp/contract.d.ts +1 -1
- package/dist/mcp/profiles.js +5 -1
- package/dist/mcp/prompts/index.js +8 -4
- package/dist/mcp/resources/index.js +46 -23
- package/dist/mcp/server.js +9 -6
- package/dist/mcp/tools/protocols.js +9 -2
- package/dist/mcp/tools/registry.js +13 -3
- package/dist/mcp/tools/seo.js +427 -2
- package/dist/mcp/types.d.ts +5 -1
- package/dist/plugins/proxy-rotator.d.ts +2 -2
- package/dist/plugins/proxy-rotator.js +6 -28
- package/dist/raffel/client.d.ts +38 -0
- package/dist/raffel/client.js +282 -0
- package/dist/raffel/index.d.ts +2 -0
- package/dist/raffel/index.js +2 -0
- package/dist/raffel/types.d.ts +40 -0
- package/dist/raffel/types.js +14 -0
- package/dist/recker.d.ts +13 -7
- package/dist/recker.js +58 -6
- package/dist/scrape/document.js +2 -2
- package/dist/scrape/element.js +7 -1
- package/dist/scrape/parser/nodes/html.js +1 -1
- package/dist/scrape/spider.d.ts +52 -0
- package/dist/scrape/spider.js +620 -38
- package/dist/scrape/types.d.ts +2 -0
- package/dist/search/google.d.ts +26 -1
- package/dist/search/google.js +427 -45
- package/dist/search/index.d.ts +1 -1
- package/dist/seo/analyzer.d.ts +1 -0
- package/dist/seo/analyzer.js +144 -1
- package/dist/seo/index.d.ts +1 -1
- package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/seo/keyword-campaign-shared.js +59 -0
- package/dist/seo/keyword-campaign.d.ts +4 -107
- package/dist/seo/keyword-campaign.js +2 -380
- package/dist/seo/keywords.js +5 -22
- package/dist/seo/types.d.ts +19 -0
- package/dist/template/index.d.ts +1 -1
- package/dist/template/types.d.ts +0 -2
- package/dist/testing/index.d.ts +1 -22
- package/dist/testing/index.js +1 -11
- package/dist/transport/curl.d.ts +5 -1
- package/dist/transport/curl.js +207 -50
- package/dist/transport/undici.d.ts +4 -3
- package/dist/transport/undici.js +123 -49
- package/dist/types/index.d.ts +9 -3
- package/dist/utils/binary-manager.js +26 -3
- package/dist/utils/block-detector.d.ts +8 -0
- package/dist/utils/block-detector.js +542 -7
- package/dist/version.js +1 -1
- package/package.json +12 -1
- package/dist/testing/mock-dns-server.d.ts +0 -69
- package/dist/testing/mock-dns-server.js +0 -269
- package/dist/testing/mock-ftp-server.d.ts +0 -89
- package/dist/testing/mock-ftp-server.js +0 -562
- package/dist/testing/mock-hls-server.d.ts +0 -80
- package/dist/testing/mock-hls-server.js +0 -381
- package/dist/testing/mock-http-server.d.ts +0 -124
- package/dist/testing/mock-http-server.js +0 -343
- package/dist/testing/mock-proxy-server.d.ts +0 -108
- package/dist/testing/mock-proxy-server.js +0 -615
- package/dist/testing/mock-sse-server.d.ts +0 -76
- package/dist/testing/mock-sse-server.js +0 -291
- package/dist/testing/mock-telnet-server.d.ts +0 -59
- package/dist/testing/mock-telnet-server.js +0 -274
- package/dist/testing/mock-udp-server.d.ts +0 -43
- package/dist/testing/mock-udp-server.js +0 -188
- package/dist/testing/mock-websocket-server.d.ts +0 -76
- package/dist/testing/mock-websocket-server.js +0 -334
- package/dist/testing/mock-whois-server.d.ts +0 -56
- package/dist/testing/mock-whois-server.js +0 -234
- package/dist/testing/proxy-certs.d.ts +0 -19
- package/dist/testing/proxy-certs.js +0 -208
package/dist/mcp/client.js
CHANGED
|
@@ -2,6 +2,18 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import { createClient } from '../core/client.js';
|
|
3
3
|
import { StateError, ProtocolError } from '../core/errors.js';
|
|
4
4
|
import { consoleLogger } from '../types/logger.js';
|
|
5
|
+
function normalizeJsonRpcParams(params) {
|
|
6
|
+
if (params === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (params === null)
|
|
9
|
+
return { value: null };
|
|
10
|
+
if (Array.isArray(params))
|
|
11
|
+
return params;
|
|
12
|
+
if (typeof params === 'object') {
|
|
13
|
+
return params;
|
|
14
|
+
}
|
|
15
|
+
return { value: params };
|
|
16
|
+
}
|
|
5
17
|
export class MCPClient extends EventEmitter {
|
|
6
18
|
client;
|
|
7
19
|
endpoint;
|
|
@@ -137,7 +149,7 @@ export class MCPClient extends EventEmitter {
|
|
|
137
149
|
jsonrpc: '2.0',
|
|
138
150
|
id: ++this.requestId,
|
|
139
151
|
method,
|
|
140
|
-
params: params,
|
|
152
|
+
params: normalizeJsonRpcParams(params),
|
|
141
153
|
};
|
|
142
154
|
this.emit('request', request);
|
|
143
155
|
const response = await this.client
|
|
@@ -154,6 +166,9 @@ export class MCPClient extends EventEmitter {
|
|
|
154
166
|
error.data = response.error.data;
|
|
155
167
|
throw error;
|
|
156
168
|
}
|
|
169
|
+
if (response.result === undefined) {
|
|
170
|
+
return {};
|
|
171
|
+
}
|
|
157
172
|
return response.result;
|
|
158
173
|
}
|
|
159
174
|
async connectSSE() {
|
|
@@ -173,8 +188,11 @@ export class MCPClient extends EventEmitter {
|
|
|
173
188
|
}
|
|
174
189
|
}
|
|
175
190
|
handleSSEEvent(event) {
|
|
191
|
+
const payload = typeof event === 'string' ? event : event.data;
|
|
192
|
+
if (!payload)
|
|
193
|
+
return;
|
|
176
194
|
try {
|
|
177
|
-
const data = JSON.parse(
|
|
195
|
+
const data = JSON.parse(payload);
|
|
178
196
|
switch (data.method) {
|
|
179
197
|
case 'notifications/progress':
|
|
180
198
|
this.emit('progress', data.params);
|
package/dist/mcp/contract.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ export declare function createMCPBatch<T extends MCPContractDefinition>(mcp: MCP
|
|
|
45
45
|
args?: T[K]["inputSchema"] extends ZodSchema ? z.infer<T[K]["inputSchema"]> : Record<string, unknown>;
|
|
46
46
|
}>) => Promise<Array<{
|
|
47
47
|
success: boolean;
|
|
48
|
-
result?:
|
|
48
|
+
result?: unknown;
|
|
49
49
|
error?: Error;
|
|
50
50
|
}>>;
|
|
51
51
|
export interface SSEStreamOptions {
|
package/dist/mcp/profiles.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValidationError } from '../core/errors.js';
|
|
1
2
|
export const categories = {
|
|
2
3
|
minimal: {
|
|
3
4
|
name: 'minimal',
|
|
@@ -216,7 +217,10 @@ export function resolveCategories(categoryNames) {
|
|
|
216
217
|
for (const name of names) {
|
|
217
218
|
const category = categories[name];
|
|
218
219
|
if (!category) {
|
|
219
|
-
throw new
|
|
220
|
+
throw new ValidationError(`Unknown category: ${name}.`, {
|
|
221
|
+
field: 'categoryNames',
|
|
222
|
+
value: name,
|
|
223
|
+
});
|
|
220
224
|
}
|
|
221
225
|
for (const tool of category.tools) {
|
|
222
226
|
toolSet.add(tool);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValidationError } from '../../core/errors.js';
|
|
1
2
|
export class PromptRegistry {
|
|
2
3
|
prompts = new Map();
|
|
3
4
|
constructor() {
|
|
@@ -12,7 +13,7 @@ export class PromptRegistry {
|
|
|
12
13
|
async getPrompt(name, args) {
|
|
13
14
|
const prompt = this.prompts.get(name);
|
|
14
15
|
if (!prompt) {
|
|
15
|
-
throw new
|
|
16
|
+
throw new ValidationError(`Prompt not found: ${name}`, { field: 'name', value: name });
|
|
16
17
|
}
|
|
17
18
|
return prompt.handler(args);
|
|
18
19
|
}
|
|
@@ -508,10 +509,13 @@ const client = createClient();
|
|
|
508
509
|
// Rotate user agents
|
|
509
510
|
client.use(userAgent({ rotate: true, type: 'desktop' }));
|
|
510
511
|
|
|
511
|
-
// Rotate proxies
|
|
512
|
+
// Rotate proxies (or pass the list directly to createClient)
|
|
513
|
+
const client2 = createClient({
|
|
514
|
+
proxy: ['http://proxy1:8080', 'socks5://proxy2:1080', 'socks5h://proxy3:1080'],
|
|
515
|
+
});
|
|
516
|
+
// Alternative via plugin
|
|
512
517
|
client.use(proxyRotator({
|
|
513
|
-
proxies: ['http://proxy1:8080', '
|
|
514
|
-
strategy: 'round-robin',
|
|
518
|
+
proxies: ['http://proxy1:8080', 'socks5://proxy2:1080'],
|
|
515
519
|
}));
|
|
516
520
|
|
|
517
521
|
// Respect rate limits
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { listCategories } from '../tools/categories.js';
|
|
2
|
+
import { ConfigurationError, NotFoundError } from '../../core/errors.js';
|
|
2
3
|
export class ResourceRegistry {
|
|
3
4
|
resources = new Map();
|
|
4
5
|
templates = [];
|
|
@@ -41,7 +42,7 @@ export class ResourceRegistry {
|
|
|
41
42
|
return template.handler(params);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
throw new
|
|
45
|
+
throw new NotFoundError(`Resource not found: ${uri}`, { resource: uri });
|
|
45
46
|
}
|
|
46
47
|
recordRequest(method, url, status, duration) {
|
|
47
48
|
this.requestHistory.push({
|
|
@@ -359,9 +360,9 @@ export class ResourceRegistry {
|
|
|
359
360
|
async loadPresetDetails(name) {
|
|
360
361
|
try {
|
|
361
362
|
const { presetRegistry } = await import('../../presets/registry.js');
|
|
362
|
-
const preset = presetRegistry.find(p => p.name === name);
|
|
363
|
+
const preset = presetRegistry.find((p) => p.name === name);
|
|
363
364
|
if (!preset) {
|
|
364
|
-
throw new
|
|
365
|
+
throw new NotFoundError(`Preset not found: ${name}`, { resource: name });
|
|
365
366
|
}
|
|
366
367
|
const envVar = `${name.toUpperCase().replace(/-/g, '_')}_API_KEY`;
|
|
367
368
|
return {
|
|
@@ -386,7 +387,9 @@ const response = await client.get('/endpoint').json();
|
|
|
386
387
|
};
|
|
387
388
|
}
|
|
388
389
|
catch (e) {
|
|
389
|
-
throw new
|
|
390
|
+
throw new ConfigurationError(`Failed to load preset '${name}': ${getErrorMessage(e)}`, {
|
|
391
|
+
configKey: `preset.${name}`,
|
|
392
|
+
});
|
|
390
393
|
}
|
|
391
394
|
}
|
|
392
395
|
async getReckerInfo() {
|
|
@@ -467,7 +470,7 @@ pnpm bench:json # JSON output
|
|
|
467
470
|
};
|
|
468
471
|
}
|
|
469
472
|
catch (e) {
|
|
470
|
-
results.checks.dns = { status: 'error', error: e
|
|
473
|
+
results.checks.dns = { status: 'error', error: getErrorMessage(e) };
|
|
471
474
|
}
|
|
472
475
|
try {
|
|
473
476
|
const { inspectTLS } = await import('../../utils/tls-inspector.js');
|
|
@@ -485,7 +488,7 @@ pnpm bench:json # JSON output
|
|
|
485
488
|
};
|
|
486
489
|
}
|
|
487
490
|
catch (e) {
|
|
488
|
-
results.checks.tls = { status: 'error', error: e
|
|
491
|
+
results.checks.tls = { status: 'error', error: getErrorMessage(e) };
|
|
489
492
|
}
|
|
490
493
|
try {
|
|
491
494
|
const { createClient } = await import('../../core/client.js');
|
|
@@ -505,7 +508,7 @@ pnpm bench:json # JSON output
|
|
|
505
508
|
};
|
|
506
509
|
}
|
|
507
510
|
catch (e) {
|
|
508
|
-
results.checks.http = { status: 'error', error: e
|
|
511
|
+
results.checks.http = { status: 'error', error: getErrorMessage(e) };
|
|
509
512
|
}
|
|
510
513
|
return results;
|
|
511
514
|
}
|
|
@@ -527,16 +530,16 @@ pnpm bench:json # JSON output
|
|
|
527
530
|
return {
|
|
528
531
|
url,
|
|
529
532
|
status: 'healthy',
|
|
530
|
-
statusCode: lastResponse
|
|
533
|
+
statusCode: lastResponse?.status,
|
|
531
534
|
latency: {
|
|
532
535
|
avg: `${avgLatency}ms`,
|
|
533
536
|
min: `${minLatency}ms`,
|
|
534
537
|
max: `${maxLatency}ms`,
|
|
535
538
|
},
|
|
536
539
|
headers: {
|
|
537
|
-
server: lastResponse
|
|
538
|
-
contentType: lastResponse
|
|
539
|
-
cacheControl: lastResponse
|
|
540
|
+
server: lastResponse?.headers.get('server'),
|
|
541
|
+
contentType: lastResponse?.headers.get('content-type'),
|
|
542
|
+
cacheControl: lastResponse?.headers.get('cache-control'),
|
|
540
543
|
},
|
|
541
544
|
checkedAt: new Date().toISOString(),
|
|
542
545
|
};
|
|
@@ -545,7 +548,7 @@ pnpm bench:json # JSON output
|
|
|
545
548
|
return {
|
|
546
549
|
url,
|
|
547
550
|
status: 'unhealthy',
|
|
548
|
-
error: e
|
|
551
|
+
error: getErrorMessage(e),
|
|
549
552
|
latency: `${Date.now() - startTime}ms (failed)`,
|
|
550
553
|
checkedAt: new Date().toISOString(),
|
|
551
554
|
};
|
|
@@ -671,7 +674,12 @@ import { userAgent, proxyRotator } from 'recker/plugins';
|
|
|
671
674
|
|
|
672
675
|
const client = createClient();
|
|
673
676
|
client.use(userAgent({ rotate: true }));
|
|
674
|
-
|
|
677
|
+
// Proxy list directly in createClient (recommended):
|
|
678
|
+
const client2 = createClient({
|
|
679
|
+
proxy: ['http://proxy1:8080', 'socks5://proxy2:1080', 'socks5h://proxy3:1080'],
|
|
680
|
+
});
|
|
681
|
+
// Or via plugin:
|
|
682
|
+
client.use(proxyRotator({ proxies: ['http://proxy1:8080', 'socks5://proxy2:1080'] }));
|
|
675
683
|
|
|
676
684
|
const doc = await client.scrape('https://protected-site.com');
|
|
677
685
|
\`\`\`
|
|
@@ -1003,19 +1011,20 @@ Make sure the URL is accessible and try again.
|
|
|
1003
1011
|
const pricing = [];
|
|
1004
1012
|
for (const provider of catalog.providers) {
|
|
1005
1013
|
for (const model of provider.models) {
|
|
1014
|
+
const features = [
|
|
1015
|
+
model.vision && 'vision',
|
|
1016
|
+
model.tools && 'tools',
|
|
1017
|
+
model.reasoning && 'reasoning',
|
|
1018
|
+
model.fast && 'fast',
|
|
1019
|
+
model.coding && 'coding',
|
|
1020
|
+
].filter((value) => Boolean(value));
|
|
1006
1021
|
pricing.push({
|
|
1007
1022
|
provider: provider.name,
|
|
1008
1023
|
model: model.id,
|
|
1009
1024
|
input: `$${model.inputPrice?.toFixed(2) || 'N/A'}`,
|
|
1010
1025
|
output: `$${model.outputPrice?.toFixed(2) || 'N/A'}`,
|
|
1011
1026
|
context: model.context?.toLocaleString() || 'N/A',
|
|
1012
|
-
features
|
|
1013
|
-
model.vision && 'vision',
|
|
1014
|
-
model.tools && 'tools',
|
|
1015
|
-
model.reasoning && 'reasoning',
|
|
1016
|
-
model.fast && 'fast',
|
|
1017
|
-
model.coding && 'coding',
|
|
1018
|
-
].filter(Boolean),
|
|
1027
|
+
features,
|
|
1019
1028
|
});
|
|
1020
1029
|
}
|
|
1021
1030
|
}
|
|
@@ -1042,7 +1051,7 @@ Make sure the URL is accessible and try again.
|
|
|
1042
1051
|
const provider = catalog.providers.find((p) => p.name === name);
|
|
1043
1052
|
if (!provider) {
|
|
1044
1053
|
const available = catalog.providers.map((p) => p.name).join(', ');
|
|
1045
|
-
throw new
|
|
1054
|
+
throw new NotFoundError(`Provider '${name}' not found. Available: ${available}`, { resource: name });
|
|
1046
1055
|
}
|
|
1047
1056
|
return {
|
|
1048
1057
|
name: provider.name,
|
|
@@ -1061,10 +1070,24 @@ Make sure the URL is accessible and try again.
|
|
|
1061
1070
|
}[name] || null,
|
|
1062
1071
|
features: {
|
|
1063
1072
|
streaming: true,
|
|
1064
|
-
functionCalling: provider.models.some((m) => m.tools),
|
|
1065
|
-
vision: provider.models.some((m) => m.vision),
|
|
1073
|
+
functionCalling: provider.models.some((m) => Boolean(m.tools)),
|
|
1074
|
+
vision: provider.models.some((m) => Boolean(m.vision)),
|
|
1066
1075
|
embeddings: ['openai', 'google', 'mistral'].includes(name),
|
|
1067
1076
|
},
|
|
1068
1077
|
};
|
|
1069
1078
|
}
|
|
1070
1079
|
}
|
|
1080
|
+
function getErrorMessage(error) {
|
|
1081
|
+
if (error instanceof Error) {
|
|
1082
|
+
return error.message;
|
|
1083
|
+
}
|
|
1084
|
+
if (typeof error === 'string') {
|
|
1085
|
+
return error;
|
|
1086
|
+
}
|
|
1087
|
+
try {
|
|
1088
|
+
return JSON.stringify(error);
|
|
1089
|
+
}
|
|
1090
|
+
catch {
|
|
1091
|
+
return String(error);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync, readdirSync, statSync, existsSync } from 'fs';
|
|
|
3
3
|
import { join, relative, extname, basename, dirname } from 'path';
|
|
4
4
|
import { createInterface } from 'readline';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import { UnsupportedError } from '../core/errors.js';
|
|
6
|
+
import { NotFoundError, UnsupportedError } from '../core/errors.js';
|
|
7
7
|
import { getIpInfo, isValidIP, isGeoIPAvailable, isBogon, isIPv6 } from './ip-intel.js';
|
|
8
8
|
import { networkTools, networkToolHandlers } from './tools/network.js';
|
|
9
9
|
import { seoTools, seoToolHandlers } from './tools/seo.js';
|
|
@@ -298,8 +298,9 @@ export class MCPServer {
|
|
|
298
298
|
return 'general';
|
|
299
299
|
}
|
|
300
300
|
inferComplexity(content, docComment) {
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
const complexityMatch = docComment.match(/@complexity\s+(basic|intermediate|advanced)/i);
|
|
302
|
+
if (complexityMatch?.[1]) {
|
|
303
|
+
return complexityMatch[1].toLowerCase();
|
|
303
304
|
}
|
|
304
305
|
const lines = content.split('\n').length;
|
|
305
306
|
const hasAsyncAwait = /async|await/.test(content);
|
|
@@ -518,7 +519,7 @@ export class MCPServer {
|
|
|
518
519
|
const path = uri.slice(7);
|
|
519
520
|
const doc = this.docsIndex.find(d => d.path === path);
|
|
520
521
|
if (!doc) {
|
|
521
|
-
throw new
|
|
522
|
+
throw new NotFoundError(`Documentation not found: ${path}`, { resource: path });
|
|
522
523
|
}
|
|
523
524
|
return [{
|
|
524
525
|
uri,
|
|
@@ -531,7 +532,7 @@ export class MCPServer {
|
|
|
531
532
|
const id = uri.slice(10);
|
|
532
533
|
const example = this.codeExamples.find(e => e.id === id);
|
|
533
534
|
if (!example) {
|
|
534
|
-
throw new
|
|
535
|
+
throw new NotFoundError(`Example not found: ${id}`, { resource: id });
|
|
535
536
|
}
|
|
536
537
|
return [{
|
|
537
538
|
uri,
|
|
@@ -540,7 +541,9 @@ export class MCPServer {
|
|
|
540
541
|
type: 'resource',
|
|
541
542
|
}];
|
|
542
543
|
}
|
|
543
|
-
throw new
|
|
544
|
+
throw new UnsupportedError(`Unknown resource scheme: ${uri}`, {
|
|
545
|
+
feature: 'recker://, docs://, example://',
|
|
546
|
+
});
|
|
544
547
|
}
|
|
545
548
|
getResourceRegistry() {
|
|
546
549
|
return this.resourceRegistry;
|
|
@@ -2,6 +2,7 @@ import { createFTP } from '../../protocols/ftp.js';
|
|
|
2
2
|
import { createSFTP } from '../../protocols/sftp.js';
|
|
3
3
|
import { createTelnet } from '../../protocols/telnet.js';
|
|
4
4
|
import { createWebSocket } from '../../websocket/client.js';
|
|
5
|
+
import { ProtocolError } from '../../core/errors.js';
|
|
5
6
|
export const ftpConnectTool = {
|
|
6
7
|
name: 'rek_ftp_connect',
|
|
7
8
|
description: 'Connect to an FTP server and list directory contents. Supports FTPS (implicit TLS).',
|
|
@@ -143,7 +144,10 @@ export const ftpDownloadTool = {
|
|
|
143
144
|
await ftp.close();
|
|
144
145
|
const content = downloadResult.data;
|
|
145
146
|
if (!content) {
|
|
146
|
-
throw new
|
|
147
|
+
throw new ProtocolError('Failed to download file', {
|
|
148
|
+
protocol: 'ftp',
|
|
149
|
+
phase: 'download',
|
|
150
|
+
});
|
|
147
151
|
}
|
|
148
152
|
let textContent;
|
|
149
153
|
let isText = true;
|
|
@@ -334,7 +338,10 @@ export const sftpDownloadTool = {
|
|
|
334
338
|
await sftp.close();
|
|
335
339
|
const content = downloadResult.data;
|
|
336
340
|
if (!content) {
|
|
337
|
-
throw new
|
|
341
|
+
throw new ProtocolError('Failed to download file', {
|
|
342
|
+
protocol: 'sftp',
|
|
343
|
+
phase: 'download',
|
|
344
|
+
});
|
|
338
345
|
}
|
|
339
346
|
let textContent;
|
|
340
347
|
let isText = true;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { matchesPattern } from '../profiles.js';
|
|
2
2
|
import { getToolCategory, listCategories } from './categories.js';
|
|
3
|
+
import { StateError, ValidationError } from '../../core/errors.js';
|
|
3
4
|
export class ToolRegistry {
|
|
4
5
|
tools = new Map();
|
|
5
6
|
handlers = new Map();
|
|
@@ -13,7 +14,10 @@ export class ToolRegistry {
|
|
|
13
14
|
}
|
|
14
15
|
registerTool(tool, handler) {
|
|
15
16
|
if (this.tools.has(tool.name)) {
|
|
16
|
-
throw new
|
|
17
|
+
throw new ValidationError(`Tool already registered: ${tool.name}`, {
|
|
18
|
+
field: 'tool.name',
|
|
19
|
+
value: tool.name,
|
|
20
|
+
});
|
|
17
21
|
}
|
|
18
22
|
this.tools.set(tool.name, tool);
|
|
19
23
|
this.handlers.set(tool.name, handler);
|
|
@@ -22,7 +26,10 @@ export class ToolRegistry {
|
|
|
22
26
|
for (const tool of module.tools) {
|
|
23
27
|
const handler = module.handlers[tool.name];
|
|
24
28
|
if (!handler) {
|
|
25
|
-
throw new
|
|
29
|
+
throw new ValidationError(`Handler missing for tool: ${tool.name}`, {
|
|
30
|
+
field: `handlers["${tool.name}"]`,
|
|
31
|
+
value: undefined,
|
|
32
|
+
});
|
|
26
33
|
}
|
|
27
34
|
this.registerTool(tool, handler);
|
|
28
35
|
}
|
|
@@ -100,7 +107,10 @@ export class ToolRegistry {
|
|
|
100
107
|
async callTool(name, args) {
|
|
101
108
|
const handler = this.handlers.get(name);
|
|
102
109
|
if (!handler) {
|
|
103
|
-
throw new
|
|
110
|
+
throw new StateError(`Unknown tool: ${name}`, {
|
|
111
|
+
expectedState: 'registered tool',
|
|
112
|
+
actualState: name,
|
|
113
|
+
});
|
|
104
114
|
}
|
|
105
115
|
return handler(args);
|
|
106
116
|
}
|