mta-mcp 3.15.1 → 3.15.3
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/dist/index.js
CHANGED
|
@@ -6403,13 +6403,17 @@ var OUTPUT_GUIDE = {
|
|
|
6403
6403
|
"- **token**: AppShadows.xxx token \u540D\uFF0C\u4F18\u5148\u4F7F\u7528\u4EE3\u66FF\u786C\u7F16\u7801 BoxShadow",
|
|
6404
6404
|
"- **r**: borderRadius \u6570\u503C",
|
|
6405
6405
|
"- **rp**: [left,top,right,bottom] \u76F8\u5BF9\u7236\u5BB9\u5668\u8FB9\u8DDD",
|
|
6406
|
+
"- **vf**: [x,y,w,h] \u89C6\u89C9\u8FB9\u754C\uFF1B\u5F53\u80CC\u666F\u5C42/\u9634\u5F71\u8D85\u51FA\u7236 Group frame \u65F6\uFF0C\u5BB9\u5668\u5C3A\u5BF8\u548C\u89C6\u89C9\u5E95\u8FB9\u8DDD\u4F18\u5148\u770B vf",
|
|
6406
6407
|
"- **icon/svg/cs/xs**: \u56FE\u6807\u6807\u8BC6/\u771F\u5B9E SvgPicture.string(...) \u4EE3\u7801/containerSize/contentSize",
|
|
6408
|
+
"- **image/img/bitmapPath/bitmapScales**: \u4F4D\u56FE\u56FE\u5C42\u6807\u8BC6/Image.asset \u4EE3\u7801/\u5EFA\u8BAE\u843D\u76D8\u8DEF\u5F84/1x-3x \u5BFC\u51FA\u8981\u6C42",
|
|
6407
6409
|
"- **svgMode/svgReason/svgFile**: preserve|tint / \u989C\u8272\u7B56\u7565\u539F\u56E0 / \u5EFA\u8BAE\u843D\u76D8\u6587\u4EF6\u540D",
|
|
6408
6410
|
"- **text/style/family/textHeight**: \u6587\u672C\u5185\u5BB9/\u5B8C\u6574 TextStyle/\u5B57\u4F53\u65CF/\u884C\u9AD8\u6BD4",
|
|
6409
6411
|
"- **lh/strut**: strutHeight / \u5B8C\u6574 StrutStyle(...)",
|
|
6410
6412
|
"- **tag**: {bg,ph,pv,r,text} Tag\u5BB9\u5668\u4FE1\u606F",
|
|
6411
6413
|
"- **layout**: {dir,gap,main,cross,pad} \u5E03\u5C40\u610F\u56FE",
|
|
6412
6414
|
"- **ch**: \u5B50\u5143\u7D20\u6570\u7EC4\uFF08\u9012\u5F52\uFF09",
|
|
6415
|
+
"- **designSurface**: {width,height,maxWidth,wideScreenRule} \u8BBE\u8BA1\u753B\u677F\u7EA6\u675F\uFF1B\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u5728\u5BBD\u5C4F\u5FC5\u987B\u505A\u5C45\u4E2D\u5939\u6301",
|
|
6416
|
+
"- **selectionContext**: compact \u82E5\u53D1\u73B0\u9009\u4E2D\u7684\u662F\u5B50\u56FE\u5C42\uFF0C\u4F1A\u81EA\u52A8\u63D0\u5347\u5230\u6240\u5C5E\u753B\u677F/\u9876\u5C42\u5BB9\u5668\u5E76\u8BB0\u5F55 warning",
|
|
6413
6417
|
"",
|
|
6414
6418
|
"### \u4F7F\u7528\u65B9\u5F0F",
|
|
6415
6419
|
"\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",
|
|
@@ -6418,7 +6422,10 @@ var OUTPUT_GUIDE = {
|
|
|
6418
6422
|
"- \u56FE\u6807\u662F\u5426\u8BEF\u7528\u65E7\u9875\u9762\u8D44\u4EA7\uFF1A\u540C\u540D\u7BAD\u5934/\u56FE\u6807\u9ED8\u8BA4\u4E0D\u53EF\u4FE1\uFF0C\u5148\u6838\u5BF9\u6765\u6E90\u56FE\u5C42",
|
|
6419
6423
|
"- SVG \u662F\u5426\u8BEF\u52A0 ColorFilter\uFF1A\u4FDD\u7559\u539F\u8272\u7684 SVG \u4E0D\u5F97\u4E8C\u6B21\u67D3\u8272",
|
|
6420
6424
|
"- \u56FE\u6807\u662F\u5426\u7528\u9519\u5C3A\u5BF8\uFF1A16x16 \u69FD\u4F4D\u4E0D\u7B49\u4E8E 16x16 \u56FE\u5F62\uFF0C\u6309 xs/cs \u5206\u79BB\u5360\u4F4D\u4E0E\u6E32\u67D3",
|
|
6421
|
-
"- Bitmap \u662F\u5426\u8BEF\u5F53 SVG\uFF1ASketch Image \u56FE\u5C42\u5FC5\u987B\u5BFC\u51FA PNG + Image.asset",
|
|
6425
|
+
"- Bitmap \u662F\u5426\u8BEF\u5F53 SVG\uFF1ASketch Image \u56FE\u5C42\u5FC5\u987B\u5BFC\u51FA PNG + Image.asset\uFF0C\u4E14\u8865\u9F50 2.0x/3.0x \u53D8\u4F53",
|
|
6426
|
+
"- \u79FB\u52A8\u7AEF\u7A84\u753B\u677F\uFF08\u5982 390 \u5BBD\uFF09\u5728\u5BBD\u5C4F\u5FC5\u987B\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u5939\u6301\uFF0C\u7981\u6B62\u8BA9 Positioned(left/right) \u76F4\u63A5\u62C9\u4F38\u5230\u5168\u5C4F",
|
|
6427
|
+
"- \u82E5\u8282\u70B9\u540C\u65F6\u7ED9\u51FA f \u4E0E vf\uFF0C\u8BF4\u660E\u80CC\u666F\u5C42/\u9634\u5F71\u8D85\u51FA\u903B\u8F91 frame\uFF1B\u5BB9\u5668\u5C3A\u5BF8\u548C\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4F7F\u7528 vf",
|
|
6428
|
+
"- \u82E5 selectionContext.autoPromoted=true\uFF0C\u8BF4\u660E\u4E4B\u524D\u9009\u4E2D\u4E86\u5185\u5C42 glyph\uFF1B\u540E\u7EED\u5C40\u90E8\u5BFC\u51FA\u56FE\u6807\u65F6\u5E94\u6539\u7528 cmd=svg \u9009\u4E2D\u5177\u4F53\u56FE\u5C42",
|
|
6422
6429
|
"- \u9875\u9762\u9AA8\u67B6\u662F\u5426\u88AB\u4E1A\u52A1\u7EC4\u4EF6\u6539\u5199\uFF1A\u6807\u9898\u3001\u9876\u90E8\u5165\u53E3\u3001\u641C\u7D22\u5757\u548C\u5E95\u5BFC\u987A\u5E8F\u5FC5\u987B\u56DE\u770B restorationContract"
|
|
6423
6430
|
].join("\n")
|
|
6424
6431
|
};
|
|
@@ -6509,14 +6516,30 @@ async function sketchMeasure(args) {
|
|
|
6509
6516
|
scriptPath: tempScriptPath,
|
|
6510
6517
|
scriptLength: fullScript.length,
|
|
6511
6518
|
pluginInstall: installStatus,
|
|
6512
|
-
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\u82E5\u504F\u5DEE\u96C6\u4E2D\u5728\u5355\u4E2A icon/svg/bitmap\uFF0C\u8BF7\u91CD\u65B0\u9009\u4E2D\u8BE5\u56FE\u5C42\u6267\u884C svg \u6216\u5C40\u90E8\u5BFC\u51FA\uFF0C\u5E76\u590D\u67E5 colorStrategy\u3001viewBox\u3001containerSize/contentSize\uFF0C\u907F\u514D\u590D\u7528\u65E7\u9875\u9762\u8D44\u4EA7\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
|
|
6519
|
+
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\u82E5\u504F\u5DEE\u96C6\u4E2D\u5728\u5355\u4E2A icon/svg/bitmap\uFF0C\u8BF7\u91CD\u65B0\u9009\u4E2D\u8BE5\u56FE\u5C42\u6267\u884C svg \u6216\u5C40\u90E8\u5BFC\u51FA\uFF0C\u5E76\u590D\u67E5 colorStrategy\u3001viewBox\u3001containerSize/contentSize\u3001vf \u4E0E bitmapScales\uFF0C\u907F\u514D\u590D\u7528\u65E7\u9875\u9762\u8D44\u4EA7\u3002\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u8981\u6309 designSurface.maxWidth \u505A\u5BBD\u5C4F\u5939\u6301\u3002compact \u82E5\u68C0\u6D4B\u5230\u4F60\u9009\u4E2D\u7684\u662F\u5185\u5C42 glyph\uFF0C\u4F1A\u81EA\u52A8\u63D0\u5347\u5230\u6240\u5C5E\u753B\u677F\u5E76\u901A\u8FC7 selectionContext \u56DE\u62A5\u3002\u8BF7\u5148\u5728 Sketch \u4E2D\u9009\u4E2D\u76EE\u6807\u753B\u677F/\u56FE\u5C42\u3002",
|
|
6513
6520
|
restoreChecklist: [
|
|
6514
6521
|
"\u5148\u6309 restorationContract \u9501\u5B9A\u9875\u9762\u9AA8\u67B6\uFF0C\u518D\u5904\u7406\u5C40\u90E8\u6837\u5F0F",
|
|
6515
6522
|
"\u5355\u4E2A\u56FE\u6807\u504F\u5DEE\u4F18\u5148\u5C40\u90E8\u91CD\u5BFC\u51FA\uFF0C\u4E0D\u590D\u7528\u5176\u5B83\u9875\u9762\u65E7\u8D44\u4EA7",
|
|
6516
6523
|
"preserve \u6A21\u5F0F SVG \u7981\u6B62\u8FFD\u52A0 ColorFilter",
|
|
6517
6524
|
"16x16 \u69FD\u4F4D\u4E0E 6x8/12x12 \u56FE\u5F62\u8981\u5206\u5F00\u5904\u7406",
|
|
6518
|
-
"Sketch Image \u56FE\u5C42\u5BFC\u51FA PNG\uFF0C\u4E0D\u8981\u4F2A\u88C5\u6210 SVG \u4F7F\u7528"
|
|
6525
|
+
"Sketch Image \u56FE\u5C42\u5BFC\u51FA PNG\uFF0C\u4E0D\u8981\u4F2A\u88C5\u6210 SVG \u4F7F\u7528\uFF0C\u5E76\u8865\u9F50 2.0x/3.0x \u53D8\u4F53",
|
|
6526
|
+
"\u79FB\u52A8\u7AEF\u7A84\u753B\u677F\u5728\u5BBD\u5C4F\u5FC5\u987B\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u5939\u6301\uFF0C\u7981\u6B62\u5168\u5C4F\u62C9\u4F38",
|
|
6527
|
+
"\u82E5\u8282\u70B9\u540C\u65F6\u51FA\u73B0 f \u4E0E vf\uFF0C\u5BB9\u5668\u5C3A\u5BF8\u548C\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4F7F\u7528 vf\uFF0C\u4E0D\u8981\u53EA\u6284\u903B\u8F91 frame",
|
|
6528
|
+
"\u82E5 compact \u8FD4\u56DE selectionContext.autoPromoted=true\uFF0C\u8BF4\u660E\u4E4B\u524D\u8BEF\u9009\u4E2D\u4E86\u5B50\u56FE\u5C42\uFF0C\u4E0D\u8981\u628A\u5185\u5C42 glyph \u5F53\u6574\u9875\u5408\u540C",
|
|
6529
|
+
"\u4EE3\u7801\u751F\u6210\u540E\u5FC5\u987B\u8C03\u7528 validate_restoration \u6821\u9A8C\u9875\u9762\u9AA8\u67B6\u3001\u8D44\u4EA7\u6765\u6E90\u548C\u771F\u5B9E\u8DEF\u7531"
|
|
6519
6530
|
],
|
|
6531
|
+
postRestoreValidator: {
|
|
6532
|
+
skill: "validate_restoration",
|
|
6533
|
+
required: true,
|
|
6534
|
+
checks: ["contract-validator", "asset-source-validator", "route-review-validator"],
|
|
6535
|
+
exampleArgs: {
|
|
6536
|
+
measurePath: "/path/to/sketch-compact-output.json",
|
|
6537
|
+
codeFilePath: "/path/to/generated_page.dart",
|
|
6538
|
+
routeFilePath: "/path/to/app_pages.dart",
|
|
6539
|
+
routeName: "AppRoutes.xxx",
|
|
6540
|
+
projectPath: "/path/to/project"
|
|
6541
|
+
}
|
|
6542
|
+
},
|
|
6520
6543
|
outputGuide: OUTPUT_GUIDE[cmd] || OUTPUT_GUIDE["measure"],
|
|
6521
6544
|
loaderScript
|
|
6522
6545
|
}, null, 2)
|
|
@@ -6524,6 +6547,460 @@ async function sketchMeasure(args) {
|
|
|
6524
6547
|
};
|
|
6525
6548
|
}
|
|
6526
6549
|
|
|
6550
|
+
// src/tools/validateRestoration.ts
|
|
6551
|
+
import * as fs20 from "fs";
|
|
6552
|
+
import * as path20 from "path";
|
|
6553
|
+
function isRecord2(value) {
|
|
6554
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6555
|
+
}
|
|
6556
|
+
function parseNestedJson(raw) {
|
|
6557
|
+
let candidate = raw.trim();
|
|
6558
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
6559
|
+
try {
|
|
6560
|
+
const parsed = JSON.parse(candidate);
|
|
6561
|
+
if (typeof parsed === "string") {
|
|
6562
|
+
candidate = parsed.trim();
|
|
6563
|
+
continue;
|
|
6564
|
+
}
|
|
6565
|
+
if (isRecord2(parsed) && Array.isArray(parsed.content) && parsed.content[0] && isRecord2(parsed.content[0])) {
|
|
6566
|
+
const text = parsed.content[0].text;
|
|
6567
|
+
if (typeof text === "string") {
|
|
6568
|
+
candidate = text.trim();
|
|
6569
|
+
continue;
|
|
6570
|
+
}
|
|
6571
|
+
}
|
|
6572
|
+
return parsed;
|
|
6573
|
+
} catch {
|
|
6574
|
+
if (candidate.startsWith("'") && candidate.endsWith("'") || candidate.startsWith('"') && candidate.endsWith('"')) {
|
|
6575
|
+
candidate = candidate.slice(1, -1);
|
|
6576
|
+
}
|
|
6577
|
+
candidate = candidate.replace(/\\n/g, "\n").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
6578
|
+
}
|
|
6579
|
+
}
|
|
6580
|
+
return JSON.parse(candidate);
|
|
6581
|
+
}
|
|
6582
|
+
function loadMeasurePayload(args) {
|
|
6583
|
+
const raw = args.measureContent || (args.measurePath ? fs20.readFileSync(args.measurePath, "utf-8") : "");
|
|
6584
|
+
if (!raw) {
|
|
6585
|
+
throw new Error("validate_restoration \u9700\u8981 measureContent \u6216 measurePath");
|
|
6586
|
+
}
|
|
6587
|
+
const parsed = parseNestedJson(raw);
|
|
6588
|
+
if (!isRecord2(parsed)) {
|
|
6589
|
+
throw new Error("measure payload \u89E3\u6790\u5931\u8D25\uFF0C\u7ED3\u679C\u4E0D\u662F\u5BF9\u8C61");
|
|
6590
|
+
}
|
|
6591
|
+
return parsed;
|
|
6592
|
+
}
|
|
6593
|
+
function hasAnyPattern(source, patterns) {
|
|
6594
|
+
return patterns.some((pattern) => pattern.test(source));
|
|
6595
|
+
}
|
|
6596
|
+
function collectAssetContracts(node, bucket = []) {
|
|
6597
|
+
if (!node) {
|
|
6598
|
+
return bucket;
|
|
6599
|
+
}
|
|
6600
|
+
if (typeof node.svgFile === "string") {
|
|
6601
|
+
bucket.push({
|
|
6602
|
+
sketchName: node.iconSketchName || node.n || node.svgFile,
|
|
6603
|
+
fileName: path20.posix.basename(node.svgFile),
|
|
6604
|
+
mode: node.svgMode,
|
|
6605
|
+
sourceType: "vector",
|
|
6606
|
+
containerSize: node.cs,
|
|
6607
|
+
contentSize: node.xs
|
|
6608
|
+
});
|
|
6609
|
+
}
|
|
6610
|
+
if (node.t === "Image") {
|
|
6611
|
+
bucket.push({
|
|
6612
|
+
sketchName: node.n || "Image",
|
|
6613
|
+
fileName: typeof node.bitmapFile === "string" ? path20.posix.basename(node.bitmapFile) : typeof node.bitmapPath === "string" ? path20.posix.basename(node.bitmapPath) : void 0,
|
|
6614
|
+
sourceType: "bitmap",
|
|
6615
|
+
scaleVariants: node.bitmapScales
|
|
6616
|
+
});
|
|
6617
|
+
}
|
|
6618
|
+
for (const child of node.ch || []) {
|
|
6619
|
+
collectAssetContracts(child, bucket);
|
|
6620
|
+
}
|
|
6621
|
+
return bucket;
|
|
6622
|
+
}
|
|
6623
|
+
function extractCodeAssets(codeContent) {
|
|
6624
|
+
const matches = codeContent.match(/assets\/[A-Za-z0-9_./-]+\.(svg|png|jpg|jpeg|webp)/g);
|
|
6625
|
+
return matches ? [...new Set(matches)] : [];
|
|
6626
|
+
}
|
|
6627
|
+
function hasCodePropertyLiteral(codeContent, property, value) {
|
|
6628
|
+
const escapedValue = String(value).replace(".", "\\.");
|
|
6629
|
+
return new RegExp(`${property}\\s*:\\s*${escapedValue}(?:\\.0+)?\\b`).test(codeContent);
|
|
6630
|
+
}
|
|
6631
|
+
function hasResponsiveSurfaceConstraint(codeContent, designWidth) {
|
|
6632
|
+
const escapedWidth = String(designWidth).replace(".", "\\.");
|
|
6633
|
+
const directPatterns = [
|
|
6634
|
+
new RegExp(`maxWidth\\s*:\\s*${escapedWidth}(?:\\.0+)?\\b`),
|
|
6635
|
+
new RegExp(`width\\s*:\\s*${escapedWidth}(?:\\.0+)?\\b`),
|
|
6636
|
+
/ConstrainedBox\s*\(/,
|
|
6637
|
+
/BoxConstraints\s*\([^)]*maxWidth\s*:/,
|
|
6638
|
+
/LayoutBuilder\s*\(/,
|
|
6639
|
+
/MediaQuery\.(sizeOf|of)\(/,
|
|
6640
|
+
/math\.(min|max)\(/,
|
|
6641
|
+
/clamp\(/
|
|
6642
|
+
];
|
|
6643
|
+
return directPatterns.some((pattern) => pattern.test(codeContent));
|
|
6644
|
+
}
|
|
6645
|
+
function hasWideStretchRisk(codeContent) {
|
|
6646
|
+
const edgePinnedPositioned = /Positioned\([\s\S]{0,220}left\s*:\s*[-\d.]+[\s\S]{0,220}right\s*:\s*[-\d.]+/.test(codeContent) || /Positioned\([\s\S]{0,220}right\s*:\s*[-\d.]+[\s\S]{0,220}left\s*:\s*[-\d.]+/.test(codeContent);
|
|
6647
|
+
return edgePinnedPositioned || /SizedBox\.expand\s*\(/.test(codeContent) || /double\.infinity/.test(codeContent);
|
|
6648
|
+
}
|
|
6649
|
+
function collectVisualFrameContracts(node, bucket = []) {
|
|
6650
|
+
if (!node) {
|
|
6651
|
+
return bucket;
|
|
6652
|
+
}
|
|
6653
|
+
if (node.f && node.vf) {
|
|
6654
|
+
const hasVisualDelta = node.f.some((value, index) => value !== node.vf[index]);
|
|
6655
|
+
if (hasVisualDelta) {
|
|
6656
|
+
bucket.push({
|
|
6657
|
+
nodeName: node.n || node.t || "unknown",
|
|
6658
|
+
frame: node.f,
|
|
6659
|
+
visualFrame: node.vf
|
|
6660
|
+
});
|
|
6661
|
+
}
|
|
6662
|
+
}
|
|
6663
|
+
for (const child of node.ch || []) {
|
|
6664
|
+
collectVisualFrameContracts(child, bucket);
|
|
6665
|
+
}
|
|
6666
|
+
return bucket;
|
|
6667
|
+
}
|
|
6668
|
+
function resolveProjectAssetPath(projectPath, assetPath) {
|
|
6669
|
+
return path20.join(projectPath, assetPath);
|
|
6670
|
+
}
|
|
6671
|
+
function getBitmapScaleVariantPaths(projectPath, assetPath) {
|
|
6672
|
+
const relativeDir = path20.posix.dirname(assetPath);
|
|
6673
|
+
const fileName = path20.posix.basename(assetPath);
|
|
6674
|
+
return [
|
|
6675
|
+
path20.join(projectPath, relativeDir, "2.0x", fileName),
|
|
6676
|
+
path20.join(projectPath, relativeDir, "3.0x", fileName)
|
|
6677
|
+
];
|
|
6678
|
+
}
|
|
6679
|
+
function extractPageClassName(codeContent) {
|
|
6680
|
+
const match = codeContent.match(/class\s+([A-Za-z0-9_]+)\s+extends\s+(StatelessWidget|StatefulWidget)/);
|
|
6681
|
+
return (match == null ? void 0 : match[1]) || null;
|
|
6682
|
+
}
|
|
6683
|
+
function buildContractValidator(payload, codeContent) {
|
|
6684
|
+
var _a, _b, _c, _d, _e;
|
|
6685
|
+
const findings = [];
|
|
6686
|
+
const blockOrder = ((_a = payload.restorationContract) == null ? void 0 : _a.blockOrder) || [];
|
|
6687
|
+
const navCopyLedger = ((_b = payload.restorationContract) == null ? void 0 : _b.navCopyLedger) || [];
|
|
6688
|
+
const pageTitle = (_c = payload.restorationContract) == null ? void 0 : _c.pageTitle;
|
|
6689
|
+
let requiredBlocks = 0;
|
|
6690
|
+
let matchedBlocks = 0;
|
|
6691
|
+
if (pageTitle) {
|
|
6692
|
+
requiredBlocks += 1;
|
|
6693
|
+
if (codeContent.includes(pageTitle)) {
|
|
6694
|
+
matchedBlocks += 1;
|
|
6695
|
+
} else {
|
|
6696
|
+
findings.push({
|
|
6697
|
+
id: "missing_page_title",
|
|
6698
|
+
severity: "error",
|
|
6699
|
+
message: `\u4EE3\u7801\u4E2D\u672A\u627E\u5230\u8BBE\u8BA1\u6807\u9898\u201C${pageTitle}\u201D`,
|
|
6700
|
+
suggestion: "\u5148\u6309 restorationContract.pageTitle \u5BF9\u9F50\u9875\u9762\u6807\u9898\uFF0C\u518D\u7EE7\u7EED\u4FEE\u5C40\u90E8\u6837\u5F0F\u3002"
|
|
6701
|
+
});
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
const needsBackButton = blockOrder.some((block) => /back/i.test(`${block.name || ""} ${block.label || ""}`));
|
|
6705
|
+
if (needsBackButton) {
|
|
6706
|
+
requiredBlocks += 1;
|
|
6707
|
+
if (hasAnyPattern(codeContent, [/Get\.back\b/, /Navigator\.pop\b/, /arrow_back/i, /back_icon\.svg/, /back_button/i])) {
|
|
6708
|
+
matchedBlocks += 1;
|
|
6709
|
+
} else {
|
|
6710
|
+
findings.push({
|
|
6711
|
+
id: "missing_back_button_block",
|
|
6712
|
+
severity: "error",
|
|
6713
|
+
message: "\u8BBE\u8BA1\u7A3F\u5B58\u5728 Back Button\uFF0C\u4F46\u4EE3\u7801\u4E2D\u672A\u68C0\u6D4B\u5230\u8FD4\u56DE\u6309\u94AE\u5B9E\u73B0\u3002",
|
|
6714
|
+
suggestion: "\u8865\u9F50\u8FD4\u56DE\u6309\u94AE\u4EA4\u4E92\u548C\u89C6\u89C9\u5B9E\u73B0\uFF0C\u4E0D\u8981\u53EA\u4FDD\u7559\u6807\u9898\u3002"
|
|
6715
|
+
});
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
const needsSupportButton = blockOrder.some((block) => /customer service|support|客服/i.test(`${block.name || ""} ${block.label || ""}`));
|
|
6719
|
+
if (needsSupportButton) {
|
|
6720
|
+
requiredBlocks += 1;
|
|
6721
|
+
if (hasAnyPattern(codeContent, [/customer[_ ]service/i, /support/i, /recipient_customer_service_button/i, /客服/])) {
|
|
6722
|
+
matchedBlocks += 1;
|
|
6723
|
+
} else {
|
|
6724
|
+
findings.push({
|
|
6725
|
+
id: "missing_customer_service_block",
|
|
6726
|
+
severity: "error",
|
|
6727
|
+
message: "\u8BBE\u8BA1\u7A3F\u5B58\u5728 Customer Service Button\uFF0C\u4F46\u4EE3\u7801\u4E2D\u672A\u68C0\u6D4B\u5230\u5BF9\u5E94\u5165\u53E3\u3002",
|
|
6728
|
+
suggestion: "\u8865\u9F50\u5BA2\u670D\u6309\u94AE\uFF0C\u4E0D\u8981\u5728\u751F\u6210\u9636\u6BB5\u76F4\u63A5\u7701\u7565\u53F3\u4E0A\u89D2\u5165\u53E3\u3002"
|
|
6729
|
+
});
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
const optionLabels = ["\u652F\u4ED8\u5B9D", "\u5FAE\u4FE1", "\u94F6\u884C\u5361"].filter((label) => navCopyLedger.includes(label));
|
|
6733
|
+
if (optionLabels.length > 0) {
|
|
6734
|
+
requiredBlocks += 1;
|
|
6735
|
+
const missingOptions = optionLabels.filter((label) => !codeContent.includes(label));
|
|
6736
|
+
if (missingOptions.length === 0) {
|
|
6737
|
+
matchedBlocks += 1;
|
|
6738
|
+
} else {
|
|
6739
|
+
findings.push({
|
|
6740
|
+
id: "missing_option_labels",
|
|
6741
|
+
severity: "error",
|
|
6742
|
+
message: `\u4EE3\u7801\u4E2D\u7F3A\u5C11\u8BBE\u8BA1\u7A3F\u9009\u9879\u6587\u6848: ${missingOptions.join(" / ")}`,
|
|
6743
|
+
suggestion: "\u9009\u9879\u5361\u6587\u6848\u9ED8\u8BA4\u4EE5 navCopyLedger \u4E3A\u771F\u503C\uFF0C\u7981\u6B62\u81EA\u884C\u6539\u5199\u6216\u9057\u6F0F\u3002"
|
|
6744
|
+
});
|
|
6745
|
+
}
|
|
6746
|
+
}
|
|
6747
|
+
const needsStatusBar = navCopyLedger.includes("9:41") || hasAnyPattern(JSON.stringify(payload.tree || {}), [/"Signal"/, /"WiFi"/, /"Battery"/]);
|
|
6748
|
+
if (needsStatusBar) {
|
|
6749
|
+
requiredBlocks += 1;
|
|
6750
|
+
if (hasAnyPattern(codeContent, [/9:41/, /Signal/, /WiFi/, /Battery/, /statusBar/i])) {
|
|
6751
|
+
matchedBlocks += 1;
|
|
6752
|
+
} else {
|
|
6753
|
+
findings.push({
|
|
6754
|
+
id: "missing_status_bar_block",
|
|
6755
|
+
severity: "warning",
|
|
6756
|
+
message: "\u8BBE\u8BA1\u7A3F\u9876\u90E8\u72B6\u6001\u680F\u5757\u672A\u843D\u5730\uFF0C\u5F53\u524D\u9875\u9762\u9AA8\u67B6\u4ECD\u7136\u4E0D\u5B8C\u6574\u3002",
|
|
6757
|
+
suggestion: "\u5982\u679C\u76EE\u6807\u662F 1:1 \u8FD8\u539F\uFF0C\u9700\u628A 9:41 / Signal / WiFi / Battery \u8FD9\u7EC4\u9876\u90E8\u5757\u8865\u56DE\u3002"
|
|
6758
|
+
});
|
|
6759
|
+
}
|
|
6760
|
+
}
|
|
6761
|
+
const designWidth = ((_d = payload.designSurface) == null ? void 0 : _d.maxWidth) || ((_e = payload.artboard) == null ? void 0 : _e.w);
|
|
6762
|
+
if (designWidth && designWidth <= 430) {
|
|
6763
|
+
const isClamped = hasResponsiveSurfaceConstraint(codeContent, designWidth);
|
|
6764
|
+
if (hasWideStretchRisk(codeContent) && !isClamped) {
|
|
6765
|
+
findings.push({
|
|
6766
|
+
id: "design_surface_constraint_missing",
|
|
6767
|
+
severity: "error",
|
|
6768
|
+
message: `\u5F53\u524D\u8BBE\u8BA1\u7A3F\u4E3A ${designWidth} \u5BBD\u79FB\u52A8\u7AEF\u753B\u677F\uFF0C\u4F46\u4EE3\u7801\u672A\u68C0\u6D4B\u5230\u5BBD\u5C4F\u5939\u6301\u7EA6\u675F\uFF0C\u5BBD\u7A97\u53E3\u4E0B\u4F1A\u88AB\u76F4\u63A5\u62C9\u4F38\u3002`,
|
|
6769
|
+
suggestion: "\u5916\u5C42\u5148\u7528 Center + ConstrainedBox(maxWidth: designSurface.maxWidth) \u6216\u7B49\u6548\u7EA6\u675F\uFF0C\u518D\u5728\u7EA6\u675F\u5185\u4F7F\u7528 Positioned/Stack\u3002"
|
|
6770
|
+
});
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6773
|
+
const visualFrameContracts = collectVisualFrameContracts(payload.tree);
|
|
6774
|
+
for (const contract of visualFrameContracts) {
|
|
6775
|
+
const [, , frameWidth, frameHeight] = contract.frame;
|
|
6776
|
+
const [, , visualWidth, visualHeight] = contract.visualFrame;
|
|
6777
|
+
const widthMismatch = frameWidth !== visualWidth && hasCodePropertyLiteral(codeContent, "width", frameWidth) && !hasCodePropertyLiteral(codeContent, "width", visualWidth);
|
|
6778
|
+
const heightMismatch = frameHeight !== visualHeight && hasCodePropertyLiteral(codeContent, "height", frameHeight) && !hasCodePropertyLiteral(codeContent, "height", visualHeight);
|
|
6779
|
+
if (widthMismatch || heightMismatch) {
|
|
6780
|
+
findings.push({
|
|
6781
|
+
id: "visual_frame_literal_mismatch",
|
|
6782
|
+
severity: "warning",
|
|
6783
|
+
message: `${contract.nodeName} \u7684\u89C6\u89C9\u8FB9\u754C\u662F ${visualWidth}x${visualHeight}\uFF0C\u4F46\u4EE3\u7801\u770B\u8D77\u6765\u4ECD\u5728\u4F7F\u7528\u903B\u8F91 frame ${frameWidth}x${frameHeight}\uFF0C\u5BB9\u6613\u9020\u6210\u5E95\u8FB9\u8DDD\u6216\u9634\u5F71\u89C6\u89C9\u8BEF\u5DEE\u3002`,
|
|
6784
|
+
evidence: [`${contract.nodeName}: frame=${contract.frame.join(",")} visualFrame=${contract.visualFrame.join(",")}`],
|
|
6785
|
+
suggestion: "\u5F53 compact \u540C\u65F6\u7ED9\u51FA f \u4E0E vf \u65F6\uFF0C\u5916\u5C42\u5BB9\u5668\u5C3A\u5BF8\u548C\u7531\u6B64\u63A8\u5BFC\u7684\u5E95\u90E8\u89C6\u89C9\u95F4\u8DDD\u4F18\u5148\u4EE5 vf \u4E3A\u51C6\u3002"
|
|
6786
|
+
});
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6789
|
+
return {
|
|
6790
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6791
|
+
requiredBlocks,
|
|
6792
|
+
matchedBlocks,
|
|
6793
|
+
findings
|
|
6794
|
+
};
|
|
6795
|
+
}
|
|
6796
|
+
function buildAssetValidator(payload, codeContent, args) {
|
|
6797
|
+
const findings = [];
|
|
6798
|
+
const assetContracts = collectAssetContracts(payload.tree);
|
|
6799
|
+
const expectedVectorFiles = new Set(
|
|
6800
|
+
assetContracts.filter((item) => item.sourceType === "vector" && item.fileName).map((item) => item.fileName.toLowerCase())
|
|
6801
|
+
);
|
|
6802
|
+
const expectedBitmapCount = assetContracts.filter((item) => item.sourceType === "bitmap").length;
|
|
6803
|
+
const codeAssets = extractCodeAssets(codeContent);
|
|
6804
|
+
const codeVectorAssets = codeAssets.filter((asset) => asset.endsWith(".svg"));
|
|
6805
|
+
const codeBitmapAssets = codeAssets.filter((asset) => /\.(png|jpg|jpeg|webp)$/.test(asset));
|
|
6806
|
+
const unexpectedVectorAssets = codeVectorAssets.filter((asset) => !expectedVectorFiles.has(path20.posix.basename(asset).toLowerCase()));
|
|
6807
|
+
if (unexpectedVectorAssets.length > 0) {
|
|
6808
|
+
findings.push({
|
|
6809
|
+
id: "unexpected_vector_assets",
|
|
6810
|
+
severity: "error",
|
|
6811
|
+
message: "\u4EE3\u7801\u4E2D\u5B58\u5728\u672A\u5728\u5F53\u524D\u8BBE\u8BA1\u7A3F contract \u4E2D\u51FA\u73B0\u7684 SVG \u8D44\u6E90\uFF0C\u7591\u4F3C\u590D\u7528\u4E86\u65E7\u9875\u9762\u8D44\u4EA7\u3002",
|
|
6812
|
+
evidence: unexpectedVectorAssets,
|
|
6813
|
+
suggestion: "\u5BF9\u8FD9\u4E9B\u56FE\u6807\u91CD\u65B0\u4ECE\u5F53\u524D\u753B\u677F\u5C40\u90E8\u5BFC\u51FA\uFF0C\u6216\u5728 validate_restoration \u901A\u8FC7\u524D\u4E0D\u8981\u7EE7\u7EED\u63D0\u4EA4\u9875\u9762\u3002"
|
|
6814
|
+
});
|
|
6815
|
+
}
|
|
6816
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length === 0) {
|
|
6817
|
+
findings.push({
|
|
6818
|
+
id: "missing_bitmap_assets",
|
|
6819
|
+
severity: "warning",
|
|
6820
|
+
message: `\u5F53\u524D\u8BBE\u8BA1\u7A3F\u5305\u542B ${expectedBitmapCount} \u4E2A Image \u56FE\u5C42\uFF0C\u4F46\u4EE3\u7801\u91CC\u6CA1\u6709\u4EFB\u4F55\u4F4D\u56FE\u8D44\u6E90\u5F15\u7528\u3002`,
|
|
6821
|
+
suggestion: "\u68C0\u67E5\u662F\u5426\u628A Sketch Image \u56FE\u5C42\u9519\u8BEF\u5F53\u6210 SVG \u6216\u4EE3\u7801\u7ED8\u5236\u4E86\u3002"
|
|
6822
|
+
});
|
|
6823
|
+
}
|
|
6824
|
+
if (codeBitmapAssets.length > 0) {
|
|
6825
|
+
findings.push({
|
|
6826
|
+
id: "bitmap_asset_source_check_required",
|
|
6827
|
+
severity: "info",
|
|
6828
|
+
message: "\u4EE3\u7801\u4E2D\u5B58\u5728\u4F4D\u56FE\u8D44\u6E90\uFF0C\u9700\u4EBA\u5DE5\u786E\u8BA4\u5B83\u4EEC\u6765\u81EA\u5F53\u524D\u753B\u677F\u800C\u4E0D\u662F\u65E7\u9875\u9762\u7F13\u5B58\u8D44\u6E90\u3002",
|
|
6829
|
+
evidence: codeBitmapAssets,
|
|
6830
|
+
suggestion: "\u4F4D\u56FE\u8D44\u6E90\u4F18\u5148\u6309\u5F53\u524D\u753B\u677F\u76F4\u63A5\u5BFC\u51FA\u5230 assets/icons/\uFF0C\u907F\u514D\u7EE7\u7EED\u590D\u7528\u65E7\u9875\u9762 PNG\u3002"
|
|
6831
|
+
});
|
|
6832
|
+
}
|
|
6833
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length > 0) {
|
|
6834
|
+
const pageClassName = extractPageClassName(codeContent) || "";
|
|
6835
|
+
const normalizedStem = pageClassName.replace(/Page$/, "").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
6836
|
+
if (normalizedStem) {
|
|
6837
|
+
const hasPageLocalBitmap = codeBitmapAssets.some(
|
|
6838
|
+
(asset) => path20.posix.basename(asset).toLowerCase().includes(normalizedStem)
|
|
6839
|
+
);
|
|
6840
|
+
if (!hasPageLocalBitmap) {
|
|
6841
|
+
findings.push({
|
|
6842
|
+
id: "bitmap_assets_not_page_local",
|
|
6843
|
+
severity: "warning",
|
|
6844
|
+
message: "\u5F53\u524D\u9875\u9762\u4F4D\u56FE\u8D44\u6E90\u770B\u8D77\u6765\u4E0D\u662F page-local \u547D\u540D\uFF0C\u5B58\u5728\u7EE7\u7EED\u590D\u7528\u65E7\u9875\u9762 PNG \u7684\u98CE\u9669\u3002",
|
|
6845
|
+
evidence: codeBitmapAssets,
|
|
6846
|
+
suggestion: "\u4F4D\u56FE\u8D44\u6E90\u4F18\u5148\u6309\u5F53\u524D\u9875\u9762\u547D\u540D\u5BFC\u51FA\uFF0C\u4F8B\u5982\u5E26\u4E0A\u9875\u9762 stem\uFF0C\u907F\u514D\u6DF7\u5165\u65E7\u9875\u9762\u901A\u7528 PNG\u3002"
|
|
6847
|
+
});
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
const expectedBitmapScales = new Set(
|
|
6852
|
+
assetContracts.filter((item) => item.sourceType === "bitmap").flatMap((item) => item.scaleVariants || [])
|
|
6853
|
+
);
|
|
6854
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length > 0 && args.projectPath) {
|
|
6855
|
+
const requiresRetinaVariants = expectedBitmapScales.size === 0 || expectedBitmapScales.has("2.0x") || expectedBitmapScales.has("3.0x");
|
|
6856
|
+
if (requiresRetinaVariants) {
|
|
6857
|
+
const missingRetinaEvidence = [];
|
|
6858
|
+
for (const asset of codeBitmapAssets) {
|
|
6859
|
+
const assetOnDisk = resolveProjectAssetPath(args.projectPath, asset);
|
|
6860
|
+
if (!fs20.existsSync(assetOnDisk)) {
|
|
6861
|
+
missingRetinaEvidence.push(`${asset} (base missing)`);
|
|
6862
|
+
continue;
|
|
6863
|
+
}
|
|
6864
|
+
const variantPaths = getBitmapScaleVariantPaths(args.projectPath, asset);
|
|
6865
|
+
const missingVariants = variantPaths.filter((variantPath) => !fs20.existsSync(variantPath)).map((variantPath) => path20.relative(args.projectPath, variantPath));
|
|
6866
|
+
if (missingVariants.length > 0) {
|
|
6867
|
+
missingRetinaEvidence.push(`${asset} -> missing ${missingVariants.join(", ")}`);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
if (missingRetinaEvidence.length > 0) {
|
|
6871
|
+
findings.push({
|
|
6872
|
+
id: "bitmap_retina_variants_missing",
|
|
6873
|
+
severity: "error",
|
|
6874
|
+
message: "\u4F4D\u56FE\u8D44\u6E90\u7F3A\u5C11 2.0x/3.0x \u53D8\u4F53\uFF0C\u9AD8\u5206\u5C4F\u4E0B\u5BB9\u6613\u53D1\u7CCA\u3002",
|
|
6875
|
+
evidence: missingRetinaEvidence,
|
|
6876
|
+
suggestion: "\u6309\u5F53\u524D\u753B\u677F\u91CD\u65B0\u5BFC\u51FA PNG\uFF0C\u5E76\u8865\u9F50 assets/.../2.0x \u4E0E 3.0x \u53D8\u4F53\u540E\u518D\u9A8C\u6536\u3002"
|
|
6877
|
+
});
|
|
6878
|
+
}
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
const preserveContracts = assetContracts.filter((item) => item.mode === "preserve");
|
|
6882
|
+
if (preserveContracts.length > 0 && /colorFilter\s*:|ColorFilter\./.test(codeContent)) {
|
|
6883
|
+
findings.push({
|
|
6884
|
+
id: "preserve_svg_tint_risk",
|
|
6885
|
+
severity: "warning",
|
|
6886
|
+
message: "\u5F53\u524D\u9875\u9762\u4EE3\u7801\u5305\u542B ColorFilter\uFF0C\u800C contract \u4E2D\u5B58\u5728 preserve \u6A21\u5F0F SVG\uFF0C\u5B58\u5728\u518D\u6B21\u67D3\u8272\u98CE\u9669\u3002",
|
|
6887
|
+
evidence: preserveContracts.map((item) => item.fileName || item.sketchName),
|
|
6888
|
+
suggestion: "\u68C0\u67E5 preserve SVG \u662F\u5426\u88AB\u6574\u4F53 tint\uFF0C\u5FC5\u8981\u65F6\u628A\u56FE\u6807\u6539\u4E3A\u4FDD\u7559\u539F\u8272\u8D44\u6E90\u3002"
|
|
6889
|
+
});
|
|
6890
|
+
}
|
|
6891
|
+
return {
|
|
6892
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6893
|
+
expectedAssetContracts: assetContracts,
|
|
6894
|
+
codeAssets,
|
|
6895
|
+
findings
|
|
6896
|
+
};
|
|
6897
|
+
}
|
|
6898
|
+
function buildRouteReviewValidator(args, codeContent) {
|
|
6899
|
+
const findings = [];
|
|
6900
|
+
const pageClassName = extractPageClassName(codeContent);
|
|
6901
|
+
let routeConnected = null;
|
|
6902
|
+
let routeTarget = null;
|
|
6903
|
+
let reviewHarnessReady = null;
|
|
6904
|
+
if (args.routeFilePath && args.routeName) {
|
|
6905
|
+
const routeContent = fs20.readFileSync(args.routeFilePath, "utf-8");
|
|
6906
|
+
const routeIndex = routeContent.indexOf(`name: ${args.routeName}`);
|
|
6907
|
+
if (routeIndex === -1) {
|
|
6908
|
+
findings.push({
|
|
6909
|
+
id: "route_not_found",
|
|
6910
|
+
severity: "error",
|
|
6911
|
+
message: `\u5728\u8DEF\u7531\u6587\u4EF6\u4E2D\u672A\u627E\u5230 ${args.routeName} \u7684\u5B9A\u4E49\u3002`,
|
|
6912
|
+
suggestion: "\u751F\u6210\u9875\u9762\u540E\u5FC5\u987B\u786E\u8BA4\u771F\u5B9E\u8DEF\u7531\u5DF2\u7ECF\u63A5\u901A\uFF0C\u4E0D\u80FD\u505C\u7559\u5728\u5B64\u7ACB\u9875\u9762\u6587\u4EF6\u3002"
|
|
6913
|
+
});
|
|
6914
|
+
} else {
|
|
6915
|
+
const routeChunk = routeContent.slice(routeIndex, routeIndex + 240);
|
|
6916
|
+
routeConnected = true;
|
|
6917
|
+
if (/_ComingSoonPage/.test(routeChunk)) {
|
|
6918
|
+
routeConnected = false;
|
|
6919
|
+
findings.push({
|
|
6920
|
+
id: "route_points_to_placeholder",
|
|
6921
|
+
severity: "error",
|
|
6922
|
+
message: `${args.routeName} \u5F53\u524D\u4ECD\u7136\u6307\u5411 _ComingSoonPage\uFF0C\u5360\u4F4D\u9875\u672A\u66FF\u6362\u3002`,
|
|
6923
|
+
suggestion: "\u628A page factory \u63A5\u5230\u771F\u5B9E\u9875\u9762\u7C7B\uFF0C\u800C\u4E0D\u662F\u4FDD\u7559\u5360\u4F4D\u5B9E\u73B0\u3002"
|
|
6924
|
+
});
|
|
6925
|
+
}
|
|
6926
|
+
const routeTargetMatch = routeChunk.match(/page:\s*\(\)\s*=>\s*const\s+([A-Za-z0-9_]+)/) || routeChunk.match(/page:\s*\(\)\s*=>\s*([A-Za-z0-9_]+)\(/);
|
|
6927
|
+
routeTarget = (routeTargetMatch == null ? void 0 : routeTargetMatch[1]) || null;
|
|
6928
|
+
if (pageClassName && routeTarget && pageClassName !== routeTarget) {
|
|
6929
|
+
findings.push({
|
|
6930
|
+
id: "route_target_mismatch",
|
|
6931
|
+
severity: "warning",
|
|
6932
|
+
message: `\u8DEF\u7531\u76EE\u6807\u7C7B ${routeTarget} \u4E0E\u9875\u9762\u4E3B\u7C7B ${pageClassName} \u4E0D\u4E00\u81F4\u3002`,
|
|
6933
|
+
suggestion: "\u786E\u8BA4\u8DEF\u7531\u63A5\u7684\u5C31\u662F\u5F53\u524D\u751F\u6210\u9875\u9762\uFF0C\u800C\u4E0D\u662F\u540C\u540D\u65E7\u9875\u9762\u3002"
|
|
6934
|
+
});
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
if (args.projectPath) {
|
|
6939
|
+
const reviewHarnessPath = path20.join(args.projectPath, "test/visual_regression/ui_review_golden_test.dart");
|
|
6940
|
+
reviewHarnessReady = fs20.existsSync(reviewHarnessPath);
|
|
6941
|
+
if (!reviewHarnessReady) {
|
|
6942
|
+
findings.push({
|
|
6943
|
+
id: "ui_review_harness_missing",
|
|
6944
|
+
severity: "warning",
|
|
6945
|
+
message: "\u9879\u76EE\u5185\u672A\u68C0\u6D4B\u5230 UI review golden harness\uFF0C\u751F\u6210\u540E\u65E0\u6CD5\u7ACB\u5373\u505A\u7ED3\u6784\u7EA7\u56DE\u5F52\u3002",
|
|
6946
|
+
suggestion: "\u81F3\u5C11\u8865\u4E0A test/visual_regression/ui_review_golden_test.dart\uFF0C\u518D\u8BA9\u8FD8\u539F\u9875\u8FDB\u5165\u81EA\u52A8 review\u3002"
|
|
6947
|
+
});
|
|
6948
|
+
} else {
|
|
6949
|
+
const reviewContent = fs20.readFileSync(reviewHarnessPath, "utf-8");
|
|
6950
|
+
const pageStem = path20.basename(args.codeFilePath || "", path20.extname(args.codeFilePath || "")).replace(/_page$/, "");
|
|
6951
|
+
if (pageStem && !reviewContent.includes(pageStem)) {
|
|
6952
|
+
findings.push({
|
|
6953
|
+
id: "ui_review_scenario_not_registered",
|
|
6954
|
+
severity: "warning",
|
|
6955
|
+
message: "UI review harness \u5DF2\u5B58\u5728\uFF0C\u4F46\u5F53\u524D\u9875\u9762\u8FD8\u6CA1\u6709\u4E13\u5C5E\u573A\u666F\u6CE8\u518C\u3002",
|
|
6956
|
+
evidence: [reviewHarnessPath],
|
|
6957
|
+
suggestion: "\u628A\u5F53\u524D\u9875\u9762\u52A0\u5165 visual regression \u573A\u666F\uFF0C\u907F\u514D\u53EA\u9760\u8089\u773C\u56DE\u5F52\u3002"
|
|
6958
|
+
});
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
const recommendedNextSteps = [
|
|
6963
|
+
"\u5148\u4FEE\u6B63\u6240\u6709 error \u7EA7\u522B\u95EE\u9898\uFF0C\u518D\u5904\u7406 warning",
|
|
6964
|
+
"\u4FEE\u6B63\u8D44\u6E90\u6765\u6E90\u540E\u91CD\u65B0\u8FD0\u884C validate_restoration\uFF0C\u76F4\u5230 unexpected vector assets \u6E05\u96F6"
|
|
6965
|
+
];
|
|
6966
|
+
if (args.routeFilePath && args.routeName) {
|
|
6967
|
+
recommendedNextSteps.push(`\u786E\u8BA4 ${args.routeName} \u4E0D\u518D\u6307\u5411 _ComingSoonPage`);
|
|
6968
|
+
}
|
|
6969
|
+
if (args.projectPath) {
|
|
6970
|
+
recommendedNextSteps.push("\u5C06\u9875\u9762\u6CE8\u518C\u5230 visual regression \u573A\u666F\u540E\u518D\u8FDB\u884C UI review");
|
|
6971
|
+
}
|
|
6972
|
+
return {
|
|
6973
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6974
|
+
routeConnected,
|
|
6975
|
+
routeTarget,
|
|
6976
|
+
reviewHarnessReady,
|
|
6977
|
+
findings,
|
|
6978
|
+
recommendedNextSteps
|
|
6979
|
+
};
|
|
6980
|
+
}
|
|
6981
|
+
async function validateRestoration(args) {
|
|
6982
|
+
var _a;
|
|
6983
|
+
if (!args.codeFilePath) {
|
|
6984
|
+
throw new Error("validate_restoration \u9700\u8981 codeFilePath \u53C2\u6570");
|
|
6985
|
+
}
|
|
6986
|
+
if (!fs20.existsSync(args.codeFilePath)) {
|
|
6987
|
+
throw new Error(`\u4EE3\u7801\u6587\u4EF6\u4E0D\u5B58\u5728: ${args.codeFilePath}`);
|
|
6988
|
+
}
|
|
6989
|
+
const payload = loadMeasurePayload(args);
|
|
6990
|
+
const codeContent = fs20.readFileSync(args.codeFilePath, "utf-8");
|
|
6991
|
+
const contractValidator = buildContractValidator(payload, codeContent);
|
|
6992
|
+
const assetValidator = buildAssetValidator(payload, codeContent, args);
|
|
6993
|
+
const routeReviewValidator = buildRouteReviewValidator(args, codeContent);
|
|
6994
|
+
return {
|
|
6995
|
+
artboardName: (_a = payload.artboard) == null ? void 0 : _a.name,
|
|
6996
|
+
ok: contractValidator.passed && assetValidator.passed && routeReviewValidator.passed,
|
|
6997
|
+
codeFilePath: args.codeFilePath,
|
|
6998
|
+
contractValidator,
|
|
6999
|
+
assetValidator,
|
|
7000
|
+
routeReviewValidator
|
|
7001
|
+
};
|
|
7002
|
+
}
|
|
7003
|
+
|
|
6527
7004
|
// src/tools/skillDefinitions.ts
|
|
6528
7005
|
function wrapAsContent(data) {
|
|
6529
7006
|
return {
|
|
@@ -6874,6 +7351,29 @@ var skillDefinitions = [
|
|
|
6874
7351
|
outputPath: params.outputPath
|
|
6875
7352
|
});
|
|
6876
7353
|
}
|
|
7354
|
+
},
|
|
7355
|
+
{
|
|
7356
|
+
name: "validate_restoration",
|
|
7357
|
+
category: "sketch",
|
|
7358
|
+
description: "\u6821\u9A8C\u8BBE\u8BA1\u8FD8\u539F\u7ED3\u679C\u3002\u5BF9\u7167 sketch_measure \u7684 restorationContract \u68C0\u67E5\u9875\u9762\u9AA8\u67B6\u3001\u8D44\u6E90\u6765\u6E90\u3001\u771F\u5B9E\u8DEF\u7531\u662F\u5426\u63A5\u901A\uFF0C\u4EE5\u53CA UI review \u573A\u666F\u662F\u5426\u51C6\u5907\u5B8C\u6210",
|
|
7359
|
+
paramHints: [
|
|
7360
|
+
{ name: "measurePath", type: "string", description: "sketch_measure \u6267\u884C\u7ED3\u679C\u6587\u4EF6\u8DEF\u5F84\uFF0C\u6216\u4FDD\u5B58\u540E\u7684 compact JSON \u8DEF\u5F84" },
|
|
7361
|
+
{ name: "measureContent", type: "string", description: "\u76F4\u63A5\u4F20\u5165 sketch_measure \u7684 JSON \u6587\u672C\uFF08measurePath \u4E0E measureContent \u4E8C\u9009\u4E00\uFF09" },
|
|
7362
|
+
{ name: "codeFilePath", type: "string", required: true, description: "\u751F\u6210\u540E\u7684\u9875\u9762\u4EE3\u7801\u6587\u4EF6\u8DEF\u5F84" },
|
|
7363
|
+
{ name: "routeFilePath", type: "string", description: "\u8DEF\u7531\u6587\u4EF6\u8DEF\u5F84\uFF08\u7528\u4E8E\u68C0\u67E5\u662F\u5426\u4ECD\u6307\u5411\u5360\u4F4D\u9875\uFF09" },
|
|
7364
|
+
{ name: "routeName", type: "string", description: "\u8DEF\u7531\u540D\uFF0C\u5982 AppRoutes.recipientAdd" },
|
|
7365
|
+
{ name: "projectPath", type: "string", description: "\u9879\u76EE\u6839\u8DEF\u5F84\uFF08\u7528\u4E8E\u68C0\u67E5 visual review harness\uFF09" }
|
|
7366
|
+
],
|
|
7367
|
+
handler: async (params) => {
|
|
7368
|
+
return wrapAsContent(await validateRestoration({
|
|
7369
|
+
measurePath: params.measurePath,
|
|
7370
|
+
measureContent: params.measureContent,
|
|
7371
|
+
codeFilePath: params.codeFilePath,
|
|
7372
|
+
routeFilePath: params.routeFilePath,
|
|
7373
|
+
routeName: params.routeName,
|
|
7374
|
+
projectPath: params.projectPath
|
|
7375
|
+
}));
|
|
7376
|
+
}
|
|
6877
7377
|
}
|
|
6878
7378
|
];
|
|
6879
7379
|
|