@bubstack/moe-memory 0.1.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 (157) hide show
  1. package/.mcp.json +18 -0
  2. package/README.md +47 -0
  3. package/agents/search-conversations.md +171 -0
  4. package/dist/LICENSE +25 -0
  5. package/dist/cli.d.ts +25 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +125 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/codex-hook-trust.d.ts +4 -0
  10. package/dist/codex-hook-trust.d.ts.map +1 -0
  11. package/dist/codex-hook-trust.js +114 -0
  12. package/dist/codex-hook-trust.js.map +1 -0
  13. package/dist/codex-support.d.ts +6 -0
  14. package/dist/codex-support.d.ts.map +1 -0
  15. package/dist/codex-support.js +29 -0
  16. package/dist/codex-support.js.map +1 -0
  17. package/dist/constants.d.ts +14 -0
  18. package/dist/constants.d.ts.map +1 -0
  19. package/dist/constants.js +14 -0
  20. package/dist/constants.js.map +1 -0
  21. package/dist/db.d.ts +103 -0
  22. package/dist/db.d.ts.map +1 -0
  23. package/dist/db.js +430 -0
  24. package/dist/db.js.map +1 -0
  25. package/dist/doctor-cli.d.ts +3 -0
  26. package/dist/doctor-cli.d.ts.map +1 -0
  27. package/dist/doctor-cli.js +43 -0
  28. package/dist/doctor-cli.js.map +1 -0
  29. package/dist/doctor.d.ts +17 -0
  30. package/dist/doctor.d.ts.map +1 -0
  31. package/dist/doctor.js +98 -0
  32. package/dist/doctor.js.map +1 -0
  33. package/dist/embedding-migration.d.ts +73 -0
  34. package/dist/embedding-migration.d.ts.map +1 -0
  35. package/dist/embedding-migration.js +120 -0
  36. package/dist/embedding-migration.js.map +1 -0
  37. package/dist/embeddings.d.ts +78 -0
  38. package/dist/embeddings.d.ts.map +1 -0
  39. package/dist/embeddings.js +180 -0
  40. package/dist/embeddings.js.map +1 -0
  41. package/dist/file-lock.d.ts +39 -0
  42. package/dist/file-lock.d.ts.map +1 -0
  43. package/dist/file-lock.js +91 -0
  44. package/dist/file-lock.js.map +1 -0
  45. package/dist/index-cli.d.ts +10 -0
  46. package/dist/index-cli.d.ts.map +1 -0
  47. package/dist/index-cli.js +195 -0
  48. package/dist/index-cli.js.map +1 -0
  49. package/dist/index.d.ts +12 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +19 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/indexer.d.ts +4 -0
  54. package/dist/indexer.d.ts.map +1 -0
  55. package/dist/indexer.js +318 -0
  56. package/dist/indexer.js.map +1 -0
  57. package/dist/install-check.d.ts +48 -0
  58. package/dist/install-check.d.ts.map +1 -0
  59. package/dist/install-check.js +82 -0
  60. package/dist/install-check.js.map +1 -0
  61. package/dist/journal/index.d.ts +5 -0
  62. package/dist/journal/index.d.ts.map +1 -0
  63. package/dist/journal/index.js +5 -0
  64. package/dist/journal/index.js.map +1 -0
  65. package/dist/journal/legacy-sidecars.d.ts +74 -0
  66. package/dist/journal/legacy-sidecars.d.ts.map +1 -0
  67. package/dist/journal/legacy-sidecars.js +151 -0
  68. package/dist/journal/legacy-sidecars.js.map +1 -0
  69. package/dist/journal/markdown.d.ts +91 -0
  70. package/dist/journal/markdown.d.ts.map +1 -0
  71. package/dist/journal/markdown.js +234 -0
  72. package/dist/journal/markdown.js.map +1 -0
  73. package/dist/journal/search.d.ts +91 -0
  74. package/dist/journal/search.d.ts.map +1 -0
  75. package/dist/journal/search.js +203 -0
  76. package/dist/journal/search.js.map +1 -0
  77. package/dist/journal/store.d.ts +96 -0
  78. package/dist/journal/store.d.ts.map +1 -0
  79. package/dist/journal/store.js +270 -0
  80. package/dist/journal/store.js.map +1 -0
  81. package/dist/journal-cli.d.ts +19 -0
  82. package/dist/journal-cli.d.ts.map +1 -0
  83. package/dist/journal-cli.js +153 -0
  84. package/dist/journal-cli.js.map +1 -0
  85. package/dist/logging.d.ts +6 -0
  86. package/dist/logging.d.ts.map +1 -0
  87. package/dist/logging.js +20 -0
  88. package/dist/logging.js.map +1 -0
  89. package/dist/mcp-server.d.ts +34 -0
  90. package/dist/mcp-server.d.ts.map +1 -0
  91. package/dist/mcp-server.js +607 -0
  92. package/dist/mcp-server.js.map +1 -0
  93. package/dist/parser.d.ts +11 -0
  94. package/dist/parser.d.ts.map +1 -0
  95. package/dist/parser.js +445 -0
  96. package/dist/parser.js.map +1 -0
  97. package/dist/paths.d.ts +103 -0
  98. package/dist/paths.d.ts.map +1 -0
  99. package/dist/paths.js +258 -0
  100. package/dist/paths.js.map +1 -0
  101. package/dist/search-cli.d.ts +3 -0
  102. package/dist/search-cli.d.ts.map +1 -0
  103. package/dist/search-cli.js +138 -0
  104. package/dist/search-cli.js.map +1 -0
  105. package/dist/search.d.ts +36 -0
  106. package/dist/search.d.ts.map +1 -0
  107. package/dist/search.js +371 -0
  108. package/dist/search.js.map +1 -0
  109. package/dist/show-cli.d.ts +3 -0
  110. package/dist/show-cli.d.ts.map +1 -0
  111. package/dist/show-cli.js +60 -0
  112. package/dist/show-cli.js.map +1 -0
  113. package/dist/show.d.ts +3 -0
  114. package/dist/show.d.ts.map +1 -0
  115. package/dist/show.js +984 -0
  116. package/dist/show.js.map +1 -0
  117. package/dist/stats-cli.d.ts +3 -0
  118. package/dist/stats-cli.d.ts.map +1 -0
  119. package/dist/stats-cli.js +51 -0
  120. package/dist/stats-cli.js.map +1 -0
  121. package/dist/stats.d.ts +19 -0
  122. package/dist/stats.d.ts.map +1 -0
  123. package/dist/stats.js +116 -0
  124. package/dist/stats.js.map +1 -0
  125. package/dist/summarizer.d.ts +83 -0
  126. package/dist/summarizer.d.ts.map +1 -0
  127. package/dist/summarizer.js +526 -0
  128. package/dist/summarizer.js.map +1 -0
  129. package/dist/summary-sentinel.d.ts +31 -0
  130. package/dist/summary-sentinel.d.ts.map +1 -0
  131. package/dist/summary-sentinel.js +80 -0
  132. package/dist/summary-sentinel.js.map +1 -0
  133. package/dist/sync-cli.d.ts +15 -0
  134. package/dist/sync-cli.d.ts.map +1 -0
  135. package/dist/sync-cli.js +202 -0
  136. package/dist/sync-cli.js.map +1 -0
  137. package/dist/sync.d.ts +35 -0
  138. package/dist/sync.d.ts.map +1 -0
  139. package/dist/sync.js +204 -0
  140. package/dist/sync.js.map +1 -0
  141. package/dist/types.d.ts +125 -0
  142. package/dist/types.d.ts.map +1 -0
  143. package/dist/types.js +32 -0
  144. package/dist/types.js.map +1 -0
  145. package/dist/verify.d.ts +30 -0
  146. package/dist/verify.d.ts.map +1 -0
  147. package/dist/verify.js +174 -0
  148. package/dist/verify.js.map +1 -0
  149. package/dist/version.d.ts +13 -0
  150. package/dist/version.d.ts.map +1 -0
  151. package/dist/version.js +13 -0
  152. package/dist/version.js.map +1 -0
  153. package/hooks/hooks.json +15 -0
  154. package/package.json +71 -0
  155. package/prompts/search-agent.md +160 -0
  156. package/skills/remembering-conversations/MCP-TOOLS.md +147 -0
  157. package/skills/remembering-conversations/SKILL.md +97 -0
package/dist/show.js ADDED
@@ -0,0 +1,984 @@
1
+ import { marked } from "marked";
2
+ export function formatConversationAsMarkdown(jsonl, startLine, endLine) {
3
+ const allLines = jsonl
4
+ .trim()
5
+ .split("\n")
6
+ .filter((line) => line.trim());
7
+ // Apply line range if specified (1-indexed, inclusive)
8
+ const lines = startLine !== undefined || endLine !== undefined
9
+ ? allLines.slice(startLine !== undefined ? startLine - 1 : 0, endLine !== undefined ? endLine : undefined)
10
+ : allLines;
11
+ if (isCodexRollout(lines)) {
12
+ return formatCodexConversationAsMarkdown(lines);
13
+ }
14
+ const allMessages = lines.map((line) => JSON.parse(line));
15
+ // Filter out system messages and messages with no content
16
+ const messages = allMessages.filter((msg) => {
17
+ if (msg.type !== "user" && msg.type !== "assistant")
18
+ return false;
19
+ if (!msg.timestamp)
20
+ return false;
21
+ if (!msg.message?.content) {
22
+ if (msg.type === "assistant" && msg.message?.usage)
23
+ return true;
24
+ return false;
25
+ }
26
+ if (Array.isArray(msg.message.content) && msg.message.content.length === 0) {
27
+ if (msg.type === "assistant" && msg.message?.usage)
28
+ return true;
29
+ return false;
30
+ }
31
+ return true;
32
+ });
33
+ if (messages.length === 0) {
34
+ return "";
35
+ }
36
+ const firstMessage = messages[0];
37
+ if (!firstMessage) {
38
+ return "";
39
+ }
40
+ let output = "# Conversation\n\n";
41
+ // Add metadata
42
+ output += "## Metadata\n\n";
43
+ if (firstMessage.sessionId) {
44
+ output += `**Session ID:** ${firstMessage.sessionId}\n\n`;
45
+ }
46
+ if (firstMessage.gitBranch) {
47
+ output += `**Git Branch:** ${firstMessage.gitBranch}\n\n`;
48
+ }
49
+ if (firstMessage.cwd) {
50
+ output += `**Working Directory:** ${firstMessage.cwd}\n\n`;
51
+ }
52
+ if (firstMessage.version) {
53
+ output += `**Claude Code Version:** ${firstMessage.version}\n\n`;
54
+ }
55
+ output += "---\n\n";
56
+ output += "## Messages\n\n";
57
+ let inSidechain = false;
58
+ for (const [i, msg] of messages.entries()) {
59
+ const timestamp = new Date(msg.timestamp).toLocaleString();
60
+ const messageId = msg.uuid || `msg-${i}`;
61
+ // Skip user messages that are just tool results
62
+ if (msg.type === "user" && Array.isArray(msg.message.content)) {
63
+ const hasOnlyToolResults = msg.message.content.every((block) => block.type === "tool_result");
64
+ if (hasOnlyToolResults) {
65
+ continue;
66
+ }
67
+ }
68
+ // Handle sidechain grouping
69
+ if (msg.isSidechain && !inSidechain) {
70
+ output += "\n---\n";
71
+ output += "**🔀 SIDECHAIN START**\n";
72
+ output += "---\n\n";
73
+ inSidechain = true;
74
+ }
75
+ else if (!msg.isSidechain && inSidechain) {
76
+ output += "\n---\n";
77
+ output += "**🔀 SIDECHAIN END**\n";
78
+ output += "---\n\n";
79
+ inSidechain = false;
80
+ }
81
+ // Determine role label
82
+ let roleLabel;
83
+ if (msg.isSidechain) {
84
+ roleLabel = msg.type === "user" ? "Agent" : "Subagent";
85
+ }
86
+ else {
87
+ roleLabel = msg.type === "user" ? "User" : "Agent";
88
+ }
89
+ output += `### **${roleLabel}** (${timestamp}) {#${messageId}}\n\n`;
90
+ if (msg.type === "user") {
91
+ // Handle tool results
92
+ if (msg.toolUseResult) {
93
+ output += "**Tool Result:**\n\n";
94
+ if (typeof msg.toolUseResult === "string") {
95
+ output += `${msg.toolUseResult}\n\n`;
96
+ }
97
+ else if (Array.isArray(msg.toolUseResult)) {
98
+ for (const result of msg.toolUseResult) {
99
+ output += `${result.text || String(result)}\n\n`;
100
+ }
101
+ }
102
+ }
103
+ else if (typeof msg.message.content === "string") {
104
+ output += `${msg.message.content}\n\n`;
105
+ }
106
+ else if (Array.isArray(msg.message.content)) {
107
+ for (const block of msg.message.content) {
108
+ if (block.type === "text" && block.text) {
109
+ output += `${block.text}\n\n`;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ else if (msg.type === "assistant") {
115
+ const content = msg.message.content;
116
+ if (typeof content === "string") {
117
+ output += `${content}\n\n`;
118
+ }
119
+ else if (Array.isArray(content)) {
120
+ for (const block of content) {
121
+ if (block.type === "text" && block.text) {
122
+ output += `${block.text}\n\n`;
123
+ }
124
+ else if (block.type === "tool_use") {
125
+ output += `**Tool Use:** \`${block.name}\`\n\n`;
126
+ // Format tool input inline
127
+ const input = block.input;
128
+ if (input && typeof input === "object") {
129
+ for (const [key, value] of Object.entries(input)) {
130
+ if (typeof value === "string" && value.includes("\n")) {
131
+ output += `- **${key}:**\n\`\`\`\n${value}\n\`\`\`\n`;
132
+ }
133
+ else if (typeof value === "string") {
134
+ output += `- **${key}:** ${value}\n`;
135
+ }
136
+ else {
137
+ output += `- **${key}:**\n\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\`\n`;
138
+ }
139
+ }
140
+ output += "\n";
141
+ }
142
+ // Look for corresponding tool result
143
+ const toolUseId = block.id;
144
+ if (toolUseId) {
145
+ let foundResult = false;
146
+ for (let j = i + 1; j < Math.min(i + 6, messages.length) && !foundResult; j++) {
147
+ const laterMsg = messages[j];
148
+ if (laterMsg &&
149
+ laterMsg.type === "user" &&
150
+ Array.isArray(laterMsg.message.content)) {
151
+ for (const resultBlock of laterMsg.message.content) {
152
+ if (resultBlock.type === "tool_result" &&
153
+ resultBlock.tool_use_id === toolUseId) {
154
+ const content = resultBlock.content;
155
+ output += "**Result:**\n";
156
+ if (typeof content === "string") {
157
+ if (content.includes("\n") || content.length > 100) {
158
+ output += "```\n";
159
+ output += content;
160
+ output += "\n```\n\n";
161
+ }
162
+ else {
163
+ output += `${content}\n\n`;
164
+ }
165
+ }
166
+ else if (Array.isArray(content)) {
167
+ output += "```json\n";
168
+ output += JSON.stringify(content, null, 2);
169
+ output += "\n```\n\n";
170
+ }
171
+ foundResult = true;
172
+ break;
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ // Add token usage if present
182
+ if (msg.message.usage) {
183
+ const usage = msg.message.usage;
184
+ output += `_in: ${(usage.input_tokens || 0).toLocaleString()}`;
185
+ if (usage.cache_read_input_tokens) {
186
+ output += ` | cache read: ${usage.cache_read_input_tokens.toLocaleString()}`;
187
+ }
188
+ if (usage.cache_creation_input_tokens) {
189
+ output += ` | cache create: ${usage.cache_creation_input_tokens.toLocaleString()}`;
190
+ }
191
+ output += ` | out: ${(usage.output_tokens || 0).toLocaleString()}_\n\n`;
192
+ }
193
+ }
194
+ }
195
+ // Close sidechain if still open
196
+ if (inSidechain) {
197
+ output += "\n---\n";
198
+ output += "**🔀 SIDECHAIN END**\n";
199
+ output += "---\n\n";
200
+ }
201
+ return output;
202
+ }
203
+ export function formatConversationAsHTML(jsonl) {
204
+ const lines = jsonl
205
+ .trim()
206
+ .split("\n")
207
+ .filter((line) => line.trim());
208
+ if (isCodexRollout(lines)) {
209
+ return formatMarkdownDocumentAsHTML(formatCodexConversationAsMarkdown(lines));
210
+ }
211
+ const allMessages = lines.map((line) => JSON.parse(line));
212
+ // Filter out system messages and messages with no content
213
+ const messages = allMessages.filter((msg) => {
214
+ // Skip file-history-snapshot and other non-conversation messages
215
+ if (msg.type !== "user" && msg.type !== "assistant")
216
+ return false;
217
+ // Skip messages with null timestamps
218
+ if (!msg.timestamp)
219
+ return false;
220
+ // Skip messages with no content (but keep if they have usage stats)
221
+ if (!msg.message?.content) {
222
+ // Keep assistant messages that only have token usage
223
+ if (msg.type === "assistant" && msg.message?.usage)
224
+ return true;
225
+ return false;
226
+ }
227
+ if (Array.isArray(msg.message.content) && msg.message.content.length === 0) {
228
+ // Keep assistant messages that only have token usage
229
+ if (msg.type === "assistant" && msg.message?.usage)
230
+ return true;
231
+ return false;
232
+ }
233
+ return true;
234
+ });
235
+ if (messages.length === 0) {
236
+ return "";
237
+ }
238
+ const firstMessage = messages[0];
239
+ if (!firstMessage) {
240
+ return "";
241
+ }
242
+ let bodyContent = "";
243
+ // Add header with metadata
244
+ bodyContent += '<div class="header">';
245
+ bodyContent += "<h1>Conversation</h1>";
246
+ bodyContent += '<table class="metadata">';
247
+ if (firstMessage.sessionId) {
248
+ bodyContent += `<tr><th>Session ID</th><td>${escapeHtml(firstMessage.sessionId)}</td></tr>`;
249
+ }
250
+ if (firstMessage.gitBranch) {
251
+ bodyContent += `<tr><th>Git Branch</th><td>${escapeHtml(firstMessage.gitBranch)}</td></tr>`;
252
+ }
253
+ if (firstMessage.cwd) {
254
+ bodyContent += `<tr><th>Working Directory</th><td>${escapeHtml(firstMessage.cwd)}</td></tr>`;
255
+ }
256
+ if (firstMessage.version) {
257
+ bodyContent += `<tr><th>Claude Code Version</th><td>${escapeHtml(firstMessage.version)}</td></tr>`;
258
+ }
259
+ bodyContent += "</table></div>";
260
+ // Render messages
261
+ bodyContent += '<div class="messages">';
262
+ // Build message index for tool results
263
+ const toolUseMap = new Map();
264
+ for (const msg of messages) {
265
+ if (msg.type === "assistant" && Array.isArray(msg.message.content)) {
266
+ for (const block of msg.message.content) {
267
+ if (block.type === "tool_use" && block.id) {
268
+ toolUseMap.set(block.id, { msg, block });
269
+ }
270
+ }
271
+ }
272
+ }
273
+ let inSidechain = false;
274
+ for (const [i, msg] of messages.entries()) {
275
+ const timestamp = new Date(msg.timestamp).toLocaleString();
276
+ const messageId = `msg-${msg.uuid || i}`;
277
+ // Skip user messages that are just tool results - they'll be rendered with their tool use
278
+ if (msg.type === "user" && Array.isArray(msg.message.content)) {
279
+ const hasOnlyToolResults = msg.message.content.every((block) => block.type === "tool_result");
280
+ if (hasOnlyToolResults) {
281
+ continue;
282
+ }
283
+ }
284
+ // Handle sidechain grouping
285
+ if (msg.isSidechain && !inSidechain) {
286
+ // Starting a sidechain group
287
+ bodyContent += '<div class="sidechain-group">';
288
+ inSidechain = true;
289
+ }
290
+ else if (!msg.isSidechain && inSidechain) {
291
+ // Ending a sidechain group
292
+ bodyContent += "</div>";
293
+ inSidechain = false;
294
+ }
295
+ const messageClass = msg.type === "user" ? "message user-message" : "message assistant-message";
296
+ // Determine role label based on context
297
+ let roleLabel;
298
+ if (msg.isSidechain) {
299
+ roleLabel = msg.type === "user" ? "Agent" : "Subagent";
300
+ }
301
+ else {
302
+ roleLabel = msg.type === "user" ? "User" : "Agent";
303
+ }
304
+ bodyContent += `<div class="${messageClass}" id="${messageId}">`;
305
+ bodyContent += `<div class="message-header">`;
306
+ bodyContent += `<span class="role">${roleLabel}</span>`;
307
+ bodyContent += `<a href="#${messageId}" class="timestamp">${escapeHtml(timestamp)}</a>`;
308
+ bodyContent += `</div>`;
309
+ bodyContent += `<div class="message-content">`;
310
+ if (msg.type === "user") {
311
+ // Handle tool results
312
+ if (msg.toolUseResult) {
313
+ bodyContent += '<div class="tool-result">';
314
+ bodyContent += "<strong>Tool Result:</strong>";
315
+ if (typeof msg.toolUseResult === "string") {
316
+ bodyContent += `<p>${escapeHtml(msg.toolUseResult)}</p>`;
317
+ }
318
+ else if (Array.isArray(msg.toolUseResult)) {
319
+ for (const result of msg.toolUseResult) {
320
+ bodyContent += `<p>${escapeHtml(result.text || String(result))}</p>`;
321
+ }
322
+ }
323
+ bodyContent += "</div>";
324
+ }
325
+ else if (typeof msg.message.content === "string") {
326
+ bodyContent += `<p>${escapeHtml(msg.message.content)}</p>`;
327
+ }
328
+ else if (Array.isArray(msg.message.content)) {
329
+ for (const block of msg.message.content) {
330
+ if (block.type === "text" && block.text) {
331
+ bodyContent += `<p>${escapeHtml(block.text)}</p>`;
332
+ }
333
+ else if (block.type === "tool_result") {
334
+ bodyContent += '<div class="tool-result">';
335
+ bodyContent += "<strong>Tool Result:</strong> ";
336
+ bodyContent += `<code>${escapeHtml(String(block.content || ""))}</code>`;
337
+ bodyContent += "</div>";
338
+ }
339
+ }
340
+ }
341
+ }
342
+ else if (msg.type === "assistant") {
343
+ const content = msg.message.content;
344
+ if (typeof content === "string") {
345
+ bodyContent += `<p>${escapeHtml(content)}</p>`;
346
+ }
347
+ else if (Array.isArray(content)) {
348
+ for (const block of content) {
349
+ if (block.type === "text" && block.text) {
350
+ // Check if text looks like markdown and render accordingly
351
+ if (isMarkdown(block.text)) {
352
+ bodyContent += '<div class="markdown-content">';
353
+ bodyContent += renderMarkdownSafely(block.text);
354
+ bodyContent += "</div>";
355
+ }
356
+ else {
357
+ // Plain text - preserve whitespace
358
+ bodyContent += `<div class="plain-content">${escapeHtml(block.text)}</div>`;
359
+ }
360
+ }
361
+ else if (block.type === "tool_use") {
362
+ bodyContent += '<div class="tool-use">';
363
+ bodyContent += `<div class="tool-name"><strong>Tool Use:</strong> <code>${escapeHtml(block.name || "")}</code></div>`;
364
+ // Format tool input inline
365
+ const input = block.input;
366
+ if (input && typeof input === "object") {
367
+ bodyContent += '<div class="tool-params">';
368
+ for (const [key, value] of Object.entries(input)) {
369
+ bodyContent += `<div class="tool-param">`;
370
+ bodyContent += `<strong>${escapeHtml(key)}:</strong> `;
371
+ if (typeof value === "string") {
372
+ // Check if value has newlines or is long - format as code block
373
+ if (value.includes("\n") || value.length > 100) {
374
+ bodyContent += "<pre>";
375
+ bodyContent += escapeHtml(value);
376
+ bodyContent += "</pre>";
377
+ }
378
+ else {
379
+ bodyContent += escapeHtml(value);
380
+ }
381
+ }
382
+ else {
383
+ // Format objects/arrays as JSON
384
+ bodyContent += "<pre>";
385
+ bodyContent += escapeHtml(JSON.stringify(value, null, 2));
386
+ bodyContent += "</pre>";
387
+ }
388
+ bodyContent += "</div>";
389
+ }
390
+ bodyContent += "</div>";
391
+ }
392
+ // Look for corresponding tool result in subsequent messages (not just next)
393
+ const toolUseId = block.id;
394
+ if (toolUseId) {
395
+ // Search forward up to 5 messages for the result
396
+ let foundResult = false;
397
+ for (let j = i + 1; j < Math.min(i + 6, messages.length) && !foundResult; j++) {
398
+ const laterMsg = messages[j];
399
+ if (laterMsg &&
400
+ laterMsg.type === "user" &&
401
+ Array.isArray(laterMsg.message.content)) {
402
+ for (const resultBlock of laterMsg.message.content) {
403
+ if (resultBlock.type === "tool_result" &&
404
+ resultBlock.tool_use_id === toolUseId) {
405
+ bodyContent += '<div class="tool-result">';
406
+ bodyContent += "<strong>Result:</strong> ";
407
+ const content = resultBlock.content;
408
+ if (typeof content === "string") {
409
+ // If content has newlines or is long, format as pre
410
+ if (content.includes("\n") || content.length > 100) {
411
+ bodyContent += "<pre>";
412
+ bodyContent += escapeHtml(content);
413
+ bodyContent += "</pre>";
414
+ }
415
+ else {
416
+ bodyContent += escapeHtml(content);
417
+ }
418
+ }
419
+ else if (Array.isArray(content)) {
420
+ bodyContent += "<pre>";
421
+ bodyContent += escapeHtml(JSON.stringify(content, null, 2));
422
+ bodyContent += "</pre>";
423
+ }
424
+ bodyContent += "</div>";
425
+ foundResult = true;
426
+ break;
427
+ }
428
+ }
429
+ }
430
+ }
431
+ }
432
+ bodyContent += "</div>";
433
+ }
434
+ }
435
+ }
436
+ // Add token usage if present
437
+ if (msg.message.usage) {
438
+ const usage = msg.message.usage;
439
+ bodyContent += '<div class="token-usage">';
440
+ bodyContent += `in: ${(usage.input_tokens || 0).toLocaleString()}`;
441
+ if (usage.cache_read_input_tokens) {
442
+ bodyContent += ` | cache read: ${usage.cache_read_input_tokens.toLocaleString()}`;
443
+ }
444
+ if (usage.cache_creation_input_tokens) {
445
+ bodyContent += ` | cache create: ${usage.cache_creation_input_tokens.toLocaleString()}`;
446
+ }
447
+ bodyContent += ` | out: ${(usage.output_tokens || 0).toLocaleString()}`;
448
+ bodyContent += "</div>";
449
+ }
450
+ }
451
+ bodyContent += "</div></div>";
452
+ }
453
+ // Close sidechain group if still open
454
+ if (inSidechain) {
455
+ bodyContent += "</div>";
456
+ }
457
+ bodyContent += "</div>";
458
+ return `<!DOCTYPE html>
459
+ <html>
460
+ <head>
461
+ <meta charset="UTF-8">
462
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
463
+ <title>Conversation</title>
464
+ <style>
465
+ * {
466
+ box-sizing: border-box;
467
+ }
468
+ body {
469
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
470
+ max-width: 900px;
471
+ margin: 0 auto;
472
+ padding: 24px;
473
+ line-height: 1.5;
474
+ color: #1d1d1f;
475
+ background: #f5f5f7;
476
+ }
477
+ .header {
478
+ margin-bottom: 32px;
479
+ padding: 24px;
480
+ background: #ffffff;
481
+ border-radius: 12px;
482
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
483
+ }
484
+ .header h1 {
485
+ margin: 0 0 20px 0;
486
+ font-size: 28px;
487
+ font-weight: 600;
488
+ color: #1d1d1f;
489
+ }
490
+ .metadata {
491
+ width: 100%;
492
+ border-collapse: collapse;
493
+ font-size: 13px;
494
+ }
495
+ .metadata th {
496
+ text-align: left;
497
+ padding: 10px 0;
498
+ color: #86868b;
499
+ font-weight: 500;
500
+ width: 180px;
501
+ border-bottom: 1px solid #f5f5f7;
502
+ }
503
+ .metadata td {
504
+ padding: 10px 0;
505
+ font-family: 'SF Mono', Consolas, monospace;
506
+ font-size: 12px;
507
+ color: #1d1d1f;
508
+ border-bottom: 1px solid #f5f5f7;
509
+ }
510
+ .messages {
511
+ display: flex;
512
+ flex-direction: column;
513
+ gap: 2px;
514
+ }
515
+ .message {
516
+ padding: 20px 24px;
517
+ background: #ffffff;
518
+ }
519
+ .user-message {
520
+ border-left: 3px solid #007aff;
521
+ }
522
+ .assistant-message {
523
+ border-left: 3px solid #34c759;
524
+ }
525
+ .message-header {
526
+ display: flex;
527
+ justify-content: space-between;
528
+ align-items: baseline;
529
+ margin-bottom: 12px;
530
+ }
531
+ .role {
532
+ font-weight: 600;
533
+ font-size: 14px;
534
+ letter-spacing: -0.01em;
535
+ }
536
+ .user-message .role {
537
+ color: #007aff;
538
+ }
539
+ .assistant-message .role {
540
+ color: #34c759;
541
+ }
542
+ .plain-content {
543
+ white-space: pre-wrap;
544
+ word-wrap: break-word;
545
+ color: #1d1d1f;
546
+ font-size: 14px;
547
+ line-height: 1.6;
548
+ }
549
+ .markdown-content {
550
+ color: #1d1d1f;
551
+ font-size: 14px;
552
+ line-height: 1.6;
553
+ }
554
+ .markdown-content p {
555
+ margin: 0 0 12px 0;
556
+ }
557
+ .markdown-content p:last-child {
558
+ margin-bottom: 0;
559
+ }
560
+ .markdown-content h1, .markdown-content h2, .markdown-content h3 {
561
+ margin: 20px 0 12px 0;
562
+ font-weight: 600;
563
+ color: #1d1d1f;
564
+ }
565
+ .markdown-content h1 {
566
+ font-size: 20px;
567
+ border-bottom: 1px solid #e5e5e7;
568
+ padding-bottom: 8px;
569
+ }
570
+ .markdown-content h2 {
571
+ font-size: 18px;
572
+ }
573
+ .markdown-content h3 {
574
+ font-size: 16px;
575
+ }
576
+ .markdown-content ul, .markdown-content ol {
577
+ margin: 12px 0;
578
+ padding-left: 24px;
579
+ }
580
+ .markdown-content li {
581
+ margin: 4px 0;
582
+ }
583
+ .markdown-content code {
584
+ background: #f5f5f7;
585
+ padding: 2px 6px;
586
+ border-radius: 4px;
587
+ font-family: 'SF Mono', Consolas, monospace;
588
+ font-size: 13px;
589
+ color: #5e5ce6;
590
+ }
591
+ .markdown-content pre {
592
+ margin: 12px 0;
593
+ background: #1d1d1f;
594
+ color: #f5f5f7;
595
+ padding: 16px;
596
+ border-radius: 8px;
597
+ overflow-x: auto;
598
+ line-height: 1.5;
599
+ }
600
+ .markdown-content pre code {
601
+ background: none;
602
+ color: #f5f5f7;
603
+ padding: 0;
604
+ font-size: 12px;
605
+ }
606
+ .markdown-content blockquote {
607
+ margin: 12px 0;
608
+ padding-left: 16px;
609
+ border-left: 3px solid #e5e5e7;
610
+ color: #6e6e73;
611
+ }
612
+ .markdown-content strong {
613
+ font-weight: 600;
614
+ color: #1d1d1f;
615
+ }
616
+ .markdown-content a {
617
+ color: #007aff;
618
+ text-decoration: none;
619
+ }
620
+ .markdown-content a:hover {
621
+ text-decoration: underline;
622
+ }
623
+ .timestamp {
624
+ font-size: 11px;
625
+ color: #86868b;
626
+ font-weight: 400;
627
+ text-decoration: none;
628
+ }
629
+ .timestamp:hover {
630
+ color: #007aff;
631
+ text-decoration: underline;
632
+ }
633
+ .tool-use {
634
+ margin: 16px 0;
635
+ background: #f5f5f7;
636
+ border-radius: 8px;
637
+ padding: 16px;
638
+ border: 1px solid #e5e5e7;
639
+ }
640
+ .tool-name {
641
+ margin-bottom: 12px;
642
+ font-size: 12px;
643
+ font-weight: 600;
644
+ color: #8e8e93;
645
+ text-transform: uppercase;
646
+ letter-spacing: 0.5px;
647
+ }
648
+ .tool-name code {
649
+ color: #5e5ce6;
650
+ background: none;
651
+ padding: 0;
652
+ font-weight: 600;
653
+ }
654
+ .tool-params {
655
+ display: flex;
656
+ flex-direction: column;
657
+ gap: 6px;
658
+ margin-top: 8px;
659
+ }
660
+ .tool-param {
661
+ font-size: 12px;
662
+ font-family: 'SF Mono', Consolas, monospace;
663
+ line-height: 1.6;
664
+ }
665
+ .tool-param strong {
666
+ color: #5e5ce6;
667
+ font-weight: 600;
668
+ }
669
+ .tool-param pre {
670
+ margin: 6px 0 0 0;
671
+ padding: 8px 12px;
672
+ background: #ffffff;
673
+ border: 1px solid #e5e5e7;
674
+ border-radius: 6px;
675
+ font-size: 11px;
676
+ white-space: pre-wrap;
677
+ word-wrap: break-word;
678
+ color: #1d1d1f;
679
+ font-family: 'SF Mono', Consolas, monospace;
680
+ line-height: 1.5;
681
+ overflow-x: auto;
682
+ }
683
+ .tool-result {
684
+ margin-top: 8px;
685
+ font-size: 12px;
686
+ font-family: 'SF Mono', Consolas, monospace;
687
+ line-height: 1.6;
688
+ }
689
+ .tool-result strong {
690
+ color: #5e5ce6;
691
+ font-weight: 600;
692
+ }
693
+ .tool-result pre {
694
+ margin: 6px 0 0 0;
695
+ padding: 8px 12px;
696
+ background: #ffffff;
697
+ border: 1px solid #e5e5e7;
698
+ border-radius: 6px;
699
+ font-size: 11px;
700
+ white-space: pre-wrap;
701
+ word-wrap: break-word;
702
+ color: #1d1d1f;
703
+ font-family: 'SF Mono', Consolas, monospace;
704
+ line-height: 1.5;
705
+ overflow-x: auto;
706
+ }
707
+ .token-usage {
708
+ margin-top: 12px;
709
+ font-size: 10px;
710
+ color: #86868b;
711
+ font-family: 'SF Mono', Consolas, monospace;
712
+ }
713
+ .sidechain-group {
714
+ background: #fffbf0;
715
+ border-left: 3px solid #ffcc00;
716
+ border-radius: 8px;
717
+ padding: 2px;
718
+ margin: 8px 0;
719
+ }
720
+ .sidechain-group .message {
721
+ background: #ffffff;
722
+ }
723
+ @media (max-width: 768px) {
724
+ body {
725
+ padding: 12px;
726
+ }
727
+ .header {
728
+ padding: 16px;
729
+ }
730
+ .message {
731
+ padding: 16px;
732
+ }
733
+ }
734
+ </style>
735
+ </head>
736
+ <body>
737
+ ${bodyContent}
738
+ </body>
739
+ </html>`;
740
+ }
741
+ function isCodexRollout(lines) {
742
+ for (const line of lines) {
743
+ try {
744
+ const parsed = JSON.parse(line);
745
+ return Boolean(parsed.payload &&
746
+ (parsed.type === "session_meta" ||
747
+ parsed.type === "turn_context" ||
748
+ parsed.type === "response_item" ||
749
+ parsed.type === "event_msg" ||
750
+ parsed.type === "compacted"));
751
+ }
752
+ catch { }
753
+ }
754
+ return false;
755
+ }
756
+ function extractCodexText(content) {
757
+ if (typeof content === "string") {
758
+ return content;
759
+ }
760
+ if (!Array.isArray(content)) {
761
+ return "";
762
+ }
763
+ return content
764
+ .filter((block) => block && typeof block === "object" && typeof block.text === "string")
765
+ .map((block) => block.text)
766
+ .join("\n");
767
+ }
768
+ function safeParseJson(value) {
769
+ try {
770
+ return JSON.parse(value);
771
+ }
772
+ catch {
773
+ return value;
774
+ }
775
+ }
776
+ function codexToolInput(payload) {
777
+ if (typeof payload.arguments === "string") {
778
+ return safeParseJson(payload.arguments);
779
+ }
780
+ if (payload.arguments !== undefined) {
781
+ return payload.arguments;
782
+ }
783
+ if (payload.input !== undefined) {
784
+ return payload.input;
785
+ }
786
+ if (payload.action !== undefined) {
787
+ return payload.action;
788
+ }
789
+ return undefined;
790
+ }
791
+ function codexToolOutput(payload) {
792
+ if (payload.output === undefined || payload.output === null) {
793
+ return "";
794
+ }
795
+ if (typeof payload.output === "string") {
796
+ return payload.output;
797
+ }
798
+ const text = extractCodexText(payload.output);
799
+ return text.trim() ? text : JSON.stringify(payload.output, null, 2);
800
+ }
801
+ function formatCodexToolInputMarkdown(input) {
802
+ if (input === undefined || input === null) {
803
+ return "";
804
+ }
805
+ if (typeof input === "string") {
806
+ return `\`\`\`\n${input}\n\`\`\`\n\n`;
807
+ }
808
+ if (typeof input !== "object") {
809
+ return `${String(input)}\n\n`;
810
+ }
811
+ let output = "";
812
+ for (const [key, value] of Object.entries(input)) {
813
+ if (typeof value === "string" && !value.includes("\n")) {
814
+ output += `- **${key}:** ${value}\n`;
815
+ }
816
+ else {
817
+ output += `- **${key}:**\n\`\`\`json\n${typeof value === "string" ? value : JSON.stringify(value, null, 2)}\n\`\`\`\n`;
818
+ }
819
+ }
820
+ return output ? `${output}\n` : "";
821
+ }
822
+ function formatCodexConversationAsMarkdown(lines) {
823
+ const entries = lines.map((line) => JSON.parse(line));
824
+ const metadata = {};
825
+ for (const entry of entries) {
826
+ const payload = entry.payload;
827
+ if (entry.type === "session_meta" && payload) {
828
+ metadata.sessionId = payload.id || metadata.sessionId;
829
+ metadata.cwd = payload.cwd || metadata.cwd;
830
+ metadata.gitBranch = payload.git?.branch || metadata.gitBranch;
831
+ metadata.cliVersion = payload.cli_version || metadata.cliVersion;
832
+ metadata.modelProvider = payload.model_provider || metadata.modelProvider;
833
+ }
834
+ else if (entry.type === "turn_context" && payload) {
835
+ metadata.cwd = payload.cwd || metadata.cwd;
836
+ metadata.model = payload.model || metadata.model;
837
+ }
838
+ }
839
+ let output = "# Conversation\n\n";
840
+ output += "## Metadata\n\n";
841
+ output += "**Harness:** Codex\n\n";
842
+ if (metadata.sessionId)
843
+ output += `**Session ID:** ${metadata.sessionId}\n\n`;
844
+ if (metadata.gitBranch)
845
+ output += `**Git Branch:** ${metadata.gitBranch}\n\n`;
846
+ if (metadata.cwd)
847
+ output += `**Working Directory:** ${metadata.cwd}\n\n`;
848
+ if (metadata.cliVersion)
849
+ output += `**Codex Version:** ${metadata.cliVersion}\n\n`;
850
+ if (metadata.model)
851
+ output += `**Model:** ${metadata.model}\n\n`;
852
+ if (metadata.modelProvider)
853
+ output += `**Model Provider:** ${metadata.modelProvider}\n\n`;
854
+ output += "---\n\n";
855
+ output += "## Messages\n\n";
856
+ for (let i = 0; i < entries.length; i++) {
857
+ const entry = entries[i];
858
+ const payload = entry.payload;
859
+ if (entry.type !== "response_item" || !payload) {
860
+ continue;
861
+ }
862
+ const timestamp = entry.timestamp ? new Date(entry.timestamp).toLocaleString() : "";
863
+ const anchor = payload.call_id || `msg-${i}`;
864
+ if (payload.type === "message") {
865
+ const text = extractCodexText(payload.content);
866
+ if (!text.trim()) {
867
+ continue;
868
+ }
869
+ const roleLabel = payload.role === "user" ? "User" : "Agent";
870
+ output += `### **${roleLabel}** (${timestamp}) {#${anchor}}\n\n`;
871
+ output += `${text}\n\n`;
872
+ }
873
+ else if (payload.type === "function_call" ||
874
+ payload.type === "custom_tool_call" ||
875
+ payload.type === "tool_search_call" ||
876
+ payload.type === "local_shell_call") {
877
+ const toolName = payload.name || payload.namespace || payload.type || "unknown";
878
+ output += `### **Tool Use** (${timestamp}) {#${anchor}}\n\n`;
879
+ output += `**Tool Use:** \`${toolName}\`\n\n`;
880
+ output += formatCodexToolInputMarkdown(codexToolInput(payload));
881
+ }
882
+ else if (payload.type === "function_call_output" ||
883
+ payload.type === "custom_tool_call_output" ||
884
+ payload.type === "tool_search_output" ||
885
+ payload.type === "local_shell_call_output") {
886
+ const result = codexToolOutput(payload);
887
+ output += `### **Tool Result** (${timestamp}) {#${anchor}-result}\n\n`;
888
+ output += "**Result:**\n";
889
+ if (result.includes("\n") || result.length > 100) {
890
+ output += `\`\`\`\n${result}\n\`\`\`\n\n`;
891
+ }
892
+ else {
893
+ output += `${result}\n\n`;
894
+ }
895
+ }
896
+ else if (payload.type === "reasoning") {
897
+ const text = extractCodexText(payload.summary);
898
+ if (text.trim()) {
899
+ output += `### **Reasoning Summary** (${timestamp}) {#${anchor}}\n\n`;
900
+ output += `${text}\n\n`;
901
+ }
902
+ }
903
+ }
904
+ return output;
905
+ }
906
+ function formatMarkdownDocumentAsHTML(markdown) {
907
+ return `<!DOCTYPE html>
908
+ <html>
909
+ <head>
910
+ <meta charset="UTF-8">
911
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
912
+ <title>Conversation</title>
913
+ <style>
914
+ body {
915
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
916
+ max-width: 900px;
917
+ margin: 0 auto;
918
+ padding: 24px;
919
+ line-height: 1.5;
920
+ color: #1d1d1f;
921
+ background: #f5f5f7;
922
+ }
923
+ .markdown-content {
924
+ background: #ffffff;
925
+ padding: 24px;
926
+ border-radius: 12px;
927
+ }
928
+ pre {
929
+ overflow-x: auto;
930
+ background: #f5f5f7;
931
+ padding: 12px;
932
+ border-radius: 6px;
933
+ }
934
+ code {
935
+ font-family: 'SF Mono', Consolas, monospace;
936
+ }
937
+ </style>
938
+ </head>
939
+ <body>
940
+ <div class="markdown-content">
941
+ ${renderMarkdownSafely(markdown)}
942
+ </div>
943
+ </body>
944
+ </html>`;
945
+ }
946
+ function escapeHtml(text) {
947
+ const map = {
948
+ "&": "&amp;",
949
+ "<": "&lt;",
950
+ ">": "&gt;",
951
+ '"': "&quot;",
952
+ "'": "&#039;",
953
+ };
954
+ return text.replace(/[&<>"']/g, (m) => map[m] ?? m);
955
+ }
956
+ function isMarkdown(text) {
957
+ // Detect common markdown patterns
958
+ const markdownPatterns = [
959
+ /^#{1,6}\s/m, // Headers
960
+ /\*\*[^*]+\*\*/, // Bold
961
+ /\*[^*]+\*/, // Italic
962
+ /`[^`]+`/, // Inline code
963
+ /```/, // Code blocks
964
+ /^\s*[-*+]\s/m, // Unordered lists
965
+ /^\s*\d+\.\s/m, // Ordered lists
966
+ /^\s*>\s/m, // Blockquotes
967
+ /\[.+\]\(.+\)/, // Links
968
+ ];
969
+ // If text has at least 2 markdown patterns, consider it markdown
970
+ const matchCount = markdownPatterns.filter((pattern) => pattern.test(text)).length;
971
+ return matchCount >= 2;
972
+ }
973
+ function renderMarkdownSafely(text) {
974
+ try {
975
+ const renderer = new marked.Renderer();
976
+ renderer.html = ({ text }) => escapeHtml(text);
977
+ return marked.parse(text, { async: false, renderer });
978
+ }
979
+ catch {
980
+ // Fallback to escaped HTML if markdown parsing fails
981
+ return `<pre>${escapeHtml(text)}</pre>`;
982
+ }
983
+ }
984
+ //# sourceMappingURL=show.js.map