From ba09184efad7d51d722482f57b32109433450f5d Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 25 Mar 2026 23:53:57 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20wizard=20"No=20JSON=20found"=20=E2=80=94?= =?UTF-8?q?=20Claude=20CLI=20stream-json=20returns=20empty=20result=20fiel?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude CLI's --output-format stream-json now returns "result": "" in the result message. The actual response text lives in assistant message text blocks, which _textOutput correctly accumulates. runPrompt() was returning the empty resultMsg.result without falling back to _textOutput.value. Also improved plan-orchestrator JSON extraction to try code-block-wrapped JSON first (```json {...} ```) before the greedy regex, plus debug logging. Co-Authored-By: Claude Opus 4.6 --- src/plan-orchestrator.ts | 38 ++++++++++++++++++++++++++++++++++---- src/session.ts | 6 ++++-- 2 files changed, 38 insertions(+), 6 deletions(-) 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';