@vamdawn/cconvo 1.0.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/dist/cli.d.ts +4 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +213 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/completion.d.ts +7 -0
  8. package/dist/completion.d.ts.map +1 -0
  9. package/dist/completion.js +227 -0
  10. package/dist/completion.js.map +1 -0
  11. package/dist/core/parser.d.ts +12 -0
  12. package/dist/core/parser.d.ts.map +1 -0
  13. package/dist/core/parser.js +178 -0
  14. package/dist/core/parser.js.map +1 -0
  15. package/dist/core/scanner.d.ts +9 -0
  16. package/dist/core/scanner.d.ts.map +1 -0
  17. package/dist/core/scanner.js +109 -0
  18. package/dist/core/scanner.js.map +1 -0
  19. package/dist/exporters/html.d.ts +3 -0
  20. package/dist/exporters/html.d.ts.map +1 -0
  21. package/dist/exporters/html.js +288 -0
  22. package/dist/exporters/html.js.map +1 -0
  23. package/dist/exporters/index.d.ts +7 -0
  24. package/dist/exporters/index.d.ts.map +1 -0
  25. package/dist/exporters/index.js +40 -0
  26. package/dist/exporters/index.js.map +1 -0
  27. package/dist/exporters/json.d.ts +3 -0
  28. package/dist/exporters/json.d.ts.map +1 -0
  29. package/dist/exporters/json.js +45 -0
  30. package/dist/exporters/json.js.map +1 -0
  31. package/dist/exporters/markdown.d.ts +3 -0
  32. package/dist/exporters/markdown.d.ts.map +1 -0
  33. package/dist/exporters/markdown.js +87 -0
  34. package/dist/exporters/markdown.js.map +1 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +14 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/interactive.d.ts +2 -0
  40. package/dist/interactive.d.ts.map +1 -0
  41. package/dist/interactive.js +348 -0
  42. package/dist/interactive.js.map +1 -0
  43. package/dist/models/types.d.ts +158 -0
  44. package/dist/models/types.d.ts.map +1 -0
  45. package/dist/models/types.js +2 -0
  46. package/dist/models/types.js.map +1 -0
  47. package/dist/utils/format.d.ts +13 -0
  48. package/dist/utils/format.d.ts.map +1 -0
  49. package/dist/utils/format.js +104 -0
  50. package/dist/utils/format.js.map +1 -0
  51. package/dist/utils/path.d.ts +10 -0
  52. package/dist/utils/path.d.ts.map +1 -0
  53. package/dist/utils/path.js +37 -0
  54. package/dist/utils/path.js.map +1 -0
  55. package/package.json +66 -0
@@ -0,0 +1,178 @@
1
+ import { createReadStream } from 'fs';
2
+ import { readdir } from 'fs/promises';
3
+ import { createInterface } from 'readline';
4
+ import { join } from 'path';
5
+ // 解析对话文件元数据(快速扫描)
6
+ export async function parseConversationMeta(filePath) {
7
+ let slug;
8
+ let startTime;
9
+ let endTime;
10
+ let messageCount = 0;
11
+ const fileStream = createReadStream(filePath);
12
+ const rl = createInterface({
13
+ input: fileStream,
14
+ crlfDelay: Infinity,
15
+ });
16
+ for await (const line of rl) {
17
+ if (!line.trim())
18
+ continue;
19
+ try {
20
+ const record = JSON.parse(line);
21
+ messageCount++;
22
+ if (record.type === 'user' || record.type === 'assistant') {
23
+ const timestamp = new Date(record.timestamp);
24
+ if (!startTime || timestamp < startTime) {
25
+ startTime = timestamp;
26
+ }
27
+ if (!endTime || timestamp > endTime) {
28
+ endTime = timestamp;
29
+ }
30
+ // 从用户消息中提取slug
31
+ if (record.type === 'user' && record.slug && !slug) {
32
+ slug = record.slug;
33
+ }
34
+ }
35
+ }
36
+ catch {
37
+ // 跳过无效行
38
+ }
39
+ }
40
+ return {
41
+ slug,
42
+ startTime: startTime || new Date(),
43
+ endTime: endTime || new Date(),
44
+ messageCount,
45
+ };
46
+ }
47
+ // 解析完整对话
48
+ export async function parseConversation(filePath, projectPath) {
49
+ const messages = [];
50
+ let slug;
51
+ let sessionId;
52
+ let startTime;
53
+ let endTime;
54
+ const totalTokens = {
55
+ input_tokens: 0,
56
+ output_tokens: 0,
57
+ cache_creation_input_tokens: 0,
58
+ cache_read_input_tokens: 0,
59
+ };
60
+ const fileStream = createReadStream(filePath);
61
+ const rl = createInterface({
62
+ input: fileStream,
63
+ crlfDelay: Infinity,
64
+ });
65
+ for await (const line of rl) {
66
+ if (!line.trim())
67
+ continue;
68
+ try {
69
+ const record = JSON.parse(line);
70
+ messages.push(record);
71
+ if (record.type === 'user') {
72
+ const userMsg = record;
73
+ const timestamp = new Date(userMsg.timestamp);
74
+ if (!startTime || timestamp < startTime)
75
+ startTime = timestamp;
76
+ if (!endTime || timestamp > endTime)
77
+ endTime = timestamp;
78
+ if (userMsg.slug && !slug)
79
+ slug = userMsg.slug;
80
+ if (userMsg.sessionId && !sessionId)
81
+ sessionId = userMsg.sessionId;
82
+ }
83
+ if (record.type === 'assistant') {
84
+ const assistantMsg = record;
85
+ const timestamp = new Date(assistantMsg.timestamp);
86
+ if (!startTime || timestamp < startTime)
87
+ startTime = timestamp;
88
+ if (!endTime || timestamp > endTime)
89
+ endTime = timestamp;
90
+ // 累计token使用
91
+ if (assistantMsg.message?.usage) {
92
+ const usage = assistantMsg.message.usage;
93
+ totalTokens.input_tokens += usage.input_tokens || 0;
94
+ totalTokens.output_tokens += usage.output_tokens || 0;
95
+ totalTokens.cache_creation_input_tokens += usage.cache_creation_input_tokens || 0;
96
+ totalTokens.cache_read_input_tokens += usage.cache_read_input_tokens || 0;
97
+ }
98
+ }
99
+ }
100
+ catch {
101
+ // 跳过无效行
102
+ }
103
+ }
104
+ // 解析子代理对话
105
+ const subagents = await parseSubagents(filePath, sessionId);
106
+ return {
107
+ sessionId: sessionId || '',
108
+ slug,
109
+ projectPath,
110
+ filePath,
111
+ messages,
112
+ subagents,
113
+ startTime: startTime || new Date(),
114
+ endTime: endTime || new Date(),
115
+ messageCount: messages.length,
116
+ totalTokens,
117
+ };
118
+ }
119
+ // 解析子代理对话
120
+ async function parseSubagents(mainFilePath, sessionId) {
121
+ if (!sessionId)
122
+ return [];
123
+ const subagentsDir = join(mainFilePath.replace('.jsonl', ''), 'subagents');
124
+ const subagents = [];
125
+ try {
126
+ const entries = await readdir(subagentsDir, { withFileTypes: true });
127
+ for (const entry of entries) {
128
+ if (entry.isFile() && entry.name.endsWith('.jsonl')) {
129
+ const agentId = entry.name.replace('agent-', '').replace('.jsonl', '');
130
+ const subagentPath = join(subagentsDir, entry.name);
131
+ const messages = await parseSubagentMessages(subagentPath);
132
+ subagents.push({
133
+ agentId,
134
+ filePath: subagentPath,
135
+ messages,
136
+ messageCount: messages.length,
137
+ });
138
+ }
139
+ }
140
+ }
141
+ catch {
142
+ // 没有子代理目录
143
+ }
144
+ return subagents;
145
+ }
146
+ // 解析子代理消息
147
+ async function parseSubagentMessages(filePath) {
148
+ const messages = [];
149
+ const fileStream = createReadStream(filePath);
150
+ const rl = createInterface({
151
+ input: fileStream,
152
+ crlfDelay: Infinity,
153
+ });
154
+ for await (const line of rl) {
155
+ if (!line.trim())
156
+ continue;
157
+ try {
158
+ const record = JSON.parse(line);
159
+ messages.push(record);
160
+ }
161
+ catch {
162
+ // 跳过无效行
163
+ }
164
+ }
165
+ return messages;
166
+ }
167
+ // 构建消息树(按parentUuid关联)
168
+ export function buildMessageTree(messages) {
169
+ // 过滤出user和assistant消息,并按时间排序
170
+ return messages
171
+ .filter(m => m.type === 'user' || m.type === 'assistant')
172
+ .sort((a, b) => {
173
+ const timeA = new Date(a.timestamp).getTime();
174
+ const timeB = new Date(b.timestamp).getTime();
175
+ return timeA - timeB;
176
+ });
177
+ }
178
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Project, ConversationSummary, ScanResult } from '../models/types.js';
2
+ export declare function scanProjects(basePath?: string): Promise<ScanResult>;
3
+ export declare function scanProject(dirPath: string, encodedPath: string): Promise<Project>;
4
+ export declare function findProject(name: string, basePath?: string): Promise<Project | null>;
5
+ export declare function findConversation(sessionId: string, basePath?: string): Promise<{
6
+ project: Project;
7
+ conversation: ConversationSummary;
8
+ } | null>;
9
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAInF,wBAAsB,YAAY,CAAC,QAAQ,GAAE,MAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgCvF;AAGD,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA4DxF;AAGD,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAqB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAMxG;AAGD,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAqB,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,mBAAmB,CAAA;CAAE,GAAG,IAAI,CAAC,CAWzE"}
@@ -0,0 +1,109 @@
1
+ import { readdir, stat } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { PROJECTS_DIR, decodePath, getProjectName, isJsonlFile, extractSessionId, } from '../utils/path.js';
4
+ import { parseConversationMeta } from './parser.js';
5
+ // 扫描所有项目
6
+ export async function scanProjects(basePath = PROJECTS_DIR) {
7
+ const projects = [];
8
+ let totalConversations = 0;
9
+ let totalSize = 0;
10
+ try {
11
+ const entries = await readdir(basePath, { withFileTypes: true });
12
+ for (const entry of entries) {
13
+ if (entry.isDirectory()) {
14
+ const project = await scanProject(join(basePath, entry.name), entry.name);
15
+ if (project.totalConversations > 0) {
16
+ projects.push(project);
17
+ totalConversations += project.totalConversations;
18
+ totalSize += project.totalSize;
19
+ }
20
+ }
21
+ }
22
+ }
23
+ catch (error) {
24
+ if (error.code !== 'ENOENT') {
25
+ throw error;
26
+ }
27
+ }
28
+ // 按项目名排序
29
+ projects.sort((a, b) => a.name.localeCompare(b.name));
30
+ return {
31
+ projects,
32
+ totalConversations,
33
+ totalSize,
34
+ };
35
+ }
36
+ // 扫描单个项目
37
+ export async function scanProject(dirPath, encodedPath) {
38
+ const conversations = [];
39
+ let totalSize = 0;
40
+ try {
41
+ const entries = await readdir(dirPath, { withFileTypes: true });
42
+ for (const entry of entries) {
43
+ if (entry.isFile() && isJsonlFile(entry.name)) {
44
+ const sessionId = extractSessionId(entry.name);
45
+ if (sessionId) {
46
+ const filePath = join(dirPath, entry.name);
47
+ const fileStat = await stat(filePath);
48
+ // 检查是否有subagents目录
49
+ const subagentsDir = join(dirPath, sessionId, 'subagents');
50
+ let hasSubagents = false;
51
+ try {
52
+ await stat(subagentsDir);
53
+ hasSubagents = true;
54
+ }
55
+ catch {
56
+ // 没有subagents目录
57
+ }
58
+ // 解析对话元数据
59
+ const meta = await parseConversationMeta(filePath);
60
+ conversations.push({
61
+ sessionId,
62
+ slug: meta.slug,
63
+ filePath,
64
+ startTime: meta.startTime,
65
+ endTime: meta.endTime,
66
+ messageCount: meta.messageCount,
67
+ fileSize: fileStat.size,
68
+ hasSubagents,
69
+ });
70
+ totalSize += fileStat.size;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ catch (error) {
76
+ if (error.code !== 'ENOENT') {
77
+ throw error;
78
+ }
79
+ }
80
+ // 按时间倒序排列
81
+ conversations.sort((a, b) => b.startTime.getTime() - a.startTime.getTime());
82
+ return {
83
+ name: getProjectName(encodedPath),
84
+ encodedPath,
85
+ originalPath: decodePath(encodedPath),
86
+ dirPath,
87
+ conversations,
88
+ totalConversations: conversations.length,
89
+ totalSize,
90
+ };
91
+ }
92
+ // 根据项目名称搜索项目
93
+ export async function findProject(name, basePath = PROJECTS_DIR) {
94
+ const result = await scanProjects(basePath);
95
+ return result.projects.find(p => p.name.toLowerCase().includes(name.toLowerCase()) ||
96
+ p.originalPath.toLowerCase().includes(name.toLowerCase())) || null;
97
+ }
98
+ // 根据sessionId查找对话
99
+ export async function findConversation(sessionId, basePath = PROJECTS_DIR) {
100
+ const result = await scanProjects(basePath);
101
+ for (const project of result.projects) {
102
+ const conversation = project.conversations.find(c => c.sessionId === sessionId);
103
+ if (conversation) {
104
+ return { project, conversation };
105
+ }
106
+ }
107
+ return null;
108
+ }
109
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Conversation, ExportOptions } from '../models/types.js';
2
+ export declare function exportToHtml(conversation: Conversation, options: ExportOptions): string;
3
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/exporters/html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAGZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAW5B,wBAAgB,YAAY,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAwPvF"}
@@ -0,0 +1,288 @@
1
+ import { formatDateTime, formatTokens, extractTextContent, extractThinking, extractToolCalls, escapeHtml, } from '../utils/format.js';
2
+ // 导出为HTML格式
3
+ export function exportToHtml(conversation, options) {
4
+ const messages = conversation.messages.filter(m => m.type === 'user' || m.type === 'assistant');
5
+ const messagesHtml = messages.map(m => formatMessageHtml(m, options)).join('\n');
6
+ let subagentsHtml = '';
7
+ if (options.includeSubagents && conversation.subagents.length > 0) {
8
+ subagentsHtml = `
9
+ <div class="subagents">
10
+ <h2>Subagent Conversations</h2>
11
+ ${conversation.subagents.map(sub => `
12
+ <div class="subagent">
13
+ <h3>Agent: ${escapeHtml(sub.agentId)}</h3>
14
+ ${sub.messages
15
+ .filter(m => m.type === 'user' || m.type === 'assistant')
16
+ .map(m => formatMessageHtml(m, options))
17
+ .join('\n')}
18
+ </div>
19
+ `).join('\n')}
20
+ </div>
21
+ `;
22
+ }
23
+ return `<!DOCTYPE html>
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="UTF-8">
27
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
28
+ <title>${escapeHtml(conversation.slug || conversation.sessionId)}</title>
29
+ <style>
30
+ :root {
31
+ --bg-color: #1a1a2e;
32
+ --card-bg: #16213e;
33
+ --user-bg: #0f3460;
34
+ --assistant-bg: #1a1a2e;
35
+ --text-color: #e8e8e8;
36
+ --text-muted: #a0a0a0;
37
+ --border-color: #2a2a4a;
38
+ --accent-color: #e94560;
39
+ --code-bg: #0d1117;
40
+ }
41
+
42
+ * {
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ body {
47
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
48
+ background-color: var(--bg-color);
49
+ color: var(--text-color);
50
+ line-height: 1.6;
51
+ margin: 0;
52
+ padding: 20px;
53
+ }
54
+
55
+ .container {
56
+ max-width: 900px;
57
+ margin: 0 auto;
58
+ }
59
+
60
+ .header {
61
+ background: var(--card-bg);
62
+ border-radius: 12px;
63
+ padding: 24px;
64
+ margin-bottom: 24px;
65
+ border: 1px solid var(--border-color);
66
+ }
67
+
68
+ .header h1 {
69
+ margin: 0 0 16px 0;
70
+ color: var(--accent-color);
71
+ }
72
+
73
+ .meta {
74
+ display: grid;
75
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
76
+ gap: 12px;
77
+ font-size: 14px;
78
+ color: var(--text-muted);
79
+ }
80
+
81
+ .meta-item {
82
+ display: flex;
83
+ gap: 8px;
84
+ }
85
+
86
+ .meta-label {
87
+ font-weight: 600;
88
+ color: var(--text-color);
89
+ }
90
+
91
+ .message {
92
+ margin-bottom: 16px;
93
+ border-radius: 12px;
94
+ padding: 16px 20px;
95
+ border: 1px solid var(--border-color);
96
+ }
97
+
98
+ .message.user {
99
+ background: var(--user-bg);
100
+ }
101
+
102
+ .message.assistant {
103
+ background: var(--assistant-bg);
104
+ }
105
+
106
+ .message-header {
107
+ display: flex;
108
+ justify-content: space-between;
109
+ align-items: center;
110
+ margin-bottom: 12px;
111
+ padding-bottom: 8px;
112
+ border-bottom: 1px solid var(--border-color);
113
+ }
114
+
115
+ .message-role {
116
+ font-weight: 600;
117
+ font-size: 14px;
118
+ }
119
+
120
+ .message-role.user {
121
+ color: #4fc3f7;
122
+ }
123
+
124
+ .message-role.assistant {
125
+ color: #81c784;
126
+ }
127
+
128
+ .message-time {
129
+ font-size: 12px;
130
+ color: var(--text-muted);
131
+ }
132
+
133
+ .message-content {
134
+ white-space: pre-wrap;
135
+ word-break: break-word;
136
+ }
137
+
138
+ .thinking, .tool-call {
139
+ margin-top: 12px;
140
+ background: var(--code-bg);
141
+ border-radius: 8px;
142
+ overflow: hidden;
143
+ }
144
+
145
+ .thinking-header, .tool-header {
146
+ padding: 8px 12px;
147
+ background: rgba(255,255,255,0.05);
148
+ font-size: 12px;
149
+ font-weight: 600;
150
+ color: var(--text-muted);
151
+ cursor: pointer;
152
+ user-select: none;
153
+ }
154
+
155
+ .thinking-header:hover, .tool-header:hover {
156
+ background: rgba(255,255,255,0.08);
157
+ }
158
+
159
+ .thinking-content, .tool-content {
160
+ padding: 12px;
161
+ font-family: 'Monaco', 'Menlo', monospace;
162
+ font-size: 13px;
163
+ max-height: 300px;
164
+ overflow-y: auto;
165
+ display: none;
166
+ }
167
+
168
+ .thinking-content.show, .tool-content.show {
169
+ display: block;
170
+ }
171
+
172
+ .subagents {
173
+ margin-top: 40px;
174
+ padding-top: 24px;
175
+ border-top: 2px solid var(--border-color);
176
+ }
177
+
178
+ .subagents h2 {
179
+ color: var(--accent-color);
180
+ }
181
+
182
+ .subagent {
183
+ margin-top: 24px;
184
+ }
185
+
186
+ .subagent h3 {
187
+ color: var(--text-muted);
188
+ font-size: 14px;
189
+ }
190
+
191
+ pre {
192
+ margin: 0;
193
+ white-space: pre-wrap;
194
+ word-break: break-word;
195
+ }
196
+ </style>
197
+ </head>
198
+ <body>
199
+ <div class="container">
200
+ <div class="header">
201
+ <h1>${escapeHtml(conversation.slug || 'Conversation')}</h1>
202
+ <div class="meta">
203
+ <div class="meta-item">
204
+ <span class="meta-label">Project:</span>
205
+ <span>${escapeHtml(conversation.projectPath)}</span>
206
+ </div>
207
+ <div class="meta-item">
208
+ <span class="meta-label">Session:</span>
209
+ <span>${escapeHtml(conversation.sessionId)}</span>
210
+ </div>
211
+ <div class="meta-item">
212
+ <span class="meta-label">Time:</span>
213
+ <span>${formatDateTime(conversation.startTime)} - ${formatDateTime(conversation.endTime)}</span>
214
+ </div>
215
+ <div class="meta-item">
216
+ <span class="meta-label">Messages:</span>
217
+ <span>${conversation.messageCount}</span>
218
+ </div>
219
+ <div class="meta-item">
220
+ <span class="meta-label">Tokens:</span>
221
+ <span>In: ${formatTokens(conversation.totalTokens.input_tokens)} / Out: ${formatTokens(conversation.totalTokens.output_tokens)}</span>
222
+ </div>
223
+ </div>
224
+ </div>
225
+
226
+ <div class="messages">
227
+ ${messagesHtml}
228
+ </div>
229
+
230
+ ${subagentsHtml}
231
+ </div>
232
+
233
+ <script>
234
+ document.querySelectorAll('.thinking-header, .tool-header').forEach(el => {
235
+ el.addEventListener('click', () => {
236
+ const content = el.nextElementSibling;
237
+ content.classList.toggle('show');
238
+ el.textContent = content.classList.contains('show')
239
+ ? el.textContent.replace('Show', 'Hide')
240
+ : el.textContent.replace('Hide', 'Show');
241
+ });
242
+ });
243
+ </script>
244
+ </body>
245
+ </html>`;
246
+ }
247
+ // 格式化单条消息为HTML
248
+ function formatMessageHtml(message, options) {
249
+ const role = message.type;
250
+ const timestamp = formatDateTime(message.timestamp);
251
+ const textContent = extractTextContent(message);
252
+ let thinkingHtml = '';
253
+ if (options.includeThinking && message.type === 'assistant') {
254
+ const thinkings = extractThinking(message);
255
+ if (thinkings.length > 0) {
256
+ thinkingHtml = thinkings.map(t => `
257
+ <div class="thinking">
258
+ <div class="thinking-header">Show Thinking</div>
259
+ <div class="thinking-content"><pre>${escapeHtml(t)}</pre></div>
260
+ </div>
261
+ `).join('');
262
+ }
263
+ }
264
+ let toolsHtml = '';
265
+ if (options.includeToolCalls && message.type === 'assistant') {
266
+ const toolCalls = extractToolCalls(message);
267
+ if (toolCalls.length > 0) {
268
+ toolsHtml = toolCalls.map(tool => `
269
+ <div class="tool-call">
270
+ <div class="tool-header">Show Tool: ${escapeHtml(tool.name)}</div>
271
+ <div class="tool-content"><pre>${escapeHtml(JSON.stringify(tool.input, null, 2))}</pre></div>
272
+ </div>
273
+ `).join('');
274
+ }
275
+ }
276
+ return `
277
+ <div class="message ${role}">
278
+ <div class="message-header">
279
+ <span class="message-role ${role}">${role === 'user' ? 'User' : 'Assistant'}</span>
280
+ <span class="message-time">${timestamp}</span>
281
+ </div>
282
+ <div class="message-content">${escapeHtml(textContent)}</div>
283
+ ${thinkingHtml}
284
+ ${toolsHtml}
285
+ </div>
286
+ `;
287
+ }
288
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/exporters/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Conversation, ExportOptions } from '../models/types.js';
2
+ export declare function exportConversation(conversation: Conversation, options: ExportOptions): Promise<string>;
3
+ export declare function getFileExtension(format: ExportOptions['format']): string;
4
+ export { exportToMarkdown } from './markdown.js';
5
+ export { exportToJson } from './json.js';
6
+ export { exportToHtml } from './html.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exporters/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMtE,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAGD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,MAAM,CAWxE;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { writeFile } from 'fs/promises';
2
+ import { exportToMarkdown } from './markdown.js';
3
+ import { exportToJson } from './json.js';
4
+ import { exportToHtml } from './html.js';
5
+ // 导出对话
6
+ export async function exportConversation(conversation, options) {
7
+ let content;
8
+ switch (options.format) {
9
+ case 'markdown':
10
+ content = exportToMarkdown(conversation, options);
11
+ break;
12
+ case 'json':
13
+ content = exportToJson(conversation, options);
14
+ break;
15
+ case 'html':
16
+ content = exportToHtml(conversation, options);
17
+ break;
18
+ default:
19
+ throw new Error(`Unsupported format: ${options.format}`);
20
+ }
21
+ await writeFile(options.outputPath, content, 'utf-8');
22
+ return content;
23
+ }
24
+ // 获取导出文件扩展名
25
+ export function getFileExtension(format) {
26
+ switch (format) {
27
+ case 'markdown':
28
+ return '.md';
29
+ case 'json':
30
+ return '.json';
31
+ case 'html':
32
+ return '.html';
33
+ default:
34
+ return '.txt';
35
+ }
36
+ }
37
+ export { exportToMarkdown } from './markdown.js';
38
+ export { exportToJson } from './json.js';
39
+ export { exportToHtml } from './html.js';
40
+ //# sourceMappingURL=index.js.map