跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptNode.jsAI大前端

Trae AI 编辑器对话记录导出脚本实现

如何通过分析 Trae AI 编辑器的工作区存储文件(state.vscdb),利用 Node.js 脚本解析 SQLite 数据库,提取对话数据并生成 Markdown 文件的方法。主要步骤包括定位存储路径、使用 better-sqlite3 读取数据库、过滤特定 Key 的数据以及格式化输出。

DataScient发布于 2026/4/5更新于 2026/9/895 浏览
Trae AI 编辑器对话记录导出脚本实现

前言

最近在尝试使用字节出的 Trae AI 编辑器,想根据对话记录写一些文章分享,但发现一条完整的对话记录跟 Cursor 一样,没有办法直接导出。靠截图?放在文章里用户体验极差。

契机

前两天找到一位大佬写的 Cursor 记录导出插件,插件方面不太可能是通用的,但是思路可以借鉴。

在插件的文档中,发现了 Cursor 工作区的存储位置,这里面存储了所有的对话记录和其他信息。

Cursor 工作区存储位置

由于使用的是 Macos,所以后面的演示都以 Macos 为例。当然,Windows 其实也可以按照同样的路径去找找看。

~/Library/Application Support/Cursor/User/workspaceStorage 

我们将工作区位置路径中的 Cursor 替换成 Trae 试试看,能不能进去:

cd Library/Application\ Support/Trae/User/workspaceStorage 

文章配图

没错,是可以进去的。

通过 open . 打开文件夹:

workspaceStorage 中的

发现是一堆文件夹,点击最新修改的一个文件夹进去看看:

文件夹详情

分析

  1. 打开 workspace.json 文件看看,内容如下:
{"folder":"file:///Users/peanut/Desktop/work/ai_all/trae_test"
}

只存了一个项目的路径,Pass。

  1. 打开 kiss 开头的文件夹,发现里头是一堆图片,看了下是正在编辑的这篇文档中图片的缓存,Pass。

文章配图

  1. 那只有 state.vscdb 这个文件了,没见过这个文件格式,但猜测是 vscode 的数据库文件。

AI 介入

来,用 Trae AI 介入,问问看。

用户 (2025/2/18 16:39:52)

你知道.vscdb 格式文件吗?

助手 (2025/2/18 16:39:52)

是的,我了解 .vscdb 文件。这是 Visual Studio Code 使用的数据库文件格式,通常用于存储 VS Code 的各种状态和配置信息。具体来说:

  1. 文件格式:它是一个 SQLite 数据库文件,使用二进制格式存储,通常位于 VS Code 的用户数据目录中。
  2. 主要用途:存储 VS Code 的状态信息、保存工作区历史记录、存储一些扩展的数据、缓存某些配置信息。
  3. 查看方式:可以使用任何支持 SQLite 的数据库查看工具打开,常用工具包括 SQLite Browser、DBeaver、VS Code 的 SQLite 扩展。
  4. 注意事项:这些文件通常不需要手动修改,VS Code 运行时会自动管理这些文件,如果文件损坏可能会影响 VS Code 的某些功能。

如果你需要查看这类文件的内容,建议使用 SQLite 浏览器工具,这样可以安全地查看而不会意外损坏文件。

用户 (2025/2/18 16:40:42)

如何解析.vscdb 这个文件格式的内容为文本呢?

助手 (2025/2/18 16:40:42)

我可以帮你写一个 Python 脚本来解析 .vscdb 文件。这个脚本使用 SQLite3 模块来读取和显示文件内容。

import sqlite3 import json def parse_vscdb(file_path): try: # 连接到 SQLite 数据库 conn = sqlite3.connect(file_path) cursor = conn.cursor() # 获取所有表名 cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") tables = cursor.fetchall() result = {} # 遍历每个表并获取内容 for table in tables: table_name = table[0] cursor.execute(f"SELECT * FROM {table_name}") columns = [description[0] for description in cursor.description] rows = cursor.fetchall() # 将结果转换为字典格式 table_data = [] for row in rows: row_dict = {} for i, column in enumerate(columns): # 尝试解析 JSON 字符串 if isinstance(row[i], str): try: row_dict[column] = json.loads(row[i]) except json.JSONDecodeError: row_dict[column] = row[i] else: row_dict[column] = row[i] table_data.append(row_dict) result[table_name] = table_data conn.close() return result except sqlite3.Error as e: print(f"SQLite 错误:{e}") return None except Exception as e: print(f"发生错误:{e}") return None if __name__ == "__main__": # 使用示例 vscdb_path = "你的.vscdb 文件路径" # 替换为实际的文件路径 data = parse_vscdb(vscdb_path) if data: # 格式化输出结果 for table_name, table_data in data.items(): print(f"\n表名:{table_name}") print("-" * 50) for row in table_data: print(json.dumps(row, indent=2, ensure_ascii=False)) print("-" * 50) 

使用方法:

  1. 将上面的代码保存为 Python 文件
  2. 修改 vscdb_path 为你要解析的 .vscdb 文件的实际路径
  3. 运行脚本

这个脚本会:

  1. 连接到 .vscdb 文件
  2. 获取所有表的内容
  3. 尝试解析可能的 JSON 格式内容
  4. 以易读的格式输出所有数据

如果你想要在命令行中直接运行,可以这样使用:

python parse_vscdb.py 

注意事项:

  1. 确保已安装 Python
  2. 运行脚本时确保 .vscdb 文件没有被其他程序占用
  3. 某些内容可能是二进制数据,会以原始格式显示
  4. 建议在解析大文件时先备份原文件

如果你需要针对特定表或内容进行解析,可以根据需要修改代码,添加过滤条件或特定的解析逻辑。

用户 (2025/2/18 16:41:08)

用 nodejs 可以解析吗?

助手 (2025/2/18 16:41:08)

是的,我们可以使用 Node.js 来解析 .vscdb 文件。下面是一个使用 better-sqlite3 模块的实现:

首先需要安装依赖:

npm install better-sqlite3 

然后这是解析脚本:

const Database = require('better-sqlite3'); function parseVSCDB(filePath) { try { // 连接数据库 const db = new Database(filePath, { readonly: true }); // 获取所有表名 const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' `).all(); const result = {}; // 遍历每个表并获取内容 tables.forEach(table => { const tableName = table.name; const rows = db.prepare(`SELECT * FROM ${tableName}`).all(); // 尝试解析每行中可能的 JSON 字符串 const parsedRows = rows.map(row => { const parsedRow = {}; Object.entries(row).forEach(([key, value]) => { if (typeof value === 'string') { try { parsedRow[key] = JSON.parse(value); } catch { parsedRow[key] = value; } } else { parsedRow[key] = value; } }); return parsedRow; }); result[tableName] = parsedRows; }); // 关闭数据库连接 db.close(); return result; } catch (error) { console.error('解析错误:', error.message); return null; } } // 使用示例 const vscdbPath = '你的.vscdb 文件路径'; // 替换为实际的文件路径 const data = parseVSCDB(vscdbPath); if (data) { // 格式化输出结果 Object.entries(data).forEach(([tableName, tableData]) => { console.log(`\n表名:${tableName}`); console.log('-'.repeat(50)); tableData.forEach(row => { console.log(JSON.stringify(row, null, 2)); }); console.log('-'.repeat(50)); }); } 

使用方法:

  1. 保存上述代码为 .js 文件
  2. 修改 vscdbPath 为你要解析的 .vscdb 文件的实际路径
  3. 运行脚本:
node parse_vscdb.js 

这个脚本的功能:

  1. 使用 better-sqlite3 连接数据库文件
  2. 获取所有表的内容
  3. 尝试解析可能的 JSON 格式内容
  4. 以易读的格式输出数据

优点:

  1. 使用 better-sqlite3 模块,性能较好
  2. 以只读模式打开文件,更安全
  3. 支持异步操作
  4. 自动处理 JSON 格式的内容

如果你需要针对特定表或内容进行解析,可以根据需要修改代码,添加过滤条件或特定的解析逻辑。

用户 (2025/2/18 16:52:12)

vscdb.js 将解析的内容写入一个 json 文件

助手 (2025/2/18 16:52:13)

我来帮你修改代码,添加将解析结果写入 JSON 文件的功能:

// ... existing code ...
// 使用示例 const vscdbPath = './state.vscdb'; const data = parseVSCDB(vscdbPath); if (data) { // 格式化输出结果到控制台 Object.entries(data).forEach(([tableName, tableData]) => { console.log(`\n表名:${tableName}`); console.log('-'.repeat(50)); tableData.forEach(row => { console.log(JSON.stringify(row, null, 2)); }); console.log('-'.repeat(50)); }); // 将结果写入 JSON 文件 const fs = require('fs'); const outputPath = './vscdb_output.json'; try { fs.writeFileSync( outputPath, JSON.stringify(data, null, 2), 'utf8' ); console.log(`数据已成功写入到 ${outputPath}`); } catch (err) { console.error('写入文件时发生错误:', err); } }

主要修改说明:

  1. 添加了 fs 模块的引入
  2. 定义了输出文件路径 outputPath
  3. 使用 writeFileSync 将解析后的数据写入 JSON 文件
  4. 添加了错误处理和成功提示
  5. JSON 数据使用 2 空格缩进格式化,便于阅读

运行脚本后,会在同目录下生成 vscdb_output.json 文件,包含所有解析的数据。

用户 (2025/2/18 16:57:44)

输出的文件是个 json,我只想保留 key 为 inputHistory 和 key 为 ChatStore 的数据

助手 (2025/2/18 16:57:44)

我来帮你修改代码,只保留指定的数据。修改 vscdb.js 文件,添加数据过滤功能:

const Database = require('better-sqlite3'); const fs = require('fs'); function parseVSCDB(filePath) { try { // 连接数据库 const db = new Database(filePath, { readonly: true }); // 获取所有表名 const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' `).all(); const result = {}; // 遍历每个表并获取内容 tables.forEach(table => { const tableName = table.name; const rows = db.prepare(`SELECT * FROM ${tableName}`).all(); // 尝试解析每行中可能的 JSON 字符串 const parsedRows = rows.map(row => { const parsedRow = {}; Object.entries(row).forEach(([key, value]) => { if (typeof value === 'string') { try { parsedRow[key] = JSON.parse(value); } catch { parsedRow[key] = value; } } else { parsedRow[key] = value; } }); return parsedRow; }); result[tableName] = parsedRows; }); // 关闭数据库连接 db.close(); // 过滤数据,只保留指定的 key const filteredData = {}; Object.entries(result).forEach(([tableName, tableData]) => { tableData.forEach(row => { if (row.key === 'inputHistory' || row.key === 'ChatStore') { if (!filteredData[tableName]) { filteredData[tableName] = []; } filteredData[tableName].push(row); } }); }); return filteredData; } catch (error) { console.error('解析错误:', error.message); return null; } } // 使用示例 const vscdbPath = './state.vscdb'; // 替换为实际的文件路径 const data = parseVSCDB(vscdbPath); if (data) { // 将过滤后的数据写入新的 JSON 文件 try { fs.writeFileSync( 'filtered_vscdb_output.json', JSON.stringify(data, null, 2), 'utf8' ); console.log('数据已成功写入到 filtered_vscdb_output.json'); } catch (err) { console.error('写入文件时出错:', err); } }

主要修改:

  1. 添加了数据过滤逻辑,只保留 key 为 'inputHistory' 和 'ChatStore' 的数据
  2. 输出文件名改为 filtered_vscdb_output.json,以区分原始输出
  3. 优化了数据结构,只包含需要的内容

运行后,新生成的 JSON 文件将只包含你指定的两个 key 的数据。

用户 (2025/2/18 17:01:37)

key 属性以 memento/icube-ai-ng-chat-storage 开头的也要的

助手 (2025/2/18 17:01:37)

好的,我来修改代码,让它过滤出 key 为 'inputHistory'、'ChatStore' 以及以 'memento/icube-ai-ng-chat-storage' 开头的数据:

const Database = require('better-sqlite3'); const fs = require('fs'); function parseVSCDB(filePath) { try { // 连接数据库 const db = new Database(filePath, { readonly: true }); // 获取所有表名 const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' `).all(); const result = {}; // 遍历每个表并获取内容 tables.forEach(table => { const tableName = table.name; const rows = db.prepare(`SELECT * FROM ${tableName}`).all(); // 尝试解析每行中可能的 JSON 字符串 const parsedRows = rows.map(row => { const parsedRow = {}; Object.entries(row).forEach(([key, value]) => { if (typeof value === 'string') { try { parsedRow[key] = JSON.parse(value); } catch { parsedRow[key] = value; } } else { parsedRow[key] = value; } }); return parsedRow; }); result[tableName] = parsedRows; }); // 关闭数据库连接 db.close(); // 过滤数据,只保留指定的 key const filteredData = {}; Object.entries(result).forEach(([tableName, tableData]) => { tableData.forEach(row => { if (row.key === 'inputHistory' || row.key === 'ChatStore' || (typeof row.key === 'string' && row.key.startsWith('memento/icube-ai-ng-chat-storage'))) { if (!filteredData[tableName]) { filteredData[tableName] = []; } filteredData[tableName].push(row); } }); }); return filteredData; } catch (error) { console.error('解析错误:', error.message); return null; } } // 使用示例 const vscdbPath = './state.vscdb'; // 替换为实际的文件路径 const data = parseVSCDB(vscdbPath); if (data) { // 将过滤后的数据写入新的 JSON 文件 try { fs.writeFileSync( 'filtered_vscdb_output.json', JSON.stringify(data, null, 2), 'utf8' ); console.log('数据已成功写入到 filtered_vscdb_output.json'); } catch (err) { console.error('写入文件时出错:', err); } }

主要修改:

  1. 在过滤条件中添加了对 memento/icube-ai-ng-chat-storage 开头的 key 的判断
  2. 使用 startsWith() 方法来检查字符串前缀
  3. 添加了类型检查,确保 key 是字符串类型

运行后,新生成的 JSON 文件将包含:

  • key 为 'inputHistory' 的数据
  • key 为 'ChatStore' 的数据
  • key 以 'memento/icube-ai-ng-chat-storage' 开头的数据
用户 (2025/2/18 17:10:50)

filtered_vscdb_output.json 再用 nodejs 写个脚本,解析对应的关系,将上一步解析出来的 json 文件的内容生成不同的 markdown 文件。名称用 parsedQuery 命名即可。解析的内容是 key 以 memento/icube-ai-ng-chat-storage 开头的,value.list 这个数组对象中的数据,每个对象生成一个 markdown 文件

助手 (2025/2/18 17:10:50)

我来帮你写一个 Node.js 脚本来处理这个需求:

const fs = require('fs'); const path = require('path'); // 读取 JSON 文件 function parseVSCDBToMarkdown() { try { // 读取 JSON 文件 const jsonData = JSON.parse(fs.readFileSync('./filtered_vscdb_output.json', 'utf8')); // 创建输出目录 const outputDir = './chat_markdown'; if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir); } // 查找以 memento/icube-ai-ng-chat-storage 开头的项 const chatData = jsonData.ItemTable.find(item => item.key.startsWith('memento/icube-ai-ng-chat-storage') ); if (!chatData || !chatData.value || !chatData.value.list) { console.log('没有找到聊天数据'); return; } // 处理每个会话 chatData.value.list.forEach(session => { if (!session.messages || !session.messages.length) return; // 获取第一条用户消息作为文件名 const firstUserMessage = session.messages.find(msg => msg.role === 'user' && msg.parsedQuery && msg.parsedQuery.length ); if (!firstUserMessage) return; const fileName = firstUserMessage.parsedQuery[0] .replace(/[<>:"/\\|?*]/g, '_') // 替换不合法的文件名字符 .substring(0, 100) // 限制文件名长度 + '.md'; let markdownContent = ''; // 生成 Markdown 内容 session.messages.forEach(msg => { if (msg.status === 'deleted') return; // 跳过已删除的消息 const role = msg.role === 'user' ? '**用户**' : '**助手**'; const timestamp = new Date(msg.timestamp).toLocaleString(); markdownContent += `### ${role} (${timestamp})\n\n`; markdownContent += `${msg.content}\n\n`; // 如果有多媒体内容 if (msg.multiMedia && msg.multiMedia.length) { markdownContent += '**多媒体内容:**\n'; msg.multiMedia.forEach(media => { markdownContent += `- ${media}\n`; }); markdownContent += '\n'; } markdownContent += '---\n\n'; }); // 写入文件 const filePath = path.join(outputDir, fileName); fs.writeFileSync(filePath, markdownContent, 'utf8'); console.log(`已生成文件:${fileName}`); }); console.log('所有 Markdown 文件生成完成!'); } catch (error) { console.error('处理过程中出错:', error); } } // 执行转换 parseVSCDBToMarkdown(); 

使用方法:

  1. 确保 filtered_vscdb_output.json 文件在同一目录下
  2. 运行脚本:
node parse_chat_to_md.js 

这个脚本会:

  1. 创建一个 chat_markdown 目录
  2. 查找以 memento/icube-ai-ng-chat-storage 开头的数据
  3. 遍历其中的 list 数组
  4. 为每个会话生成一个 Markdown 文件:
    • 使用第一条用户消息的 parsedQuery 作为文件名
    • 按时间顺序组织对话内容
    • 标记用户和助手的角色
    • 包含时间戳
    • 跳过已删除的消息
    • 处理可能的多媒体内容

生成的 Markdown 文件格式如下:

### **用户** (2024-02-19 10:30:00) 问题内容 --- ### **助手** (2024-02-19 10:30:01) 回答内容 --- 

注意事项:

  1. 文件名会自动处理特殊字符,确保合法
  2. 文件名长度限制为 100 字符
  3. 自动跳过 status 为 deleted 的消息
  4. 保留了消息的时间戳信息
用户 (2025/2/18 17:13:25)

vscdb.jsparse_chat_to_md.js 能将这两个脚本文件整合成一个脚本吗

助手 (2025/2/18 17:13:25)

是的,我来帮你整合这两个脚本文件:

const Database = require('better-sqlite3'); const fs = require('fs'); const path = require('path'); function parseVSCDB(filePath) { try { // 连接数据库 const db = new Database(filePath, { readonly: true }); // 获取所有表名 const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' `).all(); const result = {}; // 遍历每个表并获取内容 tables.forEach(table => { const tableName = table.name; const rows = db.prepare(`SELECT * FROM ${tableName}`).all(); // 尝试解析每行中可能的 JSON 字符串 const parsedRows = rows.map(row => { const parsedRow = {}; Object.entries(row).forEach(([key, value]) => { if (typeof value === 'string') { try { parsedRow[key] = JSON.parse(value); } catch { parsedRow[key] = value; } } else { parsedRow[key] = value; } }); return parsedRow; }); result[tableName] = parsedRows; }); // 关闭数据库连接 db.close(); // 过滤数据,只保留指定的 key const filteredData = {}; Object.entries(result).forEach(([tableName, tableData]) => { tableData.forEach(row => { if (row.key === 'inputHistory' || row.key === 'ChatStore' || (typeof row.key === 'string' && row.key.startsWith('memento/icube-ai-ng-chat-storage'))) { if (!filteredData[tableName]) { filteredData[tableName] = []; } filteredData[tableName].push(row); } }); }); return filteredData; } catch (error) { console.error('解析错误:', error.message); return null; } } function generateMarkdownFiles(jsonData) { try { // 创建输出目录 const outputDir = './chat_markdown'; if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir); } // 查找以 memento/icube-ai-ng-chat-storage 开头的项 const chatData = jsonData.ItemTable.find(item => item.key.startsWith('memento/icube-ai-ng-chat-storage') ); if (!chatData || !chatData.value || !chatData.value.list) { console.log('没有找到聊天数据'); return; } // 处理每个会话 chatData.value.list.forEach(session => { if (!session.messages || !session.messages.length) return; // 获取第一条用户消息作为文件名 const firstUserMessage = session.messages.find(msg => msg.role === 'user' && msg.parsedQuery && msg.parsedQuery.length ); if (!firstUserMessage) return; const fileName = firstUserMessage.parsedQuery[0] .replace(/[<>:"/\\|?*]/g, '_') // 替换不合法的文件名字符 .substring(0, 100) // 限制文件名长度 + '.md'; let markdownContent = ''; // 生成 Markdown 内容 session.messages.forEach(msg => { if (msg.status === 'deleted') return; // 跳过已删除的消息 const role = msg.role === 'user' ? '**用户**' : '**助手**'; const timestamp = new Date(msg.timestamp).toLocaleString(); markdownContent += `### ${role} (${timestamp})\n\n`; markdownContent += `${msg.content}\n\n`; // 如果有多媒体内容 if (msg.multiMedia && msg.multiMedia.length) { markdownContent += '**多媒体内容:**\n'; msg.multiMedia.forEach(media => { markdownContent += `- ${media}\n`; }); markdownContent += '\n'; } markdownContent += '---\n\n'; }); // 写入文件 const filePath = path.join(outputDir, fileName); fs.writeFileSync(filePath, markdownContent, 'utf8'); console.log(`已生成文件:${fileName}`); }); console.log('所有 Markdown 文件生成完成!'); } catch (error) { console.error('处理过程中出错:', error); } } // 主函数 function main() { const vscdbPath = './state.vscdb'; const data = parseVSCDB(vscdbPath); if (data) { // 将过滤后的数据写入 JSON 文件 try { fs.writeFileSync( 'filtered_vscdb_output.json', JSON.stringify(data, null, 2), 'utf8' ); console.log('数据已成功写入到 filtered_vscdb_output.json'); // 直接使用解析后的数据生成 Markdown 文件 generateMarkdownFiles(data); } catch (err) { console.error('处理过程中出错:', err); } } } // 执行程序 main(); 

主要改动:

  1. 将两个脚本合并为一个文件
  2. 重构为三个主要函数:
    • parseVSCDB: 解析数据库文件
    • generateMarkdownFiles: 生成 Markdown 文件
    • main: 主函数,协调整个流程
  3. 移除了中间 JSON 文件的读取步骤,直接使用内存中的数据
  4. 保留了 JSON 文件的输出,以便查看和调试

使用方法:

node vscdb_parser.js 

这个整合后的脚本会:

  1. 解析 .vscdb 文件
  2. 保存过滤后的 JSON 数据到文件
  3. 直接使用解析后的数据生成 Markdown 文件
  4. 全程只需要执行一次命令

运行脚本 导出 markdown 文件

首先我问 AI 后得知 它是一个 SQLite 数据库文件,使用二进制格式存储等巴拉巴拉。

接下来,我询问如何解析为纯文本,它给出我一个 python 脚本。貌似让大模型给你脚本的时候,如果不指定开发语言,它默认都是用 python 写的。

那不行啊,咱是前端开发,让它换成 nodejs。

后续再一步一步引导:写入 json 文件、打开 json 文件并分析数据格式、数据过滤、最终生成 markdown 文件。

运行一下,完美导出!

导出目录

完整脚本如下:

const Database = require('better-sqlite3'); const fs = require('fs'); const path = require('path'); function parseVSCDB(filePath) { try { // 连接数据库 const db = new Database(filePath, { readonly: true }); // 获取所有表名 const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' `).all(); const result = {}; // 遍历每个表并获取内容 tables.forEach(table => { const tableName = table.name; const rows = db.prepare(`SELECT * FROM ${tableName}`).all(); // 尝试解析每行中可能的 JSON 字符串 const parsedRows = rows.map(row => { const parsedRow = {}; Object.entries(row).forEach(([key, value]) => { if (typeof value === 'string') { try { parsedRow[key] = JSON.parse(value); } catch { parsedRow[key] = value; } } else { parsedRow[key] = value; } }); return parsedRow; }); result[tableName] = parsedRows; }); // 关闭数据库连接 db.close(); // 过滤数据,只保留指定的 key const filteredData = {}; Object.entries(result).forEach(([tableName, tableData]) => { tableData.forEach(row => { if (row.key === 'inputHistory' || row.key === 'ChatStore' || (typeof row.key === 'string' && row.key.startsWith('memento/icube-ai-ng-chat-storage'))) { if (!filteredData[tableName]) { filteredData[tableName] = []; } filteredData[tableName].push(row); } }); }); return filteredData; } catch (error) { console.error('解析错误:', error.message); return null; } } function generateMarkdownFiles(jsonData) { try { // 创建输出目录 const outputDir = './chat_markdown'; if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir); } // 查找以 memento/icube-ai-ng-chat-storage 开头的项 const chatData = jsonData.ItemTable.find(item => item.key.startsWith('memento/icube-ai-ng-chat-storage') ); if (!chatData || !chatData.value || !chatData.value.list) { console.log('没有找到聊天数据'); return; } // 处理每个会话 chatData.value.list.forEach(session => { if (!session.messages || !session.messages.length) return; // 获取第一条用户消息作为文件名 const firstUserMessage = session.messages.find(msg => msg.role === 'user' && msg.parsedQuery && msg.parsedQuery.length ); if (!firstUserMessage) return; const fileName = firstUserMessage.parsedQuery[0] .replace(/[<>:"/\\|?*]/g, '_') // 替换不合法的文件名字符 .substring(0, 100) // 限制文件名长度 + '.md'; let markdownContent = ''; // 生成 Markdown 内容 session.messages.forEach(msg => { if (msg.status === 'deleted') return; // 跳过已删除的消息 const role = msg.role === 'user' ? '**用户**' : '**助手**'; const timestamp = new Date(msg.timestamp).toLocaleString(); markdownContent += `### ${role} (${timestamp})\n\n`; markdownContent += `${msg.content}\n\n`; // 如果有多媒体内容 if (msg.multiMedia && msg.multiMedia.length) { markdownContent += '**多媒体内容:**\n'; msg.multiMedia.forEach(media => { markdownContent += `- ${media}\n`; }); markdownContent += '\n'; } markdownContent += '---\n\n'; }); // 写入文件 const filePath = path.join(outputDir, fileName); fs.writeFileSync(filePath, markdownContent, 'utf8'); console.log(`已生成文件:${fileName}`); }); console.log('所有 Markdown 文件生成完成!'); } catch (error) { console.error('处理过程中出错:', error); } } // 主函数 function main() { const vscdbPath = './state.vscdb'; const data = parseVSCDB(vscdbPath); if (data) { // 将过滤后的数据写入 JSON 文件 try { fs.writeFileSync( 'filtered_vscdb_output.json', JSON.stringify(data, null, 2), 'utf8' ); console.log('数据已成功写入到 filtered_vscdb_output.json'); // 直接使用解析后的数据生成 Markdown 文件 generateMarkdownFiles(data); } catch (err) { console.error('处理过程中出错:', err); } } } // 执行程序 main(); 

总结

本文通过分析 Trae AI 编辑器的工作区存储机制,借鉴 Cursor 对话记录导出插件的思路,实现了 Trae 编辑器的导出功能。

希望这个简单的实现能帮助到有相同需求的朋友,也期待未来 Trae 官方原生支持对话导出功能。

目录

  1. 前言
  2. 契机
  3. 分析
  4. AI 介入
  5. 用户 (2025/2/18 16:39:52)
  6. 助手 (2025/2/18 16:39:52)
  7. 用户 (2025/2/18 16:40:42)
  8. 助手 (2025/2/18 16:40:42)
  9. 用户 (2025/2/18 16:41:08)
  10. 助手 (2025/2/18 16:41:08)
  11. 用户 (2025/2/18 16:52:12)
  12. 助手 (2025/2/18 16:52:13)
  13. 用户 (2025/2/18 16:57:44)
  14. 助手 (2025/2/18 16:57:44)
  15. 用户 (2025/2/18 17:01:37)
  16. 助手 (2025/2/18 17:01:37)
  17. 用户 (2025/2/18 17:10:50)
  18. 助手 (2025/2/18 17:10:50)
  19. 用户 (2024-02-19 10:30:00) 问题内容 --- ### 助手 (2024-02-19 10:30:01) 回答内容 ---
  20. 用户 (2025/2/18 17:13:25)
  21. 助手 (2025/2/18 17:13:25)
  22. 运行脚本 导出 markdown 文件
  23. 总结

更多推荐文章

查看全部
  • 海康机器人 3D 激光轮廓仪快速调试指南
  • FastAPI:Python 高性能 Web 框架的优雅之选
  • 从 Prompt 到爆款短片:AI视频生成 10 分钟上手指南
  • 群智能算法:灰狼优化算法(GWO)原理与实现
  • 35 道常见前端 Vue 面试题深度解析
  • Mac mini 部署 OpenClaw:接入国产大模型与飞书机器人
  • AI 大模型应用数据中心建设与运维管理
  • 大模型算法岗常见面试题 100 道
  • 条件变分自编码器(cVAE)原理与实现
  • C++ 面试高频考点与核心技术解析
  • Ubuntu 下 CUDA 环境安装与配置
  • Mastering GitHub Copilot 课程点评:免费版与 Pro 版差异解析
  • Web 自动化测试入门:Selenium 核心原理与实战脚本
  • 五大国产 AI 工具实战指南:豆包即梦剪映飞书扣子
  • Next-AI-Draw.io 开源 AI 绘图工具自托管部署指南
  • 鸿蒙金融理财全栈项目:风险控制、合规审计与产品创新
  • Ubuntu 22.04 部署 OpenClaw 自动化助手实战
  • 解决新机型 Copilot 键替代右 Ctrl 键问题
  • Web 项目 UI 自动化测试实战:从零搭建博客系统框架
  • ComfyUI-Manager 实战指南:插件与模型的高效管理

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online