edsger 0.26.2 → 0.26.4
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.
|
@@ -25,9 +25,11 @@ The \`dev/\` prefix indicates this is a development branch. A PR will be created
|
|
|
25
25
|
|
|
26
26
|
Feature ID for this feature: ${featureId}
|
|
27
27
|
|
|
28
|
-
## Output Format
|
|
28
|
+
## CRITICAL - Output Format
|
|
29
29
|
|
|
30
|
-
You MUST
|
|
30
|
+
You MUST return ONLY a JSON object with your branch planning results.
|
|
31
|
+
Do NOT include any explanatory text, summary, or commentary before or after the JSON.
|
|
32
|
+
Return ONLY the JSON in this EXACT format:
|
|
31
33
|
|
|
32
34
|
\`\`\`json
|
|
33
35
|
{
|
|
@@ -113,7 +113,7 @@ export async function pushAndCreateGitHubPR(config, branchName, title, descripti
|
|
|
113
113
|
body: description,
|
|
114
114
|
head: prHead,
|
|
115
115
|
base: prBase,
|
|
116
|
-
draft:
|
|
116
|
+
draft: true,
|
|
117
117
|
});
|
|
118
118
|
if (verbose) {
|
|
119
119
|
logInfo(`✅ Pull request created: ${newPR.html_url}`);
|
|
@@ -269,78 +269,48 @@ async function executeAgentQuery(userPrompt, systemPrompt, config, verbose) {
|
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
271
|
/**
|
|
272
|
-
*
|
|
272
|
+
* Extract a balanced JSON object starting from a given index using brace counting.
|
|
273
|
+
* Handles nested braces and strings with escaped characters correctly.
|
|
273
274
|
*/
|
|
274
|
-
function
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
if (parsed.pull_requests) {
|
|
288
|
-
return {
|
|
289
|
-
pullRequests: parsed.pull_requests,
|
|
290
|
-
summary: parsed.summary,
|
|
291
|
-
rationale: parsed.rationale,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return parsed;
|
|
275
|
+
function extractBalancedJson(text, startIndex) {
|
|
276
|
+
if (text[startIndex] !== '{')
|
|
277
|
+
return null;
|
|
278
|
+
let braceCount = 0;
|
|
279
|
+
let inString = false;
|
|
280
|
+
let escape = false;
|
|
281
|
+
for (let i = startIndex; i < text.length; i++) {
|
|
282
|
+
const ch = text[i];
|
|
283
|
+
if (escape) {
|
|
284
|
+
escape = false;
|
|
285
|
+
continue;
|
|
295
286
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
287
|
+
if (ch === '\\' && inString) {
|
|
288
|
+
escape = true;
|
|
289
|
+
continue;
|
|
300
290
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (resultMatch) {
|
|
305
|
-
try {
|
|
306
|
-
let braceCount = 0;
|
|
307
|
-
let startIndex = -1;
|
|
308
|
-
let endIndex = -1;
|
|
309
|
-
for (let i = 0; i < responseText.length; i++) {
|
|
310
|
-
if (responseText[i] === '{') {
|
|
311
|
-
if (startIndex === -1)
|
|
312
|
-
startIndex = i;
|
|
313
|
-
braceCount++;
|
|
314
|
-
}
|
|
315
|
-
else if (responseText[i] === '}') {
|
|
316
|
-
braceCount--;
|
|
317
|
-
if (braceCount === 0 && startIndex !== -1) {
|
|
318
|
-
endIndex = i;
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (startIndex !== -1 && endIndex !== -1) {
|
|
324
|
-
const jsonStr = responseText.substring(startIndex, endIndex + 1);
|
|
325
|
-
const parsed = JSON.parse(jsonStr);
|
|
326
|
-
if (parsed.pr_splitting_result) {
|
|
327
|
-
return {
|
|
328
|
-
pullRequests: parsed.pr_splitting_result.pull_requests || [],
|
|
329
|
-
summary: parsed.pr_splitting_result.summary,
|
|
330
|
-
rationale: parsed.pr_splitting_result.rationale,
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
}
|
|
291
|
+
if (ch === '"') {
|
|
292
|
+
inString = !inString;
|
|
293
|
+
continue;
|
|
334
294
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
295
|
+
if (inString)
|
|
296
|
+
continue;
|
|
297
|
+
if (ch === '{')
|
|
298
|
+
braceCount++;
|
|
299
|
+
else if (ch === '}') {
|
|
300
|
+
braceCount--;
|
|
301
|
+
if (braceCount === 0) {
|
|
302
|
+
return text.substring(startIndex, i + 1);
|
|
338
303
|
}
|
|
339
304
|
}
|
|
340
305
|
}
|
|
341
|
-
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Try to parse a JSON string and extract PR splitting result
|
|
310
|
+
*/
|
|
311
|
+
function tryParsePRResult(jsonStr) {
|
|
342
312
|
try {
|
|
343
|
-
const parsed = JSON.parse(
|
|
313
|
+
const parsed = JSON.parse(jsonStr);
|
|
344
314
|
if (parsed.pr_splitting_result) {
|
|
345
315
|
return {
|
|
346
316
|
pullRequests: parsed.pr_splitting_result.pull_requests || [],
|
|
@@ -355,12 +325,73 @@ function parseJsonResponse(responseText, verbose) {
|
|
|
355
325
|
rationale: parsed.rationale,
|
|
356
326
|
};
|
|
357
327
|
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Parse JSON response from Claude
|
|
336
|
+
* Handles: JSON in code blocks, raw JSON mixed with markdown, pure JSON
|
|
337
|
+
*/
|
|
338
|
+
function parseJsonResponse(responseText, verbose) {
|
|
339
|
+
// Strategy 1: Find JSON code blocks and try each one (handles multiple code blocks)
|
|
340
|
+
const codeBlockRegex = /```(?:json)?\s*\n([\s\S]*?)\n\s*```/g;
|
|
341
|
+
let match;
|
|
342
|
+
while ((match = codeBlockRegex.exec(responseText)) !== null) {
|
|
343
|
+
const content = match[1].trim();
|
|
344
|
+
if (content.startsWith('{')) {
|
|
345
|
+
const result = tryParsePRResult(content);
|
|
346
|
+
if (result && result.pullRequests.length > 0) {
|
|
347
|
+
return result;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
358
350
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
351
|
+
// Strategy 2: Find "pr_splitting_result" and extract the enclosing JSON object
|
|
352
|
+
// Walk backwards from the keyword to find the outermost opening brace
|
|
353
|
+
const keyword = '"pr_splitting_result"';
|
|
354
|
+
const keywordIndex = responseText.indexOf(keyword);
|
|
355
|
+
if (keywordIndex !== -1) {
|
|
356
|
+
// Find the opening { before the keyword
|
|
357
|
+
for (let i = keywordIndex - 1; i >= 0; i--) {
|
|
358
|
+
if (responseText[i] === '{') {
|
|
359
|
+
const jsonStr = extractBalancedJson(responseText, i);
|
|
360
|
+
if (jsonStr) {
|
|
361
|
+
const result = tryParsePRResult(jsonStr);
|
|
362
|
+
if (result && result.pullRequests.length > 0) {
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
362
368
|
}
|
|
363
369
|
}
|
|
370
|
+
// Strategy 3: Find any { that starts a JSON object with "pull_requests" key
|
|
371
|
+
const pullRequestsKeyword = '"pull_requests"';
|
|
372
|
+
const prIndex = responseText.indexOf(pullRequestsKeyword);
|
|
373
|
+
if (prIndex !== -1) {
|
|
374
|
+
for (let i = prIndex - 1; i >= 0; i--) {
|
|
375
|
+
if (responseText[i] === '{') {
|
|
376
|
+
const jsonStr = extractBalancedJson(responseText, i);
|
|
377
|
+
if (jsonStr) {
|
|
378
|
+
const result = tryParsePRResult(jsonStr);
|
|
379
|
+
if (result && result.pullRequests.length > 0) {
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Strategy 4: Try to parse the entire response as JSON
|
|
388
|
+
const result = tryParsePRResult(responseText.trim());
|
|
389
|
+
if (result) {
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
if (verbose) {
|
|
393
|
+
logError(`Failed to extract PR splitting JSON from response (length: ${responseText.length})`);
|
|
394
|
+
}
|
|
364
395
|
return null;
|
|
365
396
|
}
|
|
366
397
|
// Re-export types and functions for external use
|
|
@@ -30,9 +30,11 @@ Branch names MUST follow this pattern:
|
|
|
30
30
|
- \`pr/${featureId}/2-{short-description}\`
|
|
31
31
|
- etc.
|
|
32
32
|
|
|
33
|
-
## Output Format
|
|
33
|
+
## CRITICAL - Output Format
|
|
34
34
|
|
|
35
|
-
You MUST
|
|
35
|
+
You MUST return ONLY a JSON object with your PR splitting results.
|
|
36
|
+
Do NOT include any explanatory text, summary, or commentary before or after the JSON.
|
|
37
|
+
Return ONLY the JSON in this EXACT format:
|
|
36
38
|
|
|
37
39
|
\`\`\`json
|
|
38
40
|
{
|