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.
@@ -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 (const line of lines) {
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
- // Skip metadata lines at the start
121
- if (skipUntilContent) {
122
- // Skip empty lines
123
- if (!trimmed) continue;
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; // Skip separator lines like --------
133
- if (trimmed === 'user') continue; // Skip role markers
134
- if (trimmed === 'assistant') continue;
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
- // Skip MCP client errors
137
- if (trimmed.startsWith('ERROR: MCP client for')) continue;
138
- if (trimmed.includes('failed to start')) continue;
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
- // Found actual content - stop skipping
141
- skipUntilContent = false;
175
+ continue;
142
176
  }
143
177
 
144
- // Handle thinking sections (optional: can show or hide)
145
- if (trimmed === 'thinking') {
146
- inThinkingSection = true;
147
- continue; // Skip the "thinking" marker
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
- // End of thinking section on empty line after content
151
- if (inThinkingSection && !trimmed) {
152
- inThinkingSection = false;
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
- // Skip more MCP errors anywhere in output
157
- if (trimmed.startsWith('ERROR: MCP client for')) continue;
158
- if (trimmed.includes('failed to start') && trimmed.includes('MCP')) continue;
159
-
160
- // Keep this line
161
- cleanedLines.push(line);
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 and return
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polydev-ai",
3
- "version": "1.8.16",
3
+ "version": "1.8.17",
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",