* Parses Copilot CLI log content and converts it to markdown format * @param {string} logContent - The raw log content as a string * @returns {{markdown: string, logEntries: Array, mcpFailures?: string[], maxTurnsHit?: boolean}} Formatted result with markdown and metadata
(logContent)
| 91 | * @returns {{markdown: string, logEntries: Array, mcpFailures?: string[], maxTurnsHit?: boolean}} Formatted result with markdown and metadata |
| 92 | */ |
| 93 | function parseCopilotLog(logContent) { |
| 94 | let logEntries; |
| 95 | |
| 96 | // First, try to parse as JSON array (structured format) |
| 97 | try { |
| 98 | logEntries = JSON.parse(logContent); |
| 99 | if (!Array.isArray(logEntries)) { |
| 100 | throw new Error(`${ERR_PARSE}: Not a JSON array`); |
| 101 | } |
| 102 | } catch (jsonArrayError) { |
| 103 | // If that fails, try to parse as debug logs format |
| 104 | const debugLogEntries = parseDebugLogFormat(logContent); |
| 105 | if (debugLogEntries && debugLogEntries.length > 0) { |
| 106 | logEntries = debugLogEntries; |
| 107 | } else { |
| 108 | // Try JSONL format using shared function |
| 109 | logEntries = parseLogEntries(logContent); |
| 110 | |
| 111 | // If still nothing, try the pretty-print stdout format (✗/● markers) |
| 112 | if (!logEntries || logEntries.length === 0) { |
| 113 | const prettyPrintEntries = parsePrettyPrintFormat(logContent); |
| 114 | if (prettyPrintEntries && prettyPrintEntries.length > 0) { |
| 115 | logEntries = prettyPrintEntries; |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | if (!logEntries || logEntries.length === 0) { |
| 122 | return { markdown: "## Agent Log Summary\n\nLog format not recognized as Copilot JSON array or JSONL.\n", logEntries: [] }; |
| 123 | } |
| 124 | |
| 125 | const isEventFormat = isCopilotSdkEventsFormat(logEntries); |
| 126 | let canonicalLogEntries = isEventFormat ? logEntries : convertLegacyLogEntriesToCopilotEvents(logEntries, { sourceEngine: "copilot" }); |
| 127 | const legacyRenderEntries = isEventFormat ? convertCopilotEventsToLegacyLogEntries(canonicalLogEntries) : logEntries; |
| 128 | if (isEventFormat && !canonicalLogEntries.some(entry => entry?.type === "session.result")) { |
| 129 | const legacyResult = legacyRenderEntries.find(entry => entry?.type === "result"); |
| 130 | canonicalLogEntries.push({ |
| 131 | type: "session.result", |
| 132 | data: { |
| 133 | numTurns: legacyResult?.num_turns, |
| 134 | durationMs: legacyResult?.duration_ms, |
| 135 | totalCostUsd: legacyResult?.total_cost_usd, |
| 136 | usage: legacyResult?.usage, |
| 137 | errors: legacyResult?.errors, |
| 138 | permissionDenials: legacyResult?.permission_denials, |
| 139 | }, |
| 140 | }); |
| 141 | } |
| 142 | |
| 143 | // Generate conversation markdown using shared function |
| 144 | const conversationResult = generateConversationMarkdown(canonicalLogEntries, { |
| 145 | formatToolCallback: (toolUse, toolResult) => formatToolUse(toolUse, toolResult, { includeDetailedParameters: true }), |
| 146 | formatInitCallback: initEntry => |
| 147 | formatInitializationSummary(initEntry, { |
| 148 | includeSlashCommands: false, |
| 149 | modelInfoCallback: entry => { |
| 150 | // Display premium model information if available (Copilot-specific) |
no test coverage detected