mta-mcp 3.15.1 → 3.15.2
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 +361 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6515,8 +6515,21 @@ async function sketchMeasure(args) {
|
|
|
6515
6515
|
"\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
6516
|
"preserve \u6A21\u5F0F SVG \u7981\u6B62\u8FFD\u52A0 ColorFilter",
|
|
6517
6517
|
"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"
|
|
6518
|
+
"Sketch Image \u56FE\u5C42\u5BFC\u51FA PNG\uFF0C\u4E0D\u8981\u4F2A\u88C5\u6210 SVG \u4F7F\u7528",
|
|
6519
|
+
"\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
6520
|
],
|
|
6521
|
+
postRestoreValidator: {
|
|
6522
|
+
skill: "validate_restoration",
|
|
6523
|
+
required: true,
|
|
6524
|
+
checks: ["contract-validator", "asset-source-validator", "route-review-validator"],
|
|
6525
|
+
exampleArgs: {
|
|
6526
|
+
measurePath: "/path/to/sketch-compact-output.json",
|
|
6527
|
+
codeFilePath: "/path/to/generated_page.dart",
|
|
6528
|
+
routeFilePath: "/path/to/app_pages.dart",
|
|
6529
|
+
routeName: "AppRoutes.xxx",
|
|
6530
|
+
projectPath: "/path/to/project"
|
|
6531
|
+
}
|
|
6532
|
+
},
|
|
6520
6533
|
outputGuide: OUTPUT_GUIDE[cmd] || OUTPUT_GUIDE["measure"],
|
|
6521
6534
|
loaderScript
|
|
6522
6535
|
}, null, 2)
|
|
@@ -6524,6 +6537,330 @@ async function sketchMeasure(args) {
|
|
|
6524
6537
|
};
|
|
6525
6538
|
}
|
|
6526
6539
|
|
|
6540
|
+
// src/tools/validateRestoration.ts
|
|
6541
|
+
import * as fs20 from "fs";
|
|
6542
|
+
import * as path20 from "path";
|
|
6543
|
+
function isRecord2(value) {
|
|
6544
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6545
|
+
}
|
|
6546
|
+
function parseNestedJson(raw) {
|
|
6547
|
+
let candidate = raw.trim();
|
|
6548
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
6549
|
+
try {
|
|
6550
|
+
const parsed = JSON.parse(candidate);
|
|
6551
|
+
if (typeof parsed === "string") {
|
|
6552
|
+
candidate = parsed.trim();
|
|
6553
|
+
continue;
|
|
6554
|
+
}
|
|
6555
|
+
if (isRecord2(parsed) && Array.isArray(parsed.content) && parsed.content[0] && isRecord2(parsed.content[0])) {
|
|
6556
|
+
const text = parsed.content[0].text;
|
|
6557
|
+
if (typeof text === "string") {
|
|
6558
|
+
candidate = text.trim();
|
|
6559
|
+
continue;
|
|
6560
|
+
}
|
|
6561
|
+
}
|
|
6562
|
+
return parsed;
|
|
6563
|
+
} catch {
|
|
6564
|
+
if (candidate.startsWith("'") && candidate.endsWith("'") || candidate.startsWith('"') && candidate.endsWith('"')) {
|
|
6565
|
+
candidate = candidate.slice(1, -1);
|
|
6566
|
+
}
|
|
6567
|
+
candidate = candidate.replace(/\\n/g, "\n").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
6568
|
+
}
|
|
6569
|
+
}
|
|
6570
|
+
return JSON.parse(candidate);
|
|
6571
|
+
}
|
|
6572
|
+
function loadMeasurePayload(args) {
|
|
6573
|
+
const raw = args.measureContent || (args.measurePath ? fs20.readFileSync(args.measurePath, "utf-8") : "");
|
|
6574
|
+
if (!raw) {
|
|
6575
|
+
throw new Error("validate_restoration \u9700\u8981 measureContent \u6216 measurePath");
|
|
6576
|
+
}
|
|
6577
|
+
const parsed = parseNestedJson(raw);
|
|
6578
|
+
if (!isRecord2(parsed)) {
|
|
6579
|
+
throw new Error("measure payload \u89E3\u6790\u5931\u8D25\uFF0C\u7ED3\u679C\u4E0D\u662F\u5BF9\u8C61");
|
|
6580
|
+
}
|
|
6581
|
+
return parsed;
|
|
6582
|
+
}
|
|
6583
|
+
function hasAnyPattern(source, patterns) {
|
|
6584
|
+
return patterns.some((pattern) => pattern.test(source));
|
|
6585
|
+
}
|
|
6586
|
+
function collectAssetContracts(node, bucket = []) {
|
|
6587
|
+
if (!node) {
|
|
6588
|
+
return bucket;
|
|
6589
|
+
}
|
|
6590
|
+
if (typeof node.svgFile === "string") {
|
|
6591
|
+
bucket.push({
|
|
6592
|
+
sketchName: node.iconSketchName || node.n || node.svgFile,
|
|
6593
|
+
fileName: path20.posix.basename(node.svgFile),
|
|
6594
|
+
mode: node.svgMode,
|
|
6595
|
+
sourceType: "vector",
|
|
6596
|
+
containerSize: node.cs,
|
|
6597
|
+
contentSize: node.xs
|
|
6598
|
+
});
|
|
6599
|
+
}
|
|
6600
|
+
if (node.t === "Image") {
|
|
6601
|
+
bucket.push({
|
|
6602
|
+
sketchName: node.n || "Image",
|
|
6603
|
+
sourceType: "bitmap"
|
|
6604
|
+
});
|
|
6605
|
+
}
|
|
6606
|
+
for (const child of node.ch || []) {
|
|
6607
|
+
collectAssetContracts(child, bucket);
|
|
6608
|
+
}
|
|
6609
|
+
return bucket;
|
|
6610
|
+
}
|
|
6611
|
+
function extractCodeAssets(codeContent) {
|
|
6612
|
+
const matches = codeContent.match(/assets\/[A-Za-z0-9_./-]+\.(svg|png|jpg|jpeg|webp)/g);
|
|
6613
|
+
return matches ? [...new Set(matches)] : [];
|
|
6614
|
+
}
|
|
6615
|
+
function extractPageClassName(codeContent) {
|
|
6616
|
+
const match = codeContent.match(/class\s+([A-Za-z0-9_]+)\s+extends\s+(StatelessWidget|StatefulWidget)/);
|
|
6617
|
+
return (match == null ? void 0 : match[1]) || null;
|
|
6618
|
+
}
|
|
6619
|
+
function buildContractValidator(payload, codeContent) {
|
|
6620
|
+
var _a, _b, _c;
|
|
6621
|
+
const findings = [];
|
|
6622
|
+
const blockOrder = ((_a = payload.restorationContract) == null ? void 0 : _a.blockOrder) || [];
|
|
6623
|
+
const navCopyLedger = ((_b = payload.restorationContract) == null ? void 0 : _b.navCopyLedger) || [];
|
|
6624
|
+
const pageTitle = (_c = payload.restorationContract) == null ? void 0 : _c.pageTitle;
|
|
6625
|
+
let requiredBlocks = 0;
|
|
6626
|
+
let matchedBlocks = 0;
|
|
6627
|
+
if (pageTitle) {
|
|
6628
|
+
requiredBlocks += 1;
|
|
6629
|
+
if (codeContent.includes(pageTitle)) {
|
|
6630
|
+
matchedBlocks += 1;
|
|
6631
|
+
} else {
|
|
6632
|
+
findings.push({
|
|
6633
|
+
id: "missing_page_title",
|
|
6634
|
+
severity: "error",
|
|
6635
|
+
message: `\u4EE3\u7801\u4E2D\u672A\u627E\u5230\u8BBE\u8BA1\u6807\u9898\u201C${pageTitle}\u201D`,
|
|
6636
|
+
suggestion: "\u5148\u6309 restorationContract.pageTitle \u5BF9\u9F50\u9875\u9762\u6807\u9898\uFF0C\u518D\u7EE7\u7EED\u4FEE\u5C40\u90E8\u6837\u5F0F\u3002"
|
|
6637
|
+
});
|
|
6638
|
+
}
|
|
6639
|
+
}
|
|
6640
|
+
const needsBackButton = blockOrder.some((block) => /back/i.test(`${block.name || ""} ${block.label || ""}`));
|
|
6641
|
+
if (needsBackButton) {
|
|
6642
|
+
requiredBlocks += 1;
|
|
6643
|
+
if (hasAnyPattern(codeContent, [/Get\.back\b/, /Navigator\.pop\b/, /arrow_back/i, /back_icon\.svg/, /back_button/i])) {
|
|
6644
|
+
matchedBlocks += 1;
|
|
6645
|
+
} else {
|
|
6646
|
+
findings.push({
|
|
6647
|
+
id: "missing_back_button_block",
|
|
6648
|
+
severity: "error",
|
|
6649
|
+
message: "\u8BBE\u8BA1\u7A3F\u5B58\u5728 Back Button\uFF0C\u4F46\u4EE3\u7801\u4E2D\u672A\u68C0\u6D4B\u5230\u8FD4\u56DE\u6309\u94AE\u5B9E\u73B0\u3002",
|
|
6650
|
+
suggestion: "\u8865\u9F50\u8FD4\u56DE\u6309\u94AE\u4EA4\u4E92\u548C\u89C6\u89C9\u5B9E\u73B0\uFF0C\u4E0D\u8981\u53EA\u4FDD\u7559\u6807\u9898\u3002"
|
|
6651
|
+
});
|
|
6652
|
+
}
|
|
6653
|
+
}
|
|
6654
|
+
const needsSupportButton = blockOrder.some((block) => /customer service|support|客服/i.test(`${block.name || ""} ${block.label || ""}`));
|
|
6655
|
+
if (needsSupportButton) {
|
|
6656
|
+
requiredBlocks += 1;
|
|
6657
|
+
if (hasAnyPattern(codeContent, [/customer[_ ]service/i, /support/i, /recipient_customer_service_button/i, /客服/])) {
|
|
6658
|
+
matchedBlocks += 1;
|
|
6659
|
+
} else {
|
|
6660
|
+
findings.push({
|
|
6661
|
+
id: "missing_customer_service_block",
|
|
6662
|
+
severity: "error",
|
|
6663
|
+
message: "\u8BBE\u8BA1\u7A3F\u5B58\u5728 Customer Service Button\uFF0C\u4F46\u4EE3\u7801\u4E2D\u672A\u68C0\u6D4B\u5230\u5BF9\u5E94\u5165\u53E3\u3002",
|
|
6664
|
+
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"
|
|
6665
|
+
});
|
|
6666
|
+
}
|
|
6667
|
+
}
|
|
6668
|
+
const optionLabels = ["\u652F\u4ED8\u5B9D", "\u5FAE\u4FE1", "\u94F6\u884C\u5361"].filter((label) => navCopyLedger.includes(label));
|
|
6669
|
+
if (optionLabels.length > 0) {
|
|
6670
|
+
requiredBlocks += 1;
|
|
6671
|
+
const missingOptions = optionLabels.filter((label) => !codeContent.includes(label));
|
|
6672
|
+
if (missingOptions.length === 0) {
|
|
6673
|
+
matchedBlocks += 1;
|
|
6674
|
+
} else {
|
|
6675
|
+
findings.push({
|
|
6676
|
+
id: "missing_option_labels",
|
|
6677
|
+
severity: "error",
|
|
6678
|
+
message: `\u4EE3\u7801\u4E2D\u7F3A\u5C11\u8BBE\u8BA1\u7A3F\u9009\u9879\u6587\u6848: ${missingOptions.join(" / ")}`,
|
|
6679
|
+
suggestion: "\u9009\u9879\u5361\u6587\u6848\u9ED8\u8BA4\u4EE5 navCopyLedger \u4E3A\u771F\u503C\uFF0C\u7981\u6B62\u81EA\u884C\u6539\u5199\u6216\u9057\u6F0F\u3002"
|
|
6680
|
+
});
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
const needsStatusBar = navCopyLedger.includes("9:41") || hasAnyPattern(JSON.stringify(payload.tree || {}), [/"Signal"/, /"WiFi"/, /"Battery"/]);
|
|
6684
|
+
if (needsStatusBar) {
|
|
6685
|
+
requiredBlocks += 1;
|
|
6686
|
+
if (hasAnyPattern(codeContent, [/9:41/, /Signal/, /WiFi/, /Battery/, /statusBar/i])) {
|
|
6687
|
+
matchedBlocks += 1;
|
|
6688
|
+
} else {
|
|
6689
|
+
findings.push({
|
|
6690
|
+
id: "missing_status_bar_block",
|
|
6691
|
+
severity: "warning",
|
|
6692
|
+
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",
|
|
6693
|
+
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"
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
return {
|
|
6698
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6699
|
+
requiredBlocks,
|
|
6700
|
+
matchedBlocks,
|
|
6701
|
+
findings
|
|
6702
|
+
};
|
|
6703
|
+
}
|
|
6704
|
+
function buildAssetValidator(payload, codeContent) {
|
|
6705
|
+
const findings = [];
|
|
6706
|
+
const assetContracts = collectAssetContracts(payload.tree);
|
|
6707
|
+
const expectedVectorFiles = new Set(
|
|
6708
|
+
assetContracts.filter((item) => item.sourceType === "vector" && item.fileName).map((item) => item.fileName.toLowerCase())
|
|
6709
|
+
);
|
|
6710
|
+
const expectedBitmapCount = assetContracts.filter((item) => item.sourceType === "bitmap").length;
|
|
6711
|
+
const codeAssets = extractCodeAssets(codeContent);
|
|
6712
|
+
const codeVectorAssets = codeAssets.filter((asset) => asset.endsWith(".svg"));
|
|
6713
|
+
const codeBitmapAssets = codeAssets.filter((asset) => /\.(png|jpg|jpeg|webp)$/.test(asset));
|
|
6714
|
+
const unexpectedVectorAssets = codeVectorAssets.filter((asset) => !expectedVectorFiles.has(path20.posix.basename(asset).toLowerCase()));
|
|
6715
|
+
if (unexpectedVectorAssets.length > 0) {
|
|
6716
|
+
findings.push({
|
|
6717
|
+
id: "unexpected_vector_assets",
|
|
6718
|
+
severity: "error",
|
|
6719
|
+
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",
|
|
6720
|
+
evidence: unexpectedVectorAssets,
|
|
6721
|
+
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"
|
|
6722
|
+
});
|
|
6723
|
+
}
|
|
6724
|
+
if (expectedBitmapCount > 0 && codeBitmapAssets.length === 0) {
|
|
6725
|
+
findings.push({
|
|
6726
|
+
id: "missing_bitmap_assets",
|
|
6727
|
+
severity: "warning",
|
|
6728
|
+
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`,
|
|
6729
|
+
suggestion: "\u68C0\u67E5\u662F\u5426\u628A Sketch Image \u56FE\u5C42\u9519\u8BEF\u5F53\u6210 SVG \u6216\u4EE3\u7801\u7ED8\u5236\u4E86\u3002"
|
|
6730
|
+
});
|
|
6731
|
+
}
|
|
6732
|
+
if (codeBitmapAssets.length > 0) {
|
|
6733
|
+
findings.push({
|
|
6734
|
+
id: "bitmap_asset_source_check_required",
|
|
6735
|
+
severity: "info",
|
|
6736
|
+
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",
|
|
6737
|
+
evidence: codeBitmapAssets,
|
|
6738
|
+
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"
|
|
6739
|
+
});
|
|
6740
|
+
}
|
|
6741
|
+
const preserveContracts = assetContracts.filter((item) => item.mode === "preserve");
|
|
6742
|
+
if (preserveContracts.length > 0 && /colorFilter\s*:|ColorFilter\./.test(codeContent)) {
|
|
6743
|
+
findings.push({
|
|
6744
|
+
id: "preserve_svg_tint_risk",
|
|
6745
|
+
severity: "warning",
|
|
6746
|
+
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",
|
|
6747
|
+
evidence: preserveContracts.map((item) => item.fileName || item.sketchName),
|
|
6748
|
+
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"
|
|
6749
|
+
});
|
|
6750
|
+
}
|
|
6751
|
+
return {
|
|
6752
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6753
|
+
expectedAssetContracts: assetContracts,
|
|
6754
|
+
codeAssets,
|
|
6755
|
+
findings
|
|
6756
|
+
};
|
|
6757
|
+
}
|
|
6758
|
+
function buildRouteReviewValidator(args, codeContent) {
|
|
6759
|
+
const findings = [];
|
|
6760
|
+
const pageClassName = extractPageClassName(codeContent);
|
|
6761
|
+
let routeConnected = null;
|
|
6762
|
+
let routeTarget = null;
|
|
6763
|
+
let reviewHarnessReady = null;
|
|
6764
|
+
if (args.routeFilePath && args.routeName) {
|
|
6765
|
+
const routeContent = fs20.readFileSync(args.routeFilePath, "utf-8");
|
|
6766
|
+
const routeIndex = routeContent.indexOf(`name: ${args.routeName}`);
|
|
6767
|
+
if (routeIndex === -1) {
|
|
6768
|
+
findings.push({
|
|
6769
|
+
id: "route_not_found",
|
|
6770
|
+
severity: "error",
|
|
6771
|
+
message: `\u5728\u8DEF\u7531\u6587\u4EF6\u4E2D\u672A\u627E\u5230 ${args.routeName} \u7684\u5B9A\u4E49\u3002`,
|
|
6772
|
+
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"
|
|
6773
|
+
});
|
|
6774
|
+
} else {
|
|
6775
|
+
const routeChunk = routeContent.slice(routeIndex, routeIndex + 240);
|
|
6776
|
+
routeConnected = true;
|
|
6777
|
+
if (/_ComingSoonPage/.test(routeChunk)) {
|
|
6778
|
+
routeConnected = false;
|
|
6779
|
+
findings.push({
|
|
6780
|
+
id: "route_points_to_placeholder",
|
|
6781
|
+
severity: "error",
|
|
6782
|
+
message: `${args.routeName} \u5F53\u524D\u4ECD\u7136\u6307\u5411 _ComingSoonPage\uFF0C\u5360\u4F4D\u9875\u672A\u66FF\u6362\u3002`,
|
|
6783
|
+
suggestion: "\u628A page factory \u63A5\u5230\u771F\u5B9E\u9875\u9762\u7C7B\uFF0C\u800C\u4E0D\u662F\u4FDD\u7559\u5360\u4F4D\u5B9E\u73B0\u3002"
|
|
6784
|
+
});
|
|
6785
|
+
}
|
|
6786
|
+
const routeTargetMatch = routeChunk.match(/page:\s*\(\)\s*=>\s*const\s+([A-Za-z0-9_]+)/) || routeChunk.match(/page:\s*\(\)\s*=>\s*([A-Za-z0-9_]+)\(/);
|
|
6787
|
+
routeTarget = (routeTargetMatch == null ? void 0 : routeTargetMatch[1]) || null;
|
|
6788
|
+
if (pageClassName && routeTarget && pageClassName !== routeTarget) {
|
|
6789
|
+
findings.push({
|
|
6790
|
+
id: "route_target_mismatch",
|
|
6791
|
+
severity: "warning",
|
|
6792
|
+
message: `\u8DEF\u7531\u76EE\u6807\u7C7B ${routeTarget} \u4E0E\u9875\u9762\u4E3B\u7C7B ${pageClassName} \u4E0D\u4E00\u81F4\u3002`,
|
|
6793
|
+
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"
|
|
6794
|
+
});
|
|
6795
|
+
}
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
if (args.projectPath) {
|
|
6799
|
+
const reviewHarnessPath = path20.join(args.projectPath, "test/visual_regression/ui_review_golden_test.dart");
|
|
6800
|
+
reviewHarnessReady = fs20.existsSync(reviewHarnessPath);
|
|
6801
|
+
if (!reviewHarnessReady) {
|
|
6802
|
+
findings.push({
|
|
6803
|
+
id: "ui_review_harness_missing",
|
|
6804
|
+
severity: "warning",
|
|
6805
|
+
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",
|
|
6806
|
+
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"
|
|
6807
|
+
});
|
|
6808
|
+
} else {
|
|
6809
|
+
const reviewContent = fs20.readFileSync(reviewHarnessPath, "utf-8");
|
|
6810
|
+
const pageStem = path20.basename(args.codeFilePath || "", path20.extname(args.codeFilePath || "")).replace(/_page$/, "");
|
|
6811
|
+
if (pageStem && !reviewContent.includes(pageStem)) {
|
|
6812
|
+
findings.push({
|
|
6813
|
+
id: "ui_review_scenario_not_registered",
|
|
6814
|
+
severity: "warning",
|
|
6815
|
+
message: "UI review harness \u5DF2\u5B58\u5728\uFF0C\u4F46\u5F53\u524D\u9875\u9762\u8FD8\u6CA1\u6709\u4E13\u5C5E\u573A\u666F\u6CE8\u518C\u3002",
|
|
6816
|
+
evidence: [reviewHarnessPath],
|
|
6817
|
+
suggestion: "\u628A\u5F53\u524D\u9875\u9762\u52A0\u5165 visual regression \u573A\u666F\uFF0C\u907F\u514D\u53EA\u9760\u8089\u773C\u56DE\u5F52\u3002"
|
|
6818
|
+
});
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6821
|
+
}
|
|
6822
|
+
const recommendedNextSteps = [
|
|
6823
|
+
"\u5148\u4FEE\u6B63\u6240\u6709 error \u7EA7\u522B\u95EE\u9898\uFF0C\u518D\u5904\u7406 warning",
|
|
6824
|
+
"\u4FEE\u6B63\u8D44\u6E90\u6765\u6E90\u540E\u91CD\u65B0\u8FD0\u884C validate_restoration\uFF0C\u76F4\u5230 unexpected vector assets \u6E05\u96F6"
|
|
6825
|
+
];
|
|
6826
|
+
if (args.routeFilePath && args.routeName) {
|
|
6827
|
+
recommendedNextSteps.push(`\u786E\u8BA4 ${args.routeName} \u4E0D\u518D\u6307\u5411 _ComingSoonPage`);
|
|
6828
|
+
}
|
|
6829
|
+
if (args.projectPath) {
|
|
6830
|
+
recommendedNextSteps.push("\u5C06\u9875\u9762\u6CE8\u518C\u5230 visual regression \u573A\u666F\u540E\u518D\u8FDB\u884C UI review");
|
|
6831
|
+
}
|
|
6832
|
+
return {
|
|
6833
|
+
passed: !findings.some((item) => item.severity === "error"),
|
|
6834
|
+
routeConnected,
|
|
6835
|
+
routeTarget,
|
|
6836
|
+
reviewHarnessReady,
|
|
6837
|
+
findings,
|
|
6838
|
+
recommendedNextSteps
|
|
6839
|
+
};
|
|
6840
|
+
}
|
|
6841
|
+
async function validateRestoration(args) {
|
|
6842
|
+
var _a;
|
|
6843
|
+
if (!args.codeFilePath) {
|
|
6844
|
+
throw new Error("validate_restoration \u9700\u8981 codeFilePath \u53C2\u6570");
|
|
6845
|
+
}
|
|
6846
|
+
if (!fs20.existsSync(args.codeFilePath)) {
|
|
6847
|
+
throw new Error(`\u4EE3\u7801\u6587\u4EF6\u4E0D\u5B58\u5728: ${args.codeFilePath}`);
|
|
6848
|
+
}
|
|
6849
|
+
const payload = loadMeasurePayload(args);
|
|
6850
|
+
const codeContent = fs20.readFileSync(args.codeFilePath, "utf-8");
|
|
6851
|
+
const contractValidator = buildContractValidator(payload, codeContent);
|
|
6852
|
+
const assetValidator = buildAssetValidator(payload, codeContent);
|
|
6853
|
+
const routeReviewValidator = buildRouteReviewValidator(args, codeContent);
|
|
6854
|
+
return {
|
|
6855
|
+
artboardName: (_a = payload.artboard) == null ? void 0 : _a.name,
|
|
6856
|
+
ok: contractValidator.passed && assetValidator.passed && routeReviewValidator.passed,
|
|
6857
|
+
codeFilePath: args.codeFilePath,
|
|
6858
|
+
contractValidator,
|
|
6859
|
+
assetValidator,
|
|
6860
|
+
routeReviewValidator
|
|
6861
|
+
};
|
|
6862
|
+
}
|
|
6863
|
+
|
|
6527
6864
|
// src/tools/skillDefinitions.ts
|
|
6528
6865
|
function wrapAsContent(data) {
|
|
6529
6866
|
return {
|
|
@@ -6874,6 +7211,29 @@ var skillDefinitions = [
|
|
|
6874
7211
|
outputPath: params.outputPath
|
|
6875
7212
|
});
|
|
6876
7213
|
}
|
|
7214
|
+
},
|
|
7215
|
+
{
|
|
7216
|
+
name: "validate_restoration",
|
|
7217
|
+
category: "sketch",
|
|
7218
|
+
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",
|
|
7219
|
+
paramHints: [
|
|
7220
|
+
{ 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" },
|
|
7221
|
+
{ name: "measureContent", type: "string", description: "\u76F4\u63A5\u4F20\u5165 sketch_measure \u7684 JSON \u6587\u672C\uFF08measurePath \u4E0E measureContent \u4E8C\u9009\u4E00\uFF09" },
|
|
7222
|
+
{ name: "codeFilePath", type: "string", required: true, description: "\u751F\u6210\u540E\u7684\u9875\u9762\u4EE3\u7801\u6587\u4EF6\u8DEF\u5F84" },
|
|
7223
|
+
{ 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" },
|
|
7224
|
+
{ name: "routeName", type: "string", description: "\u8DEF\u7531\u540D\uFF0C\u5982 AppRoutes.recipientAdd" },
|
|
7225
|
+
{ name: "projectPath", type: "string", description: "\u9879\u76EE\u6839\u8DEF\u5F84\uFF08\u7528\u4E8E\u68C0\u67E5 visual review harness\uFF09" }
|
|
7226
|
+
],
|
|
7227
|
+
handler: async (params) => {
|
|
7228
|
+
return wrapAsContent(await validateRestoration({
|
|
7229
|
+
measurePath: params.measurePath,
|
|
7230
|
+
measureContent: params.measureContent,
|
|
7231
|
+
codeFilePath: params.codeFilePath,
|
|
7232
|
+
routeFilePath: params.routeFilePath,
|
|
7233
|
+
routeName: params.routeName,
|
|
7234
|
+
projectPath: params.projectPath
|
|
7235
|
+
}));
|
|
7236
|
+
}
|
|
6877
7237
|
}
|
|
6878
7238
|
];
|
|
6879
7239
|
|