cardbuddy 0.11.0 → 0.12.1

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 (313) hide show
  1. package/README.md +46 -5
  2. package/dist/cli.js +51 -1
  3. package/dist/config.js +51 -16
  4. package/dist/core.js +2 -2
  5. package/dist/init.js +425 -0
  6. package/dist/preview-editor/assets/index-CHuGGIR3.js +276 -0
  7. package/dist/preview-editor/assets/{index-B4VZgNSK.css → index-CQScMhyg.css} +1 -1
  8. package/dist/preview-editor/index.html +2 -2
  9. package/dist/standalone.js +8 -0
  10. package/dist/vendored/mcp/client.mjs +537 -0
  11. package/dist/vendored/mcp/tools.mjs +268 -0
  12. package/dist/vendored/preview/assets/default-image.png +0 -0
  13. package/dist/{server-core → vendored/server/core}/ai-chat.js +82 -38
  14. package/dist/{server-core → vendored/server/core}/browser.js +1 -1
  15. package/dist/{server-core → vendored/server/core}/cardSave.js +8 -3
  16. package/dist/{server-core → vendored/server/core}/cardSync.js +6 -14
  17. package/dist/{server-core → vendored/server/core}/cardValidate.js +11 -8
  18. package/dist/{server-core → vendored/server/core}/index.js +5 -3
  19. package/dist/vendored/server/core/skillPaths.js +124 -0
  20. package/dist/{server-core → vendored/server/core}/sliceUpload.js +5 -8
  21. package/dist/vendored/skills/README.md +93 -0
  22. package/dist/vendored/skills/card-doctor/SKILL.md +52 -0
  23. package/dist/vendored/skills/card-skill-trainer/SKILL.md +312 -0
  24. package/dist/vendored/skills/card-skill-trainer/baselines/v3-r038n.json +43 -0
  25. package/dist/vendored/skills/card-skill-trainer/baselines/v3-r039n.json +47 -0
  26. package/dist/vendored/skills/card-skill-trainer/baselines/v3-r050n.json +48 -0
  27. package/dist/vendored/skills/card-skill-trainer/scripts/build_dataset.py +472 -0
  28. package/dist/vendored/skills/card-skill-trainer/scripts/build_sample.mjs +162 -0
  29. package/dist/vendored/skills/card-skill-trainer/scripts/diagnose_case.mjs +241 -0
  30. package/dist/vendored/skills/card-skill-trainer/scripts/lib/scoring.mjs +525 -0
  31. package/dist/vendored/skills/card-skill-trainer/scripts/round_diff.mjs +133 -0
  32. package/dist/vendored/skills/card-skill-trainer/scripts/run_round.mjs +1043 -0
  33. package/dist/vendored/skills/card-skill-trainer/scripts/score_round.mjs +195 -0
  34. package/dist/vendored/skills/card-skill-trainer/scripts/test_missing_slice.py +122 -0
  35. package/dist/vendored/skills/dsl-card-ai/SKILL.md +191 -0
  36. package/dist/vendored/skills/dsl-card-generator/SKILL.md +480 -0
  37. package/dist/vendored/skills/dsl-card-generator/config/render-contract.json +11 -0
  38. package/dist/vendored/skills/dsl-card-generator/references/amount_formatting.md +138 -0
  39. package/dist/vendored/skills/dsl-card-generator/references/card_index.json +1597 -0
  40. package/dist/vendored/skills/dsl-card-generator/references/card_templates.json +384 -0
  41. package/dist/vendored/skills/dsl-card-generator/references/card_to_summary.md +56 -0
  42. package/dist/vendored/skills/dsl-card-generator/references/component_rules.md +76 -0
  43. package/dist/vendored/skills/dsl-card-generator/references/component_specs.md +393 -0
  44. package/dist/vendored/skills/dsl-card-generator/references/dsl_structure.md +208 -0
  45. package/dist/vendored/skills/dsl-card-generator/references/event_patterns.md +287 -0
  46. package/dist/vendored/skills/dsl-card-generator/references/expression_engine.md +121 -0
  47. package/dist/vendored/skills/dsl-card-generator/references/field_name_dict.json +34 -0
  48. package/dist/vendored/skills/dsl-card-generator/references/field_naming.md +101 -0
  49. package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +928 -0
  50. package/dist/vendored/skills/dsl-card-generator/references/handcrafted/README.md +69 -0
  51. package/dist/vendored/skills/dsl-card-generator/references/handcrafted/examples_index.json +2967 -0
  52. package/dist/vendored/skills/dsl-card-generator/references/handcrafted/patterns.json +2835 -0
  53. package/dist/vendored/skills/dsl-card-generator/references/handcrafted/recipes_v2.json +648 -0
  54. package/dist/vendored/skills/dsl-card-generator/references/handcrafted/recipes_v2_schema.md +295 -0
  55. package/dist/vendored/skills/dsl-card-generator/references/image_diff.md +48 -0
  56. package/dist/vendored/skills/dsl-card-generator/references/image_to_card.md +129 -0
  57. package/dist/vendored/skills/dsl-card-generator/references/ir-format.md +212 -0
  58. package/dist/vendored/skills/dsl-card-generator/references/message-center-pattern.md +149 -0
  59. package/dist/vendored/skills/dsl-card-generator/references/platform_jsapi.md +196 -0
  60. package/dist/vendored/skills/dsl-card-generator/references/previewer_contract.md +54 -0
  61. package/dist/vendored/skills/dsl-card-generator/references/quickref.md +197 -0
  62. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/absolute-badge.json +84 -0
  63. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/accordion-group-toggle.json +18 -0
  64. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/alertCard-pair.json +12 -0
  65. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/alertDialog-call.json +12 -0
  66. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/canvas-countdown.json +15 -0
  67. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/canvas-donut.json +15 -0
  68. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/canvas-gauge-score.json +11 -0
  69. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/canvas-radar.json +10 -0
  70. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/canvas-title-head.json +13 -0
  71. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/globalSet.json +12 -0
  72. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/label-col-modes.json +21 -0
  73. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/list-expand-collapse.json +17 -0
  74. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/money-format.json +11 -0
  75. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/opacity-switch.json +130 -0
  76. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/progress-bar.json +25 -0
  77. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/tab-billMode.json +15 -0
  78. package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/title-underline-overlay.json +21 -0
  79. package/dist/vendored/skills/dsl-card-generator/references/recipes.md +797 -0
  80. package/dist/vendored/skills/dsl-card-generator/references/rules.md +235 -0
  81. package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +177 -0
  82. package/dist/vendored/skills/dsl-card-generator/references/spec_to_schema_patterns.md +609 -0
  83. package/dist/vendored/skills/dsl-card-generator/references/ui_fidelity_rules.md +131 -0
  84. package/dist/vendored/skills/dsl-card-generator/scripts/add_component.mjs +118 -0
  85. package/dist/vendored/skills/dsl-card-generator/scripts/analyze_component_usage.mjs +153 -0
  86. package/dist/vendored/skills/dsl-card-generator/scripts/apply_opacity_pattern.mjs +343 -0
  87. package/dist/vendored/skills/dsl-card-generator/scripts/build_card_index.mjs +108 -0
  88. package/dist/vendored/skills/dsl-card-generator/scripts/build_card_templates.mjs +190 -0
  89. package/dist/vendored/skills/dsl-card-generator/scripts/check_fidelity.mjs +257 -0
  90. package/dist/vendored/skills/dsl-card-generator/scripts/check_magic_values.mjs +79 -0
  91. package/dist/vendored/skills/dsl-card-generator/scripts/crop_slices.mjs +98 -0
  92. package/dist/vendored/skills/dsl-card-generator/scripts/describe_card.mjs +265 -0
  93. package/dist/vendored/skills/dsl-card-generator/scripts/diff_bands.mjs +257 -0
  94. package/dist/vendored/skills/dsl-card-generator/scripts/diff_card.mjs +316 -0
  95. package/dist/vendored/skills/dsl-card-generator/scripts/expand_ir.mjs +873 -0
  96. package/dist/vendored/skills/dsl-card-generator/scripts/extract_handcrafted.py +1199 -0
  97. package/dist/vendored/skills/dsl-card-generator/scripts/extract_subtree.mjs +191 -0
  98. package/dist/vendored/skills/dsl-card-generator/scripts/generate_cards.mjs +389 -0
  99. package/dist/vendored/skills/dsl-card-generator/scripts/inventory_schemas.py +160 -0
  100. package/dist/vendored/skills/dsl-card-generator/scripts/iterate.mjs +700 -0
  101. package/dist/vendored/skills/dsl-card-generator/scripts/lib/design_image.mjs +56 -0
  102. package/dist/vendored/skills/dsl-card-generator/scripts/lib/design_sample.mjs +328 -0
  103. package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout-tokens.mjs +79 -0
  104. package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.mjs +103 -0
  105. package/dist/vendored/skills/dsl-card-generator/scripts/lib/scaffold.mjs +575 -0
  106. package/dist/vendored/skills/dsl-card-generator/scripts/lib/slicePath.mjs +81 -0
  107. package/dist/vendored/skills/dsl-card-generator/scripts/lib/slice_dedupe.mjs +147 -0
  108. package/dist/vendored/skills/dsl-card-generator/scripts/lint_autofix.mjs +363 -0
  109. package/dist/vendored/skills/dsl-card-generator/scripts/lint_card.mjs +1399 -0
  110. package/dist/vendored/skills/dsl-card-generator/scripts/preflight.mjs +249 -0
  111. package/dist/vendored/skills/dsl-card-generator/scripts/register_card_template.mjs +208 -0
  112. package/dist/vendored/skills/dsl-card-generator/scripts/render_baseline.mjs +231 -0
  113. package/dist/vendored/skills/dsl-card-generator/scripts/render_card.mjs +801 -0
  114. package/dist/vendored/skills/dsl-card-generator/scripts/render_diff.mjs +239 -0
  115. package/dist/vendored/skills/dsl-card-generator/scripts/resolve_card_template.mjs +73 -0
  116. package/dist/vendored/skills/dsl-card-generator/scripts/route_input.mjs +447 -0
  117. package/dist/vendored/skills/dsl-card-generator/scripts/scaffold_card.mjs +81 -0
  118. package/dist/vendored/skills/dsl-card-generator/scripts/slices_normalize.mjs +316 -0
  119. package/dist/vendored/skills/dsl-card-generator/scripts/spec_audit.mjs +462 -0
  120. package/dist/vendored/skills/dsl-card-generator/scripts/spec_to_schema_v3.mjs +7735 -0
  121. package/dist/vendored/skills/dsl-card-generator/scripts/spec_tree.mjs +355 -0
  122. package/dist/vendored/skills/dsl-card-generator/scripts/validate_all_schemas.py +71 -0
  123. package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/default-image-wzZYQ86K.png +0 -0
  124. package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-C9k-07y7.css +1 -0
  125. package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/standalone-oFRM4f4V.js +55 -0
  126. package/dist/vendored/skills/dsl-card-generator/vendor/preview/assets/svg-symbols-B2exBrAr.svg +118 -0
  127. package/dist/vendored/skills/dsl-card-generator/vendor/preview/meta/component-meta.json +2714 -0
  128. package/dist/vendored/skills/dsl-card-generator/vendor/preview/meta/directive-meta.json +40 -0
  129. package/dist/vendored/skills/dsl-card-generator/vendor/preview/meta/style-meta.json +1086 -0
  130. package/dist/vendored/{standalone.html → skills/dsl-card-generator/vendor/preview/standalone.html} +2 -1
  131. package/dist/vendored/skills/finmall-card-sync/SKILL.md +262 -0
  132. package/dist/vendored/skills/finmall-session-navigator/SKILL.md +169 -0
  133. package/dist/vendored/skills/finmall-session-navigator/scripts/finmall_login.mjs +882 -0
  134. package/dist/vendored/skills/finmall-session-navigator/scripts/package-lock.json +59 -0
  135. package/dist/vendored/skills/finmall-session-navigator/scripts/package.json +10 -0
  136. package/dist/vendored/skills/finmall-session-navigator/scripts/session-manager.mjs +96 -0
  137. package/dist/vendored/skills/shared/README.md +55 -0
  138. package/dist/vendored/skills/shared/auth-model.md +79 -0
  139. package/dist/vendored/skills/sketch-spec-to-card/SKILL.md +329 -0
  140. package/dist/vendored/skills/sketch-spec-to-card/references/boundary.json +14 -0
  141. package/dist/vendored/skills/sketch-spec-to-card/references/card_refs.json +13 -0
  142. package/dist/vendored/skills/sketch-spec-to-card/references/spec-schema.md +103 -0
  143. package/dist/vendored/skills/sketch-spec-to-card/scripts/build_prompt.py +797 -0
  144. package/dist/vendored/skills/sketch-spec-to-card/scripts/card_refs.py +94 -0
  145. package/dist/vendored/skills/sketch-spec-to-card/scripts/cluster_states.py +706 -0
  146. package/dist/vendored/skills/sketch-spec-to-card/scripts/parse_meaxure.py +1781 -0
  147. package/dist/vendored/skills/sketch-spec-to-card/scripts/png_utils.py +318 -0
  148. package/dist/vendored/skills/sketch-spec-to-card/scripts/vision.py +1118 -0
  149. package/dist/vendored/templates/helloCard/data.json +10 -0
  150. package/dist/vendored/templates/helloCard/schema.json +238 -0
  151. package/dist/vendored/tools/link-skills.mjs +485 -0
  152. package/package.json +2 -1
  153. package/dist/preview-editor/assets/index-jl4YJzKv.js +0 -180
  154. package/dist/vendored/App.vue +0 -2858
  155. package/dist/vendored/ansi.js +0 -185
  156. package/dist/vendored/assets/apple-touch-icon.png +0 -0
  157. package/dist/vendored/assets/default-image.png +0 -0
  158. package/dist/vendored/assets/favicon-16.png +0 -0
  159. package/dist/vendored/assets/favicon-32.png +0 -0
  160. package/dist/vendored/assets/site-icon.png +0 -0
  161. package/dist/vendored/assets/svgIcons/icons.svg +0 -87
  162. package/dist/vendored/assets/svgIcons/index.js +0 -39
  163. package/dist/vendored/components/AiSettings.vue +0 -392
  164. package/dist/vendored/components/AlertCardInstance.vue +0 -58
  165. package/dist/vendored/components/AlertCardLayer.vue +0 -59
  166. package/dist/vendored/components/ApiCallPanel.vue +0 -127
  167. package/dist/vendored/components/ApiPayloadTree.vue +0 -201
  168. package/dist/vendored/components/AppToast.vue +0 -37
  169. package/dist/vendored/components/CardGallery.vue +0 -291
  170. package/dist/vendored/components/CardPreview.vue +0 -72
  171. package/dist/vendored/components/CardSelect.vue +0 -206
  172. package/dist/vendored/components/ChatComposer.vue +0 -413
  173. package/dist/vendored/components/ChatMessage.vue +0 -383
  174. package/dist/vendored/components/ChatPanel.vue +0 -937
  175. package/dist/vendored/components/ComponentPalette.vue +0 -301
  176. package/dist/vendored/components/ConfirmDialog.vue +0 -54
  177. package/dist/vendored/components/DatePickerOverlay.vue +0 -345
  178. package/dist/vendored/components/DebugPanel.vue +0 -1734
  179. package/dist/vendored/components/DeviceOverlay.vue +0 -70
  180. package/dist/vendored/components/Dropdown.vue +0 -193
  181. package/dist/vendored/components/EventEditor.vue +0 -273
  182. package/dist/vendored/components/HoverGuides.vue +0 -122
  183. package/dist/vendored/components/JsonTree.vue +0 -547
  184. package/dist/vendored/components/LogValue.vue +0 -52
  185. package/dist/vendored/components/MarkdownBody.vue +0 -64
  186. package/dist/vendored/components/NewCardDialog.vue +0 -132
  187. package/dist/vendored/components/NodeInspector.vue +0 -295
  188. package/dist/vendored/components/NumberStepper.vue +0 -125
  189. package/dist/vendored/components/PickerOverlay.vue +0 -131
  190. package/dist/vendored/components/PropControl.vue +0 -245
  191. package/dist/vendored/components/PropTree.vue +0 -128
  192. package/dist/vendored/components/RemotePreview.vue +0 -173
  193. package/dist/vendored/components/SelectionOverlay.vue +0 -105
  194. package/dist/vendored/components/StructureTree.vue +0 -1002
  195. package/dist/vendored/components/Switch.vue +0 -38
  196. package/dist/vendored/components/setters/SetBgPosition.vue +0 -64
  197. package/dist/vendored/components/setters/SetBgSize.vue +0 -90
  198. package/dist/vendored/components/setters/SetCode.vue +0 -198
  199. package/dist/vendored/components/setters/SetColor.vue +0 -244
  200. package/dist/vendored/components/setters/SetCustomSelect.vue +0 -58
  201. package/dist/vendored/components/setters/SetExpr.vue +0 -107
  202. package/dist/vendored/components/setters/SetGradient.vue +0 -125
  203. package/dist/vendored/components/setters/SetGrid9.vue +0 -68
  204. package/dist/vendored/components/setters/SetIconSelect.vue +0 -67
  205. package/dist/vendored/components/setters/SetIfForm.vue +0 -61
  206. package/dist/vendored/components/setters/SetImage.vue +0 -43
  207. package/dist/vendored/components/setters/SetList.vue +0 -139
  208. package/dist/vendored/components/setters/SetNumber.vue +0 -118
  209. package/dist/vendored/components/setters/SetNumberStyle.vue +0 -113
  210. package/dist/vendored/components/setters/SetPadding.vue +0 -77
  211. package/dist/vendored/components/setters/SetSegment.vue +0 -160
  212. package/dist/vendored/components/setters/SetSelect.vue +0 -51
  213. package/dist/vendored/components/setters/SetSwitch.vue +0 -49
  214. package/dist/vendored/components/setters/SetText.vue +0 -52
  215. package/dist/vendored/components/setters/props.js +0 -23
  216. package/dist/vendored/fidelity/baseline-messageOverview.json +0 -87
  217. package/dist/vendored/fidelity/calibration.json +0 -29
  218. package/dist/vendored/fidelity/fidelity-messageOverview-after.html +0 -114
  219. package/dist/vendored/fidelity/fidelity-messageOverview-after.json +0 -272
  220. package/dist/vendored/fidelity/fidelity-messageOverview.html +0 -185
  221. package/dist/vendored/fidelity/fidelity-messageOverview.json +0 -336
  222. package/dist/vendored/fidelity/fidelity-messageOverview_v2.html +0 -262
  223. package/dist/vendored/fidelity/fidelity-messageOverview_v2.json +0 -502
  224. package/dist/vendored/fidelity/fidelity-messageOverview_v3.html +0 -201
  225. package/dist/vendored/fidelity/fidelity-messageOverview_v3.json +0 -417
  226. package/dist/vendored/fidelity/fidelity-messageOverview_visual.html +0 -125
  227. package/dist/vendored/fidelity/fidelity-messageOverview_visual.json +0 -338
  228. package/dist/vendored/index.html +0 -16
  229. package/dist/vendored/main.js +0 -37
  230. package/dist/vendored/runtime/ai-api.js +0 -165
  231. package/dist/vendored/runtime/alert-card.js +0 -125
  232. package/dist/vendored/runtime/app-toast.js +0 -33
  233. package/dist/vendored/runtime/clipboard-node.js +0 -78
  234. package/dist/vendored/runtime/clipboard.js +0 -29
  235. package/dist/vendored/runtime/event-model.js +0 -300
  236. package/dist/vendored/runtime/hoverGuide.js +0 -31
  237. package/dist/vendored/runtime/jsapi-mock.js +0 -256
  238. package/dist/vendored/runtime/markdown.js +0 -140
  239. package/dist/vendored/runtime/node-model.js +0 -217
  240. package/dist/vendored/skills/.manifest.json +0 -1101
  241. package/dist/vendored/standalone-main.js +0 -36
  242. package/dist/vendored/styles/ai-chat.css +0 -1850
  243. package/dist/vendored/styles/app.css +0 -3648
  244. package/dist/vendored/styles/card-gallery.css +0 -285
  245. package/dist/vendored/styles/card-select.css +0 -288
  246. package/dist/vendored/styles/components.css +0 -383
  247. package/dist/vendored/styles/dropdown.css +0 -324
  248. package/dist/vendored/styles/json-tree.css +0 -308
  249. package/dist/vendored/styles/node-inspector.css +0 -800
  250. package/dist/vendored/styles/setters.css +0 -1050
  251. package/dist/vendored/styles/standalone.css +0 -27
  252. package/dist/vendored/styles/structure-tree.css +0 -460
  253. /package/dist/vendored/{api.js → preview/api.js} +0 -0
  254. /package/dist/vendored/{assets → preview/assets}/svg-symbols.svg +0 -0
  255. /package/dist/vendored/{components → preview/components}/AbsoluteLayout.vue +0 -0
  256. /package/dist/vendored/{components → preview/components}/Button.vue +0 -0
  257. /package/dist/vendored/{components → preview/components}/Canvas.vue +0 -0
  258. /package/dist/vendored/{components → preview/components}/CheckGroup.vue +0 -0
  259. /package/dist/vendored/{components → preview/components}/Column.vue +0 -0
  260. /package/dist/vendored/{components → preview/components}/CustomPlaceholder.vue +0 -0
  261. /package/dist/vendored/{components → preview/components}/Divider.vue +0 -0
  262. /package/dist/vendored/{components → preview/components}/GridLayout.vue +0 -0
  263. /package/dist/vendored/{components → preview/components}/Icon.vue +0 -0
  264. /package/dist/vendored/{components → preview/components}/Image.vue +0 -0
  265. /package/dist/vendored/{components → preview/components}/Input.vue +0 -0
  266. /package/dist/vendored/{components → preview/components}/ListLayout.vue +0 -0
  267. /package/dist/vendored/{components → preview/components}/Map.vue +0 -0
  268. /package/dist/vendored/{components → preview/components}/MultiColumn.vue +0 -0
  269. /package/dist/vendored/{components → preview/components}/MultiText.vue +0 -0
  270. /package/dist/vendored/{components → preview/components}/ProgressSlider.vue +0 -0
  271. /package/dist/vendored/{components → preview/components}/RadioButton.vue +0 -0
  272. /package/dist/vendored/{components → preview/components}/RenderTree.vue +0 -0
  273. /package/dist/vendored/{components → preview/components}/Root.vue +0 -0
  274. /package/dist/vendored/{components → preview/components}/Row.vue +0 -0
  275. /package/dist/vendored/{components → preview/components}/SvgCode.vue +0 -0
  276. /package/dist/vendored/{components → preview/components}/SvgSymbols.vue +0 -0
  277. /package/dist/vendored/{components → preview/components}/Text.vue +0 -0
  278. /package/dist/vendored/{components → preview/components}/Video.vue +0 -0
  279. /package/dist/vendored/{components → preview/components}/ViewContainer.vue +0 -0
  280. /package/dist/vendored/{components → preview/components}/base.js +0 -0
  281. /package/dist/vendored/{components → preview/components}/icons.js +0 -0
  282. /package/dist/vendored/{components → preview/components}/index.js +0 -0
  283. /package/dist/vendored/{meta → preview/meta}/component-meta.json +0 -0
  284. /package/dist/vendored/{meta → preview/meta}/directive-meta.json +0 -0
  285. /package/dist/vendored/{meta → preview/meta}/style-meta.json +0 -0
  286. /package/dist/vendored/{runtime → preview/runtime}/StyleParser.js +0 -0
  287. /package/dist/vendored/{runtime → preview/runtime}/adapter.js +0 -0
  288. /package/dist/vendored/{runtime → preview/runtime}/assets.js +0 -0
  289. /package/dist/vendored/{runtime → preview/runtime}/canvas-context.js +0 -0
  290. /package/dist/vendored/{runtime → preview/runtime}/card-runtime.js +0 -0
  291. /package/dist/vendored/{runtime → preview/runtime}/evaluate.js +0 -0
  292. /package/dist/vendored/{runtime → preview/runtime}/property.js +0 -0
  293. /package/dist/vendored/{runtime → preview/runtime}/selectionOverlay.js +0 -0
  294. /package/dist/vendored/{runtime → preview/runtime}/toPreview.js +0 -0
  295. /package/dist/{server-core → vendored/server/core}/assetProxy.js +0 -0
  296. /package/dist/{server-core → vendored/server/core}/bbox.js +0 -0
  297. /package/dist/{server-core → vendored/server/core}/buildDataFromSchema.js +0 -0
  298. /package/dist/{server-core → vendored/server/core}/cardFiles.js +0 -0
  299. /package/dist/{server-core → vendored/server/core}/cardHistory.js +0 -0
  300. /package/dist/{server-core → vendored/server/core}/cardImage.js +0 -0
  301. /package/dist/{server-core → vendored/server/core}/cardImportMeta.js +0 -0
  302. /package/dist/{server-core → vendored/server/core}/cardListCache.js +0 -0
  303. /package/dist/{server-core → vendored/server/core}/cardOpenFolder.js +0 -0
  304. /package/dist/{server-core → vendored/server/core}/cardSidecar.js +0 -0
  305. /package/dist/{server-core → vendored/server/core}/codeBridge.js +0 -0
  306. /package/dist/{server-core → vendored/server/core}/logStream.js +0 -0
  307. /package/dist/{server-core → vendored/server/core}/logger.js +0 -0
  308. /package/dist/{server-core → vendored/server/core}/nodeModels.js +0 -0
  309. /package/dist/{server-core → vendored/server/core}/renderStatus.js +0 -0
  310. /package/dist/{server-core → vendored/server/core}/screenshot.js +0 -0
  311. /package/dist/{server-core → vendored/server/core}/sliceStatic.js +0 -0
  312. /package/dist/vendored/{meta → skills/dsl-card-generator/vendor/preview/meta}/action-meta.json +0 -0
  313. /package/dist/{server-core/_vendor → vendored/tools}/finmall-env.mjs +0 -0
@@ -70,12 +70,14 @@ export {
70
70
  /**
71
71
  * 把全部卡片中间件挂到 Connect 风格容器(需实现 .use(mw))。
72
72
  * @param {{ use: (mw: Function) => void }} app
73
- * @param {{ root: string, viteServer?: import('vite').ViteDevServer | null, upstream?: string, notify?: (data: object, event?: string) => void, watchFile?: (file: string, cb: () => void) => { close: () => void } }} opts
73
+ * @param {{ root: string, viteServer?: import('vite').ViteDevServer | null, upstream?: string, notify?: (data: object, event?: string) => void, watchFile?: (file: string, cb: () => void) => { close: () => void }, allowDispatch?: boolean }} opts
74
74
  * - upstream:FinMall 远端站点基址(来自 FINMALL_BASE_URL),资源代理回源用;空串表示不回源。
75
75
  * - notify:SSE 推送入口(cardbuddy 的 /__events hub);代码桥经它推 bridge 事件,缺省时静默降级。
76
76
  * - watchFile:代码桥单文件监听能力注入(chokidar 版);缺省代码桥用 fs.watch 兜底。
77
+ * - allowDispatch:AI 的 card_patch 是否走 card_write 管线(历史快照 + 校验)。仓库内运行由
78
+ * 「root === 仓库根」自动成立;cardbuddy 发布态代码快照在包内,需宿主显式开启。
77
79
  */
78
- export function mountCoreMiddlewares(app, { root, viteServer = null, upstream = '', notify = null, watchFile = null }) {
80
+ export function mountCoreMiddlewares(app, { root, viteServer = null, upstream = '', notify = null, watchFile = null, allowDispatch = false }) {
79
81
  app.use(createSyncMiddleware({ root }))
80
82
  app.use(createPreviewMiddleware({ root }))
81
83
  app.use(createLoginCredentialsMiddleware({ root }))
@@ -110,5 +112,5 @@ export function mountCoreMiddlewares(app, { root, viteServer = null, upstream =
110
112
  // upstream 空串时中间件仍会注册,但 /minio 等请求只会走占位图兜底,不会崩溃。
111
113
  app.use(createAssetProxyMiddleware({ root, upstream }))
112
114
  // AI 聊天:POST /__ai/chat 流式调用用户自带 LLM,工具调度复用 mcp/tools.mjs
113
- app.use(createAiChatMiddleware({ root }))
115
+ app.use(createAiChatMiddleware({ root, allowDispatch }))
114
116
  }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * 技能资源(脚本 / 文档)路径解析 —— 「仓库内运行」与「npm 包安装态(cardbuddy)」的唯一差异点。
3
+ *
4
+ * 背景:server/core 既被仓库内的 dev server 直接加载,也被 cardbuddy 构建期内联进 npm 包
5
+ * (发布态落点 <pkg>/dist/vendored/server/core)。两种形态下 skills/ 的位置不同:
6
+ * - 仓库内运行: <repo>/skills (本文件的上两级即仓库根)
7
+ * - 消费者项目: <project>/skills (跑过 `cardbuddy init` 后由包内快照释放)
8
+ * - 包内快照: <pkg>/dist/vendored/skills (构建期从仓库 skills/ 内联,随包发布)
9
+ *
10
+ * 解析优先级(只读用途):configureSkillPaths 显式指定 > DSL_SKILLS_ROOT > <root>/skills > 包内快照。
11
+ * 写入用途(如 FinMall 凭据落盘)一律走 projectSkillsDir(root) —— 绝不写进 node_modules,
12
+ * 否则重装即丢、且多项目互相污染。
13
+ */
14
+ import fs from 'node:fs'
15
+ import path from 'node:path'
16
+ import { fileURLToPath } from 'node:url'
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
19
+
20
+ /**
21
+ * 快照根 = 本文件所在目录的上两级。
22
+ * 仓库内:<repo>/server/core → <repo>(真仓库根,skills/ 就在其下)
23
+ * 发布态:<pkg>/dist/vendored/server/core → <pkg>/dist/vendored(构建期内联的迷你仓库快照)
24
+ * 两种形态下 `<SNAPSHOT_ROOT>/skills` 都指向「随代码走的那份技能库」,故可作统一兜底。
25
+ */
26
+ export const SNAPSHOT_ROOT = path.resolve(__dirname, '..', '..')
27
+
28
+ /**
29
+ * 候选 skills 根,按优先级排列(去重,只保留磁盘上真实存在的)。
30
+ * `DSL_SKILLS_ROOT` 为显式覆盖开关(调试 / 非常规布局用)。
31
+ * @param {string} [root] 项目根(消费者工程 / 仓库根)
32
+ * @returns {string[]}
33
+ */
34
+ export function skillsCandidates(root) {
35
+ const list = []
36
+ const push = (dir) => {
37
+ if (!dir) return
38
+ const abs = path.resolve(dir)
39
+ if (!list.includes(abs) && fs.existsSync(abs)) list.push(abs)
40
+ }
41
+ push(process.env.DSL_SKILLS_ROOT)
42
+ if (root) push(path.join(path.resolve(root), 'skills'))
43
+ push(path.join(SNAPSHOT_ROOT, 'skills'))
44
+ return list
45
+ }
46
+
47
+ /**
48
+ * 取一个可用的 skills 根(只读场景);全都不存在时回退「项目根下的 skills」,
49
+ * 让调用方拿到符合直觉的路径去报「文件不存在」,而不是 null 引发 TypeError。
50
+ * @param {string} [root]
51
+ * @returns {string}
52
+ */
53
+ export function skillsDirFor(root) {
54
+ const found = skillsCandidates(root)
55
+ return found[0] || projectSkillsDir(root)
56
+ }
57
+
58
+ /**
59
+ * 写入用的 skills 根:永远是项目根下的 skills/(发布态即消费者工程,不进 node_modules)。
60
+ * @param {string} [root]
61
+ * @returns {string}
62
+ */
63
+ export function projectSkillsDir(root) {
64
+ return path.join(path.resolve(root || process.cwd()), 'skills')
65
+ }
66
+
67
+ /** 判断 target 是否仍在 dir 内(防路径穿越;先归一化再前缀比对)。 */
68
+ function isInside(target, dir) {
69
+ const rel = path.relative(path.resolve(dir), path.resolve(target))
70
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel))
71
+ }
72
+
73
+ /**
74
+ * 归一化「skills/ 下的相对路径」:允许带或不带 `skills/` 前缀,统一成正斜杠相对路径。
75
+ * 绝对路径与任何 `..` 片段一律判非法(返回 null)——技能脚本执行与文档读取都靠它把关。
76
+ * @param {string} rel
77
+ * @returns {string|null}
78
+ */
79
+ export function normalizeSkillRel(rel) {
80
+ const raw = String(rel || '').trim().replace(/\\/g, '/').replace(/^\.\//, '')
81
+ if (!raw || path.isAbsolute(raw)) return null
82
+ const withoutPrefix = raw.replace(/^skills\//, '')
83
+ if (!withoutPrefix) return null
84
+ const segments = withoutPrefix.split('/').filter((s) => s !== '' && s !== '.')
85
+ if (!segments.length || segments.some((s) => s === '..')) return null
86
+ return segments.join('/')
87
+ }
88
+
89
+ /**
90
+ * 解析 skills/ 下的资源路径(脚本 / 文档 / 目录),按候选根依次找第一份存在的。
91
+ * @param {string} root 项目根
92
+ * @param {string} rel skills/ 下的相对路径(可带 `skills/` 前缀)
93
+ * @param {{ mustExist?: boolean }} [opts] mustExist=false 时不校验存在性,返回首选根下的拼接结果
94
+ * @returns {string|null} 绝对路径;非法 rel 或(mustExist 时)找不到则 null
95
+ */
96
+ export function resolveSkillPath(root, rel, { mustExist = true } = {}) {
97
+ const clean = normalizeSkillRel(rel)
98
+ if (!clean) return null
99
+ const candidates = skillsCandidates(root)
100
+ if (!mustExist) {
101
+ const base = candidates[0] || projectSkillsDir(root)
102
+ return path.join(base, clean)
103
+ }
104
+ for (const dir of candidates) {
105
+ const full = path.join(dir, clean)
106
+ if (!isInside(full, dir)) continue
107
+ if (fs.existsSync(full)) return full
108
+ }
109
+ return null
110
+ }
111
+
112
+ /**
113
+ * 与 resolveSkillPath 同语义,但找不到时回退「项目根 skills/ 下的期望路径」,
114
+ * 供调用方直接交给子进程 / import 并报出人类可读的「文件不存在」。
115
+ * @param {string} root
116
+ * @param {string} rel
117
+ * @returns {string}
118
+ */
119
+ export function resolveSkillPathOrProject(root, rel) {
120
+ const clean = normalizeSkillRel(rel)
121
+ const hit = resolveSkillPath(root, rel)
122
+ if (hit) return hit
123
+ return path.join(projectSkillsDir(root), clean || String(rel || ''))
124
+ }
@@ -1,6 +1,10 @@
1
1
  import path from 'node:path'
2
2
  import { pathToFileURL } from 'node:url'
3
3
  import { log, fmtBytes } from './logger.js'
4
+ import { resolveSkillPathOrProject } from './skillPaths.js'
5
+
6
+ /** 切图上传脚本相对 skills/ 的路径 */
7
+ const UPLOAD_SCRIPT_REL = 'finmall-card-sync/scripts/slice_upload.mjs'
4
8
 
5
9
  /**
6
10
  * 顶栏「远端 → 切图上传」按钮的服务端处理:把卡片引用的 src/slices 切图上传到 FinMall
@@ -43,14 +47,7 @@ export function createSliceUploadMiddleware({ root }) {
43
47
  )
44
48
  }
45
49
  try {
46
- function resolveUploadScript(root) {
47
- const primary = path.join(root, 'skills', 'finmall-card-sync', 'scripts', 'slice_upload.mjs')
48
- if (fs.existsSync(primary)) return primary
49
- const vendored = path.resolve(__dirname, '..', 'vendored', 'skills', 'finmall-card-sync', 'scripts', 'slice_upload.mjs')
50
- if (fs.existsSync(vendored)) return vendored
51
- return primary
52
- }
53
- const skillPath = resolveUploadScript(root)
50
+ const skillPath = resolveSkillPathOrProject(root, UPLOAD_SCRIPT_REL)
54
51
  const { uploadSlices } = await import(pathToFileURL(skillPath).href)
55
52
  const summary = await uploadSlices({
56
53
  cardId: String(payload.cardId),
@@ -0,0 +1,93 @@
1
+ # Skills 目录拓扑
2
+
3
+ > 本仓库的 `skills/` 下共 8 个 skill(含 shared),按依赖关系形成如下拓扑。
4
+ > 新来的 AI 按**从下到上**的顺序读(被依赖的先读),能最快建立全局认知。
5
+
6
+ ## 依赖拓扑
7
+
8
+ ```
9
+ sketch-spec-to-card ──► dsl-card-generator ◄── dsl-card-ai
10
+ (设计稿→卡片要素) │ ▲ (引用 references/、铁律;建卡入口路由 card_route_input → 强制先转 sketch-spec-to-card)
11
+ │ │
12
+ card-doctor ─────────┘ │ (体检报告 → 编排 dsl-card-ai 修复)
13
+ │
14
+ card-skill-trainer ────┘ (训练闭环反哺 generator 与 sketch-spec-to-card)
15
+ │
16
+ dsl-card-generator
17
+ │ 接受 finmall-card-sync 同步进来的卡作为"导出实证"
18
+ ▼
19
+ finmall-card-sync ──────► finmall-session-navigator
20
+ │ │
21
+ │ 复用 playwright 依赖 │ 启动 Chrome、维持登录态
22
+ ▼ ▼
23
+ shared/
24
+ (finmall-config.mjs
25
+ auth-model.md)
26
+ ```
27
+
28
+ ## 各 skill 职责
29
+
30
+ | skill | 职责 | 依赖 |
31
+ |---|---|---|
32
+ | **shared/** | 跨 skill 共享代码与文档:环境配置加载器(`finmall-config.mjs`)、鉴权与 Playwright 工程集中陈述(`auth-model.md`) | 无(最底层) |
33
+ | **finmall-session-navigator** | 用 Playwright 独立启动 Chrome、自动登录 FinMall UAT、维持会话。所有需要登录态的下游 skill 都先调它 | shared |
34
+ | **finmall-card-sync** | 通过 API 把 FinMall 卡片同步进 `src/cards/<id>/`(schema/data/封面)。复用 finmall-session-navigator 的登录态与 playwright 依赖 | shared + finmall-session-navigator 的登录态 |
35
+ | **dsl-card-generator** | 从零/图片生成卡片、组件/表达式/事件深度语义、校验脚本库、范式片段库、**整卡模板库与沉淀闭环**(resolve 检索 → register 登记 → build 重建保留 pin)、组件使用分析、**建卡输入路由**(`scripts/route_input.mjs` / MCP `card_route_input` + SKILL.md §8 Workflow 0:识别到 Sketch MeaXure 标注导出时自动先转 sketch-spec-to-card 前处理,再回本 skill 逐卡生成)。是"卡片生成与契约"的权威方 | sketch-spec-to-card(MeaXure 导出输入时的强制上游);接受 finmall-card-sync 同步进来的卡作为 export-proven 证据 |
36
+ | **dsl-card-ai** | 在已有卡片上用 AI 编辑(修绑定 / 批量改 / 解释卡)+ **建卡入口路由**(Workflow D:MCP `card_route_input` 判输入形态,MeaXure 导出强制先转 sketch-spec-to-card,再交 dsl-card-generator 生成)。纯编排层,所有写卡收口是 `card_write` | dsl-card-generator 的 references + MCP 工具;sketch-spec-to-card(MeaXure 输入时的上游) |
37
+ | **sketch-spec-to-card** | 读取 Sketch MeaXure 标注导出,按画板聚焦提取卡片要素(prompt.md / spec.md / 截图 / 切图),产出到 UI/ 供 dsl-card-generator 消费。**用户把 MeaXure 导出丢给 dsl-card-generator 时会被自动路由到本 skill 前处理**(无需用户显式点名) | dsl-card-generator(下游消费方) |
38
+ | **card-skill-trainer** | 无人值守训练闭环:抽样设计稿 → 生成 → 结构/事实/像素评分 → 失败归因 → 反哺 sketch-spec-to-card 与 dsl-card-generator;lessons 经 `training/tools/aggregate_lessons.mjs` 聚合成提案人工审批落盘 | 被训练的两个 skill + training/ 设施 |
39
+ | **card-doctor** | 存量卡健康巡检编排层:聚合 validate/lint/files/render 输出体检报告,指导按严重度分级修复(修复走 dsl-card-ai 的 card_write 闭环) | tools/card-doctor.mjs + dsl-card-ai 修复闭环 |
40
+
41
+ ## 阅读顺序建议
42
+
43
+ 按场景挑入口,不必全读:
44
+
45
+ - **生成新卡 / 改组件结构 / 校验**:只读 `dsl-card-generator/SKILL.md` + `references/quickref.md`
46
+ - **AI 编辑已有卡(修绑定、批量改)**:读 `dsl-card-ai/SKILL.md`,需要字段细节时跳到 `dsl-card-generator/references/`
47
+ - **拉取/刷新 FinMall 卡**:先 `finmall-session-navigator` 拿登录态,再 `finmall-card-sync` 同步
48
+ - **跨 skill 排查会话/鉴权问题**:直接读 `shared/auth-model.md`(唯一权威方)
49
+ - **存量卡体检 / 治理 lint 存量**:读 `card-doctor/SKILL.md`,先跑 `node tools/card-doctor.mjs` 再看报告
50
+ - **建卡提速(模板复用/沉淀)**:先 `resolve_card_template.mjs <意图>` 查模板库;新模式交付后经 `register_card_template.mjs --check` 确认再登记
51
+ - **设计稿转卡片要素**:读 `sketch-spec-to-card/SKILL.md`;**训练/还原度优化**:读 `card-skill-trainer/SKILL.md`
52
+ - **拿到 Sketch MeaXure 导出想直接建卡**:入口仍是 `dsl-card-generator`——先 `node skills/dsl-card-generator/scripts/route_input.mjs <导出目录>`(只挂 MCP 时用等价工具 `card_route_input({path})`,见 `dsl-card-ai` Workflow D),它判出 `meaxure-export` 后会给出 sketch-spec-to-card 的前处理命令(已前处理过则跳过),产物就绪再回 `dsl-card-generator` 逐卡生成(`SKILL.md §8 Workflow 0`)
53
+
54
+ ## 文件清单
55
+
56
+ ```
57
+ skills/
58
+ ├── README.md ← 本文件
59
+ ├── shared/
60
+ │ ├── finmall-config.mjs ← 环境配置加载器(baseUrl/appId/cdpPort/...)
61
+ │ └── auth-model.md ← 鉴权模型 + Playwright 工程集中陈述
62
+ ├── finmall-session-navigator/
63
+ │ ├── SKILL.md ← 自动登录 FinMall
64
+ │ └── scripts/
65
+ │ ├── finmall_login.mjs ← 主脚本
66
+ │ ├── session-manager.mjs ← 会话管理辅助
67
+ │ └── package.json ← playwright 依赖
68
+ ├── finmall-card-sync/
69
+ │ ├── SKILL.md ← API 同步卡片到 src/cards/
70
+ │ └── scripts/
71
+ │ └── api_batch_sync.mjs ← 批量同步脚本
72
+ ├── dsl-card-generator/
73
+ │ ├── SKILL.md ← 卡片生成主入口
74
+ │ ├── docs/ ← 设计文档
75
+ │ ├── references/ ← 参考文档 + recipe_snippets/ + card_index.json(意图路由)+ card_templates.json(整卡模板库)
76
+ │ └── scripts/ ← validate/lint/diff/scaffold 等;route_input(建卡输入路由,MeaXure 导出自动转 sketch-spec-to-card);模板闭环三件套:build_card_templates / register_card_template / resolve_card_template;analyze_component_usage(使用分析反哺 recipes)
77
+ ├── dsl-card-ai/
78
+ │ └── SKILL.md ← AI 编辑编排层
79
+ ├── sketch-spec-to-card/
80
+ │ ├── SKILL.md ← Sketch MeaXure 标注 → 卡片要素
81
+ │ ├── references/
82
+ │ └── scripts/ ← parse_meaxure.py 等
83
+ ├── card-skill-trainer/
84
+ │ ├── SKILL.md ← 无人值守训练闭环
85
+ │ ├── baselines/ ← 冻结基线
86
+ │ └── scripts/ ← run_round.mjs 等
87
+ └── card-doctor/
88
+ └── SKILL.md ← 存量卡健康巡检编排层(聚合脚本在 tools/card-doctor.mjs)
89
+ ```
90
+
91
+ ## 铁律
92
+
93
+ 所有 skill 共享的铁律集中陈述在 `dsl-card-generator/references/rules.md`(十三节,含 §十三「画板聚焦与卡片生成单位」:多画板设计稿未指定画板时必须先列清单请用户选,UI 产物可全量生成、卡片生成以单画板为单位)。任何与该文件冲突的描述以该文件为准。
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: card-doctor
3
+ description: 卡片健康巡检编排层。跑 tools/card-doctor.mjs 聚合 validate(Python 硬契约)/ lint(体验)/ files(封面、data.json、侧车)/ render(可选 SSR)四类检查,输出全卡体检报告,并按严重度分级指导修复——修复一律走 dsl-card-ai 的 card_write 闭环,复检收口。与 ci-gate 的边界:ci-gate 管「能不能合入」(硬门禁),本技能管「卡群健不健康、先修哪张」(报告与治理)。Triggers: 卡片体检, 健康巡检, 全卡检查, 卡片健康报告, 修复存量卡片, 治理 lint, card-doctor, 体检报告, 哪些卡片有问题.
4
+ ---
5
+
6
+ # Card Doctor 卡片健康巡检技能
7
+
8
+ 本技能是**编排层**:巡检 = 跑聚合脚本 → 解读报告 → 编排修复 → 复检收口。绝不重新实现任何检查逻辑(检查规则的唯一真源是 `validate_schema.py` / `lint_card.mjs` / dev server SSR 自检)。
9
+
10
+ ## 0. 铁律
11
+
12
+ 1. **只编排,不实现**:所有检查来自 `tools/card-doctor.mjs` 的聚合输出;不要自己写脚本扫 schema 找问题(会造出第二套规则,必然漂移)。
13
+ 2. **修复的唯一收口是 `card_write`**(MCP 工具,写前自动留历史快照、写后自动 validate + render_status)。具体改法遵循 `dsl-card-ai` 的编辑场景范式(card-fix-bindings / card-bulk-edit)与 `dsl-card-generator/references/rules.md` 铁律。
14
+ 3. **改坏可回滚**:每次 `card_write` 自动累积快照,用 `card_history` 查看、`card_rollback` 撤销;批量治理时先跑通单卡再推广。
15
+ 4. **render_status.ok ≠ 画对了**:doctor 的 render 项只证明「结构合法 + 渲染不抛错」;视觉问题以 `card_screenshot` 为准。
16
+ 5. **doctor 默认不拦截**(exit 0),它是报告工具;卡口归 `npm run ci`(ci-gate)管,不要把 doctor 当 CI gate 用(除非显式 `--strict`)。
17
+
18
+ ## 1. 用法
19
+
20
+ ```bash
21
+ node tools/card-doctor.mjs # 体检全部卡片
22
+ node tools/card-doctor.mjs --id <cardId> # 单卡
23
+ node tools/card-doctor.mjs --render # 附加 SSR 渲染自检(需先 npm run dev;离线自动 skipped)
24
+ node tools/card-doctor.mjs --out .codex-tmp/doctor.json # 落盘 JSON 报告(.codex-tmp 已 gitignore)
25
+ ```
26
+
27
+ 报告结构:`{ generatedAt, totals, cards: { <id>: { validate, lint, files, render? } } }`。
28
+
29
+ ## 2. 检查项语义
30
+
31
+ | 维度 | 来源 | 性质 | 说明 |
32
+ |---|---|---|---|
33
+ | `validate` | `validate_schema.py`(离线) | 硬契约 | 结构/绑定/data 一致性;error 必须清零 |
34
+ | `lint` | `lint_card.mjs --all --json`(离线) | 体验软规 | error(如按钮缺 click、itemId 错配)应清零;warn/info 按存量分批治理 |
35
+ | `files.cover` | 文件系统 | 完整性 | 缺 `<id>.png` 封面的卡无法走 FinMall 封面上传链路 |
36
+ | `files.data` | 文件系统 | 完整性 | data.json 缺失或 JSON 解析失败 |
37
+ | `render`(可选) | dev server `/__render-status/:id` | SSR 自检 | bindingErrors / runtimeErrors;离线标 `skipped` 不算失败 |
38
+
39
+ ## 3. 治理工作流
40
+
41
+ 1. **体检**:`node tools/card-doctor.mjs --out .codex-tmp/doctor.json`,先看 `totals` 建立全局认知。
42
+ 2. **分级**:`validate 失败` > `lint error` > `data.json 异常` > `缺封面` > `lint warn/info`。
43
+ 3. **聚类修复**:同一 `lint.code` 跨卡批量出现(如 `text-no-color`、`icon-no-click`)时,先精读该规则在 `lint_card.mjs` 头部的检查说明,再用同一修复范式批量处理;单卡个性问题单独处理。
44
+ 4. **修复**:逐卡走 `card_read` → 改 → `card_write`;需要看渲染效果时先 `npm run dev` 再 `--render` / `card_screenshot`。
45
+ 5. **复检**:每批修复后重跑 doctor 确认 `totals` 收敛、无新增问题;存量治理目标是把 `lintError` 降到 0,warn/info 可长期分批。
46
+ 6. **防回潮**:修复合入前跑 `npm run ci`(硬门禁:card-check + magic-values + regress-data + mcp-doc-sync)。
47
+
48
+ ## 4. 边界
49
+
50
+ - **不检查视觉还原度**:与设计稿的像素级比对归 `dsl-card-generator` 的 fidelity 工具链(check_fidelity / render_diff)。
51
+ - **不替代训练**:生成质量优化归 `card-skill-trainer`;doctor 管存量卡健康。
52
+ - **不碰 FinMall 远端**:远端一致性归 `finmall-card-sync` / `card_sync`。
@@ -0,0 +1,312 @@
1
+ ---
2
+ name: card-skill-trainer
3
+ description: 无人值守联合训练 sketch-spec-to-card 与 dsl-card-generator。扫描桌面已确认 Sketch 导出,评估卡片聚焦与标注契约,批量生成 schema/data,渲染截图,执行结构、事实与像素评分,输出失败归因和下一轮规则候选。触发词:卡片训练、自动训练、训练闭环、skill 回归、还原度优化。
4
+ ---
5
+
6
+ # Card Skill Trainer
7
+
8
+ ## 定位
9
+
10
+ 本 Skill 联合训练 `sketch-spec-to-card` 和 `dsl-card-generator`:前者负责卡片聚焦与标注契约,后者负责 DSL 还原,两者都被当作被评测对象。
11
+
12
+ ```text
13
+ build_dataset.py → run_round.mjs → score_round.mjs → semantic-review.jsonl → lessons.jsonl
14
+ ```
15
+
16
+ 人工不阻塞主流程。连续回归、渲染器崩溃或置信度低于阈值的样本会进入 `review-queue.jsonl`;像素/结构失败同时生成 `semantic-review.jsonl`,由执行 Skill 的 Agent 在下一轮自动做多模态归因,再回灌到 `dsl-card-generator` 或 `sketch-spec-to-card` 的文档规则。脚本负责提出证据和复跑回归,不负责把业务语义硬编码。
17
+
18
+ ## 源码隔离铁律
19
+
20
+ 训练、评测和冒烟测试**绝不写入宿主源码目录**:
21
+
22
+ - 禁止写 `src/cards/`
23
+ - 禁止写 `src/slices/`
24
+ - 禁止写 `.card-baselines/`
25
+ - 原始桌面设计稿只读
26
+ - 所有生成物落在 `training/datasets/<version>/raw/` 或 `training/runs/<round>/`
27
+
28
+ 执行器必须在动态 import 生成器和渲染器之前设置:
29
+
30
+ ```bash
31
+ DSL_CARD_CARDS_DIR=<training-run>/cards
32
+ DSL_CARD_SLICES_DIR=<training-run>/slices
33
+ ```
34
+
35
+ 每轮结束后可用 `git status --short -- src` 验证必须为空。
36
+
37
+ ## 自动化流程
38
+
39
+ 1. 扫描所有包含 `index.html` 的 MeaXure 导出。
40
+ 2. 每套导出独立解析到 `training/raw/<source>/`,不修改桌面源文件。
41
+ 3. 将每个有效画板登记为一个案例,按内容哈希稳定划分 train/dev/eval/holdout。
42
+ 4. 使用 `v3` 策略批量生成到隔离的 run 目录(本技能是「多画板必须先选卡」铁律的**显式批量例外**:用户点名跑无人值守训练即等于授权全量画板;产物落隔离 run 目录、不写 `src/cards/`。见 `dsl-card-generator/references/rules.md §十三`)。
43
+ 5. 复制 schema 实际引用的 slices 到当前 run 的隔离资源目录。
44
+ 6. 执行 Python 结构校验、Node lint、独立 Chrome 渲染、重复内容检测和像素差异计算。
45
+ 7. 聚合 Round 报告,并按失败签名生成规则候选。
46
+ 8. Agent 自动复核失败对的 `designImage + render.png + spec.json`,把失败归入 PARSER / DSL / STYLE / DATA / INTERACTION / ASSET / EVALUATOR,并只推广通用规则。
47
+
48
+ ## 高效迭代闭环(r172 起)
49
+
50
+ 单案例修复循环按此顺序推进,避免整轮盲跑浪费时间:
51
+
52
+ 1. **诊断**:`diagnose_case.mjs` 对失败/低分案例一键产出证据包(side-by-side、像素热区、
53
+ 元素偏差表、`__prov` 源码行溯源、失败类建议)。先看偏差表与热区,再决定是否动生成器。
54
+ 2. **修复**:改动 `spec_to_schema_v3.mjs` / `vision.py` 等的通用几何规则(禁业务词硬编码)。
55
+ 3. **增量验证**:`run_round.mjs --only-failed training/runs/<上轮> --round <新轮>` 只重跑上轮
56
+ 失败案例,秒级确认修复有效。
57
+ 4. **整轮防回归**:不带开关跑全量,`round_diff.mjs --from <上轮> --to <新轮>` 确认零
58
+ PASS→FAIL 回归(该脚本存在回归时 exit 1,可直接当提交门禁)。
59
+ 5. **门禁汇总**:`score_round.mjs` 出 roundGate;全绿才允许提交并推送。
60
+
61
+ ### 校正器纪律
62
+
63
+ 后置布局校正器是安全网而不是拐杖:
64
+
65
+ - 校正采纳需**双指标守卫**:position 提升 **且** pixel 不退化(容忍 +0.005),否则回退并记
66
+ `correctorRejected`;采纳时记 `layoutCorrections` 明细。
67
+ - `summary.json` 的 `correctorCoverage`(触发率)持续 >25% 说明生成器缺陷被校正器掩盖,
68
+ 应把高频校正模式沉淀回生成器规则,而不是放任校正器兜底。
69
+ - 每 3~5 轮安排一次里程碑裸测:`run_round.mjs --no-correct --round <轮次>nc`,与同期
70
+ 正常轮对比 passRate/avgPosition,差值就是校正器的真实贡献与生成器的真实缺口。
71
+ - 模拟否决快路径:纯纵向 rigidSafe 校正的 position 分可精确模拟(22/22 对账逐位一致),
72
+ 模拟不提升即跳过二次渲染,报告记 `correctorRejected.reason=position-not-better-simulated`;
73
+ 可用 `CORR_SIM_VALIDATE=1` 双跑对账复核保真度。
74
+
75
+ ### 分区纪律
76
+
77
+ - 迭代修复**只用 train/dev**;eval 每 3 轮盲测一次;holdout 只在晋级落地时启用。
78
+ - 同一案例连续出现在诊断视野里超过 2 轮,视为过拟合风险,下一轮诊断必须换一批样本。
79
+
80
+ ## 上游质量门
81
+
82
+ 每个案例先检查 `sketch-spec-to-card` 产物,再进入 DSL 评分:
83
+
84
+ - `annotationCompleteness`:画板内叶子标注是否被完整归属到聚焦卡。
85
+ - `textRetention`:卡片内文案是否被完整保留。
86
+ - `structuralFocus`:候选是否具备卡片级结构,而不是气泡、按钮条或空壳。
87
+ - `trainingEligible`:弹窗、toast、底部抽屉必须为 false。
88
+
89
+ 任一门失败优先归因 `PARSER`,修复目标是 `vision.py` / `parse_meaxure.py` / `boundary.json` 的通用几何规则,不允许用业务名救某个样本。
90
+
91
+ ## 验收标准(r060 起)
92
+
93
+ ### 单案例通过门(per-case pass gate)
94
+
95
+ 每张卡片必须同时满足以下全部条件才算 PASS:
96
+
97
+ | 维度 | 门 (run_round 实现) | 说明 |
98
+ |---|---:|---|
99
+ | 像素差异 (pixelDiff) | **≤ 0.08** | 逐像素差异比;标注缺陷矩形与非标字体字形带局部掩膜(报告 pixelExclusions 透明可见) |
100
+ | UI 还原度 (overall) | **≥ 0.85** | 综合像素+结构+组件+文本 |
101
+ | 组件相似度 (components) | **≥ 0.75** | 文本/媒体/富文本计数匹配(ListLayout 按数据项展开计数) |
102
+ | 位置还原度 (position) | **≥ 0.80** | 文本盒对齐(含形状锚点) |
103
+ | 文本溢出 (textOverflow) | **≥ 0.90** | 渲染盒溢出/裁切 |
104
+ | 结构还原度 (structure) | **≥ 0.85** | 轮廓直方图(含 1.25% 容差窗) |
105
+ | 色彩还原度 (color) | **≥ 0.90** | 颜色分布相似度 |
106
+ | 尺寸还原度 (dimension) | **≥ 0.95** | 宽高比匹配 |
107
+ | 重复内容 (duplication) | **≥ 0.95** | 同一文案渲染次数不得超出标注次数 5%;合并渲染(¥+金额 合一)豁免 |
108
+ | validate / lint / render | 0 | 零容忍 |
109
+
110
+ > **字体掩膜口径(r201 起)**:非标字体字形带的掩膜扩宽比不再硬编码,取自 `training/reports/font-metrics.json`
111
+ > ——由 `training/tools/probe_font_metrics.mjs`(playwright `measureText` 实测设计稿字体栈的渲染宽 / 标注宽比)产出。
112
+ > 取值顺序:逐样本比例 → 同 fontSize 档中位数 → overall 中位数 → 文件缺失回退 `1.35`。
113
+ > 换字体栈、改 `preview/styles/app.css` 或改掩膜逻辑后**必须重跑探针**(`node training/tools/probe_font_metrics.mjs`),
114
+ > 否则 pixelDiff 口径漂移、轮间与锚点不可比。
115
+
116
+ ### 轮级晋级门(round-level promotion gate)
117
+
118
+ 一轮训练完成后,用 `round_diff.mjs --from <冻结锚点轮> --to <本轮>` 做冻结锚点回归,
119
+ **回归 0 例 PASS→FAIL** 才允许晋级;锚点轮目录即基线载体(当前冻结锚点 = `training/runs/r176`,
120
+ v4 sampled 44 例:与历史锚点共享 40 例 + holdout 新增 4 例计为 new 不计回归):
121
+
122
+ | 门禁 | 目标 | 说明 |
123
+ |---|---|---|
124
+ | 回归 pass→fail | **0** | round_diff 状态迁移硬底线;任何 1 例即拒绝晋级 |
125
+ | 均值指标 | 不低于锚点 | fidelity/pixel/position/structure 均值不得退化(round_diff delta 表) |
126
+ | 本轮 passRate | 批次门另计 | 新批次盲测允许低起点(如 v6 r200 = 4/30),靠迭代收敛而非门槛豁免 |
127
+ | duplicationFailures | 0 | 重复内容超限(重影)样本数 |
128
+ | lint / validate / render / upstream | 0 | 全零 |
129
+
130
+ > 基线载体是**冻结锚点轮目录**(含 reports/ 全量证据),不再维护独立 baseline JSON 文件
131
+ > (历史 `baselines/v3-r058.json` 范式已废弃)。晋级 = 新轮成为下一冻结锚点候选,并在
132
+ > `training/plans/` 记录轮号与指标。
133
+
134
+ ### 泛化盲测门(generalization gate)
135
+
136
+ 每 **3 轮**锚点回归后(或每次晋级基线前),必须用**未参与修复的新批次数据集**(或 holdout / eval 分区)抽取 **不少于 24 例未见样本** 做盲测(如 v6 sampled 30 例):
137
+
138
+ | 门禁 | 目标 | 说明 |
139
+ |---|---|---|
140
+ | 盲测样本数 | ≥ 24 | 按结构聚类抽样,覆盖列表卡、表单卡、结果卡、媒体卡和空状态 |
141
+ | 盲测 passRate | ≥ 0.85 | 至少 85% 通过新单案例门 |
142
+ | 盲测 avgFidelity | ≥ 0.78 | 未见样本平均还原度不低于 78% |
143
+ | 锚点 vs 盲测差 | ≤ 10pts | 锚点 avgFidelity − 盲测 avgFidelity ≤ 0.10(防过拟合) |
144
+
145
+ ### 收敛检测与早停
146
+
147
+ 当出现以下任一信号时,**停止脚本微调,转而修订 Skill 文档规则或范式**:
148
+
149
+ 1. **边际收益递减**:连续 3 轮焦点集 avgFidelity 提升 < 1pt(0.01)。
150
+ 2. **锚点升但盲测降**:锚点 avgFidelity 提升但盲测 avgFidelity 下降 → 判定过拟合,拒绝晋级。
151
+ 3. **同一签名反复出现**:同一失败签名在 ≥ 3 轮中重复出现且未消除 → 说明脚本补丁无效,需升级 Skill 级别范式。
152
+ 4. **盲测差扩大**:锚点−盲测差从 ≤5pts 扩大到 ≥10pts → 过拟合风险,强制回退。
153
+
154
+ 收敛触发后,Agent 必须输出 `convergence-report.json`,列出瓶颈分类和 Skill 级改进建议,而非继续打脚本补丁。
155
+
156
+ ### 视觉修正回路(模型在环)
157
+
158
+ 当脚本化校正(`correctCardLayout` 的 X/Y 轴 padding 对齐)收敛后仍无法通过门禁时,启用模型多模态回路,遵循「模型视觉判断 > 脚本启发式」的优先级:
159
+
160
+ 1. 对焦点集每例收集 `design.png`、`render.png`、`spec.json`、`schema.json` 与渲染元素盒 `elementBoxes`。
161
+ 2. 模型逐区域比对设计稿与渲染图,输出**可执行的布局修正指令**(目标节点 + 属性 + 期望值 + 证据区域),写入 `visual-fix.jsonl`;指令只允许引用结构证据(坐标、尺寸、颜色、文本),禁止出现业务词硬编码。
162
+ 3. 脚本按指令修改 schema 并重渲染,仅当 position / pixel / duplication 三项均不退化时才保留,否则回滚。
163
+ 4. 同一修正模式在 ≥3 个案例中复现 → 抽象为通用规则回灌 `dsl-card-generator` 或 `sketch-spec-to-card`,并登记 `training/lessons/lessons.jsonl`。
164
+ 5. 每轮视觉修正后必须复跑冻结锚点,防止局部修正引发全局回归。
165
+
166
+ > **lessons 反哺提案**:定期(建议每个训练批次收尾时)跑 `node training/tools/aggregate_lessons.mjs` 聚合 lessons.jsonl——重复签名(同一坑重复踩)、未落盘规则(按 targetFiles 给建议落点)、密集落盘点(规则密集文件需结构性审视)三类提案,人工逐条 yes/no 审批后落盘,工具本身不自动改任何 skill 文件。
167
+
168
+ ## 当前基线与落地门
169
+
170
+ 当前冻结锚点 = `training/runs/r176`(v4 sampled)。最近一次锚点回归 r198:共享 40 例 **0 回归**,
171
+ fidelity 96.4%、pixel 3.8%、position 95.7%、structure 95.6%(均优于 r176)。
172
+ 批次盲测基线:v5(转账二批次 17 代表)r199 = 14/17、avgFid 95.8%、avgPix 4.0%;
173
+ v6(存款+理财 30 代表)r200 = 4/30、avgFid 81.7%(新布局族缺口,下一批次主战场,见
174
+ `training/plans/v6-dataset-baseline.md`)。
175
+
176
+ 历史演进(baseline JSON 范式时期,仅供追溯):
177
+
178
+ | 基线 | 平均还原度 | 最低 | 低于80% | 结构还原度 |
179
+ |---|---:|---:|---:|---:|
180
+ | v3-r050n (08/26) | 79.5% | 73.2% | 26 | 70.4% |
181
+ | v3-r052n (08/27) | 80.5% | 74.1% | 15 | 71.1% |
182
+ | v3-r058 (08/28) | 85.9% | 82.0% | 0 | 93.2% |
183
+ | 冻结锚点范式 (r176→r198) | 96.2%→96.4% | — | 0 | 95.4%→95.6% |
184
+
185
+ ### 定向还原度迭代协议(r060 起)
186
+
187
+ 基线通过后不直接全量重训。每轮使用"冻结 48 例锚点 + 低分焦点集 + 未见样本盲测":
188
+
189
+ 1. 从最近回归中选取 `<85%` 样本组成焦点集;`<82%` 必须逐张多模态归因。
190
+ 2. Agent 同时读取设计稿、渲染截图、`spec.json` 和 `schema.json`,输出区域级 `agent-audit.jsonl`;结论必须包含失败类、通用规则候选、置信度和目标 Skill。
191
+ 3. 修复优先级:可见媒体与重影 → 语义顺序与纵向节奏 → 背景/圆角/留白 → 未见样本泛化。
192
+ 4. 缺失/状态错切图优先画板裁切(`cropSlice`,含宽条切图与纯矢量 logo 组;矩形内有文本叠加或背景级大矩形禁裁),裁切不可用才纯色近似并标记缺陷;弥散/光晕类纹理特事特办,计入局部还原度豁免。
193
+ 5. 焦点样本通过后必须复跑冻结 48 例;每 3 轮做不少于 24 例未见样本盲测。
194
+ 6. 晋级门、焦点 ID 和产物路径以 `training/plans/` 下最新 plan JSON 为准。
195
+
196
+ 训练清单可记录样本 ID 和画板名作为证据;运行时代码、Skill 判定和校验器不得引用业务词、画板名或样本专属文案。
197
+
198
+ ### 晋级落地检查清单
199
+
200
+ 新一轮改动落地前必须满足:
201
+
202
+ 1. 失败样本探针全部通过。
203
+ 2. 冻结锚点全量回归 round_diff **0 例 pass→fail**,且均值指标不退化、无新增失败签名。
204
+ 3. validate/lint/render/upstream 失败数均为 0。
205
+ 4. `git status --short -- src` 为空。
206
+ 5. 批次轮 score_round:duplicationFailures = 0;成熟批次(v4/v5)另要求 passRate 趋势向上且残留失败逐例归因。
207
+ 6. 若为晋级轮,盲测 24 例 passRate ≥ 85%,盲测 avgFidelity ≥ 78%,锚点−盲测差 ≤ 10pts。
208
+ 7. 通用规则写入 `training/lessons/lessons.jsonl`,并同步到对应 Skill 的 `SKILL.md` 或 `references/`;业务词、画板名和样本专属文案不得进入规则。
209
+ 8. 通过后以新轮目录作为下一冻结锚点候选并登记 `training/plans/`;未通过的候选规则保持 `candidate`,不修改正式 Skill 行为。
210
+
211
+ 评分器本身也要参与回归:组件语义升级(如 `Input` 正确承载金额)时,评分器必须把可编辑文本组件计入 text 维度;ListLayout 必须按数据项数展开模板内 Text/Image/Input/Button 计数,避免正确模板复用被当成组件丢失。
212
+
213
+ 结构评分对轮廓直方图使用约 1.25% 尺寸的对称最近邻对齐窗口:1–2 像素渲染偏移不视为结构丢失,明显缺块、错位和错误背景仍会扣分。调整该容差必须同步复跑冻结锚点,不允许用放宽阈值掩盖还原缺陷。
214
+
215
+ 像素对比额外记录 `bestAlignDy`(最佳纵向对齐偏移,仅诊断字段,不参与评分):用于区分「截图裁切/节奏误差」与「真实布局错误」。**禁止**用对齐搜索后的差异替代零偏移差异参与评分——实测(r125)偏移因案例而异(0 / -4 / -16px 并存),不存在可统一归一化的系统性裁切偏移,统一平移只会掩盖真实的纵向节奏缺陷。
216
+
217
+ 布局自动校正覆盖 X/Y 两轴:`correctCardLayout` 按渲染元素与标注的偏差调整子节点的 `paddingTop`/`paddingLeft`(X 轴钳制 ±48px),仅当校正后 position 总分变好才保留,否则回滚 schema。
218
+
219
+ ## 命令
220
+
221
+ ### 构建数据集
222
+
223
+ ```bash
224
+ python skills/card-skill-trainer/scripts/build_dataset.py \
225
+ --src "<设计稿导出根目录>" \
226
+ --out training/datasets/v1 \
227
+ --max-cases 160
228
+ ```
229
+
230
+ ### 运行一轮
231
+
232
+ ```bash
233
+ node skills/card-skill-trainer/scripts/run_round.mjs \
234
+ --dataset training/datasets/v3/train-set.jsonl \
235
+ --round r060 \
236
+ --strategy v3 \
237
+ --limit 48
238
+ ```
239
+
240
+ 常用开关:
241
+
242
+ - `--only <caseId[,caseId]>`:只跑指定案例(冒烟用)。
243
+ - `--only-failed training/runs/<上轮>`:只重跑上轮失败案例(修复验证快路径)。
244
+ - `--no-correct`:禁用布局校正器,裸测生成器真实水平(里程碑对照用)。
245
+ - `--splits train,dev`:限定分区(迭代纪律见上文)。
246
+
247
+ 渲染会话(Chrome + 预览 HTTP server)由 `skills/dsl-card-generator/scripts/render_card.mjs::createRenderSession`
248
+ 持有,收尾 `close()` **必须能返回**:CDP `send()` 带 60s 兜底超时、WebSocket `close/error` 立即拒绝全部在途请求、
249
+ `server.close()` 2s 后强制 `closeAllConnections()`(Chrome 的 keep-alive 连接不会自己断)。
250
+ 少了任一条,浏览器异常退出时会出现「全案例跑完、`reports/` 齐全,却卡在 finally 写不出
251
+ `review-queue.jsonl` / `summary.json`,node 进程 0% CPU 常驻」的假死(r202 实测),只能 `kill -9` 重跑整轮。
252
+
253
+ ### 单案例诊断
254
+
255
+ ```bash
256
+ node skills/card-skill-trainer/scripts/diagnose_case.mjs \
257
+ --run training/runs/r060 \
258
+ --case <caseId>
259
+ ```
260
+
261
+ 产出 `<caseId>.side.png` 并排图、像素热区直方图、元素偏差 Top10、偏差节点→生成器
262
+ 源码行(`__prov`)溯源与失败类建议。
263
+
264
+ ### 轮间对比
265
+
266
+ ```bash
267
+ node skills/card-skill-trainer/scripts/round_diff.mjs \
268
+ --from training/runs/r060 \
269
+ --to training/runs/r061
270
+ ```
271
+
272
+ 列出指标 delta、fail→pass 修复清单、pass→fail 回归清单;存在回归时 exit 1,
273
+ 可作为提交前门禁(`--allow-regressions` 可豁免)。
274
+
275
+ ### 汇总报告
276
+
277
+ ```bash
278
+ node skills/card-skill-trainer/scripts/score_round.mjs --run training/runs/r060
279
+ ```
280
+
281
+ ### 训练设施工具(`training/tools/`,已入库)
282
+
283
+ ```bash
284
+ node training/tools/aggregate_lessons.mjs # lessons 聚合 → 反哺提案(P-B 未落盘规则 / P-C 密集落盘点)
285
+ node training/tools/probe_font_metrics.mjs # 非标字体回退字宽探针 → training/reports/font-metrics.json(掩膜扩宽比)
286
+ node training/tools/analyze_position.mjs <round> [caseIdPrefix...] # 逐样本 spec 文本框 vs 渲染 elementBoxes 配对偏差
287
+ node training/tools/probe_offsets.mjs <cardsRoot> <cardId> <width> [captureHeight] # 实测渲染页 DOM 几何(padding / content box / 偏移)
288
+ python3 training/tools/split_report.py <runDir> [topN] # 按 split 聚合指标并列出最差 N 例
289
+ ```
290
+
291
+ > `training/datasets/`、`training/runs/` 仍被 gitignore(体积 + 源稿版权)。数据集可复现性靠
292
+ > `dataset-summary.json` 的 `provenance`(sourceRoot / sourceNames / toolchainRev / 解析器参数)
293
+ > 与 `training/plans/` 的轮次记录;锚点回归靠冻结轮目录(当前 `training/runs/r176`)。
294
+
295
+ ## 输出
296
+
297
+ ```text
298
+ training/runs/<round>/
299
+ cards/
300
+ slices/
301
+ reports/
302
+ <caseId>.json ← 含 layoutCorrections / correctorRejected 校正明细
303
+ <caseId>.render.png ← 最终渲染截图
304
+ <caseId>.design.png ← 设计稿参考图
305
+ <caseId>.side.png ← diagnose_case 并排对比图(按需生成)
306
+ summary.json ← 含 roundGate / roundGatePassed / correctorCoverage
307
+ summary.md ← 含晋级门禁表格与截图对比图廊
308
+ review-queue.jsonl
309
+ semantic-review.jsonl
310
+ ```
311
+
312
+ `summary.md` 是唯一需要周期性查看的产物;如果所有门禁通过,可以完全不看。