polydev-ai 1.9.25 → 1.9.27

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
@@ -208,7 +208,7 @@ class CLIManager {
208
208
  provider.command,
209
209
  provider.subcommands.version,
210
210
  'args',
211
- 5000
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
- 5000 // Reduced timeout to 5 seconds
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 (240 seconds / 4 minutes)
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 = 240000; // 240 seconds (4 minutes) default for CLI responses
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 = 240000 // Default to 240 seconds (4 minutes) for CLI responses
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 = 240000, stdinInput) {
809
+ async executeCliCommand(command, args, mode = 'args', timeoutMs = 400000, stdinInput) {
810
810
  // Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
811
- // 240 seconds (4 minutes) default for CLI responses
811
+ // 400 seconds default for CLI responses
812
812
  if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 600000) {
813
- timeoutMs = 240000 // Default to 240 seconds (4 minutes)
813
+ timeoutMs = 400000 // Default to 400 seconds
814
814
  }
815
815
 
816
816
  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(240000, () => { req.destroy(); reject(new Error('Request timed out')); });
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 240s
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
@@ -644,7 +644,7 @@ To authenticate, use one of these methods:
644
644
  // if this process dies, the new one can resume polling with same session)
645
645
  this.startLoginPolling(sessionId);
646
646
 
647
- // Wait for authentication to complete (blocks up to 120s)
647
+ // Wait for authentication to complete (blocks up to 400s)
648
648
  console.error('[Polydev] Waiting for browser authentication to complete...');
649
649
  const authenticated = await this.waitForAuthCompletion();
650
650
 
@@ -721,10 +721,10 @@ Still waiting for login. Use /polydev:auth to check status after signing in.`
721
721
  /**
722
722
  * Wait for authentication to complete by polling this.isAuthenticated
723
723
  * Used to block tool calls until login is detected by startLoginPolling
724
- * @param {number} timeoutMs - Max time to wait (default 120s)
724
+ * @param {number} timeoutMs - Max time to wait (default 400s)
725
725
  * @returns {boolean} true if authenticated, false if timed out
726
726
  */
727
- async waitForAuthCompletion(timeoutMs = 120000) {
727
+ async waitForAuthCompletion(timeoutMs = 400000) {
728
728
  const pollInterval = 3000; // Check every 3 seconds
729
729
  const maxPolls = Math.floor(timeoutMs / pollInterval);
730
730
 
@@ -813,7 +813,7 @@ Dashboard: https://polydev.ai/dashboard`
813
813
 
814
814
  /**
815
815
  * Trigger re-authentication by opening browser and starting polling
816
- * Waits for auth to complete inline (up to 120s) then returns full status
816
+ * Waits for auth to complete inline (up to 400s) then returns full status
817
817
  * Used when token is detected as invalid/expired
818
818
  * @param {*} id - JSON-RPC request id
819
819
  * @param {string} reason - Human-readable reason for re-auth
@@ -879,7 +879,7 @@ To authenticate, pass your token directly:
879
879
  this.savePendingSession(sessionId);
880
880
  this.startLoginPolling(sessionId);
881
881
 
882
- // Wait for authentication to complete (blocks up to 120s)
882
+ // Wait for authentication to complete (blocks up to 400s)
883
883
  console.error('[Polydev] Waiting for browser authentication to complete...');
884
884
  const authenticated = await this.waitForAuthCompletion();
885
885
 
@@ -1566,76 +1566,64 @@ To re-login: /polydev:login`
1566
1566
  </html>`;
1567
1567
  }
1568
1568
 
1569
- async forwardToRemoteServer(request) {
1570
- console.error(`[Stdio Wrapper] Forwarding request to remote server`);
1571
-
1572
- try {
1573
- // Use AbortController for timeout if available, otherwise rely on fetch timeout
1574
- const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
1575
- const timeoutId = controller ? setTimeout(() => controller.abort(), 240000) : null; // 240s timeout
1576
-
1577
- const response = await fetch('https://www.polydev.ai/api/mcp', {
1578
- method: 'POST',
1579
- headers: {
1580
- 'Content-Type': 'application/json',
1581
- 'Authorization': `Bearer ${this.userToken}`,
1582
- 'User-Agent': 'polydev-stdio-wrapper/1.0.0'
1583
- },
1584
- body: JSON.stringify(request),
1585
- ...(controller ? { signal: controller.signal } : {})
1586
- });
1587
-
1588
- if (timeoutId) clearTimeout(timeoutId);
1589
-
1590
- if (!response.ok) {
1591
- const errorText = await response.text();
1592
- console.error(`[Stdio Wrapper] Remote server error: ${response.status} - ${errorText}`);
1593
-
1594
- // Handle 401 specifically - token expired/invalid, trigger re-auth
1595
- if (response.status === 401) {
1596
- console.error('[Polydev] Remote API returned 401, auto-triggering re-authentication...');
1597
- return await this.triggerReAuth(request.id, 'Authentication expired. Re-authenticating...');
1598
- }
1599
-
1600
- return {
1601
- jsonrpc: '2.0',
1602
- id: request.id,
1603
- error: {
1604
- code: -32603,
1605
- message: `Remote server error: ${response.status} - ${errorText}`
1606
- }
1607
- };
1569
+ /**
1570
+ * Send an MCP progress notification to the client
1571
+ * This is a JSON-RPC notification (no id) that compatible clients use to:
1572
+ * 1. Display progress UI (status bar, spinners)
1573
+ * 2. Reset their tool call timeout (if resetTimeoutOnProgress is enabled)
1574
+ * @param {string|number} progressToken - Token from request's _meta.progressToken
1575
+ * @param {number} progress - Current progress value (must increase monotonically)
1576
+ * @param {number} total - Total expected progress value
1577
+ * @param {string} message - Human-readable status message
1578
+ */
1579
+ sendProgressNotification(progressToken, progress, total, message) {
1580
+ if (!progressToken) return; // Client didn't request progress
1581
+
1582
+ const notification = {
1583
+ jsonrpc: '2.0',
1584
+ method: 'notifications/progress',
1585
+ params: {
1586
+ progressToken,
1587
+ progress,
1588
+ total,
1589
+ message
1608
1590
  }
1609
-
1610
- const result = await response.json();
1611
- console.error(`[Stdio Wrapper] Got response from remote server`);
1612
- return result;
1613
- } catch (error) {
1614
- console.error(`[Stdio Wrapper] Network error:`, error.message);
1615
- return {
1616
- jsonrpc: '2.0',
1617
- id: request.id,
1618
- error: {
1619
- code: -32603,
1620
- message: `Network error: ${error.message}`
1621
- }
1622
- };
1591
+ };
1592
+
1593
+ try {
1594
+ process.stdout.write(JSON.stringify(notification) + '\n');
1595
+ console.error(`[Polydev] Progress: ${progress}/${total} - ${message}`);
1596
+ } catch (err) {
1597
+ console.error(`[Polydev] Failed to send progress notification:`, err.message);
1623
1598
  }
1624
1599
  }
1625
1600
 
1626
1601
  /**
1627
- * Check if a tool is a CLI tool that should be handled locally
1602
+ * Start a periodic progress heartbeat to prevent client-side timeouts.
1603
+ * Sends a progress notification every intervalMs to signal the server is still working.
1604
+ * Compatible MCP clients will reset their timeout clock on each notification.
1605
+ * @param {string|number} progressToken - Token from request's _meta.progressToken
1606
+ * @param {number} intervalMs - Heartbeat interval in milliseconds (default: 10s)
1607
+ * @returns {{ stop: Function, tick: Function }} Controller to stop heartbeat and manually tick progress
1628
1608
  */
1629
- isCliTool(toolName) {
1630
- const cliTools = [
1631
- 'force_cli_detection',
1632
- 'get_cli_status',
1633
- 'send_cli_prompt',
1634
- 'polydev.force_cli_detection',
1635
- 'polydev.get_cli_status',
1636
- 'polydev.send_cli_prompt'
1637
- ];
1638
- return cliTools.includes(toolName);
1609
+ startProgressHeartbeat(progressToken, intervalMs = 10000) {
1610
+ if (!progressToken) return { stop: () => {}, tick: () => {} };
1611
+
1612
+ let currentProgress = 0;
1613
+ const total = 100; // Use percentage-style progress
1614
+
1615
+ const interval = setInterval(() => {
1616
+ currentProgress = Math.min(currentProgress + 5, 95); // Never reach 100 until done
1617
+ this.sendProgressNotification(progressToken, currentProgress, total, 'Processing perspectives...');
1618
+ }, intervalMs);
1619
+
1620
+ return {
1621
+ stop: () => clearInterval(interval),
1622
+ tick: (progress, message) => {
1623
+ currentProgress = progress;
1624
+ this.sendProgressNotification(progressToken, progress, total, message);
1625
+ }
1626
+ };
1639
1627
  }
1640
1628
 
1641
1629
  /**
@@ -1644,12 +1632,30 @@ To re-login: /polydev:login`
1644
1632
  async handleGetPerspectivesWithCLIs(params, id) {
1645
1633
  console.error(`[Stdio Wrapper] Handling get_perspectives with local CLIs + remote`);
1646
1634
 
1635
+ // Extract progress token from request metadata (MCP spec)
1636
+ // Clients that want progress updates include this in _meta.progressToken
1637
+ const progressToken = params?._meta?.progressToken;
1638
+ if (progressToken) {
1639
+ console.error(`[Stdio Wrapper] Client requested progress updates (token: ${progressToken})`);
1640
+ }
1641
+
1642
+ // Start periodic heartbeat to prevent client-side timeouts
1643
+ // Sends progress notification every 10s to keep the connection alive
1644
+ const heartbeat = this.startProgressHeartbeat(progressToken);
1645
+
1647
1646
  try {
1647
+ // Send initial progress
1648
+ heartbeat.tick(5, 'Initializing perspectives engine...');
1649
+
1648
1650
  // Use existing localSendCliPrompt logic which already:
1649
1651
  // 1. Checks all local CLIs
1650
1652
  // 2. Calls remote perspectives
1651
1653
  // 3. Combines results
1652
- const result = await this.localSendCliPrompt(params.arguments);
1654
+ const result = await this.localSendCliPrompt(params.arguments, progressToken);
1655
+
1656
+ // Stop heartbeat before sending final response
1657
+ heartbeat.stop();
1658
+ heartbeat.tick(100, 'Complete');
1653
1659
 
1654
1660
  // Check if result indicates auth failure (from forwardToRemoteServer 401 handling)
1655
1661
  if (result?.result?.content?.[0]?.text?.includes('RE-AUTHENTICATION REQUIRED')) {
@@ -1678,6 +1684,7 @@ To re-login: /polydev:login`
1678
1684
  };
1679
1685
 
1680
1686
  } catch (error) {
1687
+ heartbeat.stop(); // Always clean up heartbeat
1681
1688
  console.error(`[Stdio Wrapper] get_perspectives error:`, error);
1682
1689
 
1683
1690
  // Check if error is auth-related
@@ -1704,9 +1711,13 @@ To re-login: /polydev:login`
1704
1711
  async handleLocalCliTool(request) {
1705
1712
  const { method, params, id } = request;
1706
1713
  const { name: toolName, arguments: args } = params;
1714
+ const progressToken = params?._meta?.progressToken;
1707
1715
 
1708
1716
  console.error(`[Stdio Wrapper] Handling local CLI tool: ${toolName}`);
1709
1717
 
1718
+ // Start heartbeat for long-running CLI operations
1719
+ const heartbeat = this.startProgressHeartbeat(progressToken);
1720
+
1710
1721
  try {
1711
1722
  let result;
1712
1723
 
@@ -1723,13 +1734,14 @@ To re-login: /polydev:login`
1723
1734
 
1724
1735
  case 'send_cli_prompt':
1725
1736
  case 'polydev.send_cli_prompt':
1726
- result = await this.localSendCliPrompt(args);
1737
+ result = await this.localSendCliPrompt(args, progressToken);
1727
1738
  break;
1728
1739
 
1729
1740
  default:
1730
1741
  throw new Error(`Unknown CLI tool: ${toolName}`);
1731
1742
  }
1732
1743
 
1744
+ heartbeat.stop();
1733
1745
  return {
1734
1746
  jsonrpc: '2.0',
1735
1747
  id,
@@ -1745,6 +1757,7 @@ To re-login: /polydev:login`
1745
1757
 
1746
1758
  } catch (error) {
1747
1759
  console.error(`[Stdio Wrapper] CLI tool error:`, error);
1760
+ heartbeat.stop();
1748
1761
  return {
1749
1762
  jsonrpc: '2.0',
1750
1763
  id,
@@ -1885,23 +1898,23 @@ To re-login: /polydev:login`
1885
1898
  * Respects user's perspectives_per_message setting for total perspectives
1886
1899
  * Uses allProviders from dashboard - tries CLI first, falls back to API
1887
1900
  */
1888
- async localSendCliPrompt(args) {
1901
+ async localSendCliPrompt(args, progressToken) {
1889
1902
  console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
1890
1903
 
1891
1904
  try {
1892
- let { provider_id, prompt, mode = 'args', timeout_ms = 240000 } = args;
1905
+ let { provider_id, prompt, mode = 'args', timeout_ms = 400000 } = args;
1893
1906
 
1894
1907
  // Ensure timeout_ms is valid (not undefined, null, Infinity, or negative)
1895
- // Default to 4 minutes (240 seconds) for complex CLI responses
1908
+ // Default to 400 seconds for complex CLI responses
1896
1909
  if (!timeout_ms || timeout_ms === Infinity || timeout_ms < 1 || timeout_ms > 600000) {
1897
- timeout_ms = 240000; // Default to 4 minutes for CLI responses
1910
+ timeout_ms = 400000; // Default to 400 seconds for CLI responses
1898
1911
  }
1899
1912
 
1900
1913
  if (!prompt) {
1901
1914
  throw new Error('prompt is required');
1902
1915
  }
1903
1916
 
1904
- // Use configured timeout but cap at 10 minutes max for safety
1917
+ // Use configured timeout but cap at 400s max for safety
1905
1918
  const gracefulTimeout = Math.min(timeout_ms, 600000);
1906
1919
 
1907
1920
  // Fetch user's model preferences (cached, non-blocking on failure)
@@ -1912,6 +1925,8 @@ To re-login: /polydev:login`
1912
1925
  } catch (prefError) {
1913
1926
  console.error('[Stdio Wrapper] Model preferences fetch failed (will use CLI defaults):', prefError.message);
1914
1927
  }
1928
+
1929
+ this.sendProgressNotification(progressToken, 15, 100, 'Loaded model preferences');
1915
1930
 
1916
1931
  // Get the user's perspectives_per_message setting (default 2)
1917
1932
  const maxPerspectives = this.perspectivesPerMessage || 2;
@@ -1920,14 +1935,11 @@ To re-login: /polydev:login`
1920
1935
  let localResults = [];
1921
1936
 
1922
1937
  if (provider_id) {
1923
- // Specific provider requested - use only that one
1938
+ // Single provider requested - use only that one
1924
1939
  console.error(`[Stdio Wrapper] Using specific provider: ${provider_id}`);
1925
1940
  const model = modelPreferences[provider_id] || null;
1926
- if (model) {
1927
- console.error(`[Stdio Wrapper] Using user's preferred model for ${provider_id}: ${model}`);
1928
- } else {
1929
- console.error(`[Stdio Wrapper] No model preference for ${provider_id}, using CLI default`);
1930
- }
1941
+ console.error(`[Stdio Wrapper] Using user's preferred model for ${provider_id}: ${model}`);
1942
+ this.sendProgressNotification(progressToken, 20, 100, `Querying ${provider_id}...`);
1931
1943
  const result = await this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout, model);
1932
1944
  localResults = [{ provider_id, ...result }];
1933
1945
  } else {
@@ -1939,6 +1951,7 @@ To re-login: /polydev:login`
1939
1951
  // Get available CLIs for checking
1940
1952
  const { available: availableClis } = await this.getAllAvailableProviders();
1941
1953
  console.error(`[Stdio Wrapper] Available CLIs: ${availableClis.join(', ') || 'none'}`);
1954
+ this.sendProgressNotification(progressToken, 25, 100, `Found ${availableClis.length} CLIs: ${availableClis.join(', ') || 'none'}`);
1942
1955
 
1943
1956
  // Get all providers from dashboard (user's configured providers + CLI-only)
1944
1957
  const allProviders = this.allProviders || [];
@@ -1983,7 +1996,7 @@ To re-login: /polydev:login`
1983
1996
  for (const cliId of cliPriorityOrder) {
1984
1997
  if (!availableClis.includes(cliId)) continue;
1985
1998
  if (cliId === excludedCli) {
1986
- console.error(`[Stdio Wrapper] [CLI-FIRST] Skipping ${cliId} (same as current IDE — would cause recursive call)`);
1999
+ console.error(`[Stdio Wrapper] [CLI-FIRST] Skipping ${excludedCli} (same as current IDE — would cause recursive call)`);
1987
2000
  continue;
1988
2001
  }
1989
2002
 
@@ -2041,6 +2054,7 @@ To re-login: /polydev:login`
2041
2054
  // Run ALL CLI prompts concurrently with fast-collect pattern
2042
2055
  // Resolves once we have maxPerspectives successes OR all complete
2043
2056
  if (cliProviderEntries.length > 0) {
2057
+ this.sendProgressNotification(progressToken, 30, 100, `Querying ${cliProviderEntries.length} CLIs in parallel...`);
2044
2058
  const cliPromises = cliProviderEntries.map(async (providerEntry) => {
2045
2059
  try {
2046
2060
  // ONLY use the model from providerEntry (which is filtered to user's own API keys, not credits)
@@ -2050,7 +2064,7 @@ To re-login: /polydev:login`
2050
2064
  if (model) {
2051
2065
  console.error(`[Stdio Wrapper] Using model for ${providerEntry.cliId}: ${model}`);
2052
2066
  }
2053
- // Use adaptive timeout based on historical response times (instead of fixed 240s)
2067
+ // Use adaptive timeout based on historical response times (instead of fixed 400s)
2054
2068
  const cliTimeout = this.getAdaptiveTimeout(providerEntry.cliId, gracefulTimeout);
2055
2069
  let result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, cliTimeout, model);
2056
2070
 
@@ -2094,6 +2108,7 @@ To re-login: /polydev:login`
2094
2108
  // Fast-collect: resolve early once we have maxPerspectives successes OR all complete
2095
2109
  localResults = await this.collectFirstNSuccesses(cliPromises, maxPerspectives);
2096
2110
  console.error(`[Stdio Wrapper] Fast-collect: got ${localResults.filter(r => r.success).length} successful, ${localResults.filter(r => !r.success).length} failed out of ${cliPromises.length} CLIs`);
2111
+ this.sendProgressNotification(progressToken, 55, 100, `Got ${localResults.filter(r => r.success).length} CLI responses`);
2097
2112
  }
2098
2113
 
2099
2114
  // Store API-only providers info for remote API call
@@ -2116,6 +2131,7 @@ To re-login: /polydev:login`
2116
2131
  // Get remote perspectives for API-only providers and failed CLIs
2117
2132
  let perspectivesResult;
2118
2133
  if (remainingPerspectives > 0) {
2134
+ this.sendProgressNotification(progressToken, 65, 100, `Fetching ${remainingPerspectives} more perspectives from API...`);
2119
2135
  console.error(`[Stdio Wrapper] Calling remote API for ${remainingPerspectives} more perspectives (have ${successfulLocalCount}/${maxPerspectives})`);
2120
2136
 
2121
2137
  // Pass API-only provider info to help remote API choose correct models
@@ -2155,6 +2171,7 @@ To re-login: /polydev:login`
2155
2171
  }
2156
2172
 
2157
2173
  // Combine all results
2174
+ this.sendProgressNotification(progressToken, 90, 100, 'Combining all perspectives...');
2158
2175
  return this.combineAllCliAndPerspectives(localResults, perspectivesResult, args);
2159
2176
 
2160
2177
  } catch (error) {
@@ -2194,7 +2211,7 @@ To re-login: /polydev:login`
2194
2211
  if (result.success) successCount++;
2195
2212
  completedCount++;
2196
2213
 
2197
- // Resolve early if we have enough successes OR all promises done
2214
+ // Resolve early if we have enough successes OR all complete
2198
2215
  if (successCount >= needed || completedCount >= promises.length) {
2199
2216
  resolved = true;
2200
2217
  resolve([...results]); // Copy to prevent mutation from late arrivals
@@ -2462,7 +2479,7 @@ To re-login: /polydev:login`
2462
2479
  user_token: this.userToken,
2463
2480
  // Exclude providers that succeeded locally
2464
2481
  exclude_providers: excludeProviders,
2465
- // NEW: Specific providers to request (from API-only list)
2482
+ // NEW: Specific providers to request (from API-only providers)
2466
2483
  request_providers: requestProviders.length > 0 ? requestProviders : undefined,
2467
2484
  // Pass CLI responses for dashboard logging
2468
2485
  cli_responses: cliResponses,
@@ -2713,16 +2730,16 @@ To re-login: /polydev:login`
2713
2730
 
2714
2731
  /**
2715
2732
  * Get adaptive timeout for a CLI based on historical response times
2716
- * Returns timeout in ms (2.5x the average, with min 30s and max 240s)
2733
+ * Returns timeout in ms (2.5x the average, with min 30s and max 400s)
2717
2734
  */
2718
- getAdaptiveTimeout(cliId, defaultTimeout = 240000) {
2735
+ getAdaptiveTimeout(cliId, defaultTimeout = 400000) {
2719
2736
  const times = this.cliResponseTimes[cliId];
2720
2737
  if (!times || times.length === 0) {
2721
2738
  return defaultTimeout; // No history, use default
2722
2739
  }
2723
2740
  const avg = times.reduce((a, b) => a + b, 0) / times.length;
2724
- // 2.5x average, clamped between 30s and 240s
2725
- const adaptive = Math.min(240000, Math.max(30000, Math.round(avg * 2.5)));
2741
+ // 2.5x average, clamped between 30s and 400s
2742
+ const adaptive = Math.min(400000, Math.max(30000, Math.round(avg * 2.5)));
2726
2743
  console.error(`[Stdio Wrapper] Adaptive timeout for ${cliId}: ${adaptive}ms (avg: ${Math.round(avg)}ms from ${times.length} samples)`);
2727
2744
  return adaptive;
2728
2745
  }
@@ -2849,11 +2866,11 @@ To re-login: /polydev:login`
2849
2866
  try {
2850
2867
  const homeDir = require('os').homedir();
2851
2868
  const polydevevDir = path.join(homeDir, '.polydev');
2852
- const usageFile = path.join(polydevevDir, 'cli-usage.json');
2869
+ const usageFile = path.join(polydeveevDir, 'cli-usage.json');
2853
2870
 
2854
2871
  // Ensure directory exists
2855
- if (!fs.existsSync(polydevevDir)) {
2856
- fs.mkdirSync(polydevevDir, { recursive: true });
2872
+ if (!fs.existsSync(polydeveevDir)) {
2873
+ fs.mkdirSync(polydeveevDir, { recursive: true });
2857
2874
  }
2858
2875
 
2859
2876
  // Add new usage record
@@ -2963,7 +2980,7 @@ To re-login: /polydev:login`
2963
2980
  this.userModelPreferences = result.modelPreferences;
2964
2981
  this.modelPreferencesCacheTime = Date.now();
2965
2982
 
2966
- // Also cache perspectives_per_message setting (default 2)
2983
+ // Also cache perspectivesPerMessage setting (default 2)
2967
2984
  this.perspectivesPerMessage = result.perspectivesPerMessage || 2;
2968
2985
 
2969
2986
  // Cache provider order from user's dashboard (respects display_order)
@@ -3141,6 +3158,7 @@ To re-login: /polydev:login`
3141
3158
  return this.localForceCliDetection({});
3142
3159
  }).then(() => {
3143
3160
  this._cliDetectionComplete = true;
3161
+ // Display CLI status after detection
3144
3162
  return this.displayCliStatus();
3145
3163
  }).catch((error) => {
3146
3164
  console.error('[Polydev] Auto-login flow error:', error.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.25",
3
+ "version": "1.9.27",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },