@qilitt-mickey/vue3-temp-skill 1.1.74 → 1.1.76

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.
Files changed (65) hide show
  1. package/SKILL.md +137 -137
  2. package/mapping/basic/color.json +35 -35
  3. package/mapping/basic/radius.json +17 -17
  4. package/mapping/basic/semantic-values.json +72 -72
  5. package/mapping/basic/spacing.json +21 -21
  6. package/mapping/basic/typography.json +21 -21
  7. package/mapping/component/button.json +90 -90
  8. package/mapping/component/card.json +31 -31
  9. package/mapping/component/input.json +42 -42
  10. package/mapping/component/overlay.json +79 -79
  11. package/mapping/component/pagination.json +34 -34
  12. package/mapping/component/table.json +42 -42
  13. package/mapping/component/tag.json +48 -48
  14. package/mapping/layout/breakpoint.json +20 -20
  15. package/mapping/scenes/admin/content.json +497 -494
  16. package/mapping/scenes/admin/layout.json +577 -574
  17. package/package.json +1 -1
  18. package/parser/fixtures/changeset-legacy.json +11 -11
  19. package/parser/fixtures/changeset-neg1.json +8 -8
  20. package/parser/fixtures/changeset-neg2.json +10 -10
  21. package/parser/fixtures/changeset-neg3.json +22 -22
  22. package/parser/fixtures/changeset-neg5-g8-stub.json +26 -26
  23. package/parser/fixtures/changeset-neg7-g10-dims.json +57 -57
  24. package/parser/fixtures/changeset-neg9-g6-token-chain.json +34 -0
  25. package/parser/fixtures/changeset-pos-g6-token-chain.json +35 -0
  26. package/parser/fixtures/changeset-pos-theme-nometa.json +260 -260
  27. package/parser/fixtures/changeset-registry-gap.json +29 -29
  28. package/parser/fixtures/fake-project/src/styles/app.scss +5 -5
  29. package/parser/fixtures/fake-project/src/views/list.vue +13 -13
  30. package/parser/fixtures/registry-bad.json +11 -11
  31. package/parser/fixtures/registry-g6-token-chain.json +10 -0
  32. package/parser/fixtures/verify/actual-clean.json +35 -35
  33. package/parser/fixtures/verify/actual.json +33 -33
  34. package/parser/fixtures/verify/mockup-g6-content.html +12 -0
  35. package/parser/fixtures/verify/mockup-neutral.html +26 -26
  36. package/parser/fixtures/verify/mockup-nometa.html +26 -26
  37. package/parser/fixtures/verify/snapshot-latest.json +102 -102
  38. package/parser/index.js +32 -1
  39. package/parser/loader.js +66 -66
  40. package/parser/validator.js +206 -206
  41. package/references/auth-pages.md +217 -217
  42. package/references/base-code-dict.md +56 -56
  43. package/references/data-compare.md +509 -509
  44. package/references/data-writeback.md +124 -124
  45. package/references/design-apply.md +167 -167
  46. package/references/detail-page.md +119 -119
  47. package/references/download-export.md +97 -97
  48. package/references/feedback-loading.md +104 -104
  49. package/references/feedback-ui.md +134 -134
  50. package/references/i18n-localization.md +230 -230
  51. package/references/layout-theme.md +2 -0
  52. package/references/project-inventory.md +438 -438
  53. package/references/rich-text.md +94 -94
  54. package/references/seamless-scroll.md +47 -47
  55. package/references/steps/step0-preflight.md +58 -58
  56. package/references/steps/step1-match.md +5 -2
  57. package/references/steps/step3-style.md +38 -33
  58. package/references/steps/step3b-shell.md +2 -0
  59. package/references/steps/step3c-priority.md +26 -26
  60. package/references/steps/step4-l3.md +14 -14
  61. package/references/steps/step5-gates.md +65 -63
  62. package/references/steps/step6-verify.md +77 -77
  63. package/references/verify-captcha.md +119 -119
  64. package/scripts/check.mjs +24 -0
  65. package/scripts/design-audit.mjs +208 -3
package/scripts/check.mjs CHANGED
@@ -129,6 +129,30 @@ const checks = [
129
129
  return " negative 被拒绝并命中「基线三件套」判据(mode 唯一合法值 restore)";
130
130
  },
131
131
  },
132
+ {
133
+ name: "层间令牌链闸回归",
134
+ desc: "G6 层间令牌链对账:共享同链间距令牌的条目声明几何字段却缺 suppress_inner 必须被 parser match 拒绝",
135
+ cmd: () => {
136
+ const cs = path.join(ROOT, "parser/fixtures/changeset-neg9-g6-token-chain.json");
137
+ if (!fs.existsSync(cs)) return "SKIPPED 未发现 G6 夹具";
138
+ let out = "";
139
+ try {
140
+ out = run(NODE, "parser/index.js", ["match", cs]);
141
+ throw Object.assign(new Error("G6 负例未被拒绝"), {
142
+ stdout: ` ✗ neg9-g6-token-chain 竟然通过 —— 同链令牌双层叠加未拦截,必须修复\n`,
143
+ });
144
+ } catch (e) {
145
+ if (e.message === "G6 负例未被拒绝") throw e;
146
+ out = (e.stdout || "") + (e.stderr || "");
147
+ }
148
+ if (!/层间令牌链对账/.test(out)) {
149
+ throw Object.assign(new Error("G6 负例未命中预期判据"), {
150
+ stdout: ` ✗ neg9-g6-token-chain 被拒绝,但未命中「层间令牌链对账」判据 —— 断言已失效\n${out.slice(-800)}\n`,
151
+ });
152
+ }
153
+ return " negative 被拒绝并命中「层间令牌链对账」判据(G6)";
154
+ },
155
+ },
132
156
  ];
133
157
 
134
158
  function run(runner, script, args = []) {
@@ -32,6 +32,8 @@
32
32
  * E13 固定尺寸内容度量 固定 width 小于内容需求且无收口兜底 → 文字换行/压缩/重叠
33
33
  * E14 列宽预算链自洽 列宽(含公式)扣掉实际 td 内边距后装不下内容 → 操作列按钮被压
34
34
  * E16 引用完整性 变更集引用的实物不存在(改名未同步)/ restore 缺顶层 theme
35
+ * E17 层间令牌链对账 父子两层盒共享同链间距令牌:绕过令牌通道抢写物理 padding 且同链令牌幸存 → 双层叠加
36
+ * E18 激活态消费者成对落地 indicator_* 形态声明后:消费者缺失 / 令牌仍透明 / 伪元素对决权重不足 → 竖条不可见
35
37
  * E15 结构声明兑现 form 值 / suppress 通道名必须在词典枚举内,且设计层有 @sid / @closed 落点证据(G3 双向对账)
36
38
  */
37
39
 
@@ -426,9 +428,14 @@ for (const r of scopedRules) {
426
428
  info("E3", "层叠胜负:无同属性竞争的组件 scoped 规则");
427
429
  return;
428
430
  }
431
+ // 出厂暗色主题层(dark.scss)不属于「本次设计落地」:它与组件 scoped 的对决是出厂内部
432
+ // 行为(架构红线也禁止改出厂文件来「修复」),按设计层宣判会永久卡死交付闸。
433
+ const FACTORY_THEME_LAYERS = new Set(["dark.scss"]);
434
+ const isFactoryLayer = (file) => FACTORY_THEME_LAYERS.has(path.basename(String(file || "")));
429
435
  const hits = [];
430
436
  const seen = new Set();
431
437
  for (const r of designRules) {
438
+ if (isFactoryLayer(r.file)) continue;
432
439
  const pe = pseudoElOf(r.selector);
433
440
  for (const part of splitList(r.selector)) {
434
441
  const last = lastCompound(part);
@@ -870,12 +877,23 @@ function extractSuppressRulesAudit(entry) {
870
877
  return rules;
871
878
  }
872
879
 
873
- const channelNamesOf = (entry) =>
874
- new Set([
880
+ const channelNamesOf = (entry) => {
881
+ const names = new Set([
875
882
  ...Object.keys(entry?.forms || {}),
876
883
  ...Object.keys(entry?.css_vars || {}),
877
884
  ...Object.keys(entry?.custom_style_map || {}),
878
885
  ]);
886
+ // suppress_rules 的「值域通道」也是合法收口目标(与 parser G1 同源):如 dropdown_popper / tool_divider
887
+ for (const channels of Object.values(entry?.suppress_rules || {})) {
888
+ if (Array.isArray(channels)) for (const ch of channels) if (typeof ch === "string") names.add(ch);
889
+ }
890
+ // forms 描述里「suppress 必含 x」内联标记的通道同样合法
891
+ for (const desc of Object.values(entry?.forms || {})) {
892
+ if (typeof desc !== "string") continue;
893
+ for (const m of desc.matchAll(/suppress\s*必含\s*([a-z][a-z0-9_]*)/gi)) names.add(m[1]);
894
+ }
895
+ return names;
896
+ };
879
897
 
880
898
  /** 通道收口证据:@closed 标记 或(css_vars 键)关闭值覆写 */
881
899
  function channelEvidence(entry, ch) {
@@ -925,7 +943,18 @@ function visibleClosureRule(change) {
925
943
  if (typeof change.form === "string" && change.form) {
926
944
  const forms = entry.forms && typeof entry.forms === "object" ? Object.keys(entry.forms) : [];
927
945
  const rules = entry.suppress_rules || {};
928
- if (forms.length && !forms.includes(change.form) && !(change.form in rules)) {
946
+ // modes 型条目(forms 值为数组的枚举字典,如 admin.content.container 的 mode: ["fixed","scroll","auto"]):
947
+ // form 合法值取数组并集
948
+ const modeValues = [];
949
+ for (const v of Object.values(entry.forms || {})) {
950
+ if (Array.isArray(v)) for (const x of v) if (typeof x === "string") modeValues.push(x);
951
+ }
952
+ if (
953
+ forms.length &&
954
+ !forms.includes(change.form) &&
955
+ !(change.form in rules) &&
956
+ !modeValues.includes(change.form)
957
+ ) {
929
958
  err(
930
959
  "E15",
931
960
  `${change.id} 的 form="${change.form}" 不在词典 forms 枚举 [${forms.join("、")}] 内 —— 项目侧无规则可挂(壳层零规则),声明悬空。形态值只能取词典已支持的枚举;确需新形态先走 pending 补词典。`,
@@ -1391,6 +1420,8 @@ const MIN_ANY_BOX = 24;
1391
1420
  path.resolve(SKILL_ROOT, val),
1392
1421
  path.resolve(SKILL_ROOT, "..", val),
1393
1422
  path.resolve(PROJECT, "..", val),
1423
+ // 设计侧 page-specs 根(效果图 / 登记表以 page-specs 根为相对基座交付)
1424
+ path.resolve(SKILL_ROOT, "..", "project-ui-design", "references", "page-specs", val),
1394
1425
  ];
1395
1426
  if (!cands.some((p) => fs.existsSync(p))) {
1396
1427
  err(
@@ -1411,6 +1442,178 @@ const MIN_ANY_BOX = 24;
1411
1442
  if (checked && !errors.some((e) => e.id === "E16")) info("E16", `引用完整性:${checked} 个路径引用均可解析到实物 ✓`);
1412
1443
  })();
1413
1444
 
1445
+ // ── E17 层间令牌链对账(双层内边距叠加断言)──────────────────
1446
+ // 失效模式:父子两层盒共享同一条间距令牌链(--layout-content-padding → --vts-margin),
1447
+ // 设计层绕过令牌通道在父层抢写物理 padding,子层同链令牌幸存 → 设计值 + 令牌出厂值叠加
1448
+ // (24px + 8px = 32px/侧,「边距很大」)。判据(词典「层间令牌链对账」标记驱动):
1449
+ // ① 设计层在标记条目的 selector 上抢写物理 padding/margin 属性(非 var 消费);
1450
+ // ② 该条目同链令牌在项目内仍存在非零定义(子层消费者会叠加取值)。
1451
+ // 修复方向:改走令牌通道(重映射 --layout-content-padding / --vts-margin),或归零另一层。
1452
+ (function checkE17() {
1453
+ // 从词典收集「层间令牌链对账」条目:selector 主类 ↔ 同链令牌(css_vars 值)与字段名
1454
+ const chainEntries = dictEntries
1455
+ .filter(({ entry }) =>
1456
+ Array.isArray(entry.preconditions) &&
1457
+ entry.preconditions.some((p) => typeof p === "string" && p.includes("层间令牌链对账")))
1458
+ .map(({ sid, entry }) => ({
1459
+ sid,
1460
+ classes: (String(entry.selector || "").match(/\.[\w-]+/g) || []).map((c) => c.slice(1)),
1461
+ vars: Object.values(entry.css_vars || {}).filter((v) => typeof v === "string"),
1462
+ fields: Object.keys(entry.css_vars || {}).filter((k) => /pad|margin/i.test(k)),
1463
+ }))
1464
+ .filter((e) => e.classes.length && e.vars.length);
1465
+
1466
+ if (!chainEntries.length) {
1467
+ info("E17", "层间令牌链对账:词典无标记条目,跳过");
1468
+ return;
1469
+ }
1470
+
1471
+ // 同链令牌在项目内(含设计层)的当前定义值(后者覆盖前者,按样式层叠顺序近似取最后定义)
1472
+ const varValueOf = (name) => {
1473
+ let last = null;
1474
+ for (const t of [projectText, designCss].filter(Boolean)) {
1475
+ const re = new RegExp(`${name.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&")}\\s*:\\s*([^;]+);`, "g");
1476
+ for (const m of t.matchAll(re)) last = m[1].trim();
1477
+ }
1478
+ return last;
1479
+ };
1480
+
1481
+ let checked = 0;
1482
+ for (const { sid, classes, vars, fields } of chainEntries) {
1483
+ for (const rule of designRules) {
1484
+ // 命中条目 selector 的主类(末位复合选择器含任一标记类)
1485
+ const ruleClasses = new Set((rule.selector.match(/\.[\w-]+/g) || []).map((c) => c.slice(1)));
1486
+ if (!classes.some((c) => ruleClasses.has(c))) continue;
1487
+ for (const prop of Object.keys(rule.decls)) {
1488
+ if (!/^(padding|margin)(-(top|right|bottom|left|inline|block))?$/.test(prop)) continue;
1489
+ checked++;
1490
+ const val = String(rule.decls[prop]);
1491
+ // 写的就是 var() 消费 = 令牌通道,合法
1492
+ if (/var\(/.test(val)) continue;
1493
+ // 抢写物理值:同链任一令牌在项目内仍有非零定义 → 双层叠加
1494
+ const survivors = vars
1495
+ .map((v) => ({ v, def: varValueOf(v) }))
1496
+ .filter(({ def }) => def && !/^(0|0px|initial|unset)$/.test(def) && !/var\(/.test(def));
1497
+ if (survivors.length) {
1498
+ err(
1499
+ "E17",
1500
+ `层间令牌链对账:${rule.selector} 的 ${prop}: ${val} 绕过令牌通道抢写物理间距,但同链令牌 ` +
1501
+ `${survivors.map((s) => `${s.v}(当前定义 ${s.def})`).join("、")} 仍非零 —— 父层设计值与子层令牌值叠加,` +
1502
+ `实际边距 = 两者之和(如 24px + 8px = 32px/侧)。修复:改走令牌通道(在该点位或消费点作用域重映射 ` +
1503
+ `${vars.join(" / ")},两层同变),或把另一层同链间距归零;仅保留一个权威来源。`,
1504
+ );
1505
+ }
1506
+ }
1507
+ }
1508
+ }
1509
+ if (checked) {
1510
+ if (!errors.some((e) => e.id === "E17")) info("E17", `层间令牌链对账:${checked} 处几何声明均走令牌通道或邻层已归零 ✓`);
1511
+ } else {
1512
+ info("E17", "层间令牌链对账:标记条目无物理几何声明,跳过");
1513
+ }
1514
+ })();
1515
+
1516
+ // ── E18 激活态消费者存活断言(成对落地 + 伪元素对决)──────────
1517
+ // 失效模式:菜单激活态令牌 --vts-theme-menu-active-before 出厂 transparent 且全项目无消费者。
1518
+ // 设计侧声明 indicator_* 形态(或 menu_active_indicator 字段)后:
1519
+ // ① 设计层不新建 ::before/::after 消费者 → 令牌仍透明、无消费点,竖条不可见;
1520
+ // ② 建了消费者但令牌从未供值(仍 transparent)→ 消费者渲染但不可见;
1521
+ // ③ 消费者与出厂 sidebar.scss 的同名 ::before 胶囊(specificity 更高 + !important 背景)
1522
+ // 对决输了 → 竖条几何整体不渲染。
1523
+ // 判据(词典「激活态消费者成对落地」标记驱动):三者缺一即 ERROR。
1524
+ (function checkE18() {
1525
+ const marked = dictEntries
1526
+ .filter(({ entry }) =>
1527
+ Array.isArray(entry.preconditions) &&
1528
+ entry.preconditions.some((p) => typeof p === "string" && p.includes("激活态消费者成对落地")))
1529
+ .map(({ sid, entry }) => ({ sid, entry }));
1530
+ if (!marked.length) {
1531
+ info("E18", "激活态消费者成对落地:词典无标记条目,跳过");
1532
+ return;
1533
+ }
1534
+
1535
+ // 令牌最终定义值(projectText → designCss 顺序近似层叠,取最后定义;支持一层 var 链解析)
1536
+ const finalVarValue = (name, seen = new Set()) => {
1537
+ let last = null;
1538
+ for (const t of [projectText, designCss].filter(Boolean)) {
1539
+ const re = new RegExp(`${name.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&")}\\s*:\\s*([^;]+);`, "g");
1540
+ for (const m of t.matchAll(re)) last = m[1].trim();
1541
+ }
1542
+ if (last == null) return null;
1543
+ const varRef = last.match(/^var\(\s*(--[\w-]+)/);
1544
+ if (varRef && !seen.has(name)) {
1545
+ seen.add(name);
1546
+ const inner = finalVarValue(varRef[1], seen);
1547
+ return inner != null ? inner : last;
1548
+ }
1549
+ return last;
1550
+ };
1551
+
1552
+ for (const { sid, entry } of marked) {
1553
+ const change = (changeset?.changes || []).find((c) => c.id === sid);
1554
+ if (!change) continue;
1555
+ const form = String(change.form || "");
1556
+ const style = change.style && typeof change.style === "object" ? change.style : {};
1557
+ const declaresIndicator =
1558
+ /indicator/.test(form) ||
1559
+ "menu_active_indicator" in style ||
1560
+ Object.keys(style).some((k) => /^active_indicator/.test(k));
1561
+ if (!declaresIndicator) continue;
1562
+
1563
+ const vars = Object.values(entry.css_vars || {})
1564
+ .filter((v) => typeof v === "string" && /active/.test(v));
1565
+ const indicatorVar = vars.find((v) => /before/.test(v)) || vars[0];
1566
+ if (!indicatorVar) continue;
1567
+
1568
+ // 断言①:设计层存在该令牌的消费者(var() 引用)
1569
+ const consumedInDesign = designRules.some((r) =>
1570
+ Object.values(r.decls).some((v) => String(v).includes(`var(${indicatorVar}`)),
1571
+ );
1572
+ if (!consumedInDesign) {
1573
+ err(
1574
+ "E18",
1575
+ `激活态消费者成对落地:${sid} 声明了指示条形态(form=${form || "—"}),但设计层没有任何规则消费 ` +
1576
+ `${indicatorVar} —— 只供值不建消费者 = 未施工(令牌出厂 transparent,全项目无消费点),竖条不可见。` +
1577
+ `修复:在 design-shell 新建 ::before/::after 消费者引用 var(${indicatorVar})。`,
1578
+ );
1579
+ continue;
1580
+ }
1581
+
1582
+ // 断言②:令牌最终定义非 transparent/none/初始值
1583
+ const finalVal = finalVarValue(indicatorVar);
1584
+ if (finalVal && /^(transparent|none|initial|unset|inherit)$/i.test(finalVal.replace(/!important\s*$/i, "").trim())) {
1585
+ err(
1586
+ "E18",
1587
+ `激活态消费者成对落地:${indicatorVar} 消费者已建,但最终定义仍为 ${finalVal.trim()}(出厂中性基线)——` +
1588
+ `消费者在渲染,色值透明 = 竖条不可见。修复:在条目 style_scope(如 .sidebar-container)内显式供值 ` +
1589
+ `(非透明设计色),或在对应 html[data-theme] 主题块确认已有非透明定义。`,
1590
+ );
1591
+ }
1592
+
1593
+ // 断言③(警告级):消费者是伪元素规则且与出厂胶囊对决——无 !important 背景 / 无提权链则提示
1594
+ const consumerRules = designRules.filter((r) =>
1595
+ Object.values(r.decls).some((v) => String(v).includes(`var(${indicatorVar}`)),
1596
+ );
1597
+ for (const r of consumerRules) {
1598
+ const isPseudo = /::(before|after)/.test(r.selector);
1599
+ const bgImportant = /important/i.test(String(r.decls["background"] || r.decls["background-color"] || ""));
1600
+ const elevated = /(^|\s)html\b[\s>]*body\b/.test(r.selector) || /body\s+\./.test(r.selector);
1601
+ if (isPseudo && !bgImportant && !elevated) {
1602
+ warn(
1603
+ "E18",
1604
+ `激活态消费者成对落地:${r.selector} 消费 ${indicatorVar} 但既无 !important 背景也无 html body 提权链——` +
1605
+ `出厂 sidebar.scss 的同名 ::before 胶囊(!important 背景)对决大概率获胜,指示条几何可能整体不渲染。` +
1606
+ `修复:背景加 !important 或用 html body 前缀提权(词典 priority.strategy=deep_qualified)。`,
1607
+ );
1608
+ }
1609
+ }
1610
+ }
1611
+ const checkedAny = marked.some(({ sid }) => (changeset?.changes || []).some((c) => c.id === sid));
1612
+ if (checkedAny && !errors.some((e) => e.id === "E18") && !warnings.some((w) => w.id === "E18")) {
1613
+ info("E18", "激活态消费者成对落地:消费者存在、令牌非透明、对决权重足够 ✓");
1614
+ }
1615
+ })();
1616
+
1414
1617
  const result = { project: PROJECT, errors, warnings, infos };
1415
1618
 
1416
1619
  const CHECK_TITLES = {
@@ -1429,6 +1632,8 @@ const CHECK_TITLES = {
1429
1632
  E13: "固定尺寸内容度量",
1430
1633
  E14: "列宽预算链自洽",
1431
1634
  E16: "引用完整性",
1635
+ E17: "层间令牌链对账",
1636
+ E18: "激活态消费者成对落地",
1432
1637
  SID: "@sid 覆盖率",
1433
1638
  };
1434
1639