codemini-cli 0.1.11 → 0.1.12
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.
- package/package.json +1 -1
- package/src/core/chat-runtime.js +113 -2
- package/src/tui/chat-app.js +166 -1
package/package.json
CHANGED
package/src/core/chat-runtime.js
CHANGED
|
@@ -498,7 +498,8 @@ function buildAutoPlanSystemSummary(auto) {
|
|
|
498
498
|
const lines = [
|
|
499
499
|
statusTitle,
|
|
500
500
|
`File: ${auto.filePath}`,
|
|
501
|
-
`Summary: ${auto.summary || '-'}`,
|
|
501
|
+
`Plan Summary: ${auto.summary || '-'}`,
|
|
502
|
+
`Final Summary: ${auto.finalSummary || auto.summary || '-'}`,
|
|
502
503
|
`Steps: ${auto.steps.length} total`,
|
|
503
504
|
`Completed: ${auto.completedCount}`,
|
|
504
505
|
`Warnings: ${auto.warningCount}`,
|
|
@@ -513,6 +514,95 @@ function buildAutoPlanSystemSummary(auto) {
|
|
|
513
514
|
return lines.join('\n');
|
|
514
515
|
}
|
|
515
516
|
|
|
517
|
+
function buildAutoPlanFinalSummaryUserPrompt({ goal, autoPlan, runItems, planningError }) {
|
|
518
|
+
const lines = [];
|
|
519
|
+
lines.push('Create a final execution summary for an auto-generated implementation/test plan.');
|
|
520
|
+
lines.push('Keep it concise, high-signal, and outcome-focused.');
|
|
521
|
+
lines.push('Include: overall result, what was verified, what is still pending, and the best next action.');
|
|
522
|
+
lines.push('Use plain text only. Do not use markdown fences.');
|
|
523
|
+
lines.push('');
|
|
524
|
+
lines.push(`Goal: ${goal}`);
|
|
525
|
+
lines.push(`Plan Summary: ${autoPlan?.summary || `Auto plan for: ${goal}`}`);
|
|
526
|
+
if (planningError) {
|
|
527
|
+
lines.push(`Planning Error: ${planningError}`);
|
|
528
|
+
}
|
|
529
|
+
lines.push('');
|
|
530
|
+
lines.push('Executed Steps:');
|
|
531
|
+
runItems.forEach((item, idx) => {
|
|
532
|
+
lines.push(`${idx + 1}. [${item.role}] ${item.title}`);
|
|
533
|
+
if (item.failed) {
|
|
534
|
+
lines.push(`Status: failed`);
|
|
535
|
+
} else if (item.warning) {
|
|
536
|
+
lines.push(`Status: warning`);
|
|
537
|
+
} else {
|
|
538
|
+
lines.push(`Status: completed`);
|
|
539
|
+
}
|
|
540
|
+
if (item.error) {
|
|
541
|
+
lines.push(`Error: ${item.error}`);
|
|
542
|
+
}
|
|
543
|
+
if (item.warning) {
|
|
544
|
+
lines.push(`Warning: ${item.warning}`);
|
|
545
|
+
}
|
|
546
|
+
lines.push(`Output: ${trimInlineText(item.output || '(empty)', 500)}`);
|
|
547
|
+
if (Array.isArray(item.artifactPaths) && item.artifactPaths.length > 0) {
|
|
548
|
+
lines.push(`Artifacts: ${item.artifactPaths.slice(0, 5).join(', ')}`);
|
|
549
|
+
}
|
|
550
|
+
lines.push('');
|
|
551
|
+
});
|
|
552
|
+
return lines.join('\n').trim();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async function buildAutoPlanFinalSummary({
|
|
556
|
+
goal,
|
|
557
|
+
autoPlan,
|
|
558
|
+
runItems,
|
|
559
|
+
planningError,
|
|
560
|
+
config,
|
|
561
|
+
model,
|
|
562
|
+
systemPrompt
|
|
563
|
+
}) {
|
|
564
|
+
const fallbackParts = [];
|
|
565
|
+
if (runItems.some((item) => item.failed || item.error)) {
|
|
566
|
+
fallbackParts.push('Execution finished with failed steps.');
|
|
567
|
+
} else if (runItems.some((item) => item.warning)) {
|
|
568
|
+
fallbackParts.push('Execution finished with warnings.');
|
|
569
|
+
} else {
|
|
570
|
+
fallbackParts.push('Execution finished successfully.');
|
|
571
|
+
}
|
|
572
|
+
const verifiedTitles = runItems.filter((item) => !item.failed).map((item) => item.title);
|
|
573
|
+
const pendingTitles = runItems.filter((item) => item.failed || item.warning).map((item) => item.title);
|
|
574
|
+
if (verifiedTitles.length > 0) {
|
|
575
|
+
fallbackParts.push(`Completed: ${verifiedTitles.slice(0, 4).join(', ')}.`);
|
|
576
|
+
}
|
|
577
|
+
if (pendingTitles.length > 0) {
|
|
578
|
+
fallbackParts.push(`Needs follow-up: ${pendingTitles.slice(0, 4).join(', ')}.`);
|
|
579
|
+
}
|
|
580
|
+
const fallbackSummary = fallbackParts.join(' ');
|
|
581
|
+
|
|
582
|
+
try {
|
|
583
|
+
const result = await createChatCompletion({
|
|
584
|
+
baseUrl: config.gateway.base_url,
|
|
585
|
+
apiKey: config.gateway.api_key,
|
|
586
|
+
model: model || config.model.name,
|
|
587
|
+
messages: [
|
|
588
|
+
{
|
|
589
|
+
role: 'system',
|
|
590
|
+
content: `${systemPrompt}\nYou are writing the final execution summary for a completed auto plan. Focus on closure, verification status, and the next action.`
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
role: 'user',
|
|
594
|
+
content: buildAutoPlanFinalSummaryUserPrompt({ goal, autoPlan, runItems, planningError })
|
|
595
|
+
}
|
|
596
|
+
],
|
|
597
|
+
timeoutMs: config.gateway.timeout_ms || 90000,
|
|
598
|
+
maxRetries: config.gateway.max_retries ?? 2
|
|
599
|
+
});
|
|
600
|
+
return trimInlineText(result.text || '', 600) || fallbackSummary;
|
|
601
|
+
} catch {
|
|
602
|
+
return fallbackSummary;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
516
606
|
async function writeMarkdownInCoderDir(subDir, title, body, fallbackName, sessionId) {
|
|
517
607
|
const parts = [process.cwd(), '.coder', subDir];
|
|
518
608
|
if (sessionId) parts.push(String(sessionId));
|
|
@@ -1050,12 +1140,13 @@ async function buildAutoPlanAndRun({
|
|
|
1050
1140
|
}
|
|
1051
1141
|
|
|
1052
1142
|
const runItems = [];
|
|
1143
|
+
const totalPlanSteps = autoPlan.steps.length + 1;
|
|
1053
1144
|
for (let i = 0; i < autoPlan.steps.length; i += 1) {
|
|
1054
1145
|
const step = autoPlan.steps[i];
|
|
1055
1146
|
if (onAgentEvent) {
|
|
1056
1147
|
onAgentEvent({
|
|
1057
1148
|
type: 'assistant:delta',
|
|
1058
|
-
text: `\n[plan] Step ${i + 1}/${
|
|
1149
|
+
text: `\n[plan] Step ${i + 1}/${totalPlanSteps} -> ${step.role}: ${step.title}\n`
|
|
1059
1150
|
});
|
|
1060
1151
|
}
|
|
1061
1152
|
try {
|
|
@@ -1106,11 +1197,30 @@ async function buildAutoPlanAndRun({
|
|
|
1106
1197
|
const warningItems = runItems.filter((s) => !s.failed && s.warning);
|
|
1107
1198
|
const completedItems = runItems.filter((s) => !s.failed);
|
|
1108
1199
|
|
|
1200
|
+
if (onAgentEvent) {
|
|
1201
|
+
onAgentEvent({
|
|
1202
|
+
type: 'assistant:delta',
|
|
1203
|
+
text: `\n[plan] Step ${totalPlanSteps}/${totalPlanSteps} -> summarizer: Final summary\n`
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
const finalSummary = await buildAutoPlanFinalSummary({
|
|
1207
|
+
goal,
|
|
1208
|
+
autoPlan,
|
|
1209
|
+
runItems,
|
|
1210
|
+
planningError,
|
|
1211
|
+
config,
|
|
1212
|
+
model,
|
|
1213
|
+
systemPrompt
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1109
1216
|
const lines = [];
|
|
1110
1217
|
lines.push(`# Auto Plan: ${goal}`);
|
|
1111
1218
|
lines.push('');
|
|
1112
1219
|
lines.push(`## Summary`);
|
|
1113
1220
|
lines.push(autoPlan.summary || `Auto plan for: ${goal}`);
|
|
1221
|
+
lines.push('');
|
|
1222
|
+
lines.push('## Final Summary');
|
|
1223
|
+
lines.push(finalSummary || '(empty)');
|
|
1114
1224
|
if (planningError) {
|
|
1115
1225
|
lines.push('');
|
|
1116
1226
|
lines.push(`Planning Error: ${planningError}`);
|
|
@@ -1152,6 +1262,7 @@ async function buildAutoPlanAndRun({
|
|
|
1152
1262
|
return {
|
|
1153
1263
|
filePath,
|
|
1154
1264
|
summary: autoPlan.summary,
|
|
1265
|
+
finalSummary,
|
|
1155
1266
|
steps: autoPlan.steps,
|
|
1156
1267
|
completedCount: completedItems.length,
|
|
1157
1268
|
warningCount: warningItems.length,
|
package/src/tui/chat-app.js
CHANGED
|
@@ -546,6 +546,161 @@ function renderTextLine(msg, line, idx, color) {
|
|
|
546
546
|
);
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
export function parseAutoPlanSummaryMessage(text) {
|
|
550
|
+
const raw = String(text || '').trim();
|
|
551
|
+
if (!/^Auto plan finished\b/i.test(raw)) return null;
|
|
552
|
+
|
|
553
|
+
const lines = raw
|
|
554
|
+
.split('\n')
|
|
555
|
+
.map((line) => line.trim())
|
|
556
|
+
.filter(Boolean);
|
|
557
|
+
const parsed = {
|
|
558
|
+
statusTitle: lines[0] || '',
|
|
559
|
+
filePath: '',
|
|
560
|
+
planSummary: '',
|
|
561
|
+
finalSummary: '',
|
|
562
|
+
stepsTotal: '',
|
|
563
|
+
completed: '',
|
|
564
|
+
warnings: '',
|
|
565
|
+
failed: '',
|
|
566
|
+
warningSteps: '',
|
|
567
|
+
failedSteps: ''
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
for (const line of lines.slice(1)) {
|
|
571
|
+
if (line.startsWith('File: ')) parsed.filePath = line.slice('File: '.length).trim();
|
|
572
|
+
else if (line.startsWith('Plan Summary: ')) parsed.planSummary = line.slice('Plan Summary: '.length).trim();
|
|
573
|
+
else if (line.startsWith('Final Summary: ')) parsed.finalSummary = line.slice('Final Summary: '.length).trim();
|
|
574
|
+
else if (line.startsWith('Steps: ')) parsed.stepsTotal = line.slice('Steps: '.length).trim();
|
|
575
|
+
else if (line.startsWith('Completed: ')) parsed.completed = line.slice('Completed: '.length).trim();
|
|
576
|
+
else if (line.startsWith('Warnings: ')) parsed.warnings = line.slice('Warnings: '.length).trim();
|
|
577
|
+
else if (line.startsWith('Failed: ')) parsed.failed = line.slice('Failed: '.length).trim();
|
|
578
|
+
else if (line.startsWith('Warning steps: ')) parsed.warningSteps = line.slice('Warning steps: '.length).trim();
|
|
579
|
+
else if (line.startsWith('Failed steps: ')) parsed.failedSteps = line.slice('Failed steps: '.length).trim();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return parsed;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function PlanSummaryBubble({ msg, copy }) {
|
|
586
|
+
const theme = roleStyle(msg.label);
|
|
587
|
+
const summary = msg.planSummary || parseAutoPlanSummaryMessage(msg.text);
|
|
588
|
+
if (!summary) return null;
|
|
589
|
+
|
|
590
|
+
const statusColor =
|
|
591
|
+
Number(summary.failed || 0) > 0 ? 'redBright' : Number(summary.warnings || 0) > 0 ? 'yellowBright' : 'greenBright';
|
|
592
|
+
const isEnglish = copy?.roleLabels?.system === 'SYSTEM';
|
|
593
|
+
const labels = isEnglish
|
|
594
|
+
? {
|
|
595
|
+
conclusion: 'Conclusion',
|
|
596
|
+
plan: 'Plan',
|
|
597
|
+
warnings: 'Warnings',
|
|
598
|
+
failed: 'Failed',
|
|
599
|
+
file: 'File',
|
|
600
|
+
steps: 'steps',
|
|
601
|
+
done: 'done',
|
|
602
|
+
warn: 'warn',
|
|
603
|
+
fail: 'fail'
|
|
604
|
+
}
|
|
605
|
+
: {
|
|
606
|
+
conclusion: '结论',
|
|
607
|
+
plan: '计划',
|
|
608
|
+
warnings: '警告',
|
|
609
|
+
failed: '失败',
|
|
610
|
+
file: '文件',
|
|
611
|
+
steps: '步骤',
|
|
612
|
+
done: '完成',
|
|
613
|
+
warn: '警告',
|
|
614
|
+
fail: '失败'
|
|
615
|
+
};
|
|
616
|
+
const metaItems = [
|
|
617
|
+
summary.stepsTotal ? `${labels.steps} ${summary.stepsTotal}` : '',
|
|
618
|
+
summary.completed ? `${labels.done} ${summary.completed}` : '',
|
|
619
|
+
summary.warnings ? `${labels.warn} ${summary.warnings}` : '',
|
|
620
|
+
summary.failed ? `${labels.fail} ${summary.failed}` : ''
|
|
621
|
+
].filter(Boolean);
|
|
622
|
+
const shortFile = summary.filePath ? trimText(summary.filePath, 96) : '';
|
|
623
|
+
|
|
624
|
+
return h(
|
|
625
|
+
Box,
|
|
626
|
+
{ marginBottom: 1, flexDirection: 'row' },
|
|
627
|
+
h(Box, { width: 2 }, h(Text, { color: theme.accent }, '│')),
|
|
628
|
+
h(
|
|
629
|
+
Box,
|
|
630
|
+
{
|
|
631
|
+
flexDirection: 'column',
|
|
632
|
+
borderStyle: 'round',
|
|
633
|
+
borderColor: theme.border,
|
|
634
|
+
paddingX: 1,
|
|
635
|
+
paddingY: 0,
|
|
636
|
+
width: '100%'
|
|
637
|
+
},
|
|
638
|
+
h(
|
|
639
|
+
Box,
|
|
640
|
+
{ justifyContent: 'space-between', marginBottom: summary.finalSummary ? 1 : 0 },
|
|
641
|
+
h(
|
|
642
|
+
Box,
|
|
643
|
+
null,
|
|
644
|
+
h(Text, { color: theme.badgeText, backgroundColor: theme.badgeBg }, ` ${messageLabel(msg.label, copy)} `),
|
|
645
|
+
h(Text, { color: 'gray' }, ' '),
|
|
646
|
+
h(Text, { color: statusColor }, summary.statusTitle)
|
|
647
|
+
),
|
|
648
|
+
h(Text, { color: theme.chrome }, ' ')
|
|
649
|
+
),
|
|
650
|
+
summary.finalSummary
|
|
651
|
+
? h(
|
|
652
|
+
Box,
|
|
653
|
+
{ marginBottom: summary.planSummary || metaItems.length > 0 || summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
654
|
+
h(Text, { color: statusColor }, labels.conclusion),
|
|
655
|
+
h(Text, { color: 'white' }, summary.finalSummary)
|
|
656
|
+
)
|
|
657
|
+
: null,
|
|
658
|
+
summary.planSummary
|
|
659
|
+
? h(
|
|
660
|
+
Box,
|
|
661
|
+
{ marginBottom: metaItems.length > 0 || summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
662
|
+
h(Text, { color: 'cyanBright' }, labels.plan),
|
|
663
|
+
h(Text, { color: 'gray' }, summary.planSummary)
|
|
664
|
+
)
|
|
665
|
+
: null,
|
|
666
|
+
metaItems.length > 0
|
|
667
|
+
? h(
|
|
668
|
+
Box,
|
|
669
|
+
{ marginBottom: summary.warningSteps || summary.failedSteps || shortFile ? 1 : 0 },
|
|
670
|
+
...metaItems.flatMap((item, idx) => [
|
|
671
|
+
idx > 0 ? h(Text, { key: `sep-${idx}`, color: 'gray' }, ' ') : null,
|
|
672
|
+
h(Text, { key: `meta-${idx}`, color: 'gray' }, item)
|
|
673
|
+
])
|
|
674
|
+
)
|
|
675
|
+
: null,
|
|
676
|
+
summary.warningSteps
|
|
677
|
+
? h(
|
|
678
|
+
Box,
|
|
679
|
+
{ marginBottom: summary.failedSteps || shortFile ? 1 : 0, flexDirection: 'column' },
|
|
680
|
+
h(Text, { color: 'yellowBright' }, labels.warnings),
|
|
681
|
+
h(Text, { color: 'gray' }, summary.warningSteps)
|
|
682
|
+
)
|
|
683
|
+
: null,
|
|
684
|
+
summary.failedSteps
|
|
685
|
+
? h(
|
|
686
|
+
Box,
|
|
687
|
+
{ marginBottom: shortFile ? 1 : 0, flexDirection: 'column' },
|
|
688
|
+
h(Text, { color: 'redBright' }, labels.failed),
|
|
689
|
+
h(Text, { color: 'gray' }, summary.failedSteps)
|
|
690
|
+
)
|
|
691
|
+
: null,
|
|
692
|
+
shortFile
|
|
693
|
+
? h(
|
|
694
|
+
Box,
|
|
695
|
+
{ flexDirection: 'column' },
|
|
696
|
+
h(Text, { color: 'gray' }, labels.file),
|
|
697
|
+
h(Text, { color: 'gray' }, shortFile)
|
|
698
|
+
)
|
|
699
|
+
: null
|
|
700
|
+
)
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
|
|
549
704
|
const BUBBLE_CHROME_ROWS = 4;
|
|
550
705
|
|
|
551
706
|
function charDisplayWidth(ch) {
|
|
@@ -729,6 +884,9 @@ function getSuggestionDisplay(item) {
|
|
|
729
884
|
}
|
|
730
885
|
|
|
731
886
|
function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, contentWidth = 72, copy }) {
|
|
887
|
+
if (msg?.planSummary || parseAutoPlanSummaryMessage(msg?.text)) {
|
|
888
|
+
return h(PlanSummaryBubble, { msg, copy });
|
|
889
|
+
}
|
|
732
890
|
const theme = roleStyle(msg.label);
|
|
733
891
|
const allRows = buildMessageRows(msg, showToolDetails, contentWidth);
|
|
734
892
|
const start = rowWindow ? Math.max(0, rowWindow.start || 0) : 0;
|
|
@@ -1338,9 +1496,16 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1338
1496
|
}
|
|
1339
1497
|
return;
|
|
1340
1498
|
}
|
|
1499
|
+
const parsedPlanSummary = result.type === 'system' ? parseAutoPlanSummaryMessage(result.text || '') : null;
|
|
1341
1500
|
setMessages((prev) => [
|
|
1342
1501
|
...prev,
|
|
1343
|
-
{
|
|
1502
|
+
{
|
|
1503
|
+
id: nextId(),
|
|
1504
|
+
label: 'system',
|
|
1505
|
+
text: result.text || '',
|
|
1506
|
+
color: 'yellowBright',
|
|
1507
|
+
...(parsedPlanSummary ? { planSummary: parsedPlanSummary } : {})
|
|
1508
|
+
}
|
|
1344
1509
|
]);
|
|
1345
1510
|
};
|
|
1346
1511
|
|