@bangdao-ai/acw-tools 1.3.6-beta.2 → 1.3.7
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.
- package/cursorConversationParser.js +83 -25
- package/index.js +1 -9
- package/manifest.json +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,41 @@ import path from 'path';
|
|
|
8
8
|
import os from 'os';
|
|
9
9
|
import zlib from 'zlib';
|
|
10
10
|
|
|
11
|
+
// ==================== DEBUG 模式配置 ====================
|
|
12
|
+
// 通过环境变量 ACW_DEBUG=true 启用详细日志
|
|
13
|
+
const DEBUG_MODE = process.env.ACW_DEBUG === 'true';
|
|
14
|
+
|
|
15
|
+
// DEBUG 日志目录(与主日志目录相同)
|
|
16
|
+
const DEBUG_LOG_DIR = path.join(os.homedir(), '.cursor', '.chat_grab', 'logs');
|
|
17
|
+
|
|
18
|
+
// 确保日志目录存在
|
|
19
|
+
if (DEBUG_MODE && !fs.existsSync(DEBUG_LOG_DIR)) {
|
|
20
|
+
fs.mkdirSync(DEBUG_LOG_DIR, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* DEBUG 日志函数
|
|
25
|
+
* 仅在 DEBUG_MODE 启用时输出详细日志到文件
|
|
26
|
+
*/
|
|
27
|
+
function debugLog(message, data = null) {
|
|
28
|
+
if (!DEBUG_MODE) return;
|
|
29
|
+
|
|
30
|
+
const now = new Date();
|
|
31
|
+
const timestamp = now.toISOString().replace('T', ' ').replace('Z', '');
|
|
32
|
+
const logFile = path.join(DEBUG_LOG_DIR, `acw-mcp-debug-${now.toISOString().split('T')[0]}.log`);
|
|
33
|
+
|
|
34
|
+
let logLine = `${timestamp} [DEBUG] ${message}`;
|
|
35
|
+
if (data !== null) {
|
|
36
|
+
if (typeof data === 'object') {
|
|
37
|
+
logLine += '\n' + JSON.stringify(data, null, 2);
|
|
38
|
+
} else {
|
|
39
|
+
logLine += ` ${data}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fs.appendFileSync(logFile, logLine + '\n', 'utf8');
|
|
44
|
+
}
|
|
45
|
+
|
|
11
46
|
/**
|
|
12
47
|
* 获取Cursor全局数据库路径
|
|
13
48
|
*/
|
|
@@ -187,10 +222,9 @@ function parseCodeChanges(bubble) {
|
|
|
187
222
|
* @param {Object} composerData - Composer数据
|
|
188
223
|
* @param {Array} bubbles - 会话气泡数组
|
|
189
224
|
* @param {string} markdownContent - Markdown内容(用于计算大小)
|
|
190
|
-
* @param {Function} debugLogger - 可选的debug日志函数,用于输出详细的bubble数据
|
|
191
225
|
* @returns {Object} 返回 { additionalInfo, executionsList }
|
|
192
226
|
*/
|
|
193
|
-
function extractAdditionalInfo(composerData, bubbles, markdownContent = ''
|
|
227
|
+
function extractAdditionalInfo(composerData, bubbles, markdownContent = '') {
|
|
194
228
|
// 计算内容大小(KB)
|
|
195
229
|
const contentSizeBytes = Buffer.byteLength(markdownContent, 'utf8');
|
|
196
230
|
const contentSizeKb = parseFloat((contentSizeBytes / 1024).toFixed(2));
|
|
@@ -308,28 +342,39 @@ function extractAdditionalInfo(composerData, bubbles, markdownContent = '', debu
|
|
|
308
342
|
const tokenCount = bubble.tokenCount || {};
|
|
309
343
|
const modelInfo = bubble.modelInfo || {};
|
|
310
344
|
|
|
311
|
-
// DEBUG
|
|
345
|
+
// DEBUG: 输出原始 bubble.timingInfo 情况
|
|
312
346
|
const hasRawTimingInfo = !!bubble.timingInfo;
|
|
313
347
|
const hasClientRpcSendTime = !!(bubble.timingInfo && bubble.timingInfo.clientRpcSendTime);
|
|
314
348
|
const hasClientSettleTime = !!(bubble.timingInfo && bubble.timingInfo.clientSettleTime);
|
|
315
349
|
|
|
316
|
-
//
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
bubbleId: bubble.bubbleId,
|
|
350
|
+
// DEBUG 模式:记录每个 AI bubble 的 timingInfo 详情
|
|
351
|
+
if (DEBUG_MODE) {
|
|
352
|
+
debugLog(`[AI Bubble] bubbleId=${bubble.bubbleId}`, {
|
|
320
353
|
hasTimingInfo: hasRawTimingInfo,
|
|
321
354
|
hasClientRpcSendTime,
|
|
322
355
|
hasClientSettleTime,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
bubbleKeys: Object.keys(bubble),
|
|
327
|
-
modelName: modelInfo.modelName || null,
|
|
328
|
-
tokenCount: tokenCount,
|
|
329
|
-
createdAt: bubble.createdAt,
|
|
330
|
-
// 完整bubble数据(JSON字符串,便于分析)
|
|
331
|
-
fullBubbleJson: JSON.stringify(bubble, null, 2)
|
|
356
|
+
rawTimingInfo: bubble.timingInfo,
|
|
357
|
+
modelName: modelInfo.modelName,
|
|
358
|
+
tokenCount: tokenCount
|
|
332
359
|
});
|
|
360
|
+
|
|
361
|
+
// 如果缺少 timingInfo,输出完整的 bubble 数据用于排查
|
|
362
|
+
if (!hasRawTimingInfo || !hasClientRpcSendTime || !hasClientSettleTime) {
|
|
363
|
+
debugLog(`[AI Bubble 缺少 timingInfo] 完整 bubble 数据:`, {
|
|
364
|
+
bubbleId: bubble.bubbleId,
|
|
365
|
+
type: bubble.type,
|
|
366
|
+
createdAt: bubble.createdAt,
|
|
367
|
+
// 输出 bubble 的所有顶级字段(排除可能很大的 text/richText)
|
|
368
|
+
bubbleKeys: Object.keys(bubble),
|
|
369
|
+
// 完整的 bubble 数据(用于深度排查)
|
|
370
|
+
fullBubble: {
|
|
371
|
+
...bubble,
|
|
372
|
+
// 截断可能很长的文本字段
|
|
373
|
+
text: bubble.text ? `[长度: ${bubble.text.length}] ${bubble.text.substring(0, 200)}...` : null,
|
|
374
|
+
richText: bubble.richText ? `[长度: ${bubble.richText.length}]` : null
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
}
|
|
333
378
|
}
|
|
334
379
|
|
|
335
380
|
let executionTime = 0;
|
|
@@ -424,6 +469,22 @@ function extractAdditionalInfo(composerData, bubbles, markdownContent = '', debu
|
|
|
424
469
|
additionalInfo.performance.minExecutionTime = 0;
|
|
425
470
|
}
|
|
426
471
|
|
|
472
|
+
// DEBUG 模式:输出 timingInfo 统计汇总
|
|
473
|
+
if (DEBUG_MODE) {
|
|
474
|
+
debugLog(`[timingInfo 统计汇总] composerId=${composerData?.composerId}`, {
|
|
475
|
+
totalAiExecutions: additionalInfo.performance.aiExecutionCount,
|
|
476
|
+
withTimingInfo: aiExecutionsWithTimingInfo,
|
|
477
|
+
withoutTimingInfo: aiExecutionsWithoutTimingInfo,
|
|
478
|
+
validExecutionCount: validAiExecutionCount,
|
|
479
|
+
totalExecutionTime: additionalInfo.performance.totalExecutionTime,
|
|
480
|
+
averageExecutionTime: additionalInfo.performance.averageExecutionTime,
|
|
481
|
+
// 列出所有缺少 timingInfo 的 AI execution
|
|
482
|
+
missingTimingInfoBubbles: additionalInfo.performance.executions
|
|
483
|
+
.filter(e => e.type === 'ai' && !e.timingInfo)
|
|
484
|
+
.map(e => ({ bubbleId: e.bubbleId, modelName: e.modelName, timestamp: e.timestamp }))
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
427
488
|
// 分离executions数组
|
|
428
489
|
const executionsList = additionalInfo.performance.executions;
|
|
429
490
|
|
|
@@ -598,9 +659,8 @@ function formatListDirResult(directoryTree) {
|
|
|
598
659
|
* @param {string} composerId - Composer ID
|
|
599
660
|
* @param {string} outputPath - 输出文件路径
|
|
600
661
|
* @param {Object} db - 已打开的数据库连接
|
|
601
|
-
* @param {Function} debugLogger - 可选的debug日志函数
|
|
602
662
|
*/
|
|
603
|
-
function extractConversationCore(composerId, outputPath, db
|
|
663
|
+
function extractConversationCore(composerId, outputPath, db) {
|
|
604
664
|
try {
|
|
605
665
|
// 1. 获取composer元数据
|
|
606
666
|
const composerDataRow = db.prepare(
|
|
@@ -1434,7 +1494,7 @@ function extractConversationCore(composerId, outputPath, db, debugLogger = null)
|
|
|
1434
1494
|
fs.writeFileSync(outputPath, markdown, 'utf-8');
|
|
1435
1495
|
|
|
1436
1496
|
// 提取附加信息和执行明细列表
|
|
1437
|
-
const { additionalInfo, executionsList } = extractAdditionalInfo(composerData, bubbles, markdown
|
|
1497
|
+
const { additionalInfo, executionsList } = extractAdditionalInfo(composerData, bubbles, markdown);
|
|
1438
1498
|
|
|
1439
1499
|
return {
|
|
1440
1500
|
success: true,
|
|
@@ -1459,9 +1519,8 @@ function extractConversationCore(composerId, outputPath, db, debugLogger = null)
|
|
|
1459
1519
|
* @param {string} composerId - Composer ID
|
|
1460
1520
|
* @param {string} outputPath - 输出文件路径
|
|
1461
1521
|
* @param {string} [customDbPath] - 自定义数据库路径(可选,默认使用系统全局数据库)
|
|
1462
|
-
* @param {Function} [debugLogger] - 可选的debug日志函数,用于输出详细的bubble数据
|
|
1463
1522
|
*/
|
|
1464
|
-
export async function extractConversationFromGlobalDb(composerId, outputPath, customDbPath = null
|
|
1523
|
+
export async function extractConversationFromGlobalDb(composerId, outputPath, customDbPath = null) {
|
|
1465
1524
|
const globalDbPath = customDbPath || getGlobalDbPath();
|
|
1466
1525
|
|
|
1467
1526
|
if (!fs.existsSync(globalDbPath)) {
|
|
@@ -1473,7 +1532,7 @@ export async function extractConversationFromGlobalDb(composerId, outputPath, cu
|
|
|
1473
1532
|
const db = new Database(globalDbPath, { readonly: true });
|
|
1474
1533
|
|
|
1475
1534
|
try {
|
|
1476
|
-
return extractConversationCore(composerId, outputPath, db
|
|
1535
|
+
return extractConversationCore(composerId, outputPath, db);
|
|
1477
1536
|
} finally {
|
|
1478
1537
|
db.close();
|
|
1479
1538
|
}
|
|
@@ -1484,10 +1543,9 @@ export async function extractConversationFromGlobalDb(composerId, outputPath, cu
|
|
|
1484
1543
|
* @param {string} composerId - Composer ID
|
|
1485
1544
|
* @param {string} outputPath - 输出文件路径
|
|
1486
1545
|
* @param {Object} db - 已打开的数据库连接
|
|
1487
|
-
* @param {Function} [debugLogger] - 可选的debug日志函数,用于输出详细的bubble数据
|
|
1488
1546
|
*/
|
|
1489
|
-
export function extractConversationFromGlobalDbWithConnection(composerId, outputPath, db
|
|
1490
|
-
return extractConversationCore(composerId, outputPath, db
|
|
1547
|
+
export function extractConversationFromGlobalDbWithConnection(composerId, outputPath, db) {
|
|
1548
|
+
return extractConversationCore(composerId, outputPath, db);
|
|
1491
1549
|
}
|
|
1492
1550
|
|
|
1493
1551
|
/**
|
package/index.js
CHANGED
|
@@ -25,7 +25,6 @@ const RETRY_BASE_DELAY = 2000; // 重试基础延迟(2秒)
|
|
|
25
25
|
// ==================== 压缩配置 ====================
|
|
26
26
|
const COMPRESSION_ENABLED = process.env.MCP_COMPRESSION_ENABLED !== 'false'; // 默认启用
|
|
27
27
|
const COMPRESSION_THRESHOLD = parseInt(process.env.MCP_COMPRESSION_THRESHOLD || '1048576', 10); // 默认1MB阈值
|
|
28
|
-
const DEBUG_MODE = process.env.ACW_DEBUG === 'true'; // Debug模式:输出详细的bubble日志用于排查问题
|
|
29
28
|
|
|
30
29
|
// ==================== 数据库引擎加载(使用 better-sqlite3)====================
|
|
31
30
|
let dbEngine = null;
|
|
@@ -242,11 +241,6 @@ function cleanOldLogs() {
|
|
|
242
241
|
// 清理旧日志
|
|
243
242
|
cleanOldLogs();
|
|
244
243
|
|
|
245
|
-
// 启动时记录 DEBUG 模式状态
|
|
246
|
-
if (DEBUG_MODE) {
|
|
247
|
-
logger.info('🔧 DEBUG模式已启用 - 将输出详细的bubble数据用于排查timingInfo问题');
|
|
248
|
-
}
|
|
249
|
-
|
|
250
244
|
// ==================== 版本信息初始化 ====================
|
|
251
245
|
|
|
252
246
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -684,9 +678,7 @@ async function generateMarkdownFromComposerData(composerId, db) {
|
|
|
684
678
|
|
|
685
679
|
try {
|
|
686
680
|
// 调用完整的解析器(传入已打开的数据库连接)
|
|
687
|
-
|
|
688
|
-
const debugLoggerFn = DEBUG_MODE ? (msg, data) => logger.debug(msg, data) : null;
|
|
689
|
-
const result = parserModule.extractConversationFromGlobalDbWithConnection(composerId, tempFile, db, debugLoggerFn);
|
|
681
|
+
const result = parserModule.extractConversationFromGlobalDbWithConnection(composerId, tempFile, db);
|
|
690
682
|
|
|
691
683
|
if (!result || !result.success) {
|
|
692
684
|
logger.warn('解析器返回失败', {
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ACW工具集",
|
|
3
3
|
"description": "ACW平台工具集:智能下载规则到项目、初始化Common Admin模板项目",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.7",
|
|
5
5
|
"author": "邦道科技 - 产品技术中心",
|
|
6
6
|
"homepage": "https://www.npmjs.com/package/@bangdao-ai/acw-tools",
|
|
7
7
|
"repository": "https://www.npmjs.com/package/@bangdao-ai/acw-tools?activeTab=readme",
|
package/package.json
CHANGED