mta-mcp 3.10.1 → 3.12.0

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.8.0 | 最后更新: 2026-01-26
4
+ > 版本: v4.0.0 | 最后更新: 2026-02-11
5
5
 
6
6
  ---
7
7
 
@@ -24,16 +24,23 @@
24
24
 
25
25
  触发词:"设计稿"、"Sketch"、"还原"、"测量"、"间距"、"UI还原"
26
26
 
27
- ### 自动流程
27
+ ### 自动流程(v4.6.0 统一入口)
28
28
 
29
29
  ```
30
30
  1. 检测设计稿意图 → 提醒用户在 Sketch 选中图层
31
- 2. 调用 mcp_sketch_get_selection_as_image 获取预览
32
- 3. 调用 mcp_sketch_run_code 执行 SketchMeasureHD 测量
33
- 4. 基于测量数据生成 Flutter 代码
31
+ 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })
32
+ 获取已注入 _SKETCH_CMD 的完整脚本(sketch-tools.js v4.6.0)
33
+ 3. 将返回的 script 传入 mcp_sketch_run_code({ code: script })
34
+ → 执行测量,获取完整 Layout Intent JSON
35
+ 4. 基于测量数据中的 flutter* 字段精准生成代码
34
36
  ```
35
37
 
36
- ### 测量数据关键字段
38
+ **注意:**
39
+ - 不要手动读取 artboard-measure.js(已废弃,合并进 sketch-tools.js)
40
+ - 不要手动拼接 _SKETCH_CMD(由 sketch_measure skill 自动处理)
41
+ - 测量结果中所有颜色均包含 `flutterColor: "Color(0xAARRGGBB)"` 格式,可直接使用
42
+
43
+ ### 测量数据关键字段(v4.6.0 新增带★标记)
37
44
 
38
45
  | 字段 | 用途 | Flutter 应用 |
39
46
  |------|------|-------------|
@@ -42,8 +49,133 @@
42
49
  | `siblingGaps` | 元素间距 | `SizedBox(height:)` |
43
50
  | `layoutIntent` | 布局方式 | `Column`/`Row`/`Center` |
44
51
  | `flutterHints` | 建议代码 | 直接参考 |
52
+ | `iconContentBounds` | Icon 实际路径尺寸 | 渲染用 contentSize,占位用 containerSize |
53
+ | `tagStyle` | Tag/标签容器样式 | background, padding, cornerRadius |
54
+ | `siblingIconAlignment` | 同行 Icon 对齐 | 统一 SizedBox 插槽尺寸 |
55
+ | ★`flutterColor` | Flutter 颜色格式 | 直接粘贴 `Color(0xAARRGGBB)` |
56
+ | ★`flutterBoxShadow` | 完整阴影代码 | 直接粘贴 `BoxShadow(...)` |
57
+ | ★`flutterBorder` | 完整边框代码 | 直接粘贴 `Border.all(...)` |
58
+ | ★`flutterLinearGradient` | 完整渐变代码 | 直接粘贴 `LinearGradient(...)` |
59
+ | ★`flutterHint` | FILL→double.infinity | 禁止硬编码宽度 |
60
+ | ★`flutterSvgCode` | 完整 SVG 加载代码 | 直接粘贴 `SvgPicture.asset(...)` |
61
+ | ★`iconFillColor` | 图标填充色 | 已含 Flutter Color 格式 |
62
+
63
+ **禁止**:未测量就凭感觉还原、硬编码尺寸、忽略 layoutIntent、手动拼接颜色十六进制
64
+
65
+ ---
66
+
67
+ ## 🔴 设计稿还原五大陷阱(最高优先级)
68
+
69
+ > 以下陷阱基于真实项目多轮修复总结,每条都曾导致 2-5 轮无效对话
70
+
71
+ ### 陷阱 1:Icon Group 尺寸 ≠ 视觉尺寸
72
+
73
+ **问题**:Sketch Icon 的 Group 容器包含 padding,直接用 Group.frame 渲染会导致 Icon 偏大。
45
74
 
46
- **禁止**:未测量就凭感觉还原、硬编码尺寸、忽略 layoutIntent
75
+ ```
76
+ Sketch 结构:
77
+ ├─ Group "Fee Icon" (16×16) ← 外层容器,含 padding
78
+ │ └─ ShapePath "path" (12×12) ← 实际可见图形
79
+ ```
80
+
81
+ **规则**:
82
+ - 测量插件输出 `iconContentBounds.containerSize`(Group 尺寸)和 `iconContentBounds.contentSize`(路径尺寸)
83
+ - **渲染 SVG 用 `contentSize`**(SvgPicture 的 width/height)
84
+ - **占位槽用 `containerSize`**(外层 SizedBox 的 width/height)
85
+
86
+ ```dart
87
+ // 正确:分离占位与渲染
88
+ SizedBox(
89
+ width: 16, height: 16, // containerSize - 占位
90
+ child: Center(
91
+ child: SvgPicture.asset('icon.svg',
92
+ width: 12, height: 12, // contentSize - 渲染
93
+ ),
94
+ ),
95
+ )
96
+
97
+ // 错误:直接用 Group 尺寸渲染
98
+ SvgPicture.asset('icon.svg', width: 16, height: 16) // 太大!
99
+ ```
100
+
101
+ ### 陷阱 2:同行 Icon 不同尺寸导致文字错位
102
+
103
+ **问题**:同一行的多个 Icon(如手续费 14px、优惠券 12px)如果直接用各自尺寸,后面的文字起始位置不一致。
104
+
105
+ **规则**:
106
+ - 测量插件输出 `siblingIconAlignment.maxSlotSize`
107
+ - 所有同行 Icon 用**相同的 SizedBox 占位**,内部 Center 包裹实际 Icon
108
+
109
+ ```dart
110
+ // 正确:统一占位 16px,文字从 20px 位置开始(16 + 4gap)
111
+ Row(children: [
112
+ SizedBox(width: 16, height: 16, child: Center(
113
+ child: SvgPicture.asset('fee.svg', width: 14, height: 14),
114
+ )),
115
+ Gap(4),
116
+ Text('手续费'),
117
+ ])
118
+ Row(children: [
119
+ SizedBox(width: 16, height: 16, child: Center(
120
+ child: SvgPicture.asset('coupon.svg', width: 12, height: 12),
121
+ )),
122
+ Gap(4),
123
+ Text('优惠券'),
124
+ ])
125
+ ```
126
+
127
+ ### 陷阱 3:Tag/标签容器样式丢失
128
+
129
+ **问题**:小型 Tag(如"支付宝"标签)的 background、padding、cornerRadius 未从 Sketch 提取,凭感觉写出的样式与设计稿不符。
130
+
131
+ **规则**:
132
+ - 测量插件输出 `tagStyle`,包含 `background`、`padding`(horizontal/vertical)、`cornerRadius`
133
+ - **直接使用测量值**,不要猜测 padding
134
+
135
+ ```dart
136
+ // 正确:使用测量数据
137
+ Container(
138
+ padding: EdgeInsets.symmetric(horizontal: 3, vertical: 1), // 测量值
139
+ decoration: BoxDecoration(
140
+ color: Color(0x991676FE), // 测量的 bg + 透明度
141
+ borderRadius: BorderRadius.circular(3), // 测量的圆角
142
+ ),
143
+ child: Text('支付宝', style: TextStyle(fontSize: 8)),
144
+ )
145
+
146
+ // 错误:凭感觉
147
+ Container(
148
+ padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2), // 猜的
149
+ decoration: BoxDecoration(
150
+ color: Color(0xFF1677FF), // 丢失透明度
151
+ borderRadius: BorderRadius.circular(4), // 猜的
152
+ ),
153
+ )
154
+ ```
155
+
156
+ ### 陷阱 4:字体权重的平台可用性
157
+
158
+ **问题**:Sketch fontWeight=8(Heavy/w800)在 PingFang SC 字体中不存在真实字重文件,Flutter 会用合成加粗(synthetic bold),视觉效果过粗。
159
+
160
+ **规则**:
161
+ - 使用 PostScript 字体名(如 `PingFangSC-Semibold`)映射权重,而非 Sketch 的 `fontWeight` 数值
162
+ - **PingFang SC 最大真实字重 = Semibold (w600)**,超过此值一律降为 w600
163
+ - **Helvetica 最大真实字重 = Bold (w700)**,超过此值一律降为 w700
164
+
165
+ | Sketch fontWeight | PostScript 名 | Flutter 正确映射 |
166
+ |-------------------|--------------|-----------------|
167
+ | 8 (Heavy) | PingFangSC-Semibold | `FontWeight.w600`(而非 w800) |
168
+ | 9 (Black) | 不存在 | `FontWeight.w600`(降级) |
169
+ | 7 (Bold) | HelveticaNeue-Bold | `FontWeight.w700` |
170
+
171
+ ### 陷阱 5:添加设计稿中不存在的元素
172
+
173
+ **问题**:AI 根据语义推测添加了设计稿中没有的 UI 元素(如在"汇率"标签前加了 swap_horiz 图标)。
174
+
175
+ **规则**:
176
+ - **只还原测量数据中存在的元素**,不自行添加
177
+ - 如果测量数据中某个标签没有关联 Icon,则不添加 Icon
178
+ - 如果不确定某元素是否存在,向用户确认
47
179
 
48
180
  ---
49
181
 
@@ -66,6 +198,10 @@ troubleshoot({ problem: "用户描述的问题" })
66
198
  | 输入框边框异常 | input, border, focus |
67
199
  | TextField 垂直居中 | textfield, placeholder, 居中, 光标, 输入框 |
68
200
  | **Tab 嵌套导航** | tabbar, navigator, 返回无效, tab切换卡顿, 嵌套 |
201
+ | **Icon 尺寸偏差** | icon, 图标大小, Group, contentSize |
202
+ | **文字过粗/合成加粗** | fontWeight, 字体粗, 加粗, synthetic bold |
203
+ | **同行元素错位** | 对齐, 错位, 文字不齐, slot |
204
+ | **Tag/标签样式错误** | tag, 标签, padding, 背景色 |
69
205
 
70
206
  > 💡 详细诊断方案由 MCP 工具从 npm 包动态加载
71
207
 
@@ -145,20 +281,25 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
145
281
  - `api-layer` - API 层封装模式
146
282
  - `component-design` - 组件设计模式
147
283
 
284
+ **设计稿还原**
285
+ - `sketch-pitfalls` - Sketch 测量五大陷阱(Icon尺寸/Tag样式/字重/对齐/幽灵元素)
286
+ - `design-restoration` - 设计稿还原通用流程
287
+ - `sketch-mcp` - Sketch MCP 深度测量规范
288
+
148
289
  ---
149
290
 
150
291
  ## 🎨 设计稿还原规范
151
292
 
152
293
  ### ⚠️ 强制流程(最高优先级)
153
294
 
154
- **在还原任何 Sketch 设计稿前,必须先调用 SketchMeasureHD 插件测量:**
295
+ **在还原任何 Sketch 设计稿前,必须先调用 MTA 测量技能获取数据:**
155
296
 
156
297
  ```
157
298
  1. 用户提供 Sketch 文件 → 先提醒:"需要先在 Sketch 中选中目标图层"
158
- 2. 调用 @sketch mcp 工具
159
- 3. 使用脚本:mcp-server/ui/sketch/sketch_measure_hd.js
160
- 4. 获取完整测量数据(绝对坐标、内边距、布局意图)
161
- 5. 基于测量数据精准还原 Flutter UI
299
+ 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })
300
+ 3. 将返回的 script 传入 mcp_sketch_run_code 执行
301
+ 4. 基于测量数据中的 flutter* 字段精准还原(flutterColor、flutterBoxShadow、flutterSvgCode 等)
302
+ 5. FILL 类型尺寸使用 flutterHint 的 double.infinity,禁止硬编码宽度
162
303
  ```
163
304
 
164
305
  ### 测量数据必备字段
@@ -172,6 +313,17 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
172
313
  | `siblingGaps` | 兄弟元素间的间距 | 转换为 `Gap()`、`SizedBox(height:)` |
173
314
  | `layoutIntent` | 布局意图(居中、填充等) | 选择 `Center`、`Column`、`Row` |
174
315
  | `flutterHints` | 直接可用的 Flutter 代码 | 参考建议代码快速实现 |
316
+ | `iconContentBounds` | Icon 容器 vs 路径尺寸 | containerSize→占位, contentSize→渲染 |
317
+ | `tagStyle` | Tag 容器完整样式 | bg/padding/cornerRadius 精确还原 |
318
+ | `siblingIconAlignment` | 同行 Icon 统一尺寸 | maxSlotSize→统一 SizedBox |
319
+ | `fontName` | PostScript 字体名 | 正确映射 FontWeight(防合成加粗) |
320
+ | `flutterColor` | Flutter 颜色格式 | 直接粘贴 Color(0xAARRGGBB) |
321
+ | `flutterBoxShadow` | 完整阴影代码 | 直接粘贴 BoxShadow(...) |
322
+ | `flutterBorder` | 完整边框代码 | 直接粘贴 Border.all(...) |
323
+ | `flutterLinearGradient` | 完整渐变代码 | 直接粘贴 LinearGradient(...) |
324
+ | `flutterHint` | 自适应宽度提示 | double.infinity + MediaQuery |
325
+ | `flutterSvgCode` | 完整 SVG 代码 | 直接粘贴 SvgPicture.asset(...) + ColorFilter |
326
+ | `iconFillColor` | 图标填充色 | 已含 flutterColor 格式 |
175
327
 
176
328
  ### 还原检查清单
177
329
 
@@ -183,6 +335,15 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
183
335
  - [ ] 使用 Token 系统($c, $t, $s, $r)替代硬编码
184
336
  - [ ] **计算内容总高度**,验证不超出容器(详见陷阱规范)
185
337
  - [ ] **避免 EdgeInsets.symmetric**,精确布局用 EdgeInsets.only
338
+ - [ ] **Icon 用 contentSize 渲染,containerSize 占位**(防 Icon 偏大)
339
+ - [ ] **同行 Icon 统一 SizedBox 占位**(防文字错位)
340
+ - [ ] **Tag 容器使用测量的 padding/bg/cornerRadius**(防样式猜测)
341
+ - [ ] **字体权重检查平台可用性**(PingFang≤w600, Helvetica≤w700)
342
+ - [ ] **只还原测量数据中存在的元素**(防添加幽灵元素)
343
+ - [ ] **优先使用 flutter* 字段**(flutterColor、flutterBoxShadow、flutterLinearGradient 等直接粘贴)
344
+ - [ ] **图标使用 flutterSvgCode**(含精确颜色和尺寸,禁止用 Icons.xxx 替代自定义 SVG)
345
+ - [ ] **FILL 类型尺寸使用 flutterHint**(double.infinity,禁止硬编码固定宽度)
346
+ - [ ] **边框使用 flutterBorder**(禁止忽略 borders 数据)
186
347
 
187
348
  ### ⚠️ 常见陷阱(必读)
188
349
 
@@ -197,6 +358,11 @@ get_standard_by_id({ id: 'sketch-pitfalls' })
197
358
  | 固定高度容器 | OVERFLOWED BY X PIXELS | 移除 height,用 MainAxisSize.min |
198
359
  | EdgeInsets.symmetric | 溢出 1-5px | 用 EdgeInsets.only 精确控制 |
199
360
  | 文本行高 | 容器高度不足 | 计算 fontSize × height 的实际占用 |
361
+ | Icon 用 Group 尺寸 | Icon 比设计稿大 2-4px | 用 contentSize 渲染,containerSize 占位 |
362
+ | 同行 Icon 不等大 | 文字起始位置不一致 | 统一 SizedBox 插槽 + Center |
363
+ | Tag 凭感觉写样式 | padding/bg/圆角全错 | 使用 tagStyle 测量数据 |
364
+ | 字重超出平台上限 | 文字过粗(合成加粗) | PingFang≤w600, Helvetica≤w700 |
365
+ | 添加不存在的元素 | UI 与设计稿不符 | 只还原测量数据中存在的元素 |
200
366
 
201
367
  > 📖 **详细案例**:`mcp-server/troubleshooting/flutter/sketch-overflow-container.md`
202
368
 
@@ -206,7 +372,11 @@ get_standard_by_id({ id: 'sketch-pitfalls' })
206
372
  ❌ **禁止**使用简单的 `Positioned` 绝对定位所有元素
207
373
  ❌ **禁止**硬编码内边距值(如 `EdgeInsets.all(16)`)而不基于测量数据
208
374
  ❌ **禁止**忽略 `layoutIntent` 字段,导致嵌套层级错误
209
- ❌ **禁止**硬编码颜色/尺寸(必须使用 Token 系统)
375
+ ❌ **禁止**硬编码颜色/尺寸(必须使用 Token 系统)
376
+ ❌ **禁止**用 Icon Group 的 frame 尺寸直接渲染 SVG(必须用 contentSize)
377
+ ❌ **禁止**凭推测添加设计稿中不存在的 UI 元素(如猜测性添加图标)
378
+ ❌ **禁止**使用超出字体平台可用范围的 FontWeight(合成加粗视觉差异大)
379
+ ❌ **禁止**同行不同尺寸 Icon 各用各的宽度(必须统一占位槽)
210
380
 
211
381
  ### 🎯 深度还原模式(像素级)
212
382
 
@@ -237,27 +407,41 @@ get_standard_by_id({ id: 'sketch-pitfalls' })
237
407
  **检测到 icon 时的处理流程**:
238
408
 
239
409
  ```
240
- 1. 深度测量脚本会标记 `isIcon: true` 并提示导出为 SVG 200h
241
- 2. SVG 文件放入 assets/icons/ 目录
242
- 3. pubspec.yaml 中声明 assets
243
- 4. 使用 flutter_svg 包加载
410
+ 1. 测量插件标记 `isIcon: true` 并输出 iconContentBounds
411
+ 2. 读取 containerSize(Group 尺寸)和 contentSize(实际路径尺寸)
412
+ 3. SVG 文件放入 assets/icons/ 目录
413
+ 4. pubspec.yaml 中声明 assets
414
+ 5. 使用 flutter_svg 包加载,宽高用 contentSize
415
+ 6. 外层用 SizedBox(containerSize) + Center 包裹
244
416
  ```
245
417
 
246
418
  **Flutter Icon 使用方式**:
247
419
 
248
420
  | 场景 | 代码示例 | 说明 |
249
421
  |------|---------|------|
250
- | **SVG Icon** | `SvgPicture.asset('assets/icons/menu.svg', width: 24, height: 24, colorFilter: ColorFilter.mode($c.iconPrimary, BlendMode.srcIn))` | 推荐,支持颜色替换 |
422
+ | **SVG Icon(标准)** | `SizedBox(width: 16, height: 16, child: Center(child: SvgPicture.asset('icon.svg', width: 12, height: 12, colorFilter: ColorFilter.mode($c.iconPrimary, BlendMode.srcIn))))` | containerSize 占位 + contentSize 渲染 |
251
423
  | **系统 Icon** | `Icon(Icons.menu, size: 24, color: $c.iconPrimary)` | 优先使用 Material Icons |
252
- | **固定尺寸** | `SizedBox(width: 24, height: 24, child: icon)` | 确保 icon 不被拉伸 |
424
+ | **同行对齐** | 所有 Icon 用 `SizedBox(width: maxSlotSize)` + `Center` | 确保后续文字对齐 |
425
+
426
+ **Icon 尺寸决策流程:**
427
+
428
+ ```
429
+ 测量数据 → iconContentBounds
430
+ ├─ containerSize (Group frame) → 外层 SizedBox 占位
431
+ ├─ contentSize (路径 union) → SvgPicture width/height
432
+ └─ siblingIconAlignment.maxSlotSize → 同行统一占位
433
+ ```
253
434
 
254
- **⚠️ Icon 禁止规则**:
435
+ **Icon 禁止规则**:
255
436
 
256
437
  | ❌ 禁止 | ✅ 正确 |
257
438
  |--------|--------|
258
439
  | `Image.asset('icon.png')` | `SvgPicture.asset('icon.svg')` |
259
440
  | `width: 32, height: 28` | 保持 1:1 宽高比或使用原始比例 |
260
441
  | 硬编码颜色 | `colorFilter: ColorFilter.mode($c.iconPrimary, ...)` |
442
+ | 直接用 Group 尺寸渲染 SVG | 用 contentSize 渲染,containerSize 占位 |
443
+ | 同行 Icon 各用各的宽度 | 统一 maxSlotSize + Center |
444
+ | 凭语义推测添加 Icon | 只添加测量数据中存在的 Icon |
261
445
 
262
446
  #### Flutter 禁止规则
263
447
 
package/dist/index.js CHANGED
@@ -3332,7 +3332,8 @@ var STANDARD_DIRS = [
3332
3332
  "standards/frameworks",
3333
3333
  "standards/libraries",
3334
3334
  "standards/patterns",
3335
- "standards/workflows"
3335
+ "standards/workflows",
3336
+ "standards/mcp-tools"
3336
3337
  ];
3337
3338
  var standardsCache = null;
3338
3339
  async function getStandardById(args) {
@@ -6029,6 +6030,90 @@ function getSkillRegistry() {
6029
6030
  return globalRegistry;
6030
6031
  }
6031
6032
 
6033
+ // src/tools/sketchMeasure.ts
6034
+ import * as fs19 from "fs";
6035
+ import * as path19 from "path";
6036
+ import { fileURLToPath as fileURLToPath8 } from "url";
6037
+ var __filename8 = fileURLToPath8(import.meta.url);
6038
+ var __dirname8 = path19.dirname(__filename8);
6039
+ var SKETCH_TOOLS_PATHS = [
6040
+ path19.resolve(__dirname8, "../ui/sketch/sketch-tools.js"),
6041
+ path19.resolve(__dirname8, "../../ui/sketch/sketch-tools.js")
6042
+ ];
6043
+ var VALID_CMDS = ["measure", "layout", "style", "svg", "auto"];
6044
+ function findSketchTools() {
6045
+ for (const p of SKETCH_TOOLS_PATHS) {
6046
+ if (fs19.existsSync(p)) {
6047
+ return p;
6048
+ }
6049
+ }
6050
+ return null;
6051
+ }
6052
+ async function sketchMeasure(args) {
6053
+ const cmd = args.cmd || "measure";
6054
+ if (!VALID_CMDS.includes(cmd)) {
6055
+ return {
6056
+ content: [{
6057
+ type: "text",
6058
+ text: JSON.stringify({
6059
+ error: `\u65E0\u6548\u7684 cmd \u53C2\u6570: "${cmd}"`,
6060
+ validValues: VALID_CMDS,
6061
+ usage: 'mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })'
6062
+ }, null, 2)
6063
+ }]
6064
+ };
6065
+ }
6066
+ const toolPath = findSketchTools();
6067
+ if (!toolPath) {
6068
+ return {
6069
+ content: [{
6070
+ type: "text",
6071
+ text: JSON.stringify({
6072
+ error: "sketch-tools.js \u6587\u4EF6\u672A\u627E\u5230",
6073
+ searchedPaths: SKETCH_TOOLS_PATHS,
6074
+ solution: "\u8BF7\u786E\u8BA4 mcp-server/ui/sketch/sketch-tools.js \u6587\u4EF6\u5B58\u5728"
6075
+ }, null, 2)
6076
+ }]
6077
+ };
6078
+ }
6079
+ const scriptContent = fs19.readFileSync(toolPath, "utf-8");
6080
+ const versionMatch = scriptContent.match(/@version\s+([\d.]+)/);
6081
+ const version = versionMatch ? versionMatch[1] : "unknown";
6082
+ const cmdLine = `var _SKETCH_CMD = '${cmd}';`;
6083
+ const fullScript = cmdLine + "\n" + scriptContent;
6084
+ return {
6085
+ content: [{
6086
+ type: "text",
6087
+ text: JSON.stringify({
6088
+ status: "ready",
6089
+ version,
6090
+ cmd,
6091
+ scriptLength: fullScript.length,
6092
+ instruction: "\u5C06 script \u5B57\u6BB5\u7684\u5185\u5BB9\u4F20\u5165 mcp_sketch_run_code({ code: script }) \u6267\u884C\u3002\u6267\u884C\u524D\u8BF7\u786E\u8BA4\u7528\u6237\u5DF2\u5728 Sketch \u4E2D\u9009\u4E2D\u4E86\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
6093
+ cmdDescription: {
6094
+ measure: "\u5B8C\u6574\u753B\u677F\u6D4B\u91CF - \u83B7\u53D6\u6240\u6709\u56FE\u5C42\u6837\u5F0F\u3001\u5C3A\u5BF8\u3001\u95F4\u8DDD\u3001\u989C\u8272\uFF08\u9009\u4E2D\u753B\u677F/Frame\uFF09",
6095
+ layout: "\u5E03\u5C40\u5206\u6790 - \u5206\u6790\u5BB9\u5668\u5B50\u5143\u7D20\u6392\u5217\uFF0C\u6216\u4E24\u4E2A\u56FE\u5C42\u7684\u76F8\u5BF9\u4F4D\u7F6E",
6096
+ style: "\u6837\u5F0F\u5FEB\u68C0 - \u5FEB\u901F\u68C0\u67E5\u9009\u4E2D\u7EC4\u4EF6\u7684\u586B\u5145\u8272\u3001\u9634\u5F71\u3001\u6587\u5B57\u6837\u5F0F",
6097
+ svg: "\u56FE\u6807\u5BFC\u51FA - \u5BFC\u51FA\u9009\u4E2D\u7684\u77E2\u91CF\u56FE\u4E3A SVG",
6098
+ auto: "\u81EA\u52A8\u6A21\u5F0F - \u6839\u636E\u9009\u4E2D\u5185\u5BB9\u81EA\u52A8\u9009\u62E9\u6D4B\u91CF\u6216\u6837\u5F0F\u6A21\u5F0F"
6099
+ }[cmd],
6100
+ v460Features: [
6101
+ "flutterColor - \u6240\u6709\u989C\u8272\u8F93\u51FA Flutter Color(0xAARRGGBB) \u683C\u5F0F\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34",
6102
+ "flutterBoxShadow - \u9634\u5F71\u8F93\u51FA\u5B8C\u6574 BoxShadow(...) \u4EE3\u7801",
6103
+ "flutterBorder - \u8FB9\u6846\u8F93\u51FA\u5B8C\u6574 Border.all(...) \u4EE3\u7801",
6104
+ "flutterLinearGradient - \u6E10\u53D8\u8F93\u51FA\u5B8C\u6574 LinearGradient(...) \u4EE3\u7801",
6105
+ "flutterHint - FILL/MATCH_PARENT \u5C3A\u5BF8\u8F93\u51FA double.infinity \u63D0\u793A",
6106
+ "flutterSvgCode - \u56FE\u6807\u8F93\u51FA\u5B8C\u6574 SvgPicture.asset(...) \u4EE3\u7801\uFF0C\u542B\u7CBE\u786E\u7684\u989C\u8272\u548C\u5C3A\u5BF8",
6107
+ "\u5168\u8986\u76D6\u5F62\u72B6\u6392\u9664 - \u80CC\u666F\u5706\u89D2\u77E9\u5F62\u4E0D\u518D\u88AB\u8BEF\u5224\u4E3A\u56FE\u6807"
6108
+ ]
6109
+ }, null, 2)
6110
+ }, {
6111
+ type: "text",
6112
+ text: fullScript
6113
+ }]
6114
+ };
6115
+ }
6116
+
6032
6117
  // src/tools/skillDefinitions.ts
6033
6118
  function wrapAsContent(data) {
6034
6119
  return {
@@ -6359,6 +6444,22 @@ var skillDefinitions = [
6359
6444
  return wrapAsContent(await listTroubleshootingCases(params.framework));
6360
6445
  }
6361
6446
  }
6447
+ },
6448
+ // ==================== Sketch 设计稿工具类 ====================
6449
+ {
6450
+ name: "sketch_measure",
6451
+ category: "sketch",
6452
+ description: "\u83B7\u53D6 Sketch \u6D4B\u91CF\u811A\u672C\uFF08sketch-tools.js v4.6.0\uFF09\u3002\u8FD4\u56DE\u5DF2\u6CE8\u5165 _SKETCH_CMD \u7684\u5B8C\u6574\u811A\u672C\uFF0C\u53EF\u76F4\u63A5\u4F20\u5165 mcp_sketch_run_code \u6267\u884C\u3002\u652F\u6301 measure(\u5B8C\u6574\u753B\u677F\u6D4B\u91CF)\u3001layout(\u5E03\u5C40\u5206\u6790)\u3001style(\u6837\u5F0F\u5FEB\u68C0)\u3001svg(\u56FE\u6807\u5BFC\u51FA)\u3001auto(\u81EA\u52A8\u6A21\u5F0F)",
6453
+ paramHints: [
6454
+ { name: "cmd", type: "string", description: "\u6267\u884C\u6A21\u5F0F: measure(\u9ED8\u8BA4\uFF0C\u5B8C\u6574\u753B\u677F) / layout(\u5E03\u5C40\u5206\u6790) / style(\u6837\u5F0F\u68C0\u67E5) / svg(\u56FE\u6807\u5BFC\u51FA) / auto(\u81EA\u52A8\u5224\u65AD)" },
6455
+ { name: "outputPath", type: "string", description: "SVG \u8F93\u51FA\u8DEF\u5F84\uFF08\u4EC5 cmd=svg \u65F6\u4F7F\u7528\uFF09" }
6456
+ ],
6457
+ handler: async (params) => {
6458
+ return sketchMeasure({
6459
+ cmd: params.cmd,
6460
+ outputPath: params.outputPath
6461
+ });
6462
+ }
6362
6463
  }
6363
6464
  ];
6364
6465