@thanhvn14/csvibe 0.1.4 → 0.1.5

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 (392) hide show
  1. package/.github/agents/schemas/base-output.schema.json +88 -0
  2. package/.github/agents/schemas/brainstorm-output.schema.json +88 -0
  3. package/.github/agents/schemas/scout-output.schema.json +60 -0
  4. package/.github/agents/scripts/fetch-copilot-tools.js +245 -0
  5. package/.github/agents/scripts/lib/parse-agent-file.js +275 -0
  6. package/.github/agents/scripts/package-lock.json +78 -0
  7. package/.github/agents/scripts/package.json +22 -0
  8. package/.github/agents/scripts/schemas/agent-frontmatter.schema.json +83 -0
  9. package/.github/agents/scripts/validate-agent-all.js +157 -0
  10. package/.github/agents/scripts/validate-agent-frontmatter.js +96 -0
  11. package/.github/agents/scripts/validate-agent-handoffs.js +169 -0
  12. package/.github/agents/scripts/validate-agent-output.js +157 -0
  13. package/.github/agents/scripts/validate-agent-tools.js +278 -0
  14. package/.github/skills/.env.example +100 -0
  15. package/.github/skills/.install-state.json +23 -0
  16. package/.github/skills/README.md +149 -0
  17. package/.github/skills/ai-multimodal/.env.example +204 -0
  18. package/.github/skills/ai-multimodal/scripts/.coverage +0 -0
  19. package/.github/skills/ai-multimodal/scripts/check_setup.py +305 -0
  20. package/.github/skills/ai-multimodal/scripts/document_converter.py +395 -0
  21. package/.github/skills/ai-multimodal/scripts/gemini_batch_process.py +1184 -0
  22. package/.github/skills/ai-multimodal/scripts/media_optimizer.py +506 -0
  23. package/.github/skills/ai-multimodal/scripts/requirements.txt +26 -0
  24. package/.github/skills/better-auth/scripts/.coverage +0 -0
  25. package/.github/skills/better-auth/scripts/better_auth_init.py +521 -0
  26. package/.github/skills/better-auth/scripts/requirements.txt +15 -0
  27. package/.github/skills/chrome-devtools/scripts/README.md +272 -0
  28. package/.github/skills/chrome-devtools/scripts/__tests__/selector.test.js +210 -0
  29. package/.github/skills/chrome-devtools/scripts/aria-snapshot.js +362 -0
  30. package/.github/skills/chrome-devtools/scripts/click.js +83 -0
  31. package/.github/skills/chrome-devtools/scripts/console.js +79 -0
  32. package/.github/skills/chrome-devtools/scripts/evaluate.js +53 -0
  33. package/.github/skills/chrome-devtools/scripts/fill.js +76 -0
  34. package/.github/skills/chrome-devtools/scripts/inject-auth.js +229 -0
  35. package/.github/skills/chrome-devtools/scripts/install-deps.sh +181 -0
  36. package/.github/skills/chrome-devtools/scripts/install.sh +83 -0
  37. package/.github/skills/chrome-devtools/scripts/lib/browser.js +318 -0
  38. package/.github/skills/chrome-devtools/scripts/lib/selector.js +178 -0
  39. package/.github/skills/chrome-devtools/scripts/navigate.js +54 -0
  40. package/.github/skills/chrome-devtools/scripts/network.js +106 -0
  41. package/.github/skills/chrome-devtools/scripts/package-lock.json +1589 -0
  42. package/.github/skills/chrome-devtools/scripts/package.json +16 -0
  43. package/.github/skills/chrome-devtools/scripts/performance.js +149 -0
  44. package/.github/skills/chrome-devtools/scripts/screenshot.js +198 -0
  45. package/.github/skills/chrome-devtools/scripts/select-ref.js +131 -0
  46. package/.github/skills/chrome-devtools/scripts/snapshot.js +135 -0
  47. package/.github/skills/common/README.md +120 -0
  48. package/.github/skills/common/api_key_helper.py +411 -0
  49. package/.github/skills/common/api_key_rotator.py +248 -0
  50. package/.github/skills/databases/scripts/.coverage +0 -0
  51. package/.github/skills/databases/scripts/db_backup.py +502 -0
  52. package/.github/skills/databases/scripts/db_migrate.py +425 -0
  53. package/.github/skills/databases/scripts/db_performance_check.py +456 -0
  54. package/.github/skills/databases/scripts/requirements.txt +20 -0
  55. package/.github/skills/debugging/scripts/find-polluter.sh +63 -0
  56. package/.github/skills/devops/.env.example +76 -0
  57. package/.github/skills/devops/scripts/cloudflare_deploy.py +269 -0
  58. package/.github/skills/devops/scripts/docker_optimize.py +331 -0
  59. package/.github/skills/devops/scripts/requirements.txt +20 -0
  60. package/.github/skills/docs-seeker/.env.example +15 -0
  61. package/.github/skills/docs-seeker/package.json +25 -0
  62. package/.github/skills/docs-seeker/scripts/analyze-llms-txt.js +211 -0
  63. package/.github/skills/docs-seeker/scripts/detect-topic.js +172 -0
  64. package/.github/skills/docs-seeker/scripts/fetch-docs.js +213 -0
  65. package/.github/skills/docs-seeker/scripts/utils/env-loader.js +94 -0
  66. package/.github/skills/document-skills/docx/LICENSE.txt +30 -0
  67. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  68. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  69. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  70. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  71. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  72. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  73. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  74. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  75. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  76. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  77. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  78. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  79. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  80. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  81. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  82. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  83. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  84. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  85. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  86. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  87. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  88. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  89. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  90. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  91. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  92. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  93. package/.github/skills/document-skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  94. package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  95. package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  96. package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  97. package/.github/skills/document-skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  98. package/.github/skills/document-skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  99. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  100. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  101. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  102. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  103. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  104. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  105. package/.github/skills/document-skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  106. package/.github/skills/document-skills/docx/ooxml/scripts/pack.py +159 -0
  107. package/.github/skills/document-skills/docx/ooxml/scripts/unpack.py +29 -0
  108. package/.github/skills/document-skills/docx/ooxml/scripts/validate.py +69 -0
  109. package/.github/skills/document-skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  110. package/.github/skills/document-skills/docx/ooxml/scripts/validation/base.py +951 -0
  111. package/.github/skills/document-skills/docx/ooxml/scripts/validation/docx.py +274 -0
  112. package/.github/skills/document-skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  113. package/.github/skills/document-skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  114. package/.github/skills/document-skills/docx/scripts/__init__.py +1 -0
  115. package/.github/skills/document-skills/docx/scripts/document.py +1276 -0
  116. package/.github/skills/document-skills/docx/scripts/templates/comments.xml +3 -0
  117. package/.github/skills/document-skills/docx/scripts/templates/commentsExtended.xml +3 -0
  118. package/.github/skills/document-skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  119. package/.github/skills/document-skills/docx/scripts/templates/commentsIds.xml +3 -0
  120. package/.github/skills/document-skills/docx/scripts/templates/people.xml +3 -0
  121. package/.github/skills/document-skills/docx/scripts/utilities.py +374 -0
  122. package/.github/skills/document-skills/pdf/LICENSE.txt +30 -0
  123. package/.github/skills/document-skills/pdf/scripts/check_bounding_boxes.py +70 -0
  124. package/.github/skills/document-skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  125. package/.github/skills/document-skills/pdf/scripts/check_fillable_fields.py +12 -0
  126. package/.github/skills/document-skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  127. package/.github/skills/document-skills/pdf/scripts/create_validation_image.py +41 -0
  128. package/.github/skills/document-skills/pdf/scripts/extract_form_field_info.py +152 -0
  129. package/.github/skills/document-skills/pdf/scripts/fill_fillable_fields.py +114 -0
  130. package/.github/skills/document-skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  131. package/.github/skills/document-skills/pptx/LICENSE.txt +30 -0
  132. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  133. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  134. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  135. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  136. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  137. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  138. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  139. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  140. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  141. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  142. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  143. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  144. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  145. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  146. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  147. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  148. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  149. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  150. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  151. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  152. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  153. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  154. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  155. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  156. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  157. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  158. package/.github/skills/document-skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  159. package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  160. package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  161. package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  162. package/.github/skills/document-skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  163. package/.github/skills/document-skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  164. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  165. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  166. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  167. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  168. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  169. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  170. package/.github/skills/document-skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  171. package/.github/skills/document-skills/pptx/ooxml/scripts/pack.py +159 -0
  172. package/.github/skills/document-skills/pptx/ooxml/scripts/unpack.py +29 -0
  173. package/.github/skills/document-skills/pptx/ooxml/scripts/validate.py +69 -0
  174. package/.github/skills/document-skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  175. package/.github/skills/document-skills/pptx/ooxml/scripts/validation/base.py +951 -0
  176. package/.github/skills/document-skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  177. package/.github/skills/document-skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  178. package/.github/skills/document-skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  179. package/.github/skills/document-skills/pptx/scripts/html2pptx.js +979 -0
  180. package/.github/skills/document-skills/pptx/scripts/inventory.py +1020 -0
  181. package/.github/skills/document-skills/pptx/scripts/rearrange.py +231 -0
  182. package/.github/skills/document-skills/pptx/scripts/replace.py +385 -0
  183. package/.github/skills/document-skills/pptx/scripts/thumbnail.py +450 -0
  184. package/.github/skills/document-skills/xlsx/LICENSE.txt +30 -0
  185. package/.github/skills/document-skills/xlsx/recalc.py +190 -0
  186. package/.github/skills/install.ps1 +1220 -0
  187. package/.github/skills/install.sh +1032 -0
  188. package/.github/skills/markdown-novel-viewer/assets/directory-browser.css +215 -0
  189. package/.github/skills/markdown-novel-viewer/assets/favicon.png +0 -0
  190. package/.github/skills/markdown-novel-viewer/assets/novel-theme.css +818 -0
  191. package/.github/skills/markdown-novel-viewer/assets/reader.js +262 -0
  192. package/.github/skills/markdown-novel-viewer/assets/template.html +80 -0
  193. package/.github/skills/markdown-novel-viewer/package-lock.json +146 -0
  194. package/.github/skills/markdown-novel-viewer/package.json +15 -0
  195. package/.github/skills/markdown-novel-viewer/scripts/lib/http-server.cjs +434 -0
  196. package/.github/skills/markdown-novel-viewer/scripts/lib/markdown-renderer.cjs +272 -0
  197. package/.github/skills/markdown-novel-viewer/scripts/lib/plan-navigator.cjs +509 -0
  198. package/.github/skills/markdown-novel-viewer/scripts/lib/port-finder.cjs +48 -0
  199. package/.github/skills/markdown-novel-viewer/scripts/lib/process-mgr.cjs +150 -0
  200. package/.github/skills/markdown-novel-viewer/scripts/server.cjs +411 -0
  201. package/.github/skills/mcp-builder/LICENSE.txt +202 -0
  202. package/.github/skills/mcp-builder/scripts/connections.py +151 -0
  203. package/.github/skills/mcp-builder/scripts/evaluation.py +373 -0
  204. package/.github/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  205. package/.github/skills/mcp-builder/scripts/requirements.txt +2 -0
  206. package/.github/skills/mcp-management/README.md +219 -0
  207. package/.github/skills/mcp-management/assets/tools.json +3146 -0
  208. package/.github/skills/mcp-management/package-lock.json +6 -0
  209. package/.github/skills/mcp-management/scripts/.env.example +10 -0
  210. package/.github/skills/mcp-management/scripts/cli.ts +195 -0
  211. package/.github/skills/mcp-management/scripts/dist/analyze-tools.js +70 -0
  212. package/.github/skills/mcp-management/scripts/dist/cli.js +160 -0
  213. package/.github/skills/mcp-management/scripts/dist/mcp-client.js +183 -0
  214. package/.github/skills/mcp-management/scripts/mcp-client.ts +230 -0
  215. package/.github/skills/mcp-management/scripts/package.json +20 -0
  216. package/.github/skills/media-processing/scripts/README.md +111 -0
  217. package/.github/skills/media-processing/scripts/batch-remove-background.sh +124 -0
  218. package/.github/skills/media-processing/scripts/batch_resize.py +342 -0
  219. package/.github/skills/media-processing/scripts/media_convert.py +311 -0
  220. package/.github/skills/media-processing/scripts/remove-background.sh +96 -0
  221. package/.github/skills/media-processing/scripts/remove-bg-node.js +158 -0
  222. package/.github/skills/media-processing/scripts/requirements.txt +24 -0
  223. package/.github/skills/media-processing/scripts/video_optimize.py +414 -0
  224. package/.github/skills/payment-integration/README.md +185 -0
  225. package/.github/skills/payment-integration/scripts/.env.example +20 -0
  226. package/.github/skills/payment-integration/scripts/checkout-helper.js +244 -0
  227. package/.github/skills/payment-integration/scripts/package.json +17 -0
  228. package/.github/skills/payment-integration/scripts/polar-webhook-verify.js +202 -0
  229. package/.github/skills/payment-integration/scripts/sepay-webhook-verify.js +193 -0
  230. package/.github/skills/payment-integration/scripts/test-scripts.js +237 -0
  231. package/.github/skills/plans-kanban/assets/dashboard-template.html +119 -0
  232. package/.github/skills/plans-kanban/assets/dashboard.css +1594 -0
  233. package/.github/skills/plans-kanban/assets/dashboard.js +596 -0
  234. package/.github/skills/plans-kanban/assets/favicon.png +0 -0
  235. package/.github/skills/plans-kanban/package-lock.json +123 -0
  236. package/.github/skills/plans-kanban/package.json +13 -0
  237. package/.github/skills/plans-kanban/scripts/lib/dashboard-renderer.cjs +884 -0
  238. package/.github/skills/plans-kanban/scripts/lib/http-server.cjs +310 -0
  239. package/.github/skills/plans-kanban/scripts/lib/plan-metadata-extractor.cjs +489 -0
  240. package/.github/skills/plans-kanban/scripts/lib/plan-parser.cjs +175 -0
  241. package/.github/skills/plans-kanban/scripts/lib/plan-scanner.cjs +272 -0
  242. package/.github/skills/plans-kanban/scripts/lib/port-finder.cjs +48 -0
  243. package/.github/skills/plans-kanban/scripts/lib/process-mgr.cjs +128 -0
  244. package/.github/skills/plans-kanban/scripts/server.cjs +260 -0
  245. package/.github/skills/repomix/scripts/.coverage +0 -0
  246. package/.github/skills/repomix/scripts/README.md +179 -0
  247. package/.github/skills/repomix/scripts/repomix_batch.py +455 -0
  248. package/.github/skills/repomix/scripts/repos.example.json +15 -0
  249. package/.github/skills/repomix/scripts/requirements.txt +15 -0
  250. package/.github/skills/scout-validation/scripts/lib/broad-pattern-detector.cjs +124 -0
  251. package/.github/skills/scout-validation/scripts/lib/path-checker.cjs +66 -0
  252. package/.github/skills/scout-validation/scripts/lib/schema-validator.cjs +45 -0
  253. package/.github/skills/scout-validation/scripts/package.json +11 -0
  254. package/.github/skills/scout-validation/scripts/validate-scout-output.cjs +219 -0
  255. package/.github/skills/scout-validation/test/broad-pattern-output.json +18 -0
  256. package/.github/skills/scout-validation/test/invalid-path-output.json +18 -0
  257. package/.github/skills/scout-validation/test/valid-scout-output.json +26 -0
  258. package/.github/skills/sequential-thinking/.env.example +8 -0
  259. package/.github/skills/sequential-thinking/README.md +183 -0
  260. package/.github/skills/sequential-thinking/package.json +31 -0
  261. package/.github/skills/sequential-thinking/scripts/format-thought.js +159 -0
  262. package/.github/skills/sequential-thinking/scripts/process-thought.js +236 -0
  263. package/.github/skills/shopify/README.md +66 -0
  264. package/.github/skills/shopify/scripts/.coverage +0 -0
  265. package/.github/skills/shopify/scripts/requirements.txt +19 -0
  266. package/.github/skills/shopify/scripts/shopify_init.py +423 -0
  267. package/.github/skills/skill-creator/LICENSE.txt +202 -0
  268. package/.github/skills/skill-creator/scripts/init_skill.py +303 -0
  269. package/.github/skills/skill-creator/scripts/package_skill.py +110 -0
  270. package/.github/skills/skill-creator/scripts/quick_validate.py +65 -0
  271. package/.github/skills/ui-styling/LICENSE.txt +202 -0
  272. package/.github/skills/ui-styling/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  273. package/.github/skills/ui-styling/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  274. package/.github/skills/ui-styling/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  275. package/.github/skills/ui-styling/canvas-fonts/BigShoulders-OFL.txt +93 -0
  276. package/.github/skills/ui-styling/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  277. package/.github/skills/ui-styling/canvas-fonts/Boldonse-OFL.txt +93 -0
  278. package/.github/skills/ui-styling/canvas-fonts/Boldonse-Regular.ttf +0 -0
  279. package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  280. package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  281. package/.github/skills/ui-styling/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  282. package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  283. package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  284. package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  285. package/.github/skills/ui-styling/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  286. package/.github/skills/ui-styling/canvas-fonts/DMMono-OFL.txt +93 -0
  287. package/.github/skills/ui-styling/canvas-fonts/DMMono-Regular.ttf +0 -0
  288. package/.github/skills/ui-styling/canvas-fonts/EricaOne-OFL.txt +94 -0
  289. package/.github/skills/ui-styling/canvas-fonts/EricaOne-Regular.ttf +0 -0
  290. package/.github/skills/ui-styling/canvas-fonts/GeistMono-Bold.ttf +0 -0
  291. package/.github/skills/ui-styling/canvas-fonts/GeistMono-OFL.txt +93 -0
  292. package/.github/skills/ui-styling/canvas-fonts/GeistMono-Regular.ttf +0 -0
  293. package/.github/skills/ui-styling/canvas-fonts/Gloock-OFL.txt +93 -0
  294. package/.github/skills/ui-styling/canvas-fonts/Gloock-Regular.ttf +0 -0
  295. package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  296. package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  297. package/.github/skills/ui-styling/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  298. package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  299. package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  300. package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  301. package/.github/skills/ui-styling/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  302. package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  303. package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  304. package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  305. package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  306. package/.github/skills/ui-styling/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  307. package/.github/skills/ui-styling/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  308. package/.github/skills/ui-styling/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  309. package/.github/skills/ui-styling/canvas-fonts/Italiana-OFL.txt +93 -0
  310. package/.github/skills/ui-styling/canvas-fonts/Italiana-Regular.ttf +0 -0
  311. package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  312. package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  313. package/.github/skills/ui-styling/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  314. package/.github/skills/ui-styling/canvas-fonts/Jura-Light.ttf +0 -0
  315. package/.github/skills/ui-styling/canvas-fonts/Jura-Medium.ttf +0 -0
  316. package/.github/skills/ui-styling/canvas-fonts/Jura-OFL.txt +93 -0
  317. package/.github/skills/ui-styling/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  318. package/.github/skills/ui-styling/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  319. package/.github/skills/ui-styling/canvas-fonts/Lora-Bold.ttf +0 -0
  320. package/.github/skills/ui-styling/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  321. package/.github/skills/ui-styling/canvas-fonts/Lora-Italic.ttf +0 -0
  322. package/.github/skills/ui-styling/canvas-fonts/Lora-OFL.txt +93 -0
  323. package/.github/skills/ui-styling/canvas-fonts/Lora-Regular.ttf +0 -0
  324. package/.github/skills/ui-styling/canvas-fonts/NationalPark-Bold.ttf +0 -0
  325. package/.github/skills/ui-styling/canvas-fonts/NationalPark-OFL.txt +93 -0
  326. package/.github/skills/ui-styling/canvas-fonts/NationalPark-Regular.ttf +0 -0
  327. package/.github/skills/ui-styling/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  328. package/.github/skills/ui-styling/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  329. package/.github/skills/ui-styling/canvas-fonts/Outfit-Bold.ttf +0 -0
  330. package/.github/skills/ui-styling/canvas-fonts/Outfit-OFL.txt +93 -0
  331. package/.github/skills/ui-styling/canvas-fonts/Outfit-Regular.ttf +0 -0
  332. package/.github/skills/ui-styling/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  333. package/.github/skills/ui-styling/canvas-fonts/PixelifySans-OFL.txt +93 -0
  334. package/.github/skills/ui-styling/canvas-fonts/PoiretOne-OFL.txt +93 -0
  335. package/.github/skills/ui-styling/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  336. package/.github/skills/ui-styling/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  337. package/.github/skills/ui-styling/canvas-fonts/RedHatMono-OFL.txt +93 -0
  338. package/.github/skills/ui-styling/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  339. package/.github/skills/ui-styling/canvas-fonts/Silkscreen-OFL.txt +93 -0
  340. package/.github/skills/ui-styling/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  341. package/.github/skills/ui-styling/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  342. package/.github/skills/ui-styling/canvas-fonts/SmoochSans-OFL.txt +93 -0
  343. package/.github/skills/ui-styling/canvas-fonts/Tektur-Medium.ttf +0 -0
  344. package/.github/skills/ui-styling/canvas-fonts/Tektur-OFL.txt +93 -0
  345. package/.github/skills/ui-styling/canvas-fonts/Tektur-Regular.ttf +0 -0
  346. package/.github/skills/ui-styling/canvas-fonts/WorkSans-Bold.ttf +0 -0
  347. package/.github/skills/ui-styling/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  348. package/.github/skills/ui-styling/canvas-fonts/WorkSans-Italic.ttf +0 -0
  349. package/.github/skills/ui-styling/canvas-fonts/WorkSans-OFL.txt +93 -0
  350. package/.github/skills/ui-styling/canvas-fonts/WorkSans-Regular.ttf +0 -0
  351. package/.github/skills/ui-styling/canvas-fonts/YoungSerif-OFL.txt +93 -0
  352. package/.github/skills/ui-styling/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  353. package/.github/skills/ui-styling/scripts/.coverage +0 -0
  354. package/.github/skills/ui-styling/scripts/requirements.txt +17 -0
  355. package/.github/skills/ui-styling/scripts/shadcn_add.py +292 -0
  356. package/.github/skills/ui-styling/scripts/tailwind_config_gen.py +456 -0
  357. package/.github/skills/ui-ux-pro-max/data/charts.csv +26 -0
  358. package/.github/skills/ui-ux-pro-max/data/colors.csv +97 -0
  359. package/.github/skills/ui-ux-pro-max/data/landing.csv +31 -0
  360. package/.github/skills/ui-ux-pro-max/data/products.csv +97 -0
  361. package/.github/skills/ui-ux-pro-max/data/prompts.csv +24 -0
  362. package/.github/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  363. package/.github/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +51 -0
  364. package/.github/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  365. package/.github/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  366. package/.github/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  367. package/.github/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  368. package/.github/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  369. package/.github/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  370. package/.github/skills/ui-ux-pro-max/data/styles.csv +59 -0
  371. package/.github/skills/ui-ux-pro-max/data/typography.csv +58 -0
  372. package/.github/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  373. package/.github/skills/ui-ux-pro-max/scripts/core.py +236 -0
  374. package/.github/skills/ui-ux-pro-max/scripts/search.py +76 -0
  375. package/.github/skills/web-frameworks/scripts/.coverage +0 -0
  376. package/.github/skills/web-frameworks/scripts/__init__.py +0 -0
  377. package/.github/skills/web-frameworks/scripts/nextjs_init.py +547 -0
  378. package/.github/skills/web-frameworks/scripts/requirements.txt +16 -0
  379. package/.github/skills/web-frameworks/scripts/turborepo_migrate.py +394 -0
  380. package/dist/config/constants.d.ts +2 -0
  381. package/dist/config/constants.d.ts.map +1 -1
  382. package/dist/config/constants.js +4 -1
  383. package/dist/config/constants.js.map +1 -1
  384. package/dist/domains/github/github-client.d.ts +5 -0
  385. package/dist/domains/github/github-client.d.ts.map +1 -1
  386. package/dist/domains/github/github-client.js +44 -0
  387. package/dist/domains/github/github-client.js.map +1 -1
  388. package/dist/utils/downloader.d.ts +3 -1
  389. package/dist/utils/downloader.d.ts.map +1 -1
  390. package/dist/utils/downloader.js +48 -11
  391. package/dist/utils/downloader.js.map +1 -1
  392. package/package.json +3 -1
@@ -0,0 +1,434 @@
1
+ /**
2
+ * Core HTTP server for markdown-novel-viewer
3
+ * Handles routing for markdown viewer and directory browser
4
+ *
5
+ * Routes:
6
+ * - /view?file=<path> - Markdown file viewer
7
+ * - /browse?dir=<path> - Directory browser
8
+ * - /assets/* - Static assets
9
+ * - /file/* - Local files (images, etc.)
10
+ *
11
+ * Security: Paths are validated to prevent directory traversal attacks
12
+ */
13
+
14
+ const http = require('http');
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const url = require('url');
18
+
19
+ // Allowed base directories for file access (set at runtime)
20
+ let allowedBaseDirs = [];
21
+
22
+ /**
23
+ * Set allowed directories for file serving
24
+ * @param {string[]} dirs - Array of allowed directory paths
25
+ */
26
+ function setAllowedDirs(dirs) {
27
+ allowedBaseDirs = dirs.map(d => path.resolve(d));
28
+ }
29
+
30
+ /**
31
+ * Validate path is within allowed directories (prevents path traversal)
32
+ * @param {string} filePath - Path to validate
33
+ * @param {string[]} allowedDirs - Allowed base directories
34
+ * @returns {boolean} - True if path is safe
35
+ */
36
+ function isPathSafe(filePath, allowedDirs = allowedBaseDirs) {
37
+ const resolved = path.resolve(filePath);
38
+
39
+ // Check for path traversal attempts
40
+ if (resolved.includes('..') || filePath.includes('\0')) {
41
+ return false;
42
+ }
43
+
44
+ // If no allowed dirs set, allow only project paths
45
+ if (allowedDirs.length === 0) {
46
+ return true;
47
+ }
48
+
49
+ // Must be within one of the allowed directories
50
+ return allowedDirs.some(dir => resolved.startsWith(dir));
51
+ }
52
+
53
+ /**
54
+ * Sanitize error message to prevent path disclosure
55
+ */
56
+ function sanitizeErrorMessage(message) {
57
+ return message.replace(/\/[^\s'"<>]+/g, '[path]');
58
+ }
59
+
60
+ // MIME type mapping
61
+ const MIME_TYPES = {
62
+ '.html': 'text/html',
63
+ '.css': 'text/css',
64
+ '.js': 'application/javascript',
65
+ '.json': 'application/json',
66
+ '.png': 'image/png',
67
+ '.jpg': 'image/jpeg',
68
+ '.jpeg': 'image/jpeg',
69
+ '.gif': 'image/gif',
70
+ '.svg': 'image/svg+xml',
71
+ '.webp': 'image/webp',
72
+ '.ico': 'image/x-icon',
73
+ '.md': 'text/markdown',
74
+ '.txt': 'text/plain',
75
+ '.pdf': 'application/pdf'
76
+ };
77
+
78
+ /**
79
+ * Get MIME type for file extension
80
+ */
81
+ function getMimeType(filePath) {
82
+ const ext = path.extname(filePath).toLowerCase();
83
+ return MIME_TYPES[ext] || 'application/octet-stream';
84
+ }
85
+
86
+ /**
87
+ * Send response with content
88
+ */
89
+ function sendResponse(res, statusCode, contentType, content) {
90
+ res.writeHead(statusCode, { 'Content-Type': contentType });
91
+ res.end(content);
92
+ }
93
+
94
+ /**
95
+ * Send error response (sanitized)
96
+ */
97
+ function sendError(res, statusCode, message) {
98
+ const safeMessage = sanitizeErrorMessage(message);
99
+ sendResponse(res, statusCode, 'text/html', `
100
+ <!DOCTYPE html>
101
+ <html>
102
+ <head><title>Error ${statusCode}</title></head>
103
+ <body style="font-family: system-ui; padding: 2rem;">
104
+ <h1>Error ${statusCode}</h1>
105
+ <p>${safeMessage}</p>
106
+ </body>
107
+ </html>
108
+ `);
109
+ }
110
+
111
+ /**
112
+ * Serve static file with path validation
113
+ */
114
+ function serveFile(res, filePath, skipValidation = false) {
115
+ if (!skipValidation && !isPathSafe(filePath)) {
116
+ sendError(res, 403, 'Access denied');
117
+ return;
118
+ }
119
+
120
+ if (!fs.existsSync(filePath)) {
121
+ sendError(res, 404, 'File not found');
122
+ return;
123
+ }
124
+
125
+ const content = fs.readFileSync(filePath);
126
+ const mimeType = getMimeType(filePath);
127
+ sendResponse(res, 200, mimeType, content);
128
+ }
129
+
130
+ /**
131
+ * Get file icon based on extension
132
+ */
133
+ function getFileIcon(filename) {
134
+ const ext = path.extname(filename).toLowerCase();
135
+ const iconMap = {
136
+ '.md': '📄',
137
+ '.txt': '📝',
138
+ '.json': '📋',
139
+ '.js': '📜',
140
+ '.cjs': '📜',
141
+ '.mjs': '📜',
142
+ '.ts': '📘',
143
+ '.css': '🎨',
144
+ '.html': '🌐',
145
+ '.png': '🖼️',
146
+ '.jpg': '🖼️',
147
+ '.jpeg': '🖼️',
148
+ '.gif': '🖼️',
149
+ '.svg': '🖼️',
150
+ '.pdf': '📕',
151
+ '.yaml': '⚙️',
152
+ '.yml': '⚙️',
153
+ '.toml': '⚙️',
154
+ '.env': '🔐',
155
+ '.sh': '💻',
156
+ '.bash': '💻'
157
+ };
158
+ return iconMap[ext] || '📄';
159
+ }
160
+
161
+ /**
162
+ * Render directory browser HTML
163
+ */
164
+ function renderDirectoryBrowser(dirPath, assetsDir) {
165
+ const items = fs.readdirSync(dirPath);
166
+ const displayPath = dirPath.length > 50 ? '...' + dirPath.slice(-47) : dirPath;
167
+
168
+ // Separate directories and files, sort alphabetically
169
+ const dirs = [];
170
+ const files = [];
171
+
172
+ for (const item of items) {
173
+ // Skip hidden files and deprecated folders
174
+ if (item.startsWith('.') || item === 'deprecated') continue;
175
+
176
+ const itemPath = path.join(dirPath, item);
177
+ try {
178
+ const stats = fs.statSync(itemPath);
179
+ if (stats.isDirectory()) {
180
+ dirs.push(item);
181
+ } else {
182
+ files.push(item);
183
+ }
184
+ } catch {
185
+ // Skip items we can't stat
186
+ }
187
+ }
188
+
189
+ dirs.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
190
+ files.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
191
+
192
+ // Build file list HTML
193
+ let listHtml = '';
194
+
195
+ // Parent directory link (if not root)
196
+ const parentDir = path.dirname(dirPath);
197
+ if (parentDir !== dirPath) {
198
+ listHtml += `<li class="dir-item parent">
199
+ <a href="/browse?dir=${encodeURIComponent(parentDir)}">
200
+ <span class="icon">📁</span>
201
+ <span class="name">..</span>
202
+ </a>
203
+ </li>`;
204
+ }
205
+
206
+ // Directories
207
+ for (const dir of dirs) {
208
+ const fullPath = path.join(dirPath, dir);
209
+ listHtml += `<li class="dir-item folder">
210
+ <a href="/browse?dir=${encodeURIComponent(fullPath)}">
211
+ <span class="icon">📁</span>
212
+ <span class="name">${dir}/</span>
213
+ </a>
214
+ </li>`;
215
+ }
216
+
217
+ // Files
218
+ for (const file of files) {
219
+ const fullPath = path.join(dirPath, file);
220
+ const icon = getFileIcon(file);
221
+ const isMarkdown = file.endsWith('.md');
222
+
223
+ if (isMarkdown) {
224
+ listHtml += `<li class="dir-item file markdown">
225
+ <a href="/view?file=${encodeURIComponent(fullPath)}">
226
+ <span class="icon">${icon}</span>
227
+ <span class="name">${file}</span>
228
+ </a>
229
+ </li>`;
230
+ } else {
231
+ listHtml += `<li class="dir-item file">
232
+ <a href="/file${fullPath}" target="_blank">
233
+ <span class="icon">${icon}</span>
234
+ <span class="name">${file}</span>
235
+ </a>
236
+ </li>`;
237
+ }
238
+ }
239
+
240
+ // Empty directory message
241
+ if (dirs.length === 0 && files.length === 0) {
242
+ listHtml = '<li class="empty">This directory is empty</li>';
243
+ }
244
+
245
+ // Read CSS
246
+ let css = '';
247
+ const cssPath = path.join(assetsDir, 'directory-browser.css');
248
+ if (fs.existsSync(cssPath)) {
249
+ css = fs.readFileSync(cssPath, 'utf8');
250
+ }
251
+
252
+ return `<!DOCTYPE html>
253
+ <html lang="en">
254
+ <head>
255
+ <meta charset="UTF-8">
256
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
257
+ <title>📁 ${path.basename(dirPath)}</title>
258
+ <style>
259
+ ${css}
260
+ </style>
261
+ </head>
262
+ <body>
263
+ <div class="container">
264
+ <header>
265
+ <h1>📁 ${path.basename(dirPath)}</h1>
266
+ <p class="path">${displayPath}</p>
267
+ </header>
268
+ <ul class="file-list">
269
+ ${listHtml}
270
+ </ul>
271
+ <footer>
272
+ <p>${dirs.length} folder${dirs.length !== 1 ? 's' : ''}, ${files.length} file${files.length !== 1 ? 's' : ''}</p>
273
+ </footer>
274
+ </div>
275
+ </body>
276
+ </html>`;
277
+ }
278
+
279
+ /**
280
+ * Create HTTP server with routing
281
+ * @param {Object} options - Server options
282
+ * @param {string} options.assetsDir - Static assets directory
283
+ * @param {Function} options.renderMarkdown - Markdown render function (filePath) => html
284
+ * @param {string[]} options.allowedDirs - Allowed directories for file access
285
+ * @returns {http.Server} - HTTP server instance
286
+ */
287
+ function createHttpServer(options) {
288
+ const { assetsDir, renderMarkdown, allowedDirs = [] } = options;
289
+
290
+ // Set allowed directories for path validation
291
+ if (allowedDirs.length > 0) {
292
+ setAllowedDirs(allowedDirs);
293
+ }
294
+
295
+ const server = http.createServer((req, res) => {
296
+ const parsedUrl = url.parse(req.url, true);
297
+ const pathname = decodeURIComponent(parsedUrl.pathname);
298
+
299
+ // Route: /assets/* - serve static files from assets directory
300
+ if (pathname.startsWith('/assets/')) {
301
+ const relativePath = pathname.replace('/assets/', '');
302
+ if (relativePath.includes('..')) {
303
+ sendError(res, 403, 'Access denied');
304
+ return;
305
+ }
306
+ const assetPath = path.join(assetsDir, relativePath);
307
+ serveFile(res, assetPath, true);
308
+ return;
309
+ }
310
+
311
+ // Route: /file/* - serve local files (images, etc.)
312
+ if (pathname.startsWith('/file/')) {
313
+ // Extract path after '/file/' prefix (slice(6) removes '/file/')
314
+ // Path is already URL-decoded by decodeURIComponent above
315
+ const filePath = pathname.slice(6);
316
+
317
+ if (!isPathSafe(filePath)) {
318
+ sendError(res, 403, 'Access denied');
319
+ return;
320
+ }
321
+
322
+ serveFile(res, filePath);
323
+ return;
324
+ }
325
+
326
+ // Route: /view?file=<path> - render markdown (query param)
327
+ if (pathname === '/view') {
328
+ const filePath = parsedUrl.query?.file;
329
+
330
+ if (!filePath) {
331
+ sendError(res, 400, 'Missing ?file= parameter. Use /view?file=/path/to/file.md');
332
+ return;
333
+ }
334
+
335
+ if (!isPathSafe(filePath)) {
336
+ sendError(res, 403, 'Access denied');
337
+ return;
338
+ }
339
+
340
+ if (!fs.existsSync(filePath)) {
341
+ sendError(res, 404, 'File not found');
342
+ return;
343
+ }
344
+
345
+ try {
346
+ const html = renderMarkdown(filePath);
347
+ sendResponse(res, 200, 'text/html', html);
348
+ } catch (err) {
349
+ console.error('[http-server] Render error:', err.message);
350
+ sendError(res, 500, 'Error rendering markdown');
351
+ }
352
+ return;
353
+ }
354
+
355
+ // Route: /browse?dir=<path> - directory browser (query param)
356
+ if (pathname === '/browse') {
357
+ const dirPath = parsedUrl.query?.dir;
358
+
359
+ if (!dirPath) {
360
+ sendError(res, 400, 'Missing ?dir= parameter. Use /browse?dir=/path/to/directory');
361
+ return;
362
+ }
363
+
364
+ if (!isPathSafe(dirPath)) {
365
+ sendError(res, 403, 'Access denied');
366
+ return;
367
+ }
368
+
369
+ if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
370
+ sendError(res, 404, 'Directory not found');
371
+ return;
372
+ }
373
+
374
+ try {
375
+ const html = renderDirectoryBrowser(dirPath, assetsDir);
376
+ sendResponse(res, 200, 'text/html', html);
377
+ } catch (err) {
378
+ console.error('[http-server] Browse error:', err.message);
379
+ sendError(res, 500, 'Error listing directory');
380
+ }
381
+ return;
382
+ }
383
+
384
+ // Route: / - show welcome/usage page
385
+ if (pathname === '/') {
386
+ sendResponse(res, 200, 'text/html', `
387
+ <!DOCTYPE html>
388
+ <html>
389
+ <head>
390
+ <title>Markdown Novel Viewer</title>
391
+ <style>
392
+ body { font-family: system-ui; max-width: 600px; margin: 2rem auto; padding: 1rem; }
393
+ h1 { color: #8b4513; }
394
+ code { background: #f5f5f5; padding: 0.2rem 0.4rem; border-radius: 3px; }
395
+ .routes { background: #faf8f3; padding: 1rem; border-radius: 8px; margin: 1rem 0; }
396
+ </style>
397
+ </head>
398
+ <body>
399
+ <h1>📖 Markdown Novel Viewer</h1>
400
+ <p>A calm, book-like viewer for markdown files.</p>
401
+ <div class="routes">
402
+ <h3>Routes</h3>
403
+ <ul>
404
+ <li><code>/view?file=/path/to/file.md</code> - View markdown</li>
405
+ <li><code>/browse?dir=/path/to/dir</code> - Browse directory</li>
406
+ </ul>
407
+ </div>
408
+ <p>Use the <code>/preview</code> command to start viewing files.</p>
409
+ </body>
410
+ </html>
411
+ `);
412
+ return;
413
+ }
414
+
415
+ // Default: 404
416
+ sendError(res, 404, 'Not found');
417
+ });
418
+
419
+ return server;
420
+ }
421
+
422
+ module.exports = {
423
+ createHttpServer,
424
+ getMimeType,
425
+ sendResponse,
426
+ sendError,
427
+ serveFile,
428
+ isPathSafe,
429
+ setAllowedDirs,
430
+ sanitizeErrorMessage,
431
+ MIME_TYPES,
432
+ renderDirectoryBrowser,
433
+ getFileIcon
434
+ };
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Markdown rendering engine with syntax highlighting and image resolution
3
+ * Converts markdown to styled HTML for novel-reader UI
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ // Lazy load dependencies
10
+ let marked = null;
11
+ let hljs = null;
12
+ let matter = null;
13
+
14
+ /**
15
+ * Initialize markdown dependencies
16
+ */
17
+ function initDependencies() {
18
+ if (!marked) {
19
+ const { Marked } = require('marked');
20
+ hljs = require('highlight.js');
21
+
22
+ marked = new Marked({
23
+ gfm: true,
24
+ breaks: true
25
+ });
26
+
27
+ // Configure highlight.js renderer
28
+ marked.setOptions({
29
+ highlight: (code, lang) => {
30
+ if (lang && hljs.getLanguage(lang)) {
31
+ try {
32
+ return hljs.highlight(code, { language: lang }).value;
33
+ } catch {
34
+ return code;
35
+ }
36
+ }
37
+ return hljs.highlightAuto(code).value;
38
+ }
39
+ });
40
+
41
+ matter = require('gray-matter');
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Resolve a single image source path to /file/ route
47
+ * @param {string} src - Image source path
48
+ * @param {string} basePath - Base directory path
49
+ * @returns {string} - Resolved path or original if absolute URL
50
+ */
51
+ function resolveImageSrc(src, basePath) {
52
+ // Skip absolute URLs
53
+ if (src.startsWith('http://') || src.startsWith('https://') || src.startsWith('/file')) {
54
+ return src;
55
+ }
56
+ // Resolve relative path to absolute /file/ route
57
+ // Use URL encoding to handle special chars and Windows paths (D:\...)
58
+ const absolutePath = path.resolve(basePath, src);
59
+ return `/file/${encodeURIComponent(absolutePath)}`;
60
+ }
61
+
62
+ /**
63
+ * Resolve relative image paths to /file/ routes
64
+ * Supports both inline and reference-style markdown images
65
+ * @param {string} markdown - Markdown content
66
+ * @param {string} basePath - Base directory path
67
+ * @returns {string} - Markdown with resolved image paths
68
+ */
69
+ function resolveImages(markdown, basePath) {
70
+ let result = markdown;
71
+
72
+ // 1. Handle inline images: ![alt](src) or ![alt](src "title")
73
+ const inlineImgRegex = /!\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
74
+ result = result.replace(inlineImgRegex, (match, alt, src) => {
75
+ const resolvedSrc = resolveImageSrc(src, basePath);
76
+ return `![${alt}](${resolvedSrc})`;
77
+ });
78
+
79
+ // 2. Handle reference-style image definitions: [label]: src or [label]: src "title"
80
+ // These appear at the end of the document like: [Step 1 Initial]: ./screenshots/step1.png
81
+ const refDefRegex = /^\[([^\]]+)\]:\s*(\S+)(?:\s+"[^"]*")?$/gm;
82
+ result = result.replace(refDefRegex, (match, label, src) => {
83
+ const resolvedSrc = resolveImageSrc(src, basePath);
84
+ return `[${label}]: ${resolvedSrc}`;
85
+ });
86
+
87
+ return result;
88
+ }
89
+
90
+ /**
91
+ * Generate table of contents from headings
92
+ * @param {string} html - Rendered HTML
93
+ * @returns {Array<{level: number, id: string, text: string}>} - TOC items
94
+ */
95
+ function generateTOC(html) {
96
+ const headings = [];
97
+ // Match h1-h3 with id attribute
98
+ const regex = /<h([1-3])[^>]*id="([^"]+)"[^>]*>([^<]+)<\/h\1>/gi;
99
+
100
+ let match;
101
+ while ((match = regex.exec(html)) !== null) {
102
+ headings.push({
103
+ level: parseInt(match[1], 10),
104
+ id: match[2],
105
+ text: match[3].trim()
106
+ });
107
+ }
108
+
109
+ return headings;
110
+ }
111
+
112
+ /**
113
+ * Generate a slug from text for use as anchor ID (matches plan-navigator.cjs)
114
+ * @param {string} text - Text to slugify
115
+ * @returns {string} - URL-safe slug
116
+ */
117
+ function slugify(text) {
118
+ return text
119
+ .toLowerCase()
120
+ .replace(/[^a-z0-9]+/g, '-')
121
+ .replace(/^-|-$/g, '');
122
+ }
123
+
124
+ /**
125
+ * Add IDs to headings for anchor links
126
+ * Also adds phase-specific IDs for inline phases in plan.md
127
+ * @param {string} html - Rendered HTML
128
+ * @returns {string} - HTML with heading IDs
129
+ */
130
+ function addHeadingIds(html) {
131
+ const usedIds = new Set();
132
+
133
+ return html.replace(/<h([1-6])>([^<]+)<\/h\1>/gi, (match, level, text) => {
134
+ // Check if this is a phase heading (e.g., "Phase 01: Name" or contains phase table row content)
135
+ const phaseMatch = text.match(/^Phase\s*(\d+)[:\s]+(.+)/i);
136
+
137
+ let id;
138
+ if (phaseMatch) {
139
+ // Generate phase-specific anchor ID that matches plan-navigator.cjs format
140
+ const phaseNum = parseInt(phaseMatch[1], 10);
141
+ const phaseName = phaseMatch[2].trim();
142
+ id = `phase-${String(phaseNum).padStart(2, '0')}-${slugify(phaseName)}`;
143
+ } else {
144
+ // Standard heading ID generation
145
+ id = slugify(text);
146
+ }
147
+
148
+ // Handle duplicate IDs
149
+ let uniqueId = id;
150
+ let counter = 1;
151
+ while (usedIds.has(uniqueId)) {
152
+ uniqueId = `${id}-${counter}`;
153
+ counter++;
154
+ }
155
+ usedIds.add(uniqueId);
156
+
157
+ return `<h${level} id="${uniqueId}">${text}</h${level}>`;
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Add anchor IDs to phase table rows
163
+ * Matches table rows with phase numbers: | 01 | Description | Status |
164
+ * @param {string} html - Rendered HTML
165
+ * @returns {string} - HTML with phase anchor IDs in table rows
166
+ */
167
+ function addPhaseTableAnchors(html) {
168
+ const usedIds = new Set();
169
+
170
+ // Match table rows with phase pattern: <tr><td>01</td><td>Description</td>...
171
+ // This handles the "Phase Summary" table format
172
+ return html.replace(/<tr>\s*<td>(\d{2})<\/td>\s*<td>([^<]+)<\/td>/gi, (match, phaseNum, description) => {
173
+ const num = parseInt(phaseNum, 10);
174
+ const slug = slugify(description.trim());
175
+ const id = `phase-${String(num).padStart(2, '0')}-${slug}`;
176
+
177
+ // Handle duplicates
178
+ let uniqueId = id;
179
+ let counter = 1;
180
+ while (usedIds.has(uniqueId)) {
181
+ uniqueId = `${id}-${counter}`;
182
+ counter++;
183
+ }
184
+ usedIds.add(uniqueId);
185
+
186
+ // Add anchor span at the start of the row
187
+ return `<tr id="${uniqueId}"><td>${phaseNum}</td><td>${description}</td>`;
188
+ });
189
+ }
190
+
191
+ /**
192
+ * Parse frontmatter from markdown
193
+ * @param {string} content - Raw markdown content
194
+ * @returns {{data: Object, content: string}} - Parsed frontmatter and content
195
+ */
196
+ function parseFrontmatter(content) {
197
+ initDependencies();
198
+ return matter(content);
199
+ }
200
+
201
+ /**
202
+ * Render markdown file to HTML
203
+ * @param {string} filePath - Path to markdown file
204
+ * @param {Object} options - Render options
205
+ * @returns {{html: string, toc: Array, frontmatter: Object, title: string}}
206
+ */
207
+ function renderMarkdownFile(filePath, options = {}) {
208
+ initDependencies();
209
+
210
+ const rawContent = fs.readFileSync(filePath, 'utf8');
211
+ const basePath = path.dirname(filePath);
212
+
213
+ // Parse frontmatter
214
+ const { data: frontmatter, content } = parseFrontmatter(rawContent);
215
+
216
+ // Resolve image paths
217
+ const resolvedContent = resolveImages(content, basePath);
218
+
219
+ // Render markdown to HTML
220
+ let html = marked.parse(resolvedContent);
221
+
222
+ // Add IDs to headings
223
+ html = addHeadingIds(html);
224
+
225
+ // Add anchor IDs to phase table rows (for inline phases in plan.md)
226
+ html = addPhaseTableAnchors(html);
227
+
228
+ // Generate TOC
229
+ const toc = generateTOC(html);
230
+
231
+ // Extract title from frontmatter or first h1
232
+ let title = frontmatter.title;
233
+ if (!title) {
234
+ const h1Match = html.match(/<h1[^>]*>([^<]+)<\/h1>/i);
235
+ title = h1Match ? h1Match[1] : path.basename(filePath, '.md');
236
+ }
237
+
238
+ return {
239
+ html,
240
+ toc,
241
+ frontmatter,
242
+ title
243
+ };
244
+ }
245
+
246
+ /**
247
+ * Render TOC as HTML sidebar
248
+ * @param {Array} toc - TOC items
249
+ * @returns {string} - HTML string
250
+ */
251
+ function renderTOCHtml(toc) {
252
+ if (!toc.length) return '';
253
+
254
+ const items = toc.map(({ level, id, text }) => {
255
+ const indent = (level - 1) * 12;
256
+ return `<li style="padding-left: ${indent}px"><a href="#${id}">${text}</a></li>`;
257
+ }).join('\n');
258
+
259
+ return `<ul class="toc-list">${items}</ul>`;
260
+ }
261
+
262
+ module.exports = {
263
+ renderMarkdownFile,
264
+ resolveImages,
265
+ resolveImageSrc,
266
+ generateTOC,
267
+ addHeadingIds,
268
+ addPhaseTableAnchors,
269
+ parseFrontmatter,
270
+ renderTOCHtml,
271
+ initDependencies
272
+ };