cardbuddy 0.15.0 → 0.17.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.
Files changed (107) hide show
  1. package/dist/init.js +0 -2
  2. package/dist/preview-editor/assets/index-CXDf5tVg.css +1 -0
  3. package/dist/preview-editor/assets/{index-CIIfMlwI.js → index-DLQkCPLT.js} +113 -86
  4. package/dist/preview-editor/index.html +2 -2
  5. package/dist/vendored/card-editor/runtime/adapter.js +2 -2
  6. package/dist/vendored/mcp/client.mjs +1 -1
  7. package/dist/vendored/server/core/ai-chat.js +251 -80
  8. package/dist/vendored/server/core/browser.js +17 -0
  9. package/dist/vendored/server/core/cardFiles.js +49 -1
  10. package/dist/vendored/server/core/cardImage.js +103 -2
  11. package/dist/vendored/server/core/cardValidate.js +16 -5
  12. package/dist/vendored/server/core/screenshot.js +94 -0
  13. package/dist/vendored/skills/card-skill-trainer/SKILL.md +68 -13
  14. package/dist/vendored/skills/card-skill-trainer/scripts/diagnose_case.mjs +14 -82
  15. package/dist/vendored/skills/card-skill-trainer/scripts/lib/diagnosis.mjs +207 -0
  16. package/dist/vendored/skills/card-skill-trainer/scripts/lib/layout-correction-sim.mjs +62 -0
  17. package/dist/vendored/skills/card-skill-trainer/scripts/lib/paradigm-router.mjs +76 -0
  18. package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker-runner.mjs +31 -0
  19. package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker.mjs +138 -0
  20. package/dist/vendored/skills/card-skill-trainer/scripts/lib/scoring.mjs +24 -20
  21. package/dist/vendored/skills/card-skill-trainer/scripts/lib/telemetry.mjs +46 -0
  22. package/dist/vendored/skills/card-skill-trainer/scripts/plan_next_round.mjs +5 -2
  23. package/dist/vendored/skills/card-skill-trainer/scripts/run_round.mjs +286 -92
  24. package/dist/vendored/skills/card-skill-trainer/scripts/score_round.mjs +74 -2
  25. package/dist/vendored/skills/card-skill-trainer/scripts/sink_rules.mjs +127 -0
  26. package/dist/vendored/skills/dsl-card-generator/SKILL.md +93 -27
  27. package/dist/vendored/skills/dsl-card-generator/references/component_rules.md +14 -0
  28. package/dist/vendored/skills/dsl-card-generator/references/dsl_structure.md +1 -15
  29. package/dist/vendored/skills/dsl-card-generator/references/expression_engine.md +11 -20
  30. package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +217 -44
  31. package/dist/vendored/skills/dsl-card-generator/references/ir-format.md +87 -3
  32. package/dist/vendored/skills/dsl-card-generator/references/iteration_protocol.md +35 -6
  33. package/dist/vendored/skills/dsl-card-generator/references/previewer_contract.md +21 -0
  34. package/dist/vendored/skills/dsl-card-generator/references/quickref.md +28 -27
  35. package/dist/vendored/skills/dsl-card-generator/references/recipes.md +30 -8
  36. package/dist/vendored/skills/dsl-card-generator/references/rules.md +3 -2
  37. package/dist/vendored/skills/dsl-card-generator/references/scripts_reference.md +5 -2
  38. package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +2 -3
  39. package/dist/vendored/skills/dsl-card-generator/references/spec_to_schema_patterns.md +1 -4
  40. package/dist/vendored/skills/dsl-card-generator/scripts/add_component.mjs +5 -14
  41. package/dist/vendored/skills/dsl-card-generator/scripts/autofix_schema.py +88 -0
  42. package/dist/vendored/skills/dsl-card-generator/scripts/check_fidelity.mjs +143 -42
  43. package/dist/vendored/skills/dsl-card-generator/scripts/check_topology.py +0 -35
  44. package/dist/vendored/skills/dsl-card-generator/scripts/expand_ir.mjs +99 -53
  45. package/dist/vendored/skills/dsl-card-generator/scripts/gate.mjs +5 -2
  46. package/dist/vendored/skills/dsl-card-generator/scripts/iterate.mjs +388 -29
  47. package/dist/vendored/skills/dsl-card-generator/scripts/lib/component_contract.mjs +315 -0
  48. package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout-tokens.mjs +1 -1
  49. package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.mjs +23 -0
  50. package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.py +0 -37
  51. package/dist/vendored/skills/dsl-card-generator/scripts/lib/python.mjs +99 -0
  52. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/adaptive-width.mjs +105 -0
  53. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/bindings.mjs +260 -0
  54. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/expr.mjs +52 -0
  55. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/image.mjs +96 -0
  56. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/registry.mjs +166 -0
  57. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/structure.mjs +127 -0
  58. package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/walk.mjs +61 -0
  59. package/dist/vendored/skills/dsl-card-generator/scripts/lib/scaffold.mjs +48 -1
  60. package/dist/vendored/skills/dsl-card-generator/scripts/lib/scope_alias.mjs +125 -0
  61. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_assemble.mjs +366 -45
  62. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_extract.mjs +169 -12
  63. package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_shared.mjs +17 -9
  64. package/dist/vendored/skills/dsl-card-generator/scripts/lint_card.mjs +119 -78
  65. package/dist/vendored/skills/dsl-card-generator/scripts/preflight.mjs +48 -50
  66. package/dist/vendored/skills/dsl-card-generator/scripts/readiness.mjs +634 -0
  67. package/dist/vendored/skills/dsl-card-generator/scripts/register_card_template.mjs +5 -8
  68. package/dist/vendored/skills/dsl-card-generator/scripts/route_input.mjs +5 -10
  69. package/dist/vendored/skills/dsl-card-generator/scripts/spec_audit.mjs +122 -8
  70. package/dist/vendored/skills/dsl-card-generator/scripts/v3_regression.mjs +11 -2
  71. package/dist/vendored/skills/dsl-card-generator/scripts/validate_schema.py +23 -15
  72. package/dist/vendored/skills/finmall-card-sync/scripts/api_batch_sync.mjs +46 -2
  73. package/dist/vendored/skills/mbank-design-gen/SKILL.md +76 -0
  74. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-apps.png +0 -0
  75. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-arrow-right-blue.png +0 -0
  76. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-check.png +0 -0
  77. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-settings.png +0 -0
  78. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-sound.png +0 -0
  79. package/dist/vendored/skills/mbank-design-gen/assets/icons/icon-voice-switch.png +0 -0
  80. package/dist/vendored/skills/mbank-design-gen/assets/icons/progress-thumb.png +0 -0
  81. package/dist/vendored/skills/mbank-design-gen/assets/icons/tag-bg.png +0 -0
  82. package/dist/vendored/skills/mbank-design-gen/assets/icons/vs-badge.png +0 -0
  83. package/dist/vendored/skills/mbank-design-gen/assets/ref/ref-chat-options.png +0 -0
  84. package/dist/vendored/skills/mbank-design-gen/assets/ref/ref-home-scene.png +0 -0
  85. package/dist/vendored/skills/mbank-design-gen/assets/ref/ref-product-detail.png +0 -0
  86. package/dist/vendored/skills/mbank-design-gen/assets/ref/ref-rate-table.png +0 -0
  87. package/dist/vendored/skills/mbank-design-gen/assets/robot.png +0 -0
  88. package/dist/vendored/skills/mbank-design-gen/references/component-library.md +127 -0
  89. package/dist/vendored/skills/mbank-design-gen/references/design-spec.md +261 -0
  90. package/dist/vendored/skills/mbank-design-gen/templates/mockup-template.html +138 -0
  91. package/dist/vendored/skills/mbank-design-gen/tools/screenshot.mjs +34 -0
  92. package/dist/vendored/skills/shared/exit-codes.md +79 -0
  93. package/dist/vendored/skills/shared/spec-contract.md +127 -0
  94. package/dist/vendored/skills/sketch-spec-to-card/SKILL.md +27 -10
  95. package/dist/vendored/skills/sketch-spec-to-card/references/spec-schema.md +3 -3
  96. package/dist/vendored/skills/sketch-spec-to-card/scripts/build_prompt.py +0 -8
  97. package/dist/vendored/skills/sketch-spec-to-card/scripts/cluster_states.py +14 -25
  98. package/dist/vendored/skills/sketch-spec-to-card/scripts/parse_meaxure.py +121 -47
  99. package/dist/vendored/skills/sketch-spec-to-card/scripts/png_utils.py +0 -5
  100. package/dist/vendored/skills/sketch-spec-to-card/scripts/test_text_only_artboard.py +98 -16
  101. package/dist/vendored/skills/sketch-spec-to-card/scripts/vision.py +55 -37
  102. package/dist/vendored/templates/helloCard/schema.json +62 -1
  103. package/dist/vendored/tools/finmall-env.mjs +1 -18
  104. package/package.json +1 -1
  105. package/dist/preview-editor/assets/index-DQn0zQBP.css +0 -1
  106. package/dist/vendored/skills/card-skill-trainer/scripts/test_missing_slice.py +0 -122
  107. package/dist/vendored/skills/dsl-card-generator/scripts/analyze_component_usage.mjs +0 -153
@@ -0,0 +1,127 @@
1
+ # MBank 组件库规范(component-library)
2
+
3
+ > 从设计稿提炼的可复用部件。所有 token 定义见 `references/design-spec.md`;此处只写组件级拼装规则。
4
+ > 数值单位 pt(@1x)。每个组件给出:结构 → 样式 → 变体。
5
+
6
+ ---
7
+
8
+ ## A. 全局框架(每屏必有)
9
+
10
+ ### A1. 状态栏
11
+ - 左:时间 `9:41`,15pt Semibold `text-1`;右:信号/WiFi/电池(系统样式)。
12
+
13
+ ### A2. 顶部导航
14
+ - 左:双 tab「此刻 / 对话」,17pt;激活 = Medium `text-1`,非激活 = Regular `text-2`,无下划线。
15
+ - 右:声音图标 + 设置图标(`assets/icons/`,24pt),间距 16pt。
16
+ - 背景:透明,融入页面氛围渐变,**不加底色不加分割线**。
17
+
18
+ ### A3. 底部输入条(固定)
19
+ - 结构:`[麦克风图标 + 占位文字] 胶囊输入条` + 右侧 `[九宫格] 圆钮`。
20
+ - 输入条:高 36pt,radius-pill,白底,占位 15pt `text-3`(「欢迎向小易提问~」),麦克风 20pt 深灰,左 padding 16pt,**宽度撑满剩余空间**。
21
+ - 圆钮:44×44pt,白底 `shadow-float`,九宫格图标 20pt `text-1`。
22
+ - 下方 Home Indicator:34pt 高,黑色圆角横条 ~134pt 居中。
23
+
24
+ ---
25
+
26
+ ## B. 对话气泡
27
+
28
+ ### B1. 用户气泡(右)
29
+ - 背景渐变 `linear-gradient(90deg,#2F86F6,#005DFD)`,白字 15pt/24 Regular。
30
+ - radius:`12 0 12 12`(右上直角)。padding 12×16。max-width 75%。
31
+ - 与右边缘间距 12pt;多条相邻用户气泡间距 12pt。
32
+
33
+ ### B2. AI 气泡(左)
34
+ - 背景 `#FEFBF7`(暖白),文字 15pt/24 `text-1`,radius `0 12 12 12`(左上直角)。
35
+ - padding 12×16;**无头像贴边**(头像仅首页问候区出现)。
36
+ - 变体 `ai-note`:气泡内底部追加「*温馨提示」13pt `text-2` + 说明文字 13pt/20 `text-2`,与正文间 8pt。
37
+
38
+ ### B3. AI 气泡内富文本
39
+ - 关键词高亮:`color-primary-bright` 加粗。
40
+ - 序号列表:`1. 2. 3.` 起头行,悬挂对齐;书名号/【】内容加粗 `text-1`。
41
+
42
+ ---
43
+
44
+ ## C. 选项列表卡(AI 给出可点选项)
45
+
46
+ - 容器:`rgba(255,255,255,0.7)`,radius 20pt,padding 12 16 16。
47
+ - 容器题:15pt `text-2`(「请选择你的借钱用途:」),下距 12pt。
48
+ - 条目:白底 radius 12pt,padding 14 16;题 16pt Medium `text-1` + 右侧 chevron(`icon-arrow-right-blue` 或灰 chevron 16pt);副文 14pt `text-2` 上距 4pt。条目间距 12pt。
49
+ - 变体 `selected`:条目题文字 `color-primary`,边框 1pt `color-primary`(用户刚点过的项)。
50
+
51
+ ---
52
+
53
+ ## D. 建议气泡(「小易猜你想问」)
54
+
55
+ - 区块题:15pt `text-2`(「小易猜你想问」),下距 12pt,左对齐 16pt 边距。
56
+ - pill:白底、1pt `color-primary` 边框、蓝字 14pt,radius-pill,高 32pt,padding 0 16pt;纵向间距 12pt,左对齐流式换行。
57
+
58
+ ---
59
+
60
+ ## E. 数据表格卡(利率表范式)
61
+
62
+ - 白底 radius 20pt padding 16;宽度 343pt。
63
+ - 标题:16pt Medium `text-1`,文字带 `#EDF5FF` 高亮衬底(padding 2 4)。
64
+ - 行 1(参数选择):左 15pt `text-1`,右「当前值 ˅」15pt `text-1` + chevron,行高 44pt,下加分隔线。
65
+ - 行 2(tabs):横排 tab,激活 = 16pt Medium `text-1` + 底部 2pt `text-1` 短下划线(宽≈字宽);非激活 15pt Regular `text-2`;间距 16pt。
66
+ - 数据行:高 44pt,分隔线 `#E9E9E9`;左标签 15pt `text-1`,右值 15pt Semibold `color-red`(利率类)或 `text-1`(普通数值)。
67
+ - 脚注:12pt/18 `text-3`(「*以上利率为我行标准利率…」),上距 8pt。
68
+
69
+ ---
70
+
71
+ ## F. 产品资产卡(我的贷款/持仓范式)
72
+
73
+ - 白底 radius 20pt,padding 16。
74
+ - 头部:产品名 18pt Semibold `text-1`;下行编号 14pt `text-2`(「贷款编号:xxx」);头部区可带 `#F5F6F8` 灰底(padding 16,radius 12)。
75
+ - 汇总面板:奶油渐变 `linear-gradient(90deg,#FEF3E9,#FEFBF7)` radius 12pt padding 16;内部两列——标签 14pt `text-2` 上、金额 20pt DIN Bold `text-1-warm` 下(金额可 24pt)。
76
+ - 提醒气泡标签:`linear-gradient(90deg,#2F86F6,#005DFD)` 白字 13pt,radius 8 8 8 0,padding 6 10,悬浮于进度条起点上方。
77
+ - 进度条:轨道 4pt `#E9ECF2` radius-pill;已还段 `color-primary`;thumb = 白圆 16pt 带 `shadow-float`(素材 `progress-thumb.png`)。
78
+ - 刻度行:两端对齐——左「1期」/右「36期」13pt `text-1`。
79
+ - 日期行:两端「起始时间:…」/「结束时间:…」13pt `text-2`。
80
+
81
+ ---
82
+
83
+ ## G. 对比卡(VS 范式)
84
+
85
+ - 白底 radius 20pt padding 16。
86
+ - 标题 18pt Semibold `text-1` 居左,带 `#EDF5FF` 衬底。
87
+ - 对比头部:左右两个圆角色块(左红 `#F3464A`、右蓝 `linear-gradient(90deg,#2F86F6,#3B73FF)`),radius 16pt,内白字居中:产品名 18pt Semibold + 副文 12pt 白 70% 透明度;中缝叠圆形 VS 徽章(白底 40pt 圆 + `vs-badge.png` 或描边字)。
88
+ - 对比行:三列——左值(红 `color-red` 15pt Semibold 居右)|中标签(`#F5F5F5` 底 radius 4pt padding 4 10,13pt `text-2`)|右值(蓝 `color-primary-bright` 15pt Semibold 居左);行距 16pt。
89
+ - 总结气泡:AI 气泡样式(`#FEFBF7` radius 12pt padding 12 16,15pt/24 `text-1`),置于卡外下方。
90
+
91
+ ---
92
+
93
+ ## H. 要点列表(产品亮点范式)
94
+
95
+ - 区块题 18pt Semibold `text-1`。
96
+ - 条目:`color-primary` 实心圆 18pt 内白字序号(①②③,11pt)+ 条目题 16pt Medium `text-1` 同行;正文 15pt/24 `text-2` 悬挂对齐(缩进 = 圆点宽 + 8pt)。
97
+ - 免责脚注:12pt/18 `text-3`,前缀「*」。
98
+
99
+ ---
100
+
101
+ ## I. 首页「此刻场景」卡片组
102
+
103
+ ### I1. 问候区
104
+ - 左:吉祥物 `robot.png` 64pt 圆形(素材自带圆底可直接用);右:问候语 24pt Semibold `text-1-warm`(「早安,追梦人!」)+ 副文 15pt/24 `text-2` 两行,左间距 12pt。
105
+
106
+ ### I2. 双列促销卡(2 列网格,gap 12pt,等宽 ~166pt)
107
+ - 基底:radius 20pt + `shadow-float`;两种底:
108
+ - `cream`:`linear-gradient(160deg,#FFF7E8,#FEF6ED)`
109
+ - `plain`:白底
110
+ - 结构:3D 插画(顶部,允许溢出卡缘 8–16pt)→ 标题 18pt Semibold `text-1-warm` → 副文 14pt/22 `text-2` → 胶囊按钮 32pt。
111
+ - 按钮:营销卡 = 橙红渐变 `linear-gradient(90deg,#F09404,#EE6723)` 白字 14pt Medium;功能卡 = `color-primary` 白字。
112
+ - 变体 `consultant`(顾问卡):顶部真人照片(radius 12pt,宽满卡)+ 直播徽标(红底白字 10pt pill)+ 题目 16pt Medium(关键词 `color-primary-bright`)+ 副文 14pt `text-2` + 底部「主讲人」描边 pill 12pt `text-2` + 右下黑色圆钮 28pt(白 chevron)。
113
+
114
+ ### I3. 筛选条件列表(绿勾)
115
+ - 区块题 16pt Medium `text-1` 带下划线装饰 + 右侧「进一步筛选 >」14pt `color-primary-bright`。
116
+ - 条目:`icon-check.png` 18pt + 15pt `text-1`,行距 12pt。
117
+
118
+ ---
119
+
120
+ ## J. 徽标与角标
121
+
122
+ | 徽标 | 样式 |
123
+ |---|---|
124
+ | 直播 live | `#F3464A` 底白字 10pt Medium pill,padding 2 8,左白点 6pt |
125
+ | 利率高亮 | `#EDF5FF` 底 `text-1` 16pt,padding 2 4 |
126
+ | 气泡提醒 | 品牌渐变底白字 13pt,radius `8 8 8 0` |
127
+ | 标签底 | `tag-bg.png` 奶油异形底 + 14pt `text-1-warm` |
@@ -0,0 +1,261 @@
1
+ # MBank 设计规范(design-spec)
2
+
3
+ > 唯一权威 token 源。由两套银行 AI 助手设计稿(贷款助手 + 存款助手,MeaXure 导出,45 个画板)程序化采样提炼。
4
+ > 单位约定:正文数值一律 **pt(@1x 设计值)**,导出/截图按 @2x ×2 换算为 px。画布 375pt 宽。
5
+ > 组件级细节见 `references/component-library.md`;生成工作流见 `SKILL.md`。
6
+
7
+ ---
8
+
9
+ ## 1. 卡片设计规范(圆角 / 阴影 / 边框 / 内边距)
10
+
11
+ ### 圆角梯度(radius scale)
12
+
13
+ | Token | 值 | 使用场景 |
14
+ |---|---|---|
15
+ | `radius-xs` | 4pt | 标签底、小色块 |
16
+ | `radius-sm` | 8pt | 进度条、小按钮、行内元素 |
17
+ | `radius-md` | 12pt | **聊天气泡**、列表条目卡、内嵌面板 |
18
+ | `radius-lg` | 20pt | **标准卡片**(白卡/奶油卡/表格卡/选项容器)、首页大卡 |
19
+ | `radius-xl` | 22pt | 特大底部面板/弹层 |
20
+ | `radius-pill` | 100pt | 胶囊按钮、建议气泡、底部输入条 |
21
+ | `radius-circle` | 50% | 圆形图标钮、序号圆点、头像 |
22
+
23
+ ### 气泡非对称圆角(对话强特征,必须遵守)
24
+
25
+ - **AI 气泡**(左侧):`12pt 12pt 12pt 0`(左上直角,其余 12)
26
+ - **用户气泡**(右侧):`12pt 0 12pt 12pt`(右上直角,其余 12)
27
+
28
+ ### 阴影(轻投影,整体偏「浮」不偏「重」)
29
+
30
+ | Token | 值 | 使用场景 |
31
+ |---|---|---|
32
+ | `shadow-float` | `0 2px 6px rgba(134,155,168,0.5)` | 悬浮卡片、首页大卡 |
33
+ | `shadow-soft` | `0 2px 10px rgba(0,0,0,0.2)` | 弹层、模态 |
34
+ | `shadow-none` | 无 | 常规列表卡、表格卡(默认无阴影) |
35
+
36
+ ### 边框
37
+
38
+ - 常规卡片**无边框**,靠背景色差分区。
39
+ - 描边仅两处:建议气泡 `1pt solid #2F86F6`;分隔线 `1pt solid #E9ECF2`(列表内可用 #E9E9E9)。
40
+
41
+ ### 内边距
42
+
43
+ | 容器 | padding |
44
+ |---|---|
45
+ | 标准卡片 | 16pt |
46
+ | 聊天气泡 | 12pt 16pt |
47
+ | 列表条目卡 | 14pt 16pt |
48
+ | 选项容器(包裹层) | 12pt 16pt 16pt |
49
+ | 底部输入条 | 12pt 16pt(左右) |
50
+
51
+ ---
52
+
53
+ ## 2. 尺寸规范(画布 / 卡片 / 组件标准尺寸与断点)
54
+
55
+ ### 画布
56
+
57
+ - 基准:**375 × 812pt**(iPhone X),导出 @2x = **750 × 1624px**。
58
+ - 纵向自适应:内容撑高,最小 812pt;底部固定区(输入条 + Home Indicator)不随内容滚动。
59
+ - 单一移动端断点;本规范不定义平板/桌面断点。内容最大宽度 = 画布宽(无居中限宽)。
60
+
61
+ ### 页面骨架尺寸
62
+
63
+ | 区域 | 尺寸 |
64
+ |---|---|
65
+ | 状态栏 | 高 44pt |
66
+ | 顶部导航(此刻/对话 tabs + 声音/设置) | 高 44pt |
67
+ | 页面左右安全边距 | 16pt(聊天气泡区 12pt) |
68
+ | 底部输入条 | 输入胶囊高 36pt,圆钮 44×44pt |
69
+ | Home Indicator | 高 34pt,黑色横条宽 ~134pt 居中 |
70
+
71
+ ### 组件标准尺寸
72
+
73
+ | 组件 | 尺寸 |
74
+ |---|---|
75
+ | 全宽卡片 | 宽 343pt(375 − 2×16),高按内容 |
76
+ | 首页双列促销卡 | 宽 ~166pt,两列 gap 12pt |
77
+ | 全宽主按钮 | 343 × 48pt,radius 24pt |
78
+ | 胶囊小按钮 | 高 32pt,左右 padding 16pt |
79
+ | 建议气泡 pill | 高 32pt,padding 0 16pt |
80
+ | 选项列表条目 | 高 ≥56pt(单行) |
81
+ | 表格行 | 高 44pt |
82
+ | 进度条 | 高 4pt,圆形 thumb 直径 16pt |
83
+ | 直播徽标 | 高 16pt,radius-pill |
84
+ | 吉祥物头像 | 直径 48–64pt |
85
+
86
+ ---
87
+
88
+ ## 3. 设计节奏(间距梯度 / 栅格)
89
+
90
+ ### 间距梯度(4pt 基数)
91
+
92
+ `4 / 8 / 12 / 16 / 20 / 24 / 32`
93
+
94
+ | 关系 | 值 |
95
+ |---|---|
96
+ | 图标↔文字(行内) | 8pt |
97
+ | 气泡↔气泡(纵向) | 12pt |
98
+ | 卡片↔卡片(纵向) | 12–16pt |
99
+ | 卡内标题↔正文 | 8pt |
100
+ | 卡内正文↔按钮 | 12pt |
101
+ | 区块↔区块(大分组) | 24pt |
102
+ | 页面顶部首个内容 | 16–24pt |
103
+
104
+ ### 栅格
105
+
106
+ - **双列网格**:首页促销卡 2 列,列宽相等,gap 12pt,边距 16pt。
107
+ - **单列流**:对话内容与数据卡全为单列流式,宽 343pt(气泡区 351pt)。
108
+ - 对齐基线统一 4pt 网格;所有测量值必须是 4 的倍数(例外:图标 15/17 等特殊尺寸允许)。
109
+
110
+ ---
111
+
112
+ ## 4. 配色规范
113
+
114
+ ### 主色(品牌蓝系)
115
+
116
+ | Token | 值 | 使用场景 |
117
+ |---|---|---|
118
+ | `color-primary` | `#2F86F6` | 主按钮、选中态、进度条、用户气泡基色 |
119
+ | `color-primary-deep` | `#005DFD` | 用户气泡渐变深端、强调 |
120
+ | `color-primary-bright` | `#3B73FF` | 链接、可点击文本、蓝色图标 |
121
+ | `primary-gradient` | `linear-gradient(90deg,#2F86F6,#005DFD)` | 用户气泡、主 CTA |
122
+
123
+ ### 辅助色(营销/情绪)
124
+
125
+ | Token | 值 | 使用场景 |
126
+ |---|---|---|
127
+ | `color-red` | `#F3464A` | 利率数字、警示、直播徽标、对比卡左方 |
128
+ | `color-orange` | `#F09404` | 活动强调、利息/收益提示 |
129
+ | `color-orange-deep` | `#EE6723` | 橙色 CTA 渐变深端(如 `linear-gradient(90deg,#F09404,#EE6723)`) |
130
+ | `color-green` | `#68C800` | 达成/对勾、筛选条件绿勾 |
131
+
132
+ ### 中性色(文字 + 背景 + 线)
133
+
134
+ | Token | 值 | 使用场景 |
135
+ |---|---|---|
136
+ | `text-1` | `#1F2635` | 主文字(冷调深灰蓝) |
137
+ | `text-1-warm` | `#221715` | 暖调标题(首页问候/营销卡,与暖背景同源) |
138
+ | `text-2` | `#727885` | 次要文字、说明、未激活 tab |
139
+ | `text-3` | `#AAAAAA` | 占位符、脚注、极弱信息 |
140
+ | `bg-page` | `#F2F3F5`(≈`#EFF1F4`) | 页面基底 |
141
+ | `bg-warm-panel` | `#FEFBF7` | AI 气泡(暖白) |
142
+ | `bg-cream` | `#FFF7E8 → #FEF6ED` | 奶油促销卡渐变 |
143
+ | `bg-blue-tint` | `#EDF5FF` | 标题高亮、淡蓝衬底 |
144
+ | `bg-gray-block` | `#F5F6F8` / `#F5F5F5` | 浅灰信息块、对比表中列 |
145
+ | `divider` | `#E9ECF2`(列表内 `#E9E9E9`) | 分隔线 |
146
+
147
+ ### 页面氛围渐变(全 App 签名特征,必须还原)
148
+
149
+ 顶部氛围光 + 下方渐隐:
150
+
151
+ ```css
152
+ background:
153
+ radial-gradient(ellipse 60% 30% at 0% 0%, #DBE3F5 0%, transparent 70%), /* 左上冷蓝 */
154
+ radial-gradient(ellipse 60% 30% at 100% 0%, #EEE6D9 0%, transparent 70%), /* 右上暖奶油 */
155
+ linear-gradient(180deg, #E4E2E4 0%, #EFF1F4 30%, #F7F8FA 70%, #FBFCFC 100%);
156
+ ```
157
+
158
+ 要点:**左冷右暖**的双色晕染只出现在首屏顶部 ~30%,向下收敛为浅灰;对话长页与首页共用。
159
+
160
+ ### 语义色使用规则
161
+
162
+ - 金额/利率涨跌与关键数字:**红 = 值得关注/收益**(`#F3464A`),蓝 = 中性数据(品牌蓝)。
163
+ - 成功/达成 = 绿 `#68C800`;警告/提醒 = 橙 `#F09404`;错误/禁止 = 红 `#F3464A`。
164
+ - 禁止把品牌蓝用于语义警示;禁止在暖色营销卡上用蓝色文字(对比冲突)。
165
+
166
+ ---
167
+
168
+ ## 5. 层级规范(字号 / 字重 / 行高 / 信息层级)
169
+
170
+ ### 字体族
171
+
172
+ - 中文/正文:`PingFang SC`(Regular 400 / Medium 500 / Semibold 600)
173
+ - 数字/金额:`DIN Alternate Bold`;数据表数值可用 `SF Pro Text Semibold`
174
+ - 回退栈:`-apple-system, "PingFang SC", "Helvetica Neue", sans-serif`
175
+
176
+ ### 字阶(7 级)
177
+
178
+ | Token | 字号/行高 | 字重 | 使用场景 |
179
+ |---|---|---|---|
180
+ | `font-hero` | 24 / 34 | Semibold | 首页问候语、大额金额(¥298.69) |
181
+ | `font-display` | 20 / 28 | Semibold + DIN | 金额、核心数值(¥6,000.00) |
182
+ | `font-title` | 18 / 26 | Semibold | 卡片标题、区块题 |
183
+ | `font-nav` | 17 / 24 | Medium | 导航 tab(激活)、大按钮 |
184
+ | `font-body-em` | 16 / 24 | Medium | 卡片条目标题、表格卡标题 |
185
+ | `font-body` | 15 / 24 | Regular | **正文基准**:气泡正文、表格行、列表 |
186
+ | `font-caption` | 14 / 22 | Regular | 辅文、副标题、按钮小字 |
187
+ | `font-footnote` | 13 / 20 | Regular | 脚注、日期行 |
188
+ | `font-note` | 12 / 18 | Regular | 免责/备注(`text-3`) |
189
+ | `font-badge` | 10 / 14 | Medium | 徽标(直播)、角标 |
190
+
191
+ ### 信息层级规则
192
+
193
+ 1. **数字大于文字**:金额/利率永远比同区块标题大(20–24pt vs 16–18pt)。
194
+ 2. 一屏最多一个 `font-hero`;区块内强调只用字重 + 语义色,不新增字号。
195
+ 3. 辅助说明统一降两级(正文 15 → 备注 12–13)并换中性灰,不缩字号凑层级。
196
+ 4. 行高:标题 1.3–1.45,正文 1.5–1.6;数字用 DIN 时行高取 1.2 并与基线对齐。
197
+
198
+ ---
199
+
200
+ ## 6. 布局规范(对齐 / 栅格 / 响应式规则)
201
+
202
+ - **整体轴向**:单列纵向流;无侧栏、无横滑布局(首页双列卡除外)。
203
+ - **对齐**:标题/正文左对齐(默认);数据值(金额/利率)与其标签左对齐成组,或表格行内「标签左、值右」两端对齐;气泡按角色左右贴边分流。
204
+ - **底部固定**:输入条 + Home Indicator 固定底部,内容区从其上方滚动;输入条上方留 12pt 间距。
205
+ - **响应式规则**(内容自适应而非多断点):
206
+ 1. 文本气泡宽度 `max-width: 75%`,超出换行,高度自适应。
207
+ 2. 卡片高度由内容撑开,不写死高度;同类卡片等宽对齐。
208
+ 3. 长页(如产品详情 812→1421pt)只向下增长,骨架区域(导航/输入条)尺寸不变。
209
+ 4. 双列网格内容超长时截断省略(`…`),不挤压列宽。
210
+
211
+ ---
212
+
213
+ ## 7. 风格化(视觉语言 / 质感 / 图标与插画)
214
+
215
+ ### 视觉语言一句话
216
+
217
+ **「暖调 AI 管家」**:冷蓝品牌色承载功能与信任,暖奶油/橙承载营销与温度;扁平 UI 面板 + 3D 轻拟物插画混搭,氛围光背景消除生硬感。
218
+
219
+ ### 质感
220
+
221
+ - UI 面板全扁平:纯色/线性渐变填充 + 大圆角,**无内阴影、无描边、无噪点**。
222
+ - 插画区轻拟物 3D:柔光、软投影、轻微光泽(glossy),禁止硬边扁平插画与线框风。
223
+ - 氛围:柔和、透气、留白充足;背景氛围光让白卡「浮」在页面上。
224
+
225
+ ### 插画风格(3D 金融物件)
226
+
227
+ - 题材:金币、存钱罐、沙漏、银行卡、计算器、进度台座等金融符号。
228
+ - 色域:暖金 `#F6CAA3` / 橙 `#F09404` / 深橙 `#EE6723` 为主,点缀品牌蓝卡片元素。
229
+ - 构图:物件置于卡片右上角或顶部,**允许溢出卡片边缘**(打破边界是设计特征)。
230
+ - 生成关键词(ImageGen 用):`3D render, soft studio light, glossy financial objects, gold coins, warm orange palette, soft shadows, isolated on transparent background, C4D style, octane render`
231
+
232
+ ### 吉祥物
233
+
234
+ - 白色圆脸机器人(`assets/robot.png`,168×168 RGBA):极简面部,橙红色圆腮红/耳点,无复杂五官。
235
+ - 用途:首页问候头像、AI 消息头像。保持原始素材,不重绘。
236
+
237
+ ### 图标
238
+
239
+ - 导航图标:黑色细线性描边(声音、设置,24pt 网格,2pt 描边)。
240
+ - 功能图标:品牌蓝填充或蓝描边(右箭头、对勾)。
241
+ - 素材直接取 `assets/icons/`(icon-sound / icon-settings / icon-voice-switch / icon-arrow-right-blue / icon-check / icon-apps / vs-badge / tag-bg / progress-thumb),等比缩放使用,不重绘。
242
+
243
+ ### 人物照片
244
+
245
+ - 人类顾问/主播用真实照片(圆角 12pt 裁切),与 3D 插画分区使用:真人 = 服务人格化,3D = 内容视觉化。无照片素材时用 ImageGen 生成职业形象照。
246
+
247
+ ### 徽标与标签
248
+
249
+ - 直播徽标:红底 `#F3464A` 白字 10pt,radius-pill,左侧圆点。
250
+ - 标签底图:`assets/icons/tag-bg.png`(奶油色异形标签)。
251
+
252
+ ---
253
+
254
+ ## 附:提炼来源与可信度
255
+
256
+ | 数据 | 来源 | 可信度 |
257
+ |---|---|---|
258
+ | 色值/字号/圆角/阴影频次 | 两套 index.html 内联样式正则统计(top 频次取众数) | 高(设计源数据) |
259
+ | 背景渐变/奶油卡色 | 预览 PNG 逐像素采样(#DBE3F5/#EEE6D9/#EFF1F4/#FFF7E8/#FEF6ED) | 高(实测) |
260
+ | 组件尺寸/间距 | 45 画板目测 + MeaXure 数值交叉 | 中高(±2pt) |
261
+ | 字体族 | MeaXure font-family 统计 | 高 |
@@ -0,0 +1,138 @@
1
+ <!DOCTYPE html>
2
+ <!-- MBank 高保真稿画布模板。用法:复制本文件,替换 <body> 内 slot 区域。
3
+ 画布 375×812pt(@2x 导出 750×1624px)。token 与 references/design-spec.md 一一对应。
4
+ assets 路径按本文件位置相对引用(templates/../assets/);复制到别处时同步调整。 -->
5
+ <html lang="zh-CN">
6
+ <head>
7
+ <meta charset="UTF-8">
8
+ <title>MBank Mockup</title>
9
+ <style>
10
+ /* ===== Design Tokens(唯一取值处,改样式只改这里) ===== */
11
+ :root {
12
+ /* 主色 */
13
+ --c-primary: #2F86F6;
14
+ --c-primary-deep: #005DFD;
15
+ --c-primary-bright: #3B73FF;
16
+ --grad-primary: linear-gradient(90deg, #2F86F6, #005DFD);
17
+ /* 辅助色 */
18
+ --c-red: #F3464A;
19
+ --c-orange: #F09404;
20
+ --c-orange-deep: #EE6723;
21
+ --grad-cta: linear-gradient(90deg, #F09404, #EE6723);
22
+ --c-green: #68C800;
23
+ /* 中性 */
24
+ --text-1: #1F2635;
25
+ --text-1-warm: #221715;
26
+ --text-2: #727885;
27
+ --text-3: #AAAAAA;
28
+ --bg-page: #F2F3F5;
29
+ --bg-warm-panel: #FEFBF7;
30
+ --bg-blue-tint: #EDF5FF;
31
+ --bg-gray-block: #F5F6F8;
32
+ --divider: #E9ECF2;
33
+ /* 圆角 */
34
+ --r-xs: 4px; --r-sm: 8px; --r-md: 12px; --r-lg: 20px; --r-xl: 22px; --r-pill: 100px;
35
+ /* 阴影 */
36
+ --shadow-float: 0 2px 6px rgba(134,155,168,.5);
37
+ --shadow-soft: 0 2px 10px rgba(0,0,0,.2);
38
+ /* 字体 */
39
+ --font: -apple-system, "PingFang SC", "Helvetica Neue", sans-serif;
40
+ --font-num: "DIN Alternate Bold", "SF Pro Text Semibold", var(--font);
41
+ /* 间距 */
42
+ --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
43
+ }
44
+ * { margin: 0; padding: 0; box-sizing: border-box; }
45
+ html, body { width: 375px; }
46
+ body {
47
+ font-family: var(--font); color: var(--text-1); font-size: 15px; line-height: 1.6;
48
+ /* 全 App 签名背景:左冷蓝右暖奶油氛围光 + 向下渐隐 */
49
+ background:
50
+ radial-gradient(ellipse 60% 30% at 0% 0%, #DBE3F5 0%, transparent 70%),
51
+ radial-gradient(ellipse 60% 30% at 100% 0%, #EEE6D9 0%, transparent 70%),
52
+ linear-gradient(180deg, #E4E2E4 0%, #EFF1F4 30%, #F7F8FA 70%, #FBFCFC 100%);
53
+ min-height: 812px; position: relative;
54
+ }
55
+ .canvas { min-height: 812px; display: flex; flex-direction: column; }
56
+
57
+ /* ===== 全局框架 ===== */
58
+ .statusbar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; font-size: 15px; font-weight: 600; }
59
+ .navbar { height: 44px; display: flex; align-items: center; padding: 0 16px; }
60
+ .navbar .tabs { display: flex; gap: 24px; }
61
+ .navbar .tab { font-size: 17px; color: var(--text-2); }
62
+ .navbar .tab.active { color: var(--text-1); font-weight: 500; }
63
+ .navbar .actions { margin-left: auto; display: flex; gap: 16px; align-items: center; }
64
+ .navbar .actions img { width: 24px; height: 24px; }
65
+ .content { flex: 1; padding: var(--sp-4) var(--sp-3); }
66
+ .bottombar { position: sticky; bottom: 0; padding: var(--sp-3) var(--sp-4) 0; display: flex; gap: var(--sp-3); align-items: center; }
67
+ .input-pill { flex: 1; height: 36px; background: #fff; border-radius: var(--r-pill); display: flex; align-items: center; padding: 0 16px; gap: var(--sp-2); color: var(--text-3); font-size: 15px; }
68
+ .grid-btn { width: 44px; height: 44px; border-radius: 50%; background: #fff; box-shadow: var(--shadow-float); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
69
+ .home-indicator { height: 34px; display: flex; align-items: center; justify-content: center; }
70
+ .home-indicator::after { content: ""; width: 134px; height: 5px; border-radius: 3px; background: #000; }
71
+
72
+ /* ===== 气泡 ===== */
73
+ .bubble { max-width: 75%; padding: 12px 16px; font-size: 15px; line-height: 1.6; margin-bottom: var(--sp-3); }
74
+ .bubble.user { margin-left: auto; background: var(--grad-primary); color: #fff; border-radius: 12px 0 12px 12px; }
75
+ .bubble.ai { background: var(--bg-warm-panel); border-radius: 0 12px 12px 12px; }
76
+ .bubble.ai .note { margin-top: var(--sp-2); font-size: 13px; line-height: 1.55; color: var(--text-2); }
77
+ .bubble.ai .hl { color: var(--c-primary-bright); font-weight: 600; }
78
+
79
+ /* ===== 选项列表卡 ===== */
80
+ .option-group { background: rgba(255,255,255,.7); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4) var(--sp-4); margin-bottom: var(--sp-3); }
81
+ .option-group .group-title { font-size: 15px; color: var(--text-2); margin-bottom: var(--sp-3); }
82
+ .option-item { background: #fff; border-radius: var(--r-md); padding: 14px var(--sp-4); display: flex; align-items: center; justify-content: space-between; }
83
+ .option-item + .option-item { margin-top: var(--sp-3); }
84
+ .option-item .t { font-size: 16px; font-weight: 500; }
85
+ .option-item .d { font-size: 14px; color: var(--text-2); margin-top: var(--sp-1); }
86
+ .option-item.selected .t { color: var(--c-primary); }
87
+ .option-item.selected { border: 1px solid var(--c-primary); }
88
+
89
+ /* ===== 建议气泡 ===== */
90
+ .suggestion { padding: 0 var(--sp-1); }
91
+ .suggestion .s-title { font-size: 15px; color: var(--text-2); margin-bottom: var(--sp-3); }
92
+ .suggestion .pill { display: inline-block; height: 32px; line-height: 30px; padding: 0 var(--sp-4); background: #fff; border: 1px solid var(--c-primary); color: var(--c-primary); border-radius: var(--r-pill); font-size: 14px; margin: 0 var(--sp-2) var(--sp-3) 0; }
93
+
94
+ /* ===== 表格卡 ===== */
95
+ .sheet { background: #fff; border-radius: var(--r-lg); padding: var(--sp-4); margin-bottom: var(--sp-3); }
96
+ .sheet .sheet-title { font-size: 16px; font-weight: 500; }
97
+ .sheet .sheet-title mark { background: var(--bg-blue-tint); padding: 2px 4px; }
98
+ .sheet .row { height: 44px; display: flex; align-items: center; justify-content: space-between; font-size: 15px; border-bottom: 1px solid #E9E9E9; }
99
+ .sheet .row:last-of-type { border-bottom: none; }
100
+ .sheet .row .val { color: var(--c-red); font-weight: 600; }
101
+ .sheet .footnote { font-size: 12px; line-height: 1.5; color: var(--text-3); margin-top: var(--sp-2); }
102
+
103
+ /* ===== 主按钮 / 胶囊 ===== */
104
+ .btn-primary { width: 100%; height: 48px; border-radius: 24px; background: var(--c-primary); color: #fff; font-size: 17px; font-weight: 500; display: flex; align-items: center; justify-content: center; }
105
+ .btn-cta { height: 32px; padding: 0 var(--sp-4); border-radius: var(--r-pill); background: var(--grad-cta); color: #fff; font-size: 14px; font-weight: 500; display: inline-flex; align-items: center; }
106
+
107
+ /* ===== 通用卡 ===== */
108
+ .card { background: #fff; border-radius: var(--r-lg); padding: var(--sp-4); margin-bottom: var(--sp-3); }
109
+ .card.float { box-shadow: var(--shadow-float); }
110
+ .card.cream { background: linear-gradient(160deg, #FFF7E8, #FEF6ED); }
111
+ .card .card-title { font-size: 18px; font-weight: 600; color: var(--text-1-warm); }
112
+
113
+ /* ===== slot:在此填充页面内容 ===== */
114
+ </style>
115
+ </head>
116
+ <body>
117
+ <div class="canvas">
118
+ <div class="statusbar"><span>9:41</span><span>▮▮▮</span></div>
119
+ <div class="navbar">
120
+ <div class="tabs"><span class="tab active">此刻</span><span class="tab">对话</span></div>
121
+ <div class="actions">
122
+ <img src="../assets/icons/icon-sound.png" alt="">
123
+ <img src="../assets/icons/icon-settings.png" alt="">
124
+ </div>
125
+ </div>
126
+
127
+ <div class="content">
128
+ <!-- SLOT:页面主体。按 component-library.md 拼装气泡/卡片/表格。 -->
129
+ </div>
130
+
131
+ <div class="bottombar">
132
+ <div class="input-pill">欢迎向小易提问~</div>
133
+ <div class="grid-btn"><img src="../assets/icons/icon-apps.png" width="20" height="20" alt=""></div>
134
+ </div>
135
+ <div class="home-indicator"></div>
136
+ </div>
137
+ </body>
138
+ </html>
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ // MBank mockup 截图工具:把 375×812 的 mockup HTML 导出为 750×1624 @2x PNG。
3
+ // 用法:node <skill>/tools/screenshot.mjs <input.html> [output.png] [--full]
4
+ // --full 整页截图(长页 mockup 用;默认 812pt 视口截断)
5
+ // 依赖 playwright(仓库根 node_modules 已装;本脚本从自身位置向上解析)。
6
+ import { createRequire } from 'node:module';
7
+ import { dirname, resolve } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { pathToFileURL } from 'node:url';
10
+
11
+ const here = dirname(fileURLToPath(import.meta.url));
12
+ const require = createRequire(import.meta.url);
13
+ const { chromium } = require('playwright');
14
+
15
+ const args = process.argv.slice(2);
16
+ const full = args.includes('--full');
17
+ const positional = args.filter((a) => !a.startsWith('--'));
18
+ const input = positional[0];
19
+ if (!input) {
20
+ console.error('usage: node screenshot.mjs <input.html> [output.png] [--full]');
21
+ process.exit(1);
22
+ }
23
+ const output = positional[1] || input.replace(/\.html$/i, '') + '.png';
24
+
25
+ const browser = await chromium.launch();
26
+ const page = await browser.newPage({
27
+ viewport: { width: 375, height: 812 },
28
+ deviceScaleFactor: 2, // @2x → 750 宽输出,与设计稿一致
29
+ });
30
+ await page.goto(pathToFileURL(resolve(input)).href, { waitUntil: 'networkidle' });
31
+ await page.waitForTimeout(300); // 字体/图片稳定
32
+ await page.screenshot({ path: output, fullPage: full });
33
+ await browser.close();
34
+ console.log(output);
@@ -0,0 +1,79 @@
1
+ # 脚本退出码语义(单一权威)
2
+
3
+ > 适用范围:`skills/dsl-card-generator/scripts/` 与 `skills/sketch-spec-to-card/scripts/` 下的
4
+ > 全部脚本(`.mjs` / `.py`)。**本文件是退出码语义的唯一权威**,其它文档只引用、不复述。
5
+ >
6
+ > 服务端记账表在 `server/core/ai-chat.js` 的 `SKILL_EXIT_SEMANTICS`;**本文件是它的来源**,
7
+ > 改动顺序永远是「先改本文件 → 再改记账表 → 跑 `tools/tests/exit-code-contract.test.mjs`」。
8
+
9
+ ## 0. 两条总则
10
+
11
+ 1. **0 = 成功,1 = 未特别声明时的通用失败**。只声明这两条是不够的 —— 见总则 2。
12
+ 2. **退出码语义按脚本查表,不跨脚本外推**。同一个数字在不同脚本里含义可以不同:
13
+ `2` 在 `iterate.mjs` 是「门禁未达标」,在 `gate.mjs` / `ir_merge.mjs` 是「用法错误」。
14
+ **永远按 (脚本名, code) 二元组查表,不要只看数字。**
15
+
16
+ 为什么这条总则值钱:模型(与服务端)天然会把**一切非 0 读成「工具坏了」**,于是去修一个
17
+ 不存在的问题、或原样重试。本链路里大量非 0 其实是**脚本正常跑完、只是结论是负面的**。
18
+
19
+ ## 1. 语义分类(kind)
20
+
21
+ | kind | 含义 | 模型该做什么 | 计入「连续失败」短路 |
22
+ |---|---|---|---|
23
+ | `diagnostic` | 正常跑完,产出就是差异/偏差清单 | 按报告逐项修 | **否** |
24
+ | `gate-fail` | 正常跑完,门禁未达标 | 按 `gate.failed` 逐项改,**不要原样重试** | 是 |
25
+ | `not-ready` | 正常跑完,输入内容尚未就绪 | 补内容后重跑(不是脚本故障) | 是 |
26
+ | `needs-user` | 正常跑完,**必须由用户做选择** | 把清单交给用户,停下等回复 | 是 |
27
+ | `fail` | 真失败(脚本报错 / 用法错误 / IO 失败) | 修调用或修脚本 | 是 |
28
+
29
+ 「计入连续失败」的判定在 `ai-chat.js:1917 skillExecFailure()`:**只有 `diagnostic` 豁免**
30
+ (连 `gate-fail` 都计入 —— 连续三次门禁不过且报错没变,短路提示比再撞一次墙更有用;
31
+ `--ir` 文件变了会换 key,所以「模型确实在改」的连续失败不会被误短路)。
32
+
33
+ ## 2. 必须登记的「非 fail」退出码
34
+
35
+ 下表每一行都会在服务端生成 `exit=N [kind:note]` 首行标签。**漏登记 = 被标成 `fail`**,
36
+ 模型会把「结论负面」当成「工具故障」。
37
+
38
+ | 脚本 | code | kind | 语义 |
39
+ |---|---|---|---|
40
+ | `readiness.mjs` | 3 | not-ready | 内容未就绪(要素 / 变量绑定 / 图片地址 / 切图落盘四类缺口),**不是脚本报错**,按报告逐项补内容后重跑 |
41
+ | `route_input.mjs` | 3 | needs-user | 输入形态判为 `unknown` —— 先问用户这是哪类输入,**不要猜、不要自己挑** |
42
+ | `parse_meaxure.py` | 4 | needs-user | 多画板选择门禁(`rules.md §十三`):脚本故意打印 1..n + 全部清单后退出,**Agent 必须把清单交给用户、停下等回复**,再用 `--pick` / `--scope-all` 重跑 |
43
+ | `iterate.mjs` | 2 | gate-fail | 门禁未达标,报告照常回喂 —— 按 `gate.failed` 逐项改 |
44
+ | `gate.mjs` | 1 | gate-fail | 门禁未过(`autofix → validate → lint → preflight` 任一步 FAIL),按规则号逐条修后重跑 |
45
+ | `preflight.mjs` | 1 | diagnostic | 正常结果:列出若干 Pre-flight 问题,按 code 逐条修 |
46
+ | `check_fidelity.mjs` | 1 | diagnostic | 正常结果:报出文本缺失 / 字号 / 颜色偏差,逐项修 |
47
+ | `lint_card.mjs` | 1 | diagnostic | 正常结果:有 lint 问题,按规则号逐项修 |
48
+ | `diff_bands.mjs` | 1 | diagnostic | 正常结果:渲染与设计的逐带差异非空 |
49
+ | `check_magic_values.mjs` | 70 | diagnostic | 正常结果:发现魔法值,改用 `lib/layout-tokens.mjs` 的 `T.*`(`70` 是历史取值,勿按数字猜语义) |
50
+ | `render_baseline.mjs` | 70 | diagnostic | 同 `check_magic_values`,历史取值 |
51
+
52
+ ## 3. 其余常见退出码(按 `fail` 处理,无需单独登记)
53
+
54
+ | 脚本 | code | 语义 |
55
+ |---|---|---|
56
+ | `expand_ir.mjs` | 1 | `validate` 未通过(报错文本写了具体项) |
57
+ | `expand_ir.mjs` | 3 | IR 含非法字段(报错已给合法值全集),改键名即可,**不要重写整份 IR** |
58
+ | `ir_restore.mjs` | 1 / 3 | 参数或文件不对 / 快照不是合法 JSON |
59
+ | `extract_subtree.mjs` | 3 | 写文件失败(IO) |
60
+ | `gate.mjs` / `ir_merge.mjs` / `describe_card.mjs` / `diff_card.mjs` / `apply_opacity_pattern.mjs` | 2 | 用法 / 参数错误 |
61
+ | `readiness.mjs` / `route_input.mjs` / `ir_merge.mjs` | 1 | 用法 / 参数错误 |
62
+
63
+ ## 4. 为什么 `iterate.mjs` 的「门禁未达标」是 `2` 而不是 `5`
64
+
65
+ 2026-09-24 的链路审计报告曾建议「统一为 `5 = 门禁未收敛`」。**评估后不采纳**,理由:
66
+
67
+ 1. **已被生产链路消费**:`SKILL_EXIT_SEMANTICS['iterate.mjs'][2]` 已是 `gate-fail`,
68
+ 语义标签与"是否计入连续失败"都按它工作;改数字是纯粹的破坏性变更,收益为零。
69
+ 2. **服务端按 (脚本, code) 查表**,不按数字跨脚本解释 —— 总则 2 已经解决了"同一个 2 两个含义"
70
+ 的问题,不需要靠换数字来解决。
71
+ 3. 报告的真实目标(「避免把收敛失败/未就绪记成工具故障」)**已由 kind 机制达成**;
72
+ 本轮做的是把它补全(§2 表里 `readiness` / `route_input` / `parse_meaxure` 三行此前缺失)。
73
+
74
+ ## 5. 新增脚本时的清单
75
+
76
+ 1. 决定了非 0 语义 → **先加进本文件 §2**(kind 四选一)。
77
+ 2. 同步加进 `server/core/ai-chat.js` 的 `SKILL_EXIT_SEMANTICS`。
78
+ 3. `npm test` 跑 `tools/tests/exit-code-contract.test.mjs`,它会断言「本文件 §2 每行都在记账表里」。
79
+ 4. 改完 `ai-chat.js` **必须重启 `npm run dev`**(后端无热重载,旧进程会继续跑旧代码)。