@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,509 @@
1
+ /**
2
+ * Plan navigation system - detects plan structure and generates navigation
3
+ * Enables sidebar navigation for multi-phase plans
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ /**
10
+ * Detect if a file is part of a plan directory
11
+ * @param {string} filePath - Path to markdown file
12
+ * @returns {{isPlan: boolean, planDir: string, planFile: string, phases: Array}}
13
+ */
14
+ function detectPlan(filePath) {
15
+ const dir = path.dirname(filePath);
16
+ const planFile = path.join(dir, 'plan.md');
17
+
18
+ if (!fs.existsSync(planFile)) {
19
+ return { isPlan: false };
20
+ }
21
+
22
+ // Find all phase files
23
+ const files = fs.readdirSync(dir);
24
+ const phases = files
25
+ .filter(f => f.startsWith('phase-') && f.endsWith('.md'))
26
+ .sort((a, b) => {
27
+ // Sort by phase number
28
+ const numA = parseInt(a.match(/phase-(\d+)/)?.[1] || '0', 10);
29
+ const numB = parseInt(b.match(/phase-(\d+)/)?.[1] || '0', 10);
30
+ return numA - numB;
31
+ });
32
+
33
+ return {
34
+ isPlan: true,
35
+ planDir: dir,
36
+ planFile,
37
+ phases: phases.map(f => path.join(dir, f))
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Normalize status string to standard format
43
+ * @param {string} raw - Raw status text
44
+ * @returns {string} - Normalized status (completed, in-progress, pending)
45
+ */
46
+ function normalizeStatus(raw) {
47
+ const s = (raw || '').toLowerCase().trim();
48
+ // Match various completed indicators
49
+ if (s.includes('complete') || s.includes('done') || s.includes('✓') || s.includes('✅')) {
50
+ return 'completed';
51
+ }
52
+ // Match in-progress indicators
53
+ if (s.includes('progress') || s.includes('active') || s.includes('wip') || s.includes('🔄')) {
54
+ return 'in-progress';
55
+ }
56
+ return 'pending';
57
+ }
58
+
59
+ /**
60
+ * Generate a slug from text for use as anchor ID
61
+ * @param {string} text - Text to slugify
62
+ * @returns {string} - URL-safe slug
63
+ */
64
+ function slugify(text) {
65
+ return text
66
+ .toLowerCase()
67
+ .replace(/[^a-z0-9]+/g, '-')
68
+ .replace(/^-|-$/g, '');
69
+ }
70
+
71
+ /**
72
+ * Parse plan.md to extract phase metadata from table
73
+ * Supports multiple table formats:
74
+ * 1. Standard: | Phase | Name | Status | [Link](path) |
75
+ * 2. Link-first: | [Phase X](path) | Description | Status | ... |
76
+ * 3. Heading-based: ### Phase X: Name with - Status: XXX
77
+ * @param {string} planFilePath - Path to plan.md
78
+ * @returns {Array<{phase: number, name: string, status: string, file: string, anchor: string}>}
79
+ */
80
+ function parsePlanTable(planFilePath) {
81
+ const content = fs.readFileSync(planFilePath, 'utf8');
82
+ const dir = path.dirname(planFilePath);
83
+ const phases = [];
84
+
85
+ // Format 1: Standard table | Phase | Name | Status | [Link](path) |
86
+ const standardRegex = /\|\s*(\d+)\s*\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|\s*\[([^\]]+)\]\(([^)]+)\)/g;
87
+ let match;
88
+ while ((match = standardRegex.exec(content)) !== null) {
89
+ const [, phase, name, status, linkText, linkPath] = match;
90
+ phases.push({
91
+ phase: parseInt(phase, 10),
92
+ name: name.trim(),
93
+ status: normalizeStatus(status),
94
+ file: path.resolve(dir, linkPath),
95
+ linkText: linkText.trim()
96
+ });
97
+ }
98
+
99
+ // Format 2: Link-first table | [Phase X](path) | Description | Status | ... |
100
+ // Matches: | [Phase 1](phase-01-xxx.md) | Description | ✓ Complete | 4h |
101
+ if (phases.length === 0) {
102
+ const linkFirstRegex = /\|\s*\[(?:Phase\s*)?(\d+)\]\(([^)]+)\)\s*\|\s*([^|]+)\s*\|\s*([^|]+)/g;
103
+ while ((match = linkFirstRegex.exec(content)) !== null) {
104
+ const [, phase, linkPath, name, status] = match;
105
+ phases.push({
106
+ phase: parseInt(phase, 10),
107
+ name: name.trim(),
108
+ status: normalizeStatus(status),
109
+ file: path.resolve(dir, linkPath),
110
+ linkText: `Phase ${phase}`
111
+ });
112
+ }
113
+ }
114
+
115
+ // Format 2b: Number-first with link in col 2: | 1 | [Name](path) | Status | ... |
116
+ // Matches: | 1 | [Tab Structure](./phase-01-xxx.md) | Pending | High | 4h |
117
+ if (phases.length === 0) {
118
+ const numLinkRegex = /\|\s*(\d+)\s*\|\s*\[([^\]]+)\]\(([^)]+)\)\s*\|\s*([^|]+)/g;
119
+ while ((match = numLinkRegex.exec(content)) !== null) {
120
+ const [, phase, name, linkPath, status] = match;
121
+ phases.push({
122
+ phase: parseInt(phase, 10),
123
+ name: name.trim(),
124
+ status: normalizeStatus(status),
125
+ file: path.resolve(dir, linkPath),
126
+ linkText: name.trim()
127
+ });
128
+ }
129
+ }
130
+
131
+ // Format 2c: Simple table without links: | Phase | Description | Status |
132
+ // Matches: | 01 | Backend: Install deps | Completed ✅ |
133
+ if (phases.length === 0) {
134
+ const simpleTblRegex = /\|\s*0?(\d+)\s*\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|/g;
135
+ while ((match = simpleTblRegex.exec(content)) !== null) {
136
+ const [fullMatch, phase, name, status] = match;
137
+ // Skip header rows and separator rows
138
+ if (name.trim().toLowerCase() === 'description' || name.trim().toLowerCase() === 'name') continue;
139
+ if (name.includes('---') || name.includes('===')) continue;
140
+ const phaseNum = parseInt(phase, 10);
141
+ phases.push({
142
+ phase: phaseNum,
143
+ name: name.trim(),
144
+ status: normalizeStatus(status),
145
+ file: planFilePath,
146
+ linkText: name.trim(),
147
+ anchor: `phase-${String(phaseNum).padStart(2, '0')}-${slugify(name.trim())}`
148
+ });
149
+ }
150
+ }
151
+
152
+ // Format 3: Heading-based phases (### Phase X: Name with - Status: XXX)
153
+ if (phases.length === 0) {
154
+ const contentLines = content.split('\n');
155
+ let currentPhase = null;
156
+
157
+ for (let i = 0; i < contentLines.length; i++) {
158
+ const line = contentLines[i];
159
+ const headingMatch = /###\s*Phase\s*(\d+)[:\s]+(.+)/i.exec(line);
160
+ if (headingMatch) {
161
+ if (currentPhase) phases.push(currentPhase);
162
+ const phaseNum = parseInt(headingMatch[1], 10);
163
+ const phaseName = headingMatch[2].trim();
164
+ currentPhase = {
165
+ phase: phaseNum,
166
+ name: phaseName,
167
+ status: 'pending',
168
+ file: planFilePath,
169
+ linkText: `Phase ${phaseNum}`,
170
+ anchor: `phase-${String(phaseNum).padStart(2, '0')}-${slugify(phaseName)}`
171
+ };
172
+ }
173
+ // Look for status in subsequent lines
174
+ if (currentPhase) {
175
+ const statusMatch = /-\s*Status:\s*(.+)/i.exec(line);
176
+ if (statusMatch) {
177
+ currentPhase.status = normalizeStatus(statusMatch[1]);
178
+ }
179
+ }
180
+ }
181
+ if (currentPhase) phases.push(currentPhase);
182
+ }
183
+
184
+ // Format 4: Bullet-list phases with nested File: references (check early - specific pattern)
185
+ // Matches:
186
+ // - Phase 01: Name ✅ (date)
187
+ // - File: `phase-01-name.md`
188
+ // - Completed: date
189
+ // Check if content has this specific pattern before proceeding
190
+ if (phases.length === 0 && /^-\s*Phase\s*\d+[:\s]/m.test(content)) {
191
+ const lines = content.split('\n');
192
+ let currentPhase = null;
193
+
194
+ for (let i = 0; i < lines.length; i++) {
195
+ const line = lines[i];
196
+
197
+ // Match phase line: "- Phase 01: Name ✅" or "- Phase 01: Name (date)"
198
+ const phaseMatch = /^-\s*Phase\s*0?(\d+)[:\s]+([^✅✓\n]+)/i.exec(line);
199
+ if (phaseMatch) {
200
+ // Save previous phase if exists
201
+ if (currentPhase) phases.push(currentPhase);
202
+
203
+ const phaseNum = parseInt(phaseMatch[1], 10);
204
+ const name = phaseMatch[2].trim().replace(/\s*\([^)]*\)\s*$/, ''); // Remove trailing (date)
205
+ const hasCheckmark = /[✅✓]/.test(line);
206
+
207
+ currentPhase = {
208
+ phase: phaseNum,
209
+ name: name,
210
+ status: hasCheckmark ? 'completed' : 'pending',
211
+ file: planFilePath, // Default to plan.md, will be updated if File: found
212
+ linkText: name,
213
+ anchor: `phase-${String(phaseNum).padStart(2, '0')}-${slugify(name)}`
214
+ };
215
+ continue;
216
+ }
217
+
218
+ // Look for nested File: reference within current phase
219
+ if (currentPhase) {
220
+ const fileMatch = /^\s+-\s*File:\s*`?([^`\n]+)`?/i.exec(line);
221
+ if (fileMatch) {
222
+ const fileName = fileMatch[1].trim();
223
+ currentPhase.file = path.resolve(dir, fileName);
224
+ // Clear anchor when separate file exists
225
+ currentPhase.anchor = null;
226
+ }
227
+
228
+ // Check for status indicators in nested lines
229
+ const statusMatch = /^\s+-\s*(Completed|Status):\s*(.+)/i.exec(line);
230
+ if (statusMatch) {
231
+ currentPhase.status = normalizeStatus(statusMatch[2]);
232
+ }
233
+
234
+ // End current phase when we hit another top-level non-phase item or section header
235
+ if (/^##/.test(line) || (/^-\s/.test(line) && !/^-\s*Phase/i.test(line) && !/^\s+-/.test(line))) {
236
+ phases.push(currentPhase);
237
+ currentPhase = null;
238
+ }
239
+ }
240
+ }
241
+
242
+ // Push last phase if exists
243
+ if (currentPhase) phases.push(currentPhase);
244
+ }
245
+
246
+ // Format 5: Numbered list phases with checkbox status
247
+ // Matches: 1) **Discovery** with status from - [x] Discovery: ...
248
+ if (phases.length === 0) {
249
+ // First pass: find numbered phases like "1) **Name**" or "1. **Name**"
250
+ const numberedPhaseRegex = /^(\d+)[)\.]\s*\*\*([^*]+)\*\*/gm;
251
+ const phaseMap = new Map();
252
+ while ((match = numberedPhaseRegex.exec(content)) !== null) {
253
+ const [, num, name] = match;
254
+ const phaseNum = parseInt(num, 10);
255
+ phaseMap.set(name.trim().toLowerCase(), {
256
+ phase: phaseNum,
257
+ name: name.trim(),
258
+ status: 'pending',
259
+ file: planFilePath,
260
+ linkText: name.trim(),
261
+ anchor: `phase-${String(phaseNum).padStart(2, '0')}-${slugify(name.trim())}`
262
+ });
263
+ }
264
+
265
+ // Second pass: find checkbox status like "- [x] Name:" or "- [ ] Name:"
266
+ const checkboxRegex = /^-\s*\[(x| )\]\s*([^:]+)/gmi;
267
+ while ((match = checkboxRegex.exec(content)) !== null) {
268
+ const [, checked, name] = match;
269
+ const key = name.trim().toLowerCase();
270
+ if (phaseMap.has(key)) {
271
+ phaseMap.get(key).status = checked.toLowerCase() === 'x' ? 'completed' : 'pending';
272
+ }
273
+ }
274
+
275
+ // Convert map to array sorted by phase number
276
+ if (phaseMap.size > 0) {
277
+ phases.push(...Array.from(phaseMap.values()).sort((a, b) => a.phase - b.phase));
278
+ }
279
+ }
280
+
281
+ // Format 6: Checkbox list with bold links
282
+ // Matches: - [ ] **[Phase 1: Name](./phase-01-xxx.md)** or - [x] **[Phase 1](path)**
283
+ if (phases.length === 0) {
284
+ const checkboxLinkRegex = /^-\s*\[(x| )\]\s*\*\*\[(?:Phase\s*)?(\d+)[:\s]*([^\]]*)\]\(([^)]+)\)\*\*/gmi;
285
+ while ((match = checkboxLinkRegex.exec(content)) !== null) {
286
+ const [, checked, phase, name, linkPath] = match;
287
+ phases.push({
288
+ phase: parseInt(phase, 10),
289
+ name: name.trim() || `Phase ${phase}`,
290
+ status: checked.toLowerCase() === 'x' ? 'completed' : 'pending',
291
+ file: path.resolve(dir, linkPath),
292
+ linkText: name.trim() || `Phase ${phase}`
293
+ });
294
+ }
295
+ }
296
+
297
+ // Enhancement: Extract file paths from "Phase Files" section if phases point to plan.md
298
+ // This handles plans with heading-based phases + separate file links section
299
+ if (phases.length > 0) {
300
+ const phaseFilesSection = content.match(/##\s*Phase\s*Files[\s\S]*?(?=##|$)/i);
301
+ if (phaseFilesSection) {
302
+ const linkRegex = /\d+\.\s*\[([^\]]+)\]\(([^)]+\.md)\)/g;
303
+ let linkMatch;
304
+ while ((linkMatch = linkRegex.exec(phaseFilesSection[0])) !== null) {
305
+ const [, linkName, linkPath] = linkMatch;
306
+ // Extract phase number from filename (phase-01-xxx.md -> 1)
307
+ const phaseNum = parseInt(linkName.match(/phase-0?(\d+)/i)?.[1] || '0', 10);
308
+ // Update corresponding phase's file path
309
+ const phase = phases.find(p => p.phase === phaseNum);
310
+ if (phase && phase.file === planFilePath) {
311
+ phase.file = path.resolve(dir, linkPath);
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ // Filter out phases that only point to the plan.md itself (inline sections)
318
+ // Only keep phases that have separate phase files
319
+ return phases.filter(p => p.file !== planFilePath);
320
+ }
321
+
322
+ /**
323
+ * Get navigation context for a file
324
+ * @param {string} filePath - Current file path
325
+ * @returns {{planInfo: Object, currentIndex: number, prev: Object, next: Object, allPhases: Array}}
326
+ */
327
+ function getNavigationContext(filePath) {
328
+ const planInfo = detectPlan(filePath);
329
+
330
+ if (!planInfo.isPlan) {
331
+ return { planInfo, currentIndex: -1, prev: null, next: null, allPhases: [] };
332
+ }
333
+
334
+ // Parse plan table for metadata
335
+ const phaseMeta = parsePlanTable(planInfo.planFile);
336
+
337
+ // Build all phases list including plan.md
338
+ const allPhases = [
339
+ {
340
+ phase: 0,
341
+ name: 'Plan Overview',
342
+ status: 'overview',
343
+ file: planInfo.planFile
344
+ },
345
+ ...phaseMeta
346
+ ];
347
+
348
+ // Find current file index
349
+ const normalizedPath = path.normalize(filePath);
350
+ const currentIndex = allPhases.findIndex(p => path.normalize(p.file) === normalizedPath);
351
+
352
+ // Get prev/next
353
+ const prev = currentIndex > 0 ? allPhases[currentIndex - 1] : null;
354
+ const next = currentIndex < allPhases.length - 1 && currentIndex >= 0
355
+ ? allPhases[currentIndex + 1]
356
+ : null;
357
+
358
+ return {
359
+ planInfo,
360
+ currentIndex,
361
+ prev,
362
+ next,
363
+ allPhases
364
+ };
365
+ }
366
+
367
+ /**
368
+ * Generate navigation sidebar HTML
369
+ * @param {string} filePath - Current file path
370
+ * @returns {string} - HTML navigation sidebar
371
+ */
372
+ function generateNavSidebar(filePath) {
373
+ const { planInfo, currentIndex, allPhases } = getNavigationContext(filePath);
374
+
375
+ if (!planInfo.isPlan) {
376
+ return '';
377
+ }
378
+
379
+ const planName = path.basename(planInfo.planDir);
380
+ const normalizedCurrentPath = path.normalize(filePath);
381
+
382
+ const items = allPhases.map((phase, index) => {
383
+ const isActive = index === currentIndex;
384
+ const statusClass = phase.status.replace(/\s+/g, '-');
385
+ const normalizedPhasePath = path.normalize(phase.file);
386
+ const isSameFile = normalizedPhasePath === normalizedCurrentPath;
387
+
388
+ // Check if phase file actually exists on disk
389
+ const fileExists = fs.existsSync(phase.file);
390
+ const unavailableClass = !fileExists ? 'unavailable' : '';
391
+
392
+ // If file doesn't exist, render as non-clickable span with tooltip
393
+ if (!fileExists) {
394
+ return `
395
+ <li class="phase-item ${unavailableClass}" data-status="${statusClass}" title="Phase planned but not yet implemented">
396
+ <span class="phase-link-disabled">
397
+ <span class="status-dot ${statusClass}"></span>
398
+ <span class="phase-name">${phase.name}</span>
399
+ <span class="unavailable-badge">Planned</span>
400
+ </span>
401
+ </li>
402
+ `;
403
+ }
404
+
405
+ // Build href: use anchor for same-file phases, full URL for different files
406
+ let href;
407
+ let isInlineSection = false;
408
+ if (isSameFile && phase.anchor) {
409
+ // Same file with anchor - use hash fragment only for smooth scrolling
410
+ href = `#${phase.anchor}`;
411
+ isInlineSection = true;
412
+ } else if (phase.anchor) {
413
+ // Different file with anchor
414
+ href = `/view?file=${encodeURIComponent(phase.file)}#${phase.anchor}`;
415
+ } else {
416
+ // No anchor (separate phase file or plan overview)
417
+ href = `/view?file=${encodeURIComponent(phase.file)}`;
418
+ }
419
+
420
+ // Add data attributes for client-side section tracking
421
+ const dataAnchor = phase.anchor ? `data-anchor="${phase.anchor}"` : '';
422
+ const inlineSectionClass = isInlineSection ? 'inline-section' : '';
423
+
424
+ // Type icon: hash/anchor for inline sections, file for separate docs
425
+ const typeIcon = isInlineSection
426
+ ? `<svg class="phase-type-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-.5 9.45a.75.75 0 01-1.06-1.06l-1.25 1.25a2 2 0 01-2.83-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25z"/></svg>`
427
+ : `<svg class="phase-type-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M3.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h8.5a.25.25 0 00.25-.25V4.664a.25.25 0 00-.073-.177l-2.914-2.914a.25.25 0 00-.177-.073H3.75zM2 1.75C2 .784 2.784 0 3.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0112.25 16h-8.5A1.75 1.75 0 012 14.25V1.75z"/></svg>`;
428
+
429
+ return `
430
+ <li class="phase-item ${isActive ? 'active' : ''} ${inlineSectionClass}" data-status="${statusClass}" ${dataAnchor}>
431
+ <a href="${href}">
432
+ ${typeIcon}
433
+ <span class="status-dot ${statusClass}"></span>
434
+ <span class="phase-name">${phase.name}</span>
435
+ </a>
436
+ </li>
437
+ `;
438
+ }).join('');
439
+
440
+ return `
441
+ <nav class="plan-nav" id="plan-nav">
442
+ <div class="plan-title">
443
+ <span class="plan-icon">&#128214;</span>
444
+ <span>${planName}</span>
445
+ </div>
446
+ <ul class="phase-list">
447
+ ${items}
448
+ </ul>
449
+ </nav>
450
+ `;
451
+ }
452
+
453
+ /**
454
+ * Generate prev/next navigation footer
455
+ * @param {string} filePath - Current file path
456
+ * @returns {string} - HTML navigation footer
457
+ */
458
+ function generateNavFooter(filePath) {
459
+ const { prev, next } = getNavigationContext(filePath);
460
+
461
+ if (!prev && !next) {
462
+ return '';
463
+ }
464
+
465
+ // Check if prev/next files exist
466
+ const prevExists = prev && fs.existsSync(prev.file);
467
+ const nextExists = next && fs.existsSync(next.file);
468
+
469
+ const prevHtml = prev ? (prevExists ? `
470
+ <a href="/view?file=${encodeURIComponent(prev.file)}" class="nav-prev">
471
+ <span class="nav-arrow">&larr;</span>
472
+ <span class="nav-label">${prev.name}</span>
473
+ </a>
474
+ ` : `
475
+ <span class="nav-prev nav-unavailable" title="Phase planned but not yet implemented">
476
+ <span class="nav-arrow">&larr;</span>
477
+ <span class="nav-label">${prev.name}</span>
478
+ <span class="nav-badge">Planned</span>
479
+ </span>
480
+ `) : '<span></span>';
481
+
482
+ const nextHtml = next ? (nextExists ? `
483
+ <a href="/view?file=${encodeURIComponent(next.file)}" class="nav-next">
484
+ <span class="nav-label">${next.name}</span>
485
+ <span class="nav-arrow">&rarr;</span>
486
+ </a>
487
+ ` : `
488
+ <span class="nav-next nav-unavailable" title="Phase planned but not yet implemented">
489
+ <span class="nav-label">${next.name}</span>
490
+ <span class="nav-badge">Planned</span>
491
+ <span class="nav-arrow">&rarr;</span>
492
+ </span>
493
+ `) : '<span></span>';
494
+
495
+ return `
496
+ <footer class="nav-footer">
497
+ ${prevHtml}
498
+ ${nextHtml}
499
+ </footer>
500
+ `;
501
+ }
502
+
503
+ module.exports = {
504
+ detectPlan,
505
+ parsePlanTable,
506
+ getNavigationContext,
507
+ generateNavSidebar,
508
+ generateNavFooter
509
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Port finder utility - finds available port in range
3
+ * Used by markdown-novel-viewer server
4
+ */
5
+
6
+ const net = require('net');
7
+
8
+ const DEFAULT_PORT = 3456;
9
+ const PORT_RANGE_END = 3500;
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: 3456)
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,150 @@
1
+ /**
2
+ * Process manager - handles PID files and server lifecycle
3
+ * Used by markdown-novel-viewer server
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const PID_DIR = '/tmp';
10
+ const PID_PREFIX = 'md-novel-viewer-';
11
+
12
+ /**
13
+ * Get PID file path for a port
14
+ * @param {number} port - Server port
15
+ * @returns {string} - PID file path
16
+ */
17
+ function getPidFilePath(port) {
18
+ return path.join(PID_DIR, `${PID_PREFIX}${port}.pid`);
19
+ }
20
+
21
+ /**
22
+ * Write PID file for running server
23
+ * @param {number} port - Server port
24
+ * @param {number} pid - Process ID
25
+ */
26
+ function writePidFile(port, pid) {
27
+ const pidPath = getPidFilePath(port);
28
+ fs.writeFileSync(pidPath, String(pid));
29
+ }
30
+
31
+ /**
32
+ * Read PID from file
33
+ * @param {number} port - Server port
34
+ * @returns {number|null} - PID or null if not found
35
+ */
36
+ function readPidFile(port) {
37
+ const pidPath = getPidFilePath(port);
38
+ if (fs.existsSync(pidPath)) {
39
+ const pid = fs.readFileSync(pidPath, 'utf8').trim();
40
+ return parseInt(pid, 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 server instances
58
+ * @returns {Array<{port: number, pid: number}>} - Running instances
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
+ // Check if process is actually running
70
+ try {
71
+ process.kill(pid, 0);
72
+ instances.push({ port, pid });
73
+ } catch {
74
+ // Process not running, clean up stale PID file
75
+ removePidFile(port);
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ return instances;
82
+ }
83
+
84
+ /**
85
+ * Stop server by port
86
+ * @param {number} port - Server port
87
+ * @returns {boolean} - True if stopped successfully
88
+ */
89
+ function stopServer(port) {
90
+ const pid = readPidFile(port);
91
+ if (!pid) return false;
92
+
93
+ try {
94
+ process.kill(pid, 'SIGTERM');
95
+ removePidFile(port);
96
+ return true;
97
+ } catch {
98
+ removePidFile(port);
99
+ return false;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Stop all running servers
105
+ * @returns {number} - Number of servers stopped
106
+ */
107
+ function stopAllServers() {
108
+ const instances = findRunningInstances();
109
+ let stopped = 0;
110
+
111
+ for (const { port, pid } of instances) {
112
+ try {
113
+ process.kill(pid, 'SIGTERM');
114
+ removePidFile(port);
115
+ stopped++;
116
+ } catch {
117
+ removePidFile(port);
118
+ }
119
+ }
120
+
121
+ return stopped;
122
+ }
123
+
124
+ /**
125
+ * Setup graceful shutdown handlers
126
+ * @param {number} port - Server port
127
+ * @param {Function} cleanup - Additional cleanup function
128
+ */
129
+ function setupShutdownHandlers(port, cleanup) {
130
+ const handler = (signal) => {
131
+ if (cleanup) cleanup();
132
+ removePidFile(port);
133
+ process.exit(0);
134
+ };
135
+
136
+ process.on('SIGTERM', handler);
137
+ process.on('SIGINT', handler);
138
+ }
139
+
140
+ module.exports = {
141
+ getPidFilePath,
142
+ writePidFile,
143
+ readPidFile,
144
+ removePidFile,
145
+ findRunningInstances,
146
+ stopServer,
147
+ stopAllServers,
148
+ setupShutdownHandlers,
149
+ PID_PREFIX
150
+ };