diff --git a/src/plan-orchestrator.ts b/src/plan-orchestrator.ts index 1135458f..7c206498 100644 --- a/src/plan-orchestrator.ts +++ b/src/plan-orchestrator.ts @@ -414,9 +414,24 @@ export class PlanOrchestrator { const durationMs = Date.now() - startTime; - // Extract JSON from response - const jsonMatch = response.match(/\{[\s\S]*\}/); + console.log( + `[PlanOrchestrator] Research response length: ${response.length}, first 500 chars:`, + response.substring(0, 500) + ); + + // Extract JSON from response — try multiple strategies + let jsonMatch = response.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/); + if (jsonMatch) { + jsonMatch = [jsonMatch[1]]; // Use captured group (inside code block) + } else { + jsonMatch = response.match(/\{[\s\S]*\}/); + } + if (!jsonMatch) { + console.error( + `[PlanOrchestrator] No JSON found in research response. Full response:`, + response.substring(0, 2000) + ); onSubagent?.({ type: 'failed', agentId, @@ -587,9 +602,24 @@ export class PlanOrchestrator { const durationMs = Date.now() - startTime; - // Extract JSON from response - const jsonMatch = response.match(/\{[\s\S]*\}/); + console.log( + `[PlanOrchestrator] Planner response length: ${response.length}, first 500 chars:`, + response.substring(0, 500) + ); + + // Extract JSON from response — try multiple strategies + let jsonMatch = response.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/); + if (jsonMatch) { + jsonMatch = [jsonMatch[1]]; // Use captured group (inside code block) + } else { + jsonMatch = response.match(/\{[\s\S]*\}/); + } + if (!jsonMatch) { + console.error( + `[PlanOrchestrator] No JSON found in planner response. Full response:`, + response.substring(0, 2000) + ); onSubagent?.({ type: 'failed', agentId, diff --git a/src/session.ts b/src/session.ts index 242bc03a..2c499d1d 100644 --- a/src/session.ts +++ b/src/session.ts @@ -1516,9 +1516,11 @@ export class Session extends EventEmitter { this._status = 'idle'; const cost = resultMsg.total_cost_usd || 0; this._totalCost += cost; - this.emit('completion', resultMsg.result || '', cost); + // Claude CLI stream-json may return empty result field — fall back to accumulated text output + const result = resultMsg.result || this._textOutput.value || ''; + this.emit('completion', result, cost); if (resolve) { - resolve({ result: resultMsg.result || '', cost }); + resolve({ result, cost }); } } else if (exitCode !== 0 || (resultMsg && resultMsg.is_error)) { this._status = 'error';