@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.
@@ -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 = '', debugLogger = null) {
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模式:输出完整的bubble数据用于排查timingInfo问题
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
- // 如果没有timingInfo或缺少关键字段,输出详细日志
317
- if (debugLogger && (!hasRawTimingInfo || !hasClientRpcSendTime || !hasClientSettleTime)) {
318
- debugLogger('🔍 [DEBUG] AI bubble缺少timingInfo关键字段', {
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
- timingInfoKeys: bubble.timingInfo ? Object.keys(bubble.timingInfo) : [],
324
- timingInfoValues: bubble.timingInfo || null,
325
- // 输出bubble的其他关键字段帮助排查
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, debugLogger = null) {
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, debugLogger);
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, debugLogger = 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, debugLogger);
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, debugLogger = null) {
1490
- return extractConversationCore(composerId, outputPath, db, debugLogger);
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
- // DEBUG模式下传入logger.debug用于输出详细的bubble数据
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.6",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bangdao-ai/acw-tools",
3
- "version": "1.3.6-beta.2",
3
+ "version": "1.3.7",
4
4
  "type": "module",
5
5
  "description": "MCP (Model Context Protocol) tools for ACW - download rules and initialize Common Admin projects",
6
6
  "main": "index.js",