polydev-ai 1.9.24 → 1.9.26
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/lib/cliManager.js +12 -25
- package/mcp/manifest.json +245 -0
- package/mcp/stdio-wrapper.js +86 -34
- package/package.json +1 -1
package/lib/cliManager.js
CHANGED
|
@@ -208,7 +208,7 @@ class CLIManager {
|
|
|
208
208
|
provider.command,
|
|
209
209
|
provider.subcommands.version,
|
|
210
210
|
'args',
|
|
211
|
-
|
|
211
|
+
400000
|
|
212
212
|
);
|
|
213
213
|
version = versionResult.stdout?.trim();
|
|
214
214
|
} catch (versionError) {
|
|
@@ -244,7 +244,7 @@ class CLIManager {
|
|
|
244
244
|
provider.command,
|
|
245
245
|
provider.subcommands.auth_status,
|
|
246
246
|
'args',
|
|
247
|
-
|
|
247
|
+
400000 // Reduced timeout to 5 seconds
|
|
248
248
|
);
|
|
249
249
|
|
|
250
250
|
// If command succeeds, check output for authentication indicators
|
|
@@ -458,16 +458,16 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
458
458
|
}
|
|
459
459
|
|
|
460
460
|
async sendCliPrompt(providerId, prompt, mode = 'args', timeoutMs = null, model = null) {
|
|
461
|
-
// Set default timeout for CLI responses (
|
|
461
|
+
// Set default timeout for CLI responses (400 seconds)
|
|
462
462
|
// CLI-within-CLI scenarios (Claude Code calling Claude Code) need generous timeouts
|
|
463
463
|
if (timeoutMs === null) {
|
|
464
|
-
timeoutMs =
|
|
464
|
+
timeoutMs = 400000; // 400 seconds default for CLI responses
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
// Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
|
|
468
468
|
// Allow up to 600 seconds (10 minutes) for very complex operations
|
|
469
469
|
if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 600000) {
|
|
470
|
-
timeoutMs =
|
|
470
|
+
timeoutMs = 400000 // Default to 400 seconds for CLI responses
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
const startTime = Date.now();
|
|
@@ -806,11 +806,11 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
806
806
|
}
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
async executeCliCommand(command, args, mode = 'args', timeoutMs =
|
|
809
|
+
async executeCliCommand(command, args, mode = 'args', timeoutMs = 400000, stdinInput) {
|
|
810
810
|
// Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
|
|
811
|
-
//
|
|
811
|
+
// 400 seconds default for CLI responses
|
|
812
812
|
if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 600000) {
|
|
813
|
-
timeoutMs =
|
|
813
|
+
timeoutMs = 400000 // Default to 400 seconds
|
|
814
814
|
}
|
|
815
815
|
|
|
816
816
|
return new Promise((resolve, reject) => {
|
|
@@ -1180,14 +1180,10 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
1180
1180
|
const parseCodexOutput = (output) => {
|
|
1181
1181
|
if (!output || !output.trim()) return null;
|
|
1182
1182
|
|
|
1183
|
-
// Strip ANSI escape codes first — Codex CLI wraps markers like 'codex' and
|
|
1184
|
-
// 'tokens used' in bold/color codes which break regex matching
|
|
1185
|
-
const cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
|
|
1186
|
-
|
|
1187
1183
|
// First, try to extract the response between "codex" marker and "tokens used"
|
|
1188
1184
|
// IMPORTANT: Use (?:^|\n) to match "codex" only at the start of a line
|
|
1189
1185
|
// This prevents matching "codex" in model names like "gpt-5.2-codex"
|
|
1190
|
-
const codexMarkerMatch =
|
|
1186
|
+
const codexMarkerMatch = output.match(/(?:^|\n)codex\s*\n([\s\S]*?)(?:\n\s*tokens used|\n\s*$)/i);
|
|
1191
1187
|
if (codexMarkerMatch && codexMarkerMatch[1]) {
|
|
1192
1188
|
const extracted = codexMarkerMatch[1].trim();
|
|
1193
1189
|
if (extracted.length > 0 && !extracted.startsWith('ERROR')) {
|
|
@@ -1196,7 +1192,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
1196
1192
|
}
|
|
1197
1193
|
|
|
1198
1194
|
// Fallback: Try to find bullet point responses
|
|
1199
|
-
const bulletMatches =
|
|
1195
|
+
const bulletMatches = output.match(/•\s*(.+)/g);
|
|
1200
1196
|
if (bulletMatches && bulletMatches.length > 0) {
|
|
1201
1197
|
const bulletContent = bulletMatches
|
|
1202
1198
|
.map(m => m.replace(/^•\s*/, '').trim())
|
|
@@ -1208,9 +1204,8 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
1208
1204
|
}
|
|
1209
1205
|
|
|
1210
1206
|
// Last resort: Filter out known noise patterns line by line
|
|
1211
|
-
const lines =
|
|
1207
|
+
const lines = output.split('\n');
|
|
1212
1208
|
const contentLines = [];
|
|
1213
|
-
let seenTokensUsed = false;
|
|
1214
1209
|
|
|
1215
1210
|
// Patterns to skip (Codex-specific noise)
|
|
1216
1211
|
const noisePatterns = [
|
|
@@ -1230,6 +1225,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
1230
1225
|
/^thinking$/i, // "thinking" marker
|
|
1231
1226
|
/^codex$/i, // "codex" marker
|
|
1232
1227
|
/^tokens used$/i, // Token count header
|
|
1228
|
+
/^[\d,]+$/, // Just numbers (token counts)
|
|
1233
1229
|
/^ERROR:\s*MCP/i, // MCP errors
|
|
1234
1230
|
/MCP client for .* failed/i, // MCP client failures
|
|
1235
1231
|
/handshake.*failed/i, // Handshake errors
|
|
@@ -1244,15 +1240,6 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
1244
1240
|
for (const line of lines) {
|
|
1245
1241
|
const trimmedLine = line.trim();
|
|
1246
1242
|
|
|
1247
|
-
// Track when we've passed the "tokens used" footer
|
|
1248
|
-
if (/^tokens used$/i.test(trimmedLine)) {
|
|
1249
|
-
seenTokensUsed = true;
|
|
1250
|
-
continue;
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
// After "tokens used", skip pure numbers (token counts like "22")
|
|
1254
|
-
if (seenTokensUsed && /^[\d,]+$/.test(trimmedLine)) continue;
|
|
1255
|
-
|
|
1256
1243
|
// Check if line matches any noise pattern
|
|
1257
1244
|
const isNoise = noisePatterns.some(pattern => pattern.test(trimmedLine));
|
|
1258
1245
|
if (isNoise) continue;
|
package/mcp/manifest.json
CHANGED
|
@@ -292,6 +292,251 @@
|
|
|
292
292
|
}
|
|
293
293
|
]
|
|
294
294
|
},
|
|
295
|
+
{
|
|
296
|
+
"name": "force_cli_detection",
|
|
297
|
+
"description": "Force detection and status update for CLI tools (Claude Code, Codex CLI, Gemini CLI). Updates local cache and reports status to MCP server via Supabase.",
|
|
298
|
+
"inputSchema": {
|
|
299
|
+
"type": "object",
|
|
300
|
+
"properties": {
|
|
301
|
+
"user_id": {
|
|
302
|
+
"type": "string",
|
|
303
|
+
"description": "User ID for database status updates (optional for stdio-wrapper)",
|
|
304
|
+
"minLength": 1
|
|
305
|
+
},
|
|
306
|
+
"provider_id": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"description": "Specific CLI provider to detect (optional, detects all if not provided)",
|
|
309
|
+
"enum": ["claude_code", "codex_cli", "gemini_cli"]
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"outputSchema": {
|
|
314
|
+
"type": "object",
|
|
315
|
+
"properties": {
|
|
316
|
+
"success": {
|
|
317
|
+
"type": "boolean",
|
|
318
|
+
"description": "Whether detection was successful"
|
|
319
|
+
},
|
|
320
|
+
"results": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"description": "Detection results for each provider",
|
|
323
|
+
"additionalProperties": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"properties": {
|
|
326
|
+
"available": {
|
|
327
|
+
"type": "boolean",
|
|
328
|
+
"description": "Whether CLI is available"
|
|
329
|
+
},
|
|
330
|
+
"authenticated": {
|
|
331
|
+
"type": "boolean",
|
|
332
|
+
"description": "Whether CLI is authenticated"
|
|
333
|
+
},
|
|
334
|
+
"version": {
|
|
335
|
+
"type": "string",
|
|
336
|
+
"description": "CLI version if available"
|
|
337
|
+
},
|
|
338
|
+
"path": {
|
|
339
|
+
"type": "string",
|
|
340
|
+
"description": "Path to CLI executable"
|
|
341
|
+
},
|
|
342
|
+
"error": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"description": "Error message if detection failed"
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
"message": {
|
|
350
|
+
"type": "string",
|
|
351
|
+
"description": "Human-readable result message"
|
|
352
|
+
},
|
|
353
|
+
"timestamp": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"description": "Detection timestamp"
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"required": ["success", "results", "message", "timestamp"]
|
|
359
|
+
},
|
|
360
|
+
"examples": [
|
|
361
|
+
{
|
|
362
|
+
"description": "Detect all CLI providers",
|
|
363
|
+
"input": {
|
|
364
|
+
"user_id": "user_123"
|
|
365
|
+
},
|
|
366
|
+
"output": {
|
|
367
|
+
"success": true,
|
|
368
|
+
"results": {
|
|
369
|
+
"claude_code": {
|
|
370
|
+
"available": true,
|
|
371
|
+
"authenticated": true,
|
|
372
|
+
"version": "claude-code v1.2.3",
|
|
373
|
+
"path": "/usr/local/bin/claude"
|
|
374
|
+
},
|
|
375
|
+
"codex_cli": {
|
|
376
|
+
"available": false,
|
|
377
|
+
"authenticated": false,
|
|
378
|
+
"error": "Codex CLI not found in PATH. Install Codex CLI from OpenAI"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
"message": "CLI detection completed for all providers",
|
|
382
|
+
"timestamp": "2024-01-15T10:30:00Z"
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"name": "get_cli_status",
|
|
389
|
+
"description": "Get current CLI status with caching support. Returns cached results if available and fresh, otherwise performs new detection.",
|
|
390
|
+
"inputSchema": {
|
|
391
|
+
"type": "object",
|
|
392
|
+
"properties": {
|
|
393
|
+
"user_id": {
|
|
394
|
+
"type": "string",
|
|
395
|
+
"description": "User ID for database status retrieval (optional for stdio-wrapper)",
|
|
396
|
+
"minLength": 1
|
|
397
|
+
},
|
|
398
|
+
"provider_id": {
|
|
399
|
+
"type": "string",
|
|
400
|
+
"description": "Specific CLI provider status to get (optional, gets all if not provided)",
|
|
401
|
+
"enum": ["claude_code", "codex_cli", "gemini_cli"]
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
"outputSchema": {
|
|
406
|
+
"type": "object",
|
|
407
|
+
"properties": {
|
|
408
|
+
"success": {
|
|
409
|
+
"type": "boolean",
|
|
410
|
+
"description": "Whether status retrieval was successful"
|
|
411
|
+
},
|
|
412
|
+
"results": {
|
|
413
|
+
"type": "object",
|
|
414
|
+
"description": "Status results for each provider",
|
|
415
|
+
"additionalProperties": {
|
|
416
|
+
"type": "object",
|
|
417
|
+
"properties": {
|
|
418
|
+
"available": {
|
|
419
|
+
"type": "boolean"
|
|
420
|
+
},
|
|
421
|
+
"authenticated": {
|
|
422
|
+
"type": "boolean"
|
|
423
|
+
},
|
|
424
|
+
"version": {
|
|
425
|
+
"type": "string"
|
|
426
|
+
},
|
|
427
|
+
"lastChecked": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"description": "Last status check timestamp"
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
"message": {
|
|
435
|
+
"type": "string"
|
|
436
|
+
},
|
|
437
|
+
"timestamp": {
|
|
438
|
+
"type": "string"
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
"required": ["success", "results"]
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
"name": "send_cli_prompt",
|
|
446
|
+
"description": "Send a prompt to a CLI provider and get response. Supports both stdin and argument modes for maximum compatibility.",
|
|
447
|
+
"inputSchema": {
|
|
448
|
+
"type": "object",
|
|
449
|
+
"properties": {
|
|
450
|
+
"provider_id": {
|
|
451
|
+
"type": "string",
|
|
452
|
+
"description": "CLI provider to send prompt to",
|
|
453
|
+
"enum": ["claude_code", "codex_cli", "gemini_cli"]
|
|
454
|
+
},
|
|
455
|
+
"prompt": {
|
|
456
|
+
"type": "string",
|
|
457
|
+
"description": "Prompt to send to the CLI",
|
|
458
|
+
"minLength": 1
|
|
459
|
+
},
|
|
460
|
+
"mode": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"description": "Prompt sending mode",
|
|
463
|
+
"enum": ["stdin", "args"],
|
|
464
|
+
"default": "args"
|
|
465
|
+
},
|
|
466
|
+
"timeout_ms": {
|
|
467
|
+
"type": "integer",
|
|
468
|
+
"description": "Timeout in milliseconds (90 seconds default for CLI-within-CLI scenarios)",
|
|
469
|
+
"minimum": 1000,
|
|
470
|
+
"maximum": 600000,
|
|
471
|
+
"default": 90000
|
|
472
|
+
},
|
|
473
|
+
"user_id": {
|
|
474
|
+
"type": "string",
|
|
475
|
+
"description": "User ID for usage tracking (optional)",
|
|
476
|
+
"minLength": 1
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
"required": ["prompt"]
|
|
480
|
+
},
|
|
481
|
+
"outputSchema": {
|
|
482
|
+
"type": "object",
|
|
483
|
+
"properties": {
|
|
484
|
+
"success": {
|
|
485
|
+
"type": "boolean",
|
|
486
|
+
"description": "Whether the prompt was sent successfully"
|
|
487
|
+
},
|
|
488
|
+
"content": {
|
|
489
|
+
"type": "string",
|
|
490
|
+
"description": "CLI response content"
|
|
491
|
+
},
|
|
492
|
+
"error": {
|
|
493
|
+
"type": "string",
|
|
494
|
+
"description": "Error message if prompt failed"
|
|
495
|
+
},
|
|
496
|
+
"tokens_used": {
|
|
497
|
+
"type": "integer",
|
|
498
|
+
"description": "Number of tokens used"
|
|
499
|
+
},
|
|
500
|
+
"latency_ms": {
|
|
501
|
+
"type": "integer",
|
|
502
|
+
"description": "Response latency in milliseconds"
|
|
503
|
+
},
|
|
504
|
+
"provider": {
|
|
505
|
+
"type": "string",
|
|
506
|
+
"description": "CLI provider used"
|
|
507
|
+
},
|
|
508
|
+
"mode": {
|
|
509
|
+
"type": "string",
|
|
510
|
+
"description": "Mode used for sending"
|
|
511
|
+
},
|
|
512
|
+
"timestamp": {
|
|
513
|
+
"type": "string",
|
|
514
|
+
"description": "Response timestamp"
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
"required": ["success", "provider", "timestamp"]
|
|
518
|
+
},
|
|
519
|
+
"examples": [
|
|
520
|
+
{
|
|
521
|
+
"description": "Send prompt to Claude Code",
|
|
522
|
+
"input": {
|
|
523
|
+
"provider_id": "claude_code",
|
|
524
|
+
"prompt": "Help me debug this TypeScript error: Property 'map' does not exist on type 'string'",
|
|
525
|
+
"mode": "args",
|
|
526
|
+
"user_id": "user_123"
|
|
527
|
+
},
|
|
528
|
+
"output": {
|
|
529
|
+
"success": true,
|
|
530
|
+
"content": "This error occurs when you're trying to use the .map() method on a string variable. The .map() method is an array method, not a string method...",
|
|
531
|
+
"tokens_used": 150,
|
|
532
|
+
"latency_ms": 1200,
|
|
533
|
+
"provider": "claude_code",
|
|
534
|
+
"mode": "args",
|
|
535
|
+
"timestamp": "2024-01-15T10:35:00Z"
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
},
|
|
295
540
|
{
|
|
296
541
|
"name": "enable_status_reporting",
|
|
297
542
|
"description": "Enable automatic CLI status reporting to polydev.ai server. Reports are sent when CLI detection runs and via periodic heartbeat. Requires a Polydev user token.",
|
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -35,7 +35,7 @@ if (typeof globalThis.fetch === 'undefined') {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
req.on('error', reject);
|
|
38
|
-
req.setTimeout(
|
|
38
|
+
req.setTimeout(400000, () => { req.destroy(); reject(new Error('Request timed out')); });
|
|
39
39
|
if (options.body) req.write(options.body);
|
|
40
40
|
req.end();
|
|
41
41
|
});
|
|
@@ -308,7 +308,7 @@ class StdioMCPWrapper {
|
|
|
308
308
|
this.clientInfo = null;
|
|
309
309
|
|
|
310
310
|
// Adaptive timeout tracking: stores recent response times per CLI
|
|
311
|
-
// Used to set smarter timeouts instead of fixed
|
|
311
|
+
// Used to set smarter timeouts instead of fixed 400s
|
|
312
312
|
this.cliResponseTimes = {}; // { cliId: [latency_ms, ...] }
|
|
313
313
|
this.CLI_RESPONSE_HISTORY_SIZE = 5; // Keep last 5 response times
|
|
314
314
|
this.loadCliResponseTimes(); // Load from disk
|
|
@@ -453,11 +453,7 @@ Token will be saved automatically after login.`
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
// Handle get_perspectives with local CLIs + remote perspectives
|
|
456
|
-
|
|
457
|
-
// (send_cli_prompt was removed from tool list to prevent AI models from choosing it
|
|
458
|
-
// over get_perspectives, but old clients may still call it)
|
|
459
|
-
if (toolName === 'get_perspectives' || toolName === 'polydev.get_perspectives' ||
|
|
460
|
-
toolName === 'send_cli_prompt' || toolName === 'polydev.send_cli_prompt') {
|
|
456
|
+
if (toolName === 'get_perspectives' || toolName === 'polydev.get_perspectives') {
|
|
461
457
|
return await this.handleGetPerspectivesWithCLIs(params, id);
|
|
462
458
|
}
|
|
463
459
|
|
|
@@ -648,7 +644,7 @@ To authenticate, use one of these methods:
|
|
|
648
644
|
// if this process dies, the new one can resume polling with same session)
|
|
649
645
|
this.startLoginPolling(sessionId);
|
|
650
646
|
|
|
651
|
-
// Wait for authentication to complete (blocks up to
|
|
647
|
+
// Wait for authentication to complete (blocks up to 400s)
|
|
652
648
|
console.error('[Polydev] Waiting for browser authentication to complete...');
|
|
653
649
|
const authenticated = await this.waitForAuthCompletion();
|
|
654
650
|
|
|
@@ -725,10 +721,10 @@ Still waiting for login. Use /polydev:auth to check status after signing in.`
|
|
|
725
721
|
/**
|
|
726
722
|
* Wait for authentication to complete by polling this.isAuthenticated
|
|
727
723
|
* Used to block tool calls until login is detected by startLoginPolling
|
|
728
|
-
* @param {number} timeoutMs - Max time to wait (default
|
|
724
|
+
* @param {number} timeoutMs - Max time to wait (default 400s)
|
|
729
725
|
* @returns {boolean} true if authenticated, false if timed out
|
|
730
726
|
*/
|
|
731
|
-
async waitForAuthCompletion(timeoutMs =
|
|
727
|
+
async waitForAuthCompletion(timeoutMs = 400000) {
|
|
732
728
|
const pollInterval = 3000; // Check every 3 seconds
|
|
733
729
|
const maxPolls = Math.floor(timeoutMs / pollInterval);
|
|
734
730
|
|
|
@@ -817,7 +813,7 @@ Dashboard: https://polydev.ai/dashboard`
|
|
|
817
813
|
|
|
818
814
|
/**
|
|
819
815
|
* Trigger re-authentication by opening browser and starting polling
|
|
820
|
-
* Waits for auth to complete inline (up to
|
|
816
|
+
* Waits for auth to complete inline (up to 400s) then returns full status
|
|
821
817
|
* Used when token is detected as invalid/expired
|
|
822
818
|
* @param {*} id - JSON-RPC request id
|
|
823
819
|
* @param {string} reason - Human-readable reason for re-auth
|
|
@@ -883,7 +879,7 @@ To authenticate, pass your token directly:
|
|
|
883
879
|
this.savePendingSession(sessionId);
|
|
884
880
|
this.startLoginPolling(sessionId);
|
|
885
881
|
|
|
886
|
-
// Wait for authentication to complete (blocks up to
|
|
882
|
+
// Wait for authentication to complete (blocks up to 400s)
|
|
887
883
|
console.error('[Polydev] Waiting for browser authentication to complete...');
|
|
888
884
|
const authenticated = await this.waitForAuthCompletion();
|
|
889
885
|
|
|
@@ -1100,10 +1096,11 @@ To authenticate, pass your token directly:
|
|
|
1100
1096
|
perspectivesSection += ` (${perspectiveCount} active)`;
|
|
1101
1097
|
|
|
1102
1098
|
// Show providers in order with their selected models
|
|
1103
|
-
for (
|
|
1099
|
+
for (let i = 0; i < modelPrefs.allProviders.length; i++) {
|
|
1100
|
+
const p = modelPrefs.allProviders[i];
|
|
1104
1101
|
const providerName = p.provider.charAt(0).toUpperCase() + p.provider.slice(1);
|
|
1105
1102
|
const source = p.cliId ? 'CLI' : (p.tier ? `Credits/${p.tier}` : 'API');
|
|
1106
|
-
perspectivesSection += `\n ${providerName.padEnd(12)} ${p.model} [${source}]`;
|
|
1103
|
+
perspectivesSection += `\n ${i + 1}. ${providerName.padEnd(12)} ${p.model} [${source}]`;
|
|
1107
1104
|
}
|
|
1108
1105
|
} else {
|
|
1109
1106
|
perspectivesSection += '\n (none configured - using defaults)';
|
|
@@ -1575,7 +1572,7 @@ To re-login: /polydev:login`
|
|
|
1575
1572
|
try {
|
|
1576
1573
|
// Use AbortController for timeout if available, otherwise rely on fetch timeout
|
|
1577
1574
|
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
1578
|
-
const timeoutId = controller ? setTimeout(() => controller.abort(),
|
|
1575
|
+
const timeoutId = controller ? setTimeout(() => controller.abort(), 400000) : null; // 400s timeout
|
|
1579
1576
|
|
|
1580
1577
|
const response = await fetch('https://www.polydev.ai/api/mcp', {
|
|
1581
1578
|
method: 'POST',
|
|
@@ -1633,8 +1630,10 @@ To re-login: /polydev:login`
|
|
|
1633
1630
|
const cliTools = [
|
|
1634
1631
|
'force_cli_detection',
|
|
1635
1632
|
'get_cli_status',
|
|
1633
|
+
'send_cli_prompt',
|
|
1636
1634
|
'polydev.force_cli_detection',
|
|
1637
|
-
'polydev.get_cli_status'
|
|
1635
|
+
'polydev.get_cli_status',
|
|
1636
|
+
'polydev.send_cli_prompt'
|
|
1638
1637
|
];
|
|
1639
1638
|
return cliTools.includes(toolName);
|
|
1640
1639
|
}
|
|
@@ -1722,6 +1721,11 @@ To re-login: /polydev:login`
|
|
|
1722
1721
|
result = await this.localGetCliStatus(args);
|
|
1723
1722
|
break;
|
|
1724
1723
|
|
|
1724
|
+
case 'send_cli_prompt':
|
|
1725
|
+
case 'polydev.send_cli_prompt':
|
|
1726
|
+
result = await this.localSendCliPrompt(args);
|
|
1727
|
+
break;
|
|
1728
|
+
|
|
1725
1729
|
default:
|
|
1726
1730
|
throw new Error(`Unknown CLI tool: ${toolName}`);
|
|
1727
1731
|
}
|
|
@@ -1885,19 +1889,19 @@ To re-login: /polydev:login`
|
|
|
1885
1889
|
console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
|
|
1886
1890
|
|
|
1887
1891
|
try {
|
|
1888
|
-
let { provider_id, prompt, mode = 'args', timeout_ms =
|
|
1892
|
+
let { provider_id, prompt, mode = 'args', timeout_ms = 400000 } = args;
|
|
1889
1893
|
|
|
1890
1894
|
// Ensure timeout_ms is valid (not undefined, null, Infinity, or negative)
|
|
1891
|
-
// Default to
|
|
1895
|
+
// Default to 400 seconds for complex CLI responses
|
|
1892
1896
|
if (!timeout_ms || timeout_ms === Infinity || timeout_ms < 1 || timeout_ms > 600000) {
|
|
1893
|
-
timeout_ms =
|
|
1897
|
+
timeout_ms = 400000; // Default to 400 seconds for CLI responses
|
|
1894
1898
|
}
|
|
1895
1899
|
|
|
1896
1900
|
if (!prompt) {
|
|
1897
1901
|
throw new Error('prompt is required');
|
|
1898
1902
|
}
|
|
1899
1903
|
|
|
1900
|
-
// Use configured timeout but cap at
|
|
1904
|
+
// Use configured timeout but cap at 400s max for safety
|
|
1901
1905
|
const gracefulTimeout = Math.min(timeout_ms, 600000);
|
|
1902
1906
|
|
|
1903
1907
|
// Fetch user's model preferences (cached, non-blocking on failure)
|
|
@@ -2046,7 +2050,7 @@ To re-login: /polydev:login`
|
|
|
2046
2050
|
if (model) {
|
|
2047
2051
|
console.error(`[Stdio Wrapper] Using model for ${providerEntry.cliId}: ${model}`);
|
|
2048
2052
|
}
|
|
2049
|
-
// Use adaptive timeout based on historical response times (instead of fixed
|
|
2053
|
+
// Use adaptive timeout based on historical response times (instead of fixed 400s)
|
|
2050
2054
|
const cliTimeout = this.getAdaptiveTimeout(providerEntry.cliId, gracefulTimeout);
|
|
2051
2055
|
let result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, cliTimeout, model);
|
|
2052
2056
|
|
|
@@ -2458,7 +2462,7 @@ To re-login: /polydev:login`
|
|
|
2458
2462
|
user_token: this.userToken,
|
|
2459
2463
|
// Exclude providers that succeeded locally
|
|
2460
2464
|
exclude_providers: excludeProviders,
|
|
2461
|
-
// NEW: Specific providers to request (from API-only
|
|
2465
|
+
// NEW: Specific providers to request (from API-only list)
|
|
2462
2466
|
request_providers: requestProviders.length > 0 ? requestProviders : undefined,
|
|
2463
2467
|
// Pass CLI responses for dashboard logging
|
|
2464
2468
|
cli_responses: cliResponses,
|
|
@@ -2520,6 +2524,9 @@ To re-login: /polydev:login`
|
|
|
2520
2524
|
}
|
|
2521
2525
|
}
|
|
2522
2526
|
|
|
2527
|
+
/**
|
|
2528
|
+
* Combine multiple CLI results and remote perspectives
|
|
2529
|
+
*/
|
|
2523
2530
|
combineAllCliAndPerspectives(localResults, perspectivesResult, args) {
|
|
2524
2531
|
// Ensure perspectivesResult is always an object to prevent undefined errors
|
|
2525
2532
|
const safePersp = perspectivesResult || { success: false, error: 'No response from perspectives server' };
|
|
@@ -2565,8 +2572,8 @@ To re-login: /polydev:login`
|
|
|
2565
2572
|
if (safePersp.raw) {
|
|
2566
2573
|
// Raw content is already formatted - use as-is
|
|
2567
2574
|
formatted += `${safePersp.content}\n\n`;
|
|
2568
|
-
} else
|
|
2569
|
-
// Legacy formatting
|
|
2575
|
+
} else {
|
|
2576
|
+
// Legacy formatting
|
|
2570
2577
|
const title = (successfulClis.length === 0) ? 'Perspectives Fallback' : 'Supplemental Multi-Model Perspectives';
|
|
2571
2578
|
formatted += `${title}\n\n`;
|
|
2572
2579
|
formatted += `${safePersp.content}\n\n`;
|
|
@@ -2576,10 +2583,6 @@ To re-login: /polydev:login`
|
|
|
2576
2583
|
formatted += `❌ Perspectives request failed: ${safePersp.error || 'Unknown error'}\n\n`;
|
|
2577
2584
|
}
|
|
2578
2585
|
|
|
2579
|
-
// Strip "LOGIN SUCCESSFUL" banner that leaks from remote server responses
|
|
2580
|
-
// It gets appended to perspective results and pollutes the output
|
|
2581
|
-
formatted = formatted.replace(/\n*LOGIN SUCCESSFUL\n={4,}\n[\s\S]*?Dashboard:.*(\n|$)/g, '');
|
|
2582
|
-
|
|
2583
2586
|
return formatted.trim();
|
|
2584
2587
|
}
|
|
2585
2588
|
|
|
@@ -2710,16 +2713,16 @@ To re-login: /polydev:login`
|
|
|
2710
2713
|
|
|
2711
2714
|
/**
|
|
2712
2715
|
* Get adaptive timeout for a CLI based on historical response times
|
|
2713
|
-
* Returns timeout in ms (2.5x the average, with min 30s and max
|
|
2716
|
+
* Returns timeout in ms (2.5x the average, with min 30s and max 400s)
|
|
2714
2717
|
*/
|
|
2715
|
-
getAdaptiveTimeout(cliId, defaultTimeout =
|
|
2718
|
+
getAdaptiveTimeout(cliId, defaultTimeout = 400000) {
|
|
2716
2719
|
const times = this.cliResponseTimes[cliId];
|
|
2717
2720
|
if (!times || times.length === 0) {
|
|
2718
2721
|
return defaultTimeout; // No history, use default
|
|
2719
2722
|
}
|
|
2720
2723
|
const avg = times.reduce((a, b) => a + b, 0) / times.length;
|
|
2721
|
-
// 2.5x average, clamped between 30s and
|
|
2722
|
-
const adaptive = Math.min(
|
|
2724
|
+
// 2.5x average, clamped between 30s and 400s
|
|
2725
|
+
const adaptive = Math.min(400000, Math.max(30000, Math.round(avg * 2.5)));
|
|
2723
2726
|
console.error(`[Stdio Wrapper] Adaptive timeout for ${cliId}: ${adaptive}ms (avg: ${Math.round(avg)}ms from ${times.length} samples)`);
|
|
2724
2727
|
return adaptive;
|
|
2725
2728
|
}
|
|
@@ -2897,6 +2900,25 @@ To re-login: /polydev:login`
|
|
|
2897
2900
|
} else {
|
|
2898
2901
|
return `CLI Response (${result.provider || 'Unknown'} - ${result.mode || 'unknown'} mode)\n\n${result.content}\n\nLatency: ${result.latency_ms || 0}ms | Tokens: ${result.tokens_used || 0} | ${result.timestamp}`;
|
|
2899
2902
|
}
|
|
2903
|
+
} else {
|
|
2904
|
+
// Status/detection response
|
|
2905
|
+
let formatted = `CLI Operation Success\n\n`;
|
|
2906
|
+
formatted += `${result.message}\n\n`;
|
|
2907
|
+
|
|
2908
|
+
if (result.results) {
|
|
2909
|
+
formatted += `Results:\n`;
|
|
2910
|
+
for (const [providerId, status] of Object.entries(result.results)) {
|
|
2911
|
+
const icon = status.available ? '[+]' : '[-]';
|
|
2912
|
+
const authStatus = status.authenticated ? '[auth]' : '[no-auth]';
|
|
2913
|
+
formatted += `- ${icon} ${authStatus} ${providerId}: ${status.available ? 'Available' : 'Not Available'}`;
|
|
2914
|
+
if (status.version) formatted += ` (${status.version})`;
|
|
2915
|
+
if (status.error) formatted += ` - ${status.error}`;
|
|
2916
|
+
formatted += `\n`;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
formatted += `\n${result.local_only ? 'Local execution' : 'Remote execution'} | ${result.timestamp}`;
|
|
2921
|
+
return formatted;
|
|
2900
2922
|
}
|
|
2901
2923
|
}
|
|
2902
2924
|
|
|
@@ -2941,7 +2963,7 @@ To re-login: /polydev:login`
|
|
|
2941
2963
|
this.userModelPreferences = result.modelPreferences;
|
|
2942
2964
|
this.modelPreferencesCacheTime = Date.now();
|
|
2943
2965
|
|
|
2944
|
-
// Also cache
|
|
2966
|
+
// Also cache perspectives_per_message setting (default 2)
|
|
2945
2967
|
this.perspectivesPerMessage = result.perspectivesPerMessage || 2;
|
|
2946
2968
|
|
|
2947
2969
|
// Cache provider order from user's dashboard (respects display_order)
|
|
@@ -3119,7 +3141,6 @@ To re-login: /polydev:login`
|
|
|
3119
3141
|
return this.localForceCliDetection({});
|
|
3120
3142
|
}).then(() => {
|
|
3121
3143
|
this._cliDetectionComplete = true;
|
|
3122
|
-
// Display CLI status after detection
|
|
3123
3144
|
return this.displayCliStatus();
|
|
3124
3145
|
}).catch((error) => {
|
|
3125
3146
|
console.error('[Polydev] Auto-login flow error:', error.message);
|
|
@@ -3395,6 +3416,37 @@ function createSandboxServer() {
|
|
|
3395
3416
|
required: ['prompt']
|
|
3396
3417
|
}
|
|
3397
3418
|
},
|
|
3419
|
+
{
|
|
3420
|
+
name: 'get_cli_status',
|
|
3421
|
+
description: 'Check status of local CLI tools (Claude Code, Codex CLI, Gemini CLI)',
|
|
3422
|
+
inputSchema: {
|
|
3423
|
+
type: 'object',
|
|
3424
|
+
properties: {
|
|
3425
|
+
provider_id: {
|
|
3426
|
+
type: 'string',
|
|
3427
|
+
description: 'Optional specific provider to check'
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
},
|
|
3432
|
+
{
|
|
3433
|
+
name: 'force_cli_detection',
|
|
3434
|
+
description: 'Force re-detection of installed local CLI tools',
|
|
3435
|
+
inputSchema: { type: 'object', properties: {} }
|
|
3436
|
+
},
|
|
3437
|
+
{
|
|
3438
|
+
name: 'send_cli_prompt',
|
|
3439
|
+
description: 'Send prompt to local CLI with perspectives fallback',
|
|
3440
|
+
inputSchema: {
|
|
3441
|
+
type: 'object',
|
|
3442
|
+
properties: {
|
|
3443
|
+
provider_id: { type: 'string', description: 'CLI provider ID' },
|
|
3444
|
+
prompt: { type: 'string', description: 'Prompt to send' },
|
|
3445
|
+
mode: { type: 'string', enum: ['args', 'stdin'], default: 'args' }
|
|
3446
|
+
},
|
|
3447
|
+
required: ['provider_id', 'prompt']
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3398
3450
|
]
|
|
3399
3451
|
};
|
|
3400
3452
|
}
|