polydev-ai 1.9.2 → 1.9.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.
package/lib/cliManager.js CHANGED
@@ -429,16 +429,16 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
429
429
  }
430
430
 
431
431
  async sendCliPrompt(providerId, prompt, mode = 'args', timeoutMs = null, model = null) {
432
- // Set default timeout for CLI-within-CLI scenarios (90 seconds)
433
- // This is important when Claude Code calls Claude Code via Polydev MCP
432
+ // Set default timeout for CLI responses (240 seconds / 4 minutes)
433
+ // CLI-within-CLI scenarios (Claude Code calling Claude Code) need generous timeouts
434
434
  if (timeoutMs === null) {
435
- timeoutMs = 90000; // 90 seconds default for CLI responses
435
+ timeoutMs = 240000; // 240 seconds (4 minutes) default for CLI responses
436
436
  }
437
437
 
438
438
  // Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
439
439
  // Allow up to 600 seconds (10 minutes) for very complex operations
440
440
  if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 600000) {
441
- timeoutMs = 90000 // Default to 90 seconds for CLI responses
441
+ timeoutMs = 240000 // Default to 240 seconds (4 minutes) for CLI responses
442
442
  }
443
443
 
444
444
  const startTime = Date.now();
@@ -777,11 +777,11 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
777
777
  }
778
778
  }
779
779
 
780
- async executeCliCommand(command, args, mode = 'args', timeoutMs = 90000, stdinInput) {
780
+ async executeCliCommand(command, args, mode = 'args', timeoutMs = 240000, stdinInput) {
781
781
  // Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
782
- // 90 seconds default for CLI-within-CLI scenarios
782
+ // 240 seconds (4 minutes) default for CLI responses
783
783
  if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 600000) {
784
- timeoutMs = 90000 // Default to 90 seconds
784
+ timeoutMs = 240000 // Default to 240 seconds (4 minutes)
785
785
  }
786
786
 
787
787
  return new Promise((resolve, reject) => {
@@ -35,7 +35,7 @@ if (typeof globalThis.fetch === 'undefined') {
35
35
  });
36
36
 
37
37
  req.on('error', reject);
38
- req.setTimeout(30000, () => { req.destroy(); reject(new Error('Request timed out')); });
38
+ req.setTimeout(240000, () => { req.destroy(); reject(new Error('Request timed out')); });
39
39
  if (options.body) req.write(options.body);
40
40
  req.end();
41
41
  });
@@ -436,8 +436,8 @@ Token will be saved automatically after login.`
436
436
  return await this.handleGetPerspectivesWithCLIs(params, id);
437
437
  }
438
438
 
439
- // Handle other CLI tools locally
440
- if (toolName.startsWith('polydev.') && this.isCliTool(toolName)) {
439
+ // Handle CLI tools locally (support both prefixed and unprefixed names)
440
+ if (this.isCliTool(toolName)) {
441
441
  return await this.handleLocalCliTool(request);
442
442
  } else {
443
443
  // Forward non-CLI tools to remote server
@@ -1170,6 +1170,10 @@ Error: ${error.message}`
1170
1170
  console.error(`[Stdio Wrapper] Forwarding request to remote server`);
1171
1171
 
1172
1172
  try {
1173
+ // Use AbortController for timeout if available, otherwise rely on fetch timeout
1174
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
1175
+ const timeoutId = controller ? setTimeout(() => controller.abort(), 240000) : null; // 240s timeout
1176
+
1173
1177
  const response = await fetch('https://www.polydev.ai/api/mcp', {
1174
1178
  method: 'POST',
1175
1179
  headers: {
@@ -1177,9 +1181,12 @@ Error: ${error.message}`
1177
1181
  'Authorization': `Bearer ${this.userToken}`,
1178
1182
  'User-Agent': 'polydev-stdio-wrapper/1.0.0'
1179
1183
  },
1180
- body: JSON.stringify(request)
1184
+ body: JSON.stringify(request),
1185
+ ...(controller ? { signal: controller.signal } : {})
1181
1186
  });
1182
1187
 
1188
+ if (timeoutId) clearTimeout(timeoutId);
1189
+
1183
1190
  if (!response.ok) {
1184
1191
  const errorText = await response.text();
1185
1192
  console.error(`[Stdio Wrapper] Remote server error: ${response.status} - ${errorText}`);
@@ -1215,6 +1222,9 @@ Error: ${error.message}`
1215
1222
  */
1216
1223
  isCliTool(toolName) {
1217
1224
  const cliTools = [
1225
+ 'force_cli_detection',
1226
+ 'get_cli_status',
1227
+ 'send_cli_prompt',
1218
1228
  'polydev.force_cli_detection',
1219
1229
  'polydev.get_cli_status',
1220
1230
  'polydev.send_cli_prompt'
@@ -1274,14 +1284,17 @@ Error: ${error.message}`
1274
1284
  let result;
1275
1285
 
1276
1286
  switch (toolName) {
1287
+ case 'force_cli_detection':
1277
1288
  case 'polydev.force_cli_detection':
1278
1289
  result = await this.localForceCliDetection(args);
1279
1290
  break;
1280
1291
 
1292
+ case 'get_cli_status':
1281
1293
  case 'polydev.get_cli_status':
1282
1294
  result = await this.localGetCliStatus(args);
1283
1295
  break;
1284
1296
 
1297
+ case 'send_cli_prompt':
1285
1298
  case 'polydev.send_cli_prompt':
1286
1299
  result = await this.localSendCliPrompt(args);
1287
1300
  break;
@@ -1551,7 +1564,23 @@ Error: ${error.message}`
1551
1564
  if (model) {
1552
1565
  console.error(`[Stdio Wrapper] Using model for ${providerEntry.cliId}: ${model}`);
1553
1566
  }
1554
- const result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, gracefulTimeout, model);
1567
+ let result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, gracefulTimeout, model);
1568
+
1569
+ // If CLI failed with a model and the error suggests model issue, retry with CLI default
1570
+ if (!result.success && model) {
1571
+ const errorLower = (result.error || '').toLowerCase();
1572
+ const isModelError = errorLower.includes('not found') ||
1573
+ errorLower.includes('not supported') ||
1574
+ errorLower.includes('invalid model') ||
1575
+ errorLower.includes('entity was not found') ||
1576
+ errorLower.includes('does not exist') ||
1577
+ errorLower.includes('unknown model');
1578
+ if (isModelError) {
1579
+ console.error(`[Stdio Wrapper] Model '${model}' failed for ${providerEntry.cliId}, retrying with CLI default...`);
1580
+ result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, gracefulTimeout, null);
1581
+ }
1582
+ }
1583
+
1555
1584
  return {
1556
1585
  provider_id: providerEntry.cliId,
1557
1586
  original_provider: providerEntry.provider,
@@ -1657,18 +1686,23 @@ Error: ${error.message}`
1657
1686
  console.error('[Polydev] CLI detection ready, proceeding with request');
1658
1687
  }
1659
1688
 
1660
- const results = await this.cliManager.forceCliDetection();
1661
- console.error(`[Stdio Wrapper] CLI detection results:`, JSON.stringify(results, null, 2));
1689
+ // Use cached status (refreshed by smart scheduler) instead of forceCliDetection on every request
1690
+ const results = await this.cliManager.getCliStatus();
1691
+ console.error(`[Stdio Wrapper] CLI status (cached):`, JSON.stringify(results, null, 2));
1662
1692
  const availableProviders = [];
1663
1693
  const unavailableProviders = [];
1664
1694
 
1665
- // Use user's provider order from dashboard (fetched via model-preferences API)
1666
- // Falls back to default order if not yet loaded or empty
1667
- // NOTE: Use length check because empty array [] is truthy in JS
1668
- const priorityOrder = (this.userProviderOrder && this.userProviderOrder.length > 0)
1695
+ // ALWAYS check ALL CLIs (they're FREE) don't limit to userProviderOrder
1696
+ // userProviderOrder only affects ordering, not which CLIs get checked
1697
+ // This fixes the bug where CLIs were missed because model-preferences API
1698
+ // only returned providerOrder for credits-tier models
1699
+ const allCliIds = ['claude_code', 'codex_cli', 'gemini_cli'];
1700
+ const userOrder = (this.userProviderOrder && this.userProviderOrder.length > 0)
1669
1701
  ? this.userProviderOrder
1670
- : ['claude_code', 'codex_cli', 'gemini_cli'];
1671
- console.error(`[Stdio Wrapper] Using provider order: ${priorityOrder.join(' > ')}`);
1702
+ : [];
1703
+ // Merge: user's preferred order first, then any CLIs not in their order
1704
+ const priorityOrder = [...new Set([...userOrder, ...allCliIds])];
1705
+ console.error(`[Stdio Wrapper] Using provider order: ${priorityOrder.join(' > ')} (user order: ${userOrder.join(', ') || 'none'})`);
1672
1706
 
1673
1707
  for (const providerId of priorityOrder) {
1674
1708
  const status = results[providerId];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.2",
3
+ "version": "1.9.4",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },
@@ -45,7 +45,11 @@
45
45
  "test:admin": "jest __tests__/api/admin",
46
46
  "mcp": "node mcp/server.js",
47
47
  "mcp-stdio": "node mcp/stdio-wrapper.js",
48
- "cli-detect": "node -e \"const CLIManager = require('./lib/cliManager').default; const m = new CLIManager(); m.forceCliDetection().then(console.log);\""
48
+ "cli-detect": "node -e \"const CLIManager = require('./lib/cliManager').default; const m = new CLIManager(); m.forceCliDetection().then(console.log);\"",
49
+ "release": "bash scripts/release.sh",
50
+ "release:patch": "bash scripts/release.sh patch",
51
+ "release:minor": "bash scripts/release.sh minor",
52
+ "release:major": "bash scripts/release.sh major"
49
53
  },
50
54
  "repository": {
51
55
  "type": "git",