polydev-ai 1.8.16 → 1.8.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.
- package/mcp/stdio-wrapper.js +87 -30
- package/package.json +1 -1
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -103,6 +103,12 @@ if (writableTmp) {
|
|
|
103
103
|
/**
|
|
104
104
|
* Clean CLI response by removing metadata and debug info
|
|
105
105
|
* Strips: provider info, approval, sandbox, reasoning, session id, MCP errors, etc.
|
|
106
|
+
*
|
|
107
|
+
* Codex CLI output structure:
|
|
108
|
+
* [metadata] → user → [echoed prompt] → thinking → [status] → codex → [RESPONSE]
|
|
109
|
+
*
|
|
110
|
+
* Claude Code output structure:
|
|
111
|
+
* [may include JSON or plain text response]
|
|
106
112
|
*/
|
|
107
113
|
function cleanCliResponse(content) {
|
|
108
114
|
if (!content || typeof content !== 'string') {
|
|
@@ -111,57 +117,108 @@ function cleanCliResponse(content) {
|
|
|
111
117
|
|
|
112
118
|
const lines = content.split('\n');
|
|
113
119
|
const cleanedLines = [];
|
|
114
|
-
let skipUntilContent = true;
|
|
115
|
-
let inThinkingSection = false;
|
|
116
120
|
|
|
117
|
-
for
|
|
121
|
+
// State machine for Codex CLI output parsing
|
|
122
|
+
// States: 'metadata' | 'user_section' | 'thinking_section' | 'response'
|
|
123
|
+
let state = 'metadata';
|
|
124
|
+
let foundCodexMarker = false;
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < lines.length; i++) {
|
|
127
|
+
const line = lines[i];
|
|
118
128
|
const trimmed = line.trim();
|
|
119
129
|
|
|
120
|
-
//
|
|
121
|
-
if (
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
// Always skip MCP errors anywhere
|
|
131
|
+
if (trimmed.startsWith('ERROR: MCP client for')) continue;
|
|
132
|
+
if (trimmed.includes('failed to start') && trimmed.includes('MCP')) continue;
|
|
133
|
+
if (trimmed.includes('handshake') && trimmed.includes('failed')) continue;
|
|
134
|
+
if (trimmed.includes('connection closed')) continue;
|
|
135
|
+
|
|
136
|
+
// State: metadata - skip until we hit a section marker
|
|
137
|
+
if (state === 'metadata') {
|
|
125
138
|
// Skip known metadata patterns
|
|
139
|
+
if (!trimmed) continue;
|
|
126
140
|
if (trimmed.startsWith('provider:')) continue;
|
|
127
141
|
if (trimmed.startsWith('approval:')) continue;
|
|
128
142
|
if (trimmed.startsWith('sandbox:')) continue;
|
|
129
143
|
if (trimmed.startsWith('reasoning effort:')) continue;
|
|
130
144
|
if (trimmed.startsWith('reasoning summaries:')) continue;
|
|
131
145
|
if (trimmed.startsWith('session id:')) continue;
|
|
132
|
-
if (trimmed.match(/^-{4,}$/)) continue; //
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
if (trimmed.match(/^-{4,}$/)) continue; // Separator lines
|
|
147
|
+
|
|
148
|
+
// Transition to user section
|
|
149
|
+
if (trimmed === 'user') {
|
|
150
|
+
state = 'user_section';
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// If we hit 'codex' directly (no user section), go to response
|
|
155
|
+
if (trimmed === 'codex') {
|
|
156
|
+
state = 'response';
|
|
157
|
+
foundCodexMarker = true;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If we hit 'assistant' (Claude Code), this might be actual content
|
|
162
|
+
if (trimmed === 'assistant') {
|
|
163
|
+
state = 'response';
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
135
166
|
|
|
136
|
-
//
|
|
137
|
-
if
|
|
138
|
-
if (trimmed.includes('
|
|
167
|
+
// If no Codex markers found and we have content, it might be Claude Code output
|
|
168
|
+
// Check if it looks like actual content (not metadata)
|
|
169
|
+
if (!trimmed.includes(':') || trimmed.length > 100) {
|
|
170
|
+
state = 'response';
|
|
171
|
+
cleanedLines.push(line);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
139
174
|
|
|
140
|
-
|
|
141
|
-
skipUntilContent = false;
|
|
175
|
+
continue;
|
|
142
176
|
}
|
|
143
177
|
|
|
144
|
-
//
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
178
|
+
// State: user_section - skip echoed prompt until thinking/codex
|
|
179
|
+
if (state === 'user_section') {
|
|
180
|
+
if (trimmed === 'thinking') {
|
|
181
|
+
state = 'thinking_section';
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (trimmed === 'codex') {
|
|
185
|
+
state = 'response';
|
|
186
|
+
foundCodexMarker = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// Skip everything in user section (echoed prompt, errors)
|
|
190
|
+
continue;
|
|
148
191
|
}
|
|
149
192
|
|
|
150
|
-
//
|
|
151
|
-
if (
|
|
152
|
-
|
|
193
|
+
// State: thinking_section - skip until codex marker
|
|
194
|
+
if (state === 'thinking_section') {
|
|
195
|
+
if (trimmed === 'codex') {
|
|
196
|
+
state = 'response';
|
|
197
|
+
foundCodexMarker = true;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
// Skip thinking content (bold status messages, reasoning)
|
|
153
201
|
continue;
|
|
154
202
|
}
|
|
155
203
|
|
|
156
|
-
//
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
204
|
+
// State: response - keep actual response content
|
|
205
|
+
if (state === 'response') {
|
|
206
|
+
// Skip footer patterns
|
|
207
|
+
if (trimmed === 'tokens used') continue;
|
|
208
|
+
if (trimmed.match(/^[\d,]+$/) && i === lines.length - 1) continue; // Token count at end
|
|
209
|
+
|
|
210
|
+
// Skip any remaining bold status markers
|
|
211
|
+
if (trimmed.match(/^\*\*.*\*\*$/)) continue;
|
|
212
|
+
|
|
213
|
+
// Keep this line
|
|
214
|
+
cleanedLines.push(line);
|
|
215
|
+
}
|
|
162
216
|
}
|
|
163
217
|
|
|
164
|
-
// Trim trailing empty lines
|
|
218
|
+
// Trim leading/trailing empty lines
|
|
219
|
+
while (cleanedLines.length > 0 && !cleanedLines[0].trim()) {
|
|
220
|
+
cleanedLines.shift();
|
|
221
|
+
}
|
|
165
222
|
while (cleanedLines.length > 0 && !cleanedLines[cleanedLines.length - 1].trim()) {
|
|
166
223
|
cleanedLines.pop();
|
|
167
224
|
}
|
package/package.json
CHANGED