sumulige-claude 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) 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/commands/todos.md +41 -6
  5. package/.claude/hooks/session-restore.cjs +102 -0
  6. package/.claude/hooks/session-save.cjs +164 -0
  7. package/.claude/hooks/todo-manager.cjs +262 -141
  8. package/.claude/settings.local.json +25 -1
  9. package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
  10. package/.claude/skills/algorithmic-art/SKILL.md +405 -0
  11. package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
  12. package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
  13. package/.claude/skills/api-tester/SKILL.md +52 -23
  14. package/.claude/skills/brand-guidelines/LICENSE.txt +202 -0
  15. package/.claude/skills/brand-guidelines/SKILL.md +73 -0
  16. package/.claude/skills/canvas-design/LICENSE.txt +202 -0
  17. package/.claude/skills/canvas-design/SKILL.md +130 -0
  18. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  19. package/.claude/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  20. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  21. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  22. package/.claude/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  23. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  24. package/.claude/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  25. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  26. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  27. package/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  28. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  29. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  30. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  31. package/.claude/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  32. package/.claude/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  33. package/.claude/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  34. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  35. package/.claude/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  36. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  37. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  38. package/.claude/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  39. package/.claude/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  40. package/.claude/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  41. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  42. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  43. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  44. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  45. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  46. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  47. package/.claude/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  48. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  49. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  50. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  51. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  52. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  53. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  54. package/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  55. package/.claude/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  56. package/.claude/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  57. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  58. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  59. package/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  60. package/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  61. package/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  62. package/.claude/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  63. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  64. package/.claude/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  65. package/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  66. package/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  67. package/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  68. package/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  69. package/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  70. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  71. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  72. package/.claude/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  73. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  74. package/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  75. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  76. package/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  77. package/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  78. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  79. package/.claude/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  80. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  81. package/.claude/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  82. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  83. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  84. package/.claude/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  85. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  86. package/.claude/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  87. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  88. package/.claude/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  89. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  90. package/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  91. package/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  92. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  93. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  94. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  95. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  96. package/.claude/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  97. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  98. package/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  99. package/.claude/skills/doc-coauthoring/SKILL.md +375 -0
  100. package/.claude/skills/docx/LICENSE.txt +30 -0
  101. package/.claude/skills/docx/SKILL.md +197 -0
  102. package/.claude/skills/docx/docx-js.md +350 -0
  103. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  104. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  105. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  106. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  107. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  108. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  109. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  110. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  111. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  112. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  113. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  114. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  115. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  116. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  117. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  118. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  119. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  120. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  121. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  122. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  123. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  124. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  125. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  126. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  127. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  128. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  129. package/.claude/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  130. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  131. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  132. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  133. package/.claude/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  134. package/.claude/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  135. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  136. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  137. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  138. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  139. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  140. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  141. package/.claude/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  142. package/.claude/skills/docx/ooxml/scripts/pack.py +159 -0
  143. package/.claude/skills/docx/ooxml/scripts/unpack.py +29 -0
  144. package/.claude/skills/docx/ooxml/scripts/validate.py +69 -0
  145. package/.claude/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  146. package/.claude/skills/docx/ooxml/scripts/validation/base.py +951 -0
  147. package/.claude/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  148. package/.claude/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  149. package/.claude/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  150. package/.claude/skills/docx/ooxml.md +610 -0
  151. package/.claude/skills/docx/scripts/__init__.py +1 -0
  152. package/.claude/skills/docx/scripts/document.py +1276 -0
  153. package/.claude/skills/docx/scripts/templates/comments.xml +3 -0
  154. package/.claude/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  155. package/.claude/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  156. package/.claude/skills/docx/scripts/templates/commentsIds.xml +3 -0
  157. package/.claude/skills/docx/scripts/templates/people.xml +3 -0
  158. package/.claude/skills/docx/scripts/utilities.py +374 -0
  159. package/.claude/skills/frontend-design/LICENSE.txt +177 -0
  160. package/.claude/skills/frontend-design/SKILL.md +42 -0
  161. package/.claude/skills/internal-comms/LICENSE.txt +202 -0
  162. package/.claude/skills/internal-comms/SKILL.md +32 -0
  163. package/.claude/skills/internal-comms/examples/3p-updates.md +47 -0
  164. package/.claude/skills/internal-comms/examples/company-newsletter.md +65 -0
  165. package/.claude/skills/internal-comms/examples/faq-answers.md +30 -0
  166. package/.claude/skills/internal-comms/examples/general-comms.md +16 -0
  167. package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
  168. package/.claude/skills/mcp-builder/SKILL.md +236 -0
  169. package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
  170. package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  171. package/.claude/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  172. package/.claude/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  173. package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
  174. package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
  175. package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  176. package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
  177. package/.claude/skills/pdf/LICENSE.txt +30 -0
  178. package/.claude/skills/pdf/SKILL.md +294 -0
  179. package/.claude/skills/pdf/forms.md +205 -0
  180. package/.claude/skills/pdf/reference.md +612 -0
  181. package/.claude/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  182. package/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  183. package/.claude/skills/pdf/scripts/check_fillable_fields.py +12 -0
  184. package/.claude/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  185. package/.claude/skills/pdf/scripts/create_validation_image.py +41 -0
  186. package/.claude/skills/pdf/scripts/extract_form_field_info.py +152 -0
  187. package/.claude/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  188. package/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  189. package/.claude/skills/pptx/LICENSE.txt +30 -0
  190. package/.claude/skills/pptx/SKILL.md +484 -0
  191. package/.claude/skills/pptx/html2pptx.md +625 -0
  192. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  193. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  194. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  195. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  196. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  197. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  198. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  199. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  200. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  201. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  202. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  203. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  204. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  205. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  206. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  207. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  208. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  209. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  210. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  211. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  212. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  213. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  214. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  215. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  216. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  217. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  218. package/.claude/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  219. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  220. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  221. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  222. package/.claude/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  223. package/.claude/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  224. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  225. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  226. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  227. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  228. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  229. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  230. package/.claude/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  231. package/.claude/skills/pptx/ooxml/scripts/pack.py +159 -0
  232. package/.claude/skills/pptx/ooxml/scripts/unpack.py +29 -0
  233. package/.claude/skills/pptx/ooxml/scripts/validate.py +69 -0
  234. package/.claude/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  235. package/.claude/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  236. package/.claude/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  237. package/.claude/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  238. package/.claude/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  239. package/.claude/skills/pptx/ooxml.md +427 -0
  240. package/.claude/skills/pptx/scripts/html2pptx.js +979 -0
  241. package/.claude/skills/pptx/scripts/inventory.py +1020 -0
  242. package/.claude/skills/pptx/scripts/rearrange.py +231 -0
  243. package/.claude/skills/pptx/scripts/replace.py +385 -0
  244. package/.claude/skills/pptx/scripts/thumbnail.py +450 -0
  245. package/.claude/skills/skill-creator/LICENSE.txt +202 -0
  246. package/.claude/skills/skill-creator/SKILL.md +356 -0
  247. package/.claude/skills/skill-creator/references/output-patterns.md +82 -0
  248. package/.claude/skills/skill-creator/references/workflows.md +28 -0
  249. package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
  250. package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
  251. package/.claude/skills/skill-creator/scripts/quick_validate.py +95 -0
  252. package/.claude/skills/slack-gif-creator/LICENSE.txt +202 -0
  253. package/.claude/skills/slack-gif-creator/SKILL.md +254 -0
  254. package/.claude/skills/slack-gif-creator/core/easing.py +234 -0
  255. package/.claude/skills/slack-gif-creator/core/frame_composer.py +176 -0
  256. package/.claude/skills/slack-gif-creator/core/gif_builder.py +269 -0
  257. package/.claude/skills/slack-gif-creator/core/validators.py +136 -0
  258. package/.claude/skills/slack-gif-creator/requirements.txt +4 -0
  259. package/.claude/skills/template/SKILL.md +6 -0
  260. package/.claude/skills/test-workflow/SKILL.md +191 -0
  261. package/.claude/skills/theme-factory/LICENSE.txt +202 -0
  262. package/.claude/skills/theme-factory/SKILL.md +59 -0
  263. package/.claude/skills/theme-factory/theme-showcase.pdf +0 -0
  264. package/.claude/skills/theme-factory/themes/arctic-frost.md +19 -0
  265. package/.claude/skills/theme-factory/themes/botanical-garden.md +19 -0
  266. package/.claude/skills/theme-factory/themes/desert-rose.md +19 -0
  267. package/.claude/skills/theme-factory/themes/forest-canopy.md +19 -0
  268. package/.claude/skills/theme-factory/themes/golden-hour.md +19 -0
  269. package/.claude/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  270. package/.claude/skills/theme-factory/themes/modern-minimalist.md +19 -0
  271. package/.claude/skills/theme-factory/themes/ocean-depths.md +19 -0
  272. package/.claude/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  273. package/.claude/skills/theme-factory/themes/tech-innovation.md +19 -0
  274. package/.claude/skills/web-artifacts-builder/LICENSE.txt +202 -0
  275. package/.claude/skills/web-artifacts-builder/SKILL.md +74 -0
  276. package/.claude/skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  277. package/.claude/skills/web-artifacts-builder/scripts/init-artifact.sh +322 -0
  278. package/.claude/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  279. package/.claude/skills/webapp-testing/LICENSE.txt +202 -0
  280. package/.claude/skills/webapp-testing/SKILL.md +96 -0
  281. package/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
  282. package/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  283. package/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  284. package/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
  285. package/.claude/skills/xlsx/LICENSE.txt +30 -0
  286. package/.claude/skills/xlsx/SKILL.md +289 -0
  287. package/.claude/skills/xlsx/recalc.py +178 -0
  288. package/.claude/templates/tasks/develop.md +69 -0
  289. package/.claude/templates/tasks/research.md +64 -0
  290. package/.claude/templates/tasks/test.md +96 -0
  291. package/.claude-plugin/marketplace.json +2 -2
  292. package/.versionrc +25 -0
  293. package/AGENTS.md +171 -86
  294. package/CHANGELOG.md +83 -4
  295. package/PROJECT_STRUCTURE.md +40 -3
  296. package/Q&A.md +184 -0
  297. package/README.md +74 -2
  298. package/cli.js +79 -5
  299. package/config/official-skills.json +183 -0
  300. package/development/todos/.state.json +4 -0
  301. package/development/todos/INDEX.md +67 -32
  302. package/docs/RELEASE.md +93 -0
  303. package/jest.config.js +61 -0
  304. package/lib/commands.js +1724 -39
  305. package/lib/migrations.js +154 -0
  306. package/lib/utils.js +102 -14
  307. package/lib/version-check.js +169 -0
  308. package/package.json +13 -3
  309. package/scripts/fix-hooks.mjs +97 -0
  310. package/template/.claude/commands/commit-push-pr.md +23 -3
  311. package/template/.claude/hooks/project-kickoff.cjs +190 -1
  312. package/template/.claude/hooks/session-restore.cjs +102 -0
  313. package/template/.claude/hooks/session-save.cjs +164 -0
  314. package/template/.claude/settings.json +114 -50
  315. package/tests/README.md +263 -0
  316. package/tests/commands.test.js +163 -0
  317. package/tests/config.test.js +100 -0
  318. package/tests/marketplace.test.js +304 -0
  319. package/tests/migrations.test.js +187 -0
  320. 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
+ });