@mariozechner/pi-coding-agent 0.27.4 → 0.27.6

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/dist/core/agent-session.d.ts +1 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +137 -40
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/compaction.d.ts +10 -0
  7. package/dist/core/compaction.d.ts.map +1 -1
  8. package/dist/core/compaction.js +35 -0
  9. package/dist/core/compaction.js.map +1 -1
  10. package/dist/core/export-html.d.ts +11 -2
  11. package/dist/core/export-html.d.ts.map +1 -1
  12. package/dist/core/export-html.js +551 -94
  13. package/dist/core/export-html.js.map +1 -1
  14. package/dist/core/hooks/runner.d.ts.map +1 -1
  15. package/dist/core/hooks/runner.js +11 -3
  16. package/dist/core/hooks/runner.js.map +1 -1
  17. package/dist/core/hooks/types.d.ts +28 -2
  18. package/dist/core/hooks/types.d.ts.map +1 -1
  19. package/dist/core/hooks/types.js.map +1 -1
  20. package/dist/core/model-config.d.ts +7 -2
  21. package/dist/core/model-config.d.ts.map +1 -1
  22. package/dist/core/model-config.js +7 -2
  23. package/dist/core/model-config.js.map +1 -1
  24. package/dist/core/sdk.d.ts.map +1 -1
  25. package/dist/core/sdk.js +1 -1
  26. package/dist/core/sdk.js.map +1 -1
  27. package/dist/core/session-manager.d.ts +24 -11
  28. package/dist/core/session-manager.d.ts.map +1 -1
  29. package/dist/core/session-manager.js +25 -21
  30. package/dist/core/session-manager.js.map +1 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  36. package/dist/modes/interactive/interactive-mode.js +5 -5
  37. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  38. package/dist/modes/print-mode.d.ts.map +1 -1
  39. package/dist/modes/print-mode.js +1 -1
  40. package/dist/modes/print-mode.js.map +1 -1
  41. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  42. package/dist/modes/rpc/rpc-mode.js +1 -1
  43. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  44. package/docs/hooks.md +126 -12
  45. package/examples/hooks/README.md +3 -0
  46. package/examples/hooks/custom-compaction.ts +115 -0
  47. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"export-html.js","sourceRoot":"","sources":["../../src/core/export-html.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState } from \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, Message, ToolResultMessage, UserMessage } from \"@mariozechner/pi-ai\";\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { basename } from \"path\";\nimport { APP_NAME, VERSION } from \"../config.js\";\nimport { type BashExecutionMessage, isBashExecutionMessage } from \"./messages.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface MessageEvent {\n\ttype: \"message\";\n\tmessage: Message;\n\ttimestamp?: number;\n}\n\ninterface ModelChangeEvent {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n\ttimestamp?: number;\n}\n\ninterface CompactionEvent {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\ttokensBefore: number;\n}\n\ntype SessionEvent = MessageEvent | ModelChangeEvent | CompactionEvent;\n\ninterface ParsedSessionData {\n\tsessionId: string;\n\ttimestamp: string;\n\tsystemPrompt?: string;\n\tmodelsUsed: Set<string>;\n\tmessages: Message[];\n\ttoolResultsMap: Map<string, ToolResultMessage>;\n\tsessionEvents: SessionEvent[];\n\ttokenStats: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcostStats: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\ttools?: { name: string; description: string }[];\n\tcontextWindow?: number;\n\tisStreamingFormat?: boolean;\n}\n\n// ============================================================================\n// Color scheme (matching TUI)\n// ============================================================================\n\nconst COLORS = {\n\tuserMessageBg: \"rgb(52, 53, 65)\",\n\ttoolPendingBg: \"rgb(40, 40, 50)\",\n\ttoolSuccessBg: \"rgb(40, 50, 40)\",\n\ttoolErrorBg: \"rgb(60, 40, 40)\",\n\tuserBashBg: \"rgb(50, 48, 35)\", // Faint yellow/brown for user-executed bash\n\tuserBashErrorBg: \"rgb(60, 45, 35)\", // Slightly more orange for errors\n\tbodyBg: \"rgb(24, 24, 30)\",\n\tcontainerBg: \"rgb(30, 30, 36)\",\n\ttext: \"rgb(229, 229, 231)\",\n\ttextDim: \"rgb(161, 161, 170)\",\n\tcyan: \"rgb(103, 232, 249)\",\n\tgreen: \"rgb(34, 197, 94)\",\n\tred: \"rgb(239, 68, 68)\",\n\tyellow: \"rgb(234, 179, 8)\",\n};\n\n// ============================================================================\n// Utility functions\n// ============================================================================\n\nfunction escapeHtml(text: string): string {\n\treturn text\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#039;\");\n}\n\nfunction shortenPath(path: string): string {\n\tconst home = homedir();\n\treturn path.startsWith(home) ? `~${path.slice(home.length)}` : path;\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction formatTimestamp(timestamp: number | string | undefined): string {\n\tif (!timestamp) return \"\";\n\tconst date = new Date(typeof timestamp === \"string\" ? timestamp : timestamp);\n\treturn date.toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\", second: \"2-digit\" });\n}\n\nfunction formatExpandableOutput(lines: string[], maxLines: number): string {\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\n\tif (remaining > 0) {\n\t\tlet out = '<div class=\"tool-output expandable\" onclick=\"this.classList.toggle(\\'expanded\\')\">';\n\t\tout += '<div class=\"output-preview\">';\n\t\tfor (const line of displayLines) {\n\t\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t\t}\n\t\tout += `<div class=\"expand-hint\">... (${remaining} more lines) - click to expand</div>`;\n\t\tout += \"</div>\";\n\t\tout += '<div class=\"output-full\">';\n\t\tfor (const line of lines) {\n\t\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t\t}\n\t\tout += \"</div></div>\";\n\t\treturn out;\n\t}\n\n\tlet out = '<div class=\"tool-output\">';\n\tfor (const line of displayLines) {\n\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t}\n\tout += \"</div>\";\n\treturn out;\n}\n\n// ============================================================================\n// Parsing functions\n// ============================================================================\n\nfunction parseSessionManagerFormat(lines: string[]): ParsedSessionData {\n\tconst data: ParsedSessionData = {\n\t\tsessionId: \"unknown\",\n\t\ttimestamp: new Date().toISOString(),\n\t\tmodelsUsed: new Set(),\n\t\tmessages: [],\n\t\ttoolResultsMap: new Map(),\n\t\tsessionEvents: [],\n\t\ttokenStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcostStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t};\n\n\tfor (const line of lines) {\n\t\tlet entry: { type: string; [key: string]: unknown };\n\t\ttry {\n\t\t\tentry = JSON.parse(line) as { type: string; [key: string]: unknown };\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch (entry.type) {\n\t\t\tcase \"session\":\n\t\t\t\tdata.sessionId = (entry.id as string) || \"unknown\";\n\t\t\t\tdata.timestamp = (entry.timestamp as string) || data.timestamp;\n\t\t\t\tdata.systemPrompt = entry.systemPrompt as string | undefined;\n\t\t\t\tif (entry.modelId) {\n\t\t\t\t\tconst modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : (entry.modelId as string);\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"message\": {\n\t\t\t\tconst message = entry.message as Message;\n\t\t\t\tdata.messages.push(message);\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\tmessage,\n\t\t\t\t\ttimestamp: entry.timestamp as number | undefined,\n\t\t\t\t});\n\n\t\t\t\tif (message.role === \"toolResult\") {\n\t\t\t\t\tconst toolResult = message as ToolResultMessage;\n\t\t\t\t\tdata.toolResultsMap.set(toolResult.toolCallId, toolResult);\n\t\t\t\t} else if (message.role === \"assistant\") {\n\t\t\t\t\tconst assistantMsg = message as AssistantMessage;\n\t\t\t\t\tif (assistantMsg.usage) {\n\t\t\t\t\t\tdata.tokenStats.input += assistantMsg.usage.input || 0;\n\t\t\t\t\t\tdata.tokenStats.output += assistantMsg.usage.output || 0;\n\t\t\t\t\t\tdata.tokenStats.cacheRead += assistantMsg.usage.cacheRead || 0;\n\t\t\t\t\t\tdata.tokenStats.cacheWrite += assistantMsg.usage.cacheWrite || 0;\n\t\t\t\t\t\tif (assistantMsg.usage.cost) {\n\t\t\t\t\t\t\tdata.costStats.input += assistantMsg.usage.cost.input || 0;\n\t\t\t\t\t\t\tdata.costStats.output += assistantMsg.usage.cost.output || 0;\n\t\t\t\t\t\t\tdata.costStats.cacheRead += assistantMsg.usage.cost.cacheRead || 0;\n\t\t\t\t\t\t\tdata.costStats.cacheWrite += assistantMsg.usage.cost.cacheWrite || 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"model_change\":\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"model_change\",\n\t\t\t\t\tprovider: entry.provider as string,\n\t\t\t\t\tmodelId: entry.modelId as string,\n\t\t\t\t\ttimestamp: entry.timestamp as number | undefined,\n\t\t\t\t});\n\t\t\t\tif (entry.modelId) {\n\t\t\t\t\tconst modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : (entry.modelId as string);\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"compaction\":\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"compaction\",\n\t\t\t\t\ttimestamp: entry.timestamp as string,\n\t\t\t\t\tsummary: entry.summary as string,\n\t\t\t\t\ttokensBefore: entry.tokensBefore as number,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn data;\n}\n\nfunction parseStreamingEventFormat(lines: string[]): ParsedSessionData {\n\tconst data: ParsedSessionData = {\n\t\tsessionId: \"unknown\",\n\t\ttimestamp: new Date().toISOString(),\n\t\tmodelsUsed: new Set(),\n\t\tmessages: [],\n\t\ttoolResultsMap: new Map(),\n\t\tsessionEvents: [],\n\t\ttokenStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcostStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tisStreamingFormat: true,\n\t};\n\n\tlet timestampSet = false;\n\n\tfor (const line of lines) {\n\t\tlet entry: { type: string; message?: Message };\n\t\ttry {\n\t\t\tentry = JSON.parse(line) as { type: string; message?: Message };\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type === \"message_end\" && entry.message) {\n\t\t\tconst msg = entry.message;\n\t\t\tdata.messages.push(msg);\n\t\t\tdata.sessionEvents.push({\n\t\t\t\ttype: \"message\",\n\t\t\t\tmessage: msg,\n\t\t\t\ttimestamp: (msg as { timestamp?: number }).timestamp,\n\t\t\t});\n\n\t\t\tif (msg.role === \"toolResult\") {\n\t\t\t\tconst toolResult = msg as ToolResultMessage;\n\t\t\t\tdata.toolResultsMap.set(toolResult.toolCallId, toolResult);\n\t\t\t} else if (msg.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\t\tif (assistantMsg.model) {\n\t\t\t\t\tconst modelInfo = assistantMsg.provider\n\t\t\t\t\t\t? `${assistantMsg.provider}/${assistantMsg.model}`\n\t\t\t\t\t\t: assistantMsg.model;\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.usage) {\n\t\t\t\t\tdata.tokenStats.input += assistantMsg.usage.input || 0;\n\t\t\t\t\tdata.tokenStats.output += assistantMsg.usage.output || 0;\n\t\t\t\t\tdata.tokenStats.cacheRead += assistantMsg.usage.cacheRead || 0;\n\t\t\t\t\tdata.tokenStats.cacheWrite += assistantMsg.usage.cacheWrite || 0;\n\t\t\t\t\tif (assistantMsg.usage.cost) {\n\t\t\t\t\t\tdata.costStats.input += assistantMsg.usage.cost.input || 0;\n\t\t\t\t\t\tdata.costStats.output += assistantMsg.usage.cost.output || 0;\n\t\t\t\t\t\tdata.costStats.cacheRead += assistantMsg.usage.cost.cacheRead || 0;\n\t\t\t\t\t\tdata.costStats.cacheWrite += assistantMsg.usage.cost.cacheWrite || 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!timestampSet && (msg as { timestamp?: number }).timestamp) {\n\t\t\t\tdata.timestamp = new Date((msg as { timestamp: number }).timestamp).toISOString();\n\t\t\t\ttimestampSet = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tdata.sessionId = `stream-${data.timestamp.replace(/[:.]/g, \"-\")}`;\n\treturn data;\n}\n\nfunction detectFormat(lines: string[]): \"session-manager\" | \"streaming-events\" | \"unknown\" {\n\tfor (const line of lines) {\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line) as { type: string };\n\t\t\tif (entry.type === \"session\") return \"session-manager\";\n\t\t\tif (entry.type === \"agent_start\" || entry.type === \"message_start\" || entry.type === \"turn_start\") {\n\t\t\t\treturn \"streaming-events\";\n\t\t\t}\n\t\t} catch {}\n\t}\n\treturn \"unknown\";\n}\n\nfunction parseSessionFile(content: string): ParsedSessionData {\n\tconst lines = content\n\t\t.trim()\n\t\t.split(\"\\n\")\n\t\t.filter((l) => l.trim());\n\n\tif (lines.length === 0) {\n\t\tthrow new Error(\"Empty session file\");\n\t}\n\n\tconst format = detectFormat(lines);\n\tif (format === \"unknown\") {\n\t\tthrow new Error(\"Unknown session file format\");\n\t}\n\n\treturn format === \"session-manager\" ? parseSessionManagerFormat(lines) : parseStreamingEventFormat(lines);\n}\n\n// ============================================================================\n// HTML formatting functions\n// ============================================================================\n\nfunction formatToolExecution(\n\ttoolName: string,\n\targs: Record<string, unknown>,\n\tresult?: ToolResultMessage,\n): { html: string; bgColor: string } {\n\tlet html = \"\";\n\tconst isError = result?.isError || false;\n\tconst bgColor = result ? (isError ? COLORS.toolErrorBg : COLORS.toolSuccessBg) : COLORS.toolPendingBg;\n\n\tconst getTextOutput = (): string => {\n\t\tif (!result) return \"\";\n\t\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\t\treturn textBlocks.map((c) => (c as { type: \"text\"; text: string }).text).join(\"\\n\");\n\t};\n\n\tswitch (toolName) {\n\t\tcase \"bash\": {\n\t\t\tconst command = (args?.command as string) || \"\";\n\t\t\thtml = `<div class=\"tool-command\">$ ${escapeHtml(command || \"...\")}</div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += formatExpandableOutput(output.split(\"\\n\"), 5);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"read\": {\n\t\t\tconst path = shortenPath((args?.file_path as string) || (args?.path as string) || \"\");\n\t\t\tconst offset = args?.offset as number | undefined;\n\t\t\tconst limit = args?.limit as number | undefined;\n\n\t\t\t// Build path display with offset/limit suffix (in yellow color if offset/limit used)\n\t\t\tlet pathHtml = escapeHtml(path || \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathHtml += `<span class=\"line-numbers\" style=\"color: ${COLORS.yellow}\">:${startLine}${endLine ? `-${endLine}` : \"\"}</span>`;\n\t\t\t}\n\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">read</span> <span class=\"tool-path\">${pathHtml}</span></div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += formatExpandableOutput(output.split(\"\\n\"), 10);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"write\": {\n\t\t\tconst path = shortenPath((args?.file_path as string) || (args?.path as string) || \"\");\n\t\t\tconst fileContent = (args?.content as string) || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">write</span> <span class=\"tool-path\">${escapeHtml(path || \"...\")}</span>`;\n\t\t\tif (lines.length > 10) {\n\t\t\t\thtml += ` <span class=\"line-count\">(${lines.length} lines)</span>`;\n\t\t\t}\n\t\t\thtml += \"</div>\";\n\n\t\t\tif (fileContent) {\n\t\t\t\thtml += formatExpandableOutput(lines, 10);\n\t\t\t}\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"edit\": {\n\t\t\tconst path = shortenPath((args?.file_path as string) || (args?.path as string) || \"\");\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">edit</span> <span class=\"tool-path\">${escapeHtml(path || \"...\")}</span></div>`;\n\n\t\t\tif (result?.details?.diff) {\n\t\t\t\tconst diffLines = result.details.diff.split(\"\\n\");\n\t\t\t\thtml += '<div class=\"tool-diff\">';\n\t\t\t\tfor (const line of diffLines) {\n\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-new\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-old\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-context\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thtml += \"</div>\";\n\t\t\t}\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault: {\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">${escapeHtml(toolName)}</span></div>`;\n\t\t\thtml += `<div class=\"tool-output\"><pre>${escapeHtml(JSON.stringify(args, null, 2))}</pre></div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { html, bgColor };\n}\n\nfunction formatMessage(message: Message, toolResultsMap: Map<string, ToolResultMessage>): string {\n\tlet html = \"\";\n\tconst timestamp = (message as { timestamp?: number }).timestamp;\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${formatTimestamp(timestamp)}</div>` : \"\";\n\n\t// Handle bash execution messages (user-executed via ! command)\n\tif (isBashExecutionMessage(message)) {\n\t\tconst bashMsg = message as unknown as BashExecutionMessage;\n\t\tconst isError = bashMsg.cancelled || (bashMsg.exitCode !== 0 && bashMsg.exitCode !== null);\n\t\tconst bgColor = isError ? COLORS.userBashErrorBg : COLORS.userBashBg;\n\n\t\thtml += `<div class=\"tool-execution\" style=\"background-color: ${bgColor}\">`;\n\t\thtml += timestampHtml;\n\t\thtml += `<div class=\"tool-command\">$ ${escapeHtml(bashMsg.command)}</div>`;\n\n\t\tif (bashMsg.output) {\n\t\t\tconst lines = bashMsg.output.split(\"\\n\");\n\t\t\thtml += formatExpandableOutput(lines, 10);\n\t\t}\n\n\t\tif (bashMsg.cancelled) {\n\t\t\thtml += `<div class=\"bash-status\" style=\"color: ${COLORS.yellow}\">(cancelled)</div>`;\n\t\t} else if (bashMsg.exitCode !== 0 && bashMsg.exitCode !== null) {\n\t\t\thtml += `<div class=\"bash-status\" style=\"color: ${COLORS.red}\">(exit ${bashMsg.exitCode})</div>`;\n\t\t}\n\n\t\tif (bashMsg.truncated && bashMsg.fullOutputPath) {\n\t\t\thtml += `<div class=\"bash-truncation\" style=\"color: ${COLORS.yellow}\">Output truncated. Full output: ${escapeHtml(bashMsg.fullOutputPath)}</div>`;\n\t\t}\n\n\t\thtml += `</div>`;\n\t\treturn html;\n\t}\n\n\tif (message.role === \"user\") {\n\t\tconst userMsg = message as UserMessage;\n\t\tlet textContent = \"\";\n\n\t\tif (typeof userMsg.content === \"string\") {\n\t\t\ttextContent = userMsg.content;\n\t\t} else {\n\t\t\tconst textBlocks = userMsg.content.filter((c) => c.type === \"text\");\n\t\t\ttextContent = textBlocks.map((c) => (c as { type: \"text\"; text: string }).text).join(\"\");\n\t\t}\n\n\t\tif (textContent.trim()) {\n\t\t\thtml += `<div class=\"user-message\">${timestampHtml}${escapeHtml(textContent).replace(/\\n/g, \"<br>\")}</div>`;\n\t\t}\n\t} else if (message.role === \"assistant\") {\n\t\tconst assistantMsg = message as AssistantMessage;\n\t\thtml += timestampHtml ? `<div class=\"assistant-message\">${timestampHtml}` : \"\";\n\n\t\tfor (const content of assistantMsg.content) {\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\thtml += `<div class=\"assistant-text\">${escapeHtml(content.text.trim()).replace(/\\n/g, \"<br>\")}</div>`;\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\thtml += `<div class=\"thinking-text\">${escapeHtml(content.thinking.trim()).replace(/\\n/g, \"<br>\")}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tfor (const content of assistantMsg.content) {\n\t\t\tif (content.type === \"toolCall\") {\n\t\t\t\tconst toolResult = toolResultsMap.get(content.id);\n\t\t\t\tconst { html: toolHtml, bgColor } = formatToolExecution(\n\t\t\t\t\tcontent.name,\n\t\t\t\t\tcontent.arguments as Record<string, unknown>,\n\t\t\t\t\ttoolResult,\n\t\t\t\t);\n\t\t\t\thtml += `<div class=\"tool-execution\" style=\"background-color: ${bgColor}\">${toolHtml}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tconst hasToolCalls = assistantMsg.content.some((c) => c.type === \"toolCall\");\n\t\tif (!hasToolCalls) {\n\t\t\tif (assistantMsg.stopReason === \"aborted\") {\n\t\t\t\thtml += '<div class=\"error-text\">Aborted</div>';\n\t\t\t} else if (assistantMsg.stopReason === \"error\") {\n\t\t\t\thtml += `<div class=\"error-text\">Error: ${escapeHtml(assistantMsg.errorMessage || \"Unknown error\")}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tif (timestampHtml) {\n\t\t\thtml += \"</div>\";\n\t\t}\n\t}\n\n\treturn html;\n}\n\nfunction formatModelChange(event: ModelChangeEvent): string {\n\tconst timestamp = formatTimestamp(event.timestamp);\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${timestamp}</div>` : \"\";\n\tconst modelInfo = `${event.provider}/${event.modelId}`;\n\treturn `<div class=\"model-change\">${timestampHtml}<div class=\"model-change-text\">Switched to model: <span class=\"model-name\">${escapeHtml(modelInfo)}</span></div></div>`;\n}\n\nfunction formatCompaction(event: CompactionEvent): string {\n\tconst timestamp = formatTimestamp(event.timestamp);\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${timestamp}</div>` : \"\";\n\tconst summaryHtml = escapeHtml(event.summary).replace(/\\n/g, \"<br>\");\n\n\treturn `<div class=\"compaction-container\">\n\t\t<div class=\"compaction-header\" onclick=\"this.parentElement.classList.toggle('expanded')\">\n\t\t\t${timestampHtml}\n\t\t\t<div class=\"compaction-header-row\">\n\t\t\t\t<span class=\"compaction-toggle\">▶</span>\n\t\t\t\t<span class=\"compaction-title\">Context compacted from ${event.tokensBefore.toLocaleString()} tokens</span>\n\t\t\t\t<span class=\"compaction-hint\">(click to expand summary)</span>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"compaction-content\">\n\t\t\t<div class=\"compaction-summary\">\n\t\t\t\t<div class=\"compaction-summary-header\">Summary sent to model</div>\n\t\t\t\t<div class=\"compaction-summary-content\">${summaryHtml}</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>`;\n}\n\n// ============================================================================\n// HTML generation\n// ============================================================================\n\nfunction generateHtml(data: ParsedSessionData, filename: string): string {\n\tconst userMessages = data.messages.filter((m) => m.role === \"user\").length;\n\tconst assistantMessages = data.messages.filter((m) => m.role === \"assistant\").length;\n\n\tlet toolCallsCount = 0;\n\tfor (const message of data.messages) {\n\t\tif (message.role === \"assistant\") {\n\t\t\ttoolCallsCount += (message as AssistantMessage).content.filter((c) => c.type === \"toolCall\").length;\n\t\t}\n\t}\n\n\tconst lastAssistantMessage = data.messages\n\t\t.slice()\n\t\t.reverse()\n\t\t.find((m) => m.role === \"assistant\" && (m as AssistantMessage).stopReason !== \"aborted\") as\n\t\t| AssistantMessage\n\t\t| undefined;\n\n\tconst contextTokens = lastAssistantMessage\n\t\t? lastAssistantMessage.usage.input +\n\t\t\tlastAssistantMessage.usage.output +\n\t\t\tlastAssistantMessage.usage.cacheRead +\n\t\t\tlastAssistantMessage.usage.cacheWrite\n\t\t: 0;\n\n\tconst lastModel = lastAssistantMessage?.model || \"unknown\";\n\tconst lastProvider = lastAssistantMessage?.provider || \"\";\n\tconst lastModelInfo = lastProvider ? `${lastProvider}/${lastModel}` : lastModel;\n\n\tconst contextWindow = data.contextWindow || 0;\n\tconst contextPercent = contextWindow > 0 ? ((contextTokens / contextWindow) * 100).toFixed(1) : null;\n\n\tlet messagesHtml = \"\";\n\tfor (const event of data.sessionEvents) {\n\t\tswitch (event.type) {\n\t\t\tcase \"message\":\n\t\t\t\tif (event.message.role !== \"toolResult\") {\n\t\t\t\t\tmessagesHtml += formatMessage(event.message, data.toolResultsMap);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"model_change\":\n\t\t\t\tmessagesHtml += formatModelChange(event);\n\t\t\t\tbreak;\n\t\t\tcase \"compaction\":\n\t\t\t\tmessagesHtml += formatCompaction(event);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst systemPromptHtml = data.systemPrompt\n\t\t? `<div class=\"system-prompt\">\n <div class=\"system-prompt-header\">System Prompt</div>\n <div class=\"system-prompt-content\">${escapeHtml(data.systemPrompt)}</div>\n </div>`\n\t\t: \"\";\n\n\tconst toolsHtml = data.tools\n\t\t? `<div class=\"tools-list\">\n <div class=\"tools-header\">Available Tools</div>\n <div class=\"tools-content\">\n ${data.tools.map((tool) => `<div class=\"tool-item\"><span class=\"tool-item-name\">${escapeHtml(tool.name)}</span> - ${escapeHtml(tool.description)}</div>`).join(\"\")}\n </div>\n </div>`\n\t\t: \"\";\n\n\tconst streamingNotice = data.isStreamingFormat\n\t\t? `<div class=\"streaming-notice\">\n <em>Note: This session was reconstructed from raw agent event logs, which do not contain system prompt or tool definitions.</em>\n </div>`\n\t\t: \"\";\n\n\tconst contextUsageText = contextPercent\n\t\t? `${contextTokens.toLocaleString()} / ${contextWindow.toLocaleString()} tokens (${contextPercent}%) - ${escapeHtml(lastModelInfo)}`\n\t\t: `${contextTokens.toLocaleString()} tokens (last turn) - ${escapeHtml(lastModelInfo)}`;\n\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Session Export - ${escapeHtml(filename)}</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n font-size: 12px;\n line-height: 1.6;\n color: ${COLORS.text};\n background: ${COLORS.bodyBg};\n padding: 24px;\n }\n .container { max-width: 700px; margin: 0 auto; }\n .header {\n margin-bottom: 24px;\n padding: 16px;\n background: ${COLORS.containerBg};\n border-radius: 4px;\n }\n .header h1 {\n font-size: 14px;\n font-weight: bold;\n margin-bottom: 12px;\n color: ${COLORS.cyan};\n }\n .header-info { display: flex; flex-direction: column; gap: 3px; font-size: 11px; }\n .info-item { color: ${COLORS.textDim}; display: flex; align-items: baseline; }\n .info-label { font-weight: 600; margin-right: 8px; min-width: 100px; }\n .info-value { color: ${COLORS.text}; flex: 1; }\n .info-value.cost { font-family: 'SF Mono', monospace; }\n .messages { display: flex; flex-direction: column; gap: 16px; }\n .message-timestamp { font-size: 10px; color: ${COLORS.textDim}; margin-bottom: 4px; opacity: 0.8; }\n .user-message {\n background: ${COLORS.userMessageBg};\n padding: 12px 16px;\n border-radius: 4px;\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n }\n .assistant-message { padding: 0; }\n .assistant-text, .thinking-text {\n padding: 12px 16px;\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n }\n .thinking-text { color: ${COLORS.textDim}; font-style: italic; }\n .model-change { padding: 8px 16px; background: rgb(40, 40, 50); border-radius: 4px; }\n .model-change-text { color: ${COLORS.textDim}; font-size: 11px; }\n .model-name { color: ${COLORS.cyan}; font-weight: bold; }\n .compaction-container { background: rgb(60, 55, 35); border-radius: 4px; overflow: hidden; }\n .compaction-header { padding: 12px 16px; cursor: pointer; }\n .compaction-header:hover { background: rgba(255, 255, 255, 0.05); }\n .compaction-header-row { display: flex; align-items: center; gap: 8px; }\n .compaction-toggle { color: ${COLORS.cyan}; font-size: 10px; transition: transform 0.2s; }\n .compaction-container.expanded .compaction-toggle { transform: rotate(90deg); }\n .compaction-title { color: ${COLORS.text}; font-weight: bold; }\n .compaction-hint { color: ${COLORS.textDim}; font-size: 11px; }\n .compaction-content { display: none; padding: 0 16px 16px 16px; }\n .compaction-container.expanded .compaction-content { display: block; }\n .compaction-summary { background: rgba(0, 0, 0, 0.2); border-radius: 4px; padding: 12px; }\n .compaction-summary-header { font-weight: bold; color: ${COLORS.cyan}; margin-bottom: 8px; font-size: 11px; }\n .compaction-summary-content { color: ${COLORS.text}; white-space: pre-wrap; word-wrap: break-word; }\n .tool-execution { padding: 12px 16px; border-radius: 4px; margin-top: 8px; }\n .tool-header, .tool-name { font-weight: bold; }\n .tool-path { color: ${COLORS.cyan}; word-break: break-all; }\n .line-count { color: ${COLORS.textDim}; }\n .tool-command { font-weight: bold; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; word-break: break-word; }\n .tool-output {\n margin-top: 12px;\n color: ${COLORS.textDim};\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n font-family: inherit;\n overflow-x: auto;\n }\n .tool-output > div { line-height: 1.4; }\n .tool-output pre { margin: 0; font-family: inherit; color: inherit; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .tool-output.expandable { cursor: pointer; }\n .tool-output.expandable:hover { opacity: 0.9; }\n .tool-output.expandable .output-full { display: none; }\n .tool-output.expandable.expanded .output-preview { display: none; }\n .tool-output.expandable.expanded .output-full { display: block; }\n .expand-hint { color: ${COLORS.cyan}; font-style: italic; margin-top: 4px; }\n .system-prompt, .tools-list { background: rgb(60, 55, 40); padding: 12px 16px; border-radius: 4px; margin-bottom: 16px; }\n .system-prompt-header, .tools-header { font-weight: bold; color: ${COLORS.yellow}; margin-bottom: 8px; }\n .system-prompt-content, .tools-content { color: ${COLORS.textDim}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; word-break: break-word; font-size: 11px; }\n .tool-item { margin: 4px 0; }\n .tool-item-name { font-weight: bold; color: ${COLORS.text}; }\n .tool-diff { margin-top: 12px; font-size: 11px; font-family: inherit; overflow-x: auto; max-width: 100%; }\n .diff-line-old { color: ${COLORS.red}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .diff-line-new { color: ${COLORS.green}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .diff-line-context { color: ${COLORS.textDim}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .error-text { color: ${COLORS.red}; padding: 12px 16px; }\n .footer { margin-top: 48px; padding: 20px; text-align: center; color: ${COLORS.textDim}; font-size: 10px; }\n .streaming-notice { background: rgb(50, 45, 35); padding: 12px 16px; border-radius: 4px; margin-bottom: 16px; color: ${COLORS.textDim}; font-size: 11px; }\n @media print { body { background: white; color: black; } .tool-execution { border: 1px solid #ddd; } }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>${APP_NAME} v${VERSION}</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">Session:</span><span class=\"info-value\">${escapeHtml(data.sessionId)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Date:</span><span class=\"info-value\">${new Date(data.timestamp).toLocaleString()}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Models:</span><span class=\"info-value\">${\n\t\t\t\t\t\t\tArray.from(data.modelsUsed)\n\t\t\t\t\t\t\t\t.map((m) => escapeHtml(m))\n\t\t\t\t\t\t\t\t.join(\", \") || \"unknown\"\n\t\t\t\t\t\t}</span></div>\n </div>\n </div>\n\n <div class=\"header\">\n <h1>Messages</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">User:</span><span class=\"info-value\">${userMessages}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Assistant:</span><span class=\"info-value\">${assistantMessages}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Tool Calls:</span><span class=\"info-value\">${toolCallsCount}</span></div>\n </div>\n </div>\n\n <div class=\"header\">\n <h1>Tokens & Cost</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">Input:</span><span class=\"info-value\">${data.tokenStats.input.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Output:</span><span class=\"info-value\">${data.tokenStats.output.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Read:</span><span class=\"info-value\">${data.tokenStats.cacheRead.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Write:</span><span class=\"info-value\">${data.tokenStats.cacheWrite.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Total:</span><span class=\"info-value\">${(data.tokenStats.input + data.tokenStats.output + data.tokenStats.cacheRead + data.tokenStats.cacheWrite).toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Input Cost:</span><span class=\"info-value cost\">$${data.costStats.input.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Output Cost:</span><span class=\"info-value cost\">$${data.costStats.output.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Read Cost:</span><span class=\"info-value cost\">$${data.costStats.cacheRead.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Write Cost:</span><span class=\"info-value cost\">$${data.costStats.cacheWrite.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Total Cost:</span><span class=\"info-value cost\"><strong>$${(data.costStats.input + data.costStats.output + data.costStats.cacheRead + data.costStats.cacheWrite).toFixed(4)}</strong></span></div>\n <div class=\"info-item\"><span class=\"info-label\">Context Usage:</span><span class=\"info-value\">${contextUsageText}</span></div>\n </div>\n </div>\n\n ${systemPromptHtml}\n ${toolsHtml}\n ${streamingNotice}\n\n <div class=\"messages\">\n ${messagesHtml}\n </div>\n\n <div class=\"footer\">\n Generated by ${APP_NAME} coding-agent on ${new Date().toLocaleString()}\n </div>\n </div>\n</body>\n</html>`;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Export session to HTML using SessionManager and AgentState.\n * Used by TUI's /export command.\n */\nexport function exportSessionToHtml(sessionManager: SessionManager, state: AgentState, outputPath?: string): string {\n\tconst sessionFile = sessionManager.getSessionFile();\n\tconst content = readFileSync(sessionFile, \"utf8\");\n\tconst data = parseSessionFile(content);\n\n\t// Enrich with data from AgentState (tools, context window)\n\tdata.tools = state.tools.map((t) => ({ name: t.name, description: t.description }));\n\tdata.contextWindow = state.model?.contextWindow;\n\tif (!data.systemPrompt) {\n\t\tdata.systemPrompt = state.systemPrompt;\n\t}\n\n\tif (!outputPath) {\n\t\tconst sessionBasename = basename(sessionFile, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${sessionBasename}.html`;\n\t}\n\n\tconst html = generateHtml(data, basename(sessionFile));\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n\n/**\n * Export session file to HTML (standalone, without AgentState).\n * Auto-detects format: session manager format or streaming event format.\n * Used by CLI for exporting arbitrary session files.\n */\nexport function exportFromFile(inputPath: string, outputPath?: string): string {\n\tif (!existsSync(inputPath)) {\n\t\tthrow new Error(`File not found: ${inputPath}`);\n\t}\n\n\tconst content = readFileSync(inputPath, \"utf8\");\n\tconst data = parseSessionFile(content);\n\n\tif (!outputPath) {\n\t\tconst inputBasename = basename(inputPath, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${inputBasename}.html`;\n\t}\n\n\tconst html = generateHtml(data, basename(inputPath));\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n"]}
1
+ {"version":3,"file":"export-html.js","sourceRoot":"","sources":["../../src/core/export-html.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentState } from \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, ImageContent, Message, ToolResultMessage, UserMessage } from \"@mariozechner/pi-ai\";\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport hljs from \"highlight.js\";\nimport { marked } from \"marked\";\nimport { homedir } from \"os\";\nimport * as path from \"path\";\nimport { basename } from \"path\";\nimport { APP_NAME, getCustomThemesDir, getThemesDir, VERSION } from \"../config.js\";\nimport { type BashExecutionMessage, isBashExecutionMessage } from \"./messages.js\";\nimport type { SessionManager } from \"./session-manager.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface MessageEvent {\n\ttype: \"message\";\n\tmessage: Message;\n\ttimestamp?: number;\n}\n\ninterface ModelChangeEvent {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n\ttimestamp?: number;\n}\n\ninterface CompactionEvent {\n\ttype: \"compaction\";\n\ttimestamp: string;\n\tsummary: string;\n\ttokensBefore: number;\n}\n\ntype SessionEvent = MessageEvent | ModelChangeEvent | CompactionEvent;\n\ninterface ParsedSessionData {\n\tsessionId: string;\n\ttimestamp: string;\n\tsystemPrompt?: string;\n\tmodelsUsed: Set<string>;\n\tmessages: Message[];\n\ttoolResultsMap: Map<string, ToolResultMessage>;\n\tsessionEvents: SessionEvent[];\n\ttokenStats: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcostStats: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\ttools?: { name: string; description: string }[];\n\tcontextWindow?: number;\n\tisStreamingFormat?: boolean;\n}\n\n// ============================================================================\n// Theme Types and Loading\n// ============================================================================\n\ninterface ThemeJson {\n\tname: string;\n\tvars?: Record<string, string | number>;\n\tcolors: Record<string, string | number>;\n}\n\ninterface ThemeColors {\n\t// Core UI\n\taccent: string;\n\tborder: string;\n\tborderAccent: string;\n\tsuccess: string;\n\terror: string;\n\twarning: string;\n\tmuted: string;\n\tdim: string;\n\ttext: string;\n\t// Backgrounds\n\tuserMessageBg: string;\n\tuserMessageText: string;\n\ttoolPendingBg: string;\n\ttoolSuccessBg: string;\n\ttoolErrorBg: string;\n\ttoolOutput: string;\n\t// Markdown\n\tmdHeading: string;\n\tmdLink: string;\n\tmdLinkUrl: string;\n\tmdCode: string;\n\tmdCodeBlock: string;\n\tmdCodeBlockBorder: string;\n\tmdQuote: string;\n\tmdQuoteBorder: string;\n\tmdHr: string;\n\tmdListBullet: string;\n\t// Diffs\n\ttoolDiffAdded: string;\n\ttoolDiffRemoved: string;\n\ttoolDiffContext: string;\n\t// Syntax highlighting\n\tsyntaxComment: string;\n\tsyntaxKeyword: string;\n\tsyntaxFunction: string;\n\tsyntaxVariable: string;\n\tsyntaxString: string;\n\tsyntaxNumber: string;\n\tsyntaxType: string;\n\tsyntaxOperator: string;\n\tsyntaxPunctuation: string;\n}\n\n/** Resolve a theme color value, following variable references until we get a final value. */\nfunction resolveColorValue(\n\tvalue: string | number,\n\tvars: Record<string, string | number>,\n\tdefaultValue: string,\n\tvisited = new Set<string>(),\n): string {\n\tif (value === \"\") return defaultValue;\n\tif (typeof value !== \"string\") return defaultValue;\n\tif (visited.has(value)) return defaultValue;\n\tif (!(value in vars)) return value; // Return as-is (hex colors work in CSS)\n\tvisited.add(value);\n\treturn resolveColorValue(vars[value], vars, defaultValue, visited);\n}\n\n/** Load theme JSON from built-in or custom themes directory. */\nfunction loadThemeJson(name: string): ThemeJson | null {\n\t// Try built-in themes first\n\tconst themesDir = getThemesDir();\n\tconst builtinPath = path.join(themesDir, `${name}.json`);\n\tif (existsSync(builtinPath)) {\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(builtinPath, \"utf-8\")) as ThemeJson;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Try custom themes\n\tconst customThemesDir = getCustomThemesDir();\n\tconst customPath = path.join(customThemesDir, `${name}.json`);\n\tif (existsSync(customPath)) {\n\t\ttry {\n\t\t\treturn JSON.parse(readFileSync(customPath, \"utf-8\")) as ThemeJson;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/** Build complete theme colors object, resolving theme JSON values against defaults. */\nfunction getThemeColors(themeName?: string): ThemeColors {\n\tconst isLight = isLightTheme(themeName);\n\n\t// Default colors based on theme type\n\tconst defaultColors: ThemeColors = isLight\n\t\t? {\n\t\t\t\t// Light theme defaults\n\t\t\t\taccent: \"rgb(95, 135, 135)\",\n\t\t\t\tborder: \"rgb(95, 135, 175)\",\n\t\t\t\tborderAccent: \"rgb(95, 135, 135)\",\n\t\t\t\tsuccess: \"rgb(135, 175, 135)\",\n\t\t\t\terror: \"rgb(175, 95, 95)\",\n\t\t\t\twarning: \"rgb(215, 175, 95)\",\n\t\t\t\tmuted: \"rgb(108, 108, 108)\",\n\t\t\t\tdim: \"rgb(138, 138, 138)\",\n\t\t\t\ttext: \"rgb(0, 0, 0)\",\n\t\t\t\tuserMessageBg: \"rgb(232, 232, 232)\",\n\t\t\t\tuserMessageText: \"rgb(0, 0, 0)\",\n\t\t\t\ttoolPendingBg: \"rgb(232, 232, 240)\",\n\t\t\t\ttoolSuccessBg: \"rgb(232, 240, 232)\",\n\t\t\t\ttoolErrorBg: \"rgb(240, 232, 232)\",\n\t\t\t\ttoolOutput: \"rgb(108, 108, 108)\",\n\t\t\t\tmdHeading: \"rgb(215, 175, 95)\",\n\t\t\t\tmdLink: \"rgb(95, 135, 175)\",\n\t\t\t\tmdLinkUrl: \"rgb(138, 138, 138)\",\n\t\t\t\tmdCode: \"rgb(95, 135, 135)\",\n\t\t\t\tmdCodeBlock: \"rgb(135, 175, 135)\",\n\t\t\t\tmdCodeBlockBorder: \"rgb(108, 108, 108)\",\n\t\t\t\tmdQuote: \"rgb(108, 108, 108)\",\n\t\t\t\tmdQuoteBorder: \"rgb(108, 108, 108)\",\n\t\t\t\tmdHr: \"rgb(108, 108, 108)\",\n\t\t\t\tmdListBullet: \"rgb(135, 175, 135)\",\n\t\t\t\ttoolDiffAdded: \"rgb(135, 175, 135)\",\n\t\t\t\ttoolDiffRemoved: \"rgb(175, 95, 95)\",\n\t\t\t\ttoolDiffContext: \"rgb(108, 108, 108)\",\n\t\t\t\tsyntaxComment: \"rgb(0, 128, 0)\",\n\t\t\t\tsyntaxKeyword: \"rgb(0, 0, 255)\",\n\t\t\t\tsyntaxFunction: \"rgb(121, 94, 38)\",\n\t\t\t\tsyntaxVariable: \"rgb(0, 16, 128)\",\n\t\t\t\tsyntaxString: \"rgb(163, 21, 21)\",\n\t\t\t\tsyntaxNumber: \"rgb(9, 134, 88)\",\n\t\t\t\tsyntaxType: \"rgb(38, 127, 153)\",\n\t\t\t\tsyntaxOperator: \"rgb(0, 0, 0)\",\n\t\t\t\tsyntaxPunctuation: \"rgb(0, 0, 0)\",\n\t\t\t}\n\t\t: {\n\t\t\t\t// Dark theme defaults\n\t\t\t\taccent: \"rgb(138, 190, 183)\",\n\t\t\t\tborder: \"rgb(95, 135, 255)\",\n\t\t\t\tborderAccent: \"rgb(0, 215, 255)\",\n\t\t\t\tsuccess: \"rgb(181, 189, 104)\",\n\t\t\t\terror: \"rgb(204, 102, 102)\",\n\t\t\t\twarning: \"rgb(255, 255, 0)\",\n\t\t\t\tmuted: \"rgb(128, 128, 128)\",\n\t\t\t\tdim: \"rgb(102, 102, 102)\",\n\t\t\t\ttext: \"rgb(229, 229, 231)\",\n\t\t\t\tuserMessageBg: \"rgb(52, 53, 65)\",\n\t\t\t\tuserMessageText: \"rgb(229, 229, 231)\",\n\t\t\t\ttoolPendingBg: \"rgb(40, 40, 50)\",\n\t\t\t\ttoolSuccessBg: \"rgb(40, 50, 40)\",\n\t\t\t\ttoolErrorBg: \"rgb(60, 40, 40)\",\n\t\t\t\ttoolOutput: \"rgb(128, 128, 128)\",\n\t\t\t\tmdHeading: \"rgb(240, 198, 116)\",\n\t\t\t\tmdLink: \"rgb(129, 162, 190)\",\n\t\t\t\tmdLinkUrl: \"rgb(102, 102, 102)\",\n\t\t\t\tmdCode: \"rgb(138, 190, 183)\",\n\t\t\t\tmdCodeBlock: \"rgb(181, 189, 104)\",\n\t\t\t\tmdCodeBlockBorder: \"rgb(128, 128, 128)\",\n\t\t\t\tmdQuote: \"rgb(128, 128, 128)\",\n\t\t\t\tmdQuoteBorder: \"rgb(128, 128, 128)\",\n\t\t\t\tmdHr: \"rgb(128, 128, 128)\",\n\t\t\t\tmdListBullet: \"rgb(138, 190, 183)\",\n\t\t\t\ttoolDiffAdded: \"rgb(181, 189, 104)\",\n\t\t\t\ttoolDiffRemoved: \"rgb(204, 102, 102)\",\n\t\t\t\ttoolDiffContext: \"rgb(128, 128, 128)\",\n\t\t\t\tsyntaxComment: \"rgb(106, 153, 85)\",\n\t\t\t\tsyntaxKeyword: \"rgb(86, 156, 214)\",\n\t\t\t\tsyntaxFunction: \"rgb(220, 220, 170)\",\n\t\t\t\tsyntaxVariable: \"rgb(156, 220, 254)\",\n\t\t\t\tsyntaxString: \"rgb(206, 145, 120)\",\n\t\t\t\tsyntaxNumber: \"rgb(181, 206, 168)\",\n\t\t\t\tsyntaxType: \"rgb(78, 201, 176)\",\n\t\t\t\tsyntaxOperator: \"rgb(212, 212, 212)\",\n\t\t\t\tsyntaxPunctuation: \"rgb(212, 212, 212)\",\n\t\t\t};\n\n\tif (!themeName) return defaultColors;\n\n\tconst themeJson = loadThemeJson(themeName);\n\tif (!themeJson) return defaultColors;\n\n\tconst vars = themeJson.vars || {};\n\tconst colors = themeJson.colors;\n\n\tconst resolve = (key: keyof ThemeColors): string => {\n\t\tconst value = colors[key];\n\t\tif (value === undefined) return defaultColors[key];\n\t\treturn resolveColorValue(value, vars, defaultColors[key]);\n\t};\n\n\treturn {\n\t\taccent: resolve(\"accent\"),\n\t\tborder: resolve(\"border\"),\n\t\tborderAccent: resolve(\"borderAccent\"),\n\t\tsuccess: resolve(\"success\"),\n\t\terror: resolve(\"error\"),\n\t\twarning: resolve(\"warning\"),\n\t\tmuted: resolve(\"muted\"),\n\t\tdim: resolve(\"dim\"),\n\t\ttext: resolve(\"text\"),\n\t\tuserMessageBg: resolve(\"userMessageBg\"),\n\t\tuserMessageText: resolve(\"userMessageText\"),\n\t\ttoolPendingBg: resolve(\"toolPendingBg\"),\n\t\ttoolSuccessBg: resolve(\"toolSuccessBg\"),\n\t\ttoolErrorBg: resolve(\"toolErrorBg\"),\n\t\ttoolOutput: resolve(\"toolOutput\"),\n\t\tmdHeading: resolve(\"mdHeading\"),\n\t\tmdLink: resolve(\"mdLink\"),\n\t\tmdLinkUrl: resolve(\"mdLinkUrl\"),\n\t\tmdCode: resolve(\"mdCode\"),\n\t\tmdCodeBlock: resolve(\"mdCodeBlock\"),\n\t\tmdCodeBlockBorder: resolve(\"mdCodeBlockBorder\"),\n\t\tmdQuote: resolve(\"mdQuote\"),\n\t\tmdQuoteBorder: resolve(\"mdQuoteBorder\"),\n\t\tmdHr: resolve(\"mdHr\"),\n\t\tmdListBullet: resolve(\"mdListBullet\"),\n\t\ttoolDiffAdded: resolve(\"toolDiffAdded\"),\n\t\ttoolDiffRemoved: resolve(\"toolDiffRemoved\"),\n\t\ttoolDiffContext: resolve(\"toolDiffContext\"),\n\t\tsyntaxComment: resolve(\"syntaxComment\"),\n\t\tsyntaxKeyword: resolve(\"syntaxKeyword\"),\n\t\tsyntaxFunction: resolve(\"syntaxFunction\"),\n\t\tsyntaxVariable: resolve(\"syntaxVariable\"),\n\t\tsyntaxString: resolve(\"syntaxString\"),\n\t\tsyntaxNumber: resolve(\"syntaxNumber\"),\n\t\tsyntaxType: resolve(\"syntaxType\"),\n\t\tsyntaxOperator: resolve(\"syntaxOperator\"),\n\t\tsyntaxPunctuation: resolve(\"syntaxPunctuation\"),\n\t};\n}\n\n/** Check if theme is a light theme (currently only matches \"light\" exactly). */\nfunction isLightTheme(themeName?: string): boolean {\n\treturn themeName === \"light\";\n}\n\n// ============================================================================\n// Utility functions\n// ============================================================================\n\nfunction escapeHtml(text: string): string {\n\treturn text\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&#039;\");\n}\n\nfunction shortenPath(path: string): string {\n\tconst home = homedir();\n\treturn path.startsWith(home) ? `~${path.slice(home.length)}` : path;\n}\n\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nfunction formatTimestamp(timestamp: number | string | undefined): string {\n\tif (!timestamp) return \"\";\n\tconst date = new Date(typeof timestamp === \"string\" ? timestamp : timestamp);\n\treturn date.toLocaleTimeString(undefined, { hour: \"2-digit\", minute: \"2-digit\", second: \"2-digit\" });\n}\n\n/** Highlight code using highlight.js. Returns HTML with syntax highlighting spans. */\nfunction highlightCode(code: string, lang?: string): string {\n\tif (!lang) {\n\t\treturn escapeHtml(code);\n\t}\n\ttry {\n\t\t// Check if language is supported\n\t\tif (hljs.getLanguage(lang)) {\n\t\t\treturn hljs.highlight(code, { language: lang, ignoreIllegals: true }).value;\n\t\t}\n\t\t// Try common aliases\n\t\tconst aliases: Record<string, string> = {\n\t\t\tts: \"typescript\",\n\t\t\tjs: \"javascript\",\n\t\t\tpy: \"python\",\n\t\t\trb: \"ruby\",\n\t\t\tsh: \"bash\",\n\t\t\tyml: \"yaml\",\n\t\t\tmd: \"markdown\",\n\t\t};\n\t\tconst aliasedLang = aliases[lang];\n\t\tif (aliasedLang && hljs.getLanguage(aliasedLang)) {\n\t\t\treturn hljs.highlight(code, { language: aliasedLang, ignoreIllegals: true }).value;\n\t\t}\n\t} catch {\n\t\t// Fall through to escaped output\n\t}\n\treturn escapeHtml(code);\n}\n\n/** Get language from file path extension. */\nfunction getLanguageFromPath(filePath: string): string | undefined {\n\tconst ext = filePath.split(\".\").pop()?.toLowerCase();\n\tif (!ext) return undefined;\n\n\tconst extToLang: Record<string, string> = {\n\t\tts: \"typescript\",\n\t\ttsx: \"typescript\",\n\t\tjs: \"javascript\",\n\t\tjsx: \"javascript\",\n\t\tmjs: \"javascript\",\n\t\tcjs: \"javascript\",\n\t\tpy: \"python\",\n\t\trb: \"ruby\",\n\t\trs: \"rust\",\n\t\tgo: \"go\",\n\t\tjava: \"java\",\n\t\tkt: \"kotlin\",\n\t\tswift: \"swift\",\n\t\tc: \"c\",\n\t\th: \"c\",\n\t\tcpp: \"cpp\",\n\t\tcc: \"cpp\",\n\t\tcxx: \"cpp\",\n\t\thpp: \"cpp\",\n\t\tcs: \"csharp\",\n\t\tphp: \"php\",\n\t\tsh: \"bash\",\n\t\tbash: \"bash\",\n\t\tzsh: \"bash\",\n\t\tfish: \"bash\",\n\t\tps1: \"powershell\",\n\t\tsql: \"sql\",\n\t\thtml: \"html\",\n\t\thtm: \"html\",\n\t\txml: \"xml\",\n\t\tcss: \"css\",\n\t\tscss: \"scss\",\n\t\tsass: \"scss\",\n\t\tless: \"less\",\n\t\tjson: \"json\",\n\t\tyaml: \"yaml\",\n\t\tyml: \"yaml\",\n\t\ttoml: \"toml\",\n\t\tini: \"ini\",\n\t\tmd: \"markdown\",\n\t\tmarkdown: \"markdown\",\n\t\tdockerfile: \"dockerfile\",\n\t\tmakefile: \"makefile\",\n\t\tcmake: \"cmake\",\n\t\tlua: \"lua\",\n\t\tr: \"r\",\n\t\tscala: \"scala\",\n\t\tclj: \"clojure\",\n\t\tcljs: \"clojure\",\n\t\tex: \"elixir\",\n\t\texs: \"elixir\",\n\t\terl: \"erlang\",\n\t\thrl: \"erlang\",\n\t\ths: \"haskell\",\n\t\tml: \"ocaml\",\n\t\tmli: \"ocaml\",\n\t\tfs: \"fsharp\",\n\t\tfsx: \"fsharp\",\n\t\tvue: \"vue\",\n\t\tsvelte: \"xml\",\n\t\ttf: \"hcl\",\n\t\thcl: \"hcl\",\n\t\tproto: \"protobuf\",\n\t\tgraphql: \"graphql\",\n\t\tgql: \"graphql\",\n\t};\n\n\treturn extToLang[ext];\n}\n\n/** Render markdown to HTML server-side with TUI-style code block formatting and syntax highlighting. */\nfunction renderMarkdown(text: string): string {\n\t// Custom renderer for code blocks to match TUI style\n\tconst renderer = new marked.Renderer();\n\trenderer.code = ({ text: code, lang }: { text: string; lang?: string }) => {\n\t\tconst language = lang || \"\";\n\t\tconst highlighted = highlightCode(code, lang);\n\t\treturn (\n\t\t\t'<div class=\"code-block-wrapper\">' +\n\t\t\t`<div class=\"code-block-header\">\\`\\`\\`${language}</div>` +\n\t\t\t`<pre><code class=\"hljs\">${highlighted}</code></pre>` +\n\t\t\t'<div class=\"code-block-footer\">```</div>' +\n\t\t\t\"</div>\"\n\t\t);\n\t};\n\n\t// Configure marked for safe rendering\n\tmarked.setOptions({\n\t\tbreaks: true,\n\t\tgfm: true,\n\t});\n\n\t// Parse markdown (marked escapes HTML by default in newer versions)\n\treturn marked.parse(text, { renderer }) as string;\n}\n\nfunction formatExpandableOutput(lines: string[], maxLines: number, lang?: string): string {\n\tconst displayLines = lines.slice(0, maxLines);\n\tconst remaining = lines.length - maxLines;\n\n\t// If language is provided, highlight the entire code block\n\tif (lang) {\n\t\tconst code = lines.join(\"\\n\");\n\t\tconst highlighted = highlightCode(code, lang);\n\n\t\tif (remaining > 0) {\n\t\t\t// For expandable, we need preview and full versions\n\t\t\tconst previewCode = displayLines.join(\"\\n\");\n\t\t\tconst previewHighlighted = highlightCode(previewCode, lang);\n\n\t\t\tlet out = '<div class=\"tool-output expandable\" onclick=\"this.classList.toggle(\\'expanded\\')\">';\n\t\t\tout += `<div class=\"output-preview\"><pre><code class=\"hljs\">${previewHighlighted}</code></pre>`;\n\t\t\tout += `<div class=\"expand-hint\">... (${remaining} more lines) - click to expand</div>`;\n\t\t\tout += \"</div>\";\n\t\t\tout += `<div class=\"output-full\"><pre><code class=\"hljs\">${highlighted}</code></pre></div></div>`;\n\t\t\treturn out;\n\t\t}\n\n\t\treturn `<div class=\"tool-output\"><pre><code class=\"hljs\">${highlighted}</code></pre></div>`;\n\t}\n\n\t// No language - plain text output\n\tif (remaining > 0) {\n\t\tlet out = '<div class=\"tool-output expandable\" onclick=\"this.classList.toggle(\\'expanded\\')\">';\n\t\tout += '<div class=\"output-preview\">';\n\t\tfor (const line of displayLines) {\n\t\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t\t}\n\t\tout += `<div class=\"expand-hint\">... (${remaining} more lines) - click to expand</div>`;\n\t\tout += \"</div>\";\n\t\tout += '<div class=\"output-full\">';\n\t\tfor (const line of lines) {\n\t\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t\t}\n\t\tout += \"</div></div>\";\n\t\treturn out;\n\t}\n\n\tlet out = '<div class=\"tool-output\">';\n\tfor (const line of displayLines) {\n\t\tout += `<div>${escapeHtml(replaceTabs(line))}</div>`;\n\t}\n\tout += \"</div>\";\n\treturn out;\n}\n\n// ============================================================================\n// Parsing functions\n// ============================================================================\n\nfunction parseSessionManagerFormat(lines: string[]): ParsedSessionData {\n\tconst data: ParsedSessionData = {\n\t\tsessionId: \"unknown\",\n\t\ttimestamp: new Date().toISOString(),\n\t\tmodelsUsed: new Set(),\n\t\tmessages: [],\n\t\ttoolResultsMap: new Map(),\n\t\tsessionEvents: [],\n\t\ttokenStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcostStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t};\n\n\tfor (const line of lines) {\n\t\tlet entry: { type: string; [key: string]: unknown };\n\t\ttry {\n\t\t\tentry = JSON.parse(line) as { type: string; [key: string]: unknown };\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch (entry.type) {\n\t\t\tcase \"session\":\n\t\t\t\tdata.sessionId = (entry.id as string) || \"unknown\";\n\t\t\t\tdata.timestamp = (entry.timestamp as string) || data.timestamp;\n\t\t\t\tdata.systemPrompt = entry.systemPrompt as string | undefined;\n\t\t\t\tif (entry.modelId) {\n\t\t\t\t\tconst modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : (entry.modelId as string);\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"message\": {\n\t\t\t\tconst message = entry.message as Message;\n\t\t\t\tdata.messages.push(message);\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\tmessage,\n\t\t\t\t\ttimestamp: entry.timestamp as number | undefined,\n\t\t\t\t});\n\n\t\t\t\tif (message.role === \"toolResult\") {\n\t\t\t\t\tconst toolResult = message as ToolResultMessage;\n\t\t\t\t\tdata.toolResultsMap.set(toolResult.toolCallId, toolResult);\n\t\t\t\t} else if (message.role === \"assistant\") {\n\t\t\t\t\tconst assistantMsg = message as AssistantMessage;\n\t\t\t\t\tif (assistantMsg.usage) {\n\t\t\t\t\t\tdata.tokenStats.input += assistantMsg.usage.input || 0;\n\t\t\t\t\t\tdata.tokenStats.output += assistantMsg.usage.output || 0;\n\t\t\t\t\t\tdata.tokenStats.cacheRead += assistantMsg.usage.cacheRead || 0;\n\t\t\t\t\t\tdata.tokenStats.cacheWrite += assistantMsg.usage.cacheWrite || 0;\n\t\t\t\t\t\tif (assistantMsg.usage.cost) {\n\t\t\t\t\t\t\tdata.costStats.input += assistantMsg.usage.cost.input || 0;\n\t\t\t\t\t\t\tdata.costStats.output += assistantMsg.usage.cost.output || 0;\n\t\t\t\t\t\t\tdata.costStats.cacheRead += assistantMsg.usage.cost.cacheRead || 0;\n\t\t\t\t\t\t\tdata.costStats.cacheWrite += assistantMsg.usage.cost.cacheWrite || 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"model_change\":\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"model_change\",\n\t\t\t\t\tprovider: entry.provider as string,\n\t\t\t\t\tmodelId: entry.modelId as string,\n\t\t\t\t\ttimestamp: entry.timestamp as number | undefined,\n\t\t\t\t});\n\t\t\t\tif (entry.modelId) {\n\t\t\t\t\tconst modelInfo = entry.provider ? `${entry.provider}/${entry.modelId}` : (entry.modelId as string);\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"compaction\":\n\t\t\t\tdata.sessionEvents.push({\n\t\t\t\t\ttype: \"compaction\",\n\t\t\t\t\ttimestamp: entry.timestamp as string,\n\t\t\t\t\tsummary: entry.summary as string,\n\t\t\t\t\ttokensBefore: entry.tokensBefore as number,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn data;\n}\n\nfunction parseStreamingEventFormat(lines: string[]): ParsedSessionData {\n\tconst data: ParsedSessionData = {\n\t\tsessionId: \"unknown\",\n\t\ttimestamp: new Date().toISOString(),\n\t\tmodelsUsed: new Set(),\n\t\tmessages: [],\n\t\ttoolResultsMap: new Map(),\n\t\tsessionEvents: [],\n\t\ttokenStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcostStats: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tisStreamingFormat: true,\n\t};\n\n\tlet timestampSet = false;\n\n\tfor (const line of lines) {\n\t\tlet entry: { type: string; message?: Message };\n\t\ttry {\n\t\t\tentry = JSON.parse(line) as { type: string; message?: Message };\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type === \"message_end\" && entry.message) {\n\t\t\tconst msg = entry.message;\n\t\t\tdata.messages.push(msg);\n\t\t\tdata.sessionEvents.push({\n\t\t\t\ttype: \"message\",\n\t\t\t\tmessage: msg,\n\t\t\t\ttimestamp: (msg as { timestamp?: number }).timestamp,\n\t\t\t});\n\n\t\t\tif (msg.role === \"toolResult\") {\n\t\t\t\tconst toolResult = msg as ToolResultMessage;\n\t\t\t\tdata.toolResultsMap.set(toolResult.toolCallId, toolResult);\n\t\t\t} else if (msg.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = msg as AssistantMessage;\n\t\t\t\tif (assistantMsg.model) {\n\t\t\t\t\tconst modelInfo = assistantMsg.provider\n\t\t\t\t\t\t? `${assistantMsg.provider}/${assistantMsg.model}`\n\t\t\t\t\t\t: assistantMsg.model;\n\t\t\t\t\tdata.modelsUsed.add(modelInfo);\n\t\t\t\t}\n\t\t\t\tif (assistantMsg.usage) {\n\t\t\t\t\tdata.tokenStats.input += assistantMsg.usage.input || 0;\n\t\t\t\t\tdata.tokenStats.output += assistantMsg.usage.output || 0;\n\t\t\t\t\tdata.tokenStats.cacheRead += assistantMsg.usage.cacheRead || 0;\n\t\t\t\t\tdata.tokenStats.cacheWrite += assistantMsg.usage.cacheWrite || 0;\n\t\t\t\t\tif (assistantMsg.usage.cost) {\n\t\t\t\t\t\tdata.costStats.input += assistantMsg.usage.cost.input || 0;\n\t\t\t\t\t\tdata.costStats.output += assistantMsg.usage.cost.output || 0;\n\t\t\t\t\t\tdata.costStats.cacheRead += assistantMsg.usage.cost.cacheRead || 0;\n\t\t\t\t\t\tdata.costStats.cacheWrite += assistantMsg.usage.cost.cacheWrite || 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!timestampSet && (msg as { timestamp?: number }).timestamp) {\n\t\t\t\tdata.timestamp = new Date((msg as { timestamp: number }).timestamp).toISOString();\n\t\t\t\ttimestampSet = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tdata.sessionId = `stream-${data.timestamp.replace(/[:.]/g, \"-\")}`;\n\treturn data;\n}\n\nfunction detectFormat(lines: string[]): \"session-manager\" | \"streaming-events\" | \"unknown\" {\n\tfor (const line of lines) {\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line) as { type: string };\n\t\t\tif (entry.type === \"session\") return \"session-manager\";\n\t\t\tif (entry.type === \"agent_start\" || entry.type === \"message_start\" || entry.type === \"turn_start\") {\n\t\t\t\treturn \"streaming-events\";\n\t\t\t}\n\t\t} catch {}\n\t}\n\treturn \"unknown\";\n}\n\nfunction parseSessionFile(content: string): ParsedSessionData {\n\tconst lines = content\n\t\t.trim()\n\t\t.split(\"\\n\")\n\t\t.filter((l) => l.trim());\n\n\tif (lines.length === 0) {\n\t\tthrow new Error(\"Empty session file\");\n\t}\n\n\tconst format = detectFormat(lines);\n\tif (format === \"unknown\") {\n\t\tthrow new Error(\"Unknown session file format\");\n\t}\n\n\treturn format === \"session-manager\" ? parseSessionManagerFormat(lines) : parseStreamingEventFormat(lines);\n}\n\n// ============================================================================\n// HTML formatting functions\n// ============================================================================\n\nfunction formatToolExecution(\n\ttoolName: string,\n\targs: Record<string, unknown>,\n\tresult: ToolResultMessage | undefined,\n\tcolors: ThemeColors,\n): { html: string; bgColor: string } {\n\tlet html = \"\";\n\tconst isError = result?.isError || false;\n\tconst bgColor = result ? (isError ? colors.toolErrorBg : colors.toolSuccessBg) : colors.toolPendingBg;\n\n\tconst getTextOutput = (): string => {\n\t\tif (!result) return \"\";\n\t\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\t\treturn textBlocks.map((c) => (c as { type: \"text\"; text: string }).text).join(\"\\n\");\n\t};\n\n\tswitch (toolName) {\n\t\tcase \"bash\": {\n\t\t\tconst command = (args?.command as string) || \"\";\n\t\t\thtml = `<div class=\"tool-command\">$ ${escapeHtml(command || \"...\")}</div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += formatExpandableOutput(output.split(\"\\n\"), 5);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"read\": {\n\t\t\tconst filePath = (args?.file_path as string) || (args?.path as string) || \"\";\n\t\t\tconst shortenedPath = shortenPath(filePath);\n\t\t\tconst offset = args?.offset as number | undefined;\n\t\t\tconst limit = args?.limit as number | undefined;\n\t\t\tconst lang = getLanguageFromPath(filePath);\n\n\t\t\t// Build path display with offset/limit suffix\n\t\t\tlet pathHtml = escapeHtml(shortenedPath || \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathHtml += `<span class=\"line-numbers\">:${startLine}${endLine ? `-${endLine}` : \"\"}</span>`;\n\t\t\t}\n\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">read</span> <span class=\"tool-path\">${pathHtml}</span></div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += formatExpandableOutput(output.split(\"\\n\"), 10, lang);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"write\": {\n\t\t\tconst filePath = (args?.file_path as string) || (args?.path as string) || \"\";\n\t\t\tconst shortenedPath = shortenPath(filePath);\n\t\t\tconst fileContent = (args?.content as string) || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\t\t\tconst lang = getLanguageFromPath(filePath);\n\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">write</span> <span class=\"tool-path\">${escapeHtml(shortenedPath || \"...\")}</span>`;\n\t\t\tif (lines.length > 10) {\n\t\t\t\thtml += ` <span class=\"line-count\">(${lines.length} lines)</span>`;\n\t\t\t}\n\t\t\thtml += \"</div>\";\n\n\t\t\tif (fileContent) {\n\t\t\t\thtml += formatExpandableOutput(lines, 10, lang);\n\t\t\t}\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"edit\": {\n\t\t\tconst path = shortenPath((args?.file_path as string) || (args?.path as string) || \"\");\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">edit</span> <span class=\"tool-path\">${escapeHtml(path || \"...\")}</span></div>`;\n\n\t\t\tif (result?.details?.diff) {\n\t\t\t\tconst diffLines = result.details.diff.split(\"\\n\");\n\t\t\t\thtml += '<div class=\"tool-diff\">';\n\t\t\t\tfor (const line of diffLines) {\n\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-new\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-old\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\thtml += `<div class=\"diff-line-context\">${escapeHtml(line)}</div>`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thtml += \"</div>\";\n\t\t\t}\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tdefault: {\n\t\t\thtml = `<div class=\"tool-header\"><span class=\"tool-name\">${escapeHtml(toolName)}</span></div>`;\n\t\t\thtml += `<div class=\"tool-output\"><pre>${escapeHtml(JSON.stringify(args, null, 2))}</pre></div>`;\n\t\t\tif (result) {\n\t\t\t\tconst output = getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\thtml += `<div class=\"tool-output\"><div>${escapeHtml(output)}</div></div>`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { html, bgColor };\n}\n\nfunction formatMessage(message: Message, toolResultsMap: Map<string, ToolResultMessage>, colors: ThemeColors): string {\n\tlet html = \"\";\n\tconst timestamp = (message as { timestamp?: number }).timestamp;\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${formatTimestamp(timestamp)}</div>` : \"\";\n\n\t// Handle bash execution messages (user-executed via ! command)\n\tif (isBashExecutionMessage(message)) {\n\t\tconst bashMsg = message as unknown as BashExecutionMessage;\n\t\tconst isError = bashMsg.cancelled || (bashMsg.exitCode !== 0 && bashMsg.exitCode !== null);\n\n\t\thtml += `<div class=\"tool-execution user-bash${isError ? \" user-bash-error\" : \"\"}\">`;\n\t\thtml += timestampHtml;\n\t\thtml += `<div class=\"tool-command\">$ ${escapeHtml(bashMsg.command)}</div>`;\n\n\t\tif (bashMsg.output) {\n\t\t\tconst lines = bashMsg.output.split(\"\\n\");\n\t\t\thtml += formatExpandableOutput(lines, 10);\n\t\t}\n\n\t\tif (bashMsg.cancelled) {\n\t\t\thtml += `<div class=\"bash-status warning\">(cancelled)</div>`;\n\t\t} else if (bashMsg.exitCode !== 0 && bashMsg.exitCode !== null) {\n\t\t\thtml += `<div class=\"bash-status error\">(exit ${bashMsg.exitCode})</div>`;\n\t\t}\n\n\t\tif (bashMsg.truncated && bashMsg.fullOutputPath) {\n\t\t\thtml += `<div class=\"bash-truncation warning\">Output truncated. Full output: ${escapeHtml(bashMsg.fullOutputPath)}</div>`;\n\t\t}\n\n\t\thtml += `</div>`;\n\t\treturn html;\n\t}\n\n\tif (message.role === \"user\") {\n\t\tconst userMsg = message as UserMessage;\n\t\tlet textContent = \"\";\n\t\tconst images: ImageContent[] = [];\n\n\t\tif (typeof userMsg.content === \"string\") {\n\t\t\ttextContent = userMsg.content;\n\t\t} else {\n\t\t\tfor (const block of userMsg.content) {\n\t\t\t\tif (block.type === \"text\") {\n\t\t\t\t\ttextContent += block.text;\n\t\t\t\t} else if (block.type === \"image\") {\n\t\t\t\t\timages.push(block as ImageContent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\thtml += `<div class=\"user-message\">${timestampHtml}`;\n\n\t\t// Render images first\n\t\tif (images.length > 0) {\n\t\t\thtml += `<div class=\"message-images\">`;\n\t\t\tfor (const img of images) {\n\t\t\t\thtml += `<img src=\"data:${img.mimeType};base64,${img.data}\" alt=\"User uploaded image\" class=\"message-image\" />`;\n\t\t\t}\n\t\t\thtml += `</div>`;\n\t\t}\n\n\t\t// Render text as markdown (server-side)\n\t\tif (textContent.trim()) {\n\t\t\thtml += `<div class=\"markdown-content\">${renderMarkdown(textContent)}</div>`;\n\t\t}\n\n\t\thtml += `</div>`;\n\t} else if (message.role === \"assistant\") {\n\t\tconst assistantMsg = message as AssistantMessage;\n\t\thtml += timestampHtml ? `<div class=\"assistant-message\">${timestampHtml}` : \"\";\n\n\t\tfor (const content of assistantMsg.content) {\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Render markdown server-side\n\t\t\t\thtml += `<div class=\"assistant-text markdown-content\">${renderMarkdown(content.text)}</div>`;\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\thtml += `<div class=\"thinking-text\">${escapeHtml(content.thinking.trim()).replace(/\\n/g, \"<br>\")}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tfor (const content of assistantMsg.content) {\n\t\t\tif (content.type === \"toolCall\") {\n\t\t\t\tconst toolResult = toolResultsMap.get(content.id);\n\t\t\t\tconst { html: toolHtml, bgColor } = formatToolExecution(\n\t\t\t\t\tcontent.name,\n\t\t\t\t\tcontent.arguments as Record<string, unknown>,\n\t\t\t\t\ttoolResult,\n\t\t\t\t\tcolors,\n\t\t\t\t);\n\t\t\t\thtml += `<div class=\"tool-execution\" style=\"background-color: ${bgColor}\">${toolHtml}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tconst hasToolCalls = assistantMsg.content.some((c) => c.type === \"toolCall\");\n\t\tif (!hasToolCalls) {\n\t\t\tif (assistantMsg.stopReason === \"aborted\") {\n\t\t\t\thtml += '<div class=\"error-text\">Aborted</div>';\n\t\t\t} else if (assistantMsg.stopReason === \"error\") {\n\t\t\t\thtml += `<div class=\"error-text\">Error: ${escapeHtml(assistantMsg.errorMessage || \"Unknown error\")}</div>`;\n\t\t\t}\n\t\t}\n\n\t\tif (timestampHtml) {\n\t\t\thtml += \"</div>\";\n\t\t}\n\t}\n\n\treturn html;\n}\n\nfunction formatModelChange(event: ModelChangeEvent): string {\n\tconst timestamp = formatTimestamp(event.timestamp);\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${timestamp}</div>` : \"\";\n\tconst modelInfo = `${event.provider}/${event.modelId}`;\n\treturn `<div class=\"model-change\">${timestampHtml}<div class=\"model-change-text\">Switched to model: <span class=\"model-name\">${escapeHtml(modelInfo)}</span></div></div>`;\n}\n\nfunction formatCompaction(event: CompactionEvent): string {\n\tconst timestamp = formatTimestamp(event.timestamp);\n\tconst timestampHtml = timestamp ? `<div class=\"message-timestamp\">${timestamp}</div>` : \"\";\n\tconst summaryHtml = escapeHtml(event.summary).replace(/\\n/g, \"<br>\");\n\n\treturn `<div class=\"compaction-container\">\n\t\t<div class=\"compaction-header\" onclick=\"this.parentElement.classList.toggle('expanded')\">\n\t\t\t${timestampHtml}\n\t\t\t<div class=\"compaction-header-row\">\n\t\t\t\t<span class=\"compaction-toggle\">▶</span>\n\t\t\t\t<span class=\"compaction-title\">Context compacted from ${event.tokensBefore.toLocaleString()} tokens</span>\n\t\t\t\t<span class=\"compaction-hint\">(click to expand summary)</span>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"compaction-content\">\n\t\t\t<div class=\"compaction-summary\">\n\t\t\t\t<div class=\"compaction-summary-header\">Summary sent to model</div>\n\t\t\t\t<div class=\"compaction-summary-content\">${summaryHtml}</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>`;\n}\n\n// ============================================================================\n// HTML generation\n// ============================================================================\n\nfunction generateHtml(data: ParsedSessionData, filename: string, colors: ThemeColors, isLight: boolean): string {\n\tconst userMessages = data.messages.filter((m) => m.role === \"user\").length;\n\tconst assistantMessages = data.messages.filter((m) => m.role === \"assistant\").length;\n\n\tlet toolCallsCount = 0;\n\tfor (const message of data.messages) {\n\t\tif (message.role === \"assistant\") {\n\t\t\ttoolCallsCount += (message as AssistantMessage).content.filter((c) => c.type === \"toolCall\").length;\n\t\t}\n\t}\n\n\tconst lastAssistantMessage = data.messages\n\t\t.slice()\n\t\t.reverse()\n\t\t.find((m) => m.role === \"assistant\" && (m as AssistantMessage).stopReason !== \"aborted\") as\n\t\t| AssistantMessage\n\t\t| undefined;\n\n\tconst contextTokens = lastAssistantMessage\n\t\t? lastAssistantMessage.usage.input +\n\t\t\tlastAssistantMessage.usage.output +\n\t\t\tlastAssistantMessage.usage.cacheRead +\n\t\t\tlastAssistantMessage.usage.cacheWrite\n\t\t: 0;\n\n\tconst lastModel = lastAssistantMessage?.model || \"unknown\";\n\tconst lastProvider = lastAssistantMessage?.provider || \"\";\n\tconst lastModelInfo = lastProvider ? `${lastProvider}/${lastModel}` : lastModel;\n\n\tconst contextWindow = data.contextWindow || 0;\n\tconst contextPercent = contextWindow > 0 ? ((contextTokens / contextWindow) * 100).toFixed(1) : null;\n\n\tlet messagesHtml = \"\";\n\tfor (const event of data.sessionEvents) {\n\t\tswitch (event.type) {\n\t\t\tcase \"message\":\n\t\t\t\tif (event.message.role !== \"toolResult\") {\n\t\t\t\t\tmessagesHtml += formatMessage(event.message, data.toolResultsMap, colors);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"model_change\":\n\t\t\t\tmessagesHtml += formatModelChange(event);\n\t\t\t\tbreak;\n\t\t\tcase \"compaction\":\n\t\t\t\tmessagesHtml += formatCompaction(event);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst systemPromptHtml = data.systemPrompt\n\t\t? `<div class=\"system-prompt\">\n <div class=\"system-prompt-header\">System Prompt</div>\n <div class=\"system-prompt-content\">${escapeHtml(data.systemPrompt)}</div>\n </div>`\n\t\t: \"\";\n\n\tconst toolsHtml = data.tools\n\t\t? `<div class=\"tools-list\">\n <div class=\"tools-header\">Available Tools</div>\n <div class=\"tools-content\">\n ${data.tools.map((tool) => `<div class=\"tool-item\"><span class=\"tool-item-name\">${escapeHtml(tool.name)}</span> - ${escapeHtml(tool.description)}</div>`).join(\"\")}\n </div>\n </div>`\n\t\t: \"\";\n\n\tconst streamingNotice = data.isStreamingFormat\n\t\t? `<div class=\"streaming-notice\">\n <em>Note: This session was reconstructed from raw agent event logs, which do not contain system prompt or tool definitions.</em>\n </div>`\n\t\t: \"\";\n\n\tconst contextUsageText = contextPercent\n\t\t? `${contextTokens.toLocaleString()} / ${contextWindow.toLocaleString()} tokens (${contextPercent}%) - ${escapeHtml(lastModelInfo)}`\n\t\t: `${contextTokens.toLocaleString()} tokens (last turn) - ${escapeHtml(lastModelInfo)}`;\n\n\t// Compute body background based on theme\n\tconst bodyBg = isLight ? \"rgb(248, 248, 248)\" : \"rgb(24, 24, 30)\";\n\tconst containerBg = isLight ? \"rgb(255, 255, 255)\" : \"rgb(30, 30, 36)\";\n\tconst compactionBg = isLight ? \"rgb(255, 248, 220)\" : \"rgb(60, 55, 35)\";\n\tconst systemPromptBg = isLight ? \"rgb(255, 250, 230)\" : \"rgb(60, 55, 40)\";\n\tconst streamingNoticeBg = isLight ? \"rgb(250, 245, 235)\" : \"rgb(50, 45, 35)\";\n\tconst modelChangeBg = isLight ? \"rgb(240, 240, 250)\" : \"rgb(40, 40, 50)\";\n\tconst userBashBg = isLight ? \"rgb(255, 250, 240)\" : \"rgb(50, 48, 35)\";\n\tconst userBashErrorBg = isLight ? \"rgb(255, 245, 235)\" : \"rgb(60, 45, 35)\";\n\n\treturn `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Session Export - ${escapeHtml(filename)}</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;\n font-size: 12px;\n line-height: 1.6;\n color: ${colors.text};\n background: ${bodyBg};\n padding: 24px;\n }\n .container { max-width: 700px; margin: 0 auto; }\n .header {\n margin-bottom: 24px;\n padding: 16px;\n background: ${containerBg};\n border-radius: 4px;\n }\n .header h1 {\n font-size: 14px;\n font-weight: bold;\n margin-bottom: 12px;\n color: ${colors.borderAccent};\n }\n .header-info { display: flex; flex-direction: column; gap: 3px; font-size: 11px; }\n .info-item { color: ${colors.dim}; display: flex; align-items: baseline; }\n .info-label { font-weight: 600; margin-right: 8px; min-width: 100px; }\n .info-value { color: ${colors.text}; flex: 1; }\n .info-value.cost { font-family: 'SF Mono', monospace; }\n .messages { display: flex; flex-direction: column; gap: 16px; }\n .message-timestamp { font-size: 10px; color: ${colors.dim}; margin-bottom: 4px; opacity: 0.8; }\n .user-message {\n background: ${colors.userMessageBg};\n color: ${colors.userMessageText};\n padding: 12px 16px;\n border-radius: 4px;\n }\n .assistant-message { padding: 0; }\n .assistant-text, .thinking-text {\n padding: 12px 16px;\n }\n .thinking-text { color: ${colors.dim}; font-style: italic; white-space: pre-wrap; }\n .model-change { padding: 8px 16px; background: ${modelChangeBg}; border-radius: 4px; }\n .model-change-text { color: ${colors.dim}; font-size: 11px; }\n .model-name { color: ${colors.borderAccent}; font-weight: bold; }\n .compaction-container { background: ${compactionBg}; border-radius: 4px; overflow: hidden; }\n .compaction-header { padding: 12px 16px; cursor: pointer; }\n .compaction-header:hover { background: rgba(${isLight ? \"0, 0, 0\" : \"255, 255, 255\"}, 0.05); }\n .compaction-header-row { display: flex; align-items: center; gap: 8px; }\n .compaction-toggle { color: ${colors.borderAccent}; font-size: 10px; transition: transform 0.2s; }\n .compaction-container.expanded .compaction-toggle { transform: rotate(90deg); }\n .compaction-title { color: ${colors.text}; font-weight: bold; }\n .compaction-hint { color: ${colors.dim}; font-size: 11px; }\n .compaction-content { display: none; padding: 0 16px 16px 16px; }\n .compaction-container.expanded .compaction-content { display: block; }\n .compaction-summary { background: rgba(0, 0, 0, 0.1); border-radius: 4px; padding: 12px; }\n .compaction-summary-header { font-weight: bold; color: ${colors.borderAccent}; margin-bottom: 8px; font-size: 11px; }\n .compaction-summary-content { color: ${colors.text}; white-space: pre-wrap; word-wrap: break-word; }\n .tool-execution { padding: 12px 16px; border-radius: 4px; margin-top: 8px; }\n .tool-execution.user-bash { background: ${userBashBg}; }\n .tool-execution.user-bash-error { background: ${userBashErrorBg}; }\n .tool-header, .tool-name { font-weight: bold; }\n .tool-path { color: ${colors.borderAccent}; word-break: break-all; }\n .line-numbers { color: ${colors.warning}; }\n .line-count { color: ${colors.dim}; }\n .tool-command { font-weight: bold; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; word-break: break-word; }\n .tool-output {\n margin-top: 12px;\n color: ${colors.toolOutput};\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n word-break: break-word;\n font-family: inherit;\n overflow-x: auto;\n }\n .tool-output > div { line-height: 1.4; }\n .tool-output pre { margin: 0; font-family: inherit; color: inherit; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .tool-output.expandable { cursor: pointer; }\n .tool-output.expandable:hover { opacity: 0.9; }\n .tool-output.expandable .output-full { display: none; }\n .tool-output.expandable.expanded .output-preview { display: none; }\n .tool-output.expandable.expanded .output-full { display: block; }\n .expand-hint { color: ${colors.borderAccent}; font-style: italic; margin-top: 4px; }\n .system-prompt, .tools-list { background: ${systemPromptBg}; padding: 12px 16px; border-radius: 4px; margin-bottom: 16px; }\n .system-prompt-header, .tools-header { font-weight: bold; color: ${colors.warning}; margin-bottom: 8px; }\n .system-prompt-content, .tools-content { color: ${colors.dim}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; word-break: break-word; font-size: 11px; }\n .tool-item { margin: 4px 0; }\n .tool-item-name { font-weight: bold; color: ${colors.text}; }\n .tool-diff { margin-top: 12px; font-size: 11px; font-family: inherit; overflow-x: auto; max-width: 100%; }\n .diff-line-old { color: ${colors.toolDiffRemoved}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .diff-line-new { color: ${colors.toolDiffAdded}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .diff-line-context { color: ${colors.toolDiffContext}; white-space: pre-wrap; word-wrap: break-word; overflow-wrap: break-word; }\n .error-text { color: ${colors.error}; padding: 12px 16px; }\n .bash-status.warning { color: ${colors.warning}; }\n .bash-status.error { color: ${colors.error}; }\n .bash-truncation.warning { color: ${colors.warning}; }\n .footer { margin-top: 48px; padding: 20px; text-align: center; color: ${colors.dim}; font-size: 10px; }\n .streaming-notice { background: ${streamingNoticeBg}; padding: 12px 16px; border-radius: 4px; margin-bottom: 16px; color: ${colors.dim}; font-size: 11px; }\n\n /* Image styles */\n .message-images { margin-bottom: 12px; }\n .message-image { max-width: 100%; max-height: 400px; border-radius: 4px; margin: 4px 0; }\n\n /* Markdown styles */\n .markdown-content h1, .markdown-content h2, .markdown-content h3,\n .markdown-content h4, .markdown-content h5, .markdown-content h6 {\n color: ${colors.mdHeading};\n margin: 1em 0 0.5em 0;\n font-weight: bold;\n }\n .markdown-content h1 { font-size: 1.4em; text-decoration: underline; }\n .markdown-content h2 { font-size: 1.2em; }\n .markdown-content h3 { font-size: 1.1em; }\n .markdown-content p { margin: 0.5em 0; }\n .markdown-content a { color: ${colors.mdLink}; text-decoration: underline; }\n .markdown-content a:hover { opacity: 0.8; }\n .markdown-content code {\n background: rgba(${isLight ? \"0, 0, 0\" : \"255, 255, 255\"}, 0.1);\n color: ${colors.mdCode};\n padding: 2px 6px;\n border-radius: 3px;\n font-family: inherit;\n }\n .markdown-content pre {\n background: transparent;\n border: none;\n border-radius: 0;\n padding: 0;\n margin: 0.5em 0;\n overflow-x: auto;\n }\n .markdown-content pre code {\n display: block;\n background: none;\n color: ${colors.mdCodeBlock};\n padding: 8px 12px;\n }\n .code-block-wrapper {\n margin: 0.5em 0;\n }\n .code-block-header {\n color: ${colors.mdCodeBlockBorder};\n font-size: 11px;\n }\n .code-block-footer {\n color: ${colors.mdCodeBlockBorder};\n font-size: 11px;\n }\n .markdown-content blockquote {\n border-left: 3px solid ${colors.mdQuoteBorder};\n padding-left: 12px;\n margin: 0.5em 0;\n color: ${colors.mdQuote};\n font-style: italic;\n }\n .markdown-content ul, .markdown-content ol {\n margin: 0.5em 0;\n padding-left: 24px;\n }\n .markdown-content li { margin: 0.25em 0; }\n .markdown-content li::marker { color: ${colors.mdListBullet}; }\n .markdown-content hr {\n border: none;\n border-top: 1px solid ${colors.mdHr};\n margin: 1em 0;\n }\n .markdown-content table {\n border-collapse: collapse;\n margin: 0.5em 0;\n width: 100%;\n }\n .markdown-content th, .markdown-content td {\n border: 1px solid ${colors.mdCodeBlockBorder};\n padding: 6px 10px;\n text-align: left;\n }\n .markdown-content th {\n background: rgba(${isLight ? \"0, 0, 0\" : \"255, 255, 255\"}, 0.05);\n font-weight: bold;\n }\n .markdown-content img {\n max-width: 100%;\n border-radius: 4px;\n }\n\n /* Syntax highlighting (highlight.js) */\n .hljs { background: transparent; }\n .hljs-comment, .hljs-quote { color: ${colors.syntaxComment}; }\n .hljs-keyword, .hljs-selector-tag, .hljs-addition { color: ${colors.syntaxKeyword}; }\n .hljs-number, .hljs-literal, .hljs-symbol, .hljs-bullet { color: ${colors.syntaxNumber}; }\n .hljs-string, .hljs-doctag, .hljs-regexp { color: ${colors.syntaxString}; }\n .hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class { color: ${colors.syntaxFunction}; }\n .hljs-type, .hljs-class, .hljs-built_in { color: ${colors.syntaxType}; }\n .hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-params { color: ${colors.syntaxVariable}; }\n .hljs-attribute { color: ${colors.syntaxVariable}; }\n .hljs-meta { color: ${colors.syntaxKeyword}; }\n .hljs-formula { background: rgba(${isLight ? \"0, 0, 0\" : \"255, 255, 255\"}, 0.05); }\n .hljs-deletion { color: ${colors.toolDiffRemoved}; }\n .hljs-emphasis { font-style: italic; }\n .hljs-strong { font-weight: bold; }\n .hljs-link { color: ${colors.mdLink}; text-decoration: underline; }\n\n @media print { body { background: white; color: black; } .tool-execution { border: 1px solid #ddd; } }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>${APP_NAME} v${VERSION}</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">Session:</span><span class=\"info-value\">${escapeHtml(data.sessionId)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Date:</span><span class=\"info-value\">${new Date(data.timestamp).toLocaleString()}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Models:</span><span class=\"info-value\">${\n\t\t\t\t\t\t\tArray.from(data.modelsUsed)\n\t\t\t\t\t\t\t\t.map((m) => escapeHtml(m))\n\t\t\t\t\t\t\t\t.join(\", \") || \"unknown\"\n\t\t\t\t\t\t}</span></div>\n </div>\n </div>\n\n <div class=\"header\">\n <h1>Messages</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">User:</span><span class=\"info-value\">${userMessages}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Assistant:</span><span class=\"info-value\">${assistantMessages}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Tool Calls:</span><span class=\"info-value\">${toolCallsCount}</span></div>\n </div>\n </div>\n\n <div class=\"header\">\n <h1>Tokens & Cost</h1>\n <div class=\"header-info\">\n <div class=\"info-item\"><span class=\"info-label\">Input:</span><span class=\"info-value\">${data.tokenStats.input.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Output:</span><span class=\"info-value\">${data.tokenStats.output.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Read:</span><span class=\"info-value\">${data.tokenStats.cacheRead.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Write:</span><span class=\"info-value\">${data.tokenStats.cacheWrite.toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Total:</span><span class=\"info-value\">${(data.tokenStats.input + data.tokenStats.output + data.tokenStats.cacheRead + data.tokenStats.cacheWrite).toLocaleString()} tokens</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Input Cost:</span><span class=\"info-value cost\">$${data.costStats.input.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Output Cost:</span><span class=\"info-value cost\">$${data.costStats.output.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Read Cost:</span><span class=\"info-value cost\">$${data.costStats.cacheRead.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Cache Write Cost:</span><span class=\"info-value cost\">$${data.costStats.cacheWrite.toFixed(4)}</span></div>\n <div class=\"info-item\"><span class=\"info-label\">Total Cost:</span><span class=\"info-value cost\"><strong>$${(data.costStats.input + data.costStats.output + data.costStats.cacheRead + data.costStats.cacheWrite).toFixed(4)}</strong></span></div>\n <div class=\"info-item\"><span class=\"info-label\">Context Usage:</span><span class=\"info-value\">${contextUsageText}</span></div>\n </div>\n </div>\n\n ${systemPromptHtml}\n ${toolsHtml}\n ${streamingNotice}\n\n <div class=\"messages\">\n ${messagesHtml}\n </div>\n\n <div class=\"footer\">\n Generated by ${APP_NAME} coding-agent on ${new Date().toLocaleString()}\n </div>\n </div>\n</body>\n</html>`;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport interface ExportOptions {\n\toutputPath?: string;\n\tthemeName?: string;\n}\n\n/**\n * Export session to HTML using SessionManager and AgentState.\n * Used by TUI's /export command.\n * @param sessionManager The session manager\n * @param state The agent state\n * @param options Export options including output path and theme name\n */\nexport function exportSessionToHtml(\n\tsessionManager: SessionManager,\n\tstate: AgentState,\n\toptions?: ExportOptions | string,\n): string {\n\t// Handle backwards compatibility: options can be just the output path string\n\tconst opts: ExportOptions = typeof options === \"string\" ? { outputPath: options } : options || {};\n\n\tconst sessionFile = sessionManager.getSessionFile();\n\tconst content = readFileSync(sessionFile, \"utf8\");\n\tconst data = parseSessionFile(content);\n\n\t// Enrich with data from AgentState (tools, context window)\n\tdata.tools = state.tools.map((t: { name: string; description: string }) => ({\n\t\tname: t.name,\n\t\tdescription: t.description,\n\t}));\n\tdata.contextWindow = state.model?.contextWindow;\n\tif (!data.systemPrompt) {\n\t\tdata.systemPrompt = state.systemPrompt;\n\t}\n\n\tlet outputPath = opts.outputPath;\n\tif (!outputPath) {\n\t\tconst sessionBasename = basename(sessionFile, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${sessionBasename}.html`;\n\t}\n\n\tconst colors = getThemeColors(opts.themeName);\n\tconst isLight = isLightTheme(opts.themeName);\n\tconst html = generateHtml(data, basename(sessionFile), colors, isLight);\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n\n/**\n * Export session file to HTML (standalone, without AgentState).\n * Auto-detects format: session manager format or streaming event format.\n * Used by CLI for exporting arbitrary session files.\n * @param inputPath Path to the session file\n * @param options Export options including output path and theme name\n */\nexport function exportFromFile(inputPath: string, options?: ExportOptions | string): string {\n\t// Handle backwards compatibility: options can be just the output path string\n\tconst opts: ExportOptions = typeof options === \"string\" ? { outputPath: options } : options || {};\n\n\tif (!existsSync(inputPath)) {\n\t\tthrow new Error(`File not found: ${inputPath}`);\n\t}\n\n\tconst content = readFileSync(inputPath, \"utf8\");\n\tconst data = parseSessionFile(content);\n\n\tlet outputPath = opts.outputPath;\n\tif (!outputPath) {\n\t\tconst inputBasename = basename(inputPath, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${inputBasename}.html`;\n\t}\n\n\tconst colors = getThemeColors(opts.themeName);\n\tconst isLight = isLightTheme(opts.themeName);\n\tconst html = generateHtml(data, basename(inputPath), colors, isLight);\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAGX,SAAS,EACT,SAAS,EAET,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAOpB;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AA4F3D;;GAEG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAqC;IAE3D,YAAY,KAAK,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAwB,EAO9E;IAED;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAG3D;IAED;;OAEG;IACH,YAAY,IAAI,MAAM,EAAE,CAEvB;IAED;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE/C;IAED;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAIzC;IAED;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAG/C;IAED;;OAEG;IACH,OAAO,CAAC,SAAS;IAMjB;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQtC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,qBAAqB,GAAG,SAAS,CAAC,CAuC5F;IAED;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAuBjF;CACD","sourcesContent":["/**\n * Hook runner - executes hooks and manages their lifecycle.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { LoadedHook, SendHandler } from \"./loader.js\";\nimport type {\n\tExecOptions,\n\tExecResult,\n\tHookError,\n\tHookEvent,\n\tHookEventContext,\n\tHookUIContext,\n\tSessionEventResult,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/**\n * Default timeout for hook execution (30 seconds).\n */\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Listener for hook errors.\n */\nexport type HookErrorListener = (error: HookError) => void;\n\n/**\n * Execute a command and return stdout/stderr/code.\n * Supports cancellation via AbortSignal and timeout.\n */\nasync function exec(command: string, args: string[], cwd: string, options?: ExecOptions): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, { cwd, shell: false });\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n\n/**\n * Create a promise that rejects after a timeout.\n */\nfunction createTimeout(ms: number): { promise: Promise<never>; clear: () => void } {\n\tlet timeoutId: NodeJS.Timeout;\n\tconst promise = new Promise<never>((_, reject) => {\n\t\ttimeoutId = setTimeout(() => reject(new Error(`Hook timed out after ${ms}ms`)), ms);\n\t});\n\treturn {\n\t\tpromise,\n\t\tclear: () => clearTimeout(timeoutId),\n\t};\n}\n\n/** No-op UI context used when no UI is available */\nconst noOpUIContext: HookUIContext = {\n\tselect: async () => null,\n\tconfirm: async () => false,\n\tinput: async () => null,\n\tnotify: () => {},\n};\n\n/**\n * HookRunner executes hooks and manages event emission.\n */\nexport class HookRunner {\n\tprivate hooks: LoadedHook[];\n\tprivate uiContext: HookUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionFile: string | null;\n\tprivate timeout: number;\n\tprivate errorListeners: Set<HookErrorListener> = new Set();\n\n\tconstructor(hooks: LoadedHook[], cwd: string, timeout: number = DEFAULT_TIMEOUT) {\n\t\tthis.hooks = hooks;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionFile = null;\n\t\tthis.timeout = timeout;\n\t}\n\n\t/**\n\t * Set the UI context for hooks.\n\t * Call this when the mode initializes and UI is available.\n\t */\n\tsetUIContext(uiContext: HookUIContext, hasUI: boolean): void {\n\t\tthis.uiContext = uiContext;\n\t\tthis.hasUI = hasUI;\n\t}\n\n\t/**\n\t * Get the paths of all loaded hooks.\n\t */\n\tgetHookPaths(): string[] {\n\t\treturn this.hooks.map((h) => h.path);\n\t}\n\n\t/**\n\t * Set the session file path.\n\t */\n\tsetSessionFile(sessionFile: string | null): void {\n\t\tthis.sessionFile = sessionFile;\n\t}\n\n\t/**\n\t * Set the send handler for all hooks' pi.send().\n\t * Call this when the mode initializes.\n\t */\n\tsetSendHandler(handler: SendHandler): void {\n\t\tfor (const hook of this.hooks) {\n\t\t\thook.setSendHandler(handler);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to hook errors.\n\t * @returns Unsubscribe function\n\t */\n\tonError(listener: HookErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\t/**\n\t * Emit an error to all listeners.\n\t */\n\tprivate emitError(error: HookError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\t/**\n\t * Check if any hooks have handlers for the given event type.\n\t */\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Create the event context for handlers.\n\t */\n\tprivate createContext(): HookEventContext {\n\t\treturn {\n\t\t\texec: (command: string, args: string[], options?: ExecOptions) => exec(command, args, this.cwd, options),\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionFile: this.sessionFile,\n\t\t};\n\t}\n\n\t/**\n\t * Emit an event to all hooks.\n\t * Returns the result from session/tool_result events (if any handler returns one).\n\t */\n\tasync emit(event: HookEvent): Promise<SessionEventResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionEventResult | ToolResultEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst timeout = createTimeout(this.timeout);\n\t\t\t\t\tconst handlerResult = await Promise.race([handler(event, ctx), timeout.promise]);\n\t\t\t\t\ttimeout.clear();\n\n\t\t\t\t\t// For session events, capture the result (for before_* cancellation)\n\t\t\t\t\tif (event.type === \"session\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionEventResult;\n\t\t\t\t\t\t// If cancelled, stop processing further hooks\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// For tool_result events, capture the result\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\thookPath: hook.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Emit a tool_call event to all hooks.\n\t * No timeout - user prompts can take as long as needed.\n\t * Errors are thrown (not swallowed) so caller can block on failure.\n\t */\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\t// No timeout - let user take their time\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\t// If blocked, stop processing further hooks\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAGX,SAAS,EACT,SAAS,EAET,aAAa,EAEb,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAOpB;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AA4F3D;;GAEG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAqC;IAE3D,YAAY,KAAK,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAwB,EAO9E;IAED;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAG3D;IAED;;OAEG;IACH,YAAY,IAAI,MAAM,EAAE,CAEvB;IAED;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE/C;IAED;;;OAGG;IACH,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAIzC;IAED;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAG/C;IAED;;OAEG;IACH,OAAO,CAAC,SAAS;IAMjB;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQtC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,qBAAqB,GAAG,SAAS,CAAC,CA+C5F;IAED;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAuBjF;CACD","sourcesContent":["/**\n * Hook runner - executes hooks and manages their lifecycle.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { LoadedHook, SendHandler } from \"./loader.js\";\nimport type {\n\tExecOptions,\n\tExecResult,\n\tHookError,\n\tHookEvent,\n\tHookEventContext,\n\tHookUIContext,\n\tSessionEvent,\n\tSessionEventResult,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/**\n * Default timeout for hook execution (30 seconds).\n */\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Listener for hook errors.\n */\nexport type HookErrorListener = (error: HookError) => void;\n\n/**\n * Execute a command and return stdout/stderr/code.\n * Supports cancellation via AbortSignal and timeout.\n */\nasync function exec(command: string, args: string[], cwd: string, options?: ExecOptions): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, { cwd, shell: false });\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n\n/**\n * Create a promise that rejects after a timeout.\n */\nfunction createTimeout(ms: number): { promise: Promise<never>; clear: () => void } {\n\tlet timeoutId: NodeJS.Timeout;\n\tconst promise = new Promise<never>((_, reject) => {\n\t\ttimeoutId = setTimeout(() => reject(new Error(`Hook timed out after ${ms}ms`)), ms);\n\t});\n\treturn {\n\t\tpromise,\n\t\tclear: () => clearTimeout(timeoutId),\n\t};\n}\n\n/** No-op UI context used when no UI is available */\nconst noOpUIContext: HookUIContext = {\n\tselect: async () => null,\n\tconfirm: async () => false,\n\tinput: async () => null,\n\tnotify: () => {},\n};\n\n/**\n * HookRunner executes hooks and manages event emission.\n */\nexport class HookRunner {\n\tprivate hooks: LoadedHook[];\n\tprivate uiContext: HookUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionFile: string | null;\n\tprivate timeout: number;\n\tprivate errorListeners: Set<HookErrorListener> = new Set();\n\n\tconstructor(hooks: LoadedHook[], cwd: string, timeout: number = DEFAULT_TIMEOUT) {\n\t\tthis.hooks = hooks;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionFile = null;\n\t\tthis.timeout = timeout;\n\t}\n\n\t/**\n\t * Set the UI context for hooks.\n\t * Call this when the mode initializes and UI is available.\n\t */\n\tsetUIContext(uiContext: HookUIContext, hasUI: boolean): void {\n\t\tthis.uiContext = uiContext;\n\t\tthis.hasUI = hasUI;\n\t}\n\n\t/**\n\t * Get the paths of all loaded hooks.\n\t */\n\tgetHookPaths(): string[] {\n\t\treturn this.hooks.map((h) => h.path);\n\t}\n\n\t/**\n\t * Set the session file path.\n\t */\n\tsetSessionFile(sessionFile: string | null): void {\n\t\tthis.sessionFile = sessionFile;\n\t}\n\n\t/**\n\t * Set the send handler for all hooks' pi.send().\n\t * Call this when the mode initializes.\n\t */\n\tsetSendHandler(handler: SendHandler): void {\n\t\tfor (const hook of this.hooks) {\n\t\t\thook.setSendHandler(handler);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to hook errors.\n\t * @returns Unsubscribe function\n\t */\n\tonError(listener: HookErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\t/**\n\t * Emit an error to all listeners.\n\t */\n\tprivate emitError(error: HookError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\t/**\n\t * Check if any hooks have handlers for the given event type.\n\t */\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Create the event context for handlers.\n\t */\n\tprivate createContext(): HookEventContext {\n\t\treturn {\n\t\t\texec: (command: string, args: string[], options?: ExecOptions) => exec(command, args, this.cwd, options),\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionFile: this.sessionFile,\n\t\t};\n\t}\n\n\t/**\n\t * Emit an event to all hooks.\n\t * Returns the result from session/tool_result events (if any handler returns one).\n\t */\n\tasync emit(event: HookEvent): Promise<SessionEventResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionEventResult | ToolResultEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\t// No timeout for before_compact events (like tool_call, they may take a while)\n\t\t\t\t\tconst isBeforeCompact = event.type === \"session\" && (event as SessionEvent).reason === \"before_compact\";\n\t\t\t\t\tlet handlerResult: unknown;\n\n\t\t\t\t\tif (isBeforeCompact) {\n\t\t\t\t\t\thandlerResult = await handler(event, ctx);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst timeout = createTimeout(this.timeout);\n\t\t\t\t\t\thandlerResult = await Promise.race([handler(event, ctx), timeout.promise]);\n\t\t\t\t\t\ttimeout.clear();\n\t\t\t\t\t}\n\n\t\t\t\t\t// For session events, capture the result (for before_* cancellation)\n\t\t\t\t\tif (event.type === \"session\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionEventResult;\n\t\t\t\t\t\t// If cancelled, stop processing further hooks\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// For tool_result events, capture the result\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\thookPath: hook.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Emit a tool_call event to all hooks.\n\t * No timeout - user prompts can take as long as needed.\n\t * Errors are thrown (not swallowed) so caller can block on failure.\n\t */\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\t// No timeout - let user take their time\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\t// If blocked, stop processing further hooks\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
@@ -189,9 +189,17 @@ export class HookRunner {
189
189
  continue;
190
190
  for (const handler of handlers) {
191
191
  try {
192
- const timeout = createTimeout(this.timeout);
193
- const handlerResult = await Promise.race([handler(event, ctx), timeout.promise]);
194
- timeout.clear();
192
+ // No timeout for before_compact events (like tool_call, they may take a while)
193
+ const isBeforeCompact = event.type === "session" && event.reason === "before_compact";
194
+ let handlerResult;
195
+ if (isBeforeCompact) {
196
+ handlerResult = await handler(event, ctx);
197
+ }
198
+ else {
199
+ const timeout = createTimeout(this.timeout);
200
+ handlerResult = await Promise.race([handler(event, ctx), timeout.promise]);
201
+ timeout.clear();
202
+ }
195
203
  // For session events, capture the result (for before_* cancellation)
196
204
  if (event.type === "session" && handlerResult) {
197
205
  result = handlerResult;
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/core/hooks/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hook runner - executes hooks and manages their lifecycle.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { LoadedHook, SendHandler } from \"./loader.js\";\nimport type {\n\tExecOptions,\n\tExecResult,\n\tHookError,\n\tHookEvent,\n\tHookEventContext,\n\tHookUIContext,\n\tSessionEventResult,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/**\n * Default timeout for hook execution (30 seconds).\n */\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Listener for hook errors.\n */\nexport type HookErrorListener = (error: HookError) => void;\n\n/**\n * Execute a command and return stdout/stderr/code.\n * Supports cancellation via AbortSignal and timeout.\n */\nasync function exec(command: string, args: string[], cwd: string, options?: ExecOptions): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, { cwd, shell: false });\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n\n/**\n * Create a promise that rejects after a timeout.\n */\nfunction createTimeout(ms: number): { promise: Promise<never>; clear: () => void } {\n\tlet timeoutId: NodeJS.Timeout;\n\tconst promise = new Promise<never>((_, reject) => {\n\t\ttimeoutId = setTimeout(() => reject(new Error(`Hook timed out after ${ms}ms`)), ms);\n\t});\n\treturn {\n\t\tpromise,\n\t\tclear: () => clearTimeout(timeoutId),\n\t};\n}\n\n/** No-op UI context used when no UI is available */\nconst noOpUIContext: HookUIContext = {\n\tselect: async () => null,\n\tconfirm: async () => false,\n\tinput: async () => null,\n\tnotify: () => {},\n};\n\n/**\n * HookRunner executes hooks and manages event emission.\n */\nexport class HookRunner {\n\tprivate hooks: LoadedHook[];\n\tprivate uiContext: HookUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionFile: string | null;\n\tprivate timeout: number;\n\tprivate errorListeners: Set<HookErrorListener> = new Set();\n\n\tconstructor(hooks: LoadedHook[], cwd: string, timeout: number = DEFAULT_TIMEOUT) {\n\t\tthis.hooks = hooks;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionFile = null;\n\t\tthis.timeout = timeout;\n\t}\n\n\t/**\n\t * Set the UI context for hooks.\n\t * Call this when the mode initializes and UI is available.\n\t */\n\tsetUIContext(uiContext: HookUIContext, hasUI: boolean): void {\n\t\tthis.uiContext = uiContext;\n\t\tthis.hasUI = hasUI;\n\t}\n\n\t/**\n\t * Get the paths of all loaded hooks.\n\t */\n\tgetHookPaths(): string[] {\n\t\treturn this.hooks.map((h) => h.path);\n\t}\n\n\t/**\n\t * Set the session file path.\n\t */\n\tsetSessionFile(sessionFile: string | null): void {\n\t\tthis.sessionFile = sessionFile;\n\t}\n\n\t/**\n\t * Set the send handler for all hooks' pi.send().\n\t * Call this when the mode initializes.\n\t */\n\tsetSendHandler(handler: SendHandler): void {\n\t\tfor (const hook of this.hooks) {\n\t\t\thook.setSendHandler(handler);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to hook errors.\n\t * @returns Unsubscribe function\n\t */\n\tonError(listener: HookErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\t/**\n\t * Emit an error to all listeners.\n\t */\n\tprivate emitError(error: HookError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\t/**\n\t * Check if any hooks have handlers for the given event type.\n\t */\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Create the event context for handlers.\n\t */\n\tprivate createContext(): HookEventContext {\n\t\treturn {\n\t\t\texec: (command: string, args: string[], options?: ExecOptions) => exec(command, args, this.cwd, options),\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionFile: this.sessionFile,\n\t\t};\n\t}\n\n\t/**\n\t * Emit an event to all hooks.\n\t * Returns the result from session/tool_result events (if any handler returns one).\n\t */\n\tasync emit(event: HookEvent): Promise<SessionEventResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionEventResult | ToolResultEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst timeout = createTimeout(this.timeout);\n\t\t\t\t\tconst handlerResult = await Promise.race([handler(event, ctx), timeout.promise]);\n\t\t\t\t\ttimeout.clear();\n\n\t\t\t\t\t// For session events, capture the result (for before_* cancellation)\n\t\t\t\t\tif (event.type === \"session\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionEventResult;\n\t\t\t\t\t\t// If cancelled, stop processing further hooks\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// For tool_result events, capture the result\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\thookPath: hook.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Emit a tool_call event to all hooks.\n\t * No timeout - user prompts can take as long as needed.\n\t * Errors are thrown (not swallowed) so caller can block on failure.\n\t */\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\t// No timeout - let user take their time\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\t// If blocked, stop processing further hooks\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/core/hooks/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hook runner - executes hooks and manages their lifecycle.\n */\n\nimport { spawn } from \"node:child_process\";\nimport type { LoadedHook, SendHandler } from \"./loader.js\";\nimport type {\n\tExecOptions,\n\tExecResult,\n\tHookError,\n\tHookEvent,\n\tHookEventContext,\n\tHookUIContext,\n\tSessionEvent,\n\tSessionEventResult,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/**\n * Default timeout for hook execution (30 seconds).\n */\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Listener for hook errors.\n */\nexport type HookErrorListener = (error: HookError) => void;\n\n/**\n * Execute a command and return stdout/stderr/code.\n * Supports cancellation via AbortSignal and timeout.\n */\nasync function exec(command: string, args: string[], cwd: string, options?: ExecOptions): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, { cwd, shell: false });\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n\n/**\n * Create a promise that rejects after a timeout.\n */\nfunction createTimeout(ms: number): { promise: Promise<never>; clear: () => void } {\n\tlet timeoutId: NodeJS.Timeout;\n\tconst promise = new Promise<never>((_, reject) => {\n\t\ttimeoutId = setTimeout(() => reject(new Error(`Hook timed out after ${ms}ms`)), ms);\n\t});\n\treturn {\n\t\tpromise,\n\t\tclear: () => clearTimeout(timeoutId),\n\t};\n}\n\n/** No-op UI context used when no UI is available */\nconst noOpUIContext: HookUIContext = {\n\tselect: async () => null,\n\tconfirm: async () => false,\n\tinput: async () => null,\n\tnotify: () => {},\n};\n\n/**\n * HookRunner executes hooks and manages event emission.\n */\nexport class HookRunner {\n\tprivate hooks: LoadedHook[];\n\tprivate uiContext: HookUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionFile: string | null;\n\tprivate timeout: number;\n\tprivate errorListeners: Set<HookErrorListener> = new Set();\n\n\tconstructor(hooks: LoadedHook[], cwd: string, timeout: number = DEFAULT_TIMEOUT) {\n\t\tthis.hooks = hooks;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionFile = null;\n\t\tthis.timeout = timeout;\n\t}\n\n\t/**\n\t * Set the UI context for hooks.\n\t * Call this when the mode initializes and UI is available.\n\t */\n\tsetUIContext(uiContext: HookUIContext, hasUI: boolean): void {\n\t\tthis.uiContext = uiContext;\n\t\tthis.hasUI = hasUI;\n\t}\n\n\t/**\n\t * Get the paths of all loaded hooks.\n\t */\n\tgetHookPaths(): string[] {\n\t\treturn this.hooks.map((h) => h.path);\n\t}\n\n\t/**\n\t * Set the session file path.\n\t */\n\tsetSessionFile(sessionFile: string | null): void {\n\t\tthis.sessionFile = sessionFile;\n\t}\n\n\t/**\n\t * Set the send handler for all hooks' pi.send().\n\t * Call this when the mode initializes.\n\t */\n\tsetSendHandler(handler: SendHandler): void {\n\t\tfor (const hook of this.hooks) {\n\t\t\thook.setSendHandler(handler);\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to hook errors.\n\t * @returns Unsubscribe function\n\t */\n\tonError(listener: HookErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\t/**\n\t * Emit an error to all listeners.\n\t */\n\tprivate emitError(error: HookError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\t/**\n\t * Check if any hooks have handlers for the given event type.\n\t */\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Create the event context for handlers.\n\t */\n\tprivate createContext(): HookEventContext {\n\t\treturn {\n\t\t\texec: (command: string, args: string[], options?: ExecOptions) => exec(command, args, this.cwd, options),\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionFile: this.sessionFile,\n\t\t};\n\t}\n\n\t/**\n\t * Emit an event to all hooks.\n\t * Returns the result from session/tool_result events (if any handler returns one).\n\t */\n\tasync emit(event: HookEvent): Promise<SessionEventResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionEventResult | ToolResultEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\t// No timeout for before_compact events (like tool_call, they may take a while)\n\t\t\t\t\tconst isBeforeCompact = event.type === \"session\" && (event as SessionEvent).reason === \"before_compact\";\n\t\t\t\t\tlet handlerResult: unknown;\n\n\t\t\t\t\tif (isBeforeCompact) {\n\t\t\t\t\t\thandlerResult = await handler(event, ctx);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst timeout = createTimeout(this.timeout);\n\t\t\t\t\t\thandlerResult = await Promise.race([handler(event, ctx), timeout.promise]);\n\t\t\t\t\t\ttimeout.clear();\n\t\t\t\t\t}\n\n\t\t\t\t\t// For session events, capture the result (for before_* cancellation)\n\t\t\t\t\tif (event.type === \"session\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionEventResult;\n\t\t\t\t\t\t// If cancelled, stop processing further hooks\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// For tool_result events, capture the result\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\thookPath: hook.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Emit a tool_call event to all hooks.\n\t * No timeout - user prompts can take as long as needed.\n\t * Errors are thrown (not swallowed) so caller can block on failure.\n\t */\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const hook of this.hooks) {\n\t\t\tconst handlers = hook.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\t// No timeout - let user take their time\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\t// If blocked, stop processing further hooks\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
@@ -5,8 +5,9 @@
5
5
  * and interact with the user via UI primitives.
6
6
  */
7
7
  import type { AppMessage, Attachment } from "@mariozechner/pi-agent-core";
8
- import type { ImageContent, TextContent, ToolResultMessage } from "@mariozechner/pi-ai";
9
- import type { SessionEntry } from "../session-manager.js";
8
+ import type { ImageContent, Model, TextContent, ToolResultMessage } from "@mariozechner/pi-ai";
9
+ import type { CutPointResult } from "../compaction.js";
10
+ import type { CompactionEntry, SessionEntry } from "../session-manager.js";
10
11
  import type { BashToolDetails, FindToolDetails, GrepToolDetails, LsToolDetails, ReadToolDetails } from "../tools/index.js";
11
12
  /**
12
13
  * Result of executing a command via ctx.exec()
@@ -87,6 +88,7 @@ interface SessionEventBase {
87
88
  * - before_switch / switch: Session switch (e.g., /resume command)
88
89
  * - before_clear / clear: Session clear (e.g., /clear command)
89
90
  * - before_branch / branch: Session branch (e.g., /branch command)
91
+ * - before_compact / compact: Before/after context compaction
90
92
  * - shutdown: Process exit (SIGINT/SIGTERM)
91
93
  *
92
94
  * "before_*" events fire before the action and can be cancelled via SessionEventResult.
@@ -98,6 +100,28 @@ export type SessionEvent = (SessionEventBase & {
98
100
  reason: "branch" | "before_branch";
99
101
  /** Index of the turn to branch from */
100
102
  targetTurnIndex: number;
103
+ }) | (SessionEventBase & {
104
+ reason: "before_compact";
105
+ cutPoint: CutPointResult;
106
+ /** Summary from previous compaction, if any. Include this in your summary to preserve context. */
107
+ previousSummary?: string;
108
+ /** Messages that will be summarized and discarded */
109
+ messagesToSummarize: AppMessage[];
110
+ /** Messages that will be kept after the summary (recent turns) */
111
+ messagesToKeep: AppMessage[];
112
+ tokensBefore: number;
113
+ customInstructions?: string;
114
+ model: Model<any>;
115
+ /** Resolve API key for any model (checks settings, OAuth, env vars) */
116
+ resolveApiKey: (model: Model<any>) => Promise<string | undefined>;
117
+ /** Abort signal - hooks should pass this to LLM calls and check it periodically */
118
+ signal: AbortSignal;
119
+ }) | (SessionEventBase & {
120
+ reason: "compact";
121
+ compactionEntry: CompactionEntry;
122
+ tokensBefore: number;
123
+ /** Whether the compaction entry was provided by a hook */
124
+ fromHook: boolean;
101
125
  });
102
126
  /**
103
127
  * Event data for agent_start event.
@@ -245,6 +269,8 @@ export interface SessionEventResult {
245
269
  cancel?: boolean;
246
270
  /** If true (for before_branch only), skip restoring conversation to branch point while still creating the branched session file */
247
271
  skipConversationRestore?: boolean;
272
+ /** Custom compaction entry (for before_compact event) */
273
+ compactionEntry?: CompactionEntry;
248
274
  }
249
275
  /**
250
276
  * Handler function type for each event.