mta-mcp 3.1.0 → 3.2.1

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mta-mcp",
3
- "version": "3.1.0",
4
- "description": "MTA - 智能编码助手 MCP 服务器(规范 + 技能 + 诊断 + 模板)",
3
+ "version": "3.2.1",
4
+ "description": "MTA - 智能编码助手 MCP 服务器(规范 + 技能 + 诊断 + 模板 + 记忆 + 思考)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -21,7 +21,6 @@
21
21
  "standards/",
22
22
  "agents/",
23
23
  "templates/",
24
- "skills.json",
25
24
  "README.md"
26
25
  ],
27
26
  "scripts": {
@@ -59,12 +58,11 @@
59
58
  },
60
59
  "dependencies": {
61
60
  "@modelcontextprotocol/sdk": "^1.24.3",
61
+ "@modelcontextprotocol/server-filesystem": "^2026.1.14",
62
+ "@modelcontextprotocol/server-memory": "^2025.11.25",
63
+ "@modelcontextprotocol/server-sequential-thinking": "^2025.12.18",
62
64
  "axios": "^1.6.5",
63
- "fast-glob": "^3.3.2",
64
- "semver": "^7.6.0"
65
- },
66
- "optionalDependencies": {
67
- "@anthropic-ai/sdk": "^0.30.0"
65
+ "fast-glob": "^3.3.2"
68
66
  },
69
67
  "devDependencies": {
70
68
  "@types/node": "^20.11.0",
@@ -8,6 +8,78 @@ Sketch MCP 是用于从 Sketch 设计文件中提取 UI 参数的工具。本文
8
8
 
9
9
  ---
10
10
 
11
+ ## 🔴 核心原则:测量 + 计算(最高优先级)
12
+
13
+ **⚠️ 关键规则:绝不直接使用测量数据,必须分析计算后再使用!**
14
+
15
+ ### 为什么需要计算?
16
+
17
+ | 场景 | 测量得到的原始数据 | 需要计算的目标值 |
18
+ |------|-------------------|-----------------|
19
+ | **行高** | 文本 Y=8, 高度=20, 字号=14 | `height: 20/14 = 1.43` |
20
+ | **居中边距** | 上边距=8, 下边距=8 | 容器用 `alignment: center` |
21
+ | **渐变方向** | from={x:0,y:0}, to={x:1,y:1} | Flutter `Alignment(-1,-1) → (1,1)` |
22
+ | **透明度** | `#1C2B4580` | `0x80 = 128/255 = 0.5` |
23
+
24
+ ### 标准流程
25
+
26
+ ```
27
+ 1. 测量 - 获取原始像素值和坐标
28
+ 2. 分析 - 理解设计师意图(居中?等间距?)
29
+ 3. 计算 - 转换为目标框架需要的参数
30
+ 4. 验证 - 与设计稿对比确认
31
+ ```
32
+
33
+ ### 典型计算公式
34
+
35
+ ```javascript
36
+ // 行高计算(Flutter/CSS 通用)
37
+ const lineHeight = 文本高度 / 字号; // 如 20/14 = 1.43
38
+
39
+ // 居中验证
40
+ const isVerticalCentered = Math.abs(上边距 - 下边距) < 2;
41
+
42
+ // 渐变角度(CSS)
43
+ const angle = Math.atan2(to.y - from.y, to.x - from.x) * 180 / Math.PI + 90;
44
+
45
+ // 透明度(从 8 位十六进制)
46
+ const alpha = parseInt(colorHex.slice(7, 9), 16) / 255;
47
+ ```
48
+
49
+ > 📖 **详细案例**:参考 [TextField 垂直居中问题](../troubleshooting-cases/flutter/textfield-vertical-centering.md),展示了如何从测量数据计算行高和配置参数。
50
+
51
+ ---
52
+
53
+ ## 🛠️ 配合测量模板使用
54
+
55
+ 调用 Sketch MCP 时,应结合 `templates/design-measurement/` 目录下的测量脚本:
56
+
57
+ | 场景 | 使用的模板 | 用途 |
58
+ |------|-----------|------|
59
+ | 单组件测量 | `component-measurement.js` | 获取尺寸、**自动计算相对边距** |
60
+ | 元素间距 | `gap-measurement.js` | 计算垂直/水平间距,检测是否统一 |
61
+ | 样式提取 | `style-extraction.js` | 渐变、阴影、圆角等完整参数 |
62
+
63
+ ### 使用示例
64
+
65
+ ```javascript
66
+ // 1. 先用模板获取完整信息
67
+ // (在 Sketch 中选中元素,运行 component-measurement.js)
68
+
69
+ // 2. 模板输出示例:
70
+ // === 相对边距(可直接使用)===
71
+ // 距父容器左边: 16
72
+ // 距父容器顶部: 8
73
+ // 距父容器右边: 16
74
+ // 距父容器底部: 8
75
+ // 父容器: Input (200x36)
76
+
77
+ // 3. 分析:上下边距相等 → 垂直居中设计
78
+ // 4. 转换为 Flutter:Container(alignment: Alignment.center, ...)
79
+ ```
80
+
81
+ ---
82
+
11
83
  ## ⚠️ 已知问题与解决方案
12
84
 
13
85
  ### 问题 1:渐变色被读取为单色
@@ -481,13 +553,15 @@ function convertGradient(gradient, framework) {
481
553
 
482
554
  - [Sketch JavaScript API 文档](https://developer.sketch.com/reference/api/)
483
555
  - [设计稿还原规范](../workflows/design-restoration.md)
484
- - [颜色系统规范](../color-system.md)
556
+ - [设计稿还原指南](../workflows/design-restoration-guide.md)
557
+ - [测量模板](../../templates/design-measurement/README.md)
558
+ - [TextField 居中案例](../troubleshooting-cases/flutter/textfield-vertical-centering.md)
485
559
 
486
560
  ---
487
561
 
488
562
  **维护者**: MTA工作室
489
563
  **创建日期**: 2026-01-20
490
- **最后更新**: 2026-01-21
564
+ **最后更新**: 2026-01-23
491
565
 
492
566
  ### 更新日志
493
567
 
@@ -495,3 +569,4 @@ function convertGradient(gradient, framework) {
495
569
  |------|------|---------|
496
570
  | v1.0 | 2026-01-20 | 初始版本 |
497
571
  | v1.1 | 2026-01-21 | 新增:fontWeight不可靠问题及fontName获取方案、图标导出规范、列表间距测量脚本 |
572
+ | v1.2 | 2026-01-23 | 新增:核心原则章节(测量+计算),强调配合测量模板使用,增加计算公式参考 |
@@ -1,96 +0,0 @@
1
- /**
2
- * Filesystem Skill - 高级文件操作
3
- * 提供批量处理和模式匹配能力
4
- */
5
- /**
6
- * 使用 glob 模式查找文件
7
- */
8
- declare function globFiles(pattern: string, options?: {
9
- cwd?: string;
10
- ignore?: string[];
11
- }): Promise<string[]>;
12
- /**
13
- * 批量重命名文件
14
- */
15
- declare function batchRename(files: string[], pattern: string, replacement: string, options?: {
16
- cwd?: string;
17
- dryRun?: boolean;
18
- }): Promise<{
19
- success: number;
20
- failed: number;
21
- changes: Array<{
22
- from: string;
23
- to: string;
24
- }>;
25
- }>;
26
- /**
27
- * 处理 glob_files 工具调用
28
- */
29
- declare function handleGlobFiles(args: any): Promise<any>;
30
- /**
31
- * 处理 batch_rename 工具调用
32
- */
33
- declare function handleBatchRename(args: any): Promise<any>;
34
- declare const FILESYSTEM_TOOLS: ({
35
- name: string;
36
- description: string;
37
- inputSchema: {
38
- type: string;
39
- properties: {
40
- pattern: {
41
- type: string;
42
- description: string;
43
- };
44
- cwd: {
45
- type: string;
46
- description: string;
47
- };
48
- ignore: {
49
- type: string;
50
- items: {
51
- type: string;
52
- };
53
- description: string;
54
- };
55
- files?: undefined;
56
- replacement?: undefined;
57
- dryRun?: undefined;
58
- };
59
- required: string[];
60
- };
61
- } | {
62
- name: string;
63
- description: string;
64
- inputSchema: {
65
- type: string;
66
- properties: {
67
- files: {
68
- type: string;
69
- items: {
70
- type: string;
71
- };
72
- description: string;
73
- };
74
- pattern: {
75
- type: string;
76
- description: string;
77
- };
78
- replacement: {
79
- type: string;
80
- description: string;
81
- };
82
- cwd: {
83
- type: string;
84
- description: string;
85
- };
86
- dryRun: {
87
- type: string;
88
- description: string;
89
- };
90
- ignore?: undefined;
91
- };
92
- required: string[];
93
- };
94
- })[];
95
-
96
- export { FILESYSTEM_TOOLS, batchRename, globFiles, handleBatchRename, handleGlobFiles };
@@ -1,269 +0,0 @@
1
- // src/skills/filesystem.ts
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- import { glob } from "fast-glob";
5
-
6
- // src/core/logger.ts
7
- var LOG_LEVEL_NAMES = {
8
- [0 /* DEBUG */]: "DEBUG",
9
- [1 /* INFO */]: "INFO",
10
- [2 /* WARN */]: "WARN",
11
- [3 /* ERROR */]: "ERROR",
12
- [4 /* SILENT */]: "SILENT"
13
- };
14
- var globalConfig = {
15
- level: process.env.DEBUG ? 0 /* DEBUG */ : 1 /* INFO */,
16
- timestamp: false,
17
- prefix: "[MCP]"
18
- };
19
- var Logger = class _Logger {
20
- constructor(name, config) {
21
- this.name = name || "";
22
- this.config = { ...globalConfig, ...config };
23
- }
24
- /**
25
- * 格式化日志消息
26
- */
27
- format(level, message, ...args) {
28
- const parts = [];
29
- if (this.config.timestamp) {
30
- parts.push((/* @__PURE__ */ new Date()).toISOString());
31
- }
32
- parts.push(this.config.prefix);
33
- if (this.name) {
34
- parts.push(`[${this.name}]`);
35
- }
36
- parts.push(`[${LOG_LEVEL_NAMES[level]}]`);
37
- parts.push(message);
38
- if (args.length > 0) {
39
- const formatted = args.map((arg) => {
40
- if (typeof arg === "object") {
41
- try {
42
- return JSON.stringify(arg, null, 2);
43
- } catch {
44
- return String(arg);
45
- }
46
- }
47
- return String(arg);
48
- });
49
- parts.push(...formatted);
50
- }
51
- return parts.join(" ");
52
- }
53
- /**
54
- * 检查日志级别是否应该输出
55
- */
56
- shouldLog(level) {
57
- return level >= this.config.level;
58
- }
59
- /**
60
- * 调试日志
61
- */
62
- debug(message, ...args) {
63
- if (this.shouldLog(0 /* DEBUG */)) {
64
- console.error(this.format(0 /* DEBUG */, message, ...args));
65
- }
66
- }
67
- /**
68
- * 信息日志
69
- */
70
- info(message, ...args) {
71
- if (this.shouldLog(1 /* INFO */)) {
72
- console.error(this.format(1 /* INFO */, message, ...args));
73
- }
74
- }
75
- /**
76
- * 简化的 log 方法(等同于 info)
77
- */
78
- log(message, ...args) {
79
- this.info(message, ...args);
80
- }
81
- /**
82
- * 警告日志
83
- */
84
- warn(message, ...args) {
85
- if (this.shouldLog(2 /* WARN */)) {
86
- console.error(this.format(2 /* WARN */, message, ...args));
87
- }
88
- }
89
- /**
90
- * 错误日志
91
- */
92
- error(message, ...args) {
93
- if (this.shouldLog(3 /* ERROR */)) {
94
- console.error(this.format(3 /* ERROR */, message, ...args));
95
- }
96
- }
97
- /**
98
- * 创建子 Logger
99
- */
100
- child(name) {
101
- const childName = this.name ? `${this.name}:${name}` : name;
102
- return new _Logger(childName, this.config);
103
- }
104
- };
105
- var logger = new Logger();
106
- function createLogger(name) {
107
- return new Logger(name);
108
- }
109
-
110
- // src/core/autoConfig.ts
111
- var CACHE_DURATION = 5 * 60 * 1e3;
112
-
113
- // src/skills/filesystem.ts
114
- var logger2 = createLogger("Skills:Filesystem");
115
- async function globFiles(pattern, options) {
116
- try {
117
- const files = await glob(pattern, {
118
- cwd: (options == null ? void 0 : options.cwd) || process.cwd(),
119
- ignore: (options == null ? void 0 : options.ignore) || ["**/node_modules/**", "**/.git/**"],
120
- absolute: false
121
- });
122
- logger2.info(`glob \u67E5\u627E: ${pattern}, \u627E\u5230 ${files.length} \u4E2A\u6587\u4EF6`);
123
- return files;
124
- } catch (error) {
125
- logger2.error(`glob \u67E5\u627E\u5931\u8D25: ${error}`);
126
- throw error;
127
- }
128
- }
129
- async function batchRename(files, pattern, replacement, options) {
130
- const cwd = (options == null ? void 0 : options.cwd) || process.cwd();
131
- const dryRun = (options == null ? void 0 : options.dryRun) || false;
132
- const changes = [];
133
- let success = 0;
134
- let failed = 0;
135
- const regex = new RegExp(pattern);
136
- for (const file of files) {
137
- const basename2 = path.basename(file);
138
- const dirname2 = path.dirname(file);
139
- if (!regex.test(basename2)) {
140
- continue;
141
- }
142
- const newBasename = basename2.replace(regex, replacement);
143
- if (newBasename === basename2) {
144
- continue;
145
- }
146
- const fromPath = path.join(cwd, file);
147
- const toPath = path.join(cwd, dirname2, newBasename);
148
- changes.push({
149
- from: file,
150
- to: path.join(dirname2, newBasename)
151
- });
152
- if (!dryRun) {
153
- try {
154
- fs.renameSync(fromPath, toPath);
155
- success++;
156
- logger2.info(`\u91CD\u547D\u540D: ${file} -> ${newBasename}`);
157
- } catch (error) {
158
- failed++;
159
- logger2.error(`\u91CD\u547D\u540D\u5931\u8D25: ${file} - ${error}`);
160
- }
161
- } else {
162
- success++;
163
- }
164
- }
165
- return { success, failed, changes };
166
- }
167
- async function handleGlobFiles(args) {
168
- const { pattern, cwd, ignore } = args;
169
- if (!pattern) {
170
- return {
171
- error: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570: pattern"
172
- };
173
- }
174
- try {
175
- const files = await globFiles(pattern, { cwd, ignore });
176
- return {
177
- count: files.length,
178
- files
179
- };
180
- } catch (error) {
181
- return {
182
- error: error.message
183
- };
184
- }
185
- }
186
- async function handleBatchRename(args) {
187
- const { files, pattern, replacement, cwd, dryRun } = args;
188
- if (!files || !pattern || !replacement) {
189
- return {
190
- error: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570: files, pattern, replacement"
191
- };
192
- }
193
- try {
194
- const result = await batchRename(files, pattern, replacement, { cwd, dryRun });
195
- return {
196
- ...result,
197
- dryRun: dryRun || false,
198
- message: dryRun ? "\u6A21\u62DF\u8FD0\u884C\uFF0C\u672A\u5B9E\u9645\u6267\u884C\u91CD\u547D\u540D" : `\u6210\u529F\u91CD\u547D\u540D ${result.success} \u4E2A\u6587\u4EF6`
199
- };
200
- } catch (error) {
201
- return {
202
- error: error.message
203
- };
204
- }
205
- }
206
- var FILESYSTEM_TOOLS = [
207
- {
208
- name: "glob_files",
209
- description: "\u4F7F\u7528 glob \u6A21\u5F0F\u67E5\u627E\u6587\u4EF6\uFF0C\u652F\u6301\u901A\u914D\u7B26\uFF08\u5982 **/*.ts\uFF09",
210
- inputSchema: {
211
- type: "object",
212
- properties: {
213
- pattern: {
214
- type: "string",
215
- description: "glob \u6A21\u5F0F\uFF08\u5982 src/**/*.ts\uFF09"
216
- },
217
- cwd: {
218
- type: "string",
219
- description: "\u5DE5\u4F5C\u76EE\u5F55\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55\uFF09"
220
- },
221
- ignore: {
222
- type: "array",
223
- items: { type: "string" },
224
- description: "\u5FFD\u7565\u7684\u6A21\u5F0F\u5217\u8868\uFF08\u53EF\u9009\uFF09"
225
- }
226
- },
227
- required: ["pattern"]
228
- }
229
- },
230
- {
231
- name: "batch_rename",
232
- description: "\u6279\u91CF\u91CD\u547D\u540D\u6587\u4EF6\uFF0C\u4F7F\u7528\u6B63\u5219\u8868\u8FBE\u5F0F\u66FF\u6362",
233
- inputSchema: {
234
- type: "object",
235
- properties: {
236
- files: {
237
- type: "array",
238
- items: { type: "string" },
239
- description: "\u8981\u91CD\u547D\u540D\u7684\u6587\u4EF6\u5217\u8868"
240
- },
241
- pattern: {
242
- type: "string",
243
- description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u6A21\u5F0F\uFF08\u7528\u4E8E\u5339\u914D\u6587\u4EF6\u540D\uFF09"
244
- },
245
- replacement: {
246
- type: "string",
247
- description: "\u66FF\u6362\u5B57\u7B26\u4E32\uFF08\u652F\u6301 $1, $2 \u7B49\u6355\u83B7\u7EC4\uFF09"
248
- },
249
- cwd: {
250
- type: "string",
251
- description: "\u5DE5\u4F5C\u76EE\u5F55\uFF08\u53EF\u9009\uFF09"
252
- },
253
- dryRun: {
254
- type: "boolean",
255
- description: "\u6A21\u62DF\u8FD0\u884C\uFF0C\u4E0D\u5B9E\u9645\u6267\u884C\uFF08\u53EF\u9009\uFF09"
256
- }
257
- },
258
- required: ["files", "pattern", "replacement"]
259
- }
260
- }
261
- ];
262
- export {
263
- FILESYSTEM_TOOLS,
264
- batchRename,
265
- globFiles,
266
- handleBatchRename,
267
- handleGlobFiles
268
- };
269
- //# sourceMappingURL=filesystem.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/skills/filesystem.ts","../../src/core/logger.ts","../../src/core/autoConfig.ts"],"sourcesContent":["/**\n * Filesystem Skill - 高级文件操作\n * 提供批量处理和模式匹配能力\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { glob } from 'fast-glob';\nimport { createLogger } from '../core/index.js';\n\nconst logger = createLogger('Skills:Filesystem');\n\n/**\n * 使用 glob 模式查找文件\n */\nexport async function globFiles(pattern: string, options?: { cwd?: string; ignore?: string[] }): Promise<string[]> {\n try {\n const files = await glob(pattern, {\n cwd: options?.cwd || process.cwd(),\n ignore: options?.ignore || ['**/node_modules/**', '**/.git/**'],\n absolute: false\n });\n \n logger.info(`glob 查找: ${pattern}, 找到 ${files.length} 个文件`);\n return files;\n } catch (error) {\n logger.error(`glob 查找失败: ${error}`);\n throw error;\n }\n}\n\n/**\n * 批量重命名文件\n */\nexport async function batchRename(\n files: string[],\n pattern: string,\n replacement: string,\n options?: { cwd?: string; dryRun?: boolean }\n): Promise<{ success: number; failed: number; changes: Array<{ from: string; to: string }> }> {\n const cwd = options?.cwd || process.cwd();\n const dryRun = options?.dryRun || false;\n const changes: Array<{ from: string; to: string }> = [];\n let success = 0;\n let failed = 0;\n \n const regex = new RegExp(pattern);\n \n for (const file of files) {\n const basename = path.basename(file);\n const dirname = path.dirname(file);\n \n if (!regex.test(basename)) {\n continue;\n }\n \n const newBasename = basename.replace(regex, replacement);\n if (newBasename === basename) {\n continue;\n }\n \n const fromPath = path.join(cwd, file);\n const toPath = path.join(cwd, dirname, newBasename);\n \n changes.push({\n from: file,\n to: path.join(dirname, newBasename)\n });\n \n if (!dryRun) {\n try {\n fs.renameSync(fromPath, toPath);\n success++;\n logger.info(`重命名: ${file} -> ${newBasename}`);\n } catch (error) {\n failed++;\n logger.error(`重命名失败: ${file} - ${error}`);\n }\n } else {\n success++;\n }\n }\n \n return { success, failed, changes };\n}\n\n/**\n * 处理 glob_files 工具调用\n */\nexport async function handleGlobFiles(args: any): Promise<any> {\n const { pattern, cwd, ignore } = args;\n \n if (!pattern) {\n return {\n error: '缺少必需参数: pattern'\n };\n }\n \n try {\n const files = await globFiles(pattern, { cwd, ignore });\n \n return {\n count: files.length,\n files\n };\n } catch (error: any) {\n return {\n error: error.message\n };\n }\n}\n\n/**\n * 处理 batch_rename 工具调用\n */\nexport async function handleBatchRename(args: any): Promise<any> {\n const { files, pattern, replacement, cwd, dryRun } = args;\n \n if (!files || !pattern || !replacement) {\n return {\n error: '缺少必需参数: files, pattern, replacement'\n };\n }\n \n try {\n const result = await batchRename(files, pattern, replacement, { cwd, dryRun });\n \n return {\n ...result,\n dryRun: dryRun || false,\n message: dryRun \n ? '模拟运行,未实际执行重命名' \n : `成功重命名 ${result.success} 个文件`\n };\n } catch (error: any) {\n return {\n error: error.message\n };\n }\n}\n\n// 导出工具定义\nexport const FILESYSTEM_TOOLS = [\n {\n name: 'glob_files',\n description: '使用 glob 模式查找文件,支持通配符(如 **/*.ts)',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'glob 模式(如 src/**/*.ts)'\n },\n cwd: {\n type: 'string',\n description: '工作目录(可选,默认为当前目录)'\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: '忽略的模式列表(可选)'\n }\n },\n required: ['pattern']\n }\n },\n {\n name: 'batch_rename',\n description: '批量重命名文件,使用正则表达式替换',\n inputSchema: {\n type: 'object',\n properties: {\n files: {\n type: 'array',\n items: { type: 'string' },\n description: '要重命名的文件列表'\n },\n pattern: {\n type: 'string',\n description: '正则表达式模式(用于匹配文件名)'\n },\n replacement: {\n type: 'string',\n description: '替换字符串(支持 $1, $2 等捕获组)'\n },\n cwd: {\n type: 'string',\n description: '工作目录(可选)'\n },\n dryRun: {\n type: 'boolean',\n description: '模拟运行,不实际执行(可选)'\n }\n },\n required: ['files', 'pattern', 'replacement']\n }\n }\n];\n","/**\n * MCP 日志模块\n * \n * 统一的日志接口,支持不同级别和格式化输出\n * MCP 服务器通过 stderr 输出日志,避免污染 stdout\n * \n * @module core/logger\n */\n\n/**\n * 日志级别\n */\nexport enum LogLevel {\n DEBUG = 0,\n INFO = 1,\n WARN = 2,\n ERROR = 3,\n SILENT = 4\n}\n\n/**\n * 日志级别名称\n */\nconst LOG_LEVEL_NAMES: Record<LogLevel, string> = {\n [LogLevel.DEBUG]: 'DEBUG',\n [LogLevel.INFO]: 'INFO',\n [LogLevel.WARN]: 'WARN',\n [LogLevel.ERROR]: 'ERROR',\n [LogLevel.SILENT]: 'SILENT'\n};\n\n/**\n * 日志配置\n */\ninterface LoggerConfig {\n /** 最小日志级别 */\n level: LogLevel;\n /** 是否显示时间戳 */\n timestamp: boolean;\n /** 前缀 */\n prefix: string;\n}\n\n/**\n * 全局日志配置\n */\nlet globalConfig: LoggerConfig = {\n level: process.env.DEBUG ? LogLevel.DEBUG : LogLevel.INFO,\n timestamp: false,\n prefix: '[MCP]'\n};\n\n/**\n * Logger 类\n */\nexport class Logger {\n private readonly name: string;\n private readonly config: LoggerConfig;\n \n constructor(name?: string, config?: Partial<LoggerConfig>) {\n this.name = name || '';\n this.config = { ...globalConfig, ...config };\n }\n \n /**\n * 格式化日志消息\n */\n private format(level: LogLevel, message: string, ...args: unknown[]): string {\n const parts: string[] = [];\n \n if (this.config.timestamp) {\n parts.push(new Date().toISOString());\n }\n \n parts.push(this.config.prefix);\n \n if (this.name) {\n parts.push(`[${this.name}]`);\n }\n \n parts.push(`[${LOG_LEVEL_NAMES[level]}]`);\n parts.push(message);\n \n // 处理额外参数\n if (args.length > 0) {\n const formatted = args.map(arg => {\n if (typeof arg === 'object') {\n try {\n return JSON.stringify(arg, null, 2);\n } catch {\n return String(arg);\n }\n }\n return String(arg);\n });\n parts.push(...formatted);\n }\n \n return parts.join(' ');\n }\n \n /**\n * 检查日志级别是否应该输出\n */\n private shouldLog(level: LogLevel): boolean {\n return level >= this.config.level;\n }\n \n /**\n * 调试日志\n */\n debug(message: string, ...args: unknown[]): void {\n if (this.shouldLog(LogLevel.DEBUG)) {\n console.error(this.format(LogLevel.DEBUG, message, ...args));\n }\n }\n \n /**\n * 信息日志\n */\n info(message: string, ...args: unknown[]): void {\n if (this.shouldLog(LogLevel.INFO)) {\n console.error(this.format(LogLevel.INFO, message, ...args));\n }\n }\n \n /**\n * 简化的 log 方法(等同于 info)\n */\n log(message: string, ...args: unknown[]): void {\n this.info(message, ...args);\n }\n \n /**\n * 警告日志\n */\n warn(message: string, ...args: unknown[]): void {\n if (this.shouldLog(LogLevel.WARN)) {\n console.error(this.format(LogLevel.WARN, message, ...args));\n }\n }\n \n /**\n * 错误日志\n */\n error(message: string, ...args: unknown[]): void {\n if (this.shouldLog(LogLevel.ERROR)) {\n console.error(this.format(LogLevel.ERROR, message, ...args));\n }\n }\n \n /**\n * 创建子 Logger\n */\n child(name: string): Logger {\n const childName = this.name ? `${this.name}:${name}` : name;\n return new Logger(childName, this.config);\n }\n}\n\n/**\n * 配置全局日志\n */\nexport function configureLogger(config: Partial<LoggerConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * 设置日志级别\n */\nexport function setLogLevel(level: LogLevel): void {\n globalConfig.level = level;\n}\n\n/**\n * 默认 Logger 实例\n */\nexport const logger = new Logger();\n\n/**\n * 创建带名称的 Logger\n */\nexport function createLogger(name: string): Logger {\n return new Logger(name);\n}\n\n/**\n * 工具函数:计时日志\n */\nexport function createTimer(logger: Logger, operation: string): () => void {\n const start = Date.now();\n logger.debug(`开始: ${operation}`);\n \n return () => {\n const duration = Date.now() - start;\n logger.debug(`完成: ${operation} (${duration}ms)`);\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\n\n/**\n * 自动配置检测与修复\n * 当 AI 调用任何工具时,自动检测并修复配置问题\n */\n\nexport interface ConfigCheckResult {\n needsSetup: boolean;\n wasFixed: boolean;\n workspacePath: string;\n message?: string;\n}\n\n// 已检测过的工作区缓存(避免重复检测)\nconst checkedWorkspaces = new Map<string, { configured: boolean; timestamp: number }>();\nconst CACHE_DURATION = 5 * 60 * 1000; // 5 分钟缓存\n\n/**\n * 检测并自动修复工作区配置\n * 使用缓存避免重复检测,只在首次或缓存过期时执行\n * @param workspacePath 工作区路径\n * @returns 配置检测结果\n */\nexport function ensureWorkspaceConfig(workspacePath: string): ConfigCheckResult {\n const result: ConfigCheckResult = {\n needsSetup: false,\n wasFixed: false,\n workspacePath\n };\n \n if (!workspacePath || !fs.existsSync(workspacePath)) {\n return result;\n }\n \n // 检查缓存\n const cached = checkedWorkspaces.get(workspacePath);\n const now = Date.now();\n \n if (cached && cached.configured && (now - cached.timestamp) < CACHE_DURATION) {\n // 缓存有效且已配置,直接返回\n return result;\n }\n \n const vscodeDir = path.join(workspacePath, '.vscode');\n const mcpJsonPath = path.join(vscodeDir, 'mcp.json');\n const settingsPath = path.join(vscodeDir, 'settings.json');\n \n // 快速检查是否已配置(只读取文件,不修改)\n let hasMtaConfig = false;\n if (fs.existsSync(mcpJsonPath)) {\n try {\n const config = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8'));\n hasMtaConfig = !!(config.servers?.mta || config.mcpServers?.mta);\n } catch {\n // 配置文件损坏\n }\n }\n \n if (hasMtaConfig) {\n // 已配置,更新缓存并返回\n checkedWorkspaces.set(workspacePath, { configured: true, timestamp: now });\n return result;\n }\n \n // 需要配置,自动修复\n result.needsSetup = true;\n \n try {\n // 创建 .vscode 目录\n if (!fs.existsSync(vscodeDir)) {\n fs.mkdirSync(vscodeDir, { recursive: true });\n }\n \n // 创建或更新 mcp.json\n let mcpConfig: any = { servers: {} };\n if (fs.existsSync(mcpJsonPath)) {\n try {\n mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8'));\n if (!mcpConfig.servers) {\n mcpConfig.servers = {};\n }\n } catch {\n mcpConfig = { servers: {} };\n }\n }\n \n mcpConfig.servers.mta = {\n command: 'npx',\n args: ['-y', 'mta-mcp'],\n env: {}\n };\n \n fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));\n \n // 更新 settings.json 启用 MCP\n let settings: any = {};\n if (fs.existsSync(settingsPath)) {\n try {\n settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));\n } catch {\n settings = {};\n }\n }\n \n if (!settings['github.copilot.chat.mcp.enabled']) {\n settings['github.copilot.chat.mcp.enabled'] = true;\n fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));\n }\n \n result.wasFixed = true;\n result.message = `✅ 已自动为 ${path.basename(workspacePath)} 配置 MTA MCP。请重新加载 VS Code 窗口使配置生效。`;\n \n // 更新缓存\n checkedWorkspaces.set(workspacePath, { configured: true, timestamp: now });\n \n } catch (error) {\n result.message = `⚠️ 自动配置失败: ${error instanceof Error ? error.message : String(error)}`;\n }\n \n return result;\n}\n\n/**\n * 包装工具响应,添加自动配置信息\n */\nexport function wrapResponseWithConfigInfo(\n response: any,\n configResult: ConfigCheckResult\n): any {\n if (!configResult.wasFixed) {\n return response;\n }\n \n // 在响应中添加配置修复信息\n if (typeof response === 'object' && response !== null) {\n return {\n ...response,\n _autoConfig: {\n wasFixed: true,\n message: configResult.message,\n action: '请运行命令: Cmd+Shift+P → \"重新加载窗口\" 使配置生效'\n }\n };\n }\n \n return response;\n}\n"],"mappings":"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","names":["logger","basename","dirname"]}
@@ -1,73 +0,0 @@
1
- /**
2
- * HTTP 请求技能
3
- *
4
- * 提供 HTTP 请求能力,可以发送 GET/POST 等请求
5
- * 使用 axios 实现,不依赖外部 MCP 服务器
6
- */
7
- interface HttpRequestArgs {
8
- url: string;
9
- method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
10
- headers?: Record<string, string>;
11
- body?: any;
12
- timeout?: number;
13
- }
14
- interface HttpResponse {
15
- status: number;
16
- statusText: string;
17
- headers: Record<string, string>;
18
- data: any;
19
- timing: number;
20
- }
21
- /**
22
- * 发送 HTTP 请求
23
- */
24
- declare function httpRequest(args: HttpRequestArgs): Promise<HttpResponse>;
25
- /**
26
- * 工具定义(供 MCP 注册)
27
- */
28
- declare const httpRequestToolDefinition: {
29
- name: string;
30
- description: string;
31
- inputSchema: {
32
- type: "object";
33
- properties: {
34
- url: {
35
- type: string;
36
- description: string;
37
- };
38
- method: {
39
- type: string;
40
- enum: string[];
41
- default: string;
42
- description: string;
43
- };
44
- headers: {
45
- type: string;
46
- additionalProperties: {
47
- type: string;
48
- };
49
- description: string;
50
- };
51
- body: {
52
- description: string;
53
- };
54
- timeout: {
55
- type: string;
56
- default: number;
57
- description: string;
58
- };
59
- };
60
- required: string[];
61
- };
62
- };
63
- /**
64
- * 处理 http_request 工具调用
65
- */
66
- declare function handleHttpRequest(args: any): Promise<{
67
- content: Array<{
68
- type: string;
69
- text: string;
70
- }>;
71
- }>;
72
-
73
- export { type HttpRequestArgs, type HttpResponse, handleHttpRequest, httpRequest, httpRequestToolDefinition };