mta-mcp 3.14.1 → 3.15.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
- > 版本: v4.0.0 | 最后更新: 2026-02-11
4
+ > 版本: v4.1.0 | 最后更新: 2026-03-11
5
5
 
6
6
  ---
7
7
 
@@ -28,28 +28,33 @@
28
28
 
29
29
  ```
30
30
  1. 检测设计稿意图 → 提醒用户在 Sketch 选中图层
31
- 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })
32
- → 获取已注入 _SKETCH_CMD 的完整脚本(sketch-tools.js v4.6.0
31
+ 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "compact" } })
32
+ → 获取已注入 _SKETCH_CMD 的完整脚本(首轮优先读取 restorationContract
33
33
  3. 将返回的 script 传入 mcp_sketch_run_code({ code: script })
34
- 执行测量,获取完整 Layout Intent JSON
35
- 4. 基于测量数据中的 flutter* 字段精准生成代码
34
+ 执行测量,获取紧凑 contract + tree JSON
35
+ 4. 先按 restorationContract 还原页面骨架和文案,再用 flutter* 字段填充样式
36
+ 5. 只有当 compact 无法解释局部布局/样式时,再补用 measure/style
36
37
  ```
37
38
 
38
39
  **注意:**
39
40
  - 不要手动读取 artboard-measure.js(已废弃,合并进 sketch-tools.js)
40
41
  - 不要手动拼接 _SKETCH_CMD(由 sketch_measure skill 自动处理)
41
42
  - 测量结果中所有颜色均包含 `flutterColor: "Color(0xAARRGGBB)"` 格式,可直接使用
43
+ - 设计稿还原时,restorationContract 优先于现有业务组件、路由标题、i18n 文案和常见 CTA 习惯
42
44
 
43
45
  ### 测量数据关键字段(v4.6.0 新增带★标记)
44
46
 
45
47
  | 字段 | 用途 | Flutter 应用 |
46
48
  |------|------|-------------|
49
+ | `restorationContract` | 页面级骨架合同 | 先读 `blockOrder/copyLedger/hardRules`,禁止结构漂移 |
47
50
  | `absoluteRect` | 绝对位置尺寸 | `width:`, `height:` |
48
51
  | `relativePosition` | 内边距 | `EdgeInsets` |
49
52
  | `siblingGaps` | 元素间距 | `SizedBox(height:)` |
50
53
  | `layoutIntent` | 布局方式 | `Column`/`Row`/`Center` |
51
54
  | `flutterHints` | 建议代码 | 直接参考 |
52
55
  | `iconContentBounds` | Icon 实际路径尺寸 | 渲染用 contentSize,占位用 containerSize |
56
+ | `iconSvgMarkup` | Sketch 真实导出的 SVG 字符串 | 优先于猜测文件名,必要时直接落盘 |
57
+ | `iconSvgMeta.colorStrategy` | SVG 颜色策略 | `preserve` 保原色,`tint` 仅单色图标可着色 |
53
58
  | `tagStyle` | Tag/标签容器样式 | background, padding, cornerRadius |
54
59
  | `siblingIconAlignment` | 同行 Icon 对齐 | 统一 SizedBox 插槽尺寸 |
55
60
  | ★`flutterColor` | Flutter 颜色格式 | 直接粘贴 `Color(0xAARRGGBB)` |
@@ -57,14 +62,24 @@
57
62
  | ★`flutterBorder` | 完整边框代码 | 直接粘贴 `Border.all(...)` |
58
63
  | ★`flutterLinearGradient` | 完整渐变代码 | 直接粘贴 `LinearGradient(...)` |
59
64
  | ★`flutterHint` | FILL→double.infinity | 禁止硬编码宽度 |
60
- | ★`flutterSvgCode` | 完整 SVG 加载代码 | 直接粘贴 `SvgPicture.asset(...)` |
65
+ | ★`flutterSvgCode` | 完整 SVG 加载代码 | 优先使用 `SvgPicture.string(actualSvg...)` |
61
66
  | ★`iconFillColor` | 图标填充色 | 已含 Flutter Color 格式 |
67
+ | ★`flutterTextStyle` | 完整文本样式提示 | 含 `fontFamily/height/letterSpacing/fontWeight/color` |
68
+ | ★`flutterStrutStyle` | 行盒校准提示 | 固定高度文本直接使用 `StrutStyle(...)` |
62
69
 
63
70
  **禁止**:未测量就凭感觉还原、硬编码尺寸、忽略 layoutIntent、手动拼接颜色十六进制
64
71
 
72
+ ### 页面级 Contract 规则(v4.1.0 新增)
73
+
74
+ - 先读 `restorationContract.blockOrder`:先还原顶层结构顺序,再处理局部样式
75
+ - `bodyCopyLedger` / `navCopyLedger` 是文案真值:默认禁止改成现有页面标题、业务分组名、路由文案
76
+ - `topPrimaryEntry` 存在时禁止下沉为底部 CTA
77
+ - `bottomNavigation.present=true` 且未测得额外 CTA 时,禁止再叠加一层固定底部按钮
78
+ - 若现有项目通用组件会引入多余 section/CTA/标题,优先新建贴合设计稿的局部实现,不强行复用
79
+
65
80
  ---
66
81
 
67
- ## 🔴 设计稿还原五大陷阱(最高优先级)
82
+ ## 🔴 设计稿还原六大陷阱(最高优先级)
68
83
 
69
84
  > 以下陷阱基于真实项目多轮修复总结,每条都曾导致 2-5 轮无效对话
70
85
 
@@ -159,16 +174,27 @@ Container(
159
174
 
160
175
  **规则**:
161
176
  - 使用 PostScript 字体名(如 `PingFangSC-Semibold`)映射权重,而非 Sketch 的 `fontWeight` 数值
162
- - **PingFang SC 最大真实字重 = Semibold (w600)**,超过此值一律降为 w600
177
+ - **PingFang SC 最大真实字重 = Semibold (w600)**,只有超过此值时才降为 w600,不再把真实的 w600 自动降成 w500
163
178
  - **Helvetica 最大真实字重 = Bold (w700)**,超过此值一律降为 w700
179
+ - 文本样式优先使用插件给出的 `flutterTextStyle`;如果文字处于固定高度/行内对齐场景,再配合 `flutterStrutStyle`
164
180
 
165
181
  | Sketch fontWeight | PostScript 名 | Flutter 正确映射 |
166
182
  |-------------------|--------------|-----------------|
167
- | 8 (Heavy) | PingFangSC-Semibold | `FontWeight.w600`(而非 w800) |
183
+ | 8 (Heavy) | PingFangSC-Semibold | `FontWeight.w600`(而非 w800,也不是错误降成 w500) |
168
184
  | 9 (Black) | 不存在 | `FontWeight.w600`(降级) |
169
185
  | 7 (Bold) | HelveticaNeue-Bold | `FontWeight.w700` |
170
186
 
171
- ### 陷阱 5:添加设计稿中不存在的元素
187
+ ### 陷阱 5:把多色/渐变 SVG 当成单色图标整体 tint
188
+
189
+ **问题**:国旗、品牌图标、渐变按钮图标如果直接套 `ColorFilter.mode()`,会把原本的多色信息全部抹平。
190
+
191
+ **规则**:
192
+ - 先看 `iconSvgMeta.colorStrategy`
193
+ - `preserve`:必须保留原始 SVG 颜色,禁止整体 tint
194
+ - `tint`:仅单色图标允许套 `ColorFilter.mode()`
195
+ - 优先使用插件生成的 `flutterSvgCode`,不要再手动把所有 SVG 改写成 `SvgPicture.asset(..., colorFilter: ...)`
196
+
197
+ ### 陷阱 6:添加设计稿中不存在的元素
172
198
 
173
199
  **问题**:AI 根据语义推测添加了设计稿中没有的 UI 元素(如在"汇率"标签前加了 swap_horiz 图标)。
174
200
 
@@ -296,12 +322,27 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
296
322
 
297
323
  ```
298
324
  1. 用户提供 Sketch 文件 → 先提醒:"需要先在 Sketch 中选中目标图层"
299
- 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })
325
+ 2. 调用 mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "compact" } })
300
326
  3. 将返回的 script 传入 mcp_sketch_run_code 执行
301
- 4. 基于测量数据中的 flutter* 字段精准还原(flutterColor、flutterBoxShadow、flutterSvgCode 等)
327
+ 4. 先按 restorationContract 还原页面骨架和文案,再消费 tree 中的 flutter* 字段
302
328
  5. FILL 类型尺寸使用 flutterHint 的 double.infinity,禁止硬编码宽度
329
+ 6. compact 无法解释局部布局/样式时,再补用 measure/style
303
330
  ```
304
331
 
332
+ ### 结构优先于业务语义(最高优先级)
333
+
334
+ 当设计稿还原发生以下冲突时,按下面优先级决策:
335
+
336
+ 1. restorationContract / 测量结果
337
+ 2. 设计稿截图的真实结构关系
338
+ 3. 项目 Token 与局部可复用样式
339
+ 4. 现有页面标题、i18n 文案、业务分组、通用 CTA 习惯
340
+
341
+ **强制结论**:
342
+ - 现有“收款人管理”“常用收款人 / 其他收款人”等业务语义,不得覆盖设计稿中测得的标题和结构
343
+ - 现有页面有底部添加按钮的实现习惯,不得据此把设计稿顶部入口改成底部固定按钮
344
+ - 现有通用列表组件如果会多带 section/header/footer,禁止为了复用而牺牲结构一致性
345
+
305
346
  ### 测量数据必备字段
306
347
 
307
348
  调用 SketchMeasureHD 后,你会得到以下关键数据:
@@ -327,6 +368,11 @@ get_standard_by_id({ ids: ['flutter', 'flutter-ui-system'] })
327
368
 
328
369
  ### 还原检查清单
329
370
 
371
+ - [ ] 先读取 `restorationContract.pageTitle`、`blockOrder`、`hardRules`
372
+ - [ ] 逐个 block 建立代码对应关系,未映射的 block 不能跳过
373
+ - [ ] `bodyCopyLedger` 文案与代码文案一致,未被业务文案覆盖
374
+ - [ ] 如果存在 `topPrimaryEntry`,确认没有被改成底部固定 CTA
375
+ - [ ] 如果 `bottomNavigation.present=true`,确认没有额外叠加固定底部操作条
330
376
  - [ ] 使用 `absoluteRect` 而非 `frame`(避免相对坐标错误)
331
377
  - [ ] 使用 `relativePosition` 计算内边距(转换为 `EdgeInsets`)
332
378
  - [ ] 使用 `siblingGaps` 确定元素间距(转换为 `Gap()`)
@@ -363,6 +409,7 @@ get_standard_by_id({ id: 'sketch-pitfalls' })
363
409
  | Tag 凭感觉写样式 | padding/bg/圆角全错 | 使用 tagStyle 测量数据 |
364
410
  | 字重超出平台上限 | 文字过粗(合成加粗) | PingFang≤w600, Helvetica≤w700 |
365
411
  | 添加不存在的元素 | UI 与设计稿不符 | 只还原测量数据中存在的元素 |
412
+ | 业务语义劫持页面骨架 | 标题/分组/CTA 被现有页面习惯改写 | 先服从 restorationContract,再考虑复用组件 |
366
413
 
367
414
  > 📖 **详细案例**:`mcp-server/troubleshooting/flutter/sketch-overflow-container.md`
368
415
 
@@ -377,6 +424,8 @@ get_standard_by_id({ id: 'sketch-pitfalls' })
377
424
  ❌ **禁止**凭推测添加设计稿中不存在的 UI 元素(如猜测性添加图标)
378
425
  ❌ **禁止**使用超出字体平台可用范围的 FontWeight(合成加粗视觉差异大)
379
426
  ❌ **禁止**同行不同尺寸 Icon 各用各的宽度(必须统一占位槽)
427
+ ❌ **禁止**用现有路由标题、i18n 文案或业务分组覆盖 restorationContract 中的文案真值
428
+ ❌ **禁止**把顶部入口卡片、顶部 CTA 或中部 section 入口迁移成底部固定按钮
380
429
 
381
430
  ### 🎯 深度还原模式(像素级)
382
431
 
package/dist/index.js CHANGED
@@ -464,20 +464,36 @@ var init_resourceLoader = __esm({
464
464
  * 支持多种运行环境
465
465
  */
466
466
  detectPackageRoot() {
467
- const rootFromDist = path4.resolve(__dirname, "..");
468
- const packageJsonPath = path4.join(rootFromDist, "package.json");
469
- if (fs4.existsSync(packageJsonPath)) {
470
- try {
471
- const pkg = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
472
- if (pkg.name === "mta-mcp") {
473
- this.log(`\u{1F4E6} \u68C0\u6D4B\u5230\u5305\u6839\u76EE\u5F55: ${rootFromDist}`);
474
- return rootFromDist;
467
+ const candidateRoots = [
468
+ path4.resolve(__dirname, ".."),
469
+ path4.resolve(__dirname, "..", ".."),
470
+ path4.resolve(__dirname, "..", "..", ".."),
471
+ process.cwd(),
472
+ path4.resolve(process.cwd(), "..")
473
+ ];
474
+ for (const candidate of candidateRoots) {
475
+ const packageJsonPath = path4.join(candidate, "package.json");
476
+ const hasResources = ["agents", "standards"].every(
477
+ (dir) => fs4.existsSync(path4.join(candidate, dir))
478
+ );
479
+ if (fs4.existsSync(packageJsonPath)) {
480
+ try {
481
+ const pkg = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
482
+ if (pkg.name === "mta-mcp") {
483
+ this.log(`\u{1F4E6} \u68C0\u6D4B\u5230\u5305\u6839\u76EE\u5F55: ${candidate}`);
484
+ return candidate;
485
+ }
486
+ } catch {
475
487
  }
476
- } catch {
488
+ }
489
+ if (hasResources) {
490
+ this.log(`\u{1F4E6} \u901A\u8FC7\u8D44\u6E90\u76EE\u5F55\u68C0\u6D4B\u5230\u5305\u6839\u76EE\u5F55: ${candidate}`);
491
+ return candidate;
477
492
  }
478
493
  }
479
- this.log(`\u{1F4E6} \u4F7F\u7528\u9ED8\u8BA4\u5305\u6839\u76EE\u5F55: ${rootFromDist}`);
480
- return rootFromDist;
494
+ const fallback = path4.resolve(__dirname, "..");
495
+ this.log(`\u{1F4E6} \u4F7F\u7528\u9ED8\u8BA4\u5305\u6839\u76EE\u5F55: ${fallback}`);
496
+ return fallback;
481
497
  }
482
498
  /**
483
499
  * 验证资源目录是否存在
@@ -2992,7 +3008,7 @@ function detectContext(args, logger4) {
2992
3008
  var _a;
2993
3009
  let fileType = "unknown";
2994
3010
  let imports = [];
2995
- let scenario = "";
3011
+ let scenario = args.scenario || "";
2996
3012
  if (args.currentFile && fs12.existsSync(args.currentFile)) {
2997
3013
  const ext = ((_a = args.currentFile.split(".").pop()) == null ? void 0 : _a.toLowerCase()) || "";
2998
3014
  const extMap = {
@@ -3016,6 +3032,7 @@ function detectContext(args, logger4) {
3016
3032
  if (fileType === "unknown") {
3017
3033
  if (args.fileContent.includes("<template>")) fileType = "vue";
3018
3034
  else if (args.fileContent.includes("interface ")) fileType = "ts";
3035
+ else if (args.fileContent.includes("package:flutter/") || args.fileContent.includes("StatelessWidget") || args.fileContent.includes("StatefulWidget") || args.fileContent.includes("Widget build(")) fileType = "dart";
3019
3036
  }
3020
3037
  scenario = scenario || inferScenario(args.fileContent, fileType);
3021
3038
  }
@@ -3049,6 +3066,9 @@ function buildKeyRulesResponse(uris, context, manager) {
3049
3066
  keyRules.push(...getCssKeyRules());
3050
3067
  } else if (context.fileType === "dart") {
3051
3068
  keyRules.push(...getFlutterKeyRules());
3069
+ if (isDesignRestorationScenario(context.scenario, context.imports)) {
3070
+ keyRules.push(...getFlutterDesignRestorationKeyRules());
3071
+ }
3052
3072
  } else if (context.fileType === "ts" || context.fileType === "tsx") {
3053
3073
  keyRules.push(...getTypeScriptKeyRules());
3054
3074
  }
@@ -3293,6 +3313,38 @@ function getFlutterKeyRules() {
3293
3313
  - \u274C \`Colors.blue\` Material \u989C\u8272\u5E38\u91CF`
3294
3314
  ];
3295
3315
  }
3316
+ function getFlutterDesignRestorationKeyRules() {
3317
+ return [
3318
+ `## Flutter \u8BBE\u8BA1\u7A3F\u8FD8\u539F\u5173\u952E\u89C4\u5219
3319
+
3320
+ ### \u5148\u8BFB\u9875\u9762 contract\uFF0C\u518D\u751F\u6210\u4EE3\u7801
3321
+ - \u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u4F18\u5148\u8BFB\u53D6 \`sketch_measure(cmd: "compact")\` \u8F93\u51FA\u4E2D\u7684 \`restorationContract\`
3322
+ - \u5148\u6309 \`blockOrder\` \u8FD8\u539F\u9875\u9762\u9AA8\u67B6\uFF0C\u518D\u5904\u7406\u989C\u8272\u3001\u5706\u89D2\u3001\u9634\u5F71\u548C SVG
3323
+ - \`bodyCopyLedger\` / \`navCopyLedger\` \u4E2D\u7684\u6587\u6848\u9ED8\u8BA4\u4E3A\u8BBE\u8BA1\u771F\u503C\uFF0C**\u7981\u6B62**\u66FF\u6362\u6210\u73B0\u6709\u8DEF\u7531\u6807\u9898\u3001i18n \u6587\u6848\u6216\u4E1A\u52A1\u5206\u7EC4\u540D
3324
+
3325
+ ### \u7ED3\u6784\u4F18\u5148\u4E8E\u4E1A\u52A1\u8BED\u4E49
3326
+ - \u73B0\u6709\u9879\u76EE\u7EC4\u4EF6\u3001\u9875\u9762\u6807\u9898\u3001\u5E38\u89C1 CTA \u4E60\u60EF\u53EA\u80FD\u4F5C\u4E3A\u5B9E\u73B0\u53C2\u8003\uFF0C**\u4E0D\u80FD\u8986\u76D6**\u6D4B\u91CF\u5F97\u5230\u7684\u7ED3\u6784
3327
+ - \u5982\u679C \`restorationContract.topPrimaryEntry\` \u5B58\u5728\uFF0C\u7981\u6B62\u628A\u9876\u90E8\u5165\u53E3\u8FC1\u79FB\u4E3A\u5E95\u90E8\u56FA\u5B9A\u6309\u94AE
3328
+ - \u5982\u679C \`restorationContract.bottomNavigation.present=true\`\uFF0C\u4E14 contract \u672A\u58F0\u660E\u989D\u5916 bottom CTA\uFF0C\u7981\u6B62\u518D\u6DFB\u52A0\u4E00\u5C42\u5E95\u90E8\u56FA\u5B9A\u64CD\u4F5C\u6761
3329
+
3330
+ ### \u6570\u636E\u4F7F\u7528\u4F18\u5148\u7EA7
3331
+ - \u9996\u8F6E\u4EE3\u7801\u751F\u6210: \`compact.restorationContract\` + \`compact.tree\`
3332
+ - \u5C40\u90E8\u6837\u5F0F/\u56FE\u6807\u8BCA\u65AD: \u518D\u8865\u8BFB \`measure\` \u6216 \`style\`
3333
+ - \u53EA\u8981 contract \u4E0E\u73B0\u6709\u4E1A\u52A1\u7EC4\u4EF6\u51B2\u7A81\uFF0C\u4F18\u5148\u4FDD\u8BC1\u8BBE\u8BA1\u7A3F\u7ED3\u6784\u4E00\u81F4\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u590D\u7528\u7EC4\u4EF6`
3334
+ ];
3335
+ }
3336
+ function isDesignRestorationScenario(scenario, imports) {
3337
+ const text = `${scenario} ${imports.join(" ")}`.toLowerCase();
3338
+ return [
3339
+ "\u8BBE\u8BA1\u7A3F",
3340
+ "\u8FD8\u539F",
3341
+ "sketch",
3342
+ "figma",
3343
+ "\u50CF\u7D20",
3344
+ "measure",
3345
+ "restoration"
3346
+ ].some((keyword) => text.includes(keyword));
3347
+ }
3296
3348
  function extractImports(content) {
3297
3349
  const imports = [];
3298
3350
  const esImportRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
@@ -3573,6 +3625,9 @@ var SCENARIO_STANDARDS = {
3573
3625
  "logicflow": ["logicflow", "vue3-composition"],
3574
3626
  "permission": ["permission-design", "route-guard"],
3575
3627
  "performance": ["performance-optimization", "lazy-loading"],
3628
+ "design-restoration": ["design-restoration", "sketch-pitfalls", "sketch-mcp"],
3629
+ "flutter-ui-restoration": ["flutter", "flutter-ui-system", "design-restoration", "sketch-pitfalls", "sketch-mcp"],
3630
+ "pixel-perfect-restoration": ["design-restoration", "sketch-pitfalls", "sketch-mcp"],
3576
3631
  // ========== 项目克隆场景 ==========
3577
3632
  "clone-project": ["project-structure", "architecture-patterns", "code-organization"],
3578
3633
  "project-skeleton": ["project-structure", "base-config", "utility-patterns"],
@@ -3582,13 +3637,15 @@ var FILETYPE_STANDARDS = {
3582
3637
  "vue": ["vue3-composition"],
3583
3638
  "ts": ["typescript-strict"],
3584
3639
  "tsx": ["react-hooks", "typescript-strict"],
3585
- "dart": ["dart-style", "flutter-bloc"]
3640
+ "dart": ["dart-base", "flutter", "flutter-ui-system"]
3586
3641
  };
3587
3642
  var IMPORT_STANDARDS = {
3588
3643
  "vue": ["vue3-composition"],
3589
3644
  "element-plus": ["element-plus"],
3590
3645
  "pinia": ["pinia-store"],
3591
3646
  "axios": ["axios-interceptor"],
3647
+ "flutter": ["flutter", "flutter-ui-system"],
3648
+ "flutter_svg": ["sketch-mcp"],
3592
3649
  "vue-i18n": ["i18n"],
3593
3650
  "@logicflow/core": ["logicflow"],
3594
3651
  "vitest": ["vitest-guide"]
@@ -3600,7 +3657,11 @@ function getStandardsForFileType(fileType) {
3600
3657
  return FILETYPE_STANDARDS[fileType] || [];
3601
3658
  }
3602
3659
  function getStandardsForImport(importName) {
3603
- const normalizedImport = importName.startsWith("@") ? importName.split("/").slice(0, 2).join("/") : importName.split("/")[0];
3660
+ let normalizedImport = importName;
3661
+ if (normalizedImport.startsWith("package:")) {
3662
+ normalizedImport = normalizedImport.replace("package:", "");
3663
+ }
3664
+ normalizedImport = normalizedImport.startsWith("@") ? normalizedImport.split("/").slice(0, 2).join("/") : normalizedImport.split("/")[0];
3604
3665
  return IMPORT_STANDARDS[normalizedImport] || [];
3605
3666
  }
3606
3667
  function listAvailableScenarios() {
@@ -5955,7 +6016,7 @@ var SkillRegistry = class {
5955
6016
  };
5956
6017
  const lines = [
5957
6018
  "MTA \u667A\u80FD\u7F16\u7801\u52A9\u624B - \u7EDF\u4E00\u6280\u80FD\u5165\u53E3\u3002",
5958
- "\u901A\u8FC7 skill \u53C2\u6570\u9009\u62E9\u8981\u6267\u884C\u7684\u6280\u80FD\uFF0Cparams \u4F20\u5165\u8BE5\u6280\u80FD\u6240\u9700\u53C2\u6570\u3002",
6019
+ "\u901A\u8FC7 skill \u53C2\u6570\u9009\u62E9\u8981\u6267\u884C\u7684\u6280\u80FD\u3002\u4F18\u5148\u4F7F\u7528 params \u4F20\u53C2\uFF1B\u82E5\u5BA2\u6237\u7AEF\u4E0D\u652F\u6301\u5D4C\u5957\u5BF9\u8C61\uFF0C\u4E5F\u53EF\u76F4\u63A5\u628A\u53C2\u6570\u5E73\u94FA\u5230\u9876\u5C42\u3002",
5959
6020
  "",
5960
6021
  "\u53EF\u7528\u6280\u80FD\uFF1A"
5961
6022
  ];
@@ -5989,6 +6050,7 @@ var SkillRegistry = class {
5989
6050
  additionalProperties: true
5990
6051
  }
5991
6052
  },
6053
+ additionalProperties: true,
5992
6054
  required: ["skill"]
5993
6055
  };
5994
6056
  }
@@ -6031,6 +6093,28 @@ function getSkillRegistry() {
6031
6093
  return globalRegistry;
6032
6094
  }
6033
6095
 
6096
+ // src/core/unifiedToolParams.ts
6097
+ function isRecord(value) {
6098
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6099
+ }
6100
+ function resolveUnifiedToolParams(args) {
6101
+ if (!isRecord(args)) {
6102
+ return {};
6103
+ }
6104
+ const nestedParams = args.params;
6105
+ if (isRecord(nestedParams)) {
6106
+ return { ...nestedParams };
6107
+ }
6108
+ const flatParams = {};
6109
+ for (const [key, value] of Object.entries(args)) {
6110
+ if (key === "skill" || key === "params") {
6111
+ continue;
6112
+ }
6113
+ flatParams[key] = value;
6114
+ }
6115
+ return flatParams;
6116
+ }
6117
+
6034
6118
  // src/tools/sketchMeasure.ts
6035
6119
  import * as fs19 from "fs";
6036
6120
  import * as os from "os";
@@ -6063,12 +6147,21 @@ var PLUGIN_SCRIPT_FILES = {
6063
6147
  };
6064
6148
  var OUTPUT_GUIDE = {
6065
6149
  measure: [
6066
- "## \u63D2\u4EF6\u8F93\u51FA\u89E3\u8BFB\u6307\u5357 (measure.js v3.0.6)",
6150
+ "## \u63D2\u4EF6\u8F93\u51FA\u89E3\u8BFB\u6307\u5357 (measure.js v3.2.0)",
6067
6151
  "",
6068
6152
  "### \u8BBE\u8BA1\u539F\u5219",
6069
6153
  "- \u63D2\u4EF6 = \u6570\u636E\u63D0\u53D6\u5DE5\u5177\uFF0C\u4E0D\u662F\u4EE3\u7801\u751F\u6210\u5668",
6070
6154
  "- \u8F93\u51FA\u5B57\u6BB5\u5C3D\u53EF\u80FD\u5E26 Flutter \u4EE3\u7801\u63D0\u793A\uFF08flutterColor/flutterBorder/flutterHint \u7B49\uFF09\uFF0C\u53EF\u76F4\u63A5\u7C98\u8D34",
6071
6155
  "- \u539F\u59CB Sketch \u6570\u636E + \u5750\u6807\u7CFB\u8F6C\u6362\u53C2\u8003\uFF0C\u7531\u4F60\u6839\u636E\u9879\u76EE\u6846\u67B6\u51B3\u5B9A\u6700\u7EC8\u5B9E\u73B0",
6156
+ "- **\u9996\u8F6E\u8FD8\u539F\u5148\u8BFB restorationContract**\uFF0C\u518D\u770B tree \u7EA7\u8282\u70B9\u660E\u7EC6\uFF0C\u907F\u514D\u88AB\u6D77\u91CF JSON \u6216\u73B0\u6709\u4E1A\u52A1\u8BED\u4E49\u5E26\u504F",
6157
+ "",
6158
+ "### \u9875\u9762\u7EA7\u8FD8\u539F\u5951\u7EA6\uFF08v3.1.0 \u65B0\u589E\uFF09",
6159
+ "- **restorationContract.pageTitle**: \u9875\u9762\u6807\u9898\u771F\u503C\uFF0C\u9ED8\u8BA4\u4F18\u5148\u4E8E\u73B0\u6709\u8DEF\u7531\u6807\u9898\u548C i18n \u6587\u6848",
6160
+ "- **restorationContract.blockOrder**: \u9876\u5C42\u9AA8\u67B6\u987A\u5E8F\uFF0C\u4EE3\u7801\u5E94\u5148\u6309\u5B83\u8FD8\u539F\u9875\u9762\u5C42\u7EA7\uFF0C\u7981\u6B62\u81EA\u884C\u91CD\u7EC4\u4E3A\u201C\u5E38\u7528/\u5176\u4ED6\u201D\u7B49\u4E1A\u52A1\u5206\u533A",
6161
+ "- **restorationContract.bodyCopyLedger/navCopyLedger**: \u8BBE\u8BA1\u7A3F\u4E2D\u6D4B\u5F97\u7684\u6B63\u6587/\u5E95\u5BFC\u6587\u6848\uFF0C\u9ED8\u8BA4\u6309\u539F\u6587\u8FD8\u539F",
6162
+ "- **restorationContract.topPrimaryEntry**: \u82E5\u5B58\u5728\u9876\u90E8\u4E3B\u5165\u53E3\u5757\uFF0C**\u7981\u6B62**\u8FC1\u79FB\u4E3A\u5E95\u90E8\u56FA\u5B9A CTA",
6163
+ "- **restorationContract.bottomNavigation.present**: \u82E5\u4E3A true \u4E14 contract \u672A\u58F0\u660E\u989D\u5916 CTA\uFF0C\u7981\u6B62\u518D\u989D\u5916\u589E\u52A0\u5E95\u90E8\u64CD\u4F5C\u6761",
6164
+ "- **restorationContract.hardRules**: \u751F\u6210\u4EE3\u7801\u524D\u5FC5\u987B\u9010\u6761\u68C0\u67E5\uFF1B\u4E00\u65E6\u8FDD\u53CD\uFF0C\u8BF4\u660E\u9875\u9762\u5DF2\u53D1\u751F\u7ED3\u6784\u6F02\u79FB",
6072
6165
  "",
6073
6166
  "### \u989C\u8272\u5B57\u6BB5\uFF08\u6700\u5E38\u51FA\u9519\uFF09",
6074
6167
  '- **colorSource**: "native" \u8868\u793A\u901A\u8FC7 Cocoa API \u83B7\u53D6\u7684\u7CBE\u786E\u989C\u8272\uFF08\u4F18\u5148\u4FE1\u4EFB\uFF09\uFF0C"jsApi" \u662F Sketch JS API \u9884\u5904\u7406\u503C\uFF08\u53EF\u80FD\u4E0D\u51C6\uFF09',
@@ -6109,7 +6202,9 @@ var OUTPUT_GUIDE = {
6109
6202
  "### \u6587\u672C\u5B57\u6BB5",
6110
6203
  "- **strutHeight**: = frameHeight / fontSize\uFF0C\u76F4\u63A5\u7528\u4F5C StrutStyle(height: N)\uFF0C\u6D88\u9664 CJK \u5B57\u4F53\u89C6\u89C9\u504F\u4E0B",
6111
6204
  "- **nativeRenderedWidth**: MSTextLayer \u6392\u7248\u5F15\u64CE\u5B9E\u9645\u6E32\u67D3\u5BBD\u5EA6\uFF08CJK \u5B57\u4F53\u5B9E\u9645\u6362\u884C\u6BD4 frame.width \u7A84\uFF09",
6112
- "- **parseFontWeight**: PingFang SC \u5728 Flutter \u6E32\u67D3\u6BD4 iOS \u7C97\uFF0C\u63D2\u4EF6\u5DF2\u81EA\u52A8\u964D\u7EA7(600\u2192500)\uFF0C\u76F4\u63A5\u4F7F\u7528 flutterValue",
6205
+ "- **flutterTextStyle**: \u63D2\u4EF6\u73B0\u5DF2\u76F4\u63A5\u8F93\u51FA\u5B8C\u6574 TextStyle\uFF08\u542B fontFamily/height/letterSpacing/color/fontWeight\uFF09",
6206
+ "- **flutterStrutStyle**: \u56FA\u5B9A\u9AD8\u5EA6\u6216\u9700\u8981\u5F3A\u6821\u51C6\u884C\u76D2\u65F6\uFF0C\u76F4\u63A5\u4F7F\u7528 StrutStyle(fontSize,height,leading:0,forceStrutHeight:true)",
6207
+ "- **parseFontWeight**: \u4FDD\u7559\u5B57\u4F53\u771F\u5B9E\u53EF\u7528\u5B57\u91CD\uFF1BPingFang/Helvetica \u53EA\u5728\u8D85\u51FA\u5E73\u53F0\u4E0A\u9650\u65F6\u94B3\u5236\uFF0C\u4E0D\u518D\u628A PingFangSC-Semibold \u81EA\u52A8\u964D\u6210 w500",
6113
6208
  "",
6114
6209
  "### \u7B26\u53F7\u5B57\u4F53\u56FE\u6807\uFF08v3.0.3 \u65B0\u589E\uFF09",
6115
6210
  "- **element.text.isSymbolFont=true**: \u6B64\u6587\u5B57\u56FE\u5C42\u4F7F\u7528 ZapfDingbats/Symbol/Webdings \u7B49\u7B26\u53F7\u5B57\u4F53",
@@ -6122,8 +6217,11 @@ var OUTPUT_GUIDE = {
6122
6217
  "",
6123
6218
  "### \u56FE\u6807\u5B57\u6BB5",
6124
6219
  "- **isIcon=true**: \u5DF2\u901A\u8FC7 5 \u7279\u5F81\u8BC4\u5206\u8BC6\u522B\u4E3A\u56FE\u6807\uFF0C\u5E94\u5BFC\u51FA SVG \u800C\u975E\u7528 Icons.xxx",
6125
- "- **flutterSvgCode**: \u53EF\u76F4\u63A5\u7C98\u8D34\u7684 SvgPicture.asset() \u4EE3\u7801\u7247\u6BB5\uFF0C\u542B\u7CBE\u786E ColorFilter",
6220
+ "- **iconSvgMarkup**: \u63D2\u4EF6\u73B0\u5DF2\u76F4\u63A5\u8FD4\u56DE\u4ECE Sketch \u5BFC\u51FA\u7684\u771F\u5B9E SVG \u5B57\u7B26\u4E32\uFF0C\u4E0D\u518D\u53EA\u731C\u6D4B\u6587\u4EF6\u540D",
6221
+ "- **iconSvgMeta.colorStrategy**: preserve=\u4FDD\u6301\u539F\u8272\uFF08\u591A\u8272/\u6E10\u53D8/\u5185\u5D4C\u4F4D\u56FE\uFF09\uFF0Ctint=\u5355\u8272\u56FE\u6807\u53EF\u7528 colorFilter",
6222
+ "- **flutterSvgCode**: \u53EF\u76F4\u63A5\u7C98\u8D34\u7684 SvgPicture.string(...) \u4EE3\u7801\uFF1B\u53EA\u6709\u5355\u8272\u56FE\u6807\u624D\u4F1A\u81EA\u52A8\u9644\u5E26 ColorFilter",
6126
6223
  "- **iconContentBounds**: \u56FE\u6807\u5185\u5BB9\u5B9E\u9645\u8FB9\u754C\uFF08vs \u5BB9\u5668\u5C3A\u5BF8\uFF09\uFF0C\u7528\u4E8E SizedBox \u7EA6\u675F",
6224
+ "- **iconExportPath/iconSvgFileName**: \u82E5\u9700\u8981\u843D\u76D8\u8D44\u6E90\uFF0C\u4F7F\u7528\u63D2\u4EF6\u5EFA\u8BAE\u6587\u4EF6\u540D\u4FDD\u5B58\u5230 assets/icons/",
6127
6225
  "- \u8986\u76D6\u4FEE\u6B63: \u56DB\u8FB9\u8DDD\u22642pt \u6216\u5BBD\u9AD8\u2265\u7236\u5BB9\u566888% \u7684 ShapePath \u662F\u80CC\u666F\u5C42\uFF0C\u5DF2\u81EA\u52A8\u6392\u9664",
6128
6226
  "",
6129
6227
  "### ShapePath \u8BED\u4E49\uFF08v3.0.6 \u66F4\u65B0\uFF09",
@@ -6211,7 +6309,7 @@ var OUTPUT_GUIDE = {
6211
6309
  "### \u6CE8\u610F\u4E8B\u9879",
6212
6310
  "- \u56FE\u6807 = [\u5706\u5F62\u5BB9\u5668 + \u56FE\u6807\u56FE\u5F62] \u65F6\uFF0C\u9009\u5916\u5C42\u5BFC\u51FA\u4F1A\u542B\u80CC\u666F\u5706\u89D2\u77E9\u5F62\u8DEF\u5F84",
6213
6311
  "- \u5982\u679C\u8F93\u51FA\u542B backgroundLayerWarnings\uFF0C\u8BF4\u660E SVG \u4E2D\u5305\u542B\u80CC\u666F\u5C42\uFF0C\u9700\u8981\u5728 Sketch \u4E2D\u53EA\u9009\u4E2D\u56FE\u6807\u56FE\u5F62\u90E8\u5206\u91CD\u65B0\u5BFC\u51FA",
6214
- "- SVG \u5BFC\u51FA\u540E\u7528 flutter_svg \u7684 SvgPicture.asset() \u52A0\u8F7D\uFF0C\u989C\u8272\u901A\u8FC7 ColorFilter.mode() \u63A7\u5236"
6312
+ "- SVG \u5BFC\u51FA\u7ED3\u679C\u4F1A\u540C\u65F6\u8FD4\u56DE svgMarkup\uFF1B\u5355\u8272\u56FE\u6807\u53EF\u7528 ColorFilter\uFF0C\u591A\u8272/\u6E10\u53D8\u56FE\u6807\u5FC5\u987B\u4FDD\u7559\u539F\u8272"
6215
6313
  ].join("\n"),
6216
6314
  auto: "",
6217
6315
  // auto 等同 measure
@@ -6219,6 +6317,7 @@ var OUTPUT_GUIDE = {
6219
6317
  "## \u63D2\u4EF6\u8F93\u51FA\u89E3\u8BFB\u6307\u5357 (measure.js compact \u6A21\u5F0F)",
6220
6318
  "",
6221
6319
  "\u8F93\u51FA\u4F53\u79EF\u7EA6\u4E3A\u5B8C\u6574 measure \u7684 3-8%\uFF0C\u53EA\u4FDD\u7559 Flutter \u4EE3\u7801\u751F\u6210\u6240\u9700\u5B57\u6BB5\u3002",
6320
+ "\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E**\u4F18\u5148\u4F7F\u7528 compact**\uFF0C\u56E0\u4E3A\u5B83\u5185\u8054\u4E86 restorationContract\uFF0C\u80FD\u5148\u9501\u5B9A\u9875\u9762\u9AA8\u67B6\u548C\u6587\u6848\u771F\u503C\u3002",
6222
6321
  "",
6223
6322
  "### \u5B57\u6BB5\u7EA6\u5B9A\uFF08\u7F29\u77ED\u952E\u540D\uFF09",
6224
6323
  "- **n/t/f**: name / type / [x,y,w,h]",
@@ -6229,15 +6328,16 @@ var OUTPUT_GUIDE = {
6229
6328
  "- **token**: AppShadows.xxx token \u540D\uFF0C\u4F18\u5148\u4F7F\u7528\u4EE3\u66FF\u786C\u7F16\u7801 BoxShadow",
6230
6329
  "- **r**: borderRadius \u6570\u503C",
6231
6330
  "- **rp**: [left,top,right,bottom] \u76F8\u5BF9\u7236\u5BB9\u5668\u8FB9\u8DDD",
6232
- "- **icon/svg/cs/xs**: \u56FE\u6807\u6807\u8BC6/SvgPicture\u4EE3\u7801/containerSize/contentSize",
6233
- "- **text/style**: \u6587\u672C\u5185\u5BB9/TextStyle(...) \u4EE3\u7801",
6234
- "- **lh**: strutHeight\uFF08\u4EC5\u975E\u6807\u51C6\u503C\uFF0C\u76F4\u63A5\u7528\u4E8E StrutStyle\uFF09",
6331
+ "- **icon/svg/cs/xs**: \u56FE\u6807\u6807\u8BC6/\u771F\u5B9E SvgPicture.string(...) \u4EE3\u7801/containerSize/contentSize",
6332
+ "- **svgMode/svgReason/svgFile**: preserve|tint / \u989C\u8272\u7B56\u7565\u539F\u56E0 / \u5EFA\u8BAE\u843D\u76D8\u6587\u4EF6\u540D",
6333
+ "- **text/style/family/textHeight**: \u6587\u672C\u5185\u5BB9/\u5B8C\u6574 TextStyle/\u5B57\u4F53\u65CF/\u884C\u9AD8\u6BD4",
6334
+ "- **lh/strut**: strutHeight / \u5B8C\u6574 StrutStyle(...)",
6235
6335
  "- **tag**: {bg,ph,pv,r,text} Tag\u5BB9\u5668\u4FE1\u606F",
6236
6336
  "- **layout**: {dir,gap,main,cross,pad} \u5E03\u5C40\u610F\u56FE",
6237
6337
  "- **ch**: \u5B50\u5143\u7D20\u6570\u7EC4\uFF08\u9012\u5F52\uFF09",
6238
6338
  "",
6239
6339
  "### \u4F7F\u7528\u65B9\u5F0F",
6240
- "\u76F4\u63A5\u8BFB\u53D6 flutter* \u5B57\u6BB5\u751F\u6210\u4EE3\u7801\uFF0C\u65E0\u9700\u89E3\u6790\u539F\u59CB Sketch \u6570\u636E\u3002"
6340
+ "\u5148\u8BFB\u53D6 restorationContract.blockOrder/bodyCopyLedger/hardRules \u9501\u5B9A\u7ED3\u6784\uFF0C\u518D\u7528 tree \u4E2D\u7684 flutter* \u5B57\u6BB5\u586B\u5145\u6837\u5F0F\u548C\u5E03\u5C40\u7EC6\u8282\u3002"
6241
6341
  ].join("\n")
6242
6342
  };
6243
6343
  function findFirst(paths) {
@@ -6267,7 +6367,7 @@ function tryAutoInstall(bundlePath) {
6267
6367
  }
6268
6368
  }
6269
6369
  async function sketchMeasure(args) {
6270
- const cmd = args.cmd || "measure";
6370
+ const cmd = args.cmd || "compact";
6271
6371
  if (!VALID_CMDS.includes(cmd)) {
6272
6372
  return {
6273
6373
  content: [{
@@ -6275,7 +6375,7 @@ async function sketchMeasure(args) {
6275
6375
  text: JSON.stringify({
6276
6376
  error: `\u65E0\u6548\u7684 cmd \u53C2\u6570: "${cmd}"`,
6277
6377
  validValues: VALID_CMDS,
6278
- usage: 'mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "measure" } })'
6378
+ usage: 'mcp_mta_mta({ skill: "sketch_measure", params: { cmd: "compact" } })'
6279
6379
  }, null, 2)
6280
6380
  }]
6281
6381
  };
@@ -6327,7 +6427,7 @@ async function sketchMeasure(args) {
6327
6427
  scriptPath: tempScriptPath,
6328
6428
  scriptLength: fullScript.length,
6329
6429
  pluginInstall: installStatus,
6330
- instruction: "\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code({ code: loaderScript }) \u6267\u884C\u3002\u811A\u672C\u5DF2\u5199\u5165\u4E34\u65F6\u6587\u4EF6\uFF0CSketch \u4F1A\u4ECE\u78C1\u76D8\u76F4\u63A5\u8BFB\u53D6\uFF0C\u65E0\u9700 AI \u4E2D\u8F6C\u811A\u672C\u5185\u5BB9\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
6430
+ instruction: "\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code({ code: loaderScript }) \u6267\u884C\u3002\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u4F18\u5148\u4F7F\u7528 cmd=compact\uFF1B\u53EA\u6709\u5F53 compact contract \u4E0D\u8DB3\u4EE5\u89E3\u91CA\u5C40\u90E8\u5E03\u5C40\u6216\u6837\u5F0F\u65F6\uFF0C\u518D\u8865\u7528 measure/style\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
6331
6431
  outputGuide: OUTPUT_GUIDE[cmd] || OUTPUT_GUIDE["measure"],
6332
6432
  loaderScript
6333
6433
  }, null, 2)
@@ -6670,9 +6770,9 @@ var skillDefinitions = [
6670
6770
  {
6671
6771
  name: "sketch_measure",
6672
6772
  category: "sketch",
6673
- description: "\u51C6\u5907 Sketch \u6D4B\u91CF\u811A\u672C\u3002\u811A\u672C\u5199\u5165\u4E34\u65F6\u6587\u4EF6\uFF0C\u8FD4\u56DE\u8F7B\u91CF\u52A0\u8F7D\u5668\u4EE3\u7801\uFF08~300B\uFF09\uFF0C\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code \u6267\u884C\u5373\u53EF\u3002Sketch \u901A\u8FC7 CocoaScript \u4ECE\u78C1\u76D8\u8BFB\u53D6\u5B8C\u6574\u811A\u672C\uFF0C\u4E0D\u7ECF\u8FC7 AI \u4E0A\u4E0B\u6587\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)",
6773
+ description: "\u51C6\u5907 Sketch \u6D4B\u91CF\u811A\u672C\u3002\u811A\u672C\u5199\u5165\u4E34\u65F6\u6587\u4EF6\uFF0C\u8FD4\u56DE\u8F7B\u91CF\u52A0\u8F7D\u5668\u4EE3\u7801\uFF08~300B\uFF09\uFF0C\u5C06 loaderScript \u4F20\u5165 mcp_sketch_run_code \u6267\u884C\u5373\u53EF\u3002Sketch \u901A\u8FC7 CocoaScript \u4ECE\u78C1\u76D8\u8BFB\u53D6\u5B8C\u6574\u811A\u672C\uFF0C\u4E0D\u7ECF\u8FC7 AI \u4E0A\u4E0B\u6587\u3002\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u9ED8\u8BA4\u5C31\u662F compact(\u5E26\u9875\u9762\u7EA7 restorationContract)\uFF0C\u518D\u6309\u9700\u7528 measure/style \u6DF1\u6316\u3002\u652F\u6301 compact(\u7D27\u51D1\u8FD8\u539F\u5408\u540C)\u3001measure(\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)",
6674
6774
  paramHints: [
6675
- { 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)" },
6775
+ { name: "cmd", type: "string", description: "\u6267\u884C\u6A21\u5F0F: compact(\u9ED8\u8BA4\uFF0C\u8BBE\u8BA1\u7A3F\u8FD8\u539F\u9996\u8F6E\u63A8\u8350\uFF0C\u8F93\u51FA restorationContract) / measure(\u5B8C\u6574\u753B\u677F) / layout(\u5E03\u5C40\u5206\u6790) / style(\u6837\u5F0F\u68C0\u67E5) / svg(\u56FE\u6807\u5BFC\u51FA) / auto(\u81EA\u52A8\u5224\u65AD)" },
6676
6776
  { name: "outputPath", type: "string", description: "SVG \u8F93\u51FA\u8DEF\u5F84\uFF08\u4EC5 cmd=svg \u65F6\u4F7F\u7528\uFF09" }
6677
6777
  ],
6678
6778
  handler: async (params) => {
@@ -7587,7 +7687,7 @@ You should:
7587
7687
  }]
7588
7688
  };
7589
7689
  } else {
7590
- const params = unifiedArgs.params || {};
7690
+ const params = resolveUnifiedToolParams(unifiedArgs);
7591
7691
  result = await this.skillRegistry.execute(unifiedArgs.skill, params);
7592
7692
  }
7593
7693
  }