Markdown export: add truncated flag and attachment metadata

The markdown export was missing the truncated flag and per-message
attachment metadata (file_name, file_size, file_type) that the JSON
export already includes. File attachments now render as:
  ### Attachment: <name> _(size, type)_
followed by extracted_content in a quadruple-backtick block. Pasted
content (no file_name) keeps the existing ### Pasted label.

Adopted from upstream commit 318d4a7. Skipped the manifest rename to
"Local" since the project uses the "Beta" suffix convention on testing.
This commit is contained in:
tux tucker 2026-05-15 00:08:44 -04:00
parent 54278ac6ce
commit 846f6557b9
6 changed files with 63 additions and 7 deletions

View file

@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Claude Exporter Beta",
"version": "1.9.7",
"version": "1.9.8",
"description": "Export conversations and artifacts from Claude.ai",
"permissions": [
"activeTab",

View file

@ -43,6 +43,9 @@ function convertToMarkdown(data, includeMetadata, conversationId = null, include
if (conversationId) {
markdown += `**Link:** [https://claude.ai/chat/${conversationId}](https://claude.ai/chat/${conversationId})\n`;
}
if (data.truncated !== undefined) {
markdown += `**Truncated:** ${data.truncated}\n`;
}
markdown += `\n---\n\n`;
}
@ -88,10 +91,30 @@ function convertToMarkdown(data, includeMetadata, conversationId = null, include
}
}
// Handle attachments (e.g., pasted content)
// Handle attachments (file uploads and pasted content)
if (message.attachments && message.attachments.length > 0) {
for (const attachment of message.attachments) {
if (attachment.extracted_content) {
if (attachment.file_name) {
// File attachment — show file metadata + extracted content if present
let header = `### Attachment: ${attachment.file_name}`;
const meta = [];
if (attachment.file_size) {
meta.push(`${(attachment.file_size / 1024).toFixed(1)} KB`);
}
if (attachment.file_type) {
meta.push(attachment.file_type);
}
if (meta.length > 0) {
header += ` _(${meta.join(', ')})_`;
}
markdown += `${header}\n`;
if (attachment.extracted_content) {
markdown += `\`\`\`\`\n${attachment.extracted_content}\n\`\`\`\`\n\n`;
} else {
markdown += `\n`;
}
} else if (attachment.extracted_content) {
// Pasted content (no file_name) — legacy label
markdown += `### Pasted\n\`\`\`\`\n${attachment.extracted_content}\n\`\`\`\`\n\n`;
}
}

View file

@ -1,5 +1,10 @@
# Changelog
## [1.9.8]
- Markdown export now includes the `truncated` flag in the metadata block (when present in the conversation data)
- Markdown export now shows file attachment metadata per message (`file_name`, `file_size`, `file_type`) — not just `extracted_content`. File attachments render as `### Attachment: <name> _(size, type)_`; pasted content keeps the legacy `### Pasted` label.
## [1.9.7]
- Reorganized the browse settings dropdown: Date and Time format toggles moved to the options page; their slot now holds a "Backup/Restore Database" item with a hover submenu (Backup / Restore)

View file

@ -1,4 +1,9 @@
# Claude Exporter - TODO List
- **Markdown export: truncated flag + attachment metadata** (v1.9.8)
- Markdown export now includes the `truncated` flag and per-message attachment info (`file_name`, `file_size`, `file_type`) — parity with what JSON export already provided
- File attachments render as `### Attachment: name _(size, type)_`; pasted content (no `file_name`) keeps the legacy `### Pasted` label
- Adopted from upstream commit `318d4a7`; skipped the extension-rename-to-"Local" half (we use the "Beta" suffix convention for testing builds)
## Pending 🔄
### Critical Priority 🔴
@ -297,4 +302,4 @@
- Backup file is structured `{ _meta, local, sync }`; restore validates `_meta.app` and confirms before overwriting
- v1.9.6: "Advanced Options" link added to the browse settings dropdown (between Time and Test connection) so the options page is reachable from the browse view
- v1.9.7: backup/restore logic moved to shared `utils.js`; reachable from the browse dropdown via a "Backup/Restore Database" hover submenu. Date/Time format toggles moved out of the dropdown into the options page.
- Future enhancement: smart per-key merge on restore (e.g. union `modelSnapshots`, keep earliest `firstSeen`) instead of overwrite
- Future enhancement: smart per-key merge on restore (e.g. union `modelSnapshots`, keep earliest `firstSeen`) instead of overwrite

View file

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Claude Exporter Beta",
"version": "1.9.7",
"version": "1.9.8",
"description": "Export conversations and artifacts from Claude.ai",
"permissions": [
"activeTab",

View file

@ -43,6 +43,9 @@ function convertToMarkdown(data, includeMetadata, conversationId = null, include
if (conversationId) {
markdown += `**Link:** [https://claude.ai/chat/${conversationId}](https://claude.ai/chat/${conversationId})\n`;
}
if (data.truncated !== undefined) {
markdown += `**Truncated:** ${data.truncated}\n`;
}
markdown += `\n---\n\n`;
}
@ -88,10 +91,30 @@ function convertToMarkdown(data, includeMetadata, conversationId = null, include
}
}
// Handle attachments (e.g., pasted content)
// Handle attachments (file uploads and pasted content)
if (message.attachments && message.attachments.length > 0) {
for (const attachment of message.attachments) {
if (attachment.extracted_content) {
if (attachment.file_name) {
// File attachment — show file metadata + extracted content if present
let header = `### Attachment: ${attachment.file_name}`;
const meta = [];
if (attachment.file_size) {
meta.push(`${(attachment.file_size / 1024).toFixed(1)} KB`);
}
if (attachment.file_type) {
meta.push(attachment.file_type);
}
if (meta.length > 0) {
header += ` _(${meta.join(', ')})_`;
}
markdown += `${header}\n`;
if (attachment.extracted_content) {
markdown += `\`\`\`\`\n${attachment.extracted_content}\n\`\`\`\`\n\n`;
} else {
markdown += `\n`;
}
} else if (attachment.extracted_content) {
// Pasted content (no file_name) — legacy label
markdown += `### Pasted\n\`\`\`\`\n${attachment.extracted_content}\n\`\`\`\`\n\n`;
}
}