* fix: preserve Markdown blocks when copying messages * fix: preserve blank lines when copying code --------- Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import type { Part } from '@opencode-ai/sdk/v2';
|
|
|
|
type TextLikePart = Part & { text?: string; content?: string };
|
|
type UserTextPart = Part & { text?: string; content?: string; shellAction?: { output?: unknown; command?: unknown } };
|
|
|
|
export const flattenAssistantTextParts = (parts: Part[]): string => {
|
|
const textParts = parts
|
|
.filter((part): part is TextLikePart => part?.type === 'text')
|
|
.map((part) => (part.text || part.content || '').trim())
|
|
.filter((text) => text.length > 0);
|
|
|
|
return textParts.join('\n\n');
|
|
};
|
|
|
|
export const flattenUserTextParts = (parts: Part[]): string => {
|
|
const textParts = parts.filter((part): part is UserTextPart => part?.type === 'text');
|
|
|
|
const shellOutputs = textParts
|
|
.map((part) => {
|
|
const output = part.shellAction?.output;
|
|
return typeof output === 'string' ? output.trim() : '';
|
|
})
|
|
.filter((output) => output.length > 0);
|
|
if (shellOutputs.length > 0) {
|
|
return shellOutputs.join('\n\n');
|
|
}
|
|
|
|
const shellCommands = textParts
|
|
.map((part) => {
|
|
const command = part.shellAction?.command;
|
|
return typeof command === 'string' ? command.trim() : '';
|
|
})
|
|
.filter((command) => command.length > 0);
|
|
if (shellCommands.length > 0) {
|
|
return shellCommands.join('\n');
|
|
}
|
|
|
|
const plainTexts = textParts
|
|
.map((part) => (part.text || part.content || '').trim())
|
|
.filter((text) => text.length > 0);
|
|
return plainTexts.join('\n\n');
|
|
};
|
|
|
|
export const suggestPlanTitleFromText = (text: string): string => {
|
|
const normalized = text
|
|
.replace(/\r\n?/g, '\n')
|
|
.split('\n')
|
|
.map((line) => line.trim())
|
|
.find((line) => line.length > 0) || 'Plan';
|
|
|
|
const cleaned = normalized
|
|
.replace(/^#+\s*/, '')
|
|
.replace(/^[-*+]\s+/, '')
|
|
.replace(/^\d+\.\s+/, '');
|
|
|
|
const sentenceMatch = cleaned.match(/(.+?[.!?])(?:\s|$)/);
|
|
const firstSentence = sentenceMatch?.[1] || cleaned;
|
|
const compact = firstSentence.replace(/\s+/g, ' ').trim();
|
|
return compact.length > 160 ? compact.slice(0, 160).trim() : compact || 'Plan';
|
|
};
|