polydev-ai 1.5.1 → 1.5.3

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
@@ -379,17 +379,15 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
379
379
  }
380
380
 
381
381
  async sendCliPrompt(providerId, prompt, mode = 'args', timeoutMs = null) {
382
- // Set provider-specific default timeouts
382
+ // Set provider-specific default timeouts (180s for all by default, complex prompts take time)
383
383
  if (timeoutMs === null) {
384
- timeoutMs = providerId === 'claude_code' ? 60000 : 30000; // 60s for Claude Code, 30s for others
385
- }
386
- if (providerId === 'codex_cli' && timeoutMs < 90000) {
387
- timeoutMs = 90000;
384
+ timeoutMs = 180000; // 180 seconds default for all providers
388
385
  }
389
386
 
390
387
  // Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
388
+ // Allow up to 300 seconds (5 minutes) for complex operations
391
389
  if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 300000) {
392
- timeoutMs = 30000 // Default to 30 seconds
390
+ timeoutMs = 180000 // Default to 180 seconds
393
391
  }
394
392
 
395
393
  const startTime = Date.now();
@@ -514,10 +512,11 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
514
512
  }
515
513
  }
516
514
 
517
- async executeCliCommand(command, args, mode = 'args', timeoutMs = 30000, stdinInput) {
515
+ async executeCliCommand(command, args, mode = 'args', timeoutMs = 180000, stdinInput) {
518
516
  // Ensure timeoutMs is valid (not undefined, null, Infinity, or negative)
517
+ // Allow up to 300 seconds (5 minutes) for complex operations
519
518
  if (!timeoutMs || timeoutMs === Infinity || timeoutMs < 1 || timeoutMs > 300000) {
520
- timeoutMs = 30000 // Default to 30 seconds
519
+ timeoutMs = 180000 // Default to 180 seconds
521
520
  }
522
521
 
523
522
  return new Promise((resolve, reject) => {
@@ -672,17 +671,98 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
672
671
  stop(() => reject(new Error(`Codex exec timeout after ${timeoutMs}ms`)));
673
672
  }, timeoutMs);
674
673
 
674
+ // Helper function to parse Codex output robustly
675
+ const parseCodexOutput = (output) => {
676
+ if (!output || !output.trim()) return null;
677
+
678
+ // First, try to extract the response between "codex" marker and "tokens used"
679
+ // This is the most reliable pattern for Codex CLI output
680
+ const codexMarkerMatch = output.match(/\bcodex\s*\n([\s\S]*?)(?:\n\s*tokens used|\n\s*$)/i);
681
+ if (codexMarkerMatch && codexMarkerMatch[1]) {
682
+ const extracted = codexMarkerMatch[1].trim();
683
+ if (extracted.length > 0 && !extracted.startsWith('ERROR')) {
684
+ return extracted;
685
+ }
686
+ }
687
+
688
+ // Fallback: Try to find bullet point responses
689
+ const bulletMatches = output.match(/•\s*(.+)/g);
690
+ if (bulletMatches && bulletMatches.length > 0) {
691
+ const bulletContent = bulletMatches
692
+ .map(m => m.replace(/^•\s*/, '').trim())
693
+ .filter(s => s.length > 0)
694
+ .join('\n');
695
+ if (bulletContent.length > 0) {
696
+ return bulletContent;
697
+ }
698
+ }
699
+
700
+ // Last resort: Filter out known noise patterns line by line
701
+ const lines = output.split('\n');
702
+ const contentLines = [];
703
+
704
+ // Patterns to skip (Codex-specific noise)
705
+ const noisePatterns = [
706
+ /^\s*$/, // Empty lines
707
+ /^\d{4}-\d{2}-\d{2}T[\d:]+.*?(ERROR|WARN|INFO)/i, // Timestamp logs
708
+ /^OpenAI Codex v[\d.]+/i, // Version banner
709
+ /^-{4,}$/, // Separator lines
710
+ /^workdir:/i, // Header fields
711
+ /^model:/i,
712
+ /^provider:/i,
713
+ /^approval:/i,
714
+ /^sandbox:/i,
715
+ /^reasoning effort:/i,
716
+ /^reasoning summaries:/i,
717
+ /^session id:/i,
718
+ /^user$/i, // "user" marker
719
+ /^thinking$/i, // "thinking" marker
720
+ /^codex$/i, // "codex" marker
721
+ /^tokens used$/i, // Token count header
722
+ /^[\d,]+$/, // Just numbers (token counts)
723
+ /^ERROR:\s*MCP/i, // MCP errors
724
+ /MCP client for .* failed/i, // MCP client failures
725
+ /handshake.*failed/i, // Handshake errors
726
+ /connection closed/i, // Connection errors
727
+ /\[MCP\]/i, // MCP tags
728
+ /^MCP\s/i, // MCP prefix
729
+ /rmcp::transport/i, // Rust MCP transport errors
730
+ /serde error/i, // Serde parsing errors
731
+ /^\*\*.*\*\*$/, // Bold status messages like **Awaiting next steps**
732
+ ];
733
+
734
+ for (const line of lines) {
735
+ const trimmedLine = line.trim();
736
+
737
+ // Check if line matches any noise pattern
738
+ const isNoise = noisePatterns.some(pattern => pattern.test(trimmedLine));
739
+ if (isNoise) continue;
740
+
741
+ // Skip if line looks like the echoed user prompt (heuristic: contains "?" and is long)
742
+ if (trimmedLine.includes('?') && trimmedLine.length > 20) continue;
743
+
744
+ contentLines.push(trimmedLine);
745
+ }
746
+
747
+ const result = contentLines.join('\n').trim();
748
+ return result.length > 0 ? result : null;
749
+ };
750
+
751
+ // Check if we have a complete response - look for actual content
675
752
  const flushIfComplete = () => {
676
- const match = stdout.match(/•\s*(.+)/);
677
- if (match && match[1]) {
753
+ const parsed = parseCodexOutput(stdout);
754
+ // Only resolve early if we have meaningful content (at least 2 chars) and output seems done
755
+ // This prevents cutting off multi-line responses
756
+ if (parsed && parsed.length >= 2 && stdout.includes('\n') && !stdout.endsWith('...')) {
678
757
  clearTimeout(timeoutHandle);
679
- stop(() => resolve(match[1].trim()));
758
+ stop(() => resolve(parsed));
680
759
  }
681
760
  };
682
761
 
683
762
  child.stdout?.on('data', (data) => {
684
763
  stdout += data.toString();
685
- flushIfComplete();
764
+ // Don't flush too eagerly - wait a bit for more data
765
+ // flushIfComplete(); // Disabled: let the process complete naturally
686
766
  });
687
767
 
688
768
  child.stderr?.on('data', (data) => {
@@ -696,16 +776,49 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
696
776
 
697
777
  const trimmedStdout = stdout.trim();
698
778
  const trimmedStderr = stderr.trim();
779
+
780
+ // Combine stdout and stderr for parsing - Codex may output to either
781
+ const combinedOutput = trimmedStdout + '\n' + trimmedStderr;
782
+
783
+ // Always try to parse stdout first, regardless of exit code
784
+ // MCP handshake failures cause non-zero exit but don't prevent valid responses
785
+ const parsedStdout = parseCodexOutput(trimmedStdout);
786
+ if (parsedStdout) {
787
+ resolve(parsedStdout);
788
+ return;
789
+ }
790
+
791
+ // Try parsing combined output (some responses may appear in stderr)
792
+ const parsedCombined = parseCodexOutput(combinedOutput);
793
+ if (parsedCombined) {
794
+ resolve(parsedCombined);
795
+ return;
796
+ }
699
797
 
700
- if (code === 0 && trimmedStdout) {
701
- const match = trimmedStdout.match(/•\s*(.+)/);
702
- if (match && match[1]) {
703
- resolve(match[1].trim());
704
- return;
798
+ // Only now consider it a failure
799
+ if (code === 0) {
800
+ // Successful exit but no parseable output
801
+ if (trimmedStdout) {
802
+ resolve(trimmedStdout); // Return raw output as fallback
803
+ } else {
804
+ reject(new Error('Codex completed but produced no output'));
705
805
  }
706
- resolve(trimmedStdout);
707
806
  } else {
708
- reject(new Error(trimmedStderr || trimmedStdout || `Codex exited with code ${code}`));
807
+ // Non-zero exit and no parseable response - this is a real error
808
+ // Filter error message to remove MCP noise
809
+ const errorLines = (trimmedStderr || trimmedStdout).split('\n')
810
+ .filter(line => {
811
+ const l = line.trim().toLowerCase();
812
+ return l.length > 0 &&
813
+ !l.includes('mcp') &&
814
+ !l.includes('handshake') &&
815
+ !l.includes('rmcp::') &&
816
+ !l.includes('serde error');
817
+ })
818
+ .slice(0, 3); // Only first 3 relevant error lines
819
+
820
+ const cleanError = errorLines.join('; ') || `Codex exited with code ${code}`;
821
+ reject(new Error(cleanError));
709
822
  }
710
823
  });
711
824
 
@@ -449,8 +449,8 @@ class StdioMCPWrapper {
449
449
  throw new Error('prompt is required');
450
450
  }
451
451
 
452
- // Use reasonable timeout for CLI responses (15 seconds instead of 5)
453
- const gracefulTimeout = Math.min(timeout_ms, 15000);
452
+ // Use reasonable timeout for CLI responses (180 seconds for complex prompts)
453
+ const gracefulTimeout = Math.min(timeout_ms, 180000);
454
454
 
455
455
  let localResults = [];
456
456
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Agentic workflow assistant with CLI integration - get diverse perspectives from multiple LLMs when stuck or need enhanced reasoning",
5
5
  "keywords": [
6
6
  "mcp",