(text: string)
| 238 | |
| 239 | /** Parse a planner's JSON output, tolerating accidental markdown fences. */ |
| 240 | export function parsePlanJson(text: string): RawPlan { |
| 241 | let s = text.trim(); |
| 242 | const fence = s.match(/```(?:json)?\s*([\s\S]*?)```/); |
| 243 | if (fence) s = fence[1]!.trim(); |
| 244 | // Find the first {...} block if there's leading prose. |
| 245 | const brace = s.indexOf('{'); |
| 246 | const lastBrace = s.lastIndexOf('}'); |
| 247 | if (brace > 0 || lastBrace < s.length - 1) { |
| 248 | if (brace >= 0 && lastBrace > brace) s = s.slice(brace, lastBrace + 1); |
| 249 | } |
| 250 | let parsed: any; |
| 251 | try { parsed = JSON.parse(s); } catch (e: any) { |
| 252 | throw new Error(`Planner did not return valid JSON: ${e?.message}. Got: ${text.slice(0, 200)}`); |
| 253 | } |
| 254 | if (!parsed || !Array.isArray(parsed.tasks)) { |
| 255 | throw new Error('Planner JSON missing "tasks" array.'); |
| 256 | } |
| 257 | return parsed as RawPlan; |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Extract file edits from a worker's final text. Workers are asked to output |
no outgoing calls
no test coverage detected