@thanhvn14/csvibe 0.1.3 → 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 (395) 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 +3 -0
  381. package/dist/config/constants.d.ts.map +1 -1
  382. package/dist/config/constants.js +5 -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/dist/utils/scaffolder.d.ts.map +1 -1
  393. package/dist/utils/scaffolder.js +2 -0
  394. package/dist/utils/scaffolder.js.map +1 -1
  395. package/package.json +3 -1
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Plan Scanner Utility
3
+ * Recursively discovers plan directories and aggregates metadata for dashboard view
4
+ *
5
+ * @module plan-scanner
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { parsePlanTable } = require('./plan-parser.cjs');
11
+ const {
12
+ extractPlanMetadata,
13
+ generateTimelineStats,
14
+ generateActivityHeatmap,
15
+ normalizeStatus
16
+ } = require('./plan-metadata-extractor.cjs');
17
+
18
+ /**
19
+ * Calculate progress statistics from phases array
20
+ * @param {Array<{status: string}>} phases - Array of phase objects with status
21
+ * @returns {{total: number, completed: number, inProgress: number, pending: number, percentage: number}}
22
+ */
23
+ function calculateProgress(phases) {
24
+ if (!phases || phases.length === 0) {
25
+ return { total: 0, completed: 0, inProgress: 0, pending: 0, percentage: 0 };
26
+ }
27
+
28
+ const stats = {
29
+ total: phases.length,
30
+ completed: 0,
31
+ inProgress: 0,
32
+ pending: 0
33
+ };
34
+
35
+ for (const phase of phases) {
36
+ const status = (phase.status || '').toLowerCase();
37
+ if (status === 'completed' || status === 'done') {
38
+ stats.completed++;
39
+ } else if (status === 'in-progress' || status === 'in progress' || status === 'active') {
40
+ stats.inProgress++;
41
+ } else {
42
+ stats.pending++;
43
+ }
44
+ }
45
+
46
+ stats.percentage = stats.total > 0
47
+ ? Math.round((stats.completed / stats.total) * 100)
48
+ : 0;
49
+
50
+ return stats;
51
+ }
52
+
53
+ /**
54
+ * Parse plan name from directory name (strip date prefix)
55
+ * @param {string} dirName - Directory name like "251211-feature-name"
56
+ * @returns {string} - Human readable name like "Feature Name"
57
+ */
58
+ function parsePlanName(dirName) {
59
+ // Remove date prefix: YYMMDD-, YYYYMMDD-, YYMMDD-HHMM-, YYYYMMDD-HHMM-
60
+ const withoutDate = dirName.replace(/^\d{6,8}(-\d{4})?-/, '');
61
+
62
+ // Convert kebab-case to Title Case
63
+ return withoutDate
64
+ .split('-')
65
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
66
+ .join(' ');
67
+ }
68
+
69
+ /**
70
+ * Derive overall status from phase statistics or header status
71
+ * @param {{completed: number, inProgress: number, pending: number, total: number}} stats
72
+ * @param {string} [headerStatus] - Optional status from plan header (e.g., **Status:** completed)
73
+ * @returns {'completed' | 'in-progress' | 'in-review' | 'cancelled' | 'pending'}
74
+ */
75
+ function deriveStatus(stats, headerStatus) {
76
+ // If header explicitly defines status, use it (normalized)
77
+ if (headerStatus) {
78
+ const normalized = headerStatus.toLowerCase().trim();
79
+ if (normalized.includes('complete') || normalized.includes('done')) {
80
+ return 'completed';
81
+ }
82
+ if (normalized.includes('review')) {
83
+ return 'in-review';
84
+ }
85
+ if (normalized.includes('cancel')) {
86
+ return 'cancelled';
87
+ }
88
+ if (normalized.includes('progress') || normalized.includes('active')) {
89
+ return 'in-progress';
90
+ }
91
+ if (normalized.includes('pending') || normalized.includes('todo') || normalized.includes('planned')) {
92
+ return 'pending';
93
+ }
94
+ }
95
+
96
+ // Otherwise derive from phase stats
97
+ if (stats.completed === stats.total && stats.total > 0) {
98
+ return 'completed';
99
+ }
100
+ if (stats.inProgress > 0 || stats.completed > 0) {
101
+ return 'in-progress';
102
+ }
103
+ return 'pending';
104
+ }
105
+
106
+ /**
107
+ * Get metadata for a single plan
108
+ * @param {string} planFilePath - Absolute path to plan.md
109
+ * @returns {Object|null} - Plan metadata object or null if invalid
110
+ */
111
+ function getPlanMetadata(planFilePath) {
112
+ try {
113
+ if (!fs.existsSync(planFilePath)) {
114
+ return null;
115
+ }
116
+
117
+ const directory = path.dirname(planFilePath);
118
+ const dirName = path.basename(directory);
119
+ const stats = fs.statSync(planFilePath);
120
+
121
+ // Parse phases from plan table
122
+ const phases = parsePlanTable(planFilePath);
123
+ const progress = calculateProgress(phases);
124
+
125
+ // Extract rich metadata (dates, effort, priority, etc.)
126
+ const richMeta = extractPlanMetadata(planFilePath);
127
+
128
+ return {
129
+ id: dirName,
130
+ name: parsePlanName(dirName),
131
+ path: planFilePath,
132
+ directory: directory,
133
+ phases: progress,
134
+ progress: progress.percentage,
135
+ lastModified: stats.mtime.toISOString(),
136
+ // Use frontmatter status if hasFrontmatter (already normalized), otherwise derive from phases
137
+ status: richMeta.hasFrontmatter && richMeta.headerStatus
138
+ ? normalizeStatus(richMeta.headerStatus)
139
+ : deriveStatus(progress, richMeta.headerStatus),
140
+ // Rich metadata
141
+ createdDate: richMeta.createdDate,
142
+ completedDate: richMeta.completedDate,
143
+ durationDays: richMeta.durationDays,
144
+ durationFormatted: richMeta.durationFormatted,
145
+ totalEffortHours: richMeta.totalEffortHours,
146
+ totalEffortFormatted: richMeta.totalEffortFormatted,
147
+ priority: richMeta.priority,
148
+ issue: richMeta.issue,
149
+ branch: richMeta.branch,
150
+ // New frontmatter fields
151
+ description: richMeta.description,
152
+ tags: richMeta.tags || [],
153
+ assignee: richMeta.assignee,
154
+ title: richMeta.title
155
+ };
156
+ } catch (err) {
157
+ console.error(`[plan-scanner] Error reading plan: ${planFilePath}`, err.message);
158
+ return null;
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Check if path is safe (within allowed directory, no traversal)
164
+ * @param {string} targetPath - Path to check
165
+ * @param {string} baseDir - Allowed base directory
166
+ * @returns {boolean}
167
+ */
168
+ function isPathSafe(targetPath, baseDir) {
169
+ const resolved = path.resolve(targetPath);
170
+ const resolvedBase = path.resolve(baseDir);
171
+
172
+ // Must start with base directory
173
+ if (!resolved.startsWith(resolvedBase)) {
174
+ return false;
175
+ }
176
+
177
+ // No null bytes
178
+ if (targetPath.includes('\0')) {
179
+ return false;
180
+ }
181
+
182
+ return true;
183
+ }
184
+
185
+ /**
186
+ * Scan directory for plan.md files
187
+ * @param {string} plansDir - Root directory to scan (e.g., ./plans)
188
+ * @param {Object} options - Scan options
189
+ * @param {number} options.maxDepth - Maximum recursion depth (default: 2)
190
+ * @param {string[]} options.exclude - Directory names to exclude (default: ['node_modules', '.git', 'templates', 'reports', 'research'])
191
+ * @returns {Array<Object>} - Array of plan metadata objects sorted by lastModified desc
192
+ */
193
+ function scanPlans(plansDir, options = {}) {
194
+ const {
195
+ maxDepth = 2,
196
+ exclude = ['node_modules', '.git', 'templates', 'reports', 'research']
197
+ } = options;
198
+
199
+ const resolvedBase = path.resolve(plansDir);
200
+ const plans = [];
201
+
202
+ /**
203
+ * Recursive directory scanner
204
+ * @param {string} dir - Current directory
205
+ * @param {number} depth - Current depth
206
+ */
207
+ function scanDir(dir, depth) {
208
+ if (depth > maxDepth) return;
209
+
210
+ // Security: validate path
211
+ if (!isPathSafe(dir, resolvedBase)) {
212
+ console.error(`[plan-scanner] Path traversal blocked: ${dir}`);
213
+ return;
214
+ }
215
+
216
+ let entries;
217
+ try {
218
+ entries = fs.readdirSync(dir, { withFileTypes: true });
219
+ } catch (err) {
220
+ console.error(`[plan-scanner] Cannot read directory: ${dir}`, err.message);
221
+ return;
222
+ }
223
+
224
+ for (const entry of entries) {
225
+ // Skip excluded directories
226
+ if (exclude.includes(entry.name)) continue;
227
+
228
+ // Skip hidden directories
229
+ if (entry.name.startsWith('.')) continue;
230
+
231
+ const fullPath = path.join(dir, entry.name);
232
+
233
+ if (entry.isDirectory()) {
234
+ // Check for plan.md in this directory
235
+ const planFile = path.join(fullPath, 'plan.md');
236
+ if (fs.existsSync(planFile)) {
237
+ const metadata = getPlanMetadata(planFile);
238
+ if (metadata) {
239
+ plans.push(metadata);
240
+ }
241
+ } else {
242
+ // Recurse into subdirectory
243
+ scanDir(fullPath, depth + 1);
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ // Start scanning
250
+ if (fs.existsSync(resolvedBase)) {
251
+ scanDir(resolvedBase, 0);
252
+ } else {
253
+ console.error(`[plan-scanner] Plans directory not found: ${plansDir}`);
254
+ }
255
+
256
+ // Sort by lastModified descending (newest first)
257
+ plans.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
258
+
259
+ return plans;
260
+ }
261
+
262
+ module.exports = {
263
+ scanPlans,
264
+ getPlanMetadata,
265
+ calculateProgress,
266
+ parsePlanName,
267
+ deriveStatus,
268
+ isPathSafe,
269
+ // Re-export timeline helpers
270
+ generateTimelineStats,
271
+ generateActivityHeatmap
272
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Port finder utility for plans-kanban server
3
+ * Uses port range 3500-3550 to avoid conflicts with markdown-novel-viewer
4
+ */
5
+
6
+ const net = require('net');
7
+
8
+ const DEFAULT_PORT = 3500;
9
+ const PORT_RANGE_END = 3550;
10
+
11
+ /**
12
+ * Check if a port is available
13
+ * @param {number} port - Port to check
14
+ * @returns {Promise<boolean>} - True if available
15
+ */
16
+ function isPortAvailable(port) {
17
+ return new Promise((resolve) => {
18
+ const server = net.createServer();
19
+ server.once('error', () => resolve(false));
20
+ server.once('listening', () => {
21
+ server.close();
22
+ resolve(true);
23
+ });
24
+ server.listen(port);
25
+ });
26
+ }
27
+
28
+ /**
29
+ * Find first available port in range
30
+ * @param {number} startPort - Starting port (default: 3500)
31
+ * @returns {Promise<number>} - Available port
32
+ * @throws {Error} - If no port available in range
33
+ */
34
+ async function findAvailablePort(startPort = DEFAULT_PORT) {
35
+ for (let port = startPort; port <= PORT_RANGE_END; port++) {
36
+ if (await isPortAvailable(port)) {
37
+ return port;
38
+ }
39
+ }
40
+ throw new Error(`No available port in range ${startPort}-${PORT_RANGE_END}`);
41
+ }
42
+
43
+ module.exports = {
44
+ isPortAvailable,
45
+ findAvailablePort,
46
+ DEFAULT_PORT,
47
+ PORT_RANGE_END
48
+ };
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Process manager for plans-kanban server
3
+ * Handles PID files and server lifecycle
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const os = require('os');
8
+ const path = require('path');
9
+
10
+ // Cross-platform temp directory for PID files
11
+ const PID_DIR = os.tmpdir();
12
+ const PID_PREFIX = 'plans-kanban-';
13
+
14
+ /**
15
+ * Get PID file path for a port
16
+ * @param {number} port - Server port
17
+ * @returns {string} - PID file path
18
+ */
19
+ function getPidFilePath(port) {
20
+ return path.join(PID_DIR, `${PID_PREFIX}${port}.pid`);
21
+ }
22
+
23
+ /**
24
+ * Write PID file for running server
25
+ * @param {number} port - Server port
26
+ * @param {number} pid - Process ID
27
+ */
28
+ function writePidFile(port, pid) {
29
+ fs.writeFileSync(getPidFilePath(port), String(pid));
30
+ }
31
+
32
+ /**
33
+ * Read PID from file
34
+ * @param {number} port - Server port
35
+ * @returns {number|null} - PID or null if not found
36
+ */
37
+ function readPidFile(port) {
38
+ const pidPath = getPidFilePath(port);
39
+ if (fs.existsSync(pidPath)) {
40
+ return parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
41
+ }
42
+ return null;
43
+ }
44
+
45
+ /**
46
+ * Remove PID file
47
+ * @param {number} port - Server port
48
+ */
49
+ function removePidFile(port) {
50
+ const pidPath = getPidFilePath(port);
51
+ if (fs.existsSync(pidPath)) {
52
+ fs.unlinkSync(pidPath);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Find all running kanban server instances
58
+ * @returns {Array<{port: number, pid: number}>}
59
+ */
60
+ function findRunningInstances() {
61
+ const instances = [];
62
+ const files = fs.readdirSync(PID_DIR);
63
+
64
+ for (const file of files) {
65
+ if (file.startsWith(PID_PREFIX) && file.endsWith('.pid')) {
66
+ const port = parseInt(file.replace(PID_PREFIX, '').replace('.pid', ''), 10);
67
+ const pid = readPidFile(port);
68
+ if (pid) {
69
+ try {
70
+ process.kill(pid, 0);
71
+ instances.push({ port, pid });
72
+ } catch {
73
+ removePidFile(port);
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ return instances;
80
+ }
81
+
82
+ /**
83
+ * Stop all running kanban servers
84
+ * @returns {number} - Number of servers stopped
85
+ */
86
+ function stopAllServers() {
87
+ const instances = findRunningInstances();
88
+ let stopped = 0;
89
+
90
+ for (const { port, pid } of instances) {
91
+ try {
92
+ process.kill(pid, 'SIGTERM');
93
+ removePidFile(port);
94
+ stopped++;
95
+ } catch {
96
+ removePidFile(port);
97
+ }
98
+ }
99
+
100
+ return stopped;
101
+ }
102
+
103
+ /**
104
+ * Setup graceful shutdown handlers
105
+ * @param {number} port - Server port
106
+ * @param {Function} cleanup - Additional cleanup function
107
+ */
108
+ function setupShutdownHandlers(port, cleanup) {
109
+ const handler = () => {
110
+ if (cleanup) cleanup();
111
+ removePidFile(port);
112
+ process.exit(0);
113
+ };
114
+
115
+ process.on('SIGTERM', handler);
116
+ process.on('SIGINT', handler);
117
+ }
118
+
119
+ module.exports = {
120
+ getPidFilePath,
121
+ writePidFile,
122
+ readPidFile,
123
+ removePidFile,
124
+ findRunningInstances,
125
+ stopAllServers,
126
+ setupShutdownHandlers,
127
+ PID_PREFIX
128
+ };
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Plans Kanban Server
5
+ * Background HTTP server for plans dashboard with progress tracking
6
+ *
7
+ * Usage:
8
+ * node server.cjs --dir ./plans [--port 3500] [--open] [--stop] [--host 0.0.0.0]
9
+ *
10
+ * Options:
11
+ * --dir <path> Path to plans directory
12
+ * --port <number> Server port (default: 3500, auto-increment if busy)
13
+ * --host <addr> Host to bind (default: localhost, use 0.0.0.0 for all interfaces)
14
+ * --open Auto-open browser after start
15
+ * --stop Stop all running kanban servers
16
+ * --background Run in background (detached) - legacy mode
17
+ * --foreground Run in foreground (for CC background tasks)
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const os = require('os');
23
+ const { spawn, execSync } = require('child_process');
24
+
25
+ const { findAvailablePort, DEFAULT_PORT } = require('./lib/port-finder.cjs');
26
+ const { writePidFile, stopAllServers, setupShutdownHandlers, findRunningInstances } = require('./lib/process-mgr.cjs');
27
+ const { createHttpServer } = require('./lib/http-server.cjs');
28
+
29
+ /**
30
+ * Parse command line arguments
31
+ */
32
+ function parseArgs(argv) {
33
+ const args = {
34
+ dir: null,
35
+ port: DEFAULT_PORT,
36
+ host: 'localhost',
37
+ open: false,
38
+ stop: false,
39
+ background: false,
40
+ foreground: false,
41
+ isChild: false
42
+ };
43
+
44
+ for (let i = 2; i < argv.length; i++) {
45
+ const arg = argv[i];
46
+ if ((arg === '--dir' || arg === '--plans') && argv[i + 1]) {
47
+ args.dir = argv[++i];
48
+ } else if (arg === '--port' && argv[i + 1]) {
49
+ args.port = parseInt(argv[++i], 10);
50
+ } else if (arg === '--host' && argv[i + 1]) {
51
+ args.host = argv[++i];
52
+ } else if (arg === '--open') {
53
+ args.open = true;
54
+ } else if (arg === '--stop') {
55
+ args.stop = true;
56
+ } else if (arg === '--background') {
57
+ args.background = true;
58
+ } else if (arg === '--foreground') {
59
+ args.foreground = true;
60
+ } else if (arg === '--child') {
61
+ args.isChild = true;
62
+ } else if (!arg.startsWith('--') && !args.dir) {
63
+ args.dir = arg;
64
+ }
65
+ }
66
+
67
+ return args;
68
+ }
69
+
70
+ /**
71
+ * Get local network IP address for remote access
72
+ */
73
+ function getLocalIP() {
74
+ const interfaces = os.networkInterfaces();
75
+ for (const name of Object.keys(interfaces)) {
76
+ for (const iface of interfaces[name]) {
77
+ if (iface.family === 'IPv4' && !iface.internal) {
78
+ return iface.address;
79
+ }
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * Build URL with network URL for remote access
87
+ */
88
+ function buildUrl(host, port, plansDir) {
89
+ const displayHost = host === '0.0.0.0' ? 'localhost' : host;
90
+ const urlPath = `/kanban?dir=${encodeURIComponent(plansDir)}`;
91
+ const url = `http://${displayHost}:${port}${urlPath}`;
92
+
93
+ let networkUrl = null;
94
+ if (host === '0.0.0.0') {
95
+ const localIP = getLocalIP();
96
+ if (localIP) {
97
+ networkUrl = `http://${localIP}:${port}${urlPath}`;
98
+ }
99
+ }
100
+
101
+ return { url, networkUrl };
102
+ }
103
+
104
+ /**
105
+ * Open browser
106
+ */
107
+ function openBrowser(url) {
108
+ const platform = process.platform;
109
+ let cmd;
110
+
111
+ if (platform === 'darwin') {
112
+ cmd = `open "${url}"`;
113
+ } else if (platform === 'win32') {
114
+ cmd = `start "${url}"`;
115
+ } else {
116
+ cmd = `xdg-open "${url}"`;
117
+ }
118
+
119
+ try {
120
+ execSync(cmd, { stdio: 'ignore' });
121
+ } catch {
122
+ // Ignore browser open errors
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Main function
128
+ */
129
+ async function main() {
130
+ const args = parseArgs(process.argv);
131
+ const cwd = process.cwd();
132
+ const assetsDir = path.join(__dirname, '..', 'assets');
133
+
134
+ // Handle --stop
135
+ if (args.stop) {
136
+ const instances = findRunningInstances();
137
+ if (instances.length === 0) {
138
+ console.log('No kanban server running to stop');
139
+ process.exit(0);
140
+ }
141
+ const stopped = stopAllServers();
142
+ console.log(`Stopped ${stopped} kanban server(s)`);
143
+ process.exit(0);
144
+ }
145
+
146
+ // Validate input
147
+ if (!args.dir) {
148
+ console.error('Error: --dir argument required');
149
+ console.error('Usage:');
150
+ console.error(' node server.cjs --dir <plans-dir> [--port 3500] [--open]');
151
+ process.exit(1);
152
+ }
153
+
154
+ // Resolve plans directory
155
+ const plansDir = path.isAbsolute(args.dir) ? args.dir : path.resolve(cwd, args.dir);
156
+
157
+ if (!fs.existsSync(plansDir) || !fs.statSync(plansDir).isDirectory()) {
158
+ console.error(`Error: Directory not found: ${args.dir}`);
159
+ process.exit(1);
160
+ }
161
+
162
+ // Background mode - spawn child and exit (legacy mode for manual runs)
163
+ // Skip if --foreground is set (for Claude Code background tasks)
164
+ if (args.background && !args.foreground && !args.isChild) {
165
+ const childArgs = ['--dir', plansDir, '--port', String(args.port), '--host', args.host, '--child'];
166
+ if (args.open) childArgs.push('--open');
167
+
168
+ const child = spawn(process.execPath, [__filename, ...childArgs], {
169
+ detached: true,
170
+ stdio: 'ignore',
171
+ cwd: cwd
172
+ });
173
+ child.unref();
174
+
175
+ await new Promise(r => setTimeout(r, 500));
176
+
177
+ const instances = findRunningInstances();
178
+ const instance = instances.find(i => i.port >= args.port);
179
+ const port = instance ? instance.port : args.port;
180
+
181
+ const { url, networkUrl } = buildUrl(args.host, port, plansDir);
182
+
183
+ const result = {
184
+ success: true,
185
+ url,
186
+ dir: plansDir,
187
+ port,
188
+ host: args.host,
189
+ mode: 'kanban'
190
+ };
191
+ if (networkUrl) result.networkUrl = networkUrl;
192
+
193
+ console.log(JSON.stringify(result));
194
+ process.exit(0);
195
+ }
196
+
197
+ // Find available port
198
+ const port = await findAvailablePort(args.port);
199
+ if (port !== args.port) {
200
+ console.error(`Port ${args.port} in use, using ${port}`);
201
+ }
202
+
203
+ // Determine allowed directories
204
+ const allowedDirs = [assetsDir, cwd, plansDir];
205
+
206
+ // Create server
207
+ const server = createHttpServer({
208
+ assetsDir,
209
+ allowedDirs,
210
+ plansDir
211
+ });
212
+
213
+ // Start server
214
+ server.listen(port, args.host, () => {
215
+ const { url, networkUrl } = buildUrl(args.host, port, plansDir);
216
+
217
+ writePidFile(port, process.pid);
218
+ setupShutdownHandlers(port, () => server.close());
219
+
220
+ // Output for CLI/command integration
221
+ // In foreground mode (CC background task), always output JSON
222
+ if (args.foreground || args.isChild || process.env.CLAUDE_COMMAND) {
223
+ const result = {
224
+ success: true,
225
+ url,
226
+ dir: plansDir,
227
+ port,
228
+ host: args.host,
229
+ mode: 'kanban'
230
+ };
231
+ if (networkUrl) result.networkUrl = networkUrl;
232
+ console.log(JSON.stringify(result));
233
+ } else {
234
+ console.log(`\nPlans Kanban Dashboard`);
235
+ console.log(`${'─'.repeat(40)}`);
236
+ console.log(`URL: ${url}`);
237
+ if (networkUrl) {
238
+ console.log(`Network: ${networkUrl}`);
239
+ }
240
+ console.log(`Plans: ${plansDir}`);
241
+ console.log(`Port: ${port}`);
242
+ console.log(`Host: ${args.host}`);
243
+ console.log(`\nPress Ctrl+C to stop\n`);
244
+ }
245
+
246
+ if (args.open) {
247
+ openBrowser(url);
248
+ }
249
+ });
250
+
251
+ server.on('error', (err) => {
252
+ console.error(`Server error: ${err.message}`);
253
+ process.exit(1);
254
+ });
255
+ }
256
+
257
+ main().catch(err => {
258
+ console.error(`Error: ${err.message}`);
259
+ process.exit(1);
260
+ });