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 +132 -19
- package/mcp/stdio-wrapper.js +2 -2
- package/package.json +1 -1
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
677
|
-
if (
|
|
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(
|
|
758
|
+
stop(() => resolve(parsed));
|
|
680
759
|
}
|
|
681
760
|
};
|
|
682
761
|
|
|
683
762
|
child.stdout?.on('data', (data) => {
|
|
684
763
|
stdout += data.toString();
|
|
685
|
-
|
|
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
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
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
|
-
|
|
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
|
|
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -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 (
|
|
453
|
-
const gracefulTimeout = Math.min(timeout_ms,
|
|
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