@macpaw/cctk 1.0.0-beta.1

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 (415) hide show
  1. package/License +21 -0
  2. package/README.md +142 -0
  3. package/bin/index.js +5 -0
  4. package/dist/index.js +1 -0
  5. package/package.json +65 -0
  6. package/templates/claude/agents/brainstormer.md +113 -0
  7. package/templates/claude/agents/code-reviewer.md +157 -0
  8. package/templates/claude/agents/copywriter.md +110 -0
  9. package/templates/claude/agents/database-admin.md +92 -0
  10. package/templates/claude/agents/debugger.md +137 -0
  11. package/templates/claude/agents/docs-manager.md +208 -0
  12. package/templates/claude/agents/fullstack-developer.md +95 -0
  13. package/templates/claude/agents/git-manager.md +394 -0
  14. package/templates/claude/agents/journal-writer.md +113 -0
  15. package/templates/claude/agents/mcp-manager.md +89 -0
  16. package/templates/claude/agents/planner.md +108 -0
  17. package/templates/claude/agents/project-manager.md +125 -0
  18. package/templates/claude/agents/registry.json +304 -0
  19. package/templates/claude/agents/researcher.md +37 -0
  20. package/templates/claude/agents/scout-external.md +140 -0
  21. package/templates/claude/agents/scout.md +106 -0
  22. package/templates/claude/agents/tester.md +105 -0
  23. package/templates/claude/agents/ui-ux-designer.md +208 -0
  24. package/templates/claude/commands/ask.md +56 -0
  25. package/templates/claude/commands/bootstrap/auto/fast.md +106 -0
  26. package/templates/claude/commands/bootstrap/auto/parallel.md +64 -0
  27. package/templates/claude/commands/bootstrap/auto.md +110 -0
  28. package/templates/claude/commands/bootstrap.md +130 -0
  29. package/templates/claude/commands/brainstorm.md +75 -0
  30. package/templates/claude/commands/code/auto.md +198 -0
  31. package/templates/claude/commands/code/no-test.md +172 -0
  32. package/templates/claude/commands/code/parallel.md +100 -0
  33. package/templates/claude/commands/code.md +197 -0
  34. package/templates/claude/commands/coding-level.md +37 -0
  35. package/templates/claude/commands/content/cro.md +41 -0
  36. package/templates/claude/commands/content/enhance.md +12 -0
  37. package/templates/claude/commands/content/fast.md +11 -0
  38. package/templates/claude/commands/content/good.md +14 -0
  39. package/templates/claude/commands/cook/auto/fast.md +26 -0
  40. package/templates/claude/commands/cook/auto/parallel.md +49 -0
  41. package/templates/claude/commands/cook/auto.md +15 -0
  42. package/templates/claude/commands/cook.md +101 -0
  43. package/templates/claude/commands/debug.md +13 -0
  44. package/templates/claude/commands/docs/init.md +37 -0
  45. package/templates/claude/commands/docs/summarize.md +22 -0
  46. package/templates/claude/commands/docs/update.md +78 -0
  47. package/templates/claude/commands/fix/ci.md +17 -0
  48. package/templates/claude/commands/fix/fast.md +18 -0
  49. package/templates/claude/commands/fix/hard.md +35 -0
  50. package/templates/claude/commands/fix/logs.md +26 -0
  51. package/templates/claude/commands/fix/parallel.md +54 -0
  52. package/templates/claude/commands/fix/test.md +20 -0
  53. package/templates/claude/commands/fix/types.md +9 -0
  54. package/templates/claude/commands/fix/ui.md +33 -0
  55. package/templates/claude/commands/fix.md +43 -0
  56. package/templates/claude/commands/git/cm.md +5 -0
  57. package/templates/claude/commands/git/cp.md +4 -0
  58. package/templates/claude/commands/git/merge.md +40 -0
  59. package/templates/claude/commands/git/pr.md +50 -0
  60. package/templates/claude/commands/journal.md +7 -0
  61. package/templates/claude/commands/kanban.md +99 -0
  62. package/templates/claude/commands/plan/archive.md +57 -0
  63. package/templates/claude/commands/plan/ci.md +33 -0
  64. package/templates/claude/commands/plan/cro.md +67 -0
  65. package/templates/claude/commands/plan/fast.md +66 -0
  66. package/templates/claude/commands/plan/hard.md +92 -0
  67. package/templates/claude/commands/plan/parallel.md +129 -0
  68. package/templates/claude/commands/plan/two.md +45 -0
  69. package/templates/claude/commands/plan/validate.md +117 -0
  70. package/templates/claude/commands/plan.md +30 -0
  71. package/templates/claude/commands/preview.md +87 -0
  72. package/templates/claude/commands/registry.json +313 -0
  73. package/templates/claude/commands/review/codebase/parallel.md +122 -0
  74. package/templates/claude/commands/review/codebase.md +47 -0
  75. package/templates/claude/commands/scout/ext.md +35 -0
  76. package/templates/claude/commands/scout.md +28 -0
  77. package/templates/claude/commands/skill/add.md +36 -0
  78. package/templates/claude/commands/skill/create.md +29 -0
  79. package/templates/claude/commands/skill/fix-logs.md +22 -0
  80. package/templates/claude/commands/skill/optimize/auto.md +25 -0
  81. package/templates/claude/commands/skill/optimize.md +34 -0
  82. package/templates/claude/commands/skill/plan.md +45 -0
  83. package/templates/claude/commands/test/ui.md +91 -0
  84. package/templates/claude/commands/test.md +8 -0
  85. package/templates/claude/commands/use-mcp.md +34 -0
  86. package/templates/claude/commands/watzup.md +8 -0
  87. package/templates/claude/commands/worktree.md +126 -0
  88. package/templates/claude/hooks/dev-rules-reminder.cjs +258 -0
  89. package/templates/claude/hooks/docs/README.md +42 -0
  90. package/templates/claude/hooks/lib/cctk-config-utils.cjs +751 -0
  91. package/templates/claude/hooks/lib/cctk-paths.cjs +106 -0
  92. package/templates/claude/hooks/lib/context-tracker.cjs +346 -0
  93. package/templates/claude/hooks/privacy-block.cjs +289 -0
  94. package/templates/claude/hooks/registry.json +77 -0
  95. package/templates/claude/hooks/scout-block/broad-pattern-detector.cjs +293 -0
  96. package/templates/claude/hooks/scout-block/error-formatter.cjs +156 -0
  97. package/templates/claude/hooks/scout-block/path-extractor.cjs +359 -0
  98. package/templates/claude/hooks/scout-block/pattern-matcher.cjs +184 -0
  99. package/templates/claude/hooks/scout-block/vendor/ignore.js +626 -0
  100. package/templates/claude/hooks/scout-block.cjs +167 -0
  101. package/templates/claude/hooks/session-end.cjs +35 -0
  102. package/templates/claude/hooks/session-init.cjs +214 -0
  103. package/templates/claude/hooks/subagent-init.cjs +161 -0
  104. package/templates/claude/hooks/write-compact-marker.cjs +153 -0
  105. package/templates/claude/output-styles/coding-level-1.md +148 -0
  106. package/templates/claude/output-styles/coding-level-2.md +159 -0
  107. package/templates/claude/output-styles/coding-level-3.md +91 -0
  108. package/templates/claude/scripts/README.md +33 -0
  109. package/templates/claude/scripts/generate-catalogs.cjs +318 -0
  110. package/templates/claude/scripts/registry.json +48 -0
  111. package/templates/claude/scripts/set-active-plan.cjs +45 -0
  112. package/templates/claude/scripts/validate-docs.cjs +447 -0
  113. package/templates/claude/scripts/worktree.cjs +658 -0
  114. package/templates/claude/skills/README.md +112 -0
  115. package/templates/claude/skills/ai-artist/SKILL.md +75 -0
  116. package/templates/claude/skills/ai-artist/references/advanced-techniques.md +184 -0
  117. package/templates/claude/skills/ai-artist/references/domain-code.md +66 -0
  118. package/templates/claude/skills/ai-artist/references/domain-data.md +72 -0
  119. package/templates/claude/skills/ai-artist/references/domain-marketing.md +66 -0
  120. package/templates/claude/skills/ai-artist/references/domain-patterns.md +33 -0
  121. package/templates/claude/skills/ai-artist/references/domain-writing.md +68 -0
  122. package/templates/claude/skills/ai-artist/references/image-prompting.md +141 -0
  123. package/templates/claude/skills/ai-artist/references/llm-prompting.md +165 -0
  124. package/templates/claude/skills/ai-artist/references/nano-banana.md +59 -0
  125. package/templates/claude/skills/ai-artist/references/reasoning-techniques.md +201 -0
  126. package/templates/claude/skills/backend-development/SKILL.md +95 -0
  127. package/templates/claude/skills/backend-development/references/backend-api-design.md +495 -0
  128. package/templates/claude/skills/backend-development/references/backend-architecture.md +454 -0
  129. package/templates/claude/skills/backend-development/references/backend-authentication.md +338 -0
  130. package/templates/claude/skills/backend-development/references/backend-code-quality.md +659 -0
  131. package/templates/claude/skills/backend-development/references/backend-debugging.md +904 -0
  132. package/templates/claude/skills/backend-development/references/backend-devops.md +494 -0
  133. package/templates/claude/skills/backend-development/references/backend-mindset.md +387 -0
  134. package/templates/claude/skills/backend-development/references/backend-performance.md +397 -0
  135. package/templates/claude/skills/backend-development/references/backend-security.md +290 -0
  136. package/templates/claude/skills/backend-development/references/backend-technologies.md +256 -0
  137. package/templates/claude/skills/backend-development/references/backend-testing.md +429 -0
  138. package/templates/claude/skills/better-auth/SKILL.md +204 -0
  139. package/templates/claude/skills/better-auth/references/advanced-features.md +553 -0
  140. package/templates/claude/skills/better-auth/references/database-integration.md +577 -0
  141. package/templates/claude/skills/better-auth/references/email-password-auth.md +416 -0
  142. package/templates/claude/skills/better-auth/references/oauth-providers.md +430 -0
  143. package/templates/claude/skills/better-auth/scripts/better_auth_init.py +521 -0
  144. package/templates/claude/skills/chrome-devtools/SKILL.md +473 -0
  145. package/templates/claude/skills/chrome-devtools/references/cdp-domains.md +694 -0
  146. package/templates/claude/skills/chrome-devtools/references/performance-guide.md +940 -0
  147. package/templates/claude/skills/chrome-devtools/references/puppeteer-reference.md +953 -0
  148. package/templates/claude/skills/chrome-devtools/scripts/README.md +288 -0
  149. package/templates/claude/skills/chrome-devtools/scripts/aria-snapshot.js +368 -0
  150. package/templates/claude/skills/chrome-devtools/scripts/click.js +92 -0
  151. package/templates/claude/skills/chrome-devtools/scripts/console.js +85 -0
  152. package/templates/claude/skills/chrome-devtools/scripts/evaluate.js +59 -0
  153. package/templates/claude/skills/chrome-devtools/scripts/fill.js +84 -0
  154. package/templates/claude/skills/chrome-devtools/scripts/inject-auth.js +247 -0
  155. package/templates/claude/skills/chrome-devtools/scripts/install-deps.sh +11 -0
  156. package/templates/claude/skills/chrome-devtools/scripts/install.sh +36 -0
  157. package/templates/claude/skills/chrome-devtools/scripts/lib/browser.js +335 -0
  158. package/templates/claude/skills/chrome-devtools/scripts/lib/selector.js +183 -0
  159. package/templates/claude/skills/chrome-devtools/scripts/navigate.js +60 -0
  160. package/templates/claude/skills/chrome-devtools/scripts/network.js +113 -0
  161. package/templates/claude/skills/chrome-devtools/scripts/package.json +16 -0
  162. package/templates/claude/skills/chrome-devtools/scripts/performance.js +159 -0
  163. package/templates/claude/skills/chrome-devtools/scripts/screenshot.js +212 -0
  164. package/templates/claude/skills/chrome-devtools/scripts/select-ref.js +151 -0
  165. package/templates/claude/skills/chrome-devtools/scripts/snapshot.js +143 -0
  166. package/templates/claude/skills/chrome-devtools/scripts/ws-debug.js +47 -0
  167. package/templates/claude/skills/chrome-devtools/scripts/ws-full-debug.js +115 -0
  168. package/templates/claude/skills/claude-code/references/advanced-features.md +399 -0
  169. package/templates/claude/skills/claude-code/references/agent-skills.md +399 -0
  170. package/templates/claude/skills/claude-code/references/api-reference.md +498 -0
  171. package/templates/claude/skills/claude-code/references/best-practices.md +447 -0
  172. package/templates/claude/skills/claude-code/references/cicd-integration.md +428 -0
  173. package/templates/claude/skills/claude-code/references/common-workflows.md +107 -0
  174. package/templates/claude/skills/claude-code/references/configuration.md +480 -0
  175. package/templates/claude/skills/claude-code/references/enterprise-features.md +472 -0
  176. package/templates/claude/skills/claude-code/references/getting-started.md +244 -0
  177. package/templates/claude/skills/claude-code/references/hooks-and-plugins.md +444 -0
  178. package/templates/claude/skills/claude-code/references/hooks-comprehensive.md +622 -0
  179. package/templates/claude/skills/claude-code/references/ide-integration.md +316 -0
  180. package/templates/claude/skills/claude-code/references/mcp-integration.md +386 -0
  181. package/templates/claude/skills/claude-code/references/slash-commands.md +460 -0
  182. package/templates/claude/skills/claude-code/references/troubleshooting.md +455 -0
  183. package/templates/claude/skills/claude-code/skill.md +60 -0
  184. package/templates/claude/skills/code-review/SKILL.md +143 -0
  185. package/templates/claude/skills/code-review/references/code-review-reception.md +209 -0
  186. package/templates/claude/skills/code-review/references/requesting-code-review.md +105 -0
  187. package/templates/claude/skills/code-review/references/verification-before-completion.md +139 -0
  188. package/templates/claude/skills/context-engineering/SKILL.md +86 -0
  189. package/templates/claude/skills/context-engineering/references/context-compression.md +84 -0
  190. package/templates/claude/skills/context-engineering/references/context-degradation.md +93 -0
  191. package/templates/claude/skills/context-engineering/references/context-fundamentals.md +75 -0
  192. package/templates/claude/skills/context-engineering/references/context-optimization.md +82 -0
  193. package/templates/claude/skills/context-engineering/references/evaluation.md +89 -0
  194. package/templates/claude/skills/context-engineering/references/memory-systems.md +88 -0
  195. package/templates/claude/skills/context-engineering/references/multi-agent-patterns.md +90 -0
  196. package/templates/claude/skills/context-engineering/references/project-development.md +97 -0
  197. package/templates/claude/skills/context-engineering/references/tool-design.md +86 -0
  198. package/templates/claude/skills/context-engineering/scripts/compression_evaluator.py +329 -0
  199. package/templates/claude/skills/context-engineering/scripts/context_analyzer.py +294 -0
  200. package/templates/claude/skills/databases/SKILL.md +232 -0
  201. package/templates/claude/skills/databases/references/mongodb-aggregation.md +447 -0
  202. package/templates/claude/skills/databases/references/mongodb-atlas.md +465 -0
  203. package/templates/claude/skills/databases/references/mongodb-crud.md +408 -0
  204. package/templates/claude/skills/databases/references/mongodb-indexing.md +442 -0
  205. package/templates/claude/skills/databases/references/postgresql-administration.md +594 -0
  206. package/templates/claude/skills/databases/references/postgresql-performance.md +527 -0
  207. package/templates/claude/skills/databases/references/postgresql-psql-cli.md +467 -0
  208. package/templates/claude/skills/databases/references/postgresql-queries.md +475 -0
  209. package/templates/claude/skills/databases/scripts/db_backup.py +502 -0
  210. package/templates/claude/skills/databases/scripts/db_migrate.py +414 -0
  211. package/templates/claude/skills/databases/scripts/db_performance_check.py +445 -0
  212. package/templates/claude/skills/debugging/SKILL.md +84 -0
  213. package/templates/claude/skills/debugging/references/defense-in-depth.md +124 -0
  214. package/templates/claude/skills/debugging/references/root-cause-tracing.md +122 -0
  215. package/templates/claude/skills/debugging/references/systematic-debugging.md +102 -0
  216. package/templates/claude/skills/debugging/references/verification.md +123 -0
  217. package/templates/claude/skills/debugging/scripts/find-polluter.sh +63 -0
  218. package/templates/claude/skills/debugging/scripts/find-polluter.test.md +102 -0
  219. package/templates/claude/skills/devops/SKILL.md +293 -0
  220. package/templates/claude/skills/devops/references/browser-rendering.md +305 -0
  221. package/templates/claude/skills/devops/references/cloudflare-d1-kv.md +123 -0
  222. package/templates/claude/skills/devops/references/cloudflare-platform.md +271 -0
  223. package/templates/claude/skills/devops/references/cloudflare-r2-storage.md +280 -0
  224. package/templates/claude/skills/devops/references/cloudflare-workers-advanced.md +312 -0
  225. package/templates/claude/skills/devops/references/cloudflare-workers-apis.md +309 -0
  226. package/templates/claude/skills/devops/references/cloudflare-workers-basics.md +418 -0
  227. package/templates/claude/skills/devops/references/docker-basics.md +297 -0
  228. package/templates/claude/skills/devops/references/docker-compose.md +292 -0
  229. package/templates/claude/skills/devops/references/gcloud-platform.md +307 -0
  230. package/templates/claude/skills/devops/references/gcloud-services.md +304 -0
  231. package/templates/claude/skills/devops/scripts/cloudflare_deploy.py +269 -0
  232. package/templates/claude/skills/devops/scripts/docker_optimize.py +320 -0
  233. package/templates/claude/skills/docs-seeker/SKILL.md +95 -0
  234. package/templates/claude/skills/docs-seeker/package.json +24 -0
  235. package/templates/claude/skills/docs-seeker/references/advanced.md +78 -0
  236. package/templates/claude/skills/docs-seeker/references/context7-patterns.md +68 -0
  237. package/templates/claude/skills/docs-seeker/references/errors.md +68 -0
  238. package/templates/claude/skills/docs-seeker/scripts/analyze-llms-txt.js +245 -0
  239. package/templates/claude/skills/docs-seeker/scripts/detect-topic.js +172 -0
  240. package/templates/claude/skills/docs-seeker/scripts/fetch-docs.js +212 -0
  241. package/templates/claude/skills/docs-seeker/workflows/library-search.md +87 -0
  242. package/templates/claude/skills/docs-seeker/workflows/repo-analysis.md +91 -0
  243. package/templates/claude/skills/docs-seeker/workflows/topic-search.md +77 -0
  244. package/templates/claude/skills/frontend-design/SKILL.md +85 -0
  245. package/templates/claude/skills/frontend-design/references/analysis-best-practices.md +80 -0
  246. package/templates/claude/skills/frontend-design/references/analysis-prompts.md +141 -0
  247. package/templates/claude/skills/frontend-design/references/analysis-techniques.md +118 -0
  248. package/templates/claude/skills/frontend-design/references/animejs.md +396 -0
  249. package/templates/claude/skills/frontend-design/references/design-extraction-overview.md +71 -0
  250. package/templates/claude/skills/frontend-design/references/extraction-best-practices.md +141 -0
  251. package/templates/claude/skills/frontend-design/references/extraction-output-templates.md +162 -0
  252. package/templates/claude/skills/frontend-design/references/extraction-prompts.md +127 -0
  253. package/templates/claude/skills/frontend-design/references/technical-accessibility.md +119 -0
  254. package/templates/claude/skills/frontend-design/references/technical-best-practices.md +97 -0
  255. package/templates/claude/skills/frontend-design/references/technical-optimization.md +44 -0
  256. package/templates/claude/skills/frontend-design/references/technical-overview.md +90 -0
  257. package/templates/claude/skills/frontend-design/references/technical-workflows.md +150 -0
  258. package/templates/claude/skills/frontend-design/references/visual-analysis-overview.md +95 -0
  259. package/templates/claude/skills/frontend-development/SKILL.md +399 -0
  260. package/templates/claude/skills/frontend-development/resources/common-patterns.md +331 -0
  261. package/templates/claude/skills/frontend-development/resources/complete-examples.md +872 -0
  262. package/templates/claude/skills/frontend-development/resources/component-patterns.md +502 -0
  263. package/templates/claude/skills/frontend-development/resources/data-fetching.md +767 -0
  264. package/templates/claude/skills/frontend-development/resources/file-organization.md +502 -0
  265. package/templates/claude/skills/frontend-development/resources/loading-and-error-states.md +501 -0
  266. package/templates/claude/skills/frontend-development/resources/performance.md +406 -0
  267. package/templates/claude/skills/frontend-development/resources/routing-guide.md +364 -0
  268. package/templates/claude/skills/frontend-development/resources/styling-guide.md +428 -0
  269. package/templates/claude/skills/frontend-development/resources/typescript-standards.md +418 -0
  270. package/templates/claude/skills/markdown-novel-viewer/SKILL.md +272 -0
  271. package/templates/claude/skills/markdown-novel-viewer/assets/directory-browser.css +215 -0
  272. package/templates/claude/skills/markdown-novel-viewer/assets/favicon.png +0 -0
  273. package/templates/claude/skills/markdown-novel-viewer/assets/novel-theme.css +872 -0
  274. package/templates/claude/skills/markdown-novel-viewer/assets/reader.js +378 -0
  275. package/templates/claude/skills/markdown-novel-viewer/assets/template.html +85 -0
  276. package/templates/claude/skills/markdown-novel-viewer/package.json +15 -0
  277. package/templates/claude/skills/markdown-novel-viewer/scripts/lib/http-server.cjs +434 -0
  278. package/templates/claude/skills/markdown-novel-viewer/scripts/lib/markdown-renderer.cjs +335 -0
  279. package/templates/claude/skills/markdown-novel-viewer/scripts/lib/plan-navigator.cjs +509 -0
  280. package/templates/claude/skills/markdown-novel-viewer/scripts/lib/port-finder.cjs +49 -0
  281. package/templates/claude/skills/markdown-novel-viewer/scripts/lib/process-mgr.cjs +150 -0
  282. package/templates/claude/skills/markdown-novel-viewer/scripts/server.cjs +398 -0
  283. package/templates/claude/skills/mcp-builder/SKILL.md +328 -0
  284. package/templates/claude/skills/mcp-builder/reference/evaluation.md +602 -0
  285. package/templates/claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
  286. package/templates/claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
  287. package/templates/claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
  288. package/templates/claude/skills/mcp-builder/scripts/connections.py +151 -0
  289. package/templates/claude/skills/mcp-builder/scripts/evaluation.py +381 -0
  290. package/templates/claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  291. package/templates/claude/skills/mcp-builder/scripts/requirements.txt +2 -0
  292. package/templates/claude/skills/mcp-management/README.md +219 -0
  293. package/templates/claude/skills/mcp-management/SKILL.md +209 -0
  294. package/templates/claude/skills/mcp-management/assets/tools.json +3146 -0
  295. package/templates/claude/skills/mcp-management/references/configuration.md +114 -0
  296. package/templates/claude/skills/mcp-management/references/gemini-cli-integration.md +209 -0
  297. package/templates/claude/skills/mcp-management/references/mcp-protocol.md +116 -0
  298. package/templates/claude/skills/mcp-management/scripts/.env.example +10 -0
  299. package/templates/claude/skills/mcp-management/scripts/cli.ts +202 -0
  300. package/templates/claude/skills/mcp-management/scripts/mcp-client.ts +247 -0
  301. package/templates/claude/skills/mcp-management/scripts/package.json +20 -0
  302. package/templates/claude/skills/mcp-management/scripts/tsconfig.json +15 -0
  303. package/templates/claude/skills/media-processing/SKILL.md +91 -0
  304. package/templates/claude/skills/media-processing/references/common-workflows.md +132 -0
  305. package/templates/claude/skills/media-processing/references/ffmpeg-encoding.md +358 -0
  306. package/templates/claude/skills/media-processing/references/ffmpeg-filters.md +503 -0
  307. package/templates/claude/skills/media-processing/references/ffmpeg-streaming.md +395 -0
  308. package/templates/claude/skills/media-processing/references/format-compatibility.md +375 -0
  309. package/templates/claude/skills/media-processing/references/imagemagick-batch.md +612 -0
  310. package/templates/claude/skills/media-processing/references/imagemagick-editing.md +623 -0
  311. package/templates/claude/skills/media-processing/references/rmbg-background-removal.md +66 -0
  312. package/templates/claude/skills/media-processing/references/troubleshooting.md +109 -0
  313. package/templates/claude/skills/media-processing/scripts/README.md +102 -0
  314. package/templates/claude/skills/media-processing/scripts/batch-remove-background.sh +124 -0
  315. package/templates/claude/skills/media-processing/scripts/batch_resize.py +342 -0
  316. package/templates/claude/skills/media-processing/scripts/media_convert.py +311 -0
  317. package/templates/claude/skills/media-processing/scripts/remove-background.sh +96 -0
  318. package/templates/claude/skills/media-processing/scripts/remove-bg-node.js +181 -0
  319. package/templates/claude/skills/mermaidjs-v11/SKILL.md +115 -0
  320. package/templates/claude/skills/mermaidjs-v11/references/cli-usage.md +228 -0
  321. package/templates/claude/skills/mermaidjs-v11/references/configuration.md +232 -0
  322. package/templates/claude/skills/mermaidjs-v11/references/diagram-types.md +315 -0
  323. package/templates/claude/skills/mermaidjs-v11/references/examples.md +344 -0
  324. package/templates/claude/skills/mermaidjs-v11/references/integration.md +310 -0
  325. package/templates/claude/skills/planning/SKILL.md +115 -0
  326. package/templates/claude/skills/planning/references/codebase-understanding.md +62 -0
  327. package/templates/claude/skills/planning/references/output-standards.md +127 -0
  328. package/templates/claude/skills/planning/references/plan-organization.md +150 -0
  329. package/templates/claude/skills/planning/references/research-phase.md +49 -0
  330. package/templates/claude/skills/planning/references/solution-design.md +63 -0
  331. package/templates/claude/skills/plans-kanban/SKILL.md +157 -0
  332. package/templates/claude/skills/plans-kanban/assets/dashboard-template.html +119 -0
  333. package/templates/claude/skills/plans-kanban/assets/dashboard.css +1594 -0
  334. package/templates/claude/skills/plans-kanban/assets/dashboard.js +659 -0
  335. package/templates/claude/skills/plans-kanban/assets/favicon.png +0 -0
  336. package/templates/claude/skills/plans-kanban/package.json +13 -0
  337. package/templates/claude/skills/plans-kanban/scripts/lib/dashboard-renderer.cjs +941 -0
  338. package/templates/claude/skills/plans-kanban/scripts/lib/http-server.cjs +310 -0
  339. package/templates/claude/skills/plans-kanban/scripts/lib/plan-metadata-extractor.cjs +489 -0
  340. package/templates/claude/skills/plans-kanban/scripts/lib/plan-parser.cjs +194 -0
  341. package/templates/claude/skills/plans-kanban/scripts/lib/plan-scanner.cjs +277 -0
  342. package/templates/claude/skills/plans-kanban/scripts/lib/port-finder.cjs +49 -0
  343. package/templates/claude/skills/plans-kanban/scripts/lib/process-mgr.cjs +128 -0
  344. package/templates/claude/skills/plans-kanban/scripts/server.cjs +249 -0
  345. package/templates/claude/skills/problem-solving/SKILL.md +96 -0
  346. package/templates/claude/skills/problem-solving/references/attribution.md +69 -0
  347. package/templates/claude/skills/problem-solving/references/collision-zone-thinking.md +79 -0
  348. package/templates/claude/skills/problem-solving/references/inversion-exercise.md +91 -0
  349. package/templates/claude/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
  350. package/templates/claude/skills/problem-solving/references/scale-game.md +95 -0
  351. package/templates/claude/skills/problem-solving/references/simplification-cascades.md +80 -0
  352. package/templates/claude/skills/problem-solving/references/when-stuck.md +72 -0
  353. package/templates/claude/skills/registry.json +258 -0
  354. package/templates/claude/skills/repomix/SKILL.md +247 -0
  355. package/templates/claude/skills/repomix/references/configuration.md +211 -0
  356. package/templates/claude/skills/repomix/references/usage-patterns.md +232 -0
  357. package/templates/claude/skills/repomix/scripts/README.md +179 -0
  358. package/templates/claude/skills/repomix/scripts/repomix_batch.py +455 -0
  359. package/templates/claude/skills/repomix/scripts/repos.example.json +15 -0
  360. package/templates/claude/skills/research/SKILL.md +168 -0
  361. package/templates/claude/skills/sequential-thinking/.env.example +8 -0
  362. package/templates/claude/skills/sequential-thinking/README.md +183 -0
  363. package/templates/claude/skills/sequential-thinking/SKILL.md +94 -0
  364. package/templates/claude/skills/sequential-thinking/package.json +31 -0
  365. package/templates/claude/skills/sequential-thinking/references/advanced-strategies.md +79 -0
  366. package/templates/claude/skills/sequential-thinking/references/advanced-techniques.md +76 -0
  367. package/templates/claude/skills/sequential-thinking/references/core-patterns.md +95 -0
  368. package/templates/claude/skills/sequential-thinking/references/examples-api.md +88 -0
  369. package/templates/claude/skills/sequential-thinking/references/examples-architecture.md +94 -0
  370. package/templates/claude/skills/sequential-thinking/references/examples-debug.md +90 -0
  371. package/templates/claude/skills/sequential-thinking/scripts/format-thought.js +182 -0
  372. package/templates/claude/skills/sequential-thinking/scripts/process-thought.js +252 -0
  373. package/templates/claude/skills/skill-creator/LICENSE.txt +202 -0
  374. package/templates/claude/skills/skill-creator/SKILL.md +266 -0
  375. package/templates/claude/skills/skill-creator/references/agent-skills-spec.md +51 -0
  376. package/templates/claude/skills/skill-creator/scripts/encoding_utils.py +21 -0
  377. package/templates/claude/skills/skill-creator/scripts/init_skill.py +304 -0
  378. package/templates/claude/skills/skill-creator/scripts/package_skill.py +110 -0
  379. package/templates/claude/skills/skill-creator/scripts/quick_validate.py +66 -0
  380. package/templates/claude/skills/template-skill/SKILL.md +6 -0
  381. package/templates/claude/skills/vitest/SKILL.md +595 -0
  382. package/templates/claude/skills/vitest/references/async-patterns.md +82 -0
  383. package/templates/claude/skills/vitest/references/mock-patterns.md +78 -0
  384. package/templates/claude/skills/vitest/references/monorepo-setup.md +185 -0
  385. package/templates/claude/skills/vitest/references/turborepo-setup.md +332 -0
  386. package/templates/claude/skills/web-frameworks/SKILL.md +324 -0
  387. package/templates/claude/skills/web-frameworks/references/nextjs-app-router.md +465 -0
  388. package/templates/claude/skills/web-frameworks/references/nextjs-data-fetching.md +459 -0
  389. package/templates/claude/skills/web-frameworks/references/nextjs-optimization.md +511 -0
  390. package/templates/claude/skills/web-frameworks/references/nextjs-server-components.md +495 -0
  391. package/templates/claude/skills/web-frameworks/references/remix-icon-integration.md +603 -0
  392. package/templates/claude/skills/web-frameworks/references/turborepo-caching.md +551 -0
  393. package/templates/claude/skills/web-frameworks/references/turborepo-pipelines.md +517 -0
  394. package/templates/claude/skills/web-frameworks/references/turborepo-setup.md +542 -0
  395. package/templates/claude/skills/web-frameworks/scripts/nextjs_init.py +547 -0
  396. package/templates/claude/skills/web-frameworks/scripts/turborepo_migrate.py +394 -0
  397. package/templates/claude/workflows/development-rules.md +40 -0
  398. package/templates/claude/workflows/documentation-management.md +121 -0
  399. package/templates/claude/workflows/orchestration-protocol.md +16 -0
  400. package/templates/claude/workflows/primary-workflow.md +45 -0
  401. package/templates/claude/workflows/registry.json +37 -0
  402. package/templates/common/.cct.json +41 -0
  403. package/templates/common/.cctkignore +22 -0
  404. package/templates/common/.env.example +39 -0
  405. package/templates/common/.mcp.json.example +16 -0
  406. package/templates/common/metadata.json +15 -0
  407. package/templates/common/settings.json +79 -0
  408. package/templates/common/statusline.cjs +271 -0
  409. package/templates/config/.repomixignore +22 -0
  410. package/templates/config/AGENTS.md +55 -0
  411. package/templates/config/CLAUDE.md +87 -0
  412. package/templates/plans/bug-fix-template.md +69 -0
  413. package/templates/plans/feature-implementation-template.md +84 -0
  414. package/templates/plans/refactor-template.md +82 -0
  415. package/templates/plans/template-usage-guide.md +58 -0
@@ -0,0 +1,941 @@
1
+ /**
2
+ * Dashboard Renderer
3
+ * Generates HTML for the enhanced plans dashboard view with glassmorphism design
4
+ *
5
+ * @module dashboard-renderer
6
+ */
7
+
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+ const { generateTimelineStats, generateActivityHeatmap } = require('./plan-metadata-extractor.cjs');
11
+
12
+ /**
13
+ * Escape HTML special characters to prevent XSS
14
+ * @param {string} str - String to escape
15
+ * @returns {string} - Escaped string
16
+ */
17
+ function escapeHtml(str) {
18
+ if (!str) return '';
19
+
20
+
21
+ return String(str)
22
+ .replaceAll('&', '&')
23
+ .replaceAll('<', '&lt;')
24
+ .replaceAll('>', '&gt;')
25
+ .replaceAll('"', '&quot;')
26
+ .replaceAll('\'', '&#039;');
27
+ }
28
+
29
+ /**
30
+ * Truncate text to specified length with ellipsis
31
+ * @param {string} text - Text to truncate
32
+ * @param {number} maxLen - Maximum length
33
+ * @returns {string} - Truncated text
34
+ */
35
+ function truncate(text, maxLen = 100) {
36
+ if (!text) return '';
37
+ if (text.length <= maxLen) return text;
38
+
39
+
40
+ return `${text.slice(0, maxLen - 3).trim() }...`;
41
+ }
42
+
43
+ /**
44
+ * Get priority color class based on priority level
45
+ * @param {string} priority - Priority string (P1/P2/P3 or High/Medium/Low)
46
+ * @returns {string} - CSS class name
47
+ */
48
+ function getPriorityColorClass(priority) {
49
+ if (!priority) return '';
50
+ const p = String(priority).toUpperCase();
51
+
52
+
53
+ if (p === 'P1' || p === 'HIGH' || p === 'CRITICAL') return 'priority-high';
54
+ if (p === 'P2' || p === 'MEDIUM' || p === 'NORMAL') return 'priority-medium';
55
+ if (p === 'P3' || p === 'LOW') return 'priority-low';
56
+
57
+
58
+ return '';
59
+ }
60
+
61
+ /**
62
+ * Format date for display
63
+ * @param {string} isoDate - ISO date string
64
+ * @returns {string} - Formatted date
65
+ */
66
+ function formatDate(isoDate) {
67
+ if (!isoDate) return '';
68
+ const date = new Date(isoDate);
69
+
70
+
71
+
72
+ return date.toLocaleDateString('en-US', {
73
+ month: 'short',
74
+ day: 'numeric',
75
+ year: 'numeric',
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Format relative time (e.g., "2 days ago")
81
+ * @param {string} isoDate - ISO date string
82
+ * @returns {string} - Relative time string
83
+ */
84
+ function formatRelativeTime(isoDate) {
85
+ if (!isoDate) return '';
86
+ const date = new Date(isoDate);
87
+ const now = new Date();
88
+ const diffMs = now - date;
89
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
90
+
91
+ if (diffDays === 0) return 'Today';
92
+ if (diffDays === 1) return 'Yesterday';
93
+ if (diffDays < 7) return `${diffDays} days ago`;
94
+ if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
95
+ if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
96
+
97
+
98
+ return `${Math.floor(diffDays / 365)} years ago`;
99
+ }
100
+
101
+ /**
102
+ * Get human-readable status label
103
+ * @param {string} status - Status code
104
+ * @returns {string} - Human-readable label
105
+ */
106
+ function getStatusLabel(status) {
107
+ const labels = {
108
+ completed: 'Completed',
109
+ complete: 'Completed',
110
+ 'in-progress': 'In Progress',
111
+ 'in-review': 'In Review',
112
+ cancelled: 'Cancelled',
113
+ pending: 'Pending',
114
+ };
115
+
116
+
117
+
118
+ return labels[status] || 'Pending';
119
+ }
120
+
121
+ /**
122
+ * Generate SVG progress ring (kept for backward compatibility but hidden in new design)
123
+ * @param {number} progress - Progress percentage (0-100)
124
+ * @returns {string} - SVG HTML
125
+ */
126
+ function generateProgressRing(progress) {
127
+ // Hidden in new minimal design - kept for compatibility
128
+ return '';
129
+ }
130
+
131
+ /**
132
+ * Generate simple progress bar (monochrome design)
133
+ * @param {{total: number, completed: number, inProgress: number, pending: number}} phases
134
+ * @returns {string} - Progress bar HTML
135
+ */
136
+ function generateProgressBar(phases) {
137
+ const total = phases.total || 1;
138
+ const completedPct = ((phases.completed / total) * 100).toFixed(1);
139
+ const inProgressPct = ((phases.inProgress / total) * 100).toFixed(1);
140
+
141
+ return `
142
+ <div class="progress-bar" role="progressbar"
143
+ aria-valuenow="${phases.completed}" aria-valuemin="0" aria-valuemax="${total}"
144
+ aria-label="Progress: ${phases.completed} of ${total} phases completed">
145
+ <div class="bar-segment completed" style="width: ${completedPct}%"></div>
146
+ <div class="bar-segment in-progress" style="width: ${inProgressPct}%"></div>
147
+ </div>
148
+ <div class="phase-count"><strong>${phases.completed}</strong> of ${total} phases</div>
149
+ `;
150
+ }
151
+
152
+ /**
153
+ * Generate status counts HTML (hidden in minimal design)
154
+ * @param {{completed: number, inProgress: number, pending: number}} phases
155
+ * @returns {string} - Status counts HTML
156
+ */
157
+ function generateStatusCounts(phases) {
158
+ // Hidden in minimal design
159
+ return '';
160
+ }
161
+
162
+ /**
163
+ * Generate status badge HTML (simplified for monochrome design)
164
+ * @param {string} status - Status string
165
+ * @returns {string} - Status badge HTML
166
+ */
167
+ function generateStatusBadge(status) {
168
+ const statusClass = (status || 'pending').replaceAll(/\s+/g, '-');
169
+ // Simplified labels for minimal design
170
+ const labels = {
171
+ completed: 'Done',
172
+ complete: 'Done',
173
+ 'in-progress': 'Active',
174
+ pending: 'Pending',
175
+ };
176
+ const label = labels[statusClass] || 'Pending';
177
+
178
+
179
+
180
+ return `<span class="status-badge ${statusClass}">${label}</span>`;
181
+ }
182
+
183
+ /**
184
+ * Generate meta tags HTML for plan card (duration, effort, priority, issue, tags)
185
+ * @param {Object} plan - Plan metadata
186
+ * @returns {string} - Meta tags HTML
187
+ */
188
+ function generateCardMeta(plan) {
189
+ const metaTags = [];
190
+
191
+ // Duration tag
192
+ if (plan.durationFormatted) {
193
+ const icon =
194
+ '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>';
195
+
196
+
197
+ metaTags.push(
198
+ `<span class="meta-tag duration" title="Duration">${icon} ${escapeHtml(plan.durationFormatted)}</span>`,
199
+ );
200
+ }
201
+
202
+ // Effort tag
203
+ if (plan.totalEffortFormatted) {
204
+ metaTags.push(
205
+ `<span class="meta-tag effort" title="Estimated effort"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> ${escapeHtml(plan.totalEffortFormatted)}</span>`,
206
+ );
207
+ }
208
+
209
+ // Priority tag with color class
210
+ if (plan.priority) {
211
+ const priorityColorClass = getPriorityColorClass(plan.priority);
212
+
213
+
214
+ metaTags.push(
215
+ `<span class="meta-tag priority ${priorityColorClass}" title="Priority">${escapeHtml(plan.priority)}</span>`,
216
+ );
217
+ }
218
+
219
+ if (metaTags.length === 0) return '';
220
+
221
+
222
+ return `<div class="card-meta">${metaTags.join('')}</div>`;
223
+ }
224
+
225
+ /**
226
+ * Generate tags pills HTML
227
+ * @param {Array<string>} tags - Array of tag strings
228
+ * @param {number} maxVisible - Maximum visible tags (default 3)
229
+ * @returns {string} - Tags HTML
230
+ */
231
+ function generateTagsPills(tags, maxVisible = 3) {
232
+ if (!tags || !Array.isArray(tags) || tags.length === 0) return '';
233
+
234
+ const visibleTags = tags.slice(0, maxVisible);
235
+ const hiddenCount = tags.length - maxVisible;
236
+
237
+ let html = '<div class="card-tags">';
238
+
239
+
240
+ html += visibleTags.map((tag) => `<span class="tag-pill">${escapeHtml(tag)}</span>`).join('');
241
+
242
+ if (hiddenCount > 0) {
243
+ html += `<span class="tag-pill tag-more">+${hiddenCount}</span>`;
244
+ }
245
+ html += '</div>';
246
+
247
+ return html;
248
+ }
249
+
250
+ /**
251
+ * Generate HTML for a single plan card (minimal design with rich metadata)
252
+ * @param {Object} plan - Plan metadata
253
+ * @returns {string} - Card HTML
254
+ */
255
+ function generatePlanCard(plan) {
256
+ const statusClass = (plan.status || 'pending').replaceAll(/\s+/g, '-');
257
+ const name = escapeHtml(plan.name);
258
+ const relativeTime = formatRelativeTime(plan.lastModified);
259
+ const cardMeta = generateCardMeta(plan);
260
+
261
+ // Description section (truncated)
262
+ const descriptionHtml = plan.description
263
+ ? `<p class="card-description">${escapeHtml(truncate(plan.description, 100))}</p>`
264
+ : '';
265
+
266
+ // Tags pills
267
+ const tagsHtml = generateTagsPills(plan.tags);
268
+
269
+ return `
270
+ <article class="plan-card" data-status="${statusClass}" data-id="${escapeHtml(plan.id)}" tabindex="0"
271
+ data-created="${plan.createdDate || ''}" data-duration="${plan.durationDays || 0}"
272
+ data-effort="${plan.totalEffortHours || 0}" data-priority="${plan.priority || ''}">
273
+ <header class="card-header">
274
+ <div class="card-header-content">
275
+ <h2 class="plan-name">${name}</h2>
276
+ <div class="plan-date">
277
+ <time datetime="${plan.lastModified}">${relativeTime}</time>
278
+ </div>
279
+ </div>
280
+ ${generateStatusBadge(statusClass)}
281
+ </header>
282
+ <div class="card-body">
283
+ ${descriptionHtml}
284
+ ${generateProgressBar(plan.phases)}
285
+ ${cardMeta}
286
+ ${tagsHtml}
287
+ </div>
288
+ <footer class="card-footer">
289
+ <div class="phases-summary">${plan.phases.total} phases total</div>
290
+ <a href="/view?file=${encodeURIComponent(plan.path)}" class="view-btn">
291
+ View
292
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
293
+ <path d="M5 12h14M12 5l7 7-7 7"/>
294
+ </svg>
295
+ </a>
296
+ </footer>
297
+ </article>
298
+ `;
299
+ }
300
+
301
+ /**
302
+ * Auto-stack plans into layers to avoid overlap (like Google Calendar)
303
+ * Uses actual plan duration for in-progress items instead of extending to today
304
+ * @param {Array} plans - Plans with createdDate and durationDays
305
+ * @param {Date} rangeStart - Start of visible range
306
+ * @param {Date} rangeEnd - End of visible range
307
+ * @returns {Array} - Plans with layer assignments
308
+ */
309
+ function assignLayers(plans, rangeStart, rangeEnd) {
310
+ const rangeDays = Math.ceil((rangeEnd - rangeStart) / (1000 * 60 * 60 * 24));
311
+ const now = new Date();
312
+ const layers = []; // Each layer tracks occupied day ranges
313
+
314
+ // Filter to plans with dates, then sort by start date
315
+ const sorted = [...plans]
316
+ .filter((p) => p.createdDate)
317
+ .sort((a, b) => new Date(a.createdDate) - new Date(b.createdDate));
318
+
319
+ // Filter to plans within visible range
320
+ const visible = sorted.filter((plan) => {
321
+ const startDate = new Date(plan.createdDate);
322
+ const endDate = plan.completedDate
323
+ ? new Date(plan.completedDate)
324
+ : new Date(startDate.getTime() + (plan.durationDays || 1) * 24 * 60 * 60 * 1000);
325
+
326
+
327
+
328
+ return endDate >= rangeStart && startDate <= rangeEnd;
329
+ });
330
+
331
+ return visible.map((plan) => {
332
+ const startDate = new Date(plan.createdDate);
333
+ // Determine end date based on status
334
+ let endDate;
335
+
336
+
337
+ if (plan.completedDate) {
338
+ endDate = new Date(plan.completedDate);
339
+ } else if (plan.status === 'completed') {
340
+ // Completed without explicit date: use lastModified or cap at today
341
+ endDate = plan.lastModified ? new Date(plan.lastModified) : now;
342
+ } else {
343
+ // In-progress/pending: use duration from start
344
+ endDate = new Date(startDate.getTime() + Math.max(1, plan.durationDays || 1) * 24 * 60 * 60 * 1000);
345
+ }
346
+ // Completed plans can't extend past today
347
+ if (plan.status === 'completed' && endDate > now) {
348
+ endDate = now;
349
+ }
350
+
351
+ // Calculate position as percentage (clamp to range)
352
+ const startDay = Math.max(0, Math.ceil((startDate - rangeStart) / (1000 * 60 * 60 * 24)));
353
+ const endDay = Math.min(rangeDays, Math.ceil((endDate - rangeStart) / (1000 * 60 * 60 * 24)));
354
+
355
+ // Ensure minimum visible width (2 days)
356
+ const adjustedEndDay = Math.max(startDay + 2, endDay);
357
+ const leftPct = (startDay / rangeDays) * 100;
358
+ const widthPct = Math.min(100 - leftPct, Math.max(4, ((adjustedEndDay - startDay) / rangeDays) * 100));
359
+
360
+ // Find first layer without overlap (greedy algorithm)
361
+ let layer = 0;
362
+ let foundSlot = false;
363
+
364
+
365
+ for (const [i, layer_] of layers.entries()) {
366
+ const hasOverlap = layer_.some((range) => !(adjustedEndDay <= range.start || startDay >= range.end));
367
+
368
+
369
+ if (!hasOverlap) {
370
+ layer = i;
371
+ foundSlot = true;
372
+ break;
373
+ }
374
+ }
375
+ if (!foundSlot) {
376
+ layer = layers.length;
377
+ }
378
+
379
+ // Add to layer
380
+ if (!layers[layer]) layers[layer] = [];
381
+ layers[layer].push({ start: startDay, end: adjustedEndDay });
382
+
383
+ return { ...plan, layer, leftPct, widthPct, startDay, endDay: adjustedEndDay };
384
+ });
385
+ }
386
+
387
+ /**
388
+ * Generate timeline section HTML with Layered Gantt
389
+ * @param {Array} plans - Array of plan metadata objects
390
+ * @returns {string} - Timeline section HTML
391
+ */
392
+ function generateTimelineSection(plans) {
393
+ if (!plans || plans.length === 0) return '';
394
+
395
+ const stats = generateTimelineStats(plans);
396
+
397
+ // Calculate date range (last 3 weeks to now + 1 week)
398
+ const now = new Date();
399
+ const rangeStart = new Date(now.getTime() - 21 * 24 * 60 * 60 * 1000);
400
+ const rangeEnd = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
401
+ const rangeDays = Math.ceil((rangeEnd - rangeStart) / (1000 * 60 * 60 * 24));
402
+
403
+ // Generate date axis labels (7 markers)
404
+ const axisLabels = [];
405
+
406
+
407
+ for (let i = 0; i < 7; i++) {
408
+ const date = new Date(rangeStart.getTime() + ((i * rangeDays) / 6) * 24 * 60 * 60 * 1000);
409
+ const isToday = date.toDateString() === now.toDateString();
410
+
411
+
412
+ axisLabels.push({
413
+ label: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
414
+ isToday,
415
+ });
416
+ }
417
+
418
+ const axisHtml = axisLabels
419
+ .map((a) => `<span class="gantt-axis-label${a.isToday ? ' today' : ''}">${a.label}</span>`)
420
+ .join('');
421
+
422
+ // Calculate today marker position
423
+ const todayPct = ((now - rangeStart) / (rangeEnd - rangeStart)) * 100;
424
+
425
+ // Auto-stack plans into layers
426
+ const layeredPlans = assignLayers(plans, rangeStart, rangeEnd);
427
+ const maxLayer = layeredPlans.length > 0 ? Math.max(...layeredPlans.map((p) => p.layer), 0) : 0;
428
+ // Compact layout: 22px per layer (bar 18px + 4px gap), no max cap
429
+ const trackHeight = Math.max(60, (maxLayer + 1) * 22 + 12);
430
+
431
+ // Generate gantt bars
432
+ const barsHtml = layeredPlans
433
+ .map((plan) => {
434
+ const statusClass =
435
+ plan.status === 'completed' ? 'completed' : plan.status === 'in-progress' ? 'in-progress' : 'pending';
436
+ const top = plan.layer * 22 + 6;
437
+ const statusIcon = plan.status === 'completed' ? '✓' : plan.status === 'in-progress' ? '◐' : '○';
438
+
439
+ return `
440
+ <a href="/view?file=${encodeURIComponent(plan.path)}" class="gantt-bar ${statusClass}"
441
+ style="left: ${plan.leftPct.toFixed(1)}%; width: ${plan.widthPct.toFixed(1)}%; top: ${top}px;"
442
+ data-id="${escapeHtml(plan.id)}">
443
+ <span class="gantt-bar-label">${escapeHtml(plan.name)}</span>
444
+ <span class="gantt-bar-status">${statusIcon}</span>
445
+ <div class="gantt-tooltip">
446
+ <div class="gantt-tooltip-title">${escapeHtml(plan.name)}</div>
447
+ <div class="gantt-tooltip-meta">
448
+ <span>${plan.durationFormatted || 'Today'}</span>
449
+ <span>${plan.phases.completed}/${plan.phases.total} phases</span>
450
+ ${plan.totalEffortFormatted ? `<span>${plan.totalEffortFormatted}</span>` : ''}
451
+ </div>
452
+ </div>
453
+ </a>
454
+ `;
455
+ })
456
+ .join('');
457
+
458
+ // Summary counts
459
+ const completedCount = plans.filter((p) => p.status === 'completed').length;
460
+ const activeCount = plans.filter((p) => p.status === 'in-progress').length;
461
+ const pendingCount = plans.filter((p) => p.status === 'pending').length;
462
+
463
+ return `
464
+ <section class="timeline-section" aria-label="Project timeline">
465
+ <div class="timeline-header">
466
+ <h2 class="timeline-title">Timeline</h2>
467
+ <div class="timeline-stats">
468
+ <div class="timeline-stat">
469
+ <span>Avg:</span>
470
+ <strong>${stats.avgDurationDays}d</strong>
471
+ </div>
472
+ <div class="timeline-stat">
473
+ <span>Effort:</span>
474
+ <strong>${stats.totalEffortHours.toFixed(0)}h</strong>
475
+ </div>
476
+ </div>
477
+ </div>
478
+ <div class="gantt-container">
479
+ <div class="gantt-axis">${axisHtml}</div>
480
+ <div class="gantt-track" style="height: ${trackHeight}px;">
481
+ <div class="gantt-today-marker" style="left: ${todayPct.toFixed(1)}%;"></div>
482
+ ${barsHtml}
483
+ </div>
484
+ </div>
485
+ <div class="timeline-summary">
486
+ <div class="timeline-summary-item">
487
+ <span class="timeline-summary-dot completed"></span>
488
+ <span>${completedCount} done</span>
489
+ </div>
490
+ <div class="timeline-summary-item">
491
+ <span class="timeline-summary-dot in-progress"></span>
492
+ <span>${activeCount} active</span>
493
+ </div>
494
+ <div class="timeline-summary-item">
495
+ <span class="timeline-summary-dot pending"></span>
496
+ <span>${pendingCount} pending</span>
497
+ </div>
498
+ </div>
499
+ </section>
500
+ `;
501
+ }
502
+
503
+ /**
504
+ * Generate empty state HTML with animated icon
505
+ * @returns {string} - Empty state HTML
506
+ */
507
+ function generateEmptyState() {
508
+ return `
509
+ <div class="empty-state" hidden>
510
+ <div class="empty-icon" aria-hidden="true">
511
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
512
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
513
+ <polyline points="14 2 14 8 20 8"/>
514
+ <line x1="16" y1="13" x2="8" y2="13"/>
515
+ <line x1="16" y1="17" x2="8" y2="17"/>
516
+ <polyline points="10 9 9 9 8 9"/>
517
+ </svg>
518
+ </div>
519
+ <h2>No plans found</h2>
520
+ <p>Create a plan directory with a plan.md file to get started with tracking your projects.</p>
521
+ </div>
522
+ `;
523
+ }
524
+
525
+ /**
526
+ * Generate plans grid HTML
527
+ * @param {Array} plans - Array of plan metadata objects
528
+ * @returns {string} - Grid HTML
529
+ */
530
+ function generatePlansGrid(plans) {
531
+ if (!plans || plans.length === 0) {
532
+ return '';
533
+ }
534
+
535
+ return plans.map(generatePlanCard).join('\n');
536
+ }
537
+
538
+ /**
539
+ * Status column configuration for kanban board
540
+ */
541
+ const STATUS_COLUMNS = [
542
+ { id: 'pending', label: 'Pending', color: 'pending' },
543
+ { id: 'in-progress', label: 'In Progress', color: 'in-progress' },
544
+ { id: 'in-review', label: 'In Review', color: 'in-review' },
545
+ { id: 'completed', label: 'Done', color: 'completed' },
546
+ { id: 'cancelled', label: 'Cancelled', color: 'cancelled' },
547
+ ];
548
+
549
+ /**
550
+ * Generate kanban card HTML for a single plan (enhanced with details)
551
+ * @param {Object} plan - Plan metadata
552
+ * @returns {string} - Card HTML
553
+ */
554
+ function generateKanbanCard(plan) {
555
+ const progressPct = Math.round(plan.progress || 0);
556
+ const dateStr = formatRelativeTime(plan.lastModified);
557
+
558
+ // Priority badge
559
+ let priorityHtml = '';
560
+
561
+
562
+ if (plan.priority) {
563
+ const priorityColorClass = getPriorityColorClass(plan.priority);
564
+
565
+
566
+ if (priorityColorClass) {
567
+ priorityHtml = `<span class="kanban-card-priority ${priorityColorClass}">${escapeHtml(plan.priority)}</span>`;
568
+ }
569
+ }
570
+
571
+ // Description (truncated)
572
+ let descriptionHtml = '';
573
+
574
+
575
+ if (plan.description) {
576
+ descriptionHtml = `<p class="kanban-card-description">${escapeHtml(truncate(plan.description, 80))}</p>`;
577
+ }
578
+
579
+ // Tags (max 3 visible)
580
+ let tagsHtml = '';
581
+
582
+
583
+ if (plan.tags && Array.isArray(plan.tags) && plan.tags.length > 0) {
584
+ const visibleTags = plan.tags.slice(0, 3);
585
+ const hiddenCount = plan.tags.length - 3;
586
+
587
+
588
+ tagsHtml = '<div class="kanban-card-tags">';
589
+ tagsHtml += visibleTags.map((tag) => `<span class="kanban-card-tag">${escapeHtml(tag)}</span>`).join('');
590
+ if (hiddenCount > 0) {
591
+ tagsHtml += `<span class="kanban-card-tag tag-more">+${hiddenCount}</span>`;
592
+ }
593
+ tagsHtml += '</div>';
594
+ }
595
+
596
+ // Footer with effort and phases
597
+ let footerHtml = '';
598
+ const effortHtml = plan.totalEffortFormatted
599
+ ? `<span class="kanban-card-effort"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>${escapeHtml(plan.totalEffortFormatted)}</span>`
600
+ : '';
601
+ const phasesHtml =
602
+ plan.phases && plan.phases.total ? `<span class="kanban-card-phases">${plan.phases.total} phases</span>` : '';
603
+
604
+
605
+ if (effortHtml || phasesHtml) {
606
+ footerHtml = `<div class="kanban-card-footer">${effortHtml}${phasesHtml}</div>`;
607
+ }
608
+
609
+ return `
610
+ <a href="/view?file=${encodeURIComponent(plan.path)}" class="kanban-card" data-id="${escapeHtml(plan.id)}">
611
+ <div class="kanban-card-header">
612
+ <h4 class="kanban-card-title">${escapeHtml(plan.name)}</h4>
613
+ ${priorityHtml}
614
+ </div>
615
+ ${descriptionHtml}
616
+ <div class="kanban-card-meta">
617
+ <div class="kanban-card-progress">
618
+ <div class="kanban-card-progress-bar">
619
+ <div class="kanban-card-progress-fill" style="width: ${progressPct}%"></div>
620
+ </div>
621
+ <span>${progressPct}%</span>
622
+ </div>
623
+ <span class="kanban-card-date">${dateStr}</span>
624
+ </div>
625
+ ${tagsHtml}
626
+ ${footerHtml}
627
+ </a>
628
+ `;
629
+ }
630
+
631
+ /**
632
+ * Generate kanban board columns HTML
633
+ * @param {Array} plans - Array of plan metadata objects
634
+ * @returns {string} - Kanban columns HTML
635
+ */
636
+ function generateKanbanColumns(plans) {
637
+ if (!plans || plans.length === 0) {
638
+ // Return empty columns structure
639
+ return STATUS_COLUMNS.map(
640
+ (col) => `
641
+ <div class="kanban-column" data-status="${col.id}">
642
+ <div class="kanban-column-header">
643
+ <div class="kanban-column-title">
644
+ <span class="kanban-status-dot ${col.color}"></span>
645
+ <span>${col.label}</span>
646
+ </div>
647
+ <span class="kanban-column-count">0</span>
648
+ </div>
649
+ <div class="kanban-cards">
650
+ <div class="kanban-empty">
651
+ <svg class="kanban-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
652
+ <rect x="3" y="3" width="18" height="18" rx="2"/>
653
+ <path d="M9 9h6M9 13h6M9 17h4"/>
654
+ </svg>
655
+ <span>No plans</span>
656
+ </div>
657
+ </div>
658
+ </div>
659
+ `,
660
+ ).join('');
661
+ }
662
+
663
+ // Group plans by status
664
+ const grouped = {};
665
+
666
+
667
+ STATUS_COLUMNS.forEach((col) => {
668
+ grouped[col.id] = [];
669
+ });
670
+
671
+ plans.forEach((plan) => {
672
+ const status = plan.status || 'pending';
673
+
674
+
675
+ if (grouped[status]) {
676
+ grouped[status].push(plan);
677
+ } else {
678
+ grouped['pending'].push(plan);
679
+ }
680
+ });
681
+
682
+ // Generate column HTML
683
+ return STATUS_COLUMNS.map((col) => {
684
+ const columnPlans = grouped[col.id];
685
+ const cardsHtml =
686
+ columnPlans.length > 0
687
+ ? columnPlans.map(generateKanbanCard).join('')
688
+ : `<div class="kanban-empty">
689
+ <svg class="kanban-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
690
+ <rect x="3" y="3" width="18" height="18" rx="2"/>
691
+ <path d="M9 9h6M9 13h6M9 17h4"/>
692
+ </svg>
693
+ <span>No plans</span>
694
+ </div>`;
695
+
696
+ return `
697
+ <div class="kanban-column" data-status="${col.id}">
698
+ <div class="kanban-column-header">
699
+ <div class="kanban-column-title">
700
+ <span class="kanban-status-dot ${col.color}"></span>
701
+ <span>${col.label}</span>
702
+ </div>
703
+ <span class="kanban-column-count">${columnPlans.length}</span>
704
+ </div>
705
+ <div class="kanban-cards">
706
+ ${cardsHtml}
707
+ </div>
708
+ </div>
709
+ `;
710
+ }).join('');
711
+ }
712
+
713
+ /**
714
+ * Calculate statistics from plans array
715
+ * @param {Array} plans - Array of plan metadata objects
716
+ * @returns {Object} - Statistics object
717
+ */
718
+ function calculateStats(plans) {
719
+ const stats = {
720
+ total: plans.length,
721
+ completed: 0,
722
+ inProgress: 0,
723
+ pending: 0,
724
+ };
725
+
726
+ plans.forEach((plan) => {
727
+ const status = (plan.status || 'pending').replaceAll(/\s+/g, '-');
728
+
729
+
730
+ if (status === 'completed' || status === 'complete') {
731
+ stats.completed++;
732
+ } else if (status === 'in-progress') {
733
+ stats.inProgress++;
734
+ } else {
735
+ stats.pending++;
736
+ }
737
+ });
738
+
739
+ return stats;
740
+ }
741
+
742
+ /**
743
+ * Render complete dashboard HTML
744
+ * @param {Array} plans - Array of plan metadata objects
745
+ * @param {Object} options - Render options
746
+ * @param {string} options.assetsDir - Assets directory path
747
+ * @param {string} options.plansDir - Plans directory path
748
+ * @returns {string} - Complete HTML page
749
+ */
750
+ function renderDashboard(plans, options = {}) {
751
+ const { assetsDir } = options;
752
+
753
+ // Load template
754
+ const templatePath = path.join(assetsDir, 'dashboard-template.html');
755
+ let template;
756
+
757
+ try {
758
+ template = fs.readFileSync(templatePath, 'utf8');
759
+ } catch {
760
+ // Fallback inline template if file not found
761
+ template = getInlineTemplate();
762
+ }
763
+
764
+ // Calculate statistics
765
+ const stats = calculateStats(plans);
766
+
767
+ // Generate cards
768
+ const plansGrid = generatePlansGrid(plans);
769
+ const planCount = plans.length;
770
+
771
+ // Generate timeline section
772
+ const timelineSection = generateTimelineSection(plans);
773
+
774
+ // Generate kanban columns
775
+ const kanbanColumns = generateKanbanColumns(plans);
776
+
777
+ // Generate JSON for client-side filtering (include rich metadata)
778
+ const plansJson = JSON.stringify(
779
+ plans.map((p) => ({
780
+ id: p.id,
781
+ name: p.name,
782
+ status: p.status,
783
+ progress: p.progress,
784
+ lastModified: p.lastModified,
785
+ phasesTotal: p.phases.total,
786
+ path: p.path, // Required for kanban card links
787
+ // Rich metadata
788
+ createdDate: p.createdDate,
789
+ completedDate: p.completedDate,
790
+ durationDays: p.durationDays,
791
+ durationFormatted: p.durationFormatted,
792
+ totalEffortHours: p.totalEffortHours,
793
+ totalEffortFormatted: p.totalEffortFormatted,
794
+ priority: p.priority,
795
+ issue: p.issue,
796
+ branch: p.branch,
797
+ // New frontmatter fields
798
+ description: p.description,
799
+ tags: p.tags || [],
800
+ assignee: p.assignee,
801
+ })),
802
+ );
803
+
804
+ // Replace placeholders
805
+ template = template
806
+ .replaceAll('{{plans-grid}}', plansGrid)
807
+ .replaceAll('{{kanban-columns}}', kanbanColumns)
808
+ .replaceAll('{{plan-count}}', String(planCount))
809
+ .replaceAll('{{plans-json}}', plansJson)
810
+ .replaceAll('{{empty-state}}', generateEmptyState())
811
+ .replaceAll('{{timeline-section}}', timelineSection)
812
+ .replaceAll('{{has-plans}}', plans.length > 0 ? 'plans-loaded' : '')
813
+ .replaceAll('{{stat-total}}', String(stats.total))
814
+ .replaceAll('{{stat-completed}}', String(stats.completed))
815
+ .replaceAll('{{stat-in-progress}}', String(stats.inProgress))
816
+ .replaceAll('{{stat-pending}}', String(stats.pending));
817
+
818
+ return template;
819
+ }
820
+
821
+ /**
822
+ * Get inline fallback template
823
+ * @returns {string} - Inline HTML template
824
+ */
825
+ function getInlineTemplate() {
826
+ return `<!DOCTYPE html>
827
+ <html lang="en" data-theme="light">
828
+ <head>
829
+ <meta charset="UTF-8">
830
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
831
+ <title>Plans Dashboard</title>
832
+ <link rel="icon" type="image/png" href="/assets/favicon.png">
833
+ <link rel="stylesheet" href="/assets/novel-theme.css">
834
+ <link rel="stylesheet" href="/assets/dashboard.css">
835
+ </head>
836
+ <body class="dashboard-view {{has-plans}}">
837
+ <header class="dashboard-header">
838
+ <div class="header-left">
839
+ <h1>Plans Dashboard</h1>
840
+ </div>
841
+ <div class="header-right">
842
+ <button id="theme-toggle" class="icon-btn" aria-label="Toggle theme">
843
+ <svg class="sun-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
844
+ <circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
845
+ </svg>
846
+ <svg class="moon-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
847
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
848
+ </svg>
849
+ </button>
850
+ </div>
851
+ </header>
852
+
853
+ <main role="main" aria-label="Plans Dashboard">
854
+ <section class="stats-hero" aria-label="Plan statistics">
855
+ <div class="stat-card total">
856
+ <div class="stat-icon">📋</div>
857
+ <div class="stat-value">{{stat-total}}</div>
858
+ <div class="stat-label">Total Plans</div>
859
+ </div>
860
+ <div class="stat-card completed">
861
+ <div class="stat-icon">✅</div>
862
+ <div class="stat-value">{{stat-completed}}</div>
863
+ <div class="stat-label">Completed</div>
864
+ </div>
865
+ <div class="stat-card in-progress">
866
+ <div class="stat-icon">🔄</div>
867
+ <div class="stat-value">{{stat-in-progress}}</div>
868
+ <div class="stat-label">In Progress</div>
869
+ </div>
870
+ <div class="stat-card pending">
871
+ <div class="stat-icon">⏳</div>
872
+ <div class="stat-value">{{stat-pending}}</div>
873
+ <div class="stat-label">Pending</div>
874
+ </div>
875
+ </section>
876
+
877
+ <div class="dashboard-controls">
878
+ <div class="search-box">
879
+ <svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
880
+ <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
881
+ </svg>
882
+ <input type="search" id="plan-search" placeholder="Search plans..." aria-label="Search plans">
883
+ </div>
884
+
885
+ <select id="sort-select" aria-label="Sort plans by">
886
+ <option value="date-desc">Newest First</option>
887
+ <option value="date-asc">Oldest First</option>
888
+ <option value="name-asc">Name A-Z</option>
889
+ <option value="name-desc">Name Z-A</option>
890
+ <option value="progress-desc">Most Progress</option>
891
+ <option value="progress-asc">Least Progress</option>
892
+ </select>
893
+
894
+ <div class="filter-pills" role="group" aria-label="Filter by status">
895
+ <button class="filter-pill active" data-filter="all" aria-pressed="true">All</button>
896
+ <button class="filter-pill" data-filter="completed" aria-pressed="false">Completed</button>
897
+ <button class="filter-pill" data-filter="in-progress" aria-pressed="false">In Progress</button>
898
+ <button class="filter-pill" data-filter="pending" aria-pressed="false">Pending</button>
899
+ </div>
900
+
901
+ <div role="status" aria-live="polite" class="result-count">
902
+ Showing <strong>{{plan-count}}</strong> plans
903
+ </div>
904
+ </div>
905
+
906
+ <section class="plans-grid" aria-label="Plans list">
907
+ {{plans-grid}}
908
+ </section>
909
+
910
+ {{empty-state}}
911
+ </main>
912
+
913
+ <script>window.__plans = {{plans-json}};</script>
914
+ <script src="/assets/dashboard.js"></script>
915
+ </body>
916
+ </html>`;
917
+ }
918
+
919
+ module.exports = {
920
+ renderDashboard,
921
+ generatePlanCard,
922
+ generateCardMeta,
923
+ generateTagsPills,
924
+ generateProgressRing,
925
+ generateProgressBar,
926
+ generateStatusCounts,
927
+ generateStatusBadge,
928
+ generateTimelineSection,
929
+ generateEmptyState,
930
+ generatePlansGrid,
931
+ generateKanbanColumns,
932
+ generateKanbanCard,
933
+ calculateStats,
934
+ escapeHtml,
935
+ truncate,
936
+ formatDate,
937
+ formatRelativeTime,
938
+ getStatusLabel,
939
+ getPriorityColorClass,
940
+ STATUS_COLUMNS,
941
+ };