mta-mcp 3.4.0 → 3.5.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.
@@ -1,7 +1,7 @@
1
1
  # Flutter 开发代理
2
2
 
3
3
  > 此 Agent 引导 AI 通过 MCP 工具获取 npm 包中的详细规范
4
- > 版本: v3.4.0 | 最后更新: 2026-01-23
4
+ > 版本: v3.5.0 | 最后更新: 2026-01-23
5
5
 
6
6
  ---
7
7
 
@@ -133,6 +133,33 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
133
133
  | `COLUMN + gap:16` | `Column(children: [..., Gap(16), ...])` |
134
134
  | `ROW + gap:12` | `Row(children: [..., Gap.h(12), ...])` |
135
135
 
136
+ #### Icon 使用规范(重要)
137
+
138
+ **检测到 icon 时的处理流程**:
139
+
140
+ ```
141
+ 1. 深度测量脚本会标记 `isIcon: true` 并提示导出为 SVG 200h
142
+ 2. 将 SVG 文件放入 assets/icons/ 目录
143
+ 3. 在 pubspec.yaml 中声明 assets
144
+ 4. 使用 flutter_svg 包加载
145
+ ```
146
+
147
+ **Flutter Icon 使用方式**:
148
+
149
+ | 场景 | 代码示例 | 说明 |
150
+ |------|---------|------|
151
+ | **SVG Icon** | `SvgPicture.asset('assets/icons/menu.svg', width: 24, height: 24, colorFilter: ColorFilter.mode($c.iconPrimary, BlendMode.srcIn))` | 推荐,支持颜色替换 |
152
+ | **系统 Icon** | `Icon(Icons.menu, size: 24, color: $c.iconPrimary)` | 优先使用 Material Icons |
153
+ | **固定尺寸** | `SizedBox(width: 24, height: 24, child: icon)` | 确保 icon 不被拉伸 |
154
+
155
+ **⚠️ Icon 禁止规则**:
156
+
157
+ | ❌ 禁止 | ✅ 正确 |
158
+ |--------|--------|
159
+ | `Image.asset('icon.png')` | `SvgPicture.asset('icon.svg')` |
160
+ | `width: 32, height: 28` | 保持 1:1 宽高比或使用原始比例 |
161
+ | 硬编码颜色 | `colorFilter: ColorFilter.mode($c.iconPrimary, ...)` |
162
+
136
163
  #### Flutter 禁止规则
137
164
 
138
165
  | ❌ 禁止 | ✅ 正确 |
@@ -111,7 +111,55 @@ MTA 不是传统的"编码规范管理器",而是一个**智能编码助手技
111
111
  | `sequentialthinking` | 分步推理 | 复杂问题分解、多步规划 |
112
112
 
113
113
  ---
114
+ ## 🎨 Sketch 设计稿还原规范
114
115
 
116
+ ### 强制流程
117
+
118
+ **在还原任何 Sketch 设计稿前,必须先调用 SketchMeasureHD 插件测量:**
119
+
120
+ ```
121
+ 1. 用户提供 Sketch 文件 → 先提醒:"需要先在 Sketch 中选中目标图层"
122
+ 2. 调用 @sketch mcp 工具
123
+ 3. 使用脚本:mcp-server/ui/sketch/sketch_measure_hd.js
124
+ 4. 获取完整测量数据(绝对坐标、内边距、布局意图)
125
+ 5. 基于测量数据精准还原 UI
126
+ ```
127
+
128
+ ### 测量数据必备字段
129
+
130
+ 调用 SketchMeasureHD 后,你会得到以下关键数据:
131
+
132
+ | 字段 | 用途 | 示例 |
133
+ |------|------|------|
134
+ | `absoluteRect` | 元素相对于画板的绝对位置 | `{ x: 16, y: 100, width: 361, height: 120 }` |
135
+ | `relativePosition` | 元素相对于父容器的内边距 | `{ paddingLeft: 16, paddingTop: 12 }` |
136
+ | `siblingGaps` | 兄弟元素间的间距 | `{ direction: "COLUMN", uniformVerticalGap: 12 }` |
137
+ | `layoutIntent` | 布局意图(居中、填充等) | `{ alignment: ["HORIZONTAL_CENTER"], sizing: { width: "FILL" } }` |
138
+ | `flutterHints` | 直接可用的 Flutter 代码 | `{ suggestedWidget: "Column", padding: "EdgeInsets.all(16)" }` |
139
+
140
+ ### 还原检查清单
141
+
142
+ - [ ] 使用 `absoluteRect` 而非 `frame`(避免相对坐标错误)
143
+ - [ ] 使用 `relativePosition` 计算内边距(避免硬编码)
144
+ - [ ] 使用 `siblingGaps` 确定元素间距(而非猜测)
145
+ - [ ] 使用 `layoutIntent` 判断布局方式(Column/Row/Center)
146
+ - [ ] 参考 `flutterHints` 生成代码(提高准确度)
147
+
148
+ ### 禁止事项
149
+
150
+ ❌ **禁止**在未调用测量插件的情况下凭感觉还原设计稿
151
+ ❌ **禁止**使用简单的 `Positioned` 绝对定位所有元素
152
+ ❌ **禁止**硬编码内边距值(如 `padding: 16`)而不基于测量数据
153
+ ❌ **禁止**忽略 `layoutIntent` 字段,导致嵌套层级错误
154
+
155
+ ### 应用到其他 Agent
156
+
157
+ 此规范应同步到以下 Agent:
158
+ - `agents/flutter.agent.md` - Flutter 开发
159
+ - `agents/vue3.agent.md` - Vue3 开发(参考 Sketch 设计稿时)
160
+ - `agents/wechat-miniprogram.agent.md` - 小程序开发
161
+
162
+ ---
115
163
  ## 📁 知识库结构
116
164
 
117
165
  MTA 的知识分为两类,明确区分:
@@ -1,7 +1,7 @@
1
1
  # Vue 3 + TypeScript 开发代理
2
2
 
3
3
  > 此 Agent 引导 AI 通过 MCP 工具获取 npm 包中的详细规范
4
- > 版本: v3.4.0 | 最后更新: 2026-01-23
4
+ > 版本: v3.5.0 | 最后更新: 2026-01-23
5
5
 
6
6
  ---
7
7
 
@@ -165,6 +165,44 @@ get_standard_by_id({ ids: ['vue3-composition', 'element-plus', 'i18n'] })
165
165
  | `ROW + gap:12` | `display: flex; gap: 12px;` |
166
166
  | `GRID` | `display: grid; grid-template-columns: repeat(...); gap: 16px;` |
167
167
 
168
+ #### Icon 使用规范(重要)
169
+
170
+ **检测到 icon 时的处理流程**:
171
+
172
+ ```
173
+ 1. 深度测量脚本会标记 `isIcon: true` 并提示导出为 SVG 200h
174
+ 2. 将 SVG 文件放入 src/assets/icons/ 目录
175
+ 3. 在 Vue 组件中引入使用
176
+ ```
177
+
178
+ **Vue Icon 使用方式**:
179
+
180
+ | 场景 | 代码示例 | 说明 |
181
+ |------|---------|------|
182
+ | **直接引入 SVG** | `<img :src="menuIcon" class="icon" />` + `import menuIcon from '@/assets/icons/menu.svg'` | 推荐,便于维护 |
183
+ | **内联 SVG** | `<svg>...</svg>` 直接复制 SVG 代码 | 支持 CSS 样式控制 |
184
+ | **Icon 组件库** | `<el-icon><Menu /></el-icon>` | Element Plus 项目优先使用 |
185
+ | **SVG Sprite** | `<svg><use xlink:href="#icon-menu"></use></svg>` | 多个 icon 复用时使用 |
186
+
187
+ **⚠️ Icon 禁止规则**:
188
+
189
+ | ❌ 禁止 | ✅ 正确 |
190
+ |--------|--------|
191
+ | `<img src="icon.png">` | `<img src="icon.svg">` 或 SVG sprite |
192
+ | `width: 32px; height: 28px` | 保持 1:1 宽高比 `width: 24px; height: 24px;` |
193
+ | 硬编码颜色 | `fill: var(--color-icon-primary);` |
194
+
195
+ **CSS 样式控制**:
196
+
197
+ ```css
198
+ .icon {
199
+ width: 24px;
200
+ height: 24px;
201
+ fill: var(--color-icon-primary); /* SVG 内联时生效 */
202
+ color: var(--color-icon-primary); /* 部分 icon 组件库使用 */
203
+ }
204
+ ```
205
+
168
206
  #### Vue/CSS 禁止规则
169
207
 
170
208
  | ❌ 禁止 | ✅ 正确 |
@@ -1,7 +1,7 @@
1
1
  # 微信小程序开发代理
2
2
 
3
3
  > 此 Agent 引导 AI 通过 MCP 工具获取 npm 包中的详细规范
4
- > 版本: v3.4.0 | 最后更新: 2026-01-23
4
+ > 版本: v3.5.0 | 最后更新: 2026-01-23
5
5
 
6
6
  ---
7
7
 
@@ -112,6 +112,56 @@ miniprogram/
112
112
  | `COLUMN + gap:16` | `display: flex; flex-direction: column;` + 子元素 `margin-bottom: 32rpx;` |
113
113
  | `ROW + gap:12` | `display: flex;` + 子元素 `margin-right: 24rpx;` |
114
114
 
115
+ #### Icon 使用规范(重要)
116
+
117
+ **检测到 icon 时的处理流程**:
118
+
119
+ ```
120
+ 1. 深度测量脚本会标记 `isIcon: true` 并提示导出为 SVG 200h
121
+ 2. 将 SVG 转换为 Base64 或使用图片格式
122
+ 3. 放入 /images/icons/ 目录
123
+ ```
124
+
125
+ **小程序 Icon 使用方式**:
126
+
127
+ | 场景 | 代码示例 | 说明 |
128
+ |------|---------|------|
129
+ | **Image 组件** | `<image src="/images/icons/menu.svg" class="icon" mode="aspectFit" />` | SVG 支持有限,优先 PNG |
130
+ | **字体图标** | `<text class="iconfont icon-menu"></text>` | 推荐,体积小,支持颜色 |
131
+ | **Base64** | `<image src="data:image/svg+xml;base64,..." />` | 小图标可内联 |
132
+
133
+ **⚠️ 小程序 Icon 限制**:
134
+
135
+ | ❌ 禁止 | ✅ 正确 |
136
+ |--------|--------|
137
+ | 直接使用外部 SVG | 转换为 PNG 或使用字体图标 |
138
+ | `width: 32rpx; height: 28rpx` | 保持 1:1 宽高比 `width: 48rpx; height: 48rpx;` |
139
+ | 硬编码颜色 | `color: var(--icon-color-primary);` |
140
+
141
+ **WXSS 样式控制**:
142
+
143
+ ```css
144
+ .icon {
145
+ width: 48rpx;
146
+ height: 48rpx;
147
+ }
148
+
149
+ .iconfont {
150
+ font-size: 48rpx;
151
+ color: var(--icon-color-primary);
152
+ }
153
+ ```
154
+
155
+ **字体图标配置**(推荐):
156
+
157
+ ```css
158
+ /* app.wxss */
159
+ @font-face {
160
+ font-family: 'iconfont';
161
+ src: url('data:font/woff2;base64,...');
162
+ }
163
+ ```
164
+
115
165
  #### 小程序特殊规则(重要)
116
166
 
117
167
  | 设计稿 (px) | 小程序 (rpx) | 说明 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mta-mcp",
3
- "version": "3.4.0",
3
+ "version": "3.5.1",
4
4
  "description": "MTA - 智能编码助手 MCP 服务器(规范 + 技能 + 诊断 + 模板 + 记忆 + 思考)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -147,9 +147,19 @@ function deepMeasureForRestoration() {
147
147
  relativePosition: null,
148
148
  // Layout Intent(标准化布局意图)
149
149
  layoutIntent: {},
150
+ // Icon 检测标记
151
+ isIcon: false,
152
+ iconExportPath: null,
150
153
  children: [],
151
154
  };
152
155
 
156
+ // ========== Icon 智能检测 ==========
157
+ element.isIcon = detectIfIcon(layer);
158
+ if (element.isIcon) {
159
+ element.iconExportPath = `icons/${sanitizeFileName(layer.name)}.svg`;
160
+ console.log(`🎨 检测到 Icon: ${layer.name} → 建议导出为 SVG 200h`);
161
+ }
162
+
153
163
  // 计算相对位置并生成 Layout Intent
154
164
  if (parentFrame) {
155
165
  const relLeft = layer.frame.x;
@@ -354,6 +364,104 @@ function deepMeasureForRestoration() {
354
364
  return 400;
355
365
  }
356
366
 
367
+ // ========== Icon 智能检测 ==========
368
+ // 根据元素特征判断是否为 icon
369
+ function detectIfIcon(layer) {
370
+ const name = layer.name.toLowerCase();
371
+ const size = Math.max(layer.frame.width, layer.frame.height);
372
+
373
+ // 规则 1: 名称特征
374
+ const iconKeywords = ['icon', 'ico', 'logo', 'symbol', 'arrow', 'close', 'menu', 'search', 'star', 'check'];
375
+ const hasIconKeyword = iconKeywords.some(keyword => name.includes(keyword));
376
+
377
+ // 规则 2: 尺寸特征(icon 通常在 12-64px 之间)
378
+ const isIconSize = size >= 12 && size <= 64;
379
+
380
+ // 规则 3: 形状特征(正方形或近似正方形)
381
+ const aspectRatio = layer.frame.width / layer.frame.height;
382
+ const isSquarish = aspectRatio >= 0.8 && aspectRatio <= 1.2;
383
+
384
+ // 规则 4: 类型特征(Shape Path / Symbol Instance / Group 且子元素少)
385
+ const isVectorType = layer.type === 'ShapePath' || layer.type === 'SymbolInstance' ||
386
+ (layer.type === 'Group' && (layer.layers?.length || 0) <= 5);
387
+
388
+ // 规则 5: 无文本内容
389
+ const hasNoText = layer.type !== 'Text';
390
+
391
+ // 综合判定(满足 3 个条件即认为是 icon)
392
+ const matchCount = [hasIconKeyword, isIconSize, isSquarish, isVectorType, hasNoText]
393
+ .filter(Boolean).length;
394
+
395
+ return matchCount >= 3;
396
+ }
397
+
398
+ // 文件名清理(用于 SVG 导出)
399
+ function sanitizeFileName(name) {
400
+ return name
401
+ .toLowerCase()
402
+ .replace(/\s+/g, '-')
403
+ .replace(/[^a-z0-9-_]/g, '')
404
+ .replace(/-+/g, '-')
405
+ .replace(/^-|-$/g, '');
406
+ }
407
+
408
+ // ========== 子元素对齐检测(优化布局分析)==========
409
+ function detectChildrenAlignment(children) {
410
+ if (children.length < 2) return null;
411
+
412
+ const tolerance = 2; // 允许 2px 误差
413
+ const leftEdges = children.map(c => c.frame.x);
414
+ const rightEdges = children.map(c => c.frame.x + c.frame.width);
415
+ const centerXs = children.map(c => c.frame.x + c.frame.width / 2);
416
+
417
+ // 检测左对齐
418
+ const leftAligned = leftEdges.every(x => Math.abs(x - leftEdges[0]) <= tolerance);
419
+ // 检测右对齐
420
+ const rightAligned = rightEdges.every(x => Math.abs(x - rightEdges[0]) <= tolerance);
421
+ // 检测水平居中对齐
422
+ const centerAligned = centerXs.every(x => Math.abs(x - centerXs[0]) <= tolerance);
423
+
424
+ if (leftAligned) return 'START';
425
+ if (rightAligned) return 'END';
426
+ if (centerAligned) return 'CENTER';
427
+ return 'NONE';
428
+ }
429
+
430
+ // ========== 响应式建议(增强交互准确性)==========
431
+ function generateResponsiveHint(children) {
432
+ if (children.length === 0) return null;
433
+
434
+ const hint = {
435
+ wrapNeeded: false,
436
+ scrollNeeded: false,
437
+ expandableChildren: [],
438
+ };
439
+
440
+ // 检测是否需要换行(子元素宽度总和超过容器)
441
+ const totalChildWidth = children.reduce((sum, c) => sum + c.frame.width, 0);
442
+ const parentWidth = children[0].frame.x; // 假设父容器信息存在
443
+ if (totalChildWidth > parentWidth * 0.9) {
444
+ hint.wrapNeeded = true;
445
+ }
446
+
447
+ // 检测是否需要滚动(子元素高度总和超过容器)
448
+ const totalChildHeight = children.reduce((sum, c) => sum + c.frame.height, 0);
449
+ const parentHeight = children[0].frame.y;
450
+ if (totalChildHeight > parentHeight * 0.9) {
451
+ hint.scrollNeeded = true;
452
+ }
453
+
454
+ // 检测哪些子元素应该可扩展(占据剩余空间)
455
+ children.forEach((child, index) => {
456
+ // 如果是容器且包含大量内容
457
+ if ((child.children?.length || 0) > 3) {
458
+ hint.expandableChildren.push(index);
459
+ }
460
+ });
461
+
462
+ return hint;
463
+ }
464
+
357
465
  // 分析子元素排列规律 → 生成容器级 Layout Intent
358
466
  function analyzeChildrenLayout(children) {
359
467
  // 按 Y 坐标排序检测垂直排列
@@ -385,6 +493,10 @@ function deepMeasureForRestoration() {
385
493
  gap: null,
386
494
  isGapUniform: true,
387
495
  gaps: [],
496
+ // 新增:对齐检测
497
+ alignment: detectChildrenAlignment(children),
498
+ // 新增:响应式建议
499
+ responsiveHint: generateResponsiveHint(children),
388
500
  };
389
501
 
390
502
  if (avgVGap > 0 && avgHGap <= 0) {
@@ -411,10 +523,42 @@ function deepMeasureForRestoration() {
411
523
  const rootElement = measureRecursively(artboard, 0, null);
412
524
  result.elements.push(rootElement);
413
525
 
526
+ // 收集所有 icon 元素
527
+ const icons = [];
528
+ function collectIcons(element) {
529
+ if (element.isIcon) {
530
+ icons.push({
531
+ name: element.name,
532
+ id: element.id,
533
+ exportPath: element.iconExportPath,
534
+ size: { width: element.frame.width, height: element.frame.height }
535
+ });
536
+ }
537
+ element.children.forEach(collectIcons);
538
+ }
539
+ collectIcons(rootElement);
540
+
414
541
  // 输出结构化结果
415
542
  console.log('\n📊 测量完成,Layout Intent 数据:');
416
543
  console.log(JSON.stringify(result, null, 2));
417
544
 
545
+ // 输出 icon 导出指引
546
+ if (icons.length > 0) {
547
+ console.log('\n🎨 检测到 Icon,建议导出步骤:');
548
+ console.log('1️⃣ 在 Sketch 中选中以下图层:');
549
+ icons.forEach(icon => {
550
+ console.log(` - ${icon.name} (建议尺寸: ${icon.size.width}x${icon.size.height})`);
551
+ });
552
+ console.log('\n2️⃣ 点击右下角"Make Exportable"');
553
+ console.log('3️⃣ 选择格式: SVG');
554
+ console.log('4️⃣ 设置高度: 200h(保持高宽比,高度200px)');
555
+ console.log('5️⃣ 导出位置建议: assets/icons/ 或 src/assets/icons/');
556
+ console.log('\n📝 导出后的使用方式:');
557
+ icons.forEach(icon => {
558
+ console.log(` ${icon.exportPath} → 在代码中引用`);
559
+ });
560
+ }
561
+
418
562
  return result;
419
563
  }
420
564