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
package/dist/init.js ADDED
@@ -0,0 +1,425 @@
1
+ /**
2
+ * `cardbuddy init` —— 生成「立刻能开发调试」的卡片工程最小实例。
3
+ *
4
+ * 产出(全部增量、幂等;已存在的文件一律保留,除非 --force):
5
+ * src/cards/ 卡片目录骨架(后端与编辑器的约定落点)
6
+ * src/cards/helloCard/ 示例卡(schema.json + data.json,构建期已过校验)—— 起服务即有卡可看
7
+ * skills/ 随包发布的技能库全量释放:/__validate、/__sync、/__save、切图上传
8
+ * 与 AI 的 skill_read / skill_exec 都按「项目根 skills/ 优先」解析,
9
+ * 释放后既跑得快也写得了(FinMall 凭据落在项目内,不进 node_modules)
10
+ * tools/link-skills.mjs 把 skills/ 链到 Codex / Claude / WorkBuddy 等 AI 工具的项目级技能目录
11
+ * .env.cb 共享配置模板(端口 / 远端基址 / AI 网关占位;密钥写 .env.cb.local)
12
+ * package.json 声明 cardbuddy 依赖与 dev / preview / link:skills 脚本
13
+ * .gitignore 私密层与产物不入库
14
+ * README.md 上手说明
15
+ *
16
+ * 与仓库的 `npm run gen:demo` 的关系:本命令即其替代品,且更强 —— 它随 npm 包发布,
17
+ * 消费者 `npx cardbuddy init` 即可,无需检出 dsl-card 仓库,版本也天然与所装 cardbuddy 一致。
18
+ */
19
+ import fs from 'node:fs'
20
+ import os from 'node:os'
21
+ import path from 'node:path'
22
+ import { execFileSync } from 'node:child_process'
23
+ import { fileURLToPath } from 'node:url'
24
+ import chalk from 'chalk'
25
+
26
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
27
+
28
+ /** 示例卡(与 build.mjs 的 SAMPLE_CARD 一致;构建期由 scaffold_card.mjs 生成并过校验) */
29
+ const SAMPLE_CARD_ID = 'helloCard'
30
+
31
+ /** 模板 .env.cb:只放非机密的共享配置,密钥类一律注释占位(个人覆盖写 .env.cb.local) */
32
+ const ENV_TEMPLATE = `# CardBuddy 本地开发服务配置(共享层,可入库)
33
+ # 个人机密(AI_API_KEY / FinMall 凭据等)请写 .env.cb.local,它覆盖本文件且不入库。
34
+
35
+ # cardbuddy 本地服务端口(单一真值;编辑器前端也读它)
36
+ FINMALL_CARD_PORT=8787
37
+
38
+ # FinMall 远端站点基址(资源代理回源 / 同步 / 保存 / 切图上传用)
39
+ FINMALL_BASE_URL=https://uat-pkg.finmall.com
40
+ FINMALL_APP_ID=100001
41
+ FINMALL_WORKSPACE_ID=dev
42
+ # 远端编辑器 Web 访问别名(站点下挂载路径)
43
+ FINMALL_EDITOR_PATH=/ubomp-h5-sub
44
+ # Chrome 远程调试端口(复用已登录的 FinMall 会话)
45
+ FINMALL_CDP_PORT=9222
46
+
47
+ # ---- AI 开发助手(自带网关,OpenAI 兼容 /chat/completions)----
48
+ # AI_BASE_URL=https://your-gateway/openai/v1
49
+ # AI_API_KEY= # 建议写在 .env.cb.local
50
+ # AI_MODEL=
51
+ # 免确认执行策略:none=逐次审批 / skill=只免技能脚本 / all=技能脚本+本地命令都免(默认)
52
+ # AI_AUTO_APPROVE=all
53
+ # 本地命令执行(默认开;写 0 关闭 shell_exec 注册)
54
+ # AI_ALLOW_SHELL=1
55
+ # 单次输出上限:留空=自动(被 400 拒绝时自动减半重试)
56
+ # AI_MAX_TOKENS=
57
+ `
58
+
59
+ /** .gitignore 应包含的条目(缺哪条补哪条,不重写既有内容) */
60
+ const GITIGNORE_ENTRIES = [
61
+ 'node_modules/',
62
+ '.env.cb.local',
63
+ '.env.local',
64
+ '.env.finmall.local',
65
+ '.cache/',
66
+ '.local/',
67
+ 'skills/*/.local/',
68
+ '.DS_Store',
69
+ ]
70
+
71
+ /** 复制排除名单:私密凭据、依赖与缓存一律不释放到用户项目 */
72
+ const SKIP_DIRS = new Set(['node_modules', '__pycache__', '.git', '.local', '.cache', '.history'])
73
+ const SKIP_FILES = new Set(['.DS_Store', 'Thumbs.db'])
74
+
75
+ function isSkipped(name, isDir) {
76
+ if (isDir) return SKIP_DIRS.has(name)
77
+ return SKIP_FILES.has(name) || name.endsWith('.pyc')
78
+ }
79
+
80
+ /**
81
+ * 递归复制目录,跳过已存在的文件(force 时覆盖)。
82
+ * @returns {{ copied: number, skipped: number, bytes: number }}
83
+ */
84
+ function copyTree(src, dest, { force = false, dryRun = false }) {
85
+ const stat = { copied: 0, skipped: 0, bytes: 0 }
86
+ const walk = (s, d) => {
87
+ if (!dryRun) fs.mkdirSync(d, { recursive: true })
88
+ for (const entry of fs.readdirSync(s, { withFileTypes: true })) {
89
+ if (isSkipped(entry.name, entry.isDirectory())) continue
90
+ const sp = path.join(s, entry.name)
91
+ const dp = path.join(d, entry.name)
92
+ if (entry.isDirectory()) {
93
+ walk(sp, dp)
94
+ } else if (entry.isFile()) {
95
+ if (fs.existsSync(dp) && !force) {
96
+ stat.skipped++
97
+ continue
98
+ }
99
+ const size = fs.statSync(sp).size
100
+ if (!dryRun) {
101
+ fs.mkdirSync(path.dirname(dp), { recursive: true })
102
+ fs.copyFileSync(sp, dp)
103
+ }
104
+ stat.copied++
105
+ stat.bytes += size
106
+ }
107
+ }
108
+ }
109
+ walk(src, dest)
110
+ return stat
111
+ }
112
+
113
+ function fmtBytes(n) {
114
+ if (n < 1024) return `${n} B`
115
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`
116
+ return `${(n / 1024 / 1024).toFixed(2)} MB`
117
+ }
118
+
119
+ /** 写文件(存在则跳过,force 覆盖);返回 'written' | 'skipped' | 'planned' */
120
+ function writeFileSafe(file, content, { force = false, dryRun = false }) {
121
+ if (fs.existsSync(file) && !force) return 'skipped'
122
+ if (dryRun) return 'planned'
123
+ fs.mkdirSync(path.dirname(file), { recursive: true })
124
+ fs.writeFileSync(file, content, 'utf8')
125
+ return 'written'
126
+ }
127
+
128
+ /** 本包版本:用于生成工程的 devDependencies 范围(发布态/源码态都是 <pkg>/package.json) */
129
+ function ownVersion() {
130
+ try {
131
+ return JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf8')).version || '*'
132
+ } catch {
133
+ return '*'
134
+ }
135
+ }
136
+
137
+ function projectReadme(projectName, version) {
138
+ return `# ${projectName}
139
+
140
+ CardBuddy 卡片开发最小实例,由 \`cardbuddy init\` 生成。
141
+ 本地开发服务由 [\`cardbuddy\`](https://www.npmjs.com/package/cardbuddy) 提供(本工程已声明依赖 \`^${version}\`)。
142
+
143
+ ## 立刻开始
144
+
145
+ \`\`\`bash
146
+ npm install
147
+ npm run preview # 起本地服务(8787) + 托管内置编辑器前端 + 自动开浏览器
148
+ \`\`\`
149
+
150
+ 浏览器打开后即能看到示例卡 \`helloCard\`(\`src/cards/helloCard/\`)——改它的
151
+ \`schema.json\` 或 \`data.json\`,编辑器会热更新。
152
+
153
+ 只想跑后端服务、用线上编辑器时:
154
+
155
+ \`\`\`bash
156
+ npm run dev # 等价于 npx cardbuddy
157
+ \`\`\`
158
+
159
+ 然后在线上编辑器 **设置 → 本地开发服务** 里打开开关、填 \`http://127.0.0.1:8787\`
160
+ (须与 \`.env.cb\` 的 \`FINMALL_CARD_PORT\` 一致)。
161
+
162
+ ## 目录约定
163
+
164
+ \`\`\`
165
+ src/cards/<cardId>/
166
+ ├── schema.json 卡片结构定义(唯一真值)
167
+ ├── data.json 运行时数据(可由 schema 的 dictionary 派生)
168
+ └── <cardId>.png 列表缩略图(可选)
169
+ skills/ AI 协作技能库(校验 / 同步 / 建卡管线脚本 + 工作流文档)
170
+ .env.cb 共享配置(端口、远端基址、AI 网关占位)
171
+ .env.cb.local 个人机密覆盖层(AI_API_KEY 等;已被 .gitignore 忽略)
172
+ \`\`\`
173
+
174
+ ## 常用本地端点(\`http://127.0.0.1:8787\`)
175
+
176
+ | 端点 | 用途 |
177
+ | --- | --- |
178
+ | \`GET /__cards\` | 卡片列表 |
179
+ | \`GET /__card/:id\` | 读单卡 schema/data |
180
+ | \`POST /__card/:id\` | 写卡片(带历史快照) |
181
+ | \`GET /__validate/:id\` | 契约校验(跑 \`skills/\` 里的 Python 校验器) |
182
+ | \`GET /__render-status/:id\` | SSR 渲染自检(绑定错误 / 组件分布 / 运行时异常) |
183
+ | \`POST /__ai/chat\` | AI 开发助手(需在 \`.env.cb.local\` 配 AI_BASE_URL / AI_API_KEY / AI_MODEL) |
184
+
185
+ ## 让 AI 工具看到 skills/
186
+
187
+ \`\`\`bash
188
+ npm run link:skills # 交互式选择 Codex / Claude / WorkBuddy 等,建立项目级技能软链
189
+ \`\`\`
190
+
191
+ ## FinMall 远端能力(可选)
192
+
193
+ 同步 / 保存 / 切图上传需要已登录的 FinMall 会话与 \`playwright\`
194
+ (cardbuddy 的 optionalDependency,装包时默认会装)。凭据只落在本机
195
+ \`skills/finmall-session-navigator/.local/credentials.json\`,已被 .gitignore 忽略。
196
+ `
197
+ }
198
+
199
+ function projectPackageJson(projectName, version) {
200
+ return (
201
+ JSON.stringify(
202
+ {
203
+ name: projectName,
204
+ version: '0.1.0',
205
+ private: true,
206
+ description: 'CardBuddy 卡片开发最小实例:本地服务 + 内置编辑器预览 + AI 协作技能库。',
207
+ scripts: {
208
+ dev: 'cardbuddy',
209
+ start: 'cardbuddy',
210
+ preview: 'cardbuddy --preview',
211
+ 'link:skills': 'node tools/link-skills.mjs',
212
+ },
213
+ devDependencies: {
214
+ cardbuddy: `^${version}`,
215
+ },
216
+ },
217
+ null,
218
+ 2
219
+ ) + '\n'
220
+ )
221
+ }
222
+
223
+ /**
224
+ * 技能库源:发布态为包内快照 dist/vendored/skills;源码态回退仓库 skills/。
225
+ * @param {ReturnType<import('./config.js').loadConfig>} config
226
+ * @returns {string|null}
227
+ */
228
+ export function resolveSkillsSource(config) {
229
+ const candidates = [
230
+ config.vendoredSkillsDir,
231
+ // 源码态(node packages/cardbuddy/src/cli.js):上三级即仓库根 → <repo>/skills
232
+ path.resolve(__dirname, '..', '..', '..', 'skills'),
233
+ ]
234
+ for (const dir of candidates) {
235
+ if (dir && fs.existsSync(path.join(dir, 'dsl-card-generator'))) return dir
236
+ }
237
+ return null
238
+ }
239
+
240
+ /**
241
+ * 示例卡源目录:优先包内 templates(构建期生成 + 过校验);源码态没有 dist 时,
242
+ * 现场用技能库的 scaffold_card.mjs 生成一份到临时目录(同一套产物,零漂移)。
243
+ * @returns {string|null} 含 schema.json / data.json 的目录
244
+ */
245
+ function resolveSampleCardSource(config, skillsSrc) {
246
+ const candidates = [
247
+ path.join(config.vendorRoot || '', 'templates', SAMPLE_CARD_ID),
248
+ path.resolve(__dirname, 'vendored', 'templates', SAMPLE_CARD_ID),
249
+ ]
250
+ for (const dir of candidates) {
251
+ if (dir && fs.existsSync(path.join(dir, 'schema.json'))) return dir
252
+ }
253
+ if (!skillsSrc) return null
254
+ const scaffold = path.join(skillsSrc, 'dsl-card-generator', 'scripts', 'scaffold_card.mjs')
255
+ if (!fs.existsSync(scaffold)) return null
256
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'cardbuddy-sample-'))
257
+ try {
258
+ execFileSync(
259
+ process.execPath,
260
+ [scaffold, '--intent', 'detail', '--id', SAMPLE_CARD_ID, '--name', '示例卡片', '--out', tmp, '--force'],
261
+ { stdio: 'pipe' }
262
+ )
263
+ } catch {
264
+ return null
265
+ }
266
+ const made = path.join(tmp, SAMPLE_CARD_ID)
267
+ return fs.existsSync(path.join(made, 'schema.json')) ? made : null
268
+ }
269
+
270
+ /** link-skills.mjs 源:包内快照 tools/ 优先,源码态回退仓库 tools/ */
271
+ function resolveLinkSkillsSource(config) {
272
+ const candidates = [
273
+ path.join(config.vendorRoot || '', 'tools', 'link-skills.mjs'),
274
+ path.resolve(__dirname, 'vendored', 'tools', 'link-skills.mjs'),
275
+ path.resolve(__dirname, '..', '..', '..', 'tools', 'link-skills.mjs'),
276
+ ]
277
+ for (const f of candidates) if (f && fs.existsSync(f)) return f
278
+ return null
279
+ }
280
+
281
+ /**
282
+ * 执行初始化。
283
+ * @param {object} opts
284
+ * @param {string} [opts.targetDir='.'] 目标工程根
285
+ * @param {boolean} [opts.force] 覆盖已存在文件
286
+ * @param {boolean} [opts.dryRun] 只报告不落盘
287
+ * @param {boolean} [opts.skipSkills] 不释放技能库
288
+ * @param {boolean} [opts.skipSample] 不生成示例卡
289
+ * @param {ReturnType<import('./config.js').loadConfig>} opts.config
290
+ * @param {(msg: string) => void} [opts.log]
291
+ * @returns {Promise<number>} 进程退出码
292
+ */
293
+ export async function runInit({
294
+ targetDir = '.',
295
+ force = false,
296
+ dryRun = false,
297
+ skipSkills = false,
298
+ skipSample = false,
299
+ config,
300
+ log = (m) => console.log(m),
301
+ }) {
302
+ const target = path.resolve(targetDir)
303
+ const tag = chalk.magenta('▌ ') + chalk.magenta.bold('cardbuddy init') + ' '
304
+ const say = (msg) => log(tag + msg)
305
+ const ok = (msg) => say(chalk.green(`• ${msg}`))
306
+ const dim = (msg) => say(chalk.dim(`• ${msg}`))
307
+ const opts = { force, dryRun }
308
+
309
+ if (dryRun) say(chalk.yellow('(dry-run:只报告将要做的事,不落盘)'))
310
+ if (!fs.existsSync(target)) {
311
+ if (!dryRun) fs.mkdirSync(target, { recursive: true })
312
+ say(`${dryRun ? '将创建' : '已创建'}目录 ${target}`)
313
+ } else if (!fs.statSync(target).isDirectory()) {
314
+ log(chalk.red(`✖ 目标不是目录:${target}`))
315
+ return 1
316
+ }
317
+ say(`目标工程根:${target}`)
318
+
319
+ const projectName = path.basename(target) || 'cardbuddy-project'
320
+
321
+ // 1) 卡片目录骨架
322
+ const cardsDir = path.join(target, 'src', 'cards')
323
+ const cardsExisted = fs.existsSync(cardsDir)
324
+ if (!dryRun) fs.mkdirSync(cardsDir, { recursive: true })
325
+ writeFileSafe(path.join(cardsDir, '.gitkeep'), '', { force: false, dryRun })
326
+ cardsExisted ? dim('src/cards/ 已存在(跳过)') : ok('已建 src/cards/')
327
+
328
+ // 2) 释放技能库
329
+ const skillsSrc = skipSkills ? null : resolveSkillsSource(config)
330
+ if (skipSkills) {
331
+ dim('跳过技能库释放(--no-skills)')
332
+ } else if (!skillsSrc) {
333
+ log(chalk.red('✖ 找不到可释放的技能库:包内 dist/vendored/skills 缺失(包安装不完整?)'))
334
+ return 1
335
+ } else {
336
+ const dest = path.join(target, 'skills')
337
+ if (path.resolve(skillsSrc) === path.resolve(dest)) {
338
+ dim(`技能库源与目标同路径,跳过释放(${skillsSrc})`)
339
+ } else {
340
+ const stat = copyTree(skillsSrc, dest, opts)
341
+ const names = fs
342
+ .readdirSync(skillsSrc, { withFileTypes: true })
343
+ .filter((e) => e.isDirectory() && !isSkipped(e.name, true))
344
+ .map((e) => e.name)
345
+ ok(
346
+ `${dryRun ? '将释放' : '已释放'}技能库 ${names.length} 个 skill → skills/ ` +
347
+ chalk.dim(`(新增 ${stat.copied} 文件 / ${fmtBytes(stat.bytes)},保留已存在 ${stat.skipped} 个${force ? ',--force 覆盖' : ''})`)
348
+ )
349
+ if (names.length) say(chalk.dim(` ${names.join('、')}`))
350
+ }
351
+ }
352
+
353
+ // 3) 示例卡(起服务即有卡可看,不必先会写 schema)
354
+ if (skipSample) {
355
+ dim('跳过示例卡(--no-sample)')
356
+ } else {
357
+ const sampleSrc = resolveSampleCardSource(config, skillsSrc || resolveSkillsSource(config))
358
+ if (!sampleSrc) {
359
+ say(chalk.yellow('• 未能生成示例卡(技能库缺失?)—— 可稍后手动放 src/cards/<id>/schema.json'))
360
+ } else {
361
+ const dest = path.join(cardsDir, SAMPLE_CARD_ID)
362
+ if (fs.existsSync(dest) && !force) {
363
+ dim(`示例卡 src/cards/${SAMPLE_CARD_ID}/ 已存在(跳过,--force 可覆盖)`)
364
+ } else {
365
+ const stat = copyTree(sampleSrc, dest, { force: true, dryRun })
366
+ ok(`${dryRun ? '将生成' : '已生成'}示例卡 src/cards/${SAMPLE_CARD_ID}/(${stat.copied} 文件,已过 schema 校验)`)
367
+ }
368
+ }
369
+ }
370
+
371
+ // 4) .env.cb 模板
372
+ const envState = writeFileSafe(path.join(target, '.env.cb'), ENV_TEMPLATE, opts)
373
+ envState === 'skipped'
374
+ ? dim('.env.cb 已存在(跳过,--force 可覆盖)')
375
+ : ok(`${dryRun ? '将生成' : '已生成'} .env.cb 模板(端口 / 远端基址 / AI 网关占位)`)
376
+ if (!fs.existsSync(path.join(target, '.env.cb.local'))) {
377
+ dim('私密配置请另建 .env.cb.local(AI_API_KEY 等;已被 .gitignore 忽略)')
378
+ }
379
+
380
+ // 5) package.json(声明 cardbuddy 依赖 + 启动脚本)
381
+ const version = ownVersion()
382
+ const pkgState = writeFileSafe(path.join(target, 'package.json'), projectPackageJson(projectName, version), opts)
383
+ pkgState === 'skipped'
384
+ ? dim('package.json 已存在(跳过,--force 可覆盖)')
385
+ : ok(`${dryRun ? '将生成' : '已生成'} package.json(cardbuddy ^${version} + dev / preview / link:skills 脚本)`)
386
+
387
+ // 6) tools/link-skills.mjs(把 skills/ 链给 AI 工具)
388
+ const linkSrc = resolveLinkSkillsSource(config)
389
+ if (linkSrc) {
390
+ const dest = path.join(target, 'tools', 'link-skills.mjs')
391
+ const st = writeFileSafe(dest, fs.readFileSync(linkSrc, 'utf8'), opts)
392
+ st === 'skipped' ? dim('tools/link-skills.mjs 已存在(跳过)') : ok(`${dryRun ? '将释放' : '已释放'} tools/link-skills.mjs(npm run link:skills 用)`)
393
+ }
394
+
395
+ // 7) .gitignore 补齐(只追加缺失条目,不重写既有内容)
396
+ const giFile = path.join(target, '.gitignore')
397
+ const existing = fs.existsSync(giFile) ? fs.readFileSync(giFile, 'utf8') : ''
398
+ const existingLines = new Set(existing.split('\n').map((l) => l.trim()))
399
+ const missing = GITIGNORE_ENTRIES.filter((e) => !existingLines.has(e))
400
+ if (missing.length) {
401
+ const block =
402
+ (existing && !existing.endsWith('\n') ? '\n' : '') +
403
+ (existing ? '' : '# CardBuddy\n') +
404
+ missing.join('\n') +
405
+ '\n'
406
+ if (!dryRun) fs.appendFileSync(giFile, block, 'utf8')
407
+ ok(`${dryRun ? '将补' : '已补'} .gitignore:${missing.join('、')}`)
408
+ } else {
409
+ dim('.gitignore 无需补充')
410
+ }
411
+
412
+ // 8) README.md
413
+ const readmeState = writeFileSafe(path.join(target, 'README.md'), projectReadme(projectName, version), opts)
414
+ readmeState === 'skipped' ? dim('README.md 已存在(跳过)') : ok(`${dryRun ? '将生成' : '已生成'} README.md(上手说明)`)
415
+
416
+ // 收尾
417
+ const hasNodeModules = fs.existsSync(path.join(target, 'node_modules', 'cardbuddy'))
418
+ log('')
419
+ log(tag + chalk.green(dryRun ? 'dry-run 完成(未落盘)' : '初始化完成'))
420
+ log(tag + chalk.dim('下一步:'))
421
+ log(tag + chalk.dim(` 1) cd ${target}`))
422
+ log(tag + chalk.dim(` 2) ${hasNodeModules ? 'npm run preview' : 'npm install && npm run preview'} # 本地服务 + 内置编辑器,自动开浏览器`))
423
+ log(tag + chalk.dim(' 3) 改 src/cards/helloCard/schema.json 看热更新;AI 助手密钥写 .env.cb.local'))
424
+ return 0
425
+ }