export-markdown.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { Anthropic } from "@anthropic-ai/sdk"
  2. import os from "os"
  3. import * as path from "path"
  4. import * as vscode from "vscode"
  5. export async function downloadTask(dateTs: number, conversationHistory: Anthropic.MessageParam[]) {
  6. // File name
  7. const date = new Date(dateTs)
  8. const month = date.toLocaleString("en-US", { month: "short" }).toLowerCase()
  9. const day = date.getDate()
  10. const year = date.getFullYear()
  11. let hours = date.getHours()
  12. const minutes = date.getMinutes().toString().padStart(2, "0")
  13. const seconds = date.getSeconds().toString().padStart(2, "0")
  14. const ampm = hours >= 12 ? "pm" : "am"
  15. hours = hours % 12
  16. hours = hours ? hours : 12 // the hour '0' should be '12'
  17. const fileName = `claude_dev_task_${month}-${day}-${year}_${hours}-${minutes}-${seconds}-${ampm}.md`
  18. // Generate markdown
  19. const markdownContent = conversationHistory
  20. .map((message) => {
  21. const role = message.role === "user" ? "**User:**" : "**Assistant:**"
  22. const content = Array.isArray(message.content)
  23. ? message.content.map(formatContentBlockToMarkdown).join("\n")
  24. : message.content
  25. return `${role}\n\n${content}\n\n`
  26. })
  27. .join("---\n\n")
  28. // Prompt user for save location
  29. const saveUri = await vscode.window.showSaveDialog({
  30. filters: { Markdown: ["md"] },
  31. defaultUri: vscode.Uri.file(path.join(os.homedir(), "Downloads", fileName)),
  32. })
  33. if (saveUri) {
  34. // Write content to the selected location
  35. await vscode.workspace.fs.writeFile(saveUri, Buffer.from(markdownContent))
  36. vscode.window.showTextDocument(saveUri, { preview: true })
  37. }
  38. }
  39. export function formatContentBlockToMarkdown(
  40. block:
  41. | Anthropic.TextBlockParam
  42. | Anthropic.ImageBlockParam
  43. | Anthropic.ToolUseBlockParam
  44. | Anthropic.ToolResultBlockParam
  45. ): string {
  46. switch (block.type) {
  47. case "text":
  48. return block.text
  49. case "image":
  50. return `[Image]`
  51. case "tool_use":
  52. let input: string
  53. if (typeof block.input === "object" && block.input !== null) {
  54. input = Object.entries(block.input)
  55. .map(([key, value]) => `${key.charAt(0).toUpperCase() + key.slice(1)}: ${value}`)
  56. .join("\n")
  57. } else {
  58. input = String(block.input)
  59. }
  60. return `[Tool Use: ${block.name}]\n${input}`
  61. case "tool_result":
  62. if (typeof block.content === "string") {
  63. return `[Tool Result${block.is_error ? " (Error)" : ""}]\n${block.content}`
  64. } else if (Array.isArray(block.content)) {
  65. return `[Tool Result${block.is_error ? " (Error)" : ""}]\n${block.content
  66. .map(formatContentBlockToMarkdown)
  67. .join("\n")}`
  68. } else {
  69. return `[Tool Result${block.is_error ? " (Error)" : ""}]`
  70. }
  71. default:
  72. return "[Unexpected content type]"
  73. }
  74. }