polydev-ai 1.9.15 → 1.9.17

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.
@@ -299,7 +299,11 @@ class StdioMCPWrapper {
299
299
 
300
300
  // Pending session file for surviving restarts
301
301
  this.PENDING_SESSION_FILE = path.join(os.homedir(), '.polydev-pending-session');
302
-
302
+
303
+ // MCP client info (set during initialize handshake)
304
+ // Used to detect which IDE is running us and exclude its CLI to avoid recursive calls
305
+ this.clientInfo = null;
306
+
303
307
  // Initialize CLI Manager for local CLI functionality
304
308
  // Disable StatusReporter - it's redundant (updateCliStatusInDatabase handles DB updates via /api/cli-status-update)
305
309
  // and causes 401 errors because /api/mcp uses different auth than /api/cli-status-update
@@ -363,6 +367,12 @@ class StdioMCPWrapper {
363
367
  try {
364
368
  switch (method) {
365
369
  case 'initialize':
370
+ // Capture client info to detect which IDE is running us
371
+ // This lets us exclude its CLI to avoid recursive calls (e.g., Claude Code → claude_code CLI)
372
+ this.clientInfo = params?.clientInfo || null;
373
+ if (this.clientInfo) {
374
+ console.error(`[Stdio Wrapper] IDE detected: ${this.clientInfo.name} v${this.clientInfo.version || 'unknown'}`);
375
+ }
366
376
  return {
367
377
  jsonrpc: '2.0',
368
378
  id,
@@ -1679,6 +1689,47 @@ Error: ${error.message}`
1679
1689
  }
1680
1690
  }
1681
1691
 
1692
+ /**
1693
+ * Get the CLI ID to exclude based on the current IDE client.
1694
+ * Prevents recursive calls (e.g., Claude Code calling claude_code CLI which spawns another Claude Code).
1695
+ * Returns null if no CLI should be excluded.
1696
+ */
1697
+ getExcludedCliForCurrentIDE() {
1698
+ if (!this.clientInfo?.name) return null;
1699
+
1700
+ const clientName = this.clientInfo.name.toLowerCase();
1701
+
1702
+ // Map known IDE client names to their corresponding CLI IDs
1703
+ // These are the clientInfo.name values sent during MCP initialize handshake
1704
+ const ideToCliMap = {
1705
+ // Claude Code variants
1706
+ 'claude-code': 'claude_code',
1707
+ 'claude_code': 'claude_code',
1708
+ 'claude code': 'claude_code',
1709
+ 'claudecode': 'claude_code',
1710
+ // Cursor uses Claude under the hood but is a separate IDE — don't exclude
1711
+ // Gemini CLI / Google IDX
1712
+ 'gemini-cli': 'gemini_cli',
1713
+ 'gemini_cli': 'gemini_cli',
1714
+ // Codex CLI / OpenAI
1715
+ 'codex-cli': 'codex_cli',
1716
+ 'codex_cli': 'codex_cli',
1717
+ 'codex': 'codex_cli',
1718
+ };
1719
+
1720
+ // Direct match first
1721
+ if (ideToCliMap[clientName]) {
1722
+ return ideToCliMap[clientName];
1723
+ }
1724
+
1725
+ // Fuzzy match: check if client name contains known patterns
1726
+ if (clientName.includes('claude')) return 'claude_code';
1727
+ if (clientName.includes('gemini')) return 'gemini_cli';
1728
+ if (clientName.includes('codex')) return 'codex_cli';
1729
+
1730
+ return null;
1731
+ }
1732
+
1682
1733
  /**
1683
1734
  * Local CLI prompt sending with ALL available CLIs + remote perspectives
1684
1735
  * Respects user's perspectives_per_message setting for total perspectives
@@ -1764,16 +1815,27 @@ Error: ${error.message}`
1764
1815
 
1765
1816
  // CLI priority order: Claude Code first, then Gemini, then Codex
1766
1817
  const cliPriorityOrder = ['claude_code', 'gemini_cli', 'codex_cli'];
1767
-
1818
+
1819
+ // Detect if we should exclude the current IDE's CLI to avoid recursive calls
1820
+ const excludedCli = this.getExcludedCliForCurrentIDE();
1821
+ if (excludedCli) {
1822
+ console.error(`[Stdio Wrapper] Excluding CLI '${excludedCli}' (current IDE: ${this.clientInfo?.name}) to avoid recursive calls`);
1823
+ }
1824
+
1768
1825
  // Build merged provider list: CLIs first, then API-only
1769
1826
  const finalProviders = [];
1770
1827
  const usedProviderNames = new Set();
1771
-
1828
+
1772
1829
  // STEP 1: Add ALL available CLIs (in priority order) - they're FREE
1773
1830
  // Don't limit to maxPerspectives here — we run all CLIs in parallel
1774
1831
  // and take the first maxPerspectives successes (fast-collect pattern)
1832
+ // Skip the CLI that matches the current IDE to avoid recursive calls
1775
1833
  for (const cliId of cliPriorityOrder) {
1776
1834
  if (!availableClis.includes(cliId)) continue;
1835
+ if (cliId === excludedCli) {
1836
+ console.error(`[Stdio Wrapper] [CLI-FIRST] Skipping ${cliId} (same as current IDE — would cause recursive call)`);
1837
+ continue;
1838
+ }
1777
1839
 
1778
1840
  const providerName = cliToProviderMap[cliId];
1779
1841
  usedProviderNames.add(providerName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.9.15",
3
+ "version": "1.9.17",
4
4
  "engines": {
5
5
  "node": ">=20.x <=22.x"
6
6
  },