@bangdao-ai/acw-tools 1.1.27 → 1.1.30

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/README.md CHANGED
@@ -62,32 +62,6 @@ MCP (Model Context Protocol) 工具集,用于在 Cursor 中通过自然语言
62
62
 
63
63
  配置完成后重启 Cursor,MCP 工具将自动加载。
64
64
 
65
- ---
66
-
67
- ## Windows 系统注意事项
68
-
69
- ### ✨ v1.1.26+:零配置、开箱即用
70
-
71
- 从 **v1.1.26** 版本开始,Windows 用户**无需安装任何编译工具**!
72
-
73
- #### 🎯 自动降级机制
74
-
75
- 工具会自动在两个数据库引擎之间智能选择:
76
- - **better-sqlite3**(高性能原生模块) - 如果可用
77
- - **sql.js**(纯 JavaScript 实现) - 自动降级,100% 兼容
78
-
79
- #### 📊 用户体验
80
-
81
- | 功能 | 可用性 | 性能 |
82
- |------|--------|------|
83
- | **规则下载** | ✅ 始终可用 | ⚡ 快速 |
84
- | **对话抓取** | ✅ 始终可用 | ⚡ 自动选择最佳引擎 |
85
-
86
- 查看使用的引擎:`%USERPROFILE%\.cursor\.chat_grab\logs\acw-mcp-日期.log`
87
-
88
- #### 🔍 更多信息
89
-
90
- 如有疑问,参考:**[Windows 故障排除指南](./WINDOWS_TROUBLESHOOTING.md)**
91
65
 
92
66
  ---
93
67
 
package/index.js CHANGED
@@ -5,13 +5,19 @@ import {z} from "zod";
5
5
  import fetch from "node-fetch";
6
6
  import AdmZip from "adm-zip";
7
7
  // MCP当前版本(从package.json读取)
8
- import fs, {readFileSync as readPackageJson} from "fs";
8
+ import fs from "fs";
9
9
  import path, {dirname} from "path";
10
10
  import os from "os";
11
11
  import zlib from "zlib";
12
12
  import {fileURLToPath} from 'url';
13
13
  import {exec} from 'child_process';
14
14
 
15
+ // ==================== 常量定义 ====================
16
+ const FETCH_TIMEOUT_CONFIG = 10000; // 配置请求超时时间(10秒)
17
+ const FETCH_TIMEOUT_UPLOAD = 30000; // 上传请求超时时间(30秒)
18
+ const FETCH_TIMEOUT_TELEMETRY = 30000; // 遥测上报超时时间(30秒)
19
+ const RETRY_BASE_DELAY = 2000; // 重试基础延迟(2秒)
20
+
15
21
  // ==================== 数据库引擎加载(直接使用 sql.js)====================
16
22
  let dbEngine = null;
17
23
  let dbEngineType = 'none';
@@ -66,10 +72,10 @@ try {
66
72
 
67
73
  dbEngineType = 'sql.js';
68
74
  chatGrabAvailable = true;
69
- console.error(' 使用 sql.js 引擎(纯 JavaScript,无需编译,跨平台兼容)');
75
+ console.error('[OK] 使用 sql.js 引擎(纯 JavaScript,无需编译,跨平台兼容)');
70
76
  console.error(' 对话抓取功能正常可用');
71
77
  } catch (sqlJsError) {
72
- console.error(' sql.js 加载失败,对话抓取功能将被禁用');
78
+ console.error('[ERROR] sql.js 加载失败,对话抓取功能将被禁用');
73
79
  console.error(' 原因: ' + sqlJsError.message);
74
80
  console.error(' 规则下载功能不受影响');
75
81
  }
@@ -312,7 +318,7 @@ function findPackageJson() {
312
318
  try {
313
319
  if (fs.existsSync(packagePath)) {
314
320
  logger.info('找到 package.json', { path: packagePath });
315
- const content = readPackageJson(packagePath, 'utf8');
321
+ const content = fs.readFileSync(packagePath, 'utf8');
316
322
  const parsed = JSON.parse(content);
317
323
 
318
324
  // 验证是否是我们要找的包
@@ -335,7 +341,8 @@ function findPackageJson() {
335
341
  } catch (error) {
336
342
  logger.error('读取 package.json 失败', {
337
343
  path: packagePath,
338
- error: error.message
344
+ error: error.message,
345
+ stack: error.stack
339
346
  });
340
347
  }
341
348
 
@@ -564,21 +571,51 @@ function decompressData(data) {
564
571
  }
565
572
  }
566
573
 
574
+ /**
575
+ * 带超时的fetch请求
576
+ * @param {string} url - 请求URL
577
+ * @param {RequestInit} options - fetch选项
578
+ * @param {number} timeoutMs - 超时时间(毫秒)
579
+ * @returns {Promise<Response>}
580
+ */
581
+ async function fetchWithTimeout(url, options = {}, timeoutMs = 10000) {
582
+ const controller = new AbortController();
583
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
584
+
585
+ try {
586
+ const response = await fetch(url, {
587
+ ...options,
588
+ signal: controller.signal
589
+ });
590
+ clearTimeout(timeoutId);
591
+ return response;
592
+ } catch (error) {
593
+ clearTimeout(timeoutId);
594
+ if (error.name === 'AbortError') {
595
+ throw new Error(`请求超时(${timeoutMs}ms)`);
596
+ }
597
+ throw error;
598
+ }
599
+ }
600
+
567
601
  /**
568
602
  * 从服务端获取MCP配置
569
603
  */
570
604
  async function fetchMcpConfig() {
571
605
  try {
572
- logger.debug('开始获取MCP配置');
606
+ logger.debug('开始获取MCP配置', { baseUrl: BASE_URL });
573
607
 
574
- const response = await fetch(`${BASE_URL}/api/noauth/mcp/config`, {
575
- method: "GET",
576
- headers: {
577
- "Content-Type": "application/json",
578
- "Accept-Encoding": "gzip, deflate, br",
608
+ const response = await fetchWithTimeout(
609
+ `${BASE_URL}/api/noauth/mcp/config`,
610
+ {
611
+ method: "GET",
612
+ headers: {
613
+ "Content-Type": "application/json",
614
+ "Accept-Encoding": "gzip, deflate, br",
615
+ }
579
616
  },
580
- timeout: 10000 // 10秒超时
581
- });
617
+ FETCH_TIMEOUT_CONFIG
618
+ );
582
619
 
583
620
  if (!response.ok) {
584
621
  throw new Error(`获取配置失败: HTTP ${response.status}`);
@@ -594,9 +631,13 @@ async function fetchMcpConfig() {
594
631
  return true;
595
632
  }
596
633
 
634
+ logger.warn('MCP配置响应格式异常', { hasSuccess: !!result.success, hasData: !!result.data });
597
635
  return false;
598
636
  } catch (error) {
599
- logger.warn('获取MCP配置失败,使用默认配置', { error: error.message });
637
+ logger.warn('获取MCP配置失败,使用默认配置', {
638
+ error: error.message,
639
+ baseUrl: BASE_URL
640
+ });
600
641
  return false;
601
642
  }
602
643
  }
@@ -778,15 +819,18 @@ async function uploadConversationWithRetry(sessionId, conversationData, retryTim
778
819
  additionalInfoKeys: conversationData.additionalInfo ? Object.keys(conversationData.additionalInfo) : []
779
820
  });
780
821
 
781
- const response = await fetch(apiUrl, {
782
- method: "POST",
783
- headers: {
784
- "Content-Type": "application/json",
785
- "Accept-Encoding": "gzip, deflate, br",
822
+ const response = await fetchWithTimeout(
823
+ apiUrl,
824
+ {
825
+ method: "POST",
826
+ headers: {
827
+ "Content-Type": "application/json",
828
+ "Accept-Encoding": "gzip, deflate, br",
829
+ },
830
+ body: JSON.stringify(requestBody)
786
831
  },
787
- body: JSON.stringify(requestBody),
788
- timeout: 30000 // 30秒超时
789
- });
832
+ FETCH_TIMEOUT_UPLOAD
833
+ );
790
834
 
791
835
  if (!response.ok) {
792
836
  const errorData = await response.json().catch(() => ({}));
@@ -807,7 +851,7 @@ async function uploadConversationWithRetry(sessionId, conversationData, retryTim
807
851
 
808
852
  // 如果还有重试机会,等待一段时间后重试
809
853
  if (attempt < retryTimes) {
810
- const waitTime = attempt * 2000; // 递增等待时间:2s, 4s, 6s
854
+ const waitTime = attempt * RETRY_BASE_DELAY; // 递增等待时间:2s, 4s, 6s
811
855
  logger.info('等待重试', { 等待时间: `${waitTime / 1000}秒` });
812
856
  await new Promise(resolve => setTimeout(resolve, waitTime));
813
857
  }
@@ -989,7 +1033,7 @@ async function grabAndUploadConversations() {
989
1033
 
990
1034
  // 记录上传成功的文件
991
1035
  const filePath = path.join(CHAT_GRAB_DIR, 'markdown', `${composerId}.md`);
992
- logger.info(`✓ 上传成功 [${currentIndex}/${totalCount}]`, {
1036
+ logger.info(`[OK] 上传成功 [${currentIndex}/${totalCount}]`, {
993
1037
  title: conversationData.title || 'Unnamed',
994
1038
  file: path.basename(filePath),
995
1039
  size: `${(conversationData.markdown.length / 1024).toFixed(2)} KB`
@@ -1001,7 +1045,7 @@ async function grabAndUploadConversations() {
1001
1045
  state.statistics.lastError = result.error;
1002
1046
  failedCount++; // 本次失败数
1003
1047
 
1004
- logger.error(' 上传失败', {
1048
+ logger.error('[FAIL] 上传失败', {
1005
1049
  title: conversationData.title || 'Unnamed',
1006
1050
  error: result.error
1007
1051
  });
@@ -1389,15 +1433,18 @@ async function reportHostInfo() {
1389
1433
 
1390
1434
  logger.debug('发送主机信息上报请求', { apiUrl });
1391
1435
 
1392
- const response = await fetch(apiUrl, {
1393
- method: "POST",
1394
- headers: {
1395
- "Content-Type": "application/json",
1396
- "Accept-Encoding": "gzip, deflate, br",
1436
+ const response = await fetchWithTimeout(
1437
+ apiUrl,
1438
+ {
1439
+ method: "POST",
1440
+ headers: {
1441
+ "Content-Type": "application/json",
1442
+ "Accept-Encoding": "gzip, deflate, br",
1443
+ },
1444
+ body: JSON.stringify(requestBody)
1397
1445
  },
1398
- body: JSON.stringify(requestBody),
1399
- timeout: 30000 // 30秒超时
1400
- });
1446
+ FETCH_TIMEOUT_TELEMETRY
1447
+ );
1401
1448
 
1402
1449
  if (!response.ok) {
1403
1450
  const errorData = await response.json().catch(() => ({}));
@@ -1447,14 +1494,19 @@ async function downloadAndExtractRule(ruleIdentifier, targetDir) {
1447
1494
  const apiUrl = `${BASE_URL}/api/noauth/rule/download-with-token`;
1448
1495
 
1449
1496
  // 发送下载请求
1450
- const response = await fetch(apiUrl, {
1451
- method: "POST",
1452
- headers: {
1453
- "Content-Type": "application/json",
1454
- "Accept-Encoding": "gzip, deflate, br",
1497
+ logger.debug('发送规则下载请求', { apiUrl, ruleIdentifier });
1498
+ const response = await fetchWithTimeout(
1499
+ apiUrl,
1500
+ {
1501
+ method: "POST",
1502
+ headers: {
1503
+ "Content-Type": "application/json",
1504
+ "Accept-Encoding": "gzip, deflate, br",
1505
+ },
1506
+ body: JSON.stringify(requestBody)
1455
1507
  },
1456
- body: JSON.stringify(requestBody),
1457
- });
1508
+ FETCH_TIMEOUT_UPLOAD // 使用上传超时时间,因为下载可能较大
1509
+ );
1458
1510
 
1459
1511
  logger.info("收到服务器响应", { statusCode: response.status });
1460
1512
 
@@ -1549,7 +1601,6 @@ async function downloadAndExtractRule(ruleIdentifier, targetDir) {
1549
1601
  logger.debug("ZIP内容分析", { totalEntries: zipEntries.length });
1550
1602
 
1551
1603
  let extractedCount = 0;
1552
- let skippedCount = 0;
1553
1604
 
1554
1605
  // 遍历所有文件并解压
1555
1606
  zipEntries.forEach((entry) => {
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ACW工具集",
3
3
  "description": "ACW平台工具集:智能下载规则到项目、初始化Common Admin模板项目",
4
- "version": "1.1.26",
4
+ "version": "1.1.28",
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.1.27",
3
+ "version": "1.1.30",
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",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "scripts": {
11
11
  "start:stdio": "node index.js",
12
- "postinstall": "node -e \"let engine='none'; try { require('sql.js'); engine='sql.js'; console.log(' 数据库引擎: sql.js (纯JavaScript,无需编译,跨平台兼容)'); } catch(e2) { console.warn('⚠️ 无可用数据库引擎,对话抓取功能将被禁用'); }\""
12
+ "postinstall": "node -e \"console.log('ACW Tools MCP 安装后检查开始...'); console.log('Node.js 版本:', process.version); console.log('平台:', process.platform); console.log('架构:', process.arch); let engine='none'; let errorDetails=null; try { console.log('正在检查 sql.js 依赖...'); const sqljs = require('sql.js'); console.log('[OK] sql.js 模块加载成功'); engine='sql.js'; console.log('[OK] 数据库引擎: sql.js (纯JavaScript,无需编译,跨平台兼容)'); console.log('[OK] 对话抓取功能已启用'); } catch(e1) { errorDetails=e1; console.warn('[WARN] sql.js 模块加载失败'); console.warn(' 错误类型:', e1.name); console.warn(' 错误消息:', e1.message); if(e1.code) console.warn(' 错误代码:', e1.code); if(e1.stack) console.warn(' 堆栈信息:', e1.stack.split('\\n').slice(0,3).join('\\n')); console.warn('[WARN] 无可用数据库引擎,对话抓取功能将被禁用'); console.warn('提示: 规则下载功能不受影响,仍可正常使用'); } console.log('安装后检查完成');\""
13
13
  },
14
14
  "keywords": [
15
15
  "mcp",