sumulige-claude 1.0.9 → 1.0.11

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 (299) hide show
  1. package/.claude/.version +1 -0
  2. package/.claude/AGENTS.md +9 -9
  3. package/.claude/commands/commit-push-pr.md +23 -3
  4. package/.claude/settings.local.json +15 -1
  5. package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
  6. package/.claude/skills/algorithmic-art/SKILL.md +405 -0
  7. package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
  8. package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
  9. package/.claude/skills/brand-guidelines/LICENSE.txt +202 -0
  10. package/.claude/skills/brand-guidelines/SKILL.md +73 -0
  11. package/.claude/skills/canvas-design/LICENSE.txt +202 -0
  12. package/.claude/skills/canvas-design/SKILL.md +130 -0
  13. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  14. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  15. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  16. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  17. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  18. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  19. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  20. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  21. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  22. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  23. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  24. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  25. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  26. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  27. package/.claude/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  28. package/.claude/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  29. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  30. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  31. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  32. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  33. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  34. package/.claude/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  35. package/.claude/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  36. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  37. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  38. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  39. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  40. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  41. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  42. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  43. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  44. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  45. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  46. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  47. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  48. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  49. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  50. package/.claude/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  51. package/.claude/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  52. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  53. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  54. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  55. package/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  56. package/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  57. package/.claude/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  58. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  59. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  60. package/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  61. package/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  62. package/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  63. package/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  64. package/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  65. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  66. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  67. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  68. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  69. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  70. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  71. package/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  72. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  73. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  74. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  75. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  76. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  77. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  78. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  79. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  80. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  81. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  82. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  83. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  84. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  85. package/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  86. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  87. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  88. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  89. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  90. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  91. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  92. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  93. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  94. package/.claude/skills/doc-coauthoring/SKILL.md +375 -0
  95. package/.claude/skills/docx/LICENSE.txt +30 -0
  96. package/.claude/skills/docx/SKILL.md +197 -0
  97. package/.claude/skills/docx/docx-js.md +350 -0
  98. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  99. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  100. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  101. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  102. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  103. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  104. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  105. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  106. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  107. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  108. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  109. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  110. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  111. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  112. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  113. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  114. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  115. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  116. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  117. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  118. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  119. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  120. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  121. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  122. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  123. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  124. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  125. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  126. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  127. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  128. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  129. package/.claude/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  130. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  131. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  132. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  133. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  134. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  135. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  136. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  137. package/.claude/skills/docx/ooxml/scripts/pack.py +159 -0
  138. package/.claude/skills/docx/ooxml/scripts/unpack.py +29 -0
  139. package/.claude/skills/docx/ooxml/scripts/validate.py +69 -0
  140. package/.claude/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  141. package/.claude/skills/docx/ooxml/scripts/validation/base.py +951 -0
  142. package/.claude/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  143. package/.claude/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  144. package/.claude/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  145. package/.claude/skills/docx/ooxml.md +610 -0
  146. package/.claude/skills/docx/scripts/__init__.py +1 -0
  147. package/.claude/skills/docx/scripts/document.py +1276 -0
  148. package/.claude/skills/docx/scripts/templates/comments.xml +3 -0
  149. package/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  150. package/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  151. package/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
  152. package/.claude/skills/docx/scripts/templates/people.xml +3 -0
  153. package/.claude/skills/docx/scripts/utilities.py +374 -0
  154. package/.claude/skills/frontend-design/LICENSE.txt +177 -0
  155. package/.claude/skills/frontend-design/SKILL.md +42 -0
  156. package/.claude/skills/internal-comms/LICENSE.txt +202 -0
  157. package/.claude/skills/internal-comms/SKILL.md +32 -0
  158. package/.claude/skills/internal-comms/examples/3p-updates.md +47 -0
  159. package/.claude/skills/internal-comms/examples/company-newsletter.md +65 -0
  160. package/.claude/skills/internal-comms/examples/faq-answers.md +30 -0
  161. package/.claude/skills/internal-comms/examples/general-comms.md +16 -0
  162. package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
  163. package/.claude/skills/mcp-builder/SKILL.md +236 -0
  164. package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
  165. package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  166. package/.claude/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  167. package/.claude/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  168. package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
  169. package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
  170. package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  171. package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
  172. package/.claude/skills/pdf/LICENSE.txt +30 -0
  173. package/.claude/skills/pdf/SKILL.md +294 -0
  174. package/.claude/skills/pdf/forms.md +205 -0
  175. package/.claude/skills/pdf/reference.md +612 -0
  176. package/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  177. package/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  178. package/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
  179. package/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  180. package/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
  181. package/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
  182. package/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  183. package/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  184. package/.claude/skills/pptx/LICENSE.txt +30 -0
  185. package/.claude/skills/pptx/SKILL.md +484 -0
  186. package/.claude/skills/pptx/html2pptx.md +625 -0
  187. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  188. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  189. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  190. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  191. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  192. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  193. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  194. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  195. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  196. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  197. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  198. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  199. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  200. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  201. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  202. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  203. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  204. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  205. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  206. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  207. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  208. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  209. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  210. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  211. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  212. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  213. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  214. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  215. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  216. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  217. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  218. package/.claude/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  219. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  220. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  221. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  222. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  223. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  224. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  225. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  226. package/.claude/skills/pptx/ooxml/scripts/pack.py +159 -0
  227. package/.claude/skills/pptx/ooxml/scripts/unpack.py +29 -0
  228. package/.claude/skills/pptx/ooxml/scripts/validate.py +69 -0
  229. package/.claude/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  230. package/.claude/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  231. package/.claude/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  232. package/.claude/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  233. package/.claude/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  234. package/.claude/skills/pptx/ooxml.md +427 -0
  235. package/.claude/skills/pptx/scripts/html2pptx.js +979 -0
  236. package/.claude/skills/pptx/scripts/inventory.py +1020 -0
  237. package/.claude/skills/pptx/scripts/rearrange.py +231 -0
  238. package/.claude/skills/pptx/scripts/replace.py +385 -0
  239. package/.claude/skills/pptx/scripts/thumbnail.py +450 -0
  240. package/.claude/skills/skill-creator/LICENSE.txt +202 -0
  241. package/.claude/skills/skill-creator/SKILL.md +356 -0
  242. package/.claude/skills/skill-creator/references/output-patterns.md +82 -0
  243. package/.claude/skills/skill-creator/references/workflows.md +28 -0
  244. package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
  245. package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
  246. package/.claude/skills/skill-creator/scripts/quick_validate.py +95 -0
  247. package/.claude/skills/slack-gif-creator/LICENSE.txt +202 -0
  248. package/.claude/skills/slack-gif-creator/SKILL.md +254 -0
  249. package/.claude/skills/slack-gif-creator/core/easing.py +234 -0
  250. package/.claude/skills/slack-gif-creator/core/frame_composer.py +176 -0
  251. package/.claude/skills/slack-gif-creator/core/gif_builder.py +269 -0
  252. package/.claude/skills/slack-gif-creator/core/validators.py +136 -0
  253. package/.claude/skills/slack-gif-creator/requirements.txt +4 -0
  254. package/.claude/skills/template/SKILL.md +6 -0
  255. package/.claude/skills/theme-factory/LICENSE.txt +202 -0
  256. package/.claude/skills/theme-factory/SKILL.md +59 -0
  257. package/.claude/skills/theme-factory/theme-showcase.pdf +0 -0
  258. package/.claude/skills/theme-factory/themes/arctic-frost.md +19 -0
  259. package/.claude/skills/theme-factory/themes/botanical-garden.md +19 -0
  260. package/.claude/skills/theme-factory/themes/desert-rose.md +19 -0
  261. package/.claude/skills/theme-factory/themes/forest-canopy.md +19 -0
  262. package/.claude/skills/theme-factory/themes/golden-hour.md +19 -0
  263. package/.claude/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  264. package/.claude/skills/theme-factory/themes/modern-minimalist.md +19 -0
  265. package/.claude/skills/theme-factory/themes/ocean-depths.md +19 -0
  266. package/.claude/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  267. package/.claude/skills/theme-factory/themes/tech-innovation.md +19 -0
  268. package/.claude/skills/web-artifacts-builder/LICENSE.txt +202 -0
  269. package/.claude/skills/web-artifacts-builder/SKILL.md +74 -0
  270. package/.claude/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  271. package/.claude/skills/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  272. package/.claude/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  273. package/.claude/skills/webapp-testing/LICENSE.txt +202 -0
  274. package/.claude/skills/webapp-testing/SKILL.md +96 -0
  275. package/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
  276. package/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  277. package/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  278. package/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
  279. package/.claude/skills/xlsx/LICENSE.txt +30 -0
  280. package/.claude/skills/xlsx/SKILL.md +289 -0
  281. package/.claude/skills/xlsx/recalc.py +178 -0
  282. package/.claude-plugin/marketplace.json +2 -2
  283. package/AGENTS.md +165 -86
  284. package/README.md +22 -0
  285. package/cli.js +7 -2
  286. package/development/todos/INDEX.md +10 -1
  287. package/jest.config.js +61 -0
  288. package/lib/commands.js +67 -0
  289. package/lib/migrations.js +154 -0
  290. package/package.json +7 -2
  291. package/scripts/fix-hooks.mjs +97 -0
  292. package/template/.claude/commands/commit-push-pr.md +23 -3
  293. package/template/.claude/settings.json +114 -50
  294. package/tests/README.md +263 -0
  295. package/tests/commands.test.js +163 -0
  296. package/tests/config.test.js +100 -0
  297. package/tests/marketplace.test.js +304 -0
  298. package/tests/migrations.test.js +187 -0
  299. package/tests/utils.test.js +167 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * Marketplace 模块单元测试
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const mockFs = require('mock-fs');
8
+ const sinon = require('sinon');
9
+
10
+ // 在 mock 之前加载模块
11
+ const marketplace = require('../lib/marketplace');
12
+
13
+ // 手动实现 parseSimpleYaml 用于测试(与模块中相同的实现)
14
+ function parseSimpleYaml(content) {
15
+ const result = { skills: [] };
16
+ let currentSection = null;
17
+ let currentSkill = null;
18
+ let currentKey = null;
19
+
20
+ content.split('\n').forEach(line => {
21
+ const trimmed = line.trim();
22
+ const indent = line.search(/\S/);
23
+
24
+ // Skip empty lines and comments
25
+ if (!trimmed || trimmed.startsWith('#')) {
26
+ return;
27
+ }
28
+
29
+ // Version
30
+ if (trimmed.startsWith('version:')) {
31
+ result.version = parseInt(trimmed.split(':')[1].trim());
32
+ return;
33
+ }
34
+
35
+ // Skills array starts
36
+ if (trimmed === 'skills:') {
37
+ currentSection = 'skills';
38
+ return;
39
+ }
40
+
41
+ // New skill entry (starts with -)
42
+ if (trimmed.startsWith('- name:')) {
43
+ if (currentSkill) {
44
+ result.skills.push(currentSkill);
45
+ }
46
+ currentSkill = { name: trimmed.split(':')[1].trim() };
47
+ return;
48
+ }
49
+
50
+ // Skill properties
51
+ if (currentSection === 'skills' && currentSkill) {
52
+ // Determine nesting level by indent
53
+ const isTopLevel = indent === 2;
54
+
55
+ if (isTopLevel) {
56
+ const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
57
+ if (match) {
58
+ currentKey = match[1];
59
+ let value = match[2].trim();
60
+
61
+ // Handle arrays
62
+ if (value === '[]') {
63
+ value = [];
64
+ } else if (value === 'true') {
65
+ value = true;
66
+ } else if (value === 'false') {
67
+ value = false;
68
+ } else if (value.startsWith('"') || value.startsWith("'")) {
69
+ value = value.slice(1, -1);
70
+ }
71
+
72
+ // Initialize nested objects for special keys
73
+ if (['source', 'target', 'author', 'sync'].includes(currentKey)) {
74
+ currentSkill[currentKey] = {};
75
+ // Store the value for potential later use
76
+ currentSkill[currentKey]._value = value;
77
+ } else {
78
+ currentSkill[currentKey] = value;
79
+ }
80
+ }
81
+ } else if (currentKey) {
82
+ // Nested property
83
+ const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
84
+ if (match) {
85
+ let value = match[2].trim();
86
+ if (value === 'true') value = true;
87
+ if (value === 'false') value = false;
88
+ if (value === '[]') value = [];
89
+ currentSkill[currentKey][match[1]] = value;
90
+ }
91
+ }
92
+ }
93
+ });
94
+
95
+ // Push last skill
96
+ if (currentSkill) {
97
+ result.skills.push(currentSkill);
98
+ }
99
+
100
+ return result;
101
+ }
102
+
103
+ describe('Marketplace Module', () => {
104
+ let consoleLogStub;
105
+ let execSyncStub;
106
+
107
+ beforeEach(() => {
108
+ jest.resetModules();
109
+ // Mock 文件系统,保留项目目录
110
+ mockFs({
111
+ '/project': {
112
+ 'sources.yaml': `version: 1
113
+ skills:
114
+ - name: test-skill
115
+ description: "A test skill"
116
+ native: true
117
+ - name: external-skill
118
+ description: "External skill"
119
+ source:
120
+ repo: owner/repo`,
121
+ '.claude-plugin': {
122
+ 'marketplace.json': JSON.stringify({
123
+ plugins: [],
124
+ metadata: {
125
+ skill_count: 2,
126
+ categories: {
127
+ tools: { name: 'CLI 工具', icon: '🔧' }
128
+ }
129
+ }
130
+ })
131
+ },
132
+ 'config': {
133
+ 'skill-categories.json': JSON.stringify({
134
+ tools: { name: 'CLI 工具', icon: '🔧' },
135
+ workflow: { name: '工作流编排', icon: '🎼' }
136
+ })
137
+ }
138
+ }
139
+ }, {
140
+ // 不 mock 项目的 lib 目录
141
+ [path.join(__dirname, '../lib')]: true
142
+ });
143
+
144
+ // Stub console.log to avoid actual output
145
+ consoleLogStub = sinon.stub(console, 'log');
146
+ });
147
+
148
+ afterEach(() => {
149
+ mockFs.restore();
150
+ if (consoleLogStub) consoleLogStub.restore();
151
+ if (execSyncStub) execSyncStub.restore();
152
+ });
153
+
154
+ describe('parseSimpleYaml', () => {
155
+ it('should parse version number', () => {
156
+ const yaml = `version: 1
157
+ skills:
158
+ - name: test-skill`;
159
+
160
+ const result = parseSimpleYaml(yaml);
161
+
162
+ expect(result.version).toBe(1);
163
+ });
164
+
165
+ it('should parse skill names', () => {
166
+ const yaml = `skills:
167
+ - name: skill-one
168
+ - name: skill-two
169
+ - name: skill-three`;
170
+
171
+ const result = parseSimpleYaml(yaml);
172
+
173
+ expect(result.skills).toHaveLength(3);
174
+ expect(result.skills[0].name).toBe('skill-one');
175
+ expect(result.skills[1].name).toBe('skill-two');
176
+ expect(result.skills[2].name).toBe('skill-three');
177
+ });
178
+
179
+ it('should handle empty skills array', () => {
180
+ const yaml = `version: 1`;
181
+
182
+ const result = parseSimpleYaml(yaml);
183
+
184
+ expect(result.skills).toEqual([]);
185
+ });
186
+
187
+ it('should skip comments', () => {
188
+ const yaml = `# Comment
189
+ skills:
190
+ # Another comment
191
+ - name: test`;
192
+
193
+ const result = parseSimpleYaml(yaml);
194
+
195
+ expect(result.skills).toHaveLength(1);
196
+ expect(result.skills[0].name).toBe('test');
197
+ });
198
+
199
+ it('should handle empty lines', () => {
200
+ const yaml = `skills:
201
+
202
+ - name: test
203
+
204
+ - name: test2`;
205
+
206
+ const result = parseSimpleYaml(yaml);
207
+
208
+ expect(result.skills).toHaveLength(2);
209
+ });
210
+ });
211
+
212
+ describe('marketplaceCommands', () => {
213
+ describe('marketplace:list', () => {
214
+ it('should be a function', () => {
215
+ expect(typeof marketplace.marketplaceCommands['marketplace:list']).toBe('function');
216
+ });
217
+
218
+ it('should output to console', () => {
219
+ marketplace.marketplaceCommands['marketplace:list']();
220
+
221
+ expect(consoleLogStub.called).toBe(true);
222
+ });
223
+ });
224
+
225
+ describe('marketplace:install', () => {
226
+ it('should show usage when no skill name provided', () => {
227
+ marketplace.marketplaceCommands['marketplace:install']();
228
+
229
+ expect(consoleLogStub.called).toBe(true);
230
+ const output = consoleLogStub.args.flat().join(' ');
231
+ expect(output).toContain('Usage');
232
+ });
233
+ });
234
+
235
+ describe('marketplace:sync', () => {
236
+ it('should be a function', () => {
237
+ expect(typeof marketplace.marketplaceCommands['marketplace:sync']).toBe('function');
238
+ });
239
+
240
+ it('should output sync message', () => {
241
+ marketplace.marketplaceCommands['marketplace:sync']();
242
+
243
+ expect(consoleLogStub.called).toBe(true);
244
+ });
245
+ });
246
+
247
+ describe('marketplace:add', () => {
248
+ it('should show usage when no repo provided', () => {
249
+ marketplace.marketplaceCommands['marketplace:add']();
250
+
251
+ expect(consoleLogStub.called).toBe(true);
252
+ const output = consoleLogStub.args.flat().join(' ');
253
+ expect(output).toContain('Usage');
254
+ });
255
+
256
+ it('should validate repo format', () => {
257
+ marketplace.marketplaceCommands['marketplace:add']('invalid-repo-format');
258
+
259
+ const output = consoleLogStub.args.flat().join(' ');
260
+ expect(output).toContain('Invalid');
261
+ });
262
+ });
263
+
264
+ describe('marketplace:remove', () => {
265
+ it('should show usage when no skill name provided', () => {
266
+ marketplace.marketplaceCommands['marketplace:remove']();
267
+
268
+ expect(consoleLogStub.called).toBe(true);
269
+ const output = consoleLogStub.args.flat().join(' ');
270
+ expect(output).toContain('Usage');
271
+ });
272
+ });
273
+
274
+ describe('marketplace:status', () => {
275
+ it('should be a function', () => {
276
+ expect(typeof marketplace.marketplaceCommands['marketplace:status']).toBe('function');
277
+ });
278
+
279
+ it('should output status information', () => {
280
+ marketplace.marketplaceCommands['marketplace:status']();
281
+
282
+ expect(consoleLogStub.called).toBe(true);
283
+ });
284
+ });
285
+ });
286
+
287
+ describe('exports', () => {
288
+ it('should export marketplaceCommands object', () => {
289
+ expect(marketplace.marketplaceCommands).toBeDefined();
290
+ expect(typeof marketplace.marketplaceCommands).toBe('object');
291
+ });
292
+
293
+ it('should export all marketplace commands', () => {
294
+ const commands = marketplace.marketplaceCommands;
295
+
296
+ expect(commands['marketplace:list']).toBeDefined();
297
+ expect(commands['marketplace:install']).toBeDefined();
298
+ expect(commands['marketplace:sync']).toBeDefined();
299
+ expect(commands['marketplace:add']).toBeDefined();
300
+ expect(commands['marketplace:remove']).toBeDefined();
301
+ expect(commands['marketplace:status']).toBeDefined();
302
+ });
303
+ });
304
+ });
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Migrations 模块单元测试
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const mockFs = require('mock-fs');
8
+
9
+ // 在 mock 之前加载模块
10
+ const migrations = require('../lib/migrations');
11
+
12
+ describe('Migrations Module', () => {
13
+ let originalFs = { ...fs };
14
+
15
+ beforeEach(() => {
16
+ // Mock 文件系统,保留一些必要的路径
17
+ mockFs({
18
+ '/test-project': {
19
+ '.claude': {}
20
+ }
21
+ }, {
22
+ // 不 mock 项目的 lib 目录
23
+ [path.join(__dirname, '../lib')]: true
24
+ });
25
+ });
26
+
27
+ afterEach(() => {
28
+ mockFs.restore();
29
+ });
30
+
31
+ describe('getProjectVersion', () => {
32
+ it('should return 1.0.0 when version file does not exist', () => {
33
+ const version = migrations.getProjectVersion('/test-project');
34
+ expect(version).toBe('1.0.0');
35
+ });
36
+
37
+ it('should read version from file', () => {
38
+ const versionFile = path.join('/test-project', '.claude', '.version');
39
+ fs.writeFileSync(versionFile, '1.0.5\n');
40
+
41
+ const version = migrations.getProjectVersion('/test-project');
42
+ expect(version).toBe('1.0.5');
43
+ });
44
+
45
+ it('should trim whitespace from version', () => {
46
+ const versionFile = path.join('/test-project', '.claude', '.version');
47
+ fs.writeFileSync(versionFile, ' 1.0.8 \n');
48
+
49
+ const version = migrations.getProjectVersion('/test-project');
50
+ expect(version).toBe('1.0.8');
51
+ });
52
+
53
+ it('should return 1.0.0 on read error', () => {
54
+ const version = migrations.getProjectVersion('/nonexistent');
55
+ expect(version).toBe('1.0.0');
56
+ });
57
+ });
58
+
59
+ describe('setProjectVersion', () => {
60
+ it('should write version to file', () => {
61
+ migrations.setProjectVersion('/test-project', '1.0.7');
62
+
63
+ const versionFile = path.join('/test-project', '.claude', '.version');
64
+ expect(fs.existsSync(versionFile)).toBe(true);
65
+
66
+ const content = fs.readFileSync(versionFile, 'utf-8');
67
+ expect(content.trim()).toBe('1.0.7');
68
+ });
69
+
70
+ it('should add newline after version', () => {
71
+ migrations.setProjectVersion('/test-project', '1.0.9');
72
+
73
+ const versionFile = path.join('/test-project', '.claude', '.version');
74
+ const content = fs.readFileSync(versionFile, 'utf-8');
75
+ expect(content).toBe('1.0.9\n');
76
+ });
77
+
78
+ it('should create .claude directory if not exists', () => {
79
+ // 注意:setProjectVersion 不会自动创建目录
80
+ // 需要先创建目录
81
+ fs.mkdirSync(path.join('/new-project', '.claude'), { recursive: true });
82
+ migrations.setProjectVersion('/new-project', '1.0.1');
83
+
84
+ const versionFile = path.join('/new-project', '.claude', '.version');
85
+ expect(fs.existsSync(versionFile)).toBe(true);
86
+ });
87
+ });
88
+
89
+ describe('compareVersions', () => {
90
+ it('should return -1 when v1 < v2', () => {
91
+ expect(migrations.compareVersions('1.0.0', '1.0.1')).toBe(-1);
92
+ expect(migrations.compareVersions('1.0.0', '1.1.0')).toBe(-1);
93
+ expect(migrations.compareVersions('1.0.0', '2.0.0')).toBe(-1);
94
+ });
95
+
96
+ it('should return 1 when v1 > v2', () => {
97
+ expect(migrations.compareVersions('1.0.1', '1.0.0')).toBe(1);
98
+ expect(migrations.compareVersions('1.1.0', '1.0.0')).toBe(1);
99
+ expect(migrations.compareVersions('2.0.0', '1.0.0')).toBe(1);
100
+ });
101
+
102
+ it('should return 0 when v1 === v2', () => {
103
+ expect(migrations.compareVersions('1.0.0', '1.0.0')).toBe(0);
104
+ expect(migrations.compareVersions('1.5.10', '1.5.10')).toBe(0);
105
+ });
106
+
107
+ it('should handle version comparison correctly', () => {
108
+ // Patch version comparison
109
+ expect(migrations.compareVersions('1.0.5', '1.0.10')).toBe(-1);
110
+ expect(migrations.compareVersions('1.0.10', '1.0.5')).toBe(1);
111
+
112
+ // Minor version comparison
113
+ expect(migrations.compareVersions('1.5.0', '1.10.0')).toBe(-1);
114
+
115
+ // Major version comparison
116
+ expect(migrations.compareVersions('2.0.0', '10.0.0')).toBe(-1);
117
+ });
118
+
119
+ it('should handle version strings with different formats', () => {
120
+ expect(migrations.compareVersions('1', '1.0.0')).toBe(0);
121
+ expect(migrations.compareVersions('1.0', '1.0.0')).toBe(0);
122
+ });
123
+ });
124
+
125
+ describe('runMigrations', () => {
126
+ it('should return success when already at latest version', () => {
127
+ // 设置当前版本为最新
128
+ migrations.setProjectVersion('/test-project', migrations.TEMPLATE_VERSION);
129
+
130
+ const result = migrations.runMigrations('/test-project', true);
131
+
132
+ expect(result.success).toBe(true);
133
+ expect(result.migrations).toEqual([]);
134
+ expect(result.currentVersion).toBe(migrations.TEMPLATE_VERSION);
135
+ });
136
+
137
+ it('should return success when version is newer than template', () => {
138
+ // 设置一个未来版本
139
+ migrations.setProjectVersion('/test-project', '2.0.0');
140
+
141
+ const result = migrations.runMigrations('/test-project', true);
142
+
143
+ expect(result.success).toBe(true);
144
+ expect(result.migrations).toEqual([]);
145
+ });
146
+
147
+ it('should return correct structure when pending migrations exist', () => {
148
+ // 设置旧版本
149
+ migrations.setProjectVersion('/test-project', '1.0.0');
150
+
151
+ // 创建需要迁移的 settings.json
152
+ const settingsFile = path.join('/test-project', '.claude', 'settings.json');
153
+ fs.writeFileSync(
154
+ settingsFile,
155
+ JSON.stringify({ matcher: {}, hooks: [] }, null, 2)
156
+ );
157
+
158
+ const result = migrations.runMigrations('/test-project', true);
159
+
160
+ expect(result).toBeDefined();
161
+ expect(typeof result.success).toBe('boolean');
162
+ expect(result.currentVersion).toBeDefined();
163
+ });
164
+
165
+ it('should handle missing settings.json gracefully', () => {
166
+ migrations.setProjectVersion('/test-project', '1.0.0');
167
+
168
+ const result = migrations.runMigrations('/test-project', true);
169
+
170
+ expect(result.success).toBe(true);
171
+ });
172
+ });
173
+
174
+ describe('exports', () => {
175
+ it('should export TEMPLATE_VERSION constant', () => {
176
+ expect(migrations.TEMPLATE_VERSION).toBeDefined();
177
+ expect(typeof migrations.TEMPLATE_VERSION).toBe('string');
178
+ });
179
+
180
+ it('should export all functions', () => {
181
+ expect(typeof migrations.getProjectVersion).toBe('function');
182
+ expect(typeof migrations.setProjectVersion).toBe('function');
183
+ expect(typeof migrations.compareVersions).toBe('function');
184
+ expect(typeof migrations.runMigrations).toBe('function');
185
+ });
186
+ });
187
+ });
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Utils 模块单元测试
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ const utils = require('../lib/utils');
10
+
11
+ describe('Utils Module', () => {
12
+ describe('copyRecursive', () => {
13
+ let tempSrc, tempDest;
14
+
15
+ beforeEach(() => {
16
+ // 创建临时测试目录
17
+ tempSrc = path.join(os.tmpdir(), 'test-src-' + Date.now());
18
+ tempDest = path.join(os.tmpdir(), 'test-dest-' + Date.now());
19
+ fs.mkdirSync(tempSrc, { recursive: true });
20
+ });
21
+
22
+ afterEach(() => {
23
+ // 清理临时目录
24
+ if (fs.existsSync(tempSrc)) {
25
+ fs.rmSync(tempSrc, { recursive: true, force: true });
26
+ }
27
+ if (fs.existsSync(tempDest)) {
28
+ fs.rmSync(tempDest, { recursive: true, force: true });
29
+ }
30
+ });
31
+
32
+ it('should return 0 when source does not exist', () => {
33
+ const nonExistent = path.join(os.tmpdir(), 'non-existent-' + Date.now());
34
+ const count = utils.copyRecursive(nonExistent, tempDest);
35
+
36
+ expect(count).toBe(0);
37
+ });
38
+
39
+ it('should copy files recursively', () => {
40
+ // 创建测试文件结构
41
+ fs.mkdirSync(path.join(tempSrc, 'subdir'));
42
+ fs.writeFileSync(path.join(tempSrc, 'file1.txt'), 'content1');
43
+ fs.writeFileSync(path.join(tempSrc, 'subdir', 'file2.txt'), 'content2');
44
+
45
+ const count = utils.copyRecursive(tempSrc, tempDest);
46
+
47
+ expect(count).toBe(2);
48
+ expect(fs.existsSync(path.join(tempDest, 'file1.txt'))).toBe(true);
49
+ expect(fs.existsSync(path.join(tempDest, 'subdir', 'file2.txt'))).toBe(true);
50
+ });
51
+
52
+ it('should set execute permission for script files', () => {
53
+ fs.writeFileSync(path.join(tempSrc, 'test.sh'), '#!/bin/bash\necho test');
54
+ fs.writeFileSync(path.join(tempSrc, 'test.cjs'), 'console.log("test");');
55
+ fs.writeFileSync(path.join(tempSrc, 'test.txt'), 'plain text');
56
+
57
+ utils.copyRecursive(tempSrc, tempDest);
58
+
59
+ // 检查 .sh 文件权限
60
+ const shStats = fs.statSync(path.join(tempDest, 'test.sh'));
61
+ const cjsStats = fs.statSync(path.join(tempDest, 'test.cjs'));
62
+ const txtStats = fs.statSync(path.join(tempDest, 'test.txt'));
63
+
64
+ // 检查执行权限 (0o755 的执行位)
65
+ expect(shStats.mode & 0o111).toBeTruthy();
66
+ expect(cjsStats.mode & 0o111).toBeTruthy();
67
+ // txt 文件不应该有执行权限
68
+ expect(txtStats.mode & 0o111).toBeFalsy();
69
+ });
70
+
71
+ it('should not overwrite when overwrite=false', () => {
72
+ fs.writeFileSync(path.join(tempSrc, 'file.txt'), 'new content');
73
+ fs.mkdirSync(tempDest, { recursive: true });
74
+ fs.writeFileSync(path.join(tempDest, 'file.txt'), 'old content');
75
+
76
+ const count = utils.copyRecursive(tempSrc, tempDest, false);
77
+
78
+ expect(count).toBe(0);
79
+ const content = fs.readFileSync(path.join(tempDest, 'file.txt'), 'utf-8');
80
+ expect(content).toBe('old content');
81
+ });
82
+
83
+ it('should overwrite when overwrite=true', () => {
84
+ fs.writeFileSync(path.join(tempSrc, 'file.txt'), 'new content');
85
+ fs.mkdirSync(tempDest, { recursive: true });
86
+ fs.writeFileSync(path.join(tempDest, 'file.txt'), 'old content');
87
+
88
+ const count = utils.copyRecursive(tempSrc, tempDest, true);
89
+
90
+ expect(count).toBe(1);
91
+ const content = fs.readFileSync(path.join(tempDest, 'file.txt'), 'utf-8');
92
+ expect(content).toBe('new content');
93
+ });
94
+ });
95
+
96
+ describe('ensureDir', () => {
97
+ it('should create directory if not exists', () => {
98
+ const tempDir = path.join(os.tmpdir(), 'test-ensure-' + Date.now());
99
+
100
+ utils.ensureDir(tempDir);
101
+
102
+ expect(fs.existsSync(tempDir)).toBe(true);
103
+
104
+ // 清理
105
+ fs.rmSync(tempDir, { recursive: true, force: true });
106
+ });
107
+
108
+ it('should not error if directory already exists', () => {
109
+ const tempDir = path.join(os.tmpdir(), 'test-ensure-' + Date.now());
110
+ fs.mkdirSync(tempDir, { recursive: true });
111
+
112
+ expect(() => utils.ensureDir(tempDir)).not.toThrow();
113
+
114
+ // 清理
115
+ fs.rmSync(tempDir, { recursive: true, force: true });
116
+ });
117
+
118
+ it('should create nested directories', () => {
119
+ const tempDir = path.join(os.tmpdir(), 'test-nested-' + Date.now(), 'level1', 'level2', 'level3');
120
+
121
+ utils.ensureDir(tempDir);
122
+
123
+ expect(fs.existsSync(tempDir)).toBe(true);
124
+
125
+ // 清理
126
+ fs.rmSync(path.join(os.tmpdir(), 'test-nested-' + Date.now()), { recursive: true, force: true });
127
+ });
128
+ });
129
+
130
+ describe('toTitleCase', () => {
131
+ it('should convert string to title case', () => {
132
+ expect(utils.toTitleCase('hello world')).toBe('Hello World');
133
+ expect(utils.toTitleCase('foo-bar')).toBe('Foo-Bar');
134
+ });
135
+
136
+ it('should handle single word', () => {
137
+ expect(utils.toTitleCase('hello')).toBe('Hello');
138
+ });
139
+
140
+ it('should handle empty string', () => {
141
+ expect(utils.toTitleCase('')).toBe('');
142
+ });
143
+
144
+ it('should handle already capitalized string', () => {
145
+ expect(utils.toTitleCase('Hello World')).toBe('Hello World');
146
+ });
147
+
148
+ it('should handle strings with multiple spaces', () => {
149
+ expect(utils.toTitleCase('hello world')).toBe('Hello World');
150
+ });
151
+
152
+ it('should preserve special characters', () => {
153
+ // 下划线 _ 是单词字符(\w),所以 _t 中的 t 前面没有单词边界
154
+ expect(utils.toTitleCase('hello-world_test')).toBe('Hello-World_test');
155
+ // 连字符 - 不是单词字符,所以后面的字母会被大写
156
+ expect(utils.toTitleCase('hello-world test')).toBe('Hello-World Test');
157
+ });
158
+ });
159
+
160
+ describe('exports', () => {
161
+ it('should export all functions', () => {
162
+ expect(typeof utils.copyRecursive).toBe('function');
163
+ expect(typeof utils.ensureDir).toBe('function');
164
+ expect(typeof utils.toTitleCase).toBe('function');
165
+ });
166
+ });
167
+ });