@mariozechner/pi-coding-agent 0.25.3 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +47 -5
- package/dist/cli/session-picker.d.ts +2 -2
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +2 -2
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -13
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction.d.ts.map +1 -1
- package/dist/core/compaction.js +1 -1
- package/dist/core/compaction.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts +3 -2
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +5 -4
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/export-html.d.ts.map +1 -1
- package/dist/core/export-html.js +1 -1
- package/dist/core/export-html.js.map +1 -1
- package/dist/core/hooks/loader.d.ts +2 -5
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +4 -7
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +1 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -4
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +12 -19
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/sdk.d.ts +211 -0
- package/dist/core/sdk.d.ts.map +1 -0
- package/dist/core/sdk.js +462 -0
- package/dist/core/sdk.js.map +1 -0
- package/dist/core/session-manager.d.ts +31 -91
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +188 -353
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +101 -37
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +7 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +7 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +9 -3
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +12 -9
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +24 -2
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +18 -16
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +12 -22
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +2 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +0 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +4 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +142 -312
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +2 -2
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +3 -3
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +6 -6
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-selector.js +1 -1
- package/dist/modes/interactive/components/hook-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +3 -12
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +1 -3
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +14 -14
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -6
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -6
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +2 -2
- package/dist/utils/shell.js.map +1 -1
- package/docs/sdk.md +819 -0
- package/examples/README.md +29 -0
- package/examples/sdk/01-minimal.ts +22 -0
- package/examples/sdk/02-custom-model.ts +36 -0
- package/examples/sdk/03-custom-prompt.ts +44 -0
- package/examples/sdk/04-skills.ts +44 -0
- package/examples/sdk/05-tools.ts +67 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +36 -0
- package/examples/sdk/08-slash-commands.ts +37 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +45 -0
- package/examples/sdk/10-settings.ts +38 -0
- package/examples/sdk/11-sessions.ts +46 -0
- package/examples/sdk/12-full-control.ts +91 -0
- package/examples/sdk/README.md +138 -0
- package/package.json +4 -4
|
@@ -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, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\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, 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, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\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"]}
|
|
@@ -43,14 +43,11 @@ export interface LoadHooksResult {
|
|
|
43
43
|
export declare function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult>;
|
|
44
44
|
/**
|
|
45
45
|
* Discover and load hooks from standard locations:
|
|
46
|
-
* 1.
|
|
46
|
+
* 1. agentDir/hooks/*.ts (global)
|
|
47
47
|
* 2. cwd/.pi/hooks/*.ts (project-local)
|
|
48
48
|
*
|
|
49
49
|
* Plus any explicitly configured paths from settings.
|
|
50
|
-
*
|
|
51
|
-
* @param configuredPaths - Explicit paths from settings.json
|
|
52
|
-
* @param cwd - Current working directory
|
|
53
50
|
*/
|
|
54
|
-
export declare function discoverAndLoadHooks(configuredPaths: string[], cwd: string): Promise<LoadHooksResult>;
|
|
51
|
+
export declare function discoverAndLoadHooks(configuredPaths: string[], cwd: string, agentDir?: string): Promise<LoadHooksResult>;
|
|
55
52
|
export {};
|
|
56
53
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AA0B9D;;GAEG;AACH,KAAK,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACnC,qDAAqD;IACrD,cAAc,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,gCAAgC;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,wCAAwC;IACxC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C;AA0GD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBtF;AAqBD
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AA0B9D;;GAEG;AACH,KAAK,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACnC,qDAAqD;IACrD,cAAc,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,gCAAgC;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,wCAAwC;IACxC,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C;AA0GD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBtF;AAqBD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACzC,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CA2B1B","sourcesContent":["/**\n * Hook loader - loads TypeScript hook modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir } from \"../../config.js\";\nimport type { HookAPI, HookFactory } from \"./types.js\";\n\n// Create require function to resolve module paths at runtime\nconst require = createRequire(import.meta.url);\n\n// Lazily computed aliases - resolved at runtime to handle global installs\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/hooks\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": require.resolve(\"@sinclair/typebox\"),\n\t};\n\treturn _aliases;\n}\n\n/**\n * Generic handler function type.\n */\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Send handler type for pi.send().\n */\nexport type SendHandler = (text: string, attachments?: Attachment[]) => void;\n\n/**\n * Registered handlers for a loaded hook.\n */\nexport interface LoadedHook {\n\t/** Original path from config */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** Map of event type to handler functions */\n\thandlers: Map<string, HandlerFn[]>;\n\t/** Set the send handler for this hook's pi.send() */\n\tsetSendHandler: (handler: SendHandler) => void;\n}\n\n/**\n * Result of loading hooks.\n */\nexport interface LoadHooksResult {\n\t/** Successfully loaded hooks */\n\thooks: LoadedHook[];\n\t/** Errors encountered during loading */\n\terrors: Array<{ path: string; error: string }>;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\n/**\n * Resolve hook path.\n * - Absolute paths used as-is\n * - Paths starting with ~ expanded to home directory\n * - Relative paths resolved from cwd\n */\nfunction resolveHookPath(hookPath: string, cwd: string): string {\n\tconst expanded = expandPath(hookPath);\n\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\n\t// Relative paths resolved from cwd\n\treturn path.resolve(cwd, expanded);\n}\n\n/**\n * Create a HookAPI instance that collects handlers.\n * Returns the API and a function to set the send handler later.\n */\nfunction createHookAPI(handlers: Map<string, HandlerFn[]>): {\n\tapi: HookAPI;\n\tsetSendHandler: (handler: SendHandler) => void;\n} {\n\tlet sendHandler: SendHandler = () => {\n\t\t// Default no-op until mode sets the handler\n\t};\n\n\tconst api: HookAPI = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\t\tsend(text: string, attachments?: Attachment[]): void {\n\t\t\tsendHandler(text, attachments);\n\t\t},\n\t} as HookAPI;\n\n\treturn {\n\t\tapi,\n\t\tsetSendHandler: (handler: SendHandler) => {\n\t\t\tsendHandler = handler;\n\t\t},\n\t};\n}\n\n/**\n * Load a single hook module using jiti.\n */\nasync function loadHook(hookPath: string, cwd: string): Promise<{ hook: LoadedHook | null; error: string | null }> {\n\tconst resolvedPath = resolveHookPath(hookPath, cwd);\n\n\ttry {\n\t\t// Create jiti instance for TypeScript/ESM loading\n\t\t// Use aliases to resolve package imports since hooks are loaded from user directories\n\t\t// (e.g. ~/.pi/agent/hooks) but import from packages installed with pi-coding-agent\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\t// Import the module\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as HookFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { hook: null, error: \"Hook must export a default function\" };\n\t\t}\n\n\t\t// Create handlers map and API\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst { api, setSendHandler } = createHookAPI(handlers);\n\n\t\t// Call factory to register handlers\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\thook: { path: hookPath, resolvedPath, handlers, setSendHandler },\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { hook: null, error: `Failed to load hook: ${message}` };\n\t}\n}\n\n/**\n * Load all hooks from configuration.\n * @param paths - Array of hook file paths\n * @param cwd - Current working directory for resolving relative paths\n */\nexport async function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult> {\n\tconst hooks: LoadedHook[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const hookPath of paths) {\n\t\tconst { hook, error } = await loadHook(hookPath, cwd);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: hookPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hook) {\n\t\t\thooks.push(hook);\n\t\t}\n\t}\n\n\treturn { hooks, errors };\n}\n\n/**\n * Discover hook files from a directory.\n * Returns all .ts files (and symlinks to .ts files) in the directory (non-recursive).\n */\nfunction discoverHooksInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\t\treturn entries\n\t\t\t.filter((e) => (e.isFile() || e.isSymbolicLink()) && e.name.endsWith(\".ts\"))\n\t\t\t.map((e) => path.join(dir, e.name));\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Discover and load hooks from standard locations:\n * 1. agentDir/hooks/*.ts (global)\n * 2. cwd/.pi/hooks/*.ts (project-local)\n *\n * Plus any explicitly configured paths from settings.\n */\nexport async function discoverAndLoadHooks(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n): Promise<LoadHooksResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Helper to add paths without duplicates\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global hooks: agentDir/hooks/\n\tconst globalHooksDir = path.join(agentDir, \"hooks\");\n\taddPaths(discoverHooksInDir(globalHooksDir));\n\n\t// 2. Project-local hooks: cwd/.pi/hooks/\n\tconst localHooksDir = path.join(cwd, \".pi\", \"hooks\");\n\taddPaths(discoverHooksInDir(localHooksDir));\n\n\t// 3. Explicitly configured paths (can override/add)\n\taddPaths(configuredPaths.map((p) => resolveHookPath(p, cwd)));\n\n\treturn loadHooks(allPaths, cwd);\n}\n"]}
|
|
@@ -152,15 +152,12 @@ function discoverHooksInDir(dir) {
|
|
|
152
152
|
}
|
|
153
153
|
/**
|
|
154
154
|
* Discover and load hooks from standard locations:
|
|
155
|
-
* 1.
|
|
155
|
+
* 1. agentDir/hooks/*.ts (global)
|
|
156
156
|
* 2. cwd/.pi/hooks/*.ts (project-local)
|
|
157
157
|
*
|
|
158
158
|
* Plus any explicitly configured paths from settings.
|
|
159
|
-
*
|
|
160
|
-
* @param configuredPaths - Explicit paths from settings.json
|
|
161
|
-
* @param cwd - Current working directory
|
|
162
159
|
*/
|
|
163
|
-
export async function discoverAndLoadHooks(configuredPaths, cwd) {
|
|
160
|
+
export async function discoverAndLoadHooks(configuredPaths, cwd, agentDir = getAgentDir()) {
|
|
164
161
|
const allPaths = [];
|
|
165
162
|
const seen = new Set();
|
|
166
163
|
// Helper to add paths without duplicates
|
|
@@ -173,8 +170,8 @@ export async function discoverAndLoadHooks(configuredPaths, cwd) {
|
|
|
173
170
|
}
|
|
174
171
|
}
|
|
175
172
|
};
|
|
176
|
-
// 1. Global hooks:
|
|
177
|
-
const globalHooksDir = path.join(
|
|
173
|
+
// 1. Global hooks: agentDir/hooks/
|
|
174
|
+
const globalHooksDir = path.join(agentDir, "hooks");
|
|
178
175
|
addPaths(discoverHooksInDir(globalHooksDir));
|
|
179
176
|
// 2. Project-local hooks: cwd/.pi/hooks/
|
|
180
177
|
const localHooksDir = path.join(cwd, ".pi", "hooks");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/hooks/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hook loader - loads TypeScript hook modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir } from \"../../config.js\";\nimport type { HookAPI, HookFactory } from \"./types.js\";\n\n// Create require function to resolve module paths at runtime\nconst require = createRequire(import.meta.url);\n\n// Lazily computed aliases - resolved at runtime to handle global installs\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/hooks\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": require.resolve(\"@sinclair/typebox\"),\n\t};\n\treturn _aliases;\n}\n\n/**\n * Generic handler function type.\n */\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Send handler type for pi.send().\n */\nexport type SendHandler = (text: string, attachments?: Attachment[]) => void;\n\n/**\n * Registered handlers for a loaded hook.\n */\nexport interface LoadedHook {\n\t/** Original path from config */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** Map of event type to handler functions */\n\thandlers: Map<string, HandlerFn[]>;\n\t/** Set the send handler for this hook's pi.send() */\n\tsetSendHandler: (handler: SendHandler) => void;\n}\n\n/**\n * Result of loading hooks.\n */\nexport interface LoadHooksResult {\n\t/** Successfully loaded hooks */\n\thooks: LoadedHook[];\n\t/** Errors encountered during loading */\n\terrors: Array<{ path: string; error: string }>;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\n/**\n * Resolve hook path.\n * - Absolute paths used as-is\n * - Paths starting with ~ expanded to home directory\n * - Relative paths resolved from cwd\n */\nfunction resolveHookPath(hookPath: string, cwd: string): string {\n\tconst expanded = expandPath(hookPath);\n\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\n\t// Relative paths resolved from cwd\n\treturn path.resolve(cwd, expanded);\n}\n\n/**\n * Create a HookAPI instance that collects handlers.\n * Returns the API and a function to set the send handler later.\n */\nfunction createHookAPI(handlers: Map<string, HandlerFn[]>): {\n\tapi: HookAPI;\n\tsetSendHandler: (handler: SendHandler) => void;\n} {\n\tlet sendHandler: SendHandler = () => {\n\t\t// Default no-op until mode sets the handler\n\t};\n\n\tconst api: HookAPI = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\t\tsend(text: string, attachments?: Attachment[]): void {\n\t\t\tsendHandler(text, attachments);\n\t\t},\n\t} as HookAPI;\n\n\treturn {\n\t\tapi,\n\t\tsetSendHandler: (handler: SendHandler) => {\n\t\t\tsendHandler = handler;\n\t\t},\n\t};\n}\n\n/**\n * Load a single hook module using jiti.\n */\nasync function loadHook(hookPath: string, cwd: string): Promise<{ hook: LoadedHook | null; error: string | null }> {\n\tconst resolvedPath = resolveHookPath(hookPath, cwd);\n\n\ttry {\n\t\t// Create jiti instance for TypeScript/ESM loading\n\t\t// Use aliases to resolve package imports since hooks are loaded from user directories\n\t\t// (e.g. ~/.pi/agent/hooks) but import from packages installed with pi-coding-agent\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\t// Import the module\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as HookFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { hook: null, error: \"Hook must export a default function\" };\n\t\t}\n\n\t\t// Create handlers map and API\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst { api, setSendHandler } = createHookAPI(handlers);\n\n\t\t// Call factory to register handlers\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\thook: { path: hookPath, resolvedPath, handlers, setSendHandler },\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { hook: null, error: `Failed to load hook: ${message}` };\n\t}\n}\n\n/**\n * Load all hooks from configuration.\n * @param paths - Array of hook file paths\n * @param cwd - Current working directory for resolving relative paths\n */\nexport async function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult> {\n\tconst hooks: LoadedHook[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const hookPath of paths) {\n\t\tconst { hook, error } = await loadHook(hookPath, cwd);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: hookPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hook) {\n\t\t\thooks.push(hook);\n\t\t}\n\t}\n\n\treturn { hooks, errors };\n}\n\n/**\n * Discover hook files from a directory.\n * Returns all .ts files (and symlinks to .ts files) in the directory (non-recursive).\n */\nfunction discoverHooksInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\t\treturn entries\n\t\t\t.filter((e) => (e.isFile() || e.isSymbolicLink()) && e.name.endsWith(\".ts\"))\n\t\t\t.map((e) => path.join(dir, e.name));\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Discover and load hooks from standard locations:\n * 1. ~/.pi/agent/hooks/*.ts (global)\n * 2. cwd/.pi/hooks/*.ts (project-local)\n *\n * Plus any explicitly configured paths from settings.\n *\n * @param configuredPaths - Explicit paths from settings.json\n * @param cwd - Current working directory\n */\nexport async function discoverAndLoadHooks(configuredPaths: string[], cwd: string): Promise<LoadHooksResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Helper to add paths without duplicates\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global hooks: ~/.pi/agent/hooks/\n\tconst globalHooksDir = path.join(getAgentDir(), \"hooks\");\n\taddPaths(discoverHooksInDir(globalHooksDir));\n\n\t// 2. Project-local hooks: cwd/.pi/hooks/\n\tconst localHooksDir = path.join(cwd, \".pi\", \"hooks\");\n\taddPaths(discoverHooksInDir(localHooksDir));\n\n\t// 3. Explicitly configured paths (can override/add)\n\taddPaths(configuredPaths.map((p) => resolveHookPath(p, cwd)));\n\n\treturn loadHooks(allPaths, cwd);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/hooks/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hook loader - loads TypeScript hook modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Attachment } from \"@mariozechner/pi-agent-core\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir } from \"../../config.js\";\nimport type { HookAPI, HookFactory } from \"./types.js\";\n\n// Create require function to resolve module paths at runtime\nconst require = createRequire(import.meta.url);\n\n// Lazily computed aliases - resolved at runtime to handle global installs\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/hooks\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": require.resolve(\"@sinclair/typebox\"),\n\t};\n\treturn _aliases;\n}\n\n/**\n * Generic handler function type.\n */\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Send handler type for pi.send().\n */\nexport type SendHandler = (text: string, attachments?: Attachment[]) => void;\n\n/**\n * Registered handlers for a loaded hook.\n */\nexport interface LoadedHook {\n\t/** Original path from config */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** Map of event type to handler functions */\n\thandlers: Map<string, HandlerFn[]>;\n\t/** Set the send handler for this hook's pi.send() */\n\tsetSendHandler: (handler: SendHandler) => void;\n}\n\n/**\n * Result of loading hooks.\n */\nexport interface LoadHooksResult {\n\t/** Successfully loaded hooks */\n\thooks: LoadedHook[];\n\t/** Errors encountered during loading */\n\terrors: Array<{ path: string; error: string }>;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\n/**\n * Resolve hook path.\n * - Absolute paths used as-is\n * - Paths starting with ~ expanded to home directory\n * - Relative paths resolved from cwd\n */\nfunction resolveHookPath(hookPath: string, cwd: string): string {\n\tconst expanded = expandPath(hookPath);\n\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\n\t// Relative paths resolved from cwd\n\treturn path.resolve(cwd, expanded);\n}\n\n/**\n * Create a HookAPI instance that collects handlers.\n * Returns the API and a function to set the send handler later.\n */\nfunction createHookAPI(handlers: Map<string, HandlerFn[]>): {\n\tapi: HookAPI;\n\tsetSendHandler: (handler: SendHandler) => void;\n} {\n\tlet sendHandler: SendHandler = () => {\n\t\t// Default no-op until mode sets the handler\n\t};\n\n\tconst api: HookAPI = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\t\tsend(text: string, attachments?: Attachment[]): void {\n\t\t\tsendHandler(text, attachments);\n\t\t},\n\t} as HookAPI;\n\n\treturn {\n\t\tapi,\n\t\tsetSendHandler: (handler: SendHandler) => {\n\t\t\tsendHandler = handler;\n\t\t},\n\t};\n}\n\n/**\n * Load a single hook module using jiti.\n */\nasync function loadHook(hookPath: string, cwd: string): Promise<{ hook: LoadedHook | null; error: string | null }> {\n\tconst resolvedPath = resolveHookPath(hookPath, cwd);\n\n\ttry {\n\t\t// Create jiti instance for TypeScript/ESM loading\n\t\t// Use aliases to resolve package imports since hooks are loaded from user directories\n\t\t// (e.g. ~/.pi/agent/hooks) but import from packages installed with pi-coding-agent\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\t// Import the module\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as HookFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { hook: null, error: \"Hook must export a default function\" };\n\t\t}\n\n\t\t// Create handlers map and API\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst { api, setSendHandler } = createHookAPI(handlers);\n\n\t\t// Call factory to register handlers\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\thook: { path: hookPath, resolvedPath, handlers, setSendHandler },\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { hook: null, error: `Failed to load hook: ${message}` };\n\t}\n}\n\n/**\n * Load all hooks from configuration.\n * @param paths - Array of hook file paths\n * @param cwd - Current working directory for resolving relative paths\n */\nexport async function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult> {\n\tconst hooks: LoadedHook[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const hookPath of paths) {\n\t\tconst { hook, error } = await loadHook(hookPath, cwd);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: hookPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hook) {\n\t\t\thooks.push(hook);\n\t\t}\n\t}\n\n\treturn { hooks, errors };\n}\n\n/**\n * Discover hook files from a directory.\n * Returns all .ts files (and symlinks to .ts files) in the directory (non-recursive).\n */\nfunction discoverHooksInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\t\treturn entries\n\t\t\t.filter((e) => (e.isFile() || e.isSymbolicLink()) && e.name.endsWith(\".ts\"))\n\t\t\t.map((e) => path.join(dir, e.name));\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Discover and load hooks from standard locations:\n * 1. agentDir/hooks/*.ts (global)\n * 2. cwd/.pi/hooks/*.ts (project-local)\n *\n * Plus any explicitly configured paths from settings.\n */\nexport async function discoverAndLoadHooks(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n): Promise<LoadHooksResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Helper to add paths without duplicates\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global hooks: agentDir/hooks/\n\tconst globalHooksDir = path.join(agentDir, \"hooks\");\n\taddPaths(discoverHooksInDir(globalHooksDir));\n\n\t// 2. Project-local hooks: cwd/.pi/hooks/\n\tconst localHooksDir = path.join(cwd, \".pi\", \"hooks\");\n\taddPaths(discoverHooksInDir(localHooksDir));\n\n\t// 3. Explicitly configured paths (can override/add)\n\taddPaths(configuredPaths.map((p) => resolveHookPath(p, cwd)));\n\n\treturn loadHooks(allPaths, cwd);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAMnD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CAClB;AAGD,OAAO,QAAQ,6BAA6B,CAAC,CAAC;IAC7C,UAAU,cAAc;QACvB,aAAa,EAAE,oBAAoB,CAAC;KACpC;CACD;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,GAAG,GAAG,IAAI,oBAAoB,CAE7F;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAgBrE;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAmBpE","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AppMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AppMessage } from \"@mariozechner/pi-agent-core\";\nimport type { Message } from \"@mariozechner/pi-ai\";\n\n// ============================================================================\n// Custom Message Types\n// ============================================================================\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | null;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n}\n\n// Extend CustomMessages via declaration merging\ndeclare module \"@mariozechner/pi-agent-core\" {\n\tinterface CustomMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t}\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard for BashExecutionMessage.\n */\nexport function isBashExecutionMessage(msg: AppMessage | Message): msg is BashExecutionMessage {\n\treturn (msg as BashExecutionMessage).role === \"bashExecution\";\n}\n\n// ============================================================================\n// Message Formatting\n// ============================================================================\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext +=
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAMnD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CAClB;AAGD,OAAO,QAAQ,6BAA6B,CAAC,CAAC;IAC7C,UAAU,cAAc;QACvB,aAAa,EAAE,oBAAoB,CAAC;KACpC;CACD;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,GAAG,GAAG,IAAI,oBAAoB,CAE7F;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAgBrE;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAmBpE","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AppMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AppMessage } from \"@mariozechner/pi-agent-core\";\nimport type { Message } from \"@mariozechner/pi-ai\";\n\n// ============================================================================\n// Custom Message Types\n// ============================================================================\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | null;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n}\n\n// Extend CustomMessages via declaration merging\ndeclare module \"@mariozechner/pi-agent-core\" {\n\tinterface CustomMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t}\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard for BashExecutionMessage.\n */\nexport function isBashExecutionMessage(msg: AppMessage | Message): msg is BashExecutionMessage {\n\treturn (msg as BashExecutionMessage).role === \"bashExecution\";\n}\n\n// ============================================================================\n// Message Formatting\n// ============================================================================\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\n// ============================================================================\n// Message Transformer\n// ============================================================================\n\n/**\n * Transform AppMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's messageTransformer option (for prompt calls)\n * - Compaction's generateSummary (for summarization)\n */\nexport function messageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | null => {\n\t\t\tif (isBashExecutionMessage(m)) {\n\t\t\t\t// Convert bash execution to user message\n\t\t\t\treturn {\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Pass through standard LLM roles\n\t\t\tif (m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\") {\n\t\t\t\treturn m as Message;\n\t\t\t}\n\t\t\t// Filter out unknown message types\n\t\t\treturn null;\n\t\t})\n\t\t.filter((m): m is Message => m !== null);\n}\n"]}
|
package/dist/core/messages.js
CHANGED
|
@@ -22,7 +22,7 @@ export function isBashExecutionMessage(msg) {
|
|
|
22
22
|
export function bashExecutionToText(msg) {
|
|
23
23
|
let text = `Ran \`${msg.command}\`\n`;
|
|
24
24
|
if (msg.output) {
|
|
25
|
-
text +=
|
|
25
|
+
text += `\`\`\`\n${msg.output}\n\`\`\``;
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
28
|
text += "(no output)";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8BH,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAyB,EAA+B;IAC9F,OAAQ,GAA4B,CAAC,IAAI,KAAK,eAAe,CAAC;AAAA,CAC9D;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAyB,EAAU;IACtE,IAAI,IAAI,GAAG,SAAS,GAAG,CAAC,OAAO,MAAM,CAAC;IACtC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8BH,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAyB,EAA+B;IAC9F,OAAQ,GAA4B,CAAC,IAAI,KAAK,eAAe,CAAC;AAAA,CAC9D;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAyB,EAAU;IACtE,IAAI,IAAI,GAAG,SAAS,GAAG,CAAC,OAAO,MAAM,CAAC;IACtC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,IAAI,WAAW,GAAG,CAAC,MAAM,UAAU,CAAC;IACzC,CAAC;SAAM,CAAC;QACP,IAAI,IAAI,aAAa,CAAC;IACvB,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QACnB,IAAI,IAAI,yBAAyB,CAAC;IACnC,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QACxD,IAAI,IAAI,gCAAgC,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACzC,IAAI,IAAI,uCAAuC,GAAG,CAAC,cAAc,GAAG,CAAC;IACtE,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAsB,EAAa;IACrE,OAAO,QAAQ;SACb,GAAG,CAAC,CAAC,CAAC,EAAkB,EAAE,CAAC;QAC3B,IAAI,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,yCAAyC;YACzC,OAAO;gBACN,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzD,SAAS,EAAE,CAAC,CAAC,SAAS;aACtB,CAAC;QACH,CAAC;QACD,kCAAkC;QAClC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC5E,OAAO,CAAY,CAAC;QACrB,CAAC;QACD,mCAAmC;QACnC,OAAO,IAAI,CAAC;IAAA,CACZ,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAgB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AAAA,CAC1C","sourcesContent":["/**\n * Custom message types and transformers for the coding agent.\n *\n * Extends the base AppMessage type with coding-agent specific message types,\n * and provides a transformer to convert them to LLM-compatible messages.\n */\n\nimport type { AppMessage } from \"@mariozechner/pi-agent-core\";\nimport type { Message } from \"@mariozechner/pi-ai\";\n\n// ============================================================================\n// Custom Message Types\n// ============================================================================\n\n/**\n * Message type for bash executions via the ! command.\n */\nexport interface BashExecutionMessage {\n\trole: \"bashExecution\";\n\tcommand: string;\n\toutput: string;\n\texitCode: number | null;\n\tcancelled: boolean;\n\ttruncated: boolean;\n\tfullOutputPath?: string;\n\ttimestamp: number;\n}\n\n// Extend CustomMessages via declaration merging\ndeclare module \"@mariozechner/pi-agent-core\" {\n\tinterface CustomMessages {\n\t\tbashExecution: BashExecutionMessage;\n\t}\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard for BashExecutionMessage.\n */\nexport function isBashExecutionMessage(msg: AppMessage | Message): msg is BashExecutionMessage {\n\treturn (msg as BashExecutionMessage).role === \"bashExecution\";\n}\n\n// ============================================================================\n// Message Formatting\n// ============================================================================\n\n/**\n * Convert a BashExecutionMessage to user message text for LLM context.\n */\nexport function bashExecutionToText(msg: BashExecutionMessage): string {\n\tlet text = `Ran \\`${msg.command}\\`\\n`;\n\tif (msg.output) {\n\t\ttext += `\\`\\`\\`\\n${msg.output}\\n\\`\\`\\``;\n\t} else {\n\t\ttext += \"(no output)\";\n\t}\n\tif (msg.cancelled) {\n\t\ttext += \"\\n\\n(command cancelled)\";\n\t} else if (msg.exitCode !== null && msg.exitCode !== 0) {\n\t\ttext += `\\n\\nCommand exited with code ${msg.exitCode}`;\n\t}\n\tif (msg.truncated && msg.fullOutputPath) {\n\t\ttext += `\\n\\n[Output truncated. Full output: ${msg.fullOutputPath}]`;\n\t}\n\treturn text;\n}\n\n// ============================================================================\n// Message Transformer\n// ============================================================================\n\n/**\n * Transform AppMessages (including custom types) to LLM-compatible Messages.\n *\n * This is used by:\n * - Agent's messageTransformer option (for prompt calls)\n * - Compaction's generateSummary (for summarization)\n */\nexport function messageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.map((m): Message | null => {\n\t\t\tif (isBashExecutionMessage(m)) {\n\t\t\t\t// Convert bash execution to user message\n\t\t\t\treturn {\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tcontent: [{ type: \"text\", text: bashExecutionToText(m) }],\n\t\t\t\t\ttimestamp: m.timestamp,\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Pass through standard LLM roles\n\t\t\tif (m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\") {\n\t\t\t\treturn m as Message;\n\t\t\t}\n\t\t\t// Filter out unknown message types\n\t\t\treturn null;\n\t\t})\n\t\t.filter((m): m is Message => m !== null);\n}\n"]}
|
|
@@ -8,20 +8,21 @@ export declare function resolveApiKey(keyConfig: string): string | undefined;
|
|
|
8
8
|
* Get all models (built-in + custom), freshly loaded
|
|
9
9
|
* Returns { models, error } - either models array or error message
|
|
10
10
|
*/
|
|
11
|
-
export declare function loadAndMergeModels(): {
|
|
11
|
+
export declare function loadAndMergeModels(agentDir?: string): {
|
|
12
12
|
models: Model<Api>[];
|
|
13
13
|
error: string | null;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* Get API key for a model (checks custom providers first, then built-in)
|
|
17
|
-
* Now async to support OAuth token refresh
|
|
17
|
+
* Now async to support OAuth token refresh.
|
|
18
|
+
* Note: OAuth storage location is configured globally via setOAuthStorage.
|
|
18
19
|
*/
|
|
19
20
|
export declare function getApiKeyForModel(model: Model<Api>): Promise<string | undefined>;
|
|
20
21
|
/**
|
|
21
22
|
* Get only models that have valid API keys available
|
|
22
23
|
* Returns { models, error } - either models array or error message
|
|
23
24
|
*/
|
|
24
|
-
export declare function getAvailableModels(): Promise<{
|
|
25
|
+
export declare function getAvailableModels(agentDir?: string): Promise<{
|
|
25
26
|
models: Model<Api>[];
|
|
26
27
|
error: string | null;
|
|
27
28
|
}>;
|
|
@@ -29,7 +30,7 @@ export declare function getAvailableModels(): Promise<{
|
|
|
29
30
|
* Find a specific model by provider and ID
|
|
30
31
|
* Returns { model, error } - either model or error message
|
|
31
32
|
*/
|
|
32
|
-
export declare function findModel(provider: string, modelId: string): {
|
|
33
|
+
export declare function findModel(provider: string, modelId: string, agentDir?: string): {
|
|
33
34
|
model: Model<Api> | null;
|
|
34
35
|
error: string | null;
|
|
35
36
|
};
|