polydev-ai 1.5.2 → 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 +101 -32
- package/package.json +1 -1
package/lib/cliManager.js
CHANGED
|
@@ -675,27 +675,73 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
675
675
|
const parseCodexOutput = (output) => {
|
|
676
676
|
if (!output || !output.trim()) return null;
|
|
677
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
|
|
678
701
|
const lines = output.split('\n');
|
|
679
702
|
const contentLines = [];
|
|
680
703
|
|
|
681
|
-
//
|
|
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
|
+
|
|
682
734
|
for (const line of lines) {
|
|
683
735
|
const trimmedLine = line.trim();
|
|
684
|
-
// Skip empty lines and MCP/protocol noise
|
|
685
|
-
if (!trimmedLine) continue;
|
|
686
|
-
if (trimmedLine.startsWith('MCP ')) continue;
|
|
687
|
-
if (trimmedLine.includes('handshake') && trimmedLine.includes('error')) continue;
|
|
688
|
-
if (trimmedLine.startsWith('[MCP]')) continue;
|
|
689
|
-
if (trimmedLine.startsWith('Error:') && trimmedLine.includes('MCP')) continue;
|
|
690
736
|
|
|
691
|
-
//
|
|
692
|
-
const
|
|
693
|
-
if (
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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);
|
|
699
745
|
}
|
|
700
746
|
|
|
701
747
|
const result = contentLines.join('\n').trim();
|
|
@@ -730,26 +776,49 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
730
776
|
|
|
731
777
|
const trimmedStdout = stdout.trim();
|
|
732
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
|
+
}
|
|
733
797
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
if (
|
|
738
|
-
resolve(
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
// Fallback to raw output if parsing yields nothing
|
|
742
|
-
resolve(trimmedStdout);
|
|
743
|
-
} else if (code === 0) {
|
|
744
|
-
// Code 0 but no stdout - check if stderr has useful info
|
|
745
|
-
const parsedStderr = parseCodexOutput(trimmedStderr);
|
|
746
|
-
if (parsedStderr) {
|
|
747
|
-
resolve(parsedStderr);
|
|
748
|
-
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'));
|
|
749
805
|
}
|
|
750
|
-
reject(new Error('Codex completed but produced no output'));
|
|
751
806
|
} else {
|
|
752
|
-
|
|
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));
|
|
753
822
|
}
|
|
754
823
|
});
|
|
755
824
|
|
package/package.json
CHANGED