export function buildAgentMessageParts(input) {
    const extractedReasoning = extractInlineReasoning(normalizeOutputLines(input.output));
    const lines = extractedReasoning.lines;
    const finalTextRange = findFinalTextRange(lines);
    const finalText = finalTextRange
        ? collapseRepeatedTextBlock(lines.slice(finalTextRange.start, finalTextRange.end + 1)).join('\n').trim()
        : '';
    const usage = input.usage ?? extractUsage(lines);
    const parts = [];
    const chainItems = buildChainItems(lines, finalTextRange, finalText, input.workspaceRoot, input.toolDetails, input.persistentContext, input.askUserQuestions);
    const reasoningText = normalizeReasoningText([
        ...(input.reasoning ?? []),
        ...extractedReasoning.reasoning.map((text) => ({ text })),
    ]);
    if (reasoningText) {
        parts.push({
            id: `reasoning-${input.sessionId}`,
            type: 'reasoning',
            text: reasoningText,
            status: input.success ? 'completed' : 'streaming',
        });
    }
    if (chainItems.length > 0) {
        parts.push({
            id: `chain-${input.sessionId}`,
            type: 'chain',
            chains: chainItems,
        });
    }
    for (const subagent of extractSubagentBlocks(lines, input.sessionId, input.toolDetails)) {
        parts.push(subagent);
    }
    for (const question of input.askUserQuestions ?? []) {
        parts.push({
            id: question.id,
            type: 'ask_user_question',
            question: question.question,
            choices: question.choices,
            status: question.answer ? 'answered' : 'requested',
            answer: question.answer,
            toolUseId: question.toolUseId,
        });
    }
    if (hasTokenUsage(usage)) {
        parts.push({
            id: `context-${input.sessionId}`,
            type: 'context',
            usedTokens: getTotalTokens(usage),
            maxTokens: 128_000,
            modelId: input.model,
            usage,
            agentContext: {
                sessionId: input.sessionId,
                agentConfigId: input.agentConfigId,
                name: input.presetName,
                role: input.role,
                runtime: input.runtime,
                model: input.model,
                systemPrompt: input.systemPrompt,
                userPrompt: input.userPrompt,
                fullPrompt: input.fullPrompt,
                output: lines.join('\n'),
                outputItems: input.outputItems,
                persistentContext: input.persistentContext,
            },
        });
    }
    if (input.error) {
        parts.push({
            id: `terminal-error-${input.sessionId}`,
            type: 'terminal',
            output: input.error,
            status: 'error',
        });
    }
    if (finalText && finalText !== input.error) {
        parts.push({
            id: `text-${input.sessionId}`,
            type: 'text',
            text: finalText,
        });
    }
    return parts;
}
export function normalizeOutputLines(output) {
    const lines = output
        .flatMap((line) => line.split(/\r?\n/))
        .map((line) => line.trimEnd())
        .filter((line) => line.trim());
    const seenInitLines = new Set();
    let inAgentSpacesPromptEcho = false;
    let skipNextUserMessageEchoLine = false;
    const normalizedLines = [];
    for (const line of lines) {
        const cleaned = stripRuntimeNoticePrefix(stripRuntimeLogPrefix(line)).trim();
        if (!cleaned)
            continue;
        if (skipNextUserMessageEchoLine) {
            skipNextUserMessageEchoLine = false;
            continue;
        }
        if (isAgentSpacesPromptEchoStart(cleaned) || /^Agent runtime configuration:\s*$/i.test(cleaned)) {
            inAgentSpacesPromptEcho = true;
            continue;
        }
        if (inAgentSpacesPromptEcho) {
            if (/\bUser message:\s*$/i.test(cleaned)) {
                inAgentSpacesPromptEcho = false;
                skipNextUserMessageEchoLine = true;
            }
            else if (/\bUser message:/i.test(cleaned)) {
                inAgentSpacesPromptEcho = false;
            }
            continue;
        }
        if (isIgnorablePromptEchoLine(cleaned))
            continue;
        if (isIgnorableToolProgressLine(cleaned))
            continue;
        if (/^Claude Code initialized\b/i.test(cleaned)) {
            if (seenInitLines.has(cleaned))
                continue;
            seenInitLines.add(cleaned);
        }
        normalizedLines.push(cleaned);
    }
    return normalizedLines;
}
export function mergeRuntimeOutput(liveOutput, resultOutput) {
    if (liveOutput.length === 0)
        return resultOutput;
    const finalResult = resultOutput.at(-1)?.trim();
    if (!finalResult)
        return liveOutput;
    if (liveOutput.some((line) => normalizeMessageText(line) === normalizeMessageText(finalResult))) {
        return liveOutput;
    }
    return [...liveOutput, finalResult];
}
export function buildToolDetailId(id, line) {
    const key = `${id}:${line}`;
    let hash = 0;
    for (let index = 0; index < key.length; index += 1) {
        hash = ((hash << 5) - hash + key.charCodeAt(index)) | 0;
    }
    return `tool-${Math.abs(hash).toString(36)}`;
}
export function summarizeToolLine(line, workspaceRoot) {
    const trimmed = line.trim();
    const toolName = extractToolName(trimmed);
    const inputDescription = extractQuotedField(trimmed, 'description');
    const filePath = toWorkspaceRelativePath(extractQuotedField(trimmed, 'file_path') ?? extractQuotedField(trimmed, 'path'), workspaceRoot);
    const command = extractQuotedField(trimmed, 'command') ?? extractCommand(trimmed, toolName);
    const baseName = filePath?.split(/[\\/]/).filter(Boolean).at(-1);
    if (toolName) {
        if (filePath) {
            return {
                title: `${humanizeToolName(toolName)} ${baseName ?? filePath}`,
                description: inputDescription ?? filePath,
                toolName,
                filePath,
            };
        }
        if (command) {
            return {
                title: `${humanizeToolName(toolName)} command`,
                description: inputDescription,
                toolName,
                command,
            };
        }
        const skillSummary = extractSkillParams(trimmed, toolName);
        if (skillSummary) {
            return { ...skillSummary, toolName };
        }
        const searchSummary = extractSearchParams(trimmed, toolName, workspaceRoot);
        if (searchSummary) {
            return { ...searchSummary, toolName };
        }
        const todoCount = extractTodoCount(trimmed);
        if (todoCount !== undefined) {
            return {
                title: `Update ${todoCount} ${todoCount === 1 ? 'todo' : 'todos'}`,
                toolName,
            };
        }
        return {
            title: humanizeToolName(toolName),
            toolName,
        };
    }
    return { title: trimmed };
}
export function findToolDetailForResult(toolUseId, result, toolUseDetailIds, toolDetails, workspaceRoot) {
    const detailId = toolUseId ? toolUseDetailIds.get(toolUseId) : undefined;
    const byId = detailId ? toolDetails.get(detailId) : undefined;
    if (byId)
        return byId;
    const resultFilePath = extractResultFilePath(result, workspaceRoot);
    if (resultFilePath) {
        const details = Array.from(toolDetails.values()).reverse();
        for (const detail of details) {
            if (detail.output !== undefined)
                continue;
            const inputFilePath = extractInputFilePath(detail.input, workspaceRoot);
            if (inputFilePath === resultFilePath)
                return detail;
        }
    }
    if (isSubagentToolResult(result)) {
        const detail = Array.from(toolDetails.values()).reverse().find((candidate) => {
            return candidate.output === undefined && /^Tool:\s*Task\b/i.test(candidate.raw);
        });
        if (detail)
            return detail;
    }
    return Array.from(toolDetails.values()).reverse().find((detail) => detail.output === undefined);
}
function normalizeReasoningText(reasoning) {
    if (!reasoning?.length)
        return '';
    return collapseRepeatedTextBlock(reasoning
        .map((item) => item.text.trim())
        .filter(Boolean)).join('\n\n').trim();
}
function extractInlineReasoning(lines) {
    const reasoning = [];
    const outputLines = [];
    let buffer = [];
    let inThinkBlock = false;
    const flushReasoning = () => {
        const text = buffer.join('\n').trim();
        if (text)
            reasoning.push(text);
        buffer = [];
    };
    for (const line of lines) {
        let rest = line;
        let visible = '';
        while (rest) {
            if (inThinkBlock) {
                const closeIndex = rest.search(/<\/think>/i);
                if (closeIndex < 0) {
                    buffer.push(rest);
                    rest = '';
                    continue;
                }
                buffer.push(rest.slice(0, closeIndex));
                flushReasoning();
                rest = rest.slice(closeIndex).replace(/^<\/think>/i, '');
                inThinkBlock = false;
                continue;
            }
            const openIndex = rest.search(/<think>/i);
            if (openIndex < 0) {
                visible += rest;
                rest = '';
                continue;
            }
            visible += rest.slice(0, openIndex);
            rest = rest.slice(openIndex).replace(/^<think>/i, '');
            inThinkBlock = true;
        }
        const cleaned = visible.trimEnd();
        if (cleaned.trim())
            outputLines.push(cleaned);
    }
    if (inThinkBlock)
        flushReasoning();
    return { lines: outputLines, reasoning };
}
function hasTokenUsage(usage) {
    return Boolean(usage.totalTokens || usage.inputTokens || usage.outputTokens || usage.cachedInputTokens || usage.reasoningTokens);
}
function getTotalTokens(usage) {
    return usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0) + (usage.cachedInputTokens ?? 0) + (usage.reasoningTokens ?? 0);
}
function collapseRepeatedTextBlock(lines) {
    let next = [...lines];
    while (next.length > 1 && next.length % 2 === 0) {
        const middle = next.length / 2;
        const first = next.slice(0, middle);
        const second = next.slice(middle);
        if (!sameTextBlock(first, second))
            break;
        next = first;
    }
    return next;
}
function sameTextBlock(left, right) {
    if (left.length !== right.length)
        return false;
    return normalizeMessageText(left.join('\n')) === normalizeMessageText(right.join('\n'));
}
function findFinalTextRange(lines) {
    let end = -1;
    for (let index = lines.length - 1; index >= 0; index -= 1) {
        if (isFinalAnswerLine(lines[index])) {
            end = index;
            break;
        }
    }
    if (end < 0)
        return null;
    let start = end;
    for (let index = end - 1; index >= 0; index -= 1) {
        if (!isFinalAnswerLine(lines[index]))
            break;
        start = index;
    }
    return { start, end };
}
function buildChainItems(lines, finalTextRange, finalText, workspaceRoot, toolDetails, persistentContext, askUserQuestions) {
    let toolIndex = 0;
    let messageIndex = 0;
    const items = [];
    const toolDetailMatchCounts = new Map();
    let messageBuffer = [];
    const persistentContextItem = buildPersistentContextToolItem(persistentContext);
    if (persistentContextItem) {
        items.push(persistentContextItem);
        toolIndex += 1;
    }
    for (const question of askUserQuestions ?? []) {
        items.push(buildAskUserQuestionToolItem(question, toolIndex));
        toolIndex += 1;
    }
    const flushMessageBuffer = () => {
        if (messageBuffer.length === 0)
            return;
        const text = messageBuffer.join('\n').trim();
        if (text) {
            items.push({
                id: `message-${messageIndex}`,
                title: summarizeMessageTitle(text),
                text,
                kind: 'message',
                status: 'completed',
            });
            messageIndex += 1;
        }
        messageBuffer = [];
    };
    for (let index = 0; index < lines.length; index += 1) {
        if (finalTextRange && index >= finalTextRange.start && index <= finalTextRange.end)
            continue;
        const line = lines[index];
        if (finalText && isSameMessageText(line, finalText))
            continue;
        if (isSubagentToolLine(line))
            continue;
        if (isToolLikeLine(line)) {
            flushMessageBuffer();
            items.push(buildToolTodo(line, toolIndex, workspaceRoot, toolDetails, toolDetailMatchCounts));
            toolIndex += 1;
            continue;
        }
        if (isFinalAnswerLine(line)) {
            messageBuffer.push(line);
        }
    }
    flushMessageBuffer();
    return items;
}
function buildToolTodo(line, index, workspaceRoot, toolDetails, toolDetailMatchCounts) {
    const summary = summarizeToolLine(line, workspaceRoot);
    const detailId = findToolDetailId(line, toolDetails, toolDetailMatchCounts);
    return {
        id: `tool-${index}`,
        kind: 'tool',
        title: summary.title,
        description: summary.description,
        status: 'completed',
        toolName: summary.toolName,
        filePath: summary.filePath,
        command: summary.command,
        detailId,
    };
}
function buildPersistentContextToolItem(persistentContext) {
    const counts = persistentContext?.counts;
    if (!counts?.total)
        return null;
    const parts = [
        counts.claudeMd ? `${counts.claudeMd} claude.md` : null,
        counts.agentsMd ? `${counts.agentsMd} AGENTS.md` : null,
    ].filter(Boolean);
    return {
        id: 'tool-persistent-context',
        kind: 'tool',
        title: 'Load claude.md',
        description: parts.length ? parts.join(', ') : `${counts.total} instruction files`,
        status: 'completed',
        toolName: 'LoadClaudeMd',
    };
}
function buildAskUserQuestionToolItem(question, index) {
    const choices = question.choices.length ? `选项：${question.choices.join(' / ')}` : undefined;
    const description = question.answer
        ? [question.question, `回答：${question.answer}`].join('\n')
        : [question.question, choices].filter(Boolean).join('\n');
    return {
        id: `tool-ask-user-question-${question.id || index}`,
        kind: 'tool',
        title: 'Ask user question',
        description,
        status: question.answer ? 'completed' : 'pending',
        toolName: 'AskUserQuestion',
        answer: question.answer,
    };
}
function extractSearchParams(line, toolName, workspaceRoot) {
    if (!/^(Glob|Grep|Search|SemanticSearch|WebSearch|WebFetch|Fetch)$/i.test(toolName))
        return null;
    const pattern = extractQuotedField(line, 'pattern') ?? extractQuotedField(line, 'query');
    const glob = extractQuotedField(line, 'glob');
    const searchPath = toWorkspaceRelativePath(extractQuotedField(line, 'path'), workspaceRoot);
    const url = extractQuotedField(line, 'url');
    const label = humanizeToolName(toolName);
    if (/^(WebSearch|WebFetch|Fetch)$/i.test(toolName)) {
        if (url)
            return { title: `${label} ${truncate(url, 60)}` };
        if (pattern)
            return { title: `${label} ${truncate(pattern, 60)}` };
        return { title: label };
    }
    if (/^Glob$/i.test(toolName)) {
        const parts = [];
        if (pattern)
            parts.push(truncate(pattern, 50));
        else if (glob)
            parts.push(truncate(glob, 50));
        const title = parts.length ? `${label} ${parts.join(' ')}` : label;
        const descParts = [];
        if (pattern && glob)
            descParts.push(`glob: ${glob}`);
        if (searchPath)
            descParts.push(`in ${searchPath}`);
        return { title, description: descParts.length ? descParts.join(', ') : undefined };
    }
    const parts = [];
    if (pattern)
        parts.push(truncate(pattern, 40));
    const title = parts.length ? `${label} ${parts.join(' ')}` : label;
    const descParts = [];
    if (glob)
        descParts.push(`glob: ${glob}`);
    if (searchPath)
        descParts.push(`in ${searchPath}`);
    return { title, description: descParts.length ? descParts.join(', ') : undefined };
}
function extractSubagentBlocks(lines, sessionId, toolDetails) {
    const matchCounts = new Map();
    return lines
        .map((line, index) => {
        const match = line.match(/^Tool:\s*Task\b\s*(.*)$/i);
        if (!match)
            return null;
        const name = line.match(/\bdescription=(["'])(.*?)\1/i)?.[2] || `Subagent ${index + 1}`;
        const prompt = line.match(/\bprompt=(["'])(.*?)\1/i)?.[2];
        const detailId = findToolDetailId(line, toolDetails, matchCounts);
        const detail = detailId ? toolDetails?.get(detailId) : undefined;
        const output = stringifySubagentOutput(detail?.output);
        return {
            id: `subagent-${sessionId}-${index}`,
            type: 'subagent',
            name,
            instructions: prompt,
            output,
        };
    })
        .filter((part) => Boolean(part));
}
function stringifySubagentOutput(output) {
    if (output === undefined || output === null)
        return undefined;
    if (typeof output === 'string')
        return output.trim() || undefined;
    if (Array.isArray(output)) {
        const text = output.flatMap((item) => {
            if (typeof item === 'string')
                return [item];
            if (!item || typeof item !== 'object')
                return [];
            const record = item;
            return typeof record.text === 'string' ? [record.text] : [];
        }).join('\n').trim();
        return text || undefined;
    }
    if (typeof output === 'object') {
        const record = output;
        if (typeof record.result === 'string' && record.result.trim())
            return record.result.trim();
        if (typeof record.summary === 'string' && record.summary.trim())
            return record.summary.trim();
        if (Array.isArray(record.content))
            return stringifySubagentOutput(record.content);
    }
    return undefined;
}
function extractUsage(lines) {
    const usage = {};
    for (const line of lines) {
        const lower = line.toLowerCase();
        if (!lower.includes('token'))
            continue;
        const input = line.match(/\bin(?:put)?[=:\s]+([\d,]+)/i)?.[1];
        const output = line.match(/\bout(?:put)?[=:\s]+([\d,]+)/i)?.[1];
        const total = line.match(/\btokens?[=:\s]+([\d,]+)/i)?.[1];
        if (input)
            usage.inputTokens = Number(input.replace(/,/g, ''));
        if (output)
            usage.outputTokens = Number(output.replace(/,/g, ''));
        if (total)
            usage.totalTokens = Number(total.replace(/,/g, ''));
    }
    return usage;
}
function findToolDetailId(line, toolDetails, matchCounts) {
    if (!toolDetails)
        return undefined;
    const targetMatchIndex = matchCounts?.get(line) ?? 0;
    let matchIndex = 0;
    for (const [id, detail] of toolDetails) {
        if (detail.raw !== line)
            continue;
        if (matchIndex === targetMatchIndex) {
            matchCounts?.set(line, targetMatchIndex + 1);
            return id;
        }
        matchIndex += 1;
    }
    return undefined;
}
function isSubagentToolResult(result) {
    if (!result || typeof result !== 'object' || Array.isArray(result))
        return false;
    const record = result;
    return (typeof record.agentId === 'string'
        || typeof record.agentType === 'string'
        || (record.status === 'completed' && Array.isArray(record.content)));
}
function extractResultFilePath(result, workspaceRoot) {
    if (!result || typeof result !== 'object')
        return undefined;
    const record = result;
    const file = record.file;
    if (file && typeof file === 'object') {
        const filePath = file.filePath;
        if (typeof filePath === 'string')
            return toWorkspaceRelativePath(filePath, workspaceRoot);
    }
    const filePath = record.filePath;
    if (typeof filePath === 'string')
        return toWorkspaceRelativePath(filePath, workspaceRoot);
    return undefined;
}
function extractInputFilePath(input, workspaceRoot) {
    if (!input || typeof input !== 'object')
        return undefined;
    const record = input;
    const filePath = record.file_path ?? record.path;
    return typeof filePath === 'string' ? toWorkspaceRelativePath(filePath, workspaceRoot) : undefined;
}
function isSameMessageText(left, right) {
    return normalizeMessageText(left) === normalizeMessageText(right);
}
function normalizeMessageText(text) {
    return text.trim().replace(/\s+/g, ' ');
}
function summarizeMessageTitle(text) {
    const normalized = text.trim().replace(/\s+/g, ' ');
    if (!normalized)
        return 'AI message';
    return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
}
function isToolLikeLine(line) {
    return /^(Using|Tool:|Read|Write|Edit|MultiEdit|Bash|Search|Grep|Glob|Todo|Task|Web|Fetch|Claude Code initialized|Codex initialized|.+ running \(\d+s\))/i.test(line.trim());
}
function isIgnorableToolProgressLine(line) {
    const raw = line.trim();
    const trimmed = stripSubagentProgressPrefix(raw);
    const isSubagentProgress = trimmed !== raw;
    return /^Claude$/i.test(trimmed)
        || /^(Reading|Searching)(\.{1,3}|…)?$/i.test(trimmed)
        || (isSubagentProgress && /^(Reading|Searching)\s+\S.+$/i.test(trimmed))
        || /^(Read|Search|Grep|Glob|SemanticSearch|WebSearch)\s+running\s+\(\d+s\)$/i.test(trimmed);
}
function stripRuntimeNoticePrefix(line) {
    let next = line.trim();
    while (next.startsWith('[')) {
        const closeIndex = next.indexOf(']');
        if (closeIndex < 0)
            break;
        const label = next.slice(1, closeIndex);
        if (!isStrippableRuntimeNoticeLabel(label))
            break;
        next = next.slice(closeIndex + 1).trimStart();
    }
    return next;
}
function stripRuntimeLogPrefix(line) {
    return line.replace(/^\[[a-z0-9_-]+\]\s+(?:stdout|stderr)\s*\|\s*/i, '');
}
function isStrippableRuntimeNoticeLabel(label) {
    return /^Tool loop warning:/i.test(label);
}
function isAgentSpacesPromptEchoStart(line) {
    return /^-?\s*Agent Spaces channel tools configured for this channel:/i.test(line);
}
function isIgnorablePromptEchoLine(line) {
    return /^-?\s*Code directories \(boundDirs\):/i.test(line)
        || /^-?\s*For Bash commands that create or modify files under the current working\b/i.test(line)
        || /^(directory,|paths\.)$/i.test(line)
        || /^When asked what MCP servers, skills, runtime tools, or Agent Spaces channel tools you have,/i.test(line)
        || /^When asked what MCP servers, skills, runtime tools, or Agent Spaces channel\b/i.test(line)
        || /^tools you have, answer from this configuration only\./i.test(line)
        || /^Important distinction: MCP servers configured for this agent are only the names in /i.test(line)
        || /^Important distinction: MCP servers configured for this agent are only the names\b/i.test(line)
        || /^in "MCP servers configured for this agent"\./i.test(line)
        || /^are$/i.test(line)
        || /^built-in runtime tools and must not be listed as agent-configured MCP servers\./i.test(line)
        || /^Do not infer availability from provider-side function names,/i.test(line)
        || /^Do not infer availability from provider-side function names, hidden runtime\b/i.test(line)
        || /^internals, previous sessions, or filesystem settings\./i.test(line)
        || /^-\s+(Current workspace id|MCP servers configured for this agent|Skills configured for this agent|Runtime tools available through Hermes):/i.test(line)
        || /^skills$/i.test(line)
        || /^User message:/i.test(line);
}
function stripSubagentProgressPrefix(line) {
    return line.replace(/^\[[^\]]+\]\s+subagent progress\s+\|\s*/i, '');
}
function isFinalAnswerLine(line) {
    return !isToolLikeLine(line) && !/^(\[.*\]|Agent runtime configuration:|Conversation history:)/.test(line.trim());
}
function isSubagentToolLine(line) {
    return /^Tool:\s*Task\b/i.test(line.trim());
}
function extractToolName(line) {
    return line.match(/^Tool:\s*([A-Za-z][\w-]*)\b/)?.[1]
        ?? line.match(/^([A-Za-z][\w-]*)\s+running\s+\(\d+s\)/)?.[1]
        ?? line.match(/^([A-Za-z][\w-]*):?\s+/)?.[1];
}
function humanizeToolName(toolName) {
    const labels = {
        Read: 'Read',
        Write: 'Write',
        Edit: 'Edit',
        MultiEdit: 'Edit',
        Bash: 'Run',
        TodoWrite: 'Update todos',
        Grep: 'Search',
        Glob: 'Find files',
        Search: 'Search',
        SemanticSearch: 'Semantic search',
        WebSearch: 'Web search',
        WebFetch: 'Fetch',
        Fetch: 'Fetch',
        Task: 'Run subagent',
    };
    return labels[toolName] ?? toolName.replace(/([a-z])([A-Z])/g, '$1 $2');
}
function extractQuotedField(line, key) {
    const quoted = line.match(new RegExp(`\\b${key}=(["'])(.*?)\\1`))?.[2];
    if (quoted)
        return quoted;
    const json = line.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`))?.[1];
    return json;
}
function extractSkillParams(line, toolName) {
    if (!/^Skill$/i.test(toolName))
        return null;
    const skill = extractQuotedField(line, 'skill');
    if (!skill)
        return null;
    const args = extractQuotedField(line, 'args');
    return {
        title: `Skill ${skill}`,
        description: args ? truncate(args, 120) : undefined,
    };
}
function extractCommand(line, toolName) {
    if (!toolName || !/^(Bash|Shell|Command)$/i.test(toolName))
        return undefined;
    const command = line.replace(/^Tool:\s*/i, '').replace(new RegExp(`^${toolName}:?\\s*`, 'i'), '').trim();
    return command || undefined;
}
function extractTodoCount(line) {
    const matches = line.match(/"content"\s*:/g);
    return matches?.length;
}
function toWorkspaceRelativePath(path, workspaceRoot) {
    if (!path)
        return undefined;
    if (!workspaceRoot || !path.startsWith(workspaceRoot))
        return path;
    return path.slice(workspaceRoot.length).replace(/^[/\\]/, '');
}
function truncate(str, max) {
    return str.length > max ? `${str.slice(0, max - 3)}...` : str;
}
//# sourceMappingURL=message-parts.js.map