polydev-ai 1.2.5 → 1.2.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/mcp/README.md +6 -11
- package/mcp/package.json +1 -1
- package/mcp/stdio-wrapper.js +137 -96
- package/package.json +1 -1
package/mcp/README.md
CHANGED
|
@@ -57,17 +57,12 @@ export POLYDEV_USER_TOKEN="pd_your_token_here"
|
|
|
57
57
|
Add to your Claude Code MCP configuration:
|
|
58
58
|
|
|
59
59
|
```json
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"POLYDEV_USER_TOKEN": "pd_your_token_here"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
60
|
+
"polydev": {
|
|
61
|
+
"disabled": false,
|
|
62
|
+
"timeout": 120,
|
|
63
|
+
"type": "http",
|
|
64
|
+
"url": "https://www.polydev.ai/api/mcp"
|
|
65
|
+
},
|
|
71
66
|
```
|
|
72
67
|
|
|
73
68
|
## Available Tools
|
package/mcp/package.json
CHANGED
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -212,7 +212,7 @@ class StdioMCPWrapper {
|
|
|
212
212
|
// Save status locally to file-based cache
|
|
213
213
|
await this.saveLocalCliStatus(results);
|
|
214
214
|
|
|
215
|
-
//
|
|
215
|
+
// Update database with CLI status
|
|
216
216
|
await this.updateCliStatusInDatabase(results);
|
|
217
217
|
|
|
218
218
|
return {
|
|
@@ -250,10 +250,10 @@ class StdioMCPWrapper {
|
|
|
250
250
|
results = status;
|
|
251
251
|
} else {
|
|
252
252
|
// Get all providers status
|
|
253
|
-
const providers = this.cliManager.
|
|
253
|
+
const providers = this.cliManager.getProviders();
|
|
254
254
|
for (const provider of providers) {
|
|
255
255
|
const status = await this.cliManager.getCliStatus(provider.id);
|
|
256
|
-
results[provider.id] = status
|
|
256
|
+
results[provider.id] = status;
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -280,7 +280,7 @@ class StdioMCPWrapper {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
/**
|
|
283
|
-
* Local CLI prompt sending with remote perspectives
|
|
283
|
+
* Local CLI prompt sending with ALL available CLIs + remote perspectives
|
|
284
284
|
*/
|
|
285
285
|
async localSendCliPrompt(args) {
|
|
286
286
|
console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
|
|
@@ -290,49 +290,68 @@ class StdioMCPWrapper {
|
|
|
290
290
|
|
|
291
291
|
// Ensure timeout_ms is valid (not undefined, null, Infinity, or negative)
|
|
292
292
|
if (!timeout_ms || timeout_ms === Infinity || timeout_ms < 1 || timeout_ms > 300000) {
|
|
293
|
-
timeout_ms = 30000 // Default to 30 seconds
|
|
293
|
+
timeout_ms = 30000; // Default to 30 seconds
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
if (!prompt) {
|
|
297
297
|
throw new Error('prompt is required');
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
// Auto-select best available provider if none specified
|
|
301
|
-
if (!provider_id) {
|
|
302
|
-
provider_id = await this.selectBestProvider();
|
|
303
|
-
console.error(`[Stdio Wrapper] Auto-selected provider: ${provider_id}`);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
300
|
// Use reasonable timeout for CLI responses (15 seconds instead of 5)
|
|
307
301
|
const gracefulTimeout = Math.min(timeout_ms, 15000);
|
|
308
|
-
|
|
309
|
-
// Start both operations concurrently for better performance
|
|
310
|
-
const [localResult, perspectivesResult] = await Promise.allSettled([
|
|
311
|
-
this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout),
|
|
312
|
-
this.callPerspectivesForCli(args, null)
|
|
313
|
-
]);
|
|
314
|
-
|
|
315
|
-
// Process results
|
|
316
|
-
const localResponse = localResult.status === 'fulfilled' ? localResult.value : {
|
|
317
|
-
success: false,
|
|
318
|
-
error: `CLI check failed: ${localResult.reason?.message || 'Unknown error'}`,
|
|
319
|
-
latency_ms: gracefulTimeout,
|
|
320
|
-
timestamp: new Date().toISOString()
|
|
321
|
-
};
|
|
322
302
|
|
|
323
|
-
|
|
324
|
-
success: false,
|
|
325
|
-
error: `Perspectives failed: ${perspectivesResult.reason?.message || 'Unknown error'}`,
|
|
326
|
-
timestamp: new Date().toISOString()
|
|
327
|
-
};
|
|
303
|
+
let localResults = [];
|
|
328
304
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
console.error(
|
|
332
|
-
|
|
305
|
+
if (provider_id) {
|
|
306
|
+
// Specific provider requested - use only that one
|
|
307
|
+
console.error(`[Stdio Wrapper] Using specific provider: ${provider_id}`);
|
|
308
|
+
const result = await this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout);
|
|
309
|
+
localResults = [{ provider_id, ...result }];
|
|
310
|
+
} else {
|
|
311
|
+
// No specific provider - use ALL available local CLIs
|
|
312
|
+
console.error(`[Stdio Wrapper] Using all available local CLIs`);
|
|
313
|
+
const availableProviders = await this.getAllAvailableProviders();
|
|
314
|
+
|
|
315
|
+
if (availableProviders.length === 0) {
|
|
316
|
+
console.error(`[Stdio Wrapper] No local CLIs available, will use remote perspectives only`);
|
|
317
|
+
localResults = [];
|
|
318
|
+
} else {
|
|
319
|
+
console.error(`[Stdio Wrapper] Found ${availableProviders.length} available CLIs: ${availableProviders.join(', ')}`);
|
|
320
|
+
|
|
321
|
+
// Run all CLI prompts concurrently
|
|
322
|
+
const cliPromises = availableProviders.map(async (providerId) => {
|
|
323
|
+
try {
|
|
324
|
+
const result = await this.cliManager.sendCliPrompt(providerId, prompt, mode, gracefulTimeout);
|
|
325
|
+
return { provider_id: providerId, ...result };
|
|
326
|
+
} catch (error) {
|
|
327
|
+
console.error(`[Stdio Wrapper] CLI ${providerId} failed:`, error.message);
|
|
328
|
+
return {
|
|
329
|
+
provider_id: providerId,
|
|
330
|
+
success: false,
|
|
331
|
+
error: error.message,
|
|
332
|
+
latency_ms: gracefulTimeout
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
});
|
|
333
336
|
|
|
334
|
-
|
|
335
|
-
|
|
337
|
+
localResults = await Promise.all(cliPromises);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Get remote perspectives (only for models not covered by local CLIs)
|
|
342
|
+
const perspectivesResult = await this.callPerspectivesForCli(args, localResults);
|
|
343
|
+
|
|
344
|
+
// Record usage for all CLI responses
|
|
345
|
+
for (const localResult of localResults) {
|
|
346
|
+
if (localResult.provider_id) {
|
|
347
|
+
this.recordLocalUsage(localResult.provider_id, prompt, localResult).catch(err => {
|
|
348
|
+
console.error(`[Stdio Wrapper] Usage recording failed for ${localResult.provider_id} (non-critical):`, err.message);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Combine all results
|
|
354
|
+
return this.combineAllCliAndPerspectives(localResults, perspectivesResult, args);
|
|
336
355
|
|
|
337
356
|
} catch (error) {
|
|
338
357
|
console.error('[Stdio Wrapper] Local CLI prompt error:', error);
|
|
@@ -346,43 +365,35 @@ class StdioMCPWrapper {
|
|
|
346
365
|
}
|
|
347
366
|
|
|
348
367
|
/**
|
|
349
|
-
*
|
|
368
|
+
* Get all available and authenticated CLI providers
|
|
350
369
|
*/
|
|
351
|
-
async
|
|
370
|
+
async getAllAvailableProviders() {
|
|
352
371
|
try {
|
|
353
|
-
const
|
|
372
|
+
const results = await this.cliManager.forceCliDetection();
|
|
373
|
+
const availableProviders = [];
|
|
354
374
|
|
|
355
375
|
// Priority order: claude_code > codex_cli > gemini_cli
|
|
356
376
|
const priorityOrder = ['claude_code', 'codex_cli', 'gemini_cli'];
|
|
357
377
|
|
|
358
378
|
for (const providerId of priorityOrder) {
|
|
359
|
-
const status =
|
|
379
|
+
const status = results[providerId];
|
|
360
380
|
if (status && status.available && status.authenticated) {
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// If no authenticated provider, return the first available one
|
|
366
|
-
for (const providerId of priorityOrder) {
|
|
367
|
-
const status = allStatus[providerId];
|
|
368
|
-
if (status && status.available) {
|
|
369
|
-
return providerId;
|
|
381
|
+
availableProviders.push(providerId);
|
|
370
382
|
}
|
|
371
383
|
}
|
|
372
384
|
|
|
373
|
-
|
|
374
|
-
return 'claude_code';
|
|
385
|
+
return availableProviders;
|
|
375
386
|
|
|
376
387
|
} catch (error) {
|
|
377
|
-
console.error('[Stdio Wrapper]
|
|
378
|
-
return
|
|
388
|
+
console.error('[Stdio Wrapper] Failed to get available providers:', error);
|
|
389
|
+
return [];
|
|
379
390
|
}
|
|
380
391
|
}
|
|
381
392
|
|
|
382
393
|
/**
|
|
383
394
|
* Call remote perspectives for CLI prompts
|
|
384
395
|
*/
|
|
385
|
-
async callPerspectivesForCli(args,
|
|
396
|
+
async callPerspectivesForCli(args, localResults) {
|
|
386
397
|
console.error(`[Stdio Wrapper] Calling remote perspectives for CLI prompt`);
|
|
387
398
|
|
|
388
399
|
try {
|
|
@@ -440,76 +451,99 @@ class StdioMCPWrapper {
|
|
|
440
451
|
}
|
|
441
452
|
|
|
442
453
|
/**
|
|
443
|
-
* Combine
|
|
454
|
+
* Combine multiple CLI results and remote perspectives
|
|
444
455
|
*/
|
|
445
|
-
|
|
456
|
+
combineAllCliAndPerspectives(localResults, perspectivesResult, args) {
|
|
446
457
|
const combinedResult = {
|
|
447
458
|
success: true,
|
|
448
459
|
timestamp: new Date().toISOString(),
|
|
449
|
-
provider: args.provider_id,
|
|
450
460
|
mode: args.mode,
|
|
461
|
+
local_cli_count: localResults.length,
|
|
451
462
|
sections: {
|
|
452
|
-
local:
|
|
463
|
+
local: localResults,
|
|
453
464
|
remote: perspectivesResult
|
|
454
465
|
}
|
|
455
466
|
};
|
|
456
467
|
|
|
457
|
-
//
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
combinedResult.
|
|
468
|
+
// Check if any local CLIs succeeded
|
|
469
|
+
const successfulClis = localResults.filter(result => result.success);
|
|
470
|
+
const hasSomeLocalSuccess = successfulClis.length > 0;
|
|
471
|
+
|
|
472
|
+
// Determine overall success and content
|
|
473
|
+
if (hasSomeLocalSuccess && perspectivesResult.success) {
|
|
474
|
+
combinedResult.content = this.formatMultipleCliResponse(localResults, perspectivesResult, false);
|
|
475
|
+
combinedResult.tokens_used = successfulClis.reduce((total, cli) => total + (cli.tokens_used || 0), 0);
|
|
476
|
+
combinedResult.latency_ms = Math.max(...successfulClis.map(cli => cli.latency_ms || 0));
|
|
477
|
+
} else if (!hasSomeLocalSuccess && perspectivesResult.success) {
|
|
478
|
+
// Complete fallback case - no local CLIs worked
|
|
479
|
+
combinedResult.content = this.formatMultipleCliResponse(localResults, perspectivesResult, true);
|
|
465
480
|
combinedResult.fallback_used = true;
|
|
466
481
|
combinedResult.tokens_used = 0; // No local tokens used
|
|
467
|
-
} else if (
|
|
468
|
-
// Local succeeded, remote failed
|
|
469
|
-
combinedResult.content = this.
|
|
470
|
-
combinedResult.tokens_used =
|
|
471
|
-
combinedResult.latency_ms =
|
|
482
|
+
} else if (hasSomeLocalSuccess && !perspectivesResult.success) {
|
|
483
|
+
// Local CLIs succeeded, remote failed
|
|
484
|
+
combinedResult.content = this.formatMultipleCliResponse(localResults, perspectivesResult, false);
|
|
485
|
+
combinedResult.tokens_used = successfulClis.reduce((total, cli) => total + (cli.tokens_used || 0), 0);
|
|
486
|
+
combinedResult.latency_ms = Math.max(...successfulClis.map(cli => cli.latency_ms || 0));
|
|
472
487
|
} else {
|
|
473
488
|
// Both failed
|
|
474
489
|
combinedResult.success = false;
|
|
475
|
-
|
|
490
|
+
const cliErrors = localResults.map(cli => `${cli.provider_id}: ${cli.error}`).join('; ');
|
|
491
|
+
combinedResult.error = `All local CLIs failed: ${cliErrors}; Perspectives also failed: ${perspectivesResult.error}`;
|
|
476
492
|
}
|
|
477
493
|
|
|
478
494
|
return combinedResult;
|
|
479
495
|
}
|
|
480
496
|
|
|
481
497
|
/**
|
|
482
|
-
* Format
|
|
498
|
+
* Format multiple CLI responses with remote perspectives
|
|
483
499
|
*/
|
|
484
|
-
|
|
500
|
+
formatMultipleCliResponse(localResults, perspectivesResult, isFallback) {
|
|
485
501
|
let formatted = '';
|
|
486
502
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
503
|
+
// Show all local CLI responses
|
|
504
|
+
const successfulClis = localResults.filter(result => result.success);
|
|
505
|
+
const failedClis = localResults.filter(result => !result.success);
|
|
506
|
+
|
|
507
|
+
if (successfulClis.length > 0) {
|
|
508
|
+
// Show successful CLI responses
|
|
509
|
+
for (const cliResult of successfulClis) {
|
|
510
|
+
formatted += `🟢 **Local CLI Response** (${cliResult.provider_id} - ${cliResult.mode || 'args'} mode)\n\n`;
|
|
511
|
+
formatted += `${cliResult.content}\n\n`;
|
|
512
|
+
formatted += `*Latency: ${cliResult.latency_ms || 0}ms | Tokens: ${cliResult.tokens_used || 0}*\n\n`;
|
|
513
|
+
formatted += `---\n\n`;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (failedClis.length > 0 && successfulClis.length === 0) {
|
|
518
|
+
// All local CLIs failed
|
|
519
|
+
formatted += `⚠️ **All Local CLIs Unavailable**\n`;
|
|
520
|
+
for (const cliResult of failedClis) {
|
|
521
|
+
formatted += `- ${cliResult.provider_id}: ${cliResult.error}\n`;
|
|
522
|
+
}
|
|
496
523
|
formatted += `Using perspectives fallback.\n\n`;
|
|
497
524
|
formatted += `---\n\n`;
|
|
525
|
+
} else if (failedClis.length > 0) {
|
|
526
|
+
// Some CLIs failed, some succeeded
|
|
527
|
+
formatted += `⚠️ **Some CLIs Failed**\n`;
|
|
528
|
+
for (const cliResult of failedClis) {
|
|
529
|
+
formatted += `- ${cliResult.provider_id}: ${cliResult.error}\n`;
|
|
530
|
+
}
|
|
531
|
+
formatted += `\n---\n\n`;
|
|
498
532
|
}
|
|
499
533
|
|
|
534
|
+
// Add remote perspectives
|
|
500
535
|
if (perspectivesResult.success) {
|
|
501
536
|
if (perspectivesResult.raw) {
|
|
502
|
-
// Raw content is already formatted - use as-is
|
|
503
|
-
// The remote server already includes proper headers like "Multiple AI Perspectives"
|
|
537
|
+
// Raw content is already formatted - use as-is
|
|
504
538
|
formatted += `${perspectivesResult.content}\n\n`;
|
|
505
539
|
} else {
|
|
506
|
-
// Legacy formatting
|
|
507
|
-
const title =
|
|
540
|
+
// Legacy formatting
|
|
541
|
+
const title = (successfulClis.length === 0) ? '🧠 **Perspectives Fallback**' : '🧠 **Supplemental Multi-Model Perspectives**';
|
|
508
542
|
formatted += `${title}\n\n`;
|
|
509
543
|
formatted += `${perspectivesResult.content}\n\n`;
|
|
510
544
|
}
|
|
511
|
-
} else if (
|
|
512
|
-
// Show remote error only if
|
|
545
|
+
} else if (successfulClis.length > 0) {
|
|
546
|
+
// Show remote error only if we have local success
|
|
513
547
|
formatted += `❌ **Perspectives request failed**: ${perspectivesResult.error}\n\n`;
|
|
514
548
|
}
|
|
515
549
|
|
|
@@ -523,18 +557,20 @@ class StdioMCPWrapper {
|
|
|
523
557
|
console.error('[Stdio Wrapper] Updating CLI status in database...');
|
|
524
558
|
|
|
525
559
|
try {
|
|
526
|
-
// Get user token
|
|
560
|
+
// Get user token from environment variables
|
|
527
561
|
const userToken = process.env.POLYDEV_MCP_TOKEN || this.userToken;
|
|
528
|
-
const userId = process.env.POLYDEV_USER_ID;
|
|
529
562
|
|
|
530
|
-
|
|
563
|
+
if (!userToken) {
|
|
564
|
+
console.error('[Stdio Wrapper] No user token available for database updates');
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
|
|
531
568
|
console.error(`[Stdio Wrapper] Using token: ${userToken ? userToken.substring(0, 20) + '...' : 'MISSING'}`);
|
|
532
569
|
|
|
533
570
|
for (const [providerId, result] of Object.entries(results)) {
|
|
534
571
|
const statusData = {
|
|
535
572
|
provider: providerId,
|
|
536
573
|
status: result.available ? 'available' : 'unavailable',
|
|
537
|
-
user_id: userId,
|
|
538
574
|
mcp_token: userToken,
|
|
539
575
|
cli_version: result.version || null,
|
|
540
576
|
cli_path: result.cli_path || null,
|
|
@@ -552,7 +588,6 @@ class StdioMCPWrapper {
|
|
|
552
588
|
console.error(`[Stdio Wrapper] Updating ${providerId} with data:`, JSON.stringify({
|
|
553
589
|
provider: statusData.provider,
|
|
554
590
|
status: statusData.status,
|
|
555
|
-
user_id: statusData.user_id,
|
|
556
591
|
authenticated: statusData.authenticated
|
|
557
592
|
}, null, 2));
|
|
558
593
|
|
|
@@ -778,14 +813,20 @@ class StdioMCPWrapper {
|
|
|
778
813
|
return `❌ **CLI Error**\n\n${result.error}\n\n*Timestamp: ${result.timestamp}*`;
|
|
779
814
|
}
|
|
780
815
|
|
|
781
|
-
// Handle combined CLI + perspectives response
|
|
816
|
+
// Handle combined CLI + perspectives response (single or multiple CLIs)
|
|
782
817
|
if (result.sections) {
|
|
783
818
|
return result.content;
|
|
784
819
|
}
|
|
785
820
|
|
|
786
821
|
if (result.content) {
|
|
787
822
|
// Standard prompt response
|
|
788
|
-
|
|
823
|
+
const cliCount = result.local_cli_count || 1;
|
|
824
|
+
|
|
825
|
+
if (cliCount > 1) {
|
|
826
|
+
return `✅ **Multi-CLI Response** (${cliCount} local CLIs + perspectives)\n\n${result.content}\n\n*Total Latency: ${result.latency_ms || 0}ms | Total Tokens: ${result.tokens_used || 0} | ${result.timestamp}*`;
|
|
827
|
+
} else {
|
|
828
|
+
return `✅ **CLI Response** (${result.provider || 'Unknown'} - ${result.mode || 'unknown'} mode)\n\n${result.content}\n\n*Latency: ${result.latency_ms || 0}ms | Tokens: ${result.tokens_used || 0} | ${result.timestamp}*`;
|
|
829
|
+
}
|
|
789
830
|
} else {
|
|
790
831
|
// Status/detection response
|
|
791
832
|
let formatted = `✅ **CLI Operation Success**\n\n`;
|
package/package.json
CHANGED