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
@@ -0,0 +1,447 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * route_input.mjs — 建卡输入形态路由(SKILL.md §8 Workflow 0 的机械判定器)。
4
+ *
5
+ * 收到建卡请求先把用户给的输入路径喂给本工具,由它判定形态并给出下一步命令,
6
+ * 避免 AI 凭感觉决定「要不要先跑 sketch-spec-to-card」:
7
+ * node scripts/route_input.mjs ~/Downloads/转账ui设计稿0723
8
+ * node scripts/route_input.mjs UI/01基金_基金推荐 --json
9
+ *
10
+ * 判定结果(kind):
11
+ * meaxure-export Sketch MeaXure 标注导出目录(index.html 内嵌 artboards + preview/ + assets/)
12
+ * → 必须先经 sketch-spec-to-card 前处理,禁止直接拿 preview/ 整图建卡;
13
+ * 若 UI/ 下已有 export 匹配的 manifest.json 则跳过前处理,直接消费存量产物。
14
+ * ui-bundle sketch-spec-to-card 的产物(manifest.json / spec.json + card-N.png)→ Workflow A 按用户指定的单画板生成
15
+ * card-dir 已存在的卡片目录(schema.json)→ Workflow B 编辑
16
+ * image 单张截图/设计稿 PNG → Workflow A(无 spec,全靠视觉推断)
17
+ * unknown 判不出形态,需人工确认输入
18
+ *
19
+ * 退出码:0 = 已路由;3 = unknown(需人工确认);1 = 用法错误 / 路径不存在。
20
+ */
21
+ import fs from 'node:fs'
22
+ import path from 'node:path'
23
+ import { spawnSync } from 'node:child_process'
24
+ import { fileURLToPath } from 'node:url'
25
+ import { skillsDir } from './lib/paths.mjs'
26
+
27
+ const IMAGE_EXT = new Set(['.png', '.jpg', '.jpeg', '.webp'])
28
+ /** 已知入口文件:判定交给它所在目录(index.html=MeaXure 导出;manifest/clusters/spec/prompt=要素包;schema=卡片目录)。 */
29
+ const ENTRY_FILES = new Set(['index.html', 'manifest.json', 'clusters.json', 'spec.json', 'spec.md', 'prompt.md', 'schema.json'])
30
+ const SKETCH_SKILL = path.join(skillsDir, 'sketch-spec-to-card')
31
+ /**
32
+ * 多画板选择门禁(铁律见 references/rules.md §十三):UI 产物允许全量生成,
33
+ * 但卡片生成必须以用户指定的单个画板 / 单个 cardKey 为单位。
34
+ * 作为提示文本随 next/note 下发,让判定器输出即带门禁,不依赖模型记住文档。
35
+ */
36
+ const SELECTION_GATE =
37
+ '# 多画板门禁(rules.md §十三):把全量画板按 1..n 列出(序号 1 起)+ 末尾加「全部」;当前环境支持弹选项(request_user_input)就优先弹选择,否则一句提问后停止输出、等用户回序号再继续——UI 产物可回「全部」全量生成,产卡默认单画板 / 单 cardKey(回「全部」才算显式批量授权);禁止自行挑画板、禁止擅自批量产卡;清单逐行配图:每个画板行下紧跟它自己的预览图绝对路径(--list / 门禁输出的 `图:` 行),与序号一一对应,缺图显式标缺失,禁止把图堆在清单末尾。'
38
+ /**
39
+ * 要素包根目录 UI/:与上游 `sketch-spec-to-card/scripts/parse_meaxure.py` 的 `REPO_ROOT/UI`
40
+ * (按脚本自身路径推算,非 cwd)保持同一锚点,避免「建议命令」与「实际落点」分叉。
41
+ * 可用 DSL_CARD_UI_DIR 直接指定,或用 DSL_CARD_PROJECT_ROOT 指定宿主工程根。
42
+ */
43
+ const REPO_ROOT = path.resolve(skillsDir, '..')
44
+ const UI_ROOT =
45
+ process.env.DSL_CARD_UI_DIR || path.join(process.env.DSL_CARD_PROJECT_ROOT || REPO_ROOT, 'UI')
46
+
47
+ function exists(target) {
48
+ try {
49
+ fs.accessSync(target)
50
+ return true
51
+ } catch {
52
+ return false
53
+ }
54
+ }
55
+
56
+ function isDir(target) {
57
+ try {
58
+ return fs.statSync(target).isDirectory()
59
+ } catch {
60
+ return false
61
+ }
62
+ }
63
+
64
+ function entries(target) {
65
+ try {
66
+ return fs.readdirSync(target, { withFileTypes: true })
67
+ } catch {
68
+ return []
69
+ }
70
+ }
71
+
72
+ /** 大文件安全读取:超过 cap 时只取头尾各一半(MeaXure 的 data 通常在 index.html 尾部)。 */
73
+ function readTextCapped(file, cap = 64 * 1024 * 1024) {
74
+ const size = fs.statSync(file).size
75
+ if (size <= cap) return fs.readFileSync(file, 'utf8')
76
+ const half = Math.floor(cap / 2)
77
+ const fd = fs.openSync(file, 'r')
78
+ const head = Buffer.alloc(half)
79
+ const tail = Buffer.alloc(half)
80
+ fs.readSync(fd, head, 0, half, 0)
81
+ fs.readSync(fd, tail, 0, half, Math.max(0, size - half))
82
+ fs.closeSync(fd)
83
+ return head.toString('utf8') + tail.toString('utf8')
84
+ }
85
+
86
+ /** 命令里输出相对 cwd 的短路径,跨盘/越界时退回绝对路径。 */
87
+ function shortPath(abs) {
88
+ const rel = path.relative(process.cwd(), abs)
89
+ return rel && !rel.startsWith('..') && !path.isAbsolute(rel) ? rel : abs
90
+ }
91
+
92
+ function pythonBin() {
93
+ if (process.env.DSL_CARD_PYTHON) return process.env.DSL_CARD_PYTHON
94
+ for (const bin of ['python3', 'python']) {
95
+ const probe = spawnSync(bin, ['--version'], { stdio: 'ignore' })
96
+ if (probe.status === 0) return bin
97
+ }
98
+ return 'python3'
99
+ }
100
+
101
+ /** Sketch MeaXure 标注导出判定:index.html 的 data 签名是硬证据,preview/ assets/ links/ 是佐证。 */
102
+ function detectMeaxure(dir) {
103
+ const evidence = []
104
+ const indexHtml = path.join(dir, 'index.html')
105
+ let signature = false
106
+ if (exists(indexHtml)) {
107
+ try {
108
+ const text = readTextCapped(indexHtml)
109
+ signature = /let\s+data\s*=/.test(text) && /"artboards"\s*:/.test(text)
110
+ if (signature) evidence.push('index.html 内嵌 let data = {"artboards":[...]} 标注 JSON')
111
+ else evidence.push('index.html 存在但未命中 MeaXure data 签名')
112
+ } catch {
113
+ evidence.push('index.html 不可读')
114
+ }
115
+ }
116
+ const previewDir = path.join(dir, 'preview')
117
+ const assetsDir = path.join(dir, 'assets')
118
+ const linksDir = path.join(dir, 'links')
119
+ const previewPngs = isDir(previewDir)
120
+ ? entries(previewDir).filter((e) => e.isFile() && IMAGE_EXT.has(path.extname(e.name).toLowerCase())).length
121
+ : 0
122
+ if (previewPngs) evidence.push(`preview/ 画板整图 ${previewPngs} 张`)
123
+ if (isDir(assetsDir)) evidence.push('assets/ 切图素材目录')
124
+ if (isDir(linksDir)) evidence.push('links/ 重定向页(MeaXure 附带)')
125
+
126
+ const matched = signature || (exists(indexHtml) && (previewPngs > 0 || isDir(assetsDir)))
127
+ return { matched, confidence: signature ? 'high' : 'medium', evidence, previewPngs }
128
+ }
129
+
130
+ /** sketch-spec-to-card 产物判定:支持平铺(UI/<画板>/)与按稿分片(UI/<稿名>/<画板>/)两种布局。 */
131
+ function detectUiBundle(dir) {
132
+ const evidence = []
133
+ const manifest = path.join(dir, 'manifest.json')
134
+ const clusters = path.join(dir, 'clusters.json')
135
+ const ownSpec = path.join(dir, 'spec.json')
136
+ const ownCards = entries(dir).filter((e) => e.isFile() && /^card-\d+\.png$/i.test(e.name)).length
137
+
138
+ if (exists(manifest)) evidence.push('manifest.json 画板清单')
139
+ if (exists(clusters)) evidence.push('clusters.json 聚类/状态模型')
140
+ if (exists(ownSpec)) evidence.push('spec.json 视觉要素标注')
141
+ if (ownCards) evidence.push(`card-N.png 聚焦图 ${ownCards} 张`)
142
+
143
+ const subBoards = entries(dir)
144
+ .filter((e) => e.isDirectory())
145
+ .map((e) => path.join(dir, e.name))
146
+ .filter((sub) => exists(path.join(sub, 'spec.json')))
147
+ if (subBoards.length) evidence.push(`${subBoards.length} 个画板子目录含 spec.json`)
148
+
149
+ const isArtboardBundle = exists(ownSpec) && ownCards > 0
150
+ const matched = exists(manifest) || isArtboardBundle || subBoards.length > 0
151
+ return {
152
+ matched,
153
+ confidence: exists(manifest) || isArtboardBundle ? 'high' : 'medium',
154
+ evidence,
155
+ manifest: exists(manifest) ? manifest : null,
156
+ clusters: exists(clusters) ? clusters : null,
157
+ artboardBundle: isArtboardBundle,
158
+ specJson: exists(ownSpec) ? ownSpec : null,
159
+ cardImages: ownCards,
160
+ boards: subBoards,
161
+ }
162
+ }
163
+
164
+ /** 统计一份 manifest 里「已产出要素包」的画板数:同一导出有多套产物时用它挑主产物。 */
165
+ function countGenerated(manifest) {
166
+ const canvases = Array.isArray(manifest?.canvases) ? manifest.canvases : []
167
+ return {
168
+ generated: canvases.filter((c) => c && c.status === 'generated').length,
169
+ total: canvases.length,
170
+ }
171
+ }
172
+
173
+ /**
174
+ * 在 UI/ 下找已前处理过的产物:比对 manifest.export 与输入目录,其次按稿名兜底。
175
+ *
176
+ * 同一份导出可能同时存在两套产物(历史上先平铺跑过 UI/<画板>/,后来改用按稿分片 UI/<稿名>/<画板>/):
177
+ * 只返回第一份会让下游误判「目标画板还没前处理」而重跑管线,故这里收集全部匹配,
178
+ * 以「已生成画板最多」的为主产物,其余进 alsoFound 一并报告。
179
+ */
180
+ function findPreprocessed(srcAbs) {
181
+ const norm = (p) => path.resolve(String(p || '')).replace(/[\\/]+$/, '')
182
+ const target = norm(srcAbs)
183
+ const candidates = [UI_ROOT, ...entries(UI_ROOT).filter((e) => e.isDirectory()).map((e) => path.join(UI_ROOT, e.name))]
184
+ const matches = []
185
+ for (const root of candidates) {
186
+ const manifestPath = path.join(root, 'manifest.json')
187
+ if (!exists(manifestPath)) continue
188
+ try {
189
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
190
+ if (manifest.export && norm(manifest.export) === target) {
191
+ matches.push({
192
+ uiDir: root,
193
+ manifest: manifestPath,
194
+ draft: manifest.draft || null,
195
+ via: 'manifest.export 匹配',
196
+ ...countGenerated(manifest),
197
+ })
198
+ }
199
+ } catch {
200
+ // 坏 manifest 不作为证据,继续找下一个
201
+ }
202
+ }
203
+ if (!matches.length) {
204
+ const byName = path.join(UI_ROOT, path.basename(target), 'manifest.json')
205
+ if (exists(byName)) {
206
+ let counts = { generated: 0, total: 0 }
207
+ try {
208
+ counts = countGenerated(JSON.parse(fs.readFileSync(byName, 'utf8')))
209
+ } catch {
210
+ /* 坏 manifest 仍按目录名匹配,只是不带统计 */
211
+ }
212
+ return {
213
+ uiDir: path.dirname(byName),
214
+ manifest: byName,
215
+ draft: path.basename(target),
216
+ via: '稿名同名目录兜底匹配',
217
+ ...counts,
218
+ alsoFound: [],
219
+ }
220
+ }
221
+ return null
222
+ }
223
+ matches.sort((a, b) => b.generated - a.generated || a.uiDir.length - b.uiDir.length)
224
+ const [best, ...rest] = matches
225
+ return {
226
+ ...best,
227
+ alsoFound: rest.map((m) => ({ uiDir: shortPath(m.uiDir), manifest: shortPath(m.manifest), generated: m.generated, total: m.total })),
228
+ }
229
+ }
230
+
231
+ function detectCardDir(dir) {
232
+ const schema = path.join(dir, 'schema.json')
233
+ if (!exists(schema)) return { matched: false }
234
+ return {
235
+ matched: true,
236
+ confidence: 'high',
237
+ evidence: [`schema.json(已存在卡片 ${path.basename(dir)})`, exists(path.join(dir, 'data.json')) ? 'data.json' : 'data.json 缺失'],
238
+ schema,
239
+ }
240
+ }
241
+
242
+ function route(inputAbs) {
243
+ if (isDir(inputAbs)) {
244
+ const card = detectCardDir(inputAbs)
245
+ if (card.matched) {
246
+ return {
247
+ kind: 'card-dir',
248
+ confidence: card.confidence,
249
+ evidence: card.evidence,
250
+ skillChain: ['dsl-card-generator'],
251
+ workflow: 'Workflow B — 编辑已有卡片',
252
+ next: [
253
+ `node ${shortPath(path.join(skillsDir, 'dsl-card-generator', 'scripts', 'describe_card.mjs'))} --id ${path.basename(inputAbs)}`,
254
+ `node ${shortPath(path.join(skillsDir, 'dsl-card-generator', 'scripts', 'diff_card.mjs'))} --id ${path.basename(inputAbs)}`,
255
+ ],
256
+ note: '输入已是卡片目录,走编辑链路(card_node_models 定位 + add_component 增改 + diff_card 兜底),不需要设计稿前处理。',
257
+ }
258
+ }
259
+
260
+ const meaxure = detectMeaxure(inputAbs)
261
+ if (meaxure.matched) {
262
+ const done = findPreprocessed(inputAbs)
263
+ const draft = (done && done.draft) || path.basename(inputAbs)
264
+ const uiDir = done ? done.uiDir : path.join(UI_ROOT, draft)
265
+ const parse = path.join(SKETCH_SKILL, 'scripts', 'parse_meaxure.py')
266
+ const cluster = path.join(SKETCH_SKILL, 'scripts', 'cluster_states.py')
267
+ const py = pythonBin()
268
+ const uiRel = shortPath(uiDir)
269
+ return {
270
+ kind: 'meaxure-export',
271
+ confidence: meaxure.confidence,
272
+ evidence: meaxure.evidence,
273
+ skillChain: done ? ['dsl-card-generator'] : ['sketch-spec-to-card', 'dsl-card-generator'],
274
+ workflow: done ? 'Workflow 0 入口② → 选卡后 Workflow A(单画板)' : 'Workflow 0 入口① → 先 sketch-spec-to-card 前处理',
275
+ preprocess: {
276
+ needed: !done,
277
+ draft,
278
+ uiDir: uiRel,
279
+ uiRoot: shortPath(UI_ROOT),
280
+ manifest: done ? shortPath(done.manifest) : null,
281
+ matchedVia: done ? done.via : null,
282
+ // 主产物里已生成 / 总画板数,以及同一导出的其它产物目录(平铺与按稿分片并存时)
283
+ generated: done ? done.generated : 0,
284
+ total: done ? done.total : 0,
285
+ alsoFound: done && done.alsoFound.length ? done.alsoFound : undefined,
286
+ },
287
+ next: done
288
+ ? [
289
+ `# 多画板门禁(rules.md §十三):产物已存在≠已选卡。先跑下面这条只读 --list 取全量画板清单(1..n + 全部),交给用户并停止输出等回复,再消费产物`,
290
+ `${py} ${shortPath(parse)} --src "${inputAbs}" --draft "${draft}" --list`,
291
+ SELECTION_GATE,
292
+ `# 拿到回复后(产物已存在,${done.via},已生成 ${done.generated}/${done.total} 画板),跳过前处理,只消费用户指定的那个画板:`,
293
+ `cat ${shortPath(done.manifest)}`,
294
+ `node ${shortPath(path.join(skillsDir, 'dsl-card-generator', 'scripts', 'spec_tree.mjs'))} --spec ${shortPath(path.join(uiDir, '<画板>', 'spec.json'))}`,
295
+ ...(done.alsoFound && done.alsoFound.length
296
+ ? [`# 同一导出另有产物目录(目标画板在主 manifest 里是 pending 时先去这些目录找,找到就直接用,别重跑管线):${done.alsoFound.map((m) => `${m.uiDir}(已生成 ${m.generated}/${m.total})`).join('、')}`]
297
+ : []),
298
+ `# 用户回「全部」= 显式批量授权:可重跑管线补齐缺失画板(${py} ${shortPath(parse)} --src "${inputAbs}" --out "${shortPath(UI_ROOT)}" --draft "${draft}" --scope-all --build)`,
299
+ ]
300
+ : [
301
+ `# 多画板门禁(rules.md §十三):先 --list 列 1..n + 全部 并停下等用户回复;下面 parse 不带范围直接跑会 exit 4`,
302
+ `${py} ${shortPath(parse)} --src "${inputAbs}" --out "${shortPath(UI_ROOT)}" --draft "${draft}" --build`,
303
+ `# 拿到回复后给上一条 parse 命令补范围:序号 k → --indices <k-1>;「全部」→ --scope-all`,
304
+ `${py} ${shortPath(cluster)} --out "${uiRel}"`,
305
+ SELECTION_GATE,
306
+ ],
307
+ note: done
308
+ ? 'UI/ 下已有该导出的产物,不重复跑管线;按 manifest.json / clusters.json 选卡后走 Workflow A(每轮只产用户指定的那一张卡),overlay_dialog 走 Workflow A.5(不产卡,补到父卡事件)。多画板未指定目标时先列清单请用户选,禁止自行挑画板或擅自批量(rules.md §十三)。'
309
+ : 'MeaXure 导出是多画板批量输入:禁止直接读 preview/ 整图建卡,必须先由 sketch-spec-to-card 做卡片聚焦裁切、多卡分离、弹窗识别与切图收集,产出 UI/<稿名>/ 要素包后回本 skill 生成。UI 产物可全量生成,卡片生成以用户指定的单画板 / 单 cardKey 为单位(rules.md §十三)。',
310
+ }
311
+ }
312
+
313
+ const bundle = detectUiBundle(inputAbs)
314
+ if (bundle.matched) {
315
+ const specHint = bundle.specJson
316
+ ? `node ${shortPath(path.join(skillsDir, 'dsl-card-generator', 'scripts', 'spec_tree.mjs'))} --spec ${shortPath(bundle.specJson)}`
317
+ : `cat ${shortPath(bundle.manifest || inputAbs)}`
318
+ return {
319
+ kind: 'ui-bundle',
320
+ confidence: bundle.confidence,
321
+ evidence: bundle.evidence,
322
+ skillChain: ['dsl-card-generator'],
323
+ workflow: bundle.artboardBundle ? 'Workflow A(单画板要素包)' : 'Workflow 0 入口② → 选卡后 Workflow A(单画板)',
324
+ bundle: {
325
+ manifest: bundle.manifest ? shortPath(bundle.manifest) : null,
326
+ clusters: bundle.clusters ? shortPath(bundle.clusters) : null,
327
+ specJson: bundle.specJson ? shortPath(bundle.specJson) : null,
328
+ cardImages: bundle.cardImages,
329
+ boards: bundle.boards.length,
330
+ },
331
+ next: [
332
+ specHint,
333
+ `# 再按 SKILL.md §8 Workflow A 六步闭环生成 schema(scaffold_card → add_component/expand_ir → validate+lint → render_diff)`,
334
+ ...(bundle.artboardBundle ? [] : [SELECTION_GATE]),
335
+ ],
336
+ note: bundle.artboardBundle
337
+ ? '输入已是单画板要素包,无需前处理,直接走 Workflow A 生成本卡。'
338
+ : '输入已是 sketch-spec-to-card 的产物,无需前处理;多画板/多卡时先让用户指定单个画板或 cardKey(禁止自行挑、禁止擅自批量,rules.md §十三),再走 Workflow A;subcard 与 overlay_dialog 按 Workflow A.5 分流。',
339
+ }
340
+ }
341
+
342
+ const images = entries(inputAbs).filter((e) => e.isFile() && IMAGE_EXT.has(path.extname(e.name).toLowerCase()))
343
+ if (images.length === 1) {
344
+ return route(path.join(inputAbs, images[0].name))
345
+ }
346
+ return {
347
+ kind: 'unknown',
348
+ confidence: 'low',
349
+ evidence: [
350
+ `目录内 ${entries(inputAbs).length} 项,未命中 MeaXure 签名(index.html + artboards)`,
351
+ '未命中 UI 要素包签名(manifest.json / spec.json + card-N.png)',
352
+ images.length ? `含 ${images.length} 张图片(多张,无法自动判定哪张是设计稿)` : '无图片文件',
353
+ ],
354
+ skillChain: [],
355
+ workflow: '需人工确认',
356
+ next: ['# 请指明输入形态:MeaXure 导出目录 / UI 要素包 / 单张设计稿 PNG / 已有卡片目录'],
357
+ note: '判不出形态时不要猜:向用户确认输入,或显式指定 UI/<画板>/spec.json 与 card-N.png。',
358
+ }
359
+ }
360
+
361
+ const ext = path.extname(inputAbs).toLowerCase()
362
+ if (IMAGE_EXT.has(ext)) {
363
+ const siblingSpec = path.join(path.dirname(inputAbs), 'spec.json')
364
+ if (exists(siblingSpec)) return route(path.dirname(inputAbs))
365
+ return {
366
+ kind: 'image',
367
+ confidence: 'high',
368
+ evidence: [`单张图片 ${path.basename(inputAbs)}(同目录无 spec.json)`],
369
+ skillChain: ['dsl-card-generator'],
370
+ workflow: 'Workflow 0 入口③ → Workflow A(无标注,视觉推断)',
371
+ next: [`# 直接多模态读图 → scaffold_card 出骨架 → validate+lint → render_diff 视觉闭环`],
372
+ note: '无 MeaXure 标注时全靠 AI 视觉推断,间距/圆角从图上目视估算;若这张图其实来自某份标注导出,请改传导出目录以走入口①。',
373
+ }
374
+ }
375
+
376
+ if (ENTRY_FILES.has(path.basename(inputAbs).toLowerCase())) {
377
+ return route(path.dirname(inputAbs))
378
+ }
379
+
380
+ return {
381
+ kind: 'unknown',
382
+ confidence: 'low',
383
+ evidence: [`文件 ${path.basename(inputAbs)}(${ext || '无扩展名'})不是图片,也不是目录入口`],
384
+ skillChain: [],
385
+ workflow: '需人工确认',
386
+ next: ['# 传目录(MeaXure 导出 / UI 要素包 / 卡片目录)或设计稿 PNG'],
387
+ note: '判不出形态时不要猜:向用户确认输入。',
388
+ }
389
+ }
390
+
391
+ function printHuman(result, inputAbs) {
392
+ const icon = { 'meaxure-export': '🧭', 'ui-bundle': '📦', 'card-dir': '✏️', image: '🖼️', unknown: '❓' }[result.kind] || '•'
393
+ const label = {
394
+ 'meaxure-export': 'Sketch MeaXure 标注导出目录',
395
+ 'ui-bundle': 'sketch-spec-to-card 产物(UI 要素包)',
396
+ 'card-dir': '已存在卡片目录',
397
+ image: '单张设计稿图片',
398
+ unknown: '未识别形态',
399
+ }[result.kind]
400
+ console.log(`${icon} 输入路由:${result.kind} — ${label}(置信度 ${result.confidence})`)
401
+ console.log(` 输入:${shortPath(inputAbs)}`)
402
+ console.log(` 证据:${result.evidence.join(';')}`)
403
+ console.log(` 链路:${result.skillChain.length ? result.skillChain.join(' → ') : '(待定)'}|${result.workflow}`)
404
+ if (result.preprocess) {
405
+ const p = result.preprocess
406
+ console.log(` 前处理:${p.needed ? `需要(稿名建议 "${p.draft}" → ${p.uiDir})` : `已存在,跳过(${p.matchedVia};manifest=${p.manifest})`}`)
407
+ }
408
+ console.log(' 下一步:')
409
+ for (const line of result.next) console.log(` ${line}`)
410
+ console.log(` 说明:${result.note}`)
411
+ }
412
+
413
+ /**
414
+ * 判定入口(CLI 与 MCP `card_route_input` 共用同一份实现,避免漂移)。
415
+ * 不打印、不 process.exit,只返回结构化结果;路径不存在时返回 `error` 字段。
416
+ * @param {string} input 输入路径(相对路径按 cwd 解析)
417
+ * @returns {object} `{ input, inputAbs, kind, confidence, evidence, skillChain, workflow, next, note, ... }`
418
+ */
419
+ export function routeInput(input) {
420
+ const raw = String(input == null ? '' : input)
421
+ const inputAbs = path.resolve(raw)
422
+ if (!raw.trim() || !exists(inputAbs)) {
423
+ return { input: raw, inputAbs, error: 'input-not-found', message: `输入路径不存在:${inputAbs}` }
424
+ }
425
+ return { input: shortPath(inputAbs), inputAbs, ...route(inputAbs) }
426
+ }
427
+
428
+ function main() {
429
+ const argv = process.argv.slice(2)
430
+ const asJson = argv.includes('--json')
431
+ const rest = argv.filter((a) => a !== '--json')
432
+ if (!rest.length) {
433
+ console.error('[usage] node route_input.mjs <输入路径(MeaXure 导出目录 / UI 要素包 / 卡片目录 / 设计稿 PNG)> [--json]')
434
+ process.exit(1)
435
+ }
436
+ const result = routeInput(rest[0])
437
+ if (result.error) {
438
+ console.error(`[error] ${result.message}`)
439
+ process.exit(1)
440
+ }
441
+ if (asJson) console.log(JSON.stringify(result, null, 2))
442
+ else printHuman(result, result.inputAbs)
443
+ process.exit(result.kind === 'unknown' ? 3 : 0)
444
+ }
445
+
446
+ // 只有被直接执行时才跑 CLI;被 MCP client 动态 import 时只取 routeInput,不触发 process.exit
447
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main()
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scaffold_card.mjs — 秒出合法卡片骨架,避免手写组件样板。
4
+ *
5
+ * 用法:
6
+ * node scaffold_card.mjs --intent list --id myCard --name "我的卡"
7
+ * node scaffold_card.mjs --intent form --id f1 --name "表单" --out /tmp/cards --force
8
+ * node scaffold_card.mjs --from creditCardBill --id myNewCard --name "新卡" # 整卡模板克隆
9
+ *
10
+ * 意图:blank | list | detail | form | dialog | tab | canvas-head
11
+ * 输出:<outBase>/<id>/{schema.json, data.json}(data.json 由 inputParams 反推,自洽)
12
+ *
13
+ * 设计:形状来自 lib/scaffold.mjs(与 gen-all-components-test 同源),保证合法。
14
+ * --from 模式:克隆存量整卡模板(references/card_templates.json 提供簇→代表卡路由),
15
+ * 只重写 pageId/name,版式纪律与范式原样继承;封面不复制(需定稿后重新渲染)。
16
+ */
17
+ import path from 'node:path'
18
+ import fs from 'node:fs'
19
+ import { writeSkeleton, cloneCardFrom, SCAFFOLD_INTENTS } from './lib/scaffold.mjs'
20
+
21
+ function parseArgs(argv) {
22
+ const out = {}
23
+ for (let i = 0; i < argv.length; i++) {
24
+ const a = argv[i]
25
+ if (!a.startsWith('--')) continue
26
+ const key = a.slice(2)
27
+ const next = argv[i + 1]
28
+ if (next && !next.startsWith('--')) { out[key] = next; i++ } else out[key] = true
29
+ }
30
+ return out
31
+ }
32
+
33
+ const args = parseArgs(process.argv.slice(2))
34
+ const intent = args.intent || args.i
35
+ const from = args.from
36
+ const id = args.id
37
+ const name = args.name || args.n
38
+ const outBase = args.out ? path.resolve(args.out) : undefined
39
+ const force = !!args.force
40
+
41
+ if (!from && (!intent || !SCAFFOLD_INTENTS.includes(intent))) {
42
+ console.error(`[usage] --intent <${SCAFFOLD_INTENTS.join('|')}> --id <cardId> [--name <名称>] [--out <dir>] [--force]`)
43
+ console.error(` 或 --from <模板卡id> --id <cardId> [--name <名称>] [--force](整卡模板克隆,模板见 references/card_templates.json)`)
44
+ process.exit(1)
45
+ }
46
+ if (!id) {
47
+ console.error('[error] 缺少 --id <cardId>')
48
+ process.exit(1)
49
+ }
50
+
51
+ if (force && outBase) {
52
+ const dir = path.join(outBase, id)
53
+ if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true })
54
+ }
55
+
56
+ try {
57
+ if (from) {
58
+ const dir = cloneCardFrom(from, id, { name, outBase })
59
+ console.log(`[ok] 已克隆模板卡:${from} → ${dir}`)
60
+ console.log(` 注意:封面未复制(封面必须代表卡片自身外观),结构定稿后重新渲染生成`)
61
+ } else {
62
+ const dir = writeSkeleton(id, intent, { name, outBase, force })
63
+ console.log(`[ok] 已生成骨架:${dir}`)
64
+ console.log(` 意图=${intent} 组件树=/Root>${describe(intent)}`)
65
+ }
66
+ } catch (e) {
67
+ console.error('[error] ' + e.message)
68
+ process.exit(1)
69
+ }
70
+
71
+ function describe(intent) {
72
+ return {
73
+ blank: '(空容器)',
74
+ list: 'Column > Text($title) + ListLayout($list)',
75
+ detail: 'Column > Text($title) + ListLayout($detailList) + Button',
76
+ form: 'Column > Text($title) + Input×2 + Button',
77
+ dialog: 'Column > Text($title) + Text($desc) + Button',
78
+ tab: 'Column > Row(tabs) + Column(panel)',
79
+ 'canvas-head': 'Column > Row(Canvas + Text)',
80
+ }[intent] || ''
81
+ }