vibedoc 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +39 -11
  5. package/.next/routes-manifest.json +12 -0
  6. package/.next/server/app/(app)/activity/page.js.nft.json +1 -1
  7. package/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/(app)/board/page.js.nft.json +1 -1
  9. package/.next/server/app/(app)/board/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/(app)/chat/page/app-paths-manifest.json +3 -0
  11. package/.next/server/app/(app)/chat/page/build-manifest.json +20 -0
  12. package/.next/server/app/(app)/chat/page/next-font-manifest.json +11 -0
  13. package/.next/server/app/(app)/chat/page/react-loadable-manifest.json +1 -0
  14. package/.next/server/app/(app)/chat/page/server-reference-manifest.json +4 -0
  15. package/.next/server/app/(app)/chat/page.js +15 -0
  16. package/.next/server/app/(app)/chat/page.js.map +5 -0
  17. package/.next/server/app/(app)/chat/page.js.nft.json +1 -0
  18. package/.next/server/app/(app)/chat/page_client-reference-manifest.js +3 -0
  19. package/.next/server/app/(app)/docs/page.js.nft.json +1 -1
  20. package/.next/server/app/(app)/docs/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/(app)/explorer/page.js.nft.json +1 -1
  22. package/.next/server/app/(app)/explorer/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/(app)/memory/page.js.nft.json +1 -1
  24. package/.next/server/app/(app)/memory/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/(app)/roadmap/page.js.nft.json +1 -1
  26. package/.next/server/app/(app)/roadmap/page_client-reference-manifest.js +1 -1
  27. package/.next/server/app/(app)/settings/page.js.nft.json +1 -1
  28. package/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
  29. package/.next/server/app/(app)/setup/page.js.nft.json +1 -1
  30. package/.next/server/app/(app)/setup/page_client-reference-manifest.js +1 -1
  31. package/.next/server/app/_global-error.html +1 -1
  32. package/.next/server/app/_global-error.rsc +1 -1
  33. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  34. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  36. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  37. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/_not-found.html +1 -1
  39. package/.next/server/app/_not-found.rsc +2 -2
  40. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  41. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  42. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  43. package/.next/server/app/activity.html +1 -1
  44. package/.next/server/app/activity.rsc +22 -23
  45. package/.next/server/app/activity.segments/!KGFwcCk/activity/__PAGE__.segment.rsc +9 -10
  46. package/.next/server/app/activity.segments/_full.segment.rsc +22 -23
  47. package/.next/server/app/activity.segments/_tree.segment.rsc +2 -2
  48. package/.next/server/app/api/activity/route.js.nft.json +1 -1
  49. package/.next/server/app/api/backlinks/route.js.nft.json +1 -1
  50. package/.next/server/app/api/chat/route.js.nft.json +1 -1
  51. package/.next/server/app/api/context/route.js.nft.json +1 -1
  52. package/.next/server/app/api/conversations/route/app-paths-manifest.json +3 -0
  53. package/.next/server/app/api/conversations/route/build-manifest.json +12 -0
  54. package/.next/server/app/api/conversations/route/server-reference-manifest.json +4 -0
  55. package/.next/server/app/api/conversations/route.js +9 -0
  56. package/.next/server/app/api/conversations/route.js.map +5 -0
  57. package/.next/server/app/api/conversations/route.js.nft.json +1 -0
  58. package/.next/server/app/api/conversations/route_client-reference-manifest.js +3 -0
  59. package/.next/server/app/api/decisions/route.js.nft.json +1 -1
  60. package/.next/server/app/api/docs/route.js.nft.json +1 -1
  61. package/.next/server/app/api/explorer/route.js.nft.json +1 -1
  62. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  63. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  64. package/.next/server/app/api/plan/apply/route.js.nft.json +1 -1
  65. package/.next/server/app/api/projects/route.js.nft.json +1 -1
  66. package/.next/server/app/api/registry/route.js.nft.json +1 -1
  67. package/.next/server/app/api/roadmap/create/route.js.nft.json +1 -1
  68. package/.next/server/app/api/roadmap/delete/route.js.nft.json +1 -1
  69. package/.next/server/app/api/roadmap/generate/route.js.nft.json +1 -1
  70. package/.next/server/app/api/roadmap/layout/route.js.nft.json +1 -1
  71. package/.next/server/app/api/roadmap/route.js.nft.json +1 -1
  72. package/.next/server/app/api/roadmap/update/route.js.nft.json +1 -1
  73. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  74. package/.next/server/app/api/settings/route.js.nft.json +1 -1
  75. package/.next/server/app/api/setup/generate/route.js.nft.json +1 -1
  76. package/.next/server/app/api/setup/write/route.js.nft.json +1 -1
  77. package/.next/server/app/api/summary/route.js.nft.json +1 -1
  78. package/.next/server/app/api/tasks/create/route.js.nft.json +1 -1
  79. package/.next/server/app/api/tasks/route.js.nft.json +1 -1
  80. package/.next/server/app/board.html +1 -1
  81. package/.next/server/app/board.rsc +22 -23
  82. package/.next/server/app/board.segments/!KGFwcCk/board/__PAGE__.segment.rsc +9 -10
  83. package/.next/server/app/board.segments/_full.segment.rsc +22 -23
  84. package/.next/server/app/board.segments/_tree.segment.rsc +2 -2
  85. package/.next/server/app/chat.html +1 -0
  86. package/.next/server/app/chat.meta +31 -0
  87. package/.next/server/app/chat.rsc +29 -0
  88. package/.next/server/app/chat.segments/!KGFwcCk/chat/__PAGE__.segment.rsc +31 -0
  89. package/.next/server/app/chat.segments/_full.segment.rsc +29 -0
  90. package/.next/server/app/chat.segments/_tree.segment.rsc +4 -0
  91. package/.next/server/app/docs.html +1 -1
  92. package/.next/server/app/docs.rsc +22 -27
  93. package/.next/server/app/docs.segments/!KGFwcCk/docs/__PAGE__.segment.rsc +6 -6
  94. package/.next/server/app/docs.segments/_full.segment.rsc +22 -27
  95. package/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  96. package/.next/server/app/explorer.html +1 -1
  97. package/.next/server/app/explorer.rsc +22 -23
  98. package/.next/server/app/explorer.segments/!KGFwcCk/explorer/__PAGE__.segment.rsc +9 -10
  99. package/.next/server/app/explorer.segments/_full.segment.rsc +22 -23
  100. package/.next/server/app/explorer.segments/_tree.segment.rsc +2 -2
  101. package/.next/server/app/index.html +1 -1
  102. package/.next/server/app/index.rsc +2 -2
  103. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  104. package/.next/server/app/index.segments/_full.segment.rsc +2 -2
  105. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  106. package/.next/server/app/memory.html +1 -1
  107. package/.next/server/app/memory.rsc +22 -23
  108. package/.next/server/app/memory.segments/!KGFwcCk/memory/__PAGE__.segment.rsc +9 -10
  109. package/.next/server/app/memory.segments/_full.segment.rsc +22 -23
  110. package/.next/server/app/memory.segments/_tree.segment.rsc +2 -2
  111. package/.next/server/app/page.js.nft.json +1 -1
  112. package/.next/server/app/page_client-reference-manifest.js +1 -1
  113. package/.next/server/app/roadmap.html +1 -1
  114. package/.next/server/app/roadmap.rsc +22 -26
  115. package/.next/server/app/roadmap.segments/!KGFwcCk/roadmap/__PAGE__.segment.rsc +9 -11
  116. package/.next/server/app/roadmap.segments/_full.segment.rsc +22 -26
  117. package/.next/server/app/roadmap.segments/_tree.segment.rsc +2 -2
  118. package/.next/server/app/settings.html +1 -1
  119. package/.next/server/app/settings.rsc +22 -23
  120. package/.next/server/app/settings.segments/!KGFwcCk/settings/__PAGE__.segment.rsc +9 -10
  121. package/.next/server/app/settings.segments/_full.segment.rsc +22 -23
  122. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  123. package/.next/server/app/setup.html +1 -1
  124. package/.next/server/app/setup.rsc +22 -23
  125. package/.next/server/app/setup.segments/!KGFwcCk/setup/__PAGE__.segment.rsc +9 -10
  126. package/.next/server/app/setup.segments/_full.segment.rsc +22 -23
  127. package/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  128. package/.next/server/app-paths-manifest.json +2 -0
  129. package/.next/server/chunks/11mp_@anthropic-ai_sdk_1htgzmb._.js +3 -0
  130. package/.next/server/chunks/11mp_@anthropic-ai_sdk_1htgzmb._.js.map +1 -0
  131. package/.next/server/chunks/11mp_@anthropic-ai_sdk_index_mjs_0d2_lq6._.js +3 -0
  132. package/.next/server/chunks/[root-of-the-server]__1613hjb._.js +4 -4
  133. package/.next/server/chunks/[root-of-the-server]__1613hjb._.js.map +1 -1
  134. package/.next/server/chunks/[root-of-the-server]__1jxu2x9._.js +3 -0
  135. package/.next/server/chunks/[root-of-the-server]__1jxu2x9._.js.map +1 -0
  136. package/.next/server/chunks/_1b5fqxy._.js +1 -1
  137. package/.next/server/chunks/_1b5fqxy._.js.map +1 -1
  138. package/.next/server/chunks/_next-internal_server_app_api_conversations_route_actions_1-pu7gs.js +3 -0
  139. package/.next/server/chunks/ssr/{0_nd_mermaid_dist_mermaid_core_mjs_10jvzv6._.js → 0_nd_mermaid_dist_mermaid_core_mjs_0vv_0i3._.js} +2 -2
  140. package/.next/server/chunks/ssr/{1u84_katex_dist_katex_mjs_05prlqa._.js → 1u84_katex_dist_katex_mjs_1z0p1bs._.js} +1 -1
  141. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0cvmffy._.js +3 -0
  142. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0cvmffy._.js.map +1 -0
  143. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0u3jxas._.js +3 -0
  144. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0u3jxas._.js.map +1 -0
  145. package/.next/server/chunks/ssr/[root-of-the-server]__0xt_0w2._.js.map +1 -1
  146. package/.next/server/chunks/ssr/[root-of-the-server]__11lfnu0._.js +3 -0
  147. package/.next/server/chunks/ssr/[root-of-the-server]__11lfnu0._.js.map +1 -0
  148. package/.next/server/chunks/ssr/_059qmur._.js +3 -0
  149. package/.next/server/chunks/ssr/_059qmur._.js.map +1 -0
  150. package/.next/server/chunks/ssr/_081irea._.js +3 -0
  151. package/.next/server/chunks/ssr/_081irea._.js.map +1 -0
  152. package/.next/server/chunks/ssr/_0d8t8l4._.js +3 -0
  153. package/.next/server/chunks/ssr/_0d8t8l4._.js.map +1 -0
  154. package/.next/server/chunks/ssr/_0dyvcdg._.js +3 -0
  155. package/.next/server/chunks/ssr/_0dyvcdg._.js.map +1 -0
  156. package/.next/server/chunks/ssr/_1-ghqy4._.js +3 -0
  157. package/.next/server/chunks/ssr/_1-ghqy4._.js.map +1 -0
  158. package/.next/server/chunks/ssr/_17jy5db._.js +3 -0
  159. package/.next/server/chunks/ssr/_17jy5db._.js.map +1 -0
  160. package/.next/server/chunks/ssr/_1c95ems._.js +1 -1
  161. package/.next/server/chunks/ssr/_1c95ems._.js.map +1 -1
  162. package/.next/server/chunks/ssr/_1dllfz5._.js +4 -0
  163. package/.next/server/chunks/ssr/_1dllfz5._.js.map +1 -0
  164. package/.next/server/chunks/ssr/_next-internal_server_app_(app)_chat_page_actions_0g4tbzt.js +3 -0
  165. package/.next/server/chunks/ssr/node_modules__pnpm_006_c8z._.js +3 -0
  166. package/.next/server/chunks/ssr/node_modules__pnpm_006_c8z._.js.map +1 -0
  167. package/.next/server/chunks/ssr/{node_modules__pnpm_1kngagu._.js → node_modules__pnpm_0286-tg._.js} +1 -1
  168. package/.next/server/chunks/ssr/{node_modules__pnpm_1ad2q27._.js → node_modules__pnpm_04khl_s._.js} +1 -1
  169. package/.next/server/chunks/ssr/{node_modules__pnpm_0ns_6dd._.js → node_modules__pnpm_07t_e8c._.js} +1 -1
  170. package/.next/server/chunks/ssr/{node_modules__pnpm_0baie09._.js → node_modules__pnpm_08sqeu2._.js} +1 -1
  171. package/.next/server/chunks/ssr/{node_modules__pnpm_1jfqun_._.js → node_modules__pnpm_09_i2jk._.js} +1 -1
  172. package/.next/server/chunks/ssr/node_modules__pnpm_09_i2jk._.js.map +1 -0
  173. package/.next/server/chunks/ssr/{node_modules__pnpm_1o3_0-n._.js → node_modules__pnpm_0a9b2ei._.js} +1 -1
  174. package/.next/server/chunks/ssr/{node_modules__pnpm_0e15nhj._.js → node_modules__pnpm_0ah02mu._.js} +1 -1
  175. package/.next/server/chunks/ssr/{node_modules__pnpm_20tdqv_._.js → node_modules__pnpm_0cj8ryj._.js} +1 -1
  176. package/.next/server/chunks/ssr/{node_modules__pnpm_0wnlgm-._.js → node_modules__pnpm_0dwi7mu._.js} +2 -2
  177. package/.next/server/chunks/ssr/node_modules__pnpm_0dwi7mu._.js.map +1 -0
  178. package/.next/server/chunks/ssr/{node_modules__pnpm_1h890n6._.js → node_modules__pnpm_0f77_ng._.js} +1 -1
  179. package/.next/server/chunks/ssr/{node_modules__pnpm_1u8p2h3._.js → node_modules__pnpm_0fd3pr1._.js} +2 -2
  180. package/.next/server/chunks/ssr/{node_modules__pnpm_1zu-9we._.js → node_modules__pnpm_0gifu-u._.js} +2 -2
  181. package/.next/server/chunks/ssr/{node_modules__pnpm_1_o0jyk._.js → node_modules__pnpm_0jpv2b6._.js} +2 -2
  182. package/.next/server/chunks/ssr/{node_modules__pnpm_1f3lm9p._.js → node_modules__pnpm_0og06fy._.js} +1 -1
  183. package/.next/server/chunks/ssr/{node_modules__pnpm_12s6q4d._.js → node_modules__pnpm_0qc3gsk._.js} +1 -1
  184. package/.next/server/chunks/ssr/{node_modules__pnpm_0e3u5g-._.js → node_modules__pnpm_0ts89ne._.js} +1 -1
  185. package/.next/server/chunks/ssr/{node_modules__pnpm_1moe8b6._.js → node_modules__pnpm_0ttvopp._.js} +1 -1
  186. package/.next/server/chunks/ssr/{node_modules__pnpm_1ly58kw._.js → node_modules__pnpm_0u3u82f._.js} +1 -1
  187. package/.next/server/chunks/ssr/{node_modules__pnpm_1hw4h9e._.js → node_modules__pnpm_0y35hs4._.js} +1 -1
  188. package/.next/server/chunks/ssr/{node_modules__pnpm_0jhh7p5._.js → node_modules__pnpm_104pzhc._.js} +2 -2
  189. package/.next/server/chunks/ssr/{node_modules__pnpm_1gqkoe3._.js → node_modules__pnpm_195j8p_._.js} +1 -1
  190. package/.next/server/chunks/ssr/node_modules__pnpm_1kcnkjs._.js +3 -0
  191. package/.next/server/chunks/ssr/node_modules__pnpm_1kcnkjs._.js.map +1 -0
  192. package/.next/server/chunks/ssr/{node_modules__pnpm_0i0uccx._.js → node_modules__pnpm_1l8k8w1._.js} +1 -1
  193. package/.next/server/chunks/ssr/{node_modules__pnpm_0rd-a9g._.js → node_modules__pnpm_1w0f1m5._.js} +1 -1
  194. package/.next/server/chunks/ssr/{node_modules__pnpm_1gtgu48._.js → node_modules__pnpm_1woddr6._.js} +2 -2
  195. package/.next/server/chunks/ssr/{node_modules__pnpm_0_z3_bl._.js → node_modules__pnpm_1x0t5_z._.js} +1 -1
  196. package/.next/server/chunks/ssr/{node_modules__pnpm_07_kgbe._.js → node_modules__pnpm_1xzf8g_._.js} +1 -1
  197. package/.next/server/chunks/ssr/{node_modules__pnpm_08em703._.js → node_modules__pnpm_1yq90z7._.js} +1 -1
  198. package/.next/server/chunks/ssr/node_modules__pnpm_1yq90z7._.js.map +1 -0
  199. package/.next/server/chunks/ssr/src_app_(app)_chat_page_tsx_0c3e4l4._.js +3 -0
  200. package/.next/server/chunks/ssr/src_app_(app)_chat_page_tsx_0c3e4l4._.js.map +1 -0
  201. package/.next/server/chunks/ssr/src_app_(app)_layout_tsx_1yu5hom._.js +3 -0
  202. package/.next/server/chunks/ssr/src_app_(app)_layout_tsx_1yu5hom._.js.map +1 -0
  203. package/.next/server/chunks/ssr/src_app_(app)_roadmap_page_tsx_0vcq3jr._.js +5 -0
  204. package/.next/server/chunks/ssr/src_app_(app)_roadmap_page_tsx_0vcq3jr._.js.map +1 -0
  205. package/.next/server/chunks/ssr/src_app_(app)_settings_page_tsx_0zevtee._.js +2 -2
  206. package/.next/server/chunks/ssr/src_app_(app)_settings_page_tsx_0zevtee._.js.map +1 -1
  207. package/.next/server/chunks/ssr/src_context_ChatContext_tsx_0lowp8p._.js +5 -0
  208. package/.next/server/chunks/ssr/src_context_ChatContext_tsx_0lowp8p._.js.map +1 -0
  209. package/.next/server/chunks/ssr/{_1wf14_u._.js → src_lib_templates_index_ts_1s61uk7._.js} +2 -2
  210. package/.next/server/chunks/ssr/{_1wf14_u._.js.map → src_lib_templates_index_ts_1s61uk7._.js.map} +1 -1
  211. package/.next/server/middleware-build-manifest.js +3 -3
  212. package/.next/server/next-font-manifest.js +1 -1
  213. package/.next/server/next-font-manifest.json +4 -0
  214. package/.next/server/pages/404.html +1 -1
  215. package/.next/server/pages/500.html +1 -1
  216. package/.next/server/prefetch-hints.json +19 -0
  217. package/.next/server/server-reference-manifest.js +1 -1
  218. package/.next/server/server-reference-manifest.json +1 -1
  219. package/.next/static/chunks/050mq8l4e1ubn.js +1 -0
  220. package/.next/static/chunks/098le48845_fg.js +3 -0
  221. package/.next/static/chunks/0cw4-ebkoufdc.js +1 -0
  222. package/.next/static/chunks/0feo-go1w5nct.js +1 -0
  223. package/.next/static/chunks/14sefb904pl64.js +21 -0
  224. package/.next/static/chunks/1fer-wulyrjrs.js +3 -0
  225. package/.next/static/chunks/1o7b1x4umy8a6.js +1 -0
  226. package/.next/static/chunks/1q_io1j58aukw.js +1 -0
  227. package/.next/static/chunks/1t-cgh4477hfo.js +1 -0
  228. package/.next/static/chunks/1u-1po1qesc9f.js +1 -0
  229. package/.next/static/chunks/1u5kegkgm0xoz.js +1 -0
  230. package/.next/static/chunks/24ygzsgd-moqy.js +1 -0
  231. package/.next/static/chunks/26folxgplfa9t.js +68 -0
  232. package/.next/static/chunks/2ocixvjhv34_3.js +1 -0
  233. package/.next/static/chunks/3_lsdgxa-h7ma.css +10 -0
  234. package/.next/static/chunks/3rmv-sb9w9i3e.js +1 -0
  235. package/.next/static/chunks/3ttzomivj48jh.js +2 -0
  236. package/README.md +1 -1
  237. package/package.json +1 -1
  238. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_08ca0b4._.js +0 -3
  239. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_08ca0b4._.js.map +0 -1
  240. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0c1k9is._.js +0 -3
  241. package/.next/server/chunks/ssr/1x05_lucide-react_dist_esm_icons_0c1k9is._.js.map +0 -1
  242. package/.next/server/chunks/ssr/_01suk2m._.js +0 -3
  243. package/.next/server/chunks/ssr/_01suk2m._.js.map +0 -1
  244. package/.next/server/chunks/ssr/_0qyglif._.js +0 -5
  245. package/.next/server/chunks/ssr/_0qyglif._.js.map +0 -1
  246. package/.next/server/chunks/ssr/_0skuoxv._.js +0 -6
  247. package/.next/server/chunks/ssr/_0skuoxv._.js.map +0 -1
  248. package/.next/server/chunks/ssr/_14i_6yb._.js +0 -3
  249. package/.next/server/chunks/ssr/_14i_6yb._.js.map +0 -1
  250. package/.next/server/chunks/ssr/_1cbhuz4._.js +0 -3
  251. package/.next/server/chunks/ssr/_1cbhuz4._.js.map +0 -1
  252. package/.next/server/chunks/ssr/_1ewk_mn._.js +0 -3
  253. package/.next/server/chunks/ssr/_1ewk_mn._.js.map +0 -1
  254. package/.next/server/chunks/ssr/node_modules__pnpm_1dcmsrg._.js +0 -3
  255. package/.next/server/chunks/ssr/node_modules__pnpm_1dcmsrg._.js.map +0 -1
  256. package/.next/server/chunks/ssr/src_components_008q3v8._.js +0 -3
  257. package/.next/server/chunks/ssr/src_components_008q3v8._.js.map +0 -1
  258. package/.next/static/chunks/02sab26ica2x3.js +0 -1
  259. package/.next/static/chunks/0eggcu0ovk8sd.js +0 -68
  260. package/.next/static/chunks/0iva6rdtfqpbz.js +0 -1
  261. package/.next/static/chunks/0qm101bdsxdyh.css +0 -10
  262. package/.next/static/chunks/0wg9n5zb8mo2p.js +0 -1
  263. package/.next/static/chunks/0wjw1laqwg-cr.js +0 -21
  264. package/.next/static/chunks/0z_y7el6m76yk.js +0 -1
  265. package/.next/static/chunks/1-ekntoveuxzd.js +0 -4
  266. package/.next/static/chunks/1g6fxjtlpv6p5.js +0 -1
  267. package/.next/static/chunks/1ytqu-ra-fylk.js +0 -3
  268. package/.next/static/chunks/3dlnlsyyysw5m.js +0 -1
  269. package/.next/static/chunks/3kkg030rcpz7l.js +0 -1
  270. package/.next/static/chunks/3pf_4ye6ju8gt.js +0 -1
  271. /package/.next/server/chunks/{ssr/0_nd_mermaid_dist_mermaid_core_mjs_10jvzv6._.js.map → 11mp_@anthropic-ai_sdk_index_mjs_0d2_lq6._.js.map} +0 -0
  272. /package/.next/server/chunks/{ssr/1u84_katex_dist_katex_mjs_05prlqa._.js.map → _next-internal_server_app_api_conversations_route_actions_1-pu7gs.js.map} +0 -0
  273. /package/.next/server/chunks/ssr/{node_modules__pnpm_08em703._.js.map → 0_nd_mermaid_dist_mermaid_core_mjs_0vv_0i3._.js.map} +0 -0
  274. /package/.next/server/chunks/ssr/{node_modules__pnpm_0wnlgm-._.js.map → 1u84_katex_dist_katex_mjs_1z0p1bs._.js.map} +0 -0
  275. /package/.next/server/chunks/ssr/{node_modules__pnpm_1jfqun_._.js.map → _next-internal_server_app_(app)_chat_page_actions_0g4tbzt.js.map} +0 -0
  276. /package/.next/server/chunks/ssr/{node_modules__pnpm_1kngagu._.js.map → node_modules__pnpm_0286-tg._.js.map} +0 -0
  277. /package/.next/server/chunks/ssr/{node_modules__pnpm_1ad2q27._.js.map → node_modules__pnpm_04khl_s._.js.map} +0 -0
  278. /package/.next/server/chunks/ssr/{node_modules__pnpm_0ns_6dd._.js.map → node_modules__pnpm_07t_e8c._.js.map} +0 -0
  279. /package/.next/server/chunks/ssr/{node_modules__pnpm_0baie09._.js.map → node_modules__pnpm_08sqeu2._.js.map} +0 -0
  280. /package/.next/server/chunks/ssr/{node_modules__pnpm_1o3_0-n._.js.map → node_modules__pnpm_0a9b2ei._.js.map} +0 -0
  281. /package/.next/server/chunks/ssr/{node_modules__pnpm_0e15nhj._.js.map → node_modules__pnpm_0ah02mu._.js.map} +0 -0
  282. /package/.next/server/chunks/ssr/{node_modules__pnpm_20tdqv_._.js.map → node_modules__pnpm_0cj8ryj._.js.map} +0 -0
  283. /package/.next/server/chunks/ssr/{node_modules__pnpm_1h890n6._.js.map → node_modules__pnpm_0f77_ng._.js.map} +0 -0
  284. /package/.next/server/chunks/ssr/{node_modules__pnpm_1u8p2h3._.js.map → node_modules__pnpm_0fd3pr1._.js.map} +0 -0
  285. /package/.next/server/chunks/ssr/{node_modules__pnpm_1zu-9we._.js.map → node_modules__pnpm_0gifu-u._.js.map} +0 -0
  286. /package/.next/server/chunks/ssr/{node_modules__pnpm_1_o0jyk._.js.map → node_modules__pnpm_0jpv2b6._.js.map} +0 -0
  287. /package/.next/server/chunks/ssr/{node_modules__pnpm_1f3lm9p._.js.map → node_modules__pnpm_0og06fy._.js.map} +0 -0
  288. /package/.next/server/chunks/ssr/{node_modules__pnpm_12s6q4d._.js.map → node_modules__pnpm_0qc3gsk._.js.map} +0 -0
  289. /package/.next/server/chunks/ssr/{node_modules__pnpm_0e3u5g-._.js.map → node_modules__pnpm_0ts89ne._.js.map} +0 -0
  290. /package/.next/server/chunks/ssr/{node_modules__pnpm_1moe8b6._.js.map → node_modules__pnpm_0ttvopp._.js.map} +0 -0
  291. /package/.next/server/chunks/ssr/{node_modules__pnpm_1ly58kw._.js.map → node_modules__pnpm_0u3u82f._.js.map} +0 -0
  292. /package/.next/server/chunks/ssr/{node_modules__pnpm_1hw4h9e._.js.map → node_modules__pnpm_0y35hs4._.js.map} +0 -0
  293. /package/.next/server/chunks/ssr/{node_modules__pnpm_0jhh7p5._.js.map → node_modules__pnpm_104pzhc._.js.map} +0 -0
  294. /package/.next/server/chunks/ssr/{node_modules__pnpm_1gqkoe3._.js.map → node_modules__pnpm_195j8p_._.js.map} +0 -0
  295. /package/.next/server/chunks/ssr/{node_modules__pnpm_0i0uccx._.js.map → node_modules__pnpm_1l8k8w1._.js.map} +0 -0
  296. /package/.next/server/chunks/ssr/{node_modules__pnpm_0rd-a9g._.js.map → node_modules__pnpm_1w0f1m5._.js.map} +0 -0
  297. /package/.next/server/chunks/ssr/{node_modules__pnpm_1gtgu48._.js.map → node_modules__pnpm_1woddr6._.js.map} +0 -0
  298. /package/.next/server/chunks/ssr/{node_modules__pnpm_0_z3_bl._.js.map → node_modules__pnpm_1x0t5_z._.js.map} +0 -0
  299. /package/.next/server/chunks/ssr/{node_modules__pnpm_07_kgbe._.js.map → node_modules__pnpm_1xzf8g_._.js.map} +0 -0
  300. /package/.next/static/{ICaoXcRMmgrIFWk8C_Z6D → uJ5RYxgFnE5svAvnuLDXN}/_buildManifest.js +0 -0
  301. /package/.next/static/{ICaoXcRMmgrIFWk8C_Z6D → uJ5RYxgFnE5svAvnuLDXN}/_clientMiddlewareManifest.js +0 -0
  302. /package/.next/static/{ICaoXcRMmgrIFWk8C_Z6D → uJ5RYxgFnE5svAvnuLDXN}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/context/ChatContext.tsx","../../../../src/components/chat/QuestionCard.tsx","../../../../src/lib/plan.ts","../../../../src/lib/chats.ts"],"sourcesContent":["\"use client\"\n\n/**\n * Agent chats: one store for the sidebar list, the chat modal, the /chat page and the roadmap/board markers.\n * Each chat is its own `claude -p` session (POST /api/chat per turn); chats are saved to\n * .vibedoc/chats/<id>.json (/api/conversations) at turn end, card resolution and attach changes.\n */\n\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\"\nimport { usePathname, useRouter } from \"next/navigation\"\nimport { useApp } from \"@/context/AppContext\"\nimport type { Proposal, ProposalStatus } from \"@/components/chat/ProposalCard\"\nimport type { PlanCreated, PlanProposal, PlanStatus } from \"@/components/chat/PlanCard\"\nimport { formatAnswers, isRenderableQuestions, type Question, type QuestionSet } from \"@/components/chat/QuestionCard\"\nimport { asRenderablePlan, planTarget } from \"@/lib/plan\"\nimport type { TextEdit } from \"@/lib/diff\"\nimport { ASK_AGENT_EVENT, OPEN_CHAT_EVENT, openAgentChat, type AskAgentDetail } from \"@/lib/ask-agent\"\nimport {\n addChat, attachContext, attachKey, chatFor, chatStatus, chatTitle, defaultChat, epicOf, fromSaved, isWaiting,\n itemAgents, newChatId, newlyWaiting, patchChat, pendingReviews, routeAsk, toSaved, waitingTitle,\n type Attach, type Chat, type ChatStatus, type ItemAgent,\n} from \"@/lib/chats\"\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\"\n text: string\n tools: string[]\n proposals: Proposal[]\n plans: PlanProposal[]\n questions: QuestionSet[]\n error?: string\n}\n\nexport type ChatTab = Chat<ChatMessage>\n\nconst blank = (role: ChatMessage[\"role\"], text = \"\"): ChatMessage =>\n ({ role, text, tools: [], proposals: [], plans: [], questions: [] })\n\ninterface ChatApi {\n chats: ChatTab[]\n loaded: boolean\n /** Chat shown in the modal; null = closed */\n modalId: string | null\n /** keep: don't drop an empty chat (it is moving to the /chat page) */\n closeModal: (opts?: { keep?: boolean }) => void\n /** Open a chat: in the modal, or selected in place when already on /chat */\n show: (chatId: string) => void\n /** Header button / `c`: the most urgent or newest chat, else a fresh one */\n showDefault: () => void\n /** Resume the chat attached to `a`, or start one */\n showAbout: (a: Attach) => void\n /** A new empty chat (not saved until its first message); returns its id */\n create: (attach?: Attach | null) => string\n send: (chatId: string, text: string) => void\n stop: (chatId: string) => void\n /** Delete a chat (asks first when cards are unreviewed); returns false if the user cancelled */\n remove: (chatId: string) => boolean\n resolveProposal: (chatId: string, id: string, path: string, status: ProposalStatus) => void\n resolvePlan: (chatId: string, p: PlanProposal, status: PlanStatus, created: PlanCreated[], unchecked: string[]) => void\n answerQuestions: (chatId: string, set: QuestionSet, answers: string[]) => void\n /** attachKey → the most urgent chat working on that epic/task */\n agents: Record<string, ItemAgent>\n runningCount: number\n waitingCount: number\n /** An askAgent() refused at the running-chat cap */\n notice: string | null\n dismissNotice: () => void\n}\n\nconst ChatContext = createContext<ChatApi | null>(null)\n// Split out so roadmap nodes and board cards re-render only when some item's status flips, not per stream delta\nconst ItemAgentsContext = createContext<Record<string, ItemAgent>>({})\n\nexport function useChats(): ChatApi {\n const ctx = useContext(ChatContext)\n if (!ctx) throw new Error(\"useChats() must be used inside <ChatProvider>\")\n return ctx\n}\n\n/** The chat working on an epic/task, if any (roadmap nodes, sheets, board cards). */\nexport function useItemAgent(a: Attach): ItemAgent | undefined {\n return useContext(ItemAgentsContext)[attachKey(a)]\n}\n\nexport function ChatProvider({ children }: { children: ReactNode }) {\n const { rootParam, activeProject, selectedDoc } = useApp()\n const pathname = usePathname()\n const router = useRouter()\n const [chats, setChats] = useState<ChatTab[]>([])\n const [loaded, setLoaded] = useState(false)\n const [modalId, setModalId] = useState<string | null>(null)\n // The chat last shown (modal or page): where an askAgent() goes when that chat is idle\n const [currentId, setCurrentId] = useState<string | null>(null)\n const [notice, setNotice] = useState<string | null>(null)\n // One in-flight request per chat; a stream only ever writes into the chat id it was started for\n const abortsRef = useRef(new Map<string, AbortController>())\n // Chats changed since their last save; saved by the effect below once they aren't busy\n const dirtyRef = useRef(new Set<string>())\n const notifiedRef = useRef<Record<string, ChatStatus>>({})\n\n const onChatPage = pathname === \"/chat\"\n const docPath = pathname === \"/docs\" ? selectedDoc?.path : undefined\n\n // A Claude session belongs to one project: stop everything and load that project's chats\n useEffect(() => {\n for (const ac of abortsRef.current.values()) ac.abort()\n abortsRef.current.clear()\n dirtyRef.current.clear()\n let cancelled = false\n fetch(`/api/conversations${rootParam}`)\n .then((r) => (r.ok ? r.json() : { chats: [] }))\n .then((d: { chats?: unknown[] }) => {\n if (cancelled) return\n const loadedChats = (d.chats ?? []).map((c) => fromSaved<ChatMessage>(c)).filter((c): c is ChatTab => !!c)\n notifiedRef.current = Object.fromEntries(loadedChats.map((c) => [c.id, chatStatus(c)]))\n setChats(loadedChats)\n setModalId(null)\n setCurrentId(null)\n setLoaded(true)\n })\n .catch((e) => {\n console.warn(\"[vibedoc] could not load chats:\", e)\n if (!cancelled) { setChats([]); setLoaded(true) }\n })\n return () => { cancelled = true }\n }, [activeProject, rootParam])\n\n // Save chats marked dirty: at turn start (so a reload shows it as interrupted), turn end and card resolution.\n // Never per stream delta: nothing marks a chat dirty while it streams.\n useEffect(() => {\n for (const id of [...dirtyRef.current]) {\n const chat = chats.find((c) => c.id === id)\n dirtyRef.current.delete(id)\n const saved = chat && toSaved(chat)\n if (!saved) continue\n fetch(`/api/conversations${rootParam}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat: saved }),\n }).catch((e) => console.warn(`[vibedoc] could not save chat ${id}:`, e))\n }\n }, [chats, rootParam])\n\n // Reference-stable while no item's status changes (streaming text changes `chats` many times a second)\n const agentsRef = useRef<{ key: string; value: Record<string, ItemAgent> }>({ key: \"{}\", value: {} })\n const agents = useMemo(() => {\n const next = itemAgents(chats)\n const key = JSON.stringify(next)\n if (key !== agentsRef.current.key) agentsRef.current = { key, value: next }\n return agentsRef.current.value\n }, [chats])\n const runningCount = chats.filter((c) => c.busy).length\n const waitingCount = chats.filter((c) => isWaiting(chatStatus(c))).length\n\n // \"(n) VibeDoc\" in the browser tab; pathname is a dep because a navigation can put Next's metadata title back\n useEffect(() => { document.title = waitingTitle(document.title, waitingCount) }, [waitingCount, pathname])\n\n // Desktop notification when a chat starts waiting while this browser tab is in the background\n useEffect(() => {\n const fresh = newlyWaiting(notifiedRef.current, chats)\n notifiedRef.current = Object.fromEntries(chats.map((c) => [c.id, chatStatus(c)]))\n if (!fresh.length || !document.hidden || !(\"Notification\" in window) || Notification.permission !== \"granted\") return\n for (const { chat, status } of fresh) {\n const n = new Notification(status === \"needs-answer\" ? \"Agent needs your answer\" : \"Plan ready to review\", { body: chat.title, tag: chat.id })\n n.onclick = () => { window.focus(); openAgentChat(chat.id); n.close() }\n }\n }, [chats])\n\n function markDirty(id: string) { dirtyRef.current.add(id) }\n\n // A chat closed before its first message was never saved; drop it so empty chats don't pile up\n function closeModal(opts: { keep?: boolean } = {}) {\n if (!opts.keep) setChats((cs) => cs.filter((c) => c.id !== modalId || c.messages.length > 0))\n setModalId(null)\n }\n\n function show(chatId: string) {\n setCurrentId(chatId)\n if (onChatPage) {\n setModalId(null)\n router.replace(`/chat?id=${encodeURIComponent(chatId)}`, { scroll: false })\n } else {\n setModalId(chatId)\n }\n }\n\n function create(attach: Attach | null = null) {\n const id = newChatId(Date.now())\n setChats((cs) => addChat(cs, id, { attach }))\n return id\n }\n\n function showDefault() {\n const c = defaultChat(chats)\n show(c ? c.id : create())\n }\n\n function showAbout(a: Attach) {\n const c = chatFor(chats, a)\n show(c ? c.id : create(a))\n }\n\n // askAgent() from anywhere: into the current chat when it is idle, otherwise into a new one; then show it.\n // No deps on purpose: re-subscribes each render so the handler sees the current `chats`/`send`.\n useEffect(() => {\n function onAsk(e: Event) {\n const { message, newChat } = (e as CustomEvent<AskAgentDetail>).detail ?? {}\n if (!message) return\n // abortsRef is updated synchronously by send(), so it counts asks fired earlier in this same tick\n const route = routeAsk(chats, currentId, { newChat, running: abortsRef.current.size })\n if (\"refused\" in route) return setNotice(route.refused)\n setNotice(null)\n const epic = epicOf(message)\n const id = \"chatId\" in route ? route.chatId : create(epic ? { kind: \"epic\", id: epic } : null)\n send(id, message)\n // newChat asks (the multi-epic breakdown dialog) run in the background: the sidebar and roadmap show them\n if (!newChat) show(id)\n }\n function onOpen(e: Event) {\n const chatId = (e as CustomEvent<{ chatId: string }>).detail?.chatId\n if (chatId && chats.some((c) => c.id === chatId)) show(chatId)\n }\n window.addEventListener(ASK_AGENT_EVENT, onAsk)\n window.addEventListener(OPEN_CHAT_EVENT, onOpen)\n return () => {\n window.removeEventListener(ASK_AGENT_EVENT, onAsk)\n window.removeEventListener(OPEN_CHAT_EVENT, onOpen)\n }\n })\n\n function patchLast(chatId: string, fn: (m: ChatMessage) => ChatMessage) {\n setChats((cs) => patchChat(cs, chatId, (c) => ({ ...c, messages: [...c.messages.slice(0, -1), fn(c.messages[c.messages.length - 1])] })))\n }\n\n // Handles one line of `claude -p --output-format stream-json` for chat `chatId`\n function handleEvent(chatId: string, ev: any) {\n if (ev.session_id) setChats((cs) => patchChat(cs, chatId, (c) => (c.sessionId === ev.session_id ? c : { ...c, sessionId: ev.session_id })))\n if (ev.type === \"stream_event\") {\n const e = ev.event\n if (e?.type === \"message_start\") {\n patchLast(chatId, (m) => (m.text && !m.text.endsWith(\"\\n\\n\") ? { ...m, text: m.text + \"\\n\\n\" } : m))\n } else if (e?.type === \"content_block_delta\" && e.delta?.type === \"text_delta\") {\n patchLast(chatId, (m) => ({ ...m, text: m.text + e.delta.text }))\n }\n } else if (ev.type === \"assistant\") {\n const uses: { type: string; id: string; name: string; input: Record<string, unknown> }[] =\n (ev.message?.content ?? []).filter((b: { type: string }) => b.type === \"tool_use\")\n const proposals: Proposal[] = uses\n .filter((b) => b.name.endsWith(\"vibedoc_propose_edit\") && typeof b.input?.path === \"string\" && Array.isArray(b.input?.edits))\n .map((b) => ({\n id: b.id,\n path: b.input.path as string,\n edits: b.input.edits as TextEdit[],\n summary: typeof b.input.summary === \"string\" ? b.input.summary : undefined,\n status: \"pending\",\n }))\n // Cards render before the server validates the input, so drop shapes they can't draw instead of crashing\n const plans: PlanProposal[] = uses\n .filter((b) => b.name.endsWith(\"vibedoc_propose_plan\"))\n .flatMap((b) => {\n const plan = asRenderablePlan(b.input?.plan)\n return plan ? [{ id: b.id, plan, status: \"pending\" as const }] : []\n })\n const questions: QuestionSet[] = uses\n .filter((b) => b.name.endsWith(\"vibedoc_ask_questions\") && isRenderableQuestions(b.input?.questions))\n .map((b) => ({ id: b.id, questions: b.input.questions as Question[] }))\n const cards = [\"vibedoc_propose_edit\", \"vibedoc_propose_plan\", \"vibedoc_ask_questions\"]\n const tools = uses\n .filter((b) => !cards.some((c) => b.name.endsWith(c)))\n .map((b) => b.name.replace(/^mcp__vibedoc__vibedoc_/, \"\"))\n if (tools.length || proposals.length || plans.length || questions.length) {\n patchLast(chatId, (m) => ({\n ...m,\n tools: [...m.tools, ...tools],\n proposals: [...m.proposals, ...proposals],\n plans: [...m.plans, ...plans],\n questions: [...m.questions, ...questions],\n }))\n }\n } else if (ev.type === \"user\") {\n // A proposal the server rejected (bad old_string) is retried by the agent; don't show it\n const failed = new Set(\n (ev.message?.content ?? [])\n .filter((b: { type: string; is_error?: boolean }) => b.type === \"tool_result\" && b.is_error)\n .map((b: { tool_use_id: string }) => b.tool_use_id),\n )\n if (failed.size) {\n patchLast(chatId, (m) => ({\n ...m,\n proposals: m.proposals.filter((p) => !failed.has(p.id)),\n plans: m.plans.filter((p) => !failed.has(p.id)),\n questions: m.questions.filter((q) => !failed.has(q.id)),\n }))\n }\n } else if (ev.type === \"result\" && ev.is_error) {\n patchLast(chatId, (m) => ({ ...m, error: ev.result ?? ev.subtype ?? \"Agent error\" }))\n } else if (ev.type === \"error\") {\n patchLast(chatId, (m) => ({ ...m, error: ev.message }))\n }\n }\n\n // `chatId` may be a chat create() just queued, so a missing chat means a fresh one.\n async function send(chatId: string, text: string) {\n const message = text.trim()\n const chat = chats.find((c) => c.id === chatId)\n if (!message || chat?.busy) return\n // Ask once, from this click/Enter (browsers want a user gesture), so waiting chats can notify later\n if (\"Notification\" in window && Notification.permission === \"default\") void Notification.requestPermission().catch(() => {})\n const first = !chat?.messages.length\n const epic = epicOf(message)\n const attach: Attach | null = chat?.attach ?? (epic ? { kind: \"epic\", id: epic } : null)\n setChats((cs) => patchChat(cs, chatId, (c) => ({\n ...c,\n // An attached chat keeps its item title until the first message names what it's for\n title: c.messages.length ? c.title : chatTitle(message),\n attach: c.attach ?? attach,\n busy: true,\n notes: [],\n updatedAt: new Date().toISOString(),\n messages: [...c.messages, blank(\"user\", message), blank(\"assistant\")],\n })))\n markDirty(chatId)\n // Context only for a chat opened from an epic/task (showAbout); an ask like \"Break down epic R004…\" names it already\n const prefix = [\n ...(first && chat?.attach ? [attachContext(chat.attach)] : []),\n ...(chat?.notes.length ? [`[${chat.notes.join(\" \")}]`] : []),\n ]\n const outgoing = prefix.length ? `${prefix.join(\"\\n\")}\\n\\n${message}` : message\n const ac = new AbortController()\n abortsRef.current.set(chatId, ac)\n try {\n const res = await fetch(`/api/chat${rootParam}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message: outgoing, sessionId: chat?.sessionId ?? null, docPath }),\n signal: ac.signal,\n })\n if (!res.ok || !res.body) {\n const data = await res.json().catch(() => null)\n throw new Error(data?.error ?? `Request failed (${res.status})`)\n }\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buf = \"\"\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buf += decoder.decode(value, { stream: true })\n const lines = buf.split(\"\\n\")\n buf = lines.pop() ?? \"\"\n for (const line of lines) {\n if (!line.trim()) continue\n try { handleEvent(chatId, JSON.parse(line)) } catch { /* partial or non-JSON line */ }\n }\n }\n } catch (e) {\n if (!ac.signal.aborted) patchLast(chatId, (m) => ({ ...m, error: (e as Error).message }))\n else patchLast(chatId, (m) => (m.text || m.error ? m : { ...m, error: \"Stopped.\" }))\n } finally {\n // Only save a turn that is still ours: a project switch or delete clears the map first,\n // and saving then would write this chat into the next project (or resurrect a deleted one)\n if (abortsRef.current.get(chatId) === ac) {\n abortsRef.current.delete(chatId)\n markDirty(chatId)\n }\n setChats((cs) => patchChat(cs, chatId, (c) => ({ ...c, busy: false, updatedAt: new Date().toISOString() })))\n }\n }\n\n // Aborting the fetch makes /api/chat kill its `claude -p` child\n function stop(chatId: string) {\n abortsRef.current.get(chatId)?.abort()\n }\n\n function remove(chatId: string) {\n const chat = chats.find((c) => c.id === chatId)\n const n = chat ? pendingReviews(chat) : 0\n if (n && !window.confirm(`Discard ${n} unreviewed proposal${n === 1 ? \"\" : \"s\"}?`)) return false\n stop(chatId)\n abortsRef.current.delete(chatId)\n dirtyRef.current.delete(chatId)\n // Functional update so a stream chunk queued since this render isn't dropped from the other chats\n setChats((cs) => cs.filter((c) => c.id !== chatId))\n if (modalId === chatId) setModalId(null)\n if (currentId === chatId) setCurrentId(null)\n fetch(`/api/conversations${rootParam}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ delete: chatId }),\n }).catch((e) => console.warn(`[vibedoc] could not delete chat ${chatId}:`, e))\n return true\n }\n\n function mapMessages(chatId: string, fn: (m: ChatMessage) => ChatMessage, note?: string) {\n setChats((cs) => patchChat(cs, chatId, (c) => ({\n ...c,\n notes: note ? [...c.notes, note] : c.notes,\n messages: c.messages.map(fn),\n })))\n markDirty(chatId)\n }\n\n function resolveProposal(chatId: string, id: string, path: string, status: ProposalStatus) {\n mapMessages(chatId, (m) => ({\n ...m,\n proposals: m.proposals.map((p) => (p.id === id ? { ...p, status } : p)),\n }), `User ${status} your proposed edit to ${path}.`)\n }\n\n function resolvePlan(chatId: string, p: PlanProposal, status: PlanStatus, created: PlanCreated[], unchecked: string[]) {\n const epic = p.plan.kind === \"breakdown\" ? planTarget(p.plan) : \"the roadmap\"\n mapMessages(chatId, (m) => ({\n ...m,\n plans: m.plans.map((x) => (x.id === p.id ? { ...x, status, created } : x)),\n }), status === \"accepted\"\n ? `User accepted plan for ${epic}: created ${created.map((c) => c.id).join(\", \")}${unchecked.length ? ` (unchecked: ${unchecked.join(\", \")})` : \"\"}.`\n : `User rejected the plan for ${epic}.`)\n }\n\n function answerQuestions(chatId: string, set: QuestionSet, answers: string[]) {\n if (chats.find((c) => c.id === chatId)?.busy) return\n mapMessages(chatId, (m) => ({\n ...m,\n questions: m.questions.map((q) => (q.id === set.id ? { ...q, answers } : q)),\n }))\n send(chatId, formatAnswers(set.questions, answers))\n }\n\n const api: ChatApi = {\n chats, loaded, modalId,\n closeModal,\n show, showDefault, showAbout, create, send, stop, remove,\n resolveProposal, resolvePlan, answerQuestions,\n agents, runningCount, waitingCount,\n notice, dismissNotice: () => setNotice(null),\n }\n return (\n <ChatContext.Provider value={api}>\n <ItemAgentsContext.Provider value={agents}>{children}</ItemAgentsContext.Provider>\n </ChatContext.Provider>\n )\n}\n","\"use client\"\n\nimport { useState } from \"react\"\nimport { cn } from \"@/lib/utils\"\n\nexport interface QuestionOption { label: string; description?: string }\nexport interface Question { question: string; header: string; multiSelect: boolean; options: QuestionOption[] }\n\nexport interface QuestionSet {\n id: string\n questions: Question[]\n /** Set once submitted: one answer string per question, in the same order */\n answers?: string[]\n}\n\n/** Just enough shape to render, checked before the server has validated the tool input. */\nexport function isRenderableQuestions(v: unknown): v is Question[] {\n const isStr = (x: unknown) => typeof x === \"string\"\n return Array.isArray(v) && v.length > 0 && v.every((q) =>\n !!q && typeof q === \"object\" && isStr(q.question) && isStr(q.header) && Array.isArray(q.options) &&\n q.options.every((o: unknown) => !!o && typeof o === \"object\" && isStr((o as QuestionOption).label)))\n}\n\nconst OTHER = \"\\u0000other\"\n\n/** Answer message format the agent parses: one line per question, keyed by header, labels verbatim. */\nexport function formatAnswers(questions: Question[], answers: string[]): string {\n return [\"Answers:\", ...questions.map((q, i) => `- ${q.header}: ${answers[i]}`)].join(\"\\n\")\n}\n\nexport function QuestionCard({ set, disabled, onSubmit }: {\n set: QuestionSet\n disabled?: boolean\n onSubmit: (answers: string[]) => void\n}) {\n const [picked, setPicked] = useState<string[][]>(() => set.questions.map(() => []))\n const [other, setOther] = useState<string[]>(() => set.questions.map(() => \"\"))\n const done = !!set.answers\n\n function toggle(qi: number, value: string, multi: boolean) {\n setPicked((prev) => prev.map((p, i) => {\n if (i !== qi) return p\n if (!multi) return [value]\n return p.includes(value) ? p.filter((v) => v !== value) : [...p, value]\n }))\n }\n\n // Keep the order the options were offered in, with Other last\n const answers = set.questions.map((q, i) => {\n const labels = q.options.map((o) => o.label).filter((l) => picked[i].includes(l))\n if (picked[i].includes(OTHER) && other[i].trim()) labels.push(`Other: \"${other[i].trim()}\"`)\n return labels.join(\", \")\n })\n const complete = answers.every(Boolean)\n\n return (\n <div className=\"my-2 rounded-md border border-border overflow-hidden\" data-question-card>\n <div className=\"flex items-center gap-2 px-2 py-1.5 bg-surface2 border-b border-border\">\n <span className=\"text-[10px] font-mono uppercase tracking-widest text-muted\">Questions</span>\n {done && <span className=\"ml-auto text-[10px] font-mono text-accent\">✓ Answered</span>}\n </div>\n <div className=\"p-2 space-y-3\">\n {set.questions.map((q, qi) => (\n <fieldset key={qi} disabled={done} className=\"space-y-1\">\n <legend className=\"mb-1\">\n <span className=\"text-[10px] font-mono px-1.5 py-0.5 rounded-sm bg-surface2 border border-border text-accent mr-1.5\">{q.header}</span>\n <span className=\"text-xs text-txt\">{q.question}</span>\n </legend>\n {done ? (\n <p className=\"text-xs text-txt pl-1\">{set.answers?.[qi]}</p>\n ) : (\n <>\n {[...q.options, { label: \"Other\", value: OTHER }].map((o) => {\n const value = \"value\" in o ? o.value : o.label\n const checked = picked[qi].includes(value)\n return (\n <label key={value} className={cn(\"flex gap-2 items-start rounded-sm px-1 py-0.5 cursor-pointer hover:bg-surface2\", checked && \"bg-surface2\")}>\n <input\n type={q.multiSelect ? \"checkbox\" : \"radio\"}\n name={`${set.id}-${qi}`}\n checked={checked}\n onChange={() => toggle(qi, value, q.multiSelect)}\n className=\"mt-0.5 accent-accent\"\n />\n <span className=\"text-xs\">\n <span className=\"text-txt\">{o.label}</span>\n {\"description\" in o && o.description && <span className=\"block text-muted\">{o.description}</span>}\n </span>\n </label>\n )\n })}\n {picked[qi].includes(OTHER) && (\n <input\n value={other[qi]}\n onChange={(e) => setOther((prev) => prev.map((v, i) => (i === qi ? e.target.value : v)))}\n placeholder=\"Your answer\"\n aria-label={`Other answer for ${q.header}`}\n className=\"ml-6 w-[calc(100%-1.5rem)] rounded-sm bg-surface2 border border-border px-2 py-1 text-xs text-txt placeholder:text-muted focus:outline-hidden focus:border-accent\"\n />\n )}\n </>\n )}\n </fieldset>\n ))}\n {!done && (\n <button\n onClick={() => onSubmit(answers)}\n disabled={!complete || disabled}\n className=\"text-xs px-2 py-0.5 rounded-sm bg-accent/20 text-accent hover:bg-accent/30 disabled:opacity-50\"\n >\n Submit\n </button>\n )}\n </div>\n </div>\n )\n}\n","// Pure plan model for \"plan from the chat\": the agent proposes, the user reviews, the server applies.\n// No fs here; core.applyPlan() does the writing. Self-check: node src/lib/plan.check.mts\nimport type { RoadmapItem, RoadmapStatus } from './core'\n\nexport interface PlanTask {\n key: string // stable within the plan, e.g. \"t1\"; becomes a T id on apply\n title: string\n size?: string // \"S (~1 hr)\" | \"M (2–3 hrs)\" | \"L (half day)\"\n dependsOn?: string[] // keys in this plan, or existing task ids (\"T030\")\n due?: string // YYYY-MM-DD\n body: string // full markdown below the meta block: Goal, Context, Scope, Files, …\n}\nexport interface PlanHorizon { key: string; title: string; body?: string }\nexport interface PlanEpic { key: string; title: string; parent: string; status?: RoadmapStatus; body: string } // parent: existing horizon id or a horizon key\nexport interface PlanNewEpic { title: string; parent: string; body: string } // parent: existing horizon id\n/** breakdown: exactly one of `epic` (existing) or `newEpic`, or neither (loose tasks, no Phase). */\nexport type Plan =\n | { kind: 'breakdown'; epic?: string; newEpic?: PlanNewEpic; tasks: PlanTask[] }\n | { kind: 'roadmap'; horizons: PlanHorizon[]; epics: PlanEpic[] }\n\nexport interface PlanContext { roadmap: RoadmapItem[]; taskIds: string[] }\n\n/** A real calendar date \"YYYY-MM-DD\" (rejects 2026-02-30), else null. Same rule as core's parseDue. */\nfunction isDate(raw: string): boolean {\n const m = raw.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/)\n if (!m) return false\n return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3])).toISOString().slice(0, 10) === raw\n}\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\nconst str = (v: unknown) => (typeof v === 'string' ? v.trim() : '')\n\n/** Where a breakdown's tasks go, for one-line summaries: \"R002\", `new epic \"X\"`, or \"no epic\". */\nexport function planTarget(plan: Extract<Plan, { kind: 'breakdown' }>): string {\n if (str(plan.epic)) return str(plan.epic).toUpperCase()\n return plan.newEpic ? `new epic \"${str(plan.newEpic.title)}\"` : 'no epic'\n}\n\n/** An existing roadmap item that can parent an epic (a horizon), else the reason it can't. */\nfunction resolveHorizon(parent: string, roadmap: RoadmapItem[], missing = 'is not an existing roadmap item'): { id: string } | { error: string } {\n const p = roadmap.find(r => r.id === parent.toUpperCase())\n if (!p) return { error: `parent \"${parent}\" ${missing}` }\n if (p.parent !== null) return { error: `parent ${p.id} is an epic, not a horizon (max depth is 2)` }\n return { id: p.id }\n}\n\n/** Id of an existing item with this title under `parent` ('' = horizon level), case-insensitive. */\nconst titleTaken = (roadmap: RoadmapItem[], parent: string, title: string) =>\n roadmap.find(i => (i.parent ?? '') === parent && i.title.trim().toLowerCase() === title.toLowerCase())?.id\n\n/**\n * Just enough shape for the chat UI to render a proposal before the server has validated it\n * (the tool_use streams in before its tool_result). Returns null for anything a card can't draw.\n */\nexport function asRenderablePlan(p: unknown): Plan | null {\n if (!isObj(p)) return null\n const items = (v: unknown, need: string[]) => Array.isArray(v) && v.every(x =>\n isObj(x) && need.every(k => typeof x[k] === 'string') && (x.dependsOn === undefined || Array.isArray(x.dependsOn)))\n if (p.kind === 'breakdown') {\n const target = p.epic === undefined || typeof p.epic === 'string'\n const newEpic = p.newEpic === undefined || (isObj(p.newEpic) && typeof p.newEpic.title === 'string' && typeof p.newEpic.parent === 'string')\n return target && newEpic && items(p.tasks, ['key', 'title']) && (p.tasks as unknown[]).length > 0\n ? (p as unknown as Plan) : null\n }\n if (p.kind === 'roadmap') {\n const horizons = p.horizons ?? [], epics = p.epics ?? []\n return items(horizons, ['key', 'title']) && items(epics, ['key', 'title', 'parent'])\n ? ({ kind: 'roadmap', horizons, epics } as Plan) : null\n }\n return null\n}\n\n/** Every problem with the plan against the current files; [] = valid. */\nexport function validatePlan(plan: unknown, ctx: PlanContext): string[] {\n if (!isObj(plan)) return ['plan must be an object']\n if (plan.kind === 'roadmap') return validateRoadmapPlan(plan, ctx)\n if (plan.kind !== 'breakdown') return [`plan.kind must be \"breakdown\" or \"roadmap\" (got ${JSON.stringify(plan.kind)})`]\n\n const errors: string[] = []\n const epicId = str(plan.epic).toUpperCase()\n if (plan.epic !== undefined && typeof plan.epic !== 'string') errors.push('epic must be a string (an epic id)')\n else if (epicId && plan.newEpic !== undefined) errors.push('pass either epic (an existing epic) or newEpic, not both')\n else if (epicId) {\n const epic = ctx.roadmap.find(i => i.id === epicId)\n if (!epic) errors.push(`Epic ${JSON.stringify(plan.epic)} not found`)\n else if (!epic.parent) errors.push(`${epic.id} is a horizon, not an epic; pass an epic id`)\n } else if (plan.newEpic !== undefined) {\n const e = plan.newEpic\n if (!isObj(e)) errors.push('newEpic must be an object { title, parent, body }')\n else {\n const title = str(e.title), parent = str(e.parent)\n if (!title) errors.push('newEpic: title is required')\n if (typeof e.body !== 'string') errors.push('newEpic: body must be a markdown string')\n if (!parent) errors.push('newEpic: parent is required (an existing horizon id)')\n else {\n const h = resolveHorizon(parent, ctx.roadmap)\n if ('error' in h) errors.push(`newEpic: ${h.error}`)\n else if (title) {\n const other = titleTaken(ctx.roadmap, h.id, title)\n if (other) errors.push(`newEpic: \"${title}\" already exists under ${h.id} (${other})`)\n }\n }\n }\n }\n\n if (!Array.isArray(plan.tasks) || plan.tasks.length === 0) {\n errors.push('tasks must be a non-empty array')\n return errors\n }\n const tasks = plan.tasks as unknown[]\n const existing = new Set(ctx.taskIds.map(t => t.toUpperCase()))\n\n const index = new Map<string, number>()\n tasks.forEach((t, i) => {\n const key = isObj(t) ? str(t.key) : ''\n if (!key) errors.push(`task #${i + 1}: key is required`)\n else if (index.has(key)) errors.push(`duplicate key \"${key}\"`)\n else index.set(key, i)\n })\n\n const deps = new Map<string, string[]>() // key → plan keys it depends on\n tasks.forEach((t, i) => {\n if (!isObj(t)) { errors.push(`task #${i + 1} must be an object`); return }\n const label = str(t.key) || `task #${i + 1}`\n if (!str(t.title)) errors.push(`${label}: title is required`)\n if (typeof t.body !== 'string') errors.push(`${label}: body must be a markdown string`)\n if (t.size !== undefined && typeof t.size !== 'string') errors.push(`${label}: size must be a string`)\n if (t.due !== undefined && !(typeof t.due === 'string' && isDate(t.due))) {\n errors.push(`${label}: due must be a date YYYY-MM-DD (got ${JSON.stringify(t.due)})`)\n }\n if (t.dependsOn === undefined) return\n if (!Array.isArray(t.dependsOn)) { errors.push(`${label}: dependsOn must be an array`); return }\n const own: string[] = []\n for (const d of t.dependsOn) {\n const dep = str(d)\n if (index.has(dep)) own.push(dep)\n else if (!existing.has(dep.toUpperCase())) {\n errors.push(`${label}: dependsOn \"${String(d)}\" is neither a key in this plan nor an existing task`)\n }\n }\n if (str(t.key)) deps.set(str(t.key), own)\n })\n\n // Cycles (DFS, report each once), then forward references: apply creates in order,\n // so a dependency must come earlier in the list to already have its T id.\n const state = new Map<string, 'open' | 'done'>()\n const cyclic = new Set<string>()\n const visit = (k: string, stack: string[]) => {\n if (state.get(k) === 'done') return\n if (state.get(k) === 'open') {\n const cycle = [...stack.slice(stack.indexOf(k)), k]\n if (!cycle.some(c => cyclic.has(c))) errors.push(`dependency cycle: ${cycle.join(' → ')}`)\n cycle.forEach(c => cyclic.add(c))\n return\n }\n state.set(k, 'open')\n for (const d of deps.get(k) ?? []) visit(d, [...stack, k])\n state.set(k, 'done')\n }\n for (const k of deps.keys()) visit(k, [])\n for (const [k, ds] of deps) {\n if (cyclic.has(k)) continue\n for (const d of ds) {\n if ((index.get(d) ?? 0) > (index.get(k) ?? 0)) errors.push(`${k} depends on ${d}, which comes later; list ${d} first`)\n }\n }\n return errors\n}\n\nconst STATUSES = ['planned', 'in-progress', 'done']\n\nfunction validateRoadmapPlan(plan: Record<string, unknown>, ctx: PlanContext): string[] {\n const errors: string[] = []\n const horizons = plan.horizons ?? []\n const epics = plan.epics ?? []\n if (!Array.isArray(horizons)) errors.push('horizons must be an array')\n if (!Array.isArray(epics)) errors.push('epics must be an array')\n if (errors.length > 0) return errors\n const hs = horizons as unknown[]\n const es = epics as unknown[]\n if (hs.length + es.length === 0) return ['a roadmap plan needs at least one horizon or epic']\n\n const keys = new Set<string>()\n const horizonKeys = new Set<string>()\n const checkKey = (v: unknown, label: string, isHorizon: boolean) => {\n const key = isObj(v) ? str(v.key) : ''\n if (!key) errors.push(`${label}: key is required`)\n else if (keys.has(key)) errors.push(`duplicate key \"${key}\"`)\n else { keys.add(key); if (isHorizon) horizonKeys.add(key) }\n }\n hs.forEach((h, i) => checkKey(h, `horizon #${i + 1}`, true))\n es.forEach((e, i) => checkKey(e, `epic #${i + 1}`, false))\n\n // Titles are unique per level (spine, or one horizon), against existing items and within the plan.\n const seen = new Map<string, string>() // \"parent\\0title\" → who in this plan has it\n const claimTitle = (parent: string, title: string, label: string) => {\n const k = `${parent}\\0${title.toLowerCase()}`\n const other = titleTaken(ctx.roadmap, parent, title) ?? seen.get(k)\n if (other) errors.push(`${label}: \"${title}\" already exists ${parent ? `under ${parent}` : 'as a horizon'} (${other})`)\n else seen.set(k, label)\n }\n\n hs.forEach((h, i) => {\n if (!isObj(h)) { errors.push(`horizon #${i + 1} must be an object`); return }\n const label = str(h.key) || `horizon #${i + 1}`\n const title = str(h.title)\n if (!title) errors.push(`${label}: title is required`)\n else claimTitle('', title, label)\n if (h.body !== undefined && typeof h.body !== 'string') errors.push(`${label}: body must be a markdown string`)\n })\n\n es.forEach((e, i) => {\n if (!isObj(e)) { errors.push(`epic #${i + 1} must be an object`); return }\n const label = str(e.key) || `epic #${i + 1}`\n const title = str(e.title)\n if (!title) errors.push(`${label}: title is required`)\n if (typeof e.body !== 'string') errors.push(`${label}: body must be a markdown string`)\n if (e.status !== undefined && !STATUSES.includes(e.status as string)) {\n errors.push(`${label}: status must be one of ${STATUSES.join(', ')} (got ${JSON.stringify(e.status)})`)\n }\n const parent = str(e.parent)\n let parentId = ''\n if (!parent) errors.push(`${label}: parent is required (an existing horizon id or a horizon key in this plan)`)\n else if (horizonKeys.has(parent)) parentId = parent\n else if (keys.has(parent)) errors.push(`${label}: parent \"${parent}\" is an epic in this plan; an epic's parent must be a horizon`)\n else {\n const h = resolveHorizon(parent, ctx.roadmap, 'is neither a horizon key in this plan nor an existing roadmap item')\n if ('id' in h) parentId = h.id\n else errors.push(`${label}: ${h.error}`)\n }\n if (title && parentId) claimTitle(parentId, title, label)\n })\n return errors\n}\n\n/** Keep only the selected items. A kept item depending on an unchecked one is an error. */\nexport function selectPlan(plan: Plan, selected: string[]): { plan: Plan; errors: string[] } {\n if (plan.kind === 'roadmap') return selectRoadmapPlan(plan, selected)\n const errors: string[] = []\n // Trim like validatePlan/applyPlan do, or \" t1 \" vs \"t1\" slips past the unchecked-dependency check\n const keys = new Set(plan.tasks.map(t => t.key.trim()))\n const sel = new Set(selected.map(k => k.trim()))\n for (const k of sel) if (!keys.has(k)) errors.push(`unknown key \"${k}\"`)\n const tasks = plan.tasks.filter(t => sel.has(t.key.trim()))\n if (tasks.length === 0) errors.push('nothing selected')\n for (const t of tasks) {\n for (const d of (t.dependsOn ?? []).map(d => d.trim())) {\n if (keys.has(d) && !sel.has(d)) errors.push(`${t.key.trim()} depends on ${d}, which you unchecked`)\n }\n }\n return { plan: { ...plan, tasks }, errors }\n}\n\nfunction selectRoadmapPlan(plan: Extract<Plan, { kind: 'roadmap' }>, selected: string[]): { plan: Plan; errors: string[] } {\n const errors: string[] = []\n const horizons = plan.horizons ?? []\n const epics = plan.epics ?? []\n const hKeys = new Set(horizons.map(h => h.key))\n const keys = new Set([...hKeys, ...epics.map(e => e.key)])\n const sel = new Set(selected)\n for (const k of sel) if (!keys.has(k)) errors.push(`unknown key \"${k}\"`)\n const keptH = horizons.filter(h => sel.has(h.key))\n const keptE = epics.filter(e => sel.has(e.key))\n if (keptH.length + keptE.length === 0) errors.push('nothing selected')\n for (const e of keptE) {\n const p = e.parent.trim()\n if (hKeys.has(p) && !sel.has(p)) errors.push(`${e.key} is under ${p}, which you unchecked; check ${p} or uncheck ${e.key}`)\n }\n return { plan: { ...plan, horizons: keptH, epics: keptE }, errors }\n}\n","// Pure helpers for agent chats (ChatContext, ChatView, sidebar, /chat page). No React, no fs:\n// `node src/lib/chats.check.mts` runs them.\n\n/** What a chat is about: the roadmap/board show its status there, and the first turn tells the agent. */\nexport interface Attach { kind: \"epic\" | \"task\"; id: string }\n\nexport interface Chat<M = unknown> {\n id: string\n title: string\n messages: M[]\n /** Claude session to `--resume`; set by the first `session_id` in the stream */\n sessionId: string | null\n busy: boolean\n /** Accept/reject outcomes the agent hasn't heard about yet; sent with this chat's next message */\n notes: string[]\n attach: Attach | null\n createdAt: string\n updatedAt: string\n}\n\nexport function newChatId(now: number, salt = Math.random()): string {\n return `c-${now.toString(36)}${salt.toString(36).slice(2, 6)}`\n}\n\nexport function addChat<M>(chats: Chat<M>[], id: string, opts: { title?: string; attach?: Attach | null; now?: string } = {}): Chat<M>[] {\n const now = opts.now ?? new Date().toISOString()\n const title = opts.title ?? (opts.attach ? attachTitle(opts.attach) : \"New chat\")\n return [...chats, { id, title, messages: [], sessionId: null, busy: false, notes: [], attach: opts.attach ?? null, createdAt: now, updatedAt: now }]\n}\n\n/** A missing id (e.g. a closed chat whose stream is still unwinding) is a no-op. */\nexport function patchChat<M>(chats: Chat<M>[], id: string, fn: (c: Chat<M>) => Chat<M>): Chat<M>[] {\n return chats.map((c) => (c.id === id ? fn(c) : c))\n}\n\n/** The fields of a chat message the status reads (ChatContext's ChatMessage has more). */\nexport interface StatusMessage {\n role: \"user\" | \"assistant\"\n text?: string\n tools?: unknown[]\n questions: { answers?: unknown }[]\n proposals: { status: string }[]\n plans: { status: string }[]\n error?: string\n}\n\nexport type ChatStatus = \"running\" | \"needs-answer\" | \"review\" | \"idle\" | \"error\"\n\nexport const STATUS_LABEL: Record<ChatStatus, string> = {\n running: \"Running\",\n \"needs-answer\": \"Waiting for your answers\",\n review: \"Plan or edit to review\",\n error: \"Error\",\n idle: \"Idle\",\n}\n\n/** Plan and edit cards the user hasn't accepted or rejected yet, across the whole chat. */\nexport function pendingReviews(chat: Chat<StatusMessage>): number {\n return chat.messages.reduce(\n (n, m) => n + m.plans.filter((p) => p.status === \"pending\").length + m.proposals.filter((p) => p.status === \"pending\").length,\n 0,\n )\n}\n\n/** Precedence: running > needs-answer > review > error > idle. */\nexport function chatStatus(chat: Chat<StatusMessage>): ChatStatus {\n if (chat.busy) return \"running\"\n const last = chat.messages[chat.messages.length - 1]\n // Same rule as the composer hint: only the latest reply's questions block\n if (last?.questions.some((q) => !q.answers)) return \"needs-answer\"\n if (pendingReviews(chat)) return \"review\"\n const lastReply = chat.messages.findLast((m) => m.role === \"assistant\")\n return lastReply?.error ? \"error\" : \"idle\"\n}\n\nexport const isWaiting = (s: ChatStatus): s is \"needs-answer\" | \"review\" => s === \"needs-answer\" || s === \"review\"\n\n/** Each running chat is one `claude -p` process. */\nexport const MAX_RUNNING_CHATS = 4\nexport const TOO_MANY_CHATS = `Too many agents running (${MAX_RUNNING_CHATS}). Stop or close a chat, or wait.`\n\n/**\n * Where an askAgent() message goes: the current chat when it is idle, otherwise a new chat.\n * Refused at the cap. `running` overrides the busy count when `chats` may be stale (several asks in one tick).\n */\nexport function routeAsk(\n chats: Chat[],\n currentId: string | null,\n opts: { newChat?: boolean; running?: number } = {},\n): { chatId: string } | { newChat: true } | { refused: string } {\n if ((opts.running ?? chats.filter((c) => c.busy).length) >= MAX_RUNNING_CHATS) return { refused: TOO_MANY_CHATS }\n const current = chats.find((c) => c.id === currentId)\n return current && !current.busy && !opts.newChat ? { chatId: current.id } : { newChat: true }\n}\n\n// ─── Attachments ──────────────────────────────────────────────────────────────\n\nexport const attachKey = (a: Attach) => `${a.kind}:${a.id}`\nexport const sameAttach = (a: Attach | null, b: Attach | null) => !!a && !!b && a.kind === b.kind && a.id === b.id\n\nexport function attachTitle(a: Attach): string {\n return a.kind === \"epic\" ? `Epic ${a.id}` : `Task ${a.id}`\n}\n\n/** The epic a message asks to break down: the roadmap's \"Break down with agent\" wording, or the same typed by hand. */\nexport function epicOf(message: string): string | null {\n return message.trim().match(/^Break down epic (R\\d+)/i)?.[1].toUpperCase() ?? null\n}\n\n/** The chat to resume for `a`: the most recently updated one attached to it. */\nexport function chatFor<C extends Chat>(chats: C[], a: Attach): C | undefined {\n return chats.filter((c) => sameAttach(c.attach, a)).sort((x, y) => y.updatedAt.localeCompare(x.updatedAt))[0]\n}\n\n/** What the roadmap/board show on an item while a chat works on it. Idle and errored chats show nothing. */\nexport interface ItemAgent { status: \"running\" | \"needs-answer\" | \"review\"; chatId: string }\n\nconst RANK = { running: 3, \"needs-answer\": 2, review: 1 } as const\n\n/** attachKey → the most urgent chat on it (running > needs-answer > review). */\nexport function itemAgents(chats: Chat<StatusMessage>[]): Record<string, ItemAgent> {\n const out: Record<string, ItemAgent> = {}\n for (const c of chats) {\n const status = chatStatus(c)\n if (!c.attach || status === \"idle\" || status === \"error\") continue\n const key = attachKey(c.attach)\n const cur = out[key]\n if (!cur || RANK[status] > RANK[cur.status]) out[key] = { status, chatId: c.id }\n }\n return out\n}\n\n/** First-turn context for an attached chat; later turns resume the Claude session, which remembers it. */\nexport function attachContext(a: Attach): string {\n return a.kind === \"epic\"\n ? `[This chat is about epic ${a.id}. Read it with vibedoc_get_roadmap (and its tasks with vibedoc_get_task) before answering.]`\n : `[This chat is about task ${a.id}. Read it with vibedoc_get_task before answering.]`\n}\n\n/** Starter prompts shown in an empty chat. Each is something the agent can do with only the vibedoc_* tools. */\nexport function suggestions(a: Attach | null): string[] {\n if (!a) return [\"What should I work on next?\", \"Plan a roadmap for this project.\", \"What is blocked right now?\"]\n if (a.kind === \"epic\") return [`Break down epic ${a.id} into tasks.`, \"Summarize this epic's progress.\", \"What is at risk in this epic?\"]\n return [\"Refine this task's spec.\", \"Split this task into smaller tasks.\", \"What blocks this task?\"]\n}\n\n// ─── Lists ────────────────────────────────────────────────────────────────────\n\nexport interface ChatGroups<C> { needsYou: C[]; running: C[]; recent: C[] }\n\n/** Sidebar and /chat list order: waiting on you, then running, then the rest; newest first within a group. */\nexport function groupChats<C extends Chat<StatusMessage>>(chats: C[]): ChatGroups<C> {\n const byNew = [...chats].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))\n const groups: ChatGroups<C> = { needsYou: [], running: [], recent: [] }\n for (const c of byNew) {\n const s = chatStatus(c)\n if (isWaiting(s)) groups.needsYou.push(c)\n else if (s === \"running\") groups.running.push(c)\n else groups.recent.push(c)\n }\n return groups\n}\n\n/** The chat the header button / `c` opens: the most urgent, else the newest, else none. */\nexport function defaultChat<C extends Chat<StatusMessage>>(chats: C[]): C | undefined {\n const g = groupChats(chats)\n return g.needsYou[0] ?? g.running[0] ?? g.recent[0]\n}\n\n// ─── Persistence (.vibedoc/chats/<id>.json via /api/conversations) ───────────\n\n/** What gets saved: never busy (a running turn can't survive a reload). Empty chats aren't saved. */\nexport function toSaved<M>(c: Chat<M>): Chat<M> | null {\n return c.messages.length ? { ...c, busy: false } : null\n}\n\n/** A saved chat as loaded: a turn that was cut off (empty last reply, no error) gets an \"interrupted\" error. */\nexport function fromSaved<M extends StatusMessage>(raw: unknown): Chat<M> | null {\n const c = raw as Chat<M> | null\n if (!c || typeof c.id !== \"string\" || !Array.isArray(c.messages)) return null\n const last = c.messages[c.messages.length - 1]\n const cut = last?.role === \"assistant\" && !last.text && !last.error && !last.tools?.length && !last.plans?.length && !last.proposals?.length && !last.questions?.length\n const messages = cut ? [...c.messages.slice(0, -1), { ...last, error: \"Interrupted: the page reloaded while the agent was working.\" }] : c.messages\n const at = c.updatedAt ?? c.createdAt ?? new Date(0).toISOString()\n return { ...c, messages, busy: false, notes: c.notes ?? [], attach: c.attach ?? null, createdAt: c.createdAt ?? at, updatedAt: at }\n}\n\n// ─── Waiting on the user: header badge, page title, desktop notification ─────\n\n/** Chats that became waiting since `prev` (id → last status), so each one notifies once per change. */\nexport function newlyWaiting<C extends Chat<StatusMessage>>(prev: Record<string, ChatStatus>, chats: C[]): { chat: C; status: \"needs-answer\" | \"review\" }[] {\n return chats.flatMap((chat) => {\n const status = chatStatus(chat)\n return isWaiting(status) && prev[chat.id] !== status ? [{ chat, status }] : []\n })\n}\n\n/** \"(2) VibeDoc\" while 2 chats wait; the plain title otherwise. Idempotent. */\nexport function waitingTitle(title: string, n: number): string {\n const base = title.replace(/^\\(\\d+\\) /, \"\")\n return n > 0 ? `(${n}) ${base}` : base\n}\n\nexport function chatTitle(firstMessage: string): string {\n const epic = epicOf(firstMessage)\n if (epic) return `Break down ${epic}`\n const line = firstMessage.trim().split(\"\\n\")[0]\n return line.length > 40 ? `${line.slice(0, 40).trimEnd()}…` : line\n}\n\n/** \"now\", \"5m\", \"3h\", \"2d\" since `iso` (list rows). */\nexport function ago(iso: string, nowMs: number): string {\n const min = Math.max(0, Math.floor((nowMs - Date.parse(iso)) / 60_000))\n if (min < 1) return \"now\"\n if (min < 60) return `${min}m`\n if (min < 60 * 24) return `${Math.floor(min / 60)}h`\n return `${Math.floor(min / (60 * 24))}d`\n}\n"],"names":["isRenderableQuestions","v","isStr","x","Array","isArray","length","every","q","question","header","options","o","label","OTHER","formatAnswers","questions","answers","map","i","join","QuestionCard","set","disabled","onSubmit","picked","setPicked","other","setOther","done","toggle","qi","value","multi","prev","p","includes","filter","labels","l","trim","push","complete","Boolean","className","checked","type","multiSelect","name","id","onChange","description","e","target","placeholder","onClick"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- module.exports=[72551,a=>{"use strict";var b=a.i(256857);let c={name:"search",size:24,node:[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]]};c.node;let d=(0,b.default)(c);a.s(["Search",0,d],72551)},694194,a=>{"use strict";let b=[{id:"claude-md",name:"CLAUDE.md",description:"AI agent instructions for Claude Code",defaultPath:"CLAUDE.md",category:"ai-agent",content:`# {{PROJECT_NAME}} — Agent Instructions
1
+ module.exports=[694194,a=>{"use strict";let b=[{id:"claude-md",name:"CLAUDE.md",description:"AI agent instructions for Claude Code",defaultPath:"CLAUDE.md",category:"ai-agent",content:`# {{PROJECT_NAME}} — Agent Instructions
2
2
 
3
3
  ## What this is
4
4
  {{DESCRIPTION}}
@@ -2106,4 +2106,4 @@ readinessProbe:
2106
2106
  <!-- Key takeaways to share with the wider team -->
2107
2107
  `}];a.s(["TEMPLATES",0,f],694194)}];
2108
2108
 
2109
- //# sourceMappingURL=_1wf14_u._.js.map
2109
+ //# sourceMappingURL=src_lib_templates_index_ts_1s61uk7._.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../node_modules/.pnpm/lucide-react%401.48.0_react%4019.3.0/node_modules/lucide-react/src/icons/search.ts","../../../../src/lib/templates/ai-agent.ts","../../../../src/lib/templates/github.ts","../../../../src/lib/templates/process.ts","../../../../src/lib/templates/technical.ts","../../../../src/lib/templates/infrastructure.ts","../../../../src/lib/templates/github-actions.ts","../../../../src/lib/templates/code-quality.ts","../../../../src/lib/templates/monitoring.ts","../../../../src/lib/templates/index.ts"],"sourcesContent":["import createLucideIcon from '../createLucideIcon';\nimport type { LucideIconNode, LucideIconData } from '../types';\n\nexport const __iconData: LucideIconData = {\n name: 'search',\n size: 24,\n node: [\n ['path', { d: 'm21 21-4.34-4.34', key: '14j7rj' }],\n ['circle', { cx: '11', cy: '11', r: '8', key: '4ej97u' }],\n ],\n};\n\n/**\n * @deprecated Access `__iconData` instead.\n */\nexport const __iconNode: LucideIconNode[] = __iconData.node;\n\n/**\n * @component @name Search\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtMjEgMjEtNC4zNC00LjM0IiAvPgogIDxjaXJjbGUgY3g9IjExIiBjeT0iMTEiIHI9IjgiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/search\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Search = createLucideIcon(__iconData);\n\nexport default Search;\n","import type { Template } from './types'\r\n\r\nexport const AI_AGENT_TEMPLATES: Template[] = [\r\n {\r\n id: 'claude-md',\r\n name: 'CLAUDE.md',\r\n description: 'AI agent instructions for Claude Code',\r\n defaultPath: 'CLAUDE.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Agent Instructions\r\n\r\n## What this is\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Project type\r\n{{PROJECT_TYPE}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\n# Install dependencies\r\n{{PACKAGE_MANAGER}} install\r\n\r\n# Start development\r\nnpm run dev\r\n\r\n# Build for production\r\nnpm run build\r\n\r\n# Run tests\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Architecture\r\n- Primary language: {{PRIMARY_LANGUAGE}}\r\n- Deployment: {{DEPLOYMENT_PLATFORM}}\r\n- Key directories: \\`src/\\`, \\`docs/\\`, \\`tests/\\`\r\n- See \\`docs/architecture/overview.md\\` for full details\r\n\r\n## Read before coding\r\n- @docs/architecture/overview.md\r\n- @CONTRIBUTING.md\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Key features\r\n{{KEY_FEATURES}}\r\n\r\n## Non-negotiables\r\n- Always run \\`npm run build\\` before marking a task done — build must pass\r\n- Never use localStorage — causes SSR/client mismatch\r\n- Never commit secrets or credentials\r\n- Maintain test coverage\r\n- Follow security best practices\r\n\r\n## Code style\r\n- Follow existing patterns before introducing new abstractions\r\n- Keep modules small and focused\r\n- Write tests for business logic\r\n- Prefer explicit over implicit\r\n`,\r\n },\r\n {\r\n id: 'agents-md',\r\n name: 'AGENTS.md',\r\n description: 'AI agent instructions (multi-agent / OpenAI)',\r\n defaultPath: 'AGENTS.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Agent Instructions\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\nnpm install\r\nnpm run dev\r\nnpm run build\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Follow existing code patterns\r\n- Write tests for new features\r\n- Never commit secrets or credentials\r\n`,\r\n },\r\n {\r\n id: 'gemini-md',\r\n name: 'GEMINI.md',\r\n description: 'AI agent instructions for Gemini CLI',\r\n defaultPath: 'GEMINI.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Gemini Agent Instructions\r\n\r\n## What this is\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\n# Install dependencies\r\nnpm install\r\n\r\n# Start development\r\nnpm run dev\r\n\r\n# Build for production\r\nnpm run build\r\n\r\n# Run tests\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Follow existing code patterns\r\n- Write tests for new features\r\n- Never commit secrets or credentials\r\n`,\r\n },\r\n {\r\n id: 'cursorrules',\r\n name: '.cursorrules',\r\n description: 'Cursor IDE rules for AI assistance',\r\n defaultPath: '.cursorrules',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Cursor Rules\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Code style\r\n- Use {{TECH_STACK}} conventions\r\n- Follow existing patterns in the codebase\r\n- Prefer explicit over implicit\r\n- Keep functions small and focused\r\n\r\n## Conventions\r\n{{CONVENTIONS}}\r\n\r\n## What NOT to do\r\n- Don't introduce new dependencies without discussion\r\n- Don't break existing tests\r\n- Don't commit secrets or credentials\r\n- Don't over-engineer simple solutions\r\n`,\r\n },\r\n {\r\n id: 'windsurfrules',\r\n name: '.windsurfrules',\r\n description: 'Windsurf IDE rules for AI assistance',\r\n defaultPath: '.windsurfrules',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Windsurf Rules\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Code style\r\n- Follow existing patterns in the codebase\r\n- Prefer explicit over implicit\r\n- Keep functions small and focused\r\n\r\n## Conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Don't introduce breaking changes\r\n- Don't commit secrets or credentials\r\n- Maintain test coverage\r\n`,\r\n },\r\n {\r\n id: 'copilot-instructions',\r\n name: 'Copilot Instructions',\r\n description: 'GitHub Copilot custom instructions',\r\n defaultPath: '.github/copilot-instructions.md',\r\n category: 'ai-agent',\r\n content: `# GitHub Copilot Instructions — {{PROJECT_NAME}}\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Coding conventions\r\n{{CONVENTIONS}}\r\n\r\n## Key features\r\n{{KEY_FEATURES}}\r\n\r\n## Style guidelines\r\n- Follow existing patterns before creating new abstractions\r\n- Write descriptive variable and function names\r\n- Add comments for non-obvious logic only\r\n- Keep functions focused on a single responsibility\r\n\r\n## Testing\r\n- Write tests for all new functionality\r\n- Maintain existing test coverage\r\n- Use the project's established testing patterns\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const GITHUB_TEMPLATES: Template[] = [\r\n {\r\n id: 'contributing',\r\n name: 'CONTRIBUTING.md',\r\n description: 'Contribution guidelines',\r\n defaultPath: 'CONTRIBUTING.md',\r\n category: 'github',\r\n content: `# Contributing to {{PROJECT_NAME}}\r\n\r\nThank you for your interest in contributing!\r\n\r\n## Getting started\r\n\r\n1. Fork the repository\r\n2. Clone your fork: \\`git clone {{REPO_URL}}\\`\r\n3. Create a feature branch: \\`git checkout -b feat/your-feature\\`\r\n4. Make your changes\r\n5. Submit a pull request\r\n\r\n## Branch naming\r\n\r\n| Type | Pattern | Example |\r\n|------|---------|---------|\r\n| Feature | \\`feat/<description>\\` | \\`feat/user-auth\\` |\r\n| Fix | \\`fix/<description>\\` | \\`fix/login-crash\\` |\r\n| Chore | \\`chore/<description>\\` | \\`chore/update-deps\\` |\r\n| Docs | \\`docs/<description>\\` | \\`docs/api-guide\\` |\r\n| Refactor | \\`refactor/<description>\\` | \\`refactor/auth-module\\` |\r\n| Release | \\`release/<version>\\` | \\`release/v1.2.0\\` |\r\n\r\n## Commit conventions\r\n\r\nWe use [Conventional Commits](https://conventionalcommits.org):\r\n\r\n| Type | When to use |\r\n|------|------------|\r\n| \\`feat\\` | New feature |\r\n| \\`fix\\` | Bug fix |\r\n| \\`docs\\` | Documentation only |\r\n| \\`refactor\\` | Code change that's neither fix nor feature |\r\n| \\`test\\` | Adding or updating tests |\r\n| \\`chore\\` | Build process, dependencies, tooling |\r\n| \\`perf\\` | Performance improvement |\r\n| \\`ci\\` | CI/CD changes |\r\n\r\nExamples:\r\n\\`\\`\\`\r\nfeat: add user authentication\r\nfix: resolve login redirect issue\r\ndocs: update API reference\r\nchore: upgrade dependencies\r\nfeat!: redesign auth API (breaking change — note the !)\r\n\\`\\`\\`\r\n\r\n## PR size guidance\r\n\r\n| Size | Lines changed | Guidance |\r\n|------|--------------|---------|\r\n| Small | < 400 lines | Ideal — fast to review |\r\n| Medium | 400–800 lines | Acceptable — add extra context in description |\r\n| Large | > 800 lines | Needs discussion before opening — split if possible |\r\n\r\nLarge PRs slow down the team and increase the chance of missed issues. When in doubt, split.\r\n\r\n## Pull request process\r\n\r\n1. Fill out the PR template completely\r\n2. Ensure all CI checks pass\r\n3. Request review from at least one maintainer\r\n4. Address all review comments\r\n5. Squash commits before merge\r\n\r\n## Code review checklist\r\n\r\n**Author:**\r\n- [ ] Self-reviewed the diff before requesting review\r\n- [ ] PR description explains the \"why\", not just the \"what\"\r\n- [ ] Tests added/updated and passing\r\n- [ ] No secrets or credentials in code\r\n- [ ] Breaking changes noted in PR description\r\n\r\n**Reviewer:**\r\n- [ ] Code is correct and handles edge cases\r\n- [ ] No obvious performance issues\r\n- [ ] Tests are meaningful (not just coverage padding)\r\n- [ ] Naming is clear and consistent with the codebase\r\n- [ ] Documentation updated if public API changed\r\n\r\n## Code style\r\n{{CONVENTIONS}}\r\n\r\n## Reporting bugs\r\n\r\nOpen an issue with:\r\n- Description of the bug\r\n- Steps to reproduce\r\n- Expected vs actual behavior\r\n- Environment details\r\n`,\r\n },\r\n {\r\n id: 'security',\r\n name: 'SECURITY.md',\r\n description: 'Security policy and vulnerability reporting',\r\n defaultPath: 'SECURITY.md',\r\n category: 'github',\r\n content: `# Security Policy — {{PROJECT_NAME}}\r\n\r\n## Supported versions\r\n\r\n| Version | Supported |\r\n|---------|-----------|\r\n| latest | ✅ |\r\n| < 1.0 | ❌ |\r\n\r\n## Reporting a vulnerability\r\n\r\n**Please do not report security vulnerabilities through public GitHub issues.**\r\n\r\nTo report a security issue, email: **security@example.com**\r\n\r\nYou may optionally encrypt your report using our PGP key (key ID: \\`0x00000000\\`, available on keys.openpgp.org).\r\n\r\nInclude:\r\n- Description of the vulnerability\r\n- Steps to reproduce\r\n- Potential impact\r\n- Any suggested mitigations\r\n\r\nYou will receive a response within **48 hours**. We will:\r\n1. Confirm receipt of your report\r\n2. Investigate and assess the issue\r\n3. Release a fix or mitigation\r\n4. Credit you in the release notes (unless you prefer anonymity)\r\n\r\n## Vulnerability SLAs\r\n\r\n| Severity | Fix SLA |\r\n|----------|---------|\r\n| Critical | 48 hours |\r\n| High | 7 days |\r\n| Medium | 30 days |\r\n| Low | 90 days |\r\n\r\nDependabot alerts for **critical** vulnerabilities must be resolved within 48 hours. Run \\`npm audit\\` in CI on every PR.\r\n\r\n## Secrets rotation schedule\r\n\r\n| Secret | Rotation | Owner |\r\n|--------|----------|-------|\r\n| JWT signing key | Every 90 days | Platform team |\r\n| Database passwords | Every 180 days | Platform team |\r\n| API keys (third-party) | On staff change | Security team |\r\n| Deploy tokens | Every 90 days | DevOps |\r\n\r\n## OWASP Top 10 checklist\r\n\r\n- [ ] **A01 Broken Access Control** — Enforce authorization on every endpoint; deny by default\r\n- [ ] **A02 Cryptographic Failures** — Use TLS everywhere; never store plaintext secrets; use bcrypt/argon2 for passwords\r\n- [ ] **A03 Injection** — Use parameterized queries; validate and sanitize all input\r\n- [ ] **A04 Insecure Design** — Threat model new features; use principle of least privilege\r\n- [ ] **A05 Security Misconfiguration** — Harden defaults; disable unused features; set security headers\r\n- [ ] **A06 Vulnerable Components** — Run \\`npm audit\\` in CI; automate with Dependabot\r\n- [ ] **A07 Auth Failures** — Implement MFA; lock accounts after failed attempts; use secure session management\r\n- [ ] **A08 Software Integrity Failures** — Verify checksums; use lockfiles; pin CI action versions\r\n- [ ] **A09 Logging Failures** — Log auth events, access failures; never log secrets or PII\r\n- [ ] **A10 SSRF** — Validate and allowlist URLs for any server-side requests\r\n\r\n## Security best practices\r\n\r\nWhen contributing to this project:\r\n- Never commit secrets, tokens, or credentials\r\n- Use environment variables for all sensitive configuration\r\n- Validate and sanitize all user input\r\n- Follow the principle of least privilege\r\n- Keep dependencies up to date\r\n`,\r\n },\r\n {\r\n id: 'pr-template',\r\n name: 'PR Template',\r\n description: 'Pull request template',\r\n defaultPath: '.github/pull_request_template.md',\r\n category: 'github',\r\n content: `## Description\r\n\r\n<!-- Briefly describe the changes and why they were made -->\r\n\r\n## Type of change\r\n\r\n- [ ] Bug fix (non-breaking change that fixes an issue)\r\n- [ ] New feature (non-breaking change that adds functionality)\r\n- [ ] Breaking change (fix or feature that would cause existing functionality to change)\r\n- [ ] Documentation update\r\n- [ ] Refactor / code cleanup\r\n- [ ] Dependency update\r\n\r\n## Related issues\r\n\r\nCloses #\r\n\r\n## How to test\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n## Screenshots / recordings\r\n\r\n<!-- If applicable, add screenshots or screen recordings -->\r\n\r\n## Checklist\r\n\r\n- [ ] My code follows the project's style guidelines\r\n- [ ] I have performed a self-review of my changes\r\n- [ ] I have added tests that prove my fix or feature works\r\n- [ ] New and existing unit tests pass locally\r\n- [ ] I have updated documentation if needed\r\n- [ ] No secrets or credentials are included\r\n`,\r\n },\r\n {\r\n id: 'bug-report',\r\n name: 'Bug Report Template',\r\n description: 'GitHub issue template for bugs',\r\n defaultPath: '.github/ISSUE_TEMPLATE/bug_report.md',\r\n category: 'github',\r\n content: `---\r\nname: Bug report\r\nabout: Create a report to help us improve\r\nlabels: bug\r\n---\r\n\r\n## Describe the bug\r\n\r\nA clear and concise description of what the bug is.\r\n\r\n## Steps to reproduce\r\n\r\n1. Go to '...'\r\n2. Click on '...'\r\n3. See error\r\n\r\n## Expected behavior\r\n\r\nA clear and concise description of what you expected to happen.\r\n\r\n## Actual behavior\r\n\r\nWhat actually happened.\r\n\r\n## Screenshots\r\n\r\nIf applicable, add screenshots to help explain your problem.\r\n\r\n## Environment\r\n\r\n- OS: [e.g. macOS 14]\r\n- Browser: [e.g. Chrome 120]\r\n- Version: [e.g. 1.2.3]\r\n- Node.js: [e.g. 20.x]\r\n\r\n## Additional context\r\n\r\nAdd any other context about the problem here.\r\n`,\r\n },\r\n {\r\n id: 'feature-request',\r\n name: 'Feature Request Template',\r\n description: 'GitHub issue template for features',\r\n defaultPath: '.github/ISSUE_TEMPLATE/feature_request.md',\r\n category: 'github',\r\n content: `---\r\nname: Feature request\r\nabout: Suggest an idea for this project\r\nlabels: enhancement\r\n---\r\n\r\n## Problem\r\n\r\nIs your feature request related to a problem? Please describe.\r\nA clear and concise description of what the problem is.\r\n\r\n## Proposed solution\r\n\r\nA clear and concise description of what you want to happen.\r\n\r\n## Alternatives considered\r\n\r\nA clear and concise description of any alternative solutions or features you've considered.\r\n\r\n## Implementation notes\r\n\r\nAny thoughts on how this might be implemented?\r\n\r\n## Additional context\r\n\r\nAdd any other context, mockups, or screenshots about the feature request here.\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const PROCESS_TEMPLATES: Template[] = [\r\n {\r\n id: 'changelog',\r\n name: 'CHANGELOG.md',\r\n description: 'Keep a Changelog format',\r\n defaultPath: 'CHANGELOG.md',\r\n category: 'process',\r\n content: `# Changelog — {{PROJECT_NAME}}\r\n\r\nAll notable changes to this project will be documented in this file.\r\n\r\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\r\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\r\n\r\n## [Unreleased]\r\n\r\n### Added\r\n-\r\n\r\n### Changed\r\n-\r\n\r\n### Fixed\r\n-\r\n\r\n### Removed\r\n-\r\n\r\n## [1.0.0] — {{DATE}}\r\n\r\n### Added\r\n- Initial release\r\n`,\r\n },\r\n {\r\n id: 'deployment',\r\n name: 'DEPLOYMENT.md',\r\n description: 'Deployment guide and procedures',\r\n defaultPath: 'DEPLOYMENT.md',\r\n category: 'process',\r\n content: `# Deployment Guide — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Environments\r\n\r\n| Environment | URL | Branch | Auto-deploy |\r\n|-------------|-----|--------|-------------|\r\n| Production | | \\`main\\` | No |\r\n| Staging | | \\`develop\\` | Yes |\r\n| Preview | | PRs | Yes |\r\n\r\n## Prerequisites\r\n\r\n- Access to deployment platform\r\n- Environment variables configured (see \\`.env.example\\`)\r\n- CI/CD pipeline passing\r\n\r\n## Deploy to production\r\n\r\n\\`\\`\\`bash\r\n# 1. Ensure tests pass\r\nnpm test\r\n\r\n# 2. Build and verify\r\nnpm run build\r\n\r\n# 3. Merge to main\r\ngit checkout main && git merge develop\r\n\r\n# 4. Tag the release\r\ngit tag v1.x.x && git push --tags\r\n\\`\\`\\`\r\n\r\n## Environment variables\r\n\r\n| Variable | Required | Description |\r\n|----------|----------|-------------|\r\n| | Yes | |\r\n\r\n## Rollback procedure\r\n\r\n1. Identify the last stable release tag\r\n2. \\`git checkout <tag>\\`\r\n3. Redeploy the previous version\r\n4. Verify the rollback with smoke tests\r\n\r\n## Smoke tests\r\n\r\nAfter every deploy, verify:\r\n- [ ] App loads at production URL\r\n- [ ] Auth flow works\r\n- [ ] Core features functional\r\n- [ ] No error spikes in monitoring\r\n\r\n## Contacts\r\n\r\n| Role | Contact |\r\n|------|---------|\r\n| On-call | |\r\n| Release manager | |\r\n`,\r\n },\r\n {\r\n id: 'testing',\r\n name: 'TESTING.md',\r\n description: 'Testing strategy and guide',\r\n defaultPath: 'TESTING.md',\r\n category: 'process',\r\n content: `# Testing Guide — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Test pyramid\r\n\r\n\\`\\`\\`\r\n /\\\\\r\n /E2E\\\\ 10% — Critical user flows only\r\n /------\\\\\r\n /Integr. \\\\ 20% — API, DB, service boundaries\r\n /----------\\\\\r\n / Unit \\\\ 70% — Functions, logic, utilities\r\n /______________\\\\\r\n\\`\\`\\`\r\n\r\n## Test strategy\r\n\r\n| Layer | Type | Tool | Coverage target |\r\n|-------|------|------|----------------|\r\n| Unit | Functions/logic | {{TEST_FRAMEWORK}} | 80%+ |\r\n| Integration | API/DB | {{TEST_FRAMEWORK}} | 70%+ |\r\n| E2E | User flows | Playwright | Key paths |\r\n\r\n## Coverage targets by directory\r\n\r\n| Directory | Target | Rationale |\r\n|-----------|--------|-----------|\r\n| \\`src/lib/\\` | 90%+ | Core business logic |\r\n| \\`src/api/\\` | 80%+ | API handlers |\r\n| \\`src/components/\\` | 60%+ | UI — focus on logic, not rendering |\r\n| \\`src/utils/\\` | 90%+ | Pure utility functions |\r\n\r\n## Running tests\r\n\r\n\\`\\`\\`bash\r\n# Run all tests\r\nnpm test\r\n\r\n# Run with coverage\r\nnpm run test:coverage\r\n\r\n# Run E2E tests\r\nnpm run test:e2e\r\n\r\n# Watch mode\r\nnpm run test:watch\r\n\\`\\`\\`\r\n\r\n## Writing tests\r\n\r\n### Unit test example\r\n\r\n\\`\\`\\`typescript\r\ndescribe('MyFunction', () => {\r\n it('should return expected value', () => {\r\n expect(myFunction(input)).toBe(expected)\r\n })\r\n})\r\n\\`\\`\\`\r\n\r\n### Integration test guidelines\r\n- Use a real database (not mocks) for DB tests\r\n- Reset state between tests\r\n- Test happy path and error cases\r\n\r\n### E2E test guidelines\r\n- Cover critical user journeys\r\n- Use stable selectors (\\`data-testid\\`)\r\n- Run against staging environment\r\n\r\n### Playwright config example\r\n\r\n\\`\\`\\`typescript\r\n// playwright.config.ts\r\nimport { defineConfig, devices } from '@playwright/test'\r\n\r\nexport default defineConfig({\r\n testDir: './e2e',\r\n fullyParallel: true,\r\n forbidOnly: !!process.env.CI,\r\n retries: process.env.CI ? 2 : 0,\r\n reporter: 'html',\r\n use: {\r\n baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',\r\n trace: 'on-first-retry',\r\n },\r\n projects: [\r\n {name: 'chromium', use: {...devices['Desktop Chrome']}},\r\n {name: 'Mobile Safari', use: {...devices['iPhone 13']}},\r\n ],\r\n webServer: {\r\n command: 'npm run dev',\r\n url: 'http://localhost:3000',\r\n reuseExistingServer: !process.env.CI,\r\n },\r\n})\r\n\\`\\`\\`\r\n\r\n## Flaky test policy\r\n\r\n1. **Quarantine immediately** — tag with \\`@flaky\\` and skip in CI (\\`test.skip\\`)\r\n2. **Create a ticket** — track as a P2 bug with a 2-week SLA to fix\r\n3. **Root cause** — common causes: timing issues, shared state, network calls\r\n4. **Fix or delete** — flaky tests are worse than no tests (false confidence)\r\n\r\nQuarantine example:\r\n\\`\\`\\`typescript\r\ntest.skip('flaky: timing issue with animation', async ({ page }) => {\r\n // TODO: fix by waiting for animation end event instead of sleep\r\n})\r\n\\`\\`\\`\r\n\r\n## Test organization\r\n\r\n\\`\\`\\`\r\nsrc/\r\n __tests__/ # Unit tests\r\n __integration__/ # Integration tests\r\ne2e/ # E2E tests\r\n\\`\\`\\`\r\n\r\n## CI/CD\r\n\r\nTests run automatically on every PR. PRs cannot merge with failing tests.\r\n`,\r\n },\r\n {\r\n id: 'glossary',\r\n name: 'Glossary',\r\n description: 'Project terminology reference',\r\n defaultPath: 'docs/glossary.md',\r\n category: 'process',\r\n content: `# Glossary — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\nThis document defines terms used throughout the project documentation and codebase.\r\n\r\n## Terms\r\n\r\n| Term | Definition |\r\n|------|------------|\r\n| | |\r\n\r\n## Acronyms\r\n\r\n| Acronym | Full form | Meaning |\r\n|---------|-----------|---------|\r\n| | | |\r\n\r\n## Domain concepts\r\n\r\n<!-- Add domain-specific concepts here -->\r\n\r\n---\r\n\r\n*Keep this document updated as new terminology is introduced.*\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nconst today = new Date().toISOString().split('T')[0]\r\n\r\nexport const TECHNICAL_TEMPLATES: Template[] = [\r\n {\r\n id: 'prd',\r\n name: 'PRD',\r\n description: 'Product requirements document',\r\n defaultPath: 'docs/prd.md',\r\n category: 'technical',\r\n content: `# Product Requirements — {{PROJECT_NAME}}\r\n\r\n**Status:** Draft\r\n**Last updated:** {{DATE}}\r\n**Author:**\r\n**Stakeholders:**\r\n\r\n## Problem statement\r\n{{DESCRIPTION}}\r\n\r\n## Goals\r\n-\r\n-\r\n\r\n## Non-goals\r\n-\r\n-\r\n\r\n## User stories\r\n| As a... | I want to... | So that... |\r\n|---------|--------------|------------|\r\n| user | | |\r\n\r\n## Requirements\r\n\r\n### Functional\r\n{{KEY_FEATURES}}\r\n\r\n### Non-functional\r\n- Performance:\r\n- Security:\r\n- Reliability:\r\n- Scalability:\r\n\r\n## Success metrics\r\n| Metric | Current | Target |\r\n|--------|---------|--------|\r\n| | | |\r\n\r\n## Timeline\r\n| Milestone | Target date |\r\n|-----------|-------------|\r\n| | |\r\n\r\n## Open questions\r\n-\r\n`,\r\n },\r\n {\r\n id: 'architecture-overview',\r\n name: 'Architecture Overview',\r\n description: 'System architecture doc',\r\n defaultPath: 'docs/architecture/overview.md',\r\n category: 'technical',\r\n content: `# Architecture Overview — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Summary\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## System diagram\r\n\r\n### Context (C4 Level 1)\r\n\r\n\\`\\`\\`mermaid\r\ngraph TB\r\n User[\"User\"] --> System[\"{{PROJECT_NAME}}\"]\r\n System --> ExternalAPI[\"External APIs\"]\r\n System --> DB[\"Database\"]\r\n\\`\\`\\`\r\n\r\n### Container (C4 Level 2)\r\n\r\n\\`\\`\\`mermaid\r\ngraph TB\r\n Client[\"Web Client<br/>(Browser)\"] --> API[\"API Server<br/>(Node.js)\"]\r\n API --> DB[\"Database<br/>(PostgreSQL)\"]\r\n API --> Cache[\"Cache<br/>(Redis)\"]\r\n API --> Queue[\"Job Queue\"]\r\n\\`\\`\\`\r\n\r\n## Components\r\n\r\n| Component | Responsibility | Tech |\r\n|-----------|---------------|------|\r\n| | | |\r\n\r\n## Data flow\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n## Key decisions\r\n\r\n| Decision | Chosen | Alternative | Rationale |\r\n|----------|--------|-------------|-----------|\r\n| | | | |\r\n\r\n## ADR log\r\n\r\n| ADR | Title | Status | Date |\r\n|-----|-------|--------|------|\r\n| 001 | | Accepted | {{DATE}} |\r\n\r\n## Non-goals\r\n\r\n- <!-- What this system explicitly does NOT do -->\r\n\r\n## Security considerations\r\n- Authentication:\r\n- Authorization:\r\n- Data validation:\r\n- Secrets management:\r\n\r\n## Scalability notes\r\n-\r\n`,\r\n },\r\n {\r\n id: 'api-reference',\r\n name: 'API Reference',\r\n description: 'API endpoints reference',\r\n defaultPath: 'docs/api-reference.md',\r\n category: 'technical',\r\n content: `# API Reference — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Base URL\r\n\r\n\\`\\`\\`\r\nhttps://api.example.com/v1\r\n\\`\\`\\`\r\n\r\n## Versioning\r\n\r\nThis API uses URL-based versioning (\\`/v1/\\`, \\`/v2/\\`, etc.).\r\n\r\n- The current stable version is \\`v1\\`.\r\n- Deprecated versions are supported for 12 months after a new version is released.\r\n- Breaking changes always increment the major version.\r\n\r\n## Authentication\r\n\r\nAll requests require a bearer token in the Authorization header:\r\n\r\n\\`\\`\\`\r\nAuthorization: Bearer <token>\r\n\\`\\`\\`\r\n\r\n### Token refresh\r\n\r\nTokens expire after 1 hour. Refresh using:\r\n\r\n\\`\\`\\`\r\nPOST /auth/refresh\r\nContent-Type: application/json\r\n\r\n{\"refreshToken\": \"<refresh_token>\"}\r\n\\`\\`\\`\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{\"accessToken\": \"...\", \"refreshToken\": \"...\", \"expiresIn\": 3600}\r\n\\`\\`\\`\r\n\r\n## Rate limiting\r\n\r\n- **Limit:** 1000 requests/hour per API key\r\n- **Headers:** \\`X-RateLimit-Limit\\`, \\`X-RateLimit-Remaining\\`, \\`X-RateLimit-Reset\\`\r\n\r\n## Pagination\r\n\r\nList endpoints support cursor-based pagination:\r\n\r\n\\`\\`\\`\r\nGET /resources?cursor=<cursor>&limit=20\r\n\\`\\`\\`\r\n\r\n## Error format\r\n\r\nAll errors follow a standard envelope:\r\n\r\n\\`\\`\\`json\r\n{\r\n \"code\": \"VALIDATION_ERROR\",\r\n \"message\": \"Human-readable description\",\r\n \"details\": [{\"field\": \"email\", \"issue\": \"invalid format\"}]\r\n}\r\n\\`\\`\\`\r\n\r\n## Error codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 400 | Bad request — invalid parameters |\r\n| 401 | Unauthorized — missing or invalid token |\r\n| 403 | Forbidden — insufficient permissions |\r\n| 404 | Not found |\r\n| 422 | Unprocessable entity — validation error |\r\n| 429 | Too many requests |\r\n| 500 | Internal server error |\r\n\r\n## Webhooks\r\n\r\n### Signature verification\r\n\r\nAll webhook payloads are signed with HMAC-SHA256. Verify the signature:\r\n\r\n\\`\\`\\`\r\nX-Webhook-Signature: sha256=<hmac_hex>\r\n\\`\\`\\`\r\n\r\n\\`\\`\\`typescript\r\nimport crypto from 'crypto'\r\n\r\nfunction verifyWebhook(payload: string, signature: string, secret: string): boolean {\r\n const expected = crypto\r\n .createHmac('sha256', secret)\r\n .update(payload)\r\n .digest('hex')\r\n return crypto.timingSafeEqual(\r\n Buffer.from(\\`sha256=\\${expected}\\`),\r\n Buffer.from(signature)\r\n )\r\n}\r\n\\`\\`\\`\r\n\r\n## Endpoints\r\n\r\n### GET /resource\r\n\r\n**Description:** List resources\r\n\r\n**Query parameters:**\r\n- \\`limit\\` (integer, default 20) — items per page\r\n- \\`cursor\\` (string) — pagination cursor\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{\r\n \"data\": [],\r\n \"cursor\": null,\r\n \"total\": 0\r\n}\r\n\\`\\`\\`\r\n\r\n### POST /resource\r\n\r\n**Description:** Create a resource\r\n\r\n**Request body:**\r\n\\`\\`\\`json\r\n{}\r\n\\`\\`\\`\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{}\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'runbook',\r\n name: 'Runbook',\r\n description: 'Operational runbook',\r\n defaultPath: 'docs/runbook.md',\r\n category: 'technical',\r\n content: `# Runbook — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## SLOs\r\n\r\n| Metric | Target |\r\n|--------|--------|\r\n| Availability | 99.9% |\r\n| P95 latency | < 500ms |\r\n| Error rate | < 0.1% |\r\n\r\n## Environments\r\n\r\n| Env | URL | Purpose |\r\n|-----|-----|---------|\r\n| Production | | Live traffic |\r\n| Staging | | Pre-release testing |\r\n| Development | | Local dev |\r\n\r\n## Alerting\r\n\r\n| Alert | Threshold | Severity | Action |\r\n|-------|-----------|----------|--------|\r\n| | | | |\r\n\r\n## On-call contacts\r\n\r\n| Role | Name | Contact |\r\n|------|------|---------|\r\n| Primary | | |\r\n| Secondary | | |\r\n\r\n## Escalation matrix\r\n\r\n| Time since incident | Contact | Method |\r\n|--------------------|---------|--------|\r\n| 0–15 min | On-call engineer | PagerDuty / phone |\r\n| 15–30 min | Team lead | Slack + phone |\r\n| 30+ min | Engineering manager | Phone + email |\r\n\r\n## Procedures\r\n\r\n### Deploy\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n### Rollback\r\n\r\n**When to rollback:**\r\n\r\n| Signal | Action |\r\n|--------|--------|\r\n| Error rate > 1% after deploy | Immediate rollback |\r\n| P95 latency doubled | Rollback if no fix in 15 min |\r\n| Health check failing | Immediate rollback |\r\n| Critical bug reported | Rollback within 30 min |\r\n\r\n**Rollback steps:**\r\n\r\n\\`\\`\\`bash\r\n# 1. Identify last stable release\r\ngit log --oneline --tags --simplify-by-decoration | head -5\r\n\r\n# 2. Deploy previous version\r\ngit checkout <previous-tag>\r\nnpm run build && npm run deploy\r\n\r\n# 3. Verify rollback\r\ncurl -f https://your-app.com/health\r\n\\`\\`\\`\r\n\r\n### Troubleshooting\r\n\r\n#### High error rate\r\n\\`\\`\\`bash\r\n# Check recent application logs\r\ntail -f /var/log/app/error.log\r\n\r\n# Check error counts by endpoint\r\ngrep \"ERROR\" /var/log/app/app.log | awk '{print $5}' | sort | uniq -c | sort -rn | head -10\r\n\r\n# Review recent deploys\r\ngit log --oneline -10\r\n\\`\\`\\`\r\n\r\n1. Check application logs for exception traces\r\n2. Check downstream dependencies (database, cache, external APIs)\r\n3. Review recent deploys — consider rollback if deploy-correlated\r\n\r\n#### High latency\r\n\\`\\`\\`bash\r\n# Check database slow query log\r\npsql $DATABASE_URL -c \"SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;\"\r\n\r\n# Check cache hit rate\r\nredis-cli info stats | grep hit_rate\r\n\r\n# Check CPU/memory\r\ntop -b -n 1 | head -20\r\n\\`\\`\\`\r\n\r\n1. Check database query times (slow query log)\r\n2. Check cache hit rates\r\n3. Review resource utilization (CPU, memory, connections)\r\n\r\n#### Service won't start\r\n\\`\\`\\`bash\r\n# Check environment variables\r\nenv | grep -E \"DATABASE|REDIS|PORT\"\r\n\r\n# Test database connectivity\r\npsql $DATABASE_URL -c \"SELECT 1\"\r\n\r\n# Check port availability\r\nlsof -i :3000\r\n\\`\\`\\`\r\n\r\n#### Database connection issues\r\n\\`\\`\\`bash\r\n# Check connection pool status\r\npsql $DATABASE_URL -c \"SELECT count(*), state FROM pg_stat_activity GROUP BY state;\"\r\n\r\n# Check max connections\r\npsql $DATABASE_URL -c \"SHOW max_connections;\"\r\n\\`\\`\\`\r\n\r\n#### Memory leak suspected\r\n\\`\\`\\`bash\r\n# Monitor memory over time\r\nwatch -n 5 'ps aux --sort=-%mem | head -5'\r\n\r\n# Capture heap snapshot (Node.js)\r\nkill -USR2 <pid>\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'adr',\r\n name: 'Architecture Decision',\r\n description: 'Architecture Decision Record',\r\n defaultPath: 'docs/architecture/decisions/ADR-001.md',\r\n category: 'technical',\r\n content: `# ADR-001: Title\r\n\r\n**Status:** Proposed\r\n**Date:** {{DATE}}\r\n**Deciders:**\r\n\r\n## Context\r\nWhat is the issue that we're seeing that is motivating this decision or change?\r\n\r\n## Decision\r\nWhat is the change that we're proposing and/or doing?\r\n\r\n## Rationale\r\nWhy did we choose this option?\r\n\r\n## Alternatives considered\r\n- **Option A:** Description — pros/cons\r\n- **Option B:** Description — pros/cons\r\n\r\n## Consequences\r\n\r\n### Positive\r\n-\r\n\r\n### Negative\r\n-\r\n\r\n### Neutral\r\n-\r\n`,\r\n },\r\n {\r\n id: 'onboarding',\r\n name: 'Onboarding Guide',\r\n description: 'Developer onboarding guide',\r\n defaultPath: 'docs/onboarding.md',\r\n category: 'technical',\r\n content: `# Developer Onboarding — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## Prerequisites\r\n- [ ] Access to repository ({{REPO_URL}})\r\n- [ ] Access to staging environment\r\n- [ ] Accounts: (list required accounts/services)\r\n\r\n## Day 1: Get running\r\n\r\n- [ ] Clone the repository and set up local environment\r\n- [ ] Run the app locally and verify it works\r\n- [ ] Read the architecture overview (\\`docs/architecture/overview.md\\`)\r\n- [ ] Meet your team lead and get a tour of the codebase\r\n\r\n\\`\\`\\`bash\r\n# Clone\r\ngit clone {{REPO_URL}}\r\ncd {{PROJECT_NAME}}\r\n\r\n# Install dependencies\r\nnpm install\r\n\r\n# Copy environment variables\r\ncp .env.example .env.local\r\n# Edit .env.local with real values (ask your team lead)\r\n\r\n# Start development server\r\nnpm run dev\r\n\\`\\`\\`\r\n\r\n## Week 1: Get productive\r\n\r\n- [ ] Complete the environment setup checklist below\r\n- [ ] Read \\`CONTRIBUTING.md\\` and understand the PR process\r\n- [ ] Submit your first PR (even a small doc fix counts)\r\n- [ ] Attend team standup and sprint planning\r\n- [ ] Review 2–3 recent merged PRs to understand code patterns\r\n- [ ] Shadow a code review\r\n\r\n## Month 1: Get comfortable\r\n\r\n- [ ] Deliver your first feature end-to-end\r\n- [ ] Lead a code review\r\n- [ ] Identify one piece of tech debt and create a ticket\r\n- [ ] Update this onboarding doc with anything that was unclear\r\n\r\n## Environment setup\r\n\r\n\\`\\`\\`bash\r\n# Install dependencies\r\nnpm install\r\n\r\n# Copy environment variables\r\ncp .env.example .env.local\r\n\r\n# Start development server\r\nnpm run dev\r\n\\`\\`\\`\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## IDE setup\r\n- Recommended: VS Code or Cursor\r\n- Install recommended extensions (see \\`.vscode/extensions.json\\`)\r\n- Enable format on save\r\n\r\n## Project structure\r\n\r\n\\`\\`\\`\r\n(describe key directories here)\r\n\\`\\`\\`\r\n\r\n## Key concepts\r\n-\r\n\r\n## Common tasks\r\n\r\n### Running tests\r\n\\`\\`\\`bash\r\nnpm test\r\n\\`\\`\\`\r\n\r\n### Building for production\r\n\\`\\`\\`bash\r\nnpm run build\r\n\\`\\`\\`\r\n\r\n## Common pitfalls\r\n\r\n1. **Forgetting to copy .env.local** — the app won't start without required env vars. Copy from \\`.env.example\\` and fill in real values.\r\n2. **Running \\`npm install\\` instead of the project's package manager** — check \\`package.json\\` for the \\`packageManager\\` field or look for a lock file (\\`pnpm-lock.yaml\\`, \\`yarn.lock\\`).\r\n3. **Committing to \\`main\\` directly** — always branch and open a PR. Direct pushes to \\`main\\` are blocked.\r\n4. **Skipping tests** — CI will catch you, but it's faster to run \\`npm test\\` locally before pushing.\r\n5. **Not reading existing patterns** — before adding a new abstraction, search the codebase for how similar problems are solved.\r\n\r\n## Your first PR\r\n\r\n1. Pick a small, well-defined issue labelled \\`good first issue\\`\r\n2. Create a branch: \\`git checkout -b feat/your-name-first-pr\\`\r\n3. Make the change and add a test\r\n4. Open a PR with the PR template filled out\r\n5. Ask for a review in the team Slack channel\r\n\r\n## Key contacts\r\n\r\n| Role | Name | Contact |\r\n|------|------|---------|\r\n| | | |\r\n\r\n## Resources\r\n- Architecture overview: \\`docs/architecture/overview.md\\`\r\n- API reference: \\`docs/api-reference.md\\`\r\n- Runbook: \\`docs/runbook.md\\`\r\n- Contributing guide: \\`CONTRIBUTING.md\\`\r\n`,\r\n },\r\n {\r\n id: 'database',\r\n name: 'Database Docs',\r\n description: 'Database schema and design reference',\r\n defaultPath: 'docs/DATABASE.md',\r\n category: 'technical',\r\n content: `# Database Documentation — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n\r\n<!-- Brief description of the database design -->\r\n\r\n## Entity Relationship Diagram\r\n\r\n\\`\\`\\`mermaid\r\nerDiagram\r\n USERS {\r\n uuid id PK\r\n string email\r\n timestamp created_at\r\n }\r\n\\`\\`\\`\r\n\r\n## Tables\r\n\r\n### users\r\n\r\n| Column | Type | Nullable | Description |\r\n|--------|------|----------|-------------|\r\n| id | uuid | No | Primary key |\r\n| email | varchar | No | Unique email |\r\n| created_at | timestamp | No | Creation time |\r\n\r\n## Indexes\r\n\r\n| Table | Columns | Type | Purpose |\r\n|-------|---------|------|---------|\r\n| | | | |\r\n\r\n## Migrations\r\n\r\nMigrations live in \\`db/migrations/\\`. Run with:\r\n\r\n\\`\\`\\`bash\r\nnpm run db:migrate\r\n\\`\\`\\`\r\n\r\n## Connection\r\n\r\n\\`\\`\\`\r\nDATABASE_URL=postgresql://user:password@host:5432/dbname\r\n\\`\\`\\`\r\n\r\n## Backup & restore\r\n\r\n\\`\\`\\`bash\r\n# Backup\r\npg_dump $DATABASE_URL > backup.sql\r\n\r\n# Restore\r\npsql $DATABASE_URL < backup.sql\r\n\\`\\`\\`\r\n\r\n## Performance notes\r\n\r\n-\r\n`,\r\n },\r\n {\r\n id: 'openapi',\r\n name: 'OpenAPI Spec',\r\n description: 'OpenAPI 3.0 API specification scaffold',\r\n defaultPath: 'docs/api-spec.yaml',\r\n category: 'technical',\r\n content: `openapi: 3.0.3\r\ninfo:\r\n title: {{PROJECT_NAME}} API\r\n description: |\r\n {{DESCRIPTION}}\r\n version: 1.0.0\r\n contact:\r\n email: team@example.com\r\n\r\nservers:\r\n - url: https://api.example.com/v1\r\n description: Production\r\n - url: https://staging-api.example.com/v1\r\n description: Staging\r\n\r\nsecurity:\r\n - bearerAuth: []\r\n\r\npaths:\r\n /health:\r\n get:\r\n summary: Health check\r\n operationId: healthCheck\r\n security: []\r\n responses:\r\n '200':\r\n description: OK\r\n content:\r\n application/json:\r\n schema:\r\n type: object\r\n properties:\r\n status:\r\n type: string\r\n example: ok\r\n\r\n /resources:\r\n get:\r\n summary: List resources\r\n operationId: listResources\r\n parameters:\r\n - name: limit\r\n in: query\r\n schema:\r\n type: integer\r\n default: 20\r\n - name: cursor\r\n in: query\r\n schema:\r\n type: string\r\n responses:\r\n '200':\r\n description: Success\r\n content:\r\n application/json:\r\n schema:\r\n $ref: '#/components/schemas/ResourceList'\r\n '401':\r\n $ref: '#/components/responses/Unauthorized'\r\n\r\ncomponents:\r\n securitySchemes:\r\n bearerAuth:\r\n type: http\r\n scheme: bearer\r\n bearerFormat: JWT\r\n\r\n schemas:\r\n Resource:\r\n type: object\r\n properties:\r\n id:\r\n type: string\r\n format: uuid\r\n createdAt:\r\n type: string\r\n format: date-time\r\n\r\n ResourceList:\r\n type: object\r\n properties:\r\n data:\r\n type: array\r\n items:\r\n $ref: '#/components/schemas/Resource'\r\n cursor:\r\n type: string\r\n nullable: true\r\n total:\r\n type: integer\r\n\r\n Error:\r\n type: object\r\n properties:\r\n error:\r\n type: string\r\n message:\r\n type: string\r\n\r\n responses:\r\n Unauthorized:\r\n description: Unauthorized\r\n content:\r\n application/json:\r\n schema:\r\n $ref: '#/components/schemas/Error'\r\n`,\r\n },\r\n {\r\n id: 'meeting-notes',\r\n name: 'Meeting Notes',\r\n description: 'Meeting notes template',\r\n defaultPath: `docs/meetings/${today}.md`,\r\n category: 'technical',\r\n content: `# Meeting Notes — ${today}\r\n\r\n**Attendees:**\r\n**Facilitator:**\r\n\r\n## Agenda\r\n\r\n1.\r\n2.\r\n\r\n## Notes\r\n\r\n## Decisions\r\n\r\n## Action items\r\n\r\n| Action | Owner | Due |\r\n|--------|-------|-----|\r\n| | | |\r\n\r\n## Next meeting\r\n`,\r\n },\r\n {\r\n id: 'blank',\r\n name: 'Blank Document',\r\n description: 'Empty markdown file',\r\n defaultPath: 'docs/untitled.md',\r\n category: 'technical',\r\n content: '# Untitled\\n\\n',\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const INFRASTRUCTURE_TEMPLATES: Template[] = [\r\n {\r\n id: 'dockerfile',\r\n name: 'Dockerfile',\r\n description: 'Multi-stage Docker build with health check',\r\n defaultPath: 'Dockerfile',\r\n category: 'infrastructure',\r\n content: `# Stage 1: Install dependencies\r\nFROM node:20-alpine AS deps\r\nRUN apk add --no-cache libc6-compat\r\nWORKDIR /app\r\nCOPY package*.json ./\r\nRUN npm ci --only=production\r\n\r\n# Stage 2: Build\r\nFROM node:20-alpine AS builder\r\nWORKDIR /app\r\nCOPY --from=deps /app/node_modules ./node_modules\r\nCOPY . .\r\nRUN npm run build\r\n\r\n# Stage 3: Run\r\nFROM node:20-alpine AS runner\r\nWORKDIR /app\r\nENV NODE_ENV=production\r\nRUN addgroup --system --gid 1001 nodejs\r\nRUN adduser --system --uid 1001 appuser\r\nCOPY --from=builder /app/dist ./dist\r\nCOPY --from=deps /app/node_modules ./node_modules\r\nCOPY package*.json ./\r\nUSER appuser\r\nEXPOSE 3000\r\nHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\\\\r\n CMD wget -qO- http://localhost:3000/health || exit 1\r\nCMD [\"node\", \"dist/index.js\"]\r\n`,\r\n },\r\n {\r\n id: 'docker-compose',\r\n name: 'docker-compose.yml',\r\n description: 'Docker Compose with app, Postgres, and Redis',\r\n defaultPath: 'docker-compose.yml',\r\n category: 'infrastructure',\r\n content: `# Docker Compose V2+ (no version key needed)\r\nservices:\r\n app:\r\n build: .\r\n ports:\r\n - \"3000:3000\"\r\n environment:\r\n DATABASE_URL: postgresql://postgres:password@db:5432/{{PROJECT_NAME}}\r\n REDIS_URL: redis://redis:6379\r\n depends_on:\r\n db:\r\n condition: service_healthy\r\n redis:\r\n condition: service_healthy\r\n\r\n db:\r\n image: postgres:16-alpine\r\n environment:\r\n POSTGRES_PASSWORD: password\r\n POSTGRES_DB: {{PROJECT_NAME}}\r\n healthcheck:\r\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\r\n interval: 10s\r\n timeout: 5s\r\n retries: 5\r\n volumes:\r\n - postgres_data:/var/lib/postgresql/data\r\n\r\n redis:\r\n image: redis:7-alpine\r\n healthcheck:\r\n test: [\"CMD\", \"redis-cli\", \"ping\"]\r\n interval: 10s\r\n timeout: 5s\r\n retries: 5\r\n volumes:\r\n - redis_data:/data\r\n\r\nvolumes:\r\n postgres_data:\r\n redis_data:\r\n`,\r\n },\r\n {\r\n id: 'dockerignore',\r\n name: '.dockerignore',\r\n description: 'Docker build context exclusions',\r\n defaultPath: '.dockerignore',\r\n category: 'infrastructure',\r\n content: `node_modules\r\nnpm-debug.log*\r\n.git\r\n.gitignore\r\n.env*\r\n!.env.example\r\ndist\r\nbuild\r\ncoverage\r\n.nyc_output\r\n*.test.*\r\n*.spec.*\r\n__tests__\r\ne2e\r\n.github\r\ndocs\r\nREADME.md\r\nCHANGELOG.md\r\n`,\r\n },\r\n {\r\n id: 'makefile',\r\n name: 'Makefile',\r\n description: 'Makefile with common dev/build/deploy targets',\r\n defaultPath: 'Makefile',\r\n category: 'infrastructure',\r\n content: `.PHONY: help dev build test lint docker-up docker-down migrate clean\r\n\r\nhelp: ## Show this help\r\n\\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\\\033[36m%-20s\\\\033[0m %s\\\\n\", $$1, $$2}'\r\n\r\ndev: ## Start development server\r\n\\tnpm run dev\r\n\r\nbuild: ## Build for production\r\n\\tnpm run build\r\n\r\ntest: ## Run all tests\r\n\\tnpm test\r\n\r\nlint: ## Run linter\r\n\\tnpm run lint\r\n\r\ndocker-up: ## Start Docker services\r\n\\tdocker compose up -d\r\n\r\ndocker-down: ## Stop Docker services\r\n\\tdocker compose down\r\n\r\nmigrate: ## Run database migrations\r\n\\tnpm run db:migrate\r\n\r\nclean: ## Remove build artifacts\r\n\\trm -rf dist build .next coverage node_modules/.cache\r\n`,\r\n },\r\n {\r\n id: 'env-example',\r\n name: '.env.example',\r\n description: 'Annotated environment variables template',\r\n defaultPath: '.env.example',\r\n category: 'infrastructure',\r\n content: `# App Config\r\nNODE_ENV=development\r\nPORT=3000\r\nAPP_URL=http://localhost:3000\r\nLOG_LEVEL=info\r\n\r\n# Database\r\nDATABASE_URL=postgresql://user:password@localhost:5432/{{PROJECT_NAME}}_dev\r\n\r\n# Auth\r\nJWT_SECRET=your-super-secret-jwt-key-change-in-production\r\nJWT_EXPIRES_IN=7d\r\nSESSION_SECRET=your-session-secret-change-in-production\r\n\r\n# External Services\r\n# STRIPE_SECRET_KEY=sk_test_...\r\n# SENDGRID_API_KEY=SG....\r\n# AWS_ACCESS_KEY_ID=\r\n# AWS_SECRET_ACCESS_KEY=\r\n# AWS_REGION=us-east-1\r\n# AWS_S3_BUCKET=\r\n\r\n# Observability\r\n# SENTRY_DSN=https://...@sentry.io/...\r\n# DATADOG_API_KEY=\r\n# NEW_RELIC_LICENSE_KEY=\r\n`,\r\n },\r\n {\r\n id: 'nginx-conf',\r\n name: 'nginx.conf',\r\n description: 'Nginx reverse proxy with gzip, security headers, rate limiting',\r\n defaultPath: 'nginx/nginx.conf',\r\n category: 'infrastructure',\r\n content: `events {\r\n worker_connections 1024;\r\n}\r\n\r\nhttp {\r\n gzip on;\r\n gzip_types text/plain text/css application/json application/javascript text/xml;\r\n gzip_min_length 1000;\r\n\r\n # Rate limiting\r\n limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;\r\n\r\n server {\r\n listen 80;\r\n server_name _;\r\n\r\n # Security headers\r\n add_header X-Frame-Options \"SAMEORIGIN\" always;\r\n add_header X-Content-Type-Options \"nosniff\" always;\r\n add_header X-XSS-Protection \"1; mode=block\" always;\r\n add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;\r\n add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\" always;\r\n\r\n location /api/ {\r\n limit_req zone=api burst=20 nodelay;\r\n proxy_pass http://app:3000;\r\n proxy_http_version 1.1;\r\n proxy_set_header Upgrade $http_upgrade;\r\n proxy_set_header Connection 'upgrade';\r\n proxy_set_header Host $host;\r\n proxy_set_header X-Real-IP $remote_addr;\r\n proxy_cache_bypass $http_upgrade;\r\n }\r\n\r\n location / {\r\n proxy_pass http://app:3000;\r\n proxy_http_version 1.1;\r\n proxy_set_header Host $host;\r\n proxy_set_header X-Real-IP $remote_addr;\r\n }\r\n }\r\n}\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const GITHUB_ACTIONS_TEMPLATES: Template[] = [\r\n {\r\n id: 'ci-workflow',\r\n name: 'CI Workflow',\r\n description: 'GitHub Actions CI: lint, typecheck, test matrix, coverage',\r\n defaultPath: '.github/workflows/ci.yml',\r\n category: 'github-actions',\r\n content: `name: CI\r\non:\r\n push:\r\n branches: [main, develop]\r\n pull_request:\r\n branches: [main, develop]\r\n\r\njobs:\r\n lint:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run lint\r\n - run: npm run typecheck\r\n\r\n test:\r\n runs-on: ubuntu-latest\r\n strategy:\r\n matrix:\r\n node-version: ['20', '22']\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '\\${{ matrix.node-version }}', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run test:coverage\r\n - uses: codecov/codecov-action@v4\r\n if: matrix.node-version == '20'\r\n\r\n build:\r\n runs-on: ubuntu-latest\r\n needs: [lint, test]\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run build\r\n`,\r\n },\r\n {\r\n id: 'cd-workflow',\r\n name: 'CD Workflow',\r\n description: 'GitHub Actions CD: deploy to production with health check',\r\n defaultPath: '.github/workflows/cd.yml',\r\n category: 'github-actions',\r\n content: `name: CD\r\non:\r\n push:\r\n branches: [main]\r\n\r\njobs:\r\n deploy:\r\n runs-on: ubuntu-latest\r\n # needs: [ci] # Uncomment if using a reusable CI workflow\r\n environment: production\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run build\r\n - name: Deploy\r\n env:\r\n DEPLOY_TOKEN: \\${{ secrets.DEPLOY_TOKEN }}\r\n DEPLOY_URL: \\${{ secrets.DEPLOY_URL }}\r\n run: |\r\n # Add your deployment command here\r\n # e.g.: npx railway deploy, vercel deploy --prod, etc.\r\n echo \"Deploy to production\"\r\n - name: Health check\r\n run: |\r\n sleep 30\r\n curl -f \\${{ secrets.APP_URL }}/health || exit 1\r\n`,\r\n },\r\n {\r\n id: 'security-scan',\r\n name: 'Security Scan',\r\n description: 'GitHub Actions security: npm audit + CodeQL analysis',\r\n defaultPath: '.github/workflows/security.yml',\r\n category: 'github-actions',\r\n content: `name: Security\r\non:\r\n push:\r\n branches: [main]\r\n schedule:\r\n - cron: '0 0 * * 1' # Weekly on Monday\r\n\r\njobs:\r\n audit:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm audit --audit-level=high\r\n\r\n codeql:\r\n runs-on: ubuntu-latest\r\n permissions:\r\n actions: read\r\n contents: read\r\n security-events: write\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: github/codeql-action/init@v3\r\n with: {languages: javascript}\r\n - uses: github/codeql-action/autobuild@v3\r\n - uses: github/codeql-action/analyze@v3\r\n`,\r\n },\r\n {\r\n id: 'dependabot-config',\r\n name: 'Dependabot Config',\r\n description: 'Dependabot config: npm + GitHub Actions weekly updates',\r\n defaultPath: '.github/dependabot.yml',\r\n category: 'github-actions',\r\n content: `version: 2\r\nupdates:\r\n - package-ecosystem: npm\r\n directory: \"/\"\r\n schedule:\r\n interval: weekly\r\n day: monday\r\n groups:\r\n minor-and-patch:\r\n update-types: [\"minor\", \"patch\"]\r\n ignore:\r\n - dependency-name: \"*\"\r\n update-types: [\"version-update:semver-major\"]\r\n\r\n - package-ecosystem: github-actions\r\n directory: \"/\"\r\n schedule:\r\n interval: weekly\r\n day: monday\r\n`,\r\n },\r\n {\r\n id: 'release-workflow',\r\n name: 'Release Workflow',\r\n description: 'GitHub Actions release: GitHub Release + Docker image to GHCR',\r\n defaultPath: '.github/workflows/release.yml',\r\n category: 'github-actions',\r\n content: `name: Release\r\non:\r\n push:\r\n tags: ['v*']\r\n\r\njobs:\r\n release:\r\n runs-on: ubuntu-latest\r\n permissions:\r\n contents: write\r\n packages: write\r\n steps:\r\n - uses: actions/checkout@v4\r\n - name: Create GitHub Release\r\n uses: softprops/action-gh-release@v2\r\n with:\r\n generate_release_notes: true\r\n - name: Log in to GHCR\r\n uses: docker/login-action@v3\r\n with:\r\n registry: ghcr.io\r\n username: \\${{ github.actor }}\r\n password: \\${{ secrets.GITHUB_TOKEN }}\r\n - name: Build and push Docker image\r\n uses: docker/build-push-action@v5\r\n with:\r\n context: .\r\n push: true\r\n tags: |\r\n ghcr.io/\\${{ github.repository }}:\\${{ github.ref_name }}\r\n ghcr.io/\\${{ github.repository }}:latest\r\n`,\r\n },\r\n {\r\n id: 'codeowners',\r\n name: 'CODEOWNERS',\r\n description: 'GitHub CODEOWNERS file for review assignments',\r\n defaultPath: '.github/CODEOWNERS',\r\n category: 'github',\r\n content: `# IMPORTANT: Replace {{PROJECT_NAME}} below with your GitHub organization name\r\n# (org name and project name are often different)\r\n# Format: @org-name/team-slug\r\n\r\n# Global owners - review all changes\r\n* @{{PROJECT_NAME}}/maintainers\r\n\r\n# Documentation\r\ndocs/ @{{PROJECT_NAME}}/docs\r\n*.md @{{PROJECT_NAME}}/docs\r\n\r\n# CI/CD config\r\n.github/ @{{PROJECT_NAME}}/devops\r\nDockerfile @{{PROJECT_NAME}}/devops\r\ndocker-compose*.yml @{{PROJECT_NAME}}/devops\r\n\r\n# Security-sensitive files\r\n**/auth/ @{{PROJECT_NAME}}/security\r\n**/security/ @{{PROJECT_NAME}}/security\r\nSECURITY.md @{{PROJECT_NAME}}/security\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const CODE_QUALITY_TEMPLATES: Template[] = [\r\n {\r\n id: 'eslintrc',\r\n name: 'ESLint Config',\r\n description: 'ESLint config with TypeScript strict rules',\r\n defaultPath: '.eslintrc.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"extends\": [\r\n \"eslint:recommended\",\r\n \"plugin:@typescript-eslint/recommended\",\r\n \"plugin:@typescript-eslint/recommended-requiring-type-checking\"\r\n ],\r\n \"parser\": \"@typescript-eslint/parser\",\r\n \"parserOptions\": {\r\n \"project\": true,\r\n \"tsconfigRootDir\": \".\"\r\n },\r\n \"plugins\": [\"@typescript-eslint\"],\r\n \"rules\": {\r\n \"no-console\": \"warn\",\r\n \"no-unused-vars\": \"off\",\r\n \"@typescript-eslint/no-unused-vars\": [\"error\", { \"argsIgnorePattern\": \"^_\" }],\r\n \"@typescript-eslint/no-explicit-any\": \"warn\",\r\n \"@typescript-eslint/consistent-type-imports\": \"error\",\r\n \"@typescript-eslint/no-floating-promises\": \"error\"\r\n },\r\n \"ignorePatterns\": [\"dist/\", \"build/\", \"node_modules/\", \"*.config.js\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'prettierrc',\r\n name: 'Prettier Config',\r\n description: 'Prettier formatting config',\r\n defaultPath: '.prettierrc',\r\n category: 'code-quality',\r\n content: `{\r\n \"semi\": false,\r\n \"singleQuote\": true,\r\n \"trailingComma\": \"es5\",\r\n \"printWidth\": 100,\r\n \"tabWidth\": 2,\r\n \"useTabs\": false,\r\n \"bracketSpacing\": true,\r\n \"arrowParens\": \"avoid\"\r\n}\r\n`,\r\n },\r\n {\r\n id: 'tsconfig-strict',\r\n name: 'tsconfig (strict)',\r\n description: 'TypeScript config with strict settings for Node/ESM',\r\n defaultPath: 'tsconfig.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"compilerOptions\": {\r\n \"target\": \"ES2022\",\r\n \"lib\": [\"ES2022\"],\r\n \"module\": \"NodeNext\",\r\n \"moduleResolution\": \"NodeNext\",\r\n \"outDir\": \"dist\",\r\n \"rootDir\": \"src\",\r\n \"strict\": true,\r\n \"noUncheckedIndexedAccess\": true,\r\n \"exactOptionalPropertyTypes\": true,\r\n \"noImplicitReturns\": true,\r\n \"noFallthroughCasesInSwitch\": true,\r\n \"noImplicitOverride\": true,\r\n \"esModuleInterop\": true,\r\n \"skipLibCheck\": true,\r\n \"forceConsistentCasingInFileNames\": true,\r\n \"paths\": {\r\n \"@/*\": [\"./src/*\"]\r\n }\r\n },\r\n \"include\": [\"src/**/*\"],\r\n \"exclude\": [\"node_modules\", \"dist\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'editorconfig',\r\n name: '.editorconfig',\r\n description: 'EditorConfig for consistent editor settings',\r\n defaultPath: '.editorconfig',\r\n category: 'code-quality',\r\n content: `root = true\r\n\r\n[*]\r\nindent_style = space\r\nindent_size = 2\r\nend_of_line = lf\r\ncharset = utf-8\r\ntrim_trailing_whitespace = true\r\ninsert_final_newline = true\r\n\r\n[*.md]\r\ntrim_trailing_whitespace = false\r\n\r\n[Makefile]\r\nindent_style = tab\r\n\r\n[*.{yml,yaml}]\r\nindent_size = 2\r\n`,\r\n },\r\n {\r\n id: 'lint-staged',\r\n name: 'lint-staged Config',\r\n description: 'lint-staged config for pre-commit formatting and linting',\r\n defaultPath: '.lintstagedrc.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"*.{ts,tsx}\": [\"eslint --fix\", \"prettier --write\"],\r\n \"*.{js,jsx}\": [\"eslint --fix\", \"prettier --write\"],\r\n \"*.{json,md,yml,yaml}\": [\"prettier --write\"],\r\n \"*.{css,scss}\": [\"prettier --write\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'commitlint',\r\n name: 'commitlint Config',\r\n description: 'commitlint config enforcing Conventional Commits',\r\n defaultPath: 'commitlint.config.js',\r\n category: 'code-quality',\r\n content: `module.exports = {\r\n extends: ['@commitlint/config-conventional'],\r\n rules: {\r\n 'type-enum': [2, 'always', [\r\n 'feat', 'fix', 'docs', 'style', 'refactor',\r\n 'perf', 'test', 'chore', 'revert', 'ci', 'build'\r\n ]],\r\n 'scope-case': [2, 'always', 'lower-case'],\r\n 'subject-case': [2, 'always', 'lower-case'],\r\n 'subject-max-length': [2, 'always', 100],\r\n 'body-max-line-length': [2, 'always', 200],\r\n },\r\n}\r\n`,\r\n },\r\n {\r\n id: 'husky-setup',\r\n name: 'Husky Setup Doc',\r\n description: 'Documentation for Husky git hooks setup',\r\n defaultPath: '.husky/README.md',\r\n category: 'code-quality',\r\n content: `# Husky Git Hooks\r\n\r\nThis project uses [Husky](https://typicode.github.io/husky/) to enforce code quality at commit time.\r\n\r\n## Setup\r\n\r\nAfter cloning and running \\`npm install\\`, Husky hooks are auto-installed via the \\`prepare\\` script.\r\n\r\nIf hooks aren't running, install manually:\r\n\r\n\\`\\`\\`\r\nnpx husky install\r\n\\`\\`\\`\r\n\r\n## Hooks\r\n\r\n| Hook | Command | Purpose |\r\n|------|---------|---------|\r\n| pre-commit | \\`lint-staged\\` | Lint and format staged files |\r\n| commit-msg | \\`commitlint\\` | Validate commit message format |\r\n| pre-push | \\`npm test\\` | Run tests before pushing |\r\n\r\n## Skip hooks (emergencies only)\r\n\r\n\\`\\`\\`\r\ngit commit --no-verify -m \"emergency fix\"\r\n\\`\\`\\`\r\n\r\nUse sparingly. CI will still catch failures.\r\n`,\r\n },\r\n {\r\n id: 'vscode-settings',\r\n name: 'VS Code Settings',\r\n description: 'VS Code workspace settings for the project',\r\n defaultPath: '.vscode/settings.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"editor.formatOnSave\": true,\r\n \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\r\n \"editor.codeActionsOnSave\": {\r\n \"source.fixAll.eslint\": \"explicit\",\r\n \"source.organizeImports\": \"explicit\"\r\n },\r\n \"typescript.preferences.importModuleSpecifier\": \"non-relative\",\r\n \"typescript.tsdk\": \"node_modules/typescript/lib\",\r\n \"files.eol\": \"\\\\n\",\r\n \"files.trimTrailingWhitespace\": true,\r\n \"files.insertFinalNewline\": true,\r\n \"[markdown]\": {\r\n \"editor.formatOnSave\": false\r\n }\r\n}\r\n`,\r\n },\r\n {\r\n id: 'vscode-extensions',\r\n name: 'VS Code Extensions',\r\n description: 'Recommended VS Code extensions for the project',\r\n defaultPath: '.vscode/extensions.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"recommendations\": [\r\n \"esbenp.prettier-vscode\",\r\n \"dbaeumer.vscode-eslint\",\r\n \"ms-vscode.vscode-typescript-next\",\r\n \"bradlc.vscode-tailwindcss\",\r\n \"eamodio.gitlens\",\r\n \"usernamehw.errorlens\",\r\n \"streetsidesoftware.code-spell-checker\",\r\n \"github.copilot\",\r\n \"christian-kohler.path-intellisense\"\r\n ]\r\n}\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const MONITORING_TEMPLATES: Template[] = [\r\n {\r\n id: 'health-check-doc',\r\n name: 'Health Check Guide',\r\n description: 'Health check endpoint documentation with Kubernetes config',\r\n defaultPath: 'docs/health-checks.md',\r\n category: 'monitoring',\r\n content: `# Health Checks — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n\r\nHealth check endpoints allow load balancers and orchestrators to verify service status.\r\n\r\n## Endpoints\r\n\r\n| Endpoint | Purpose | Auth required |\r\n|----------|---------|---------------|\r\n| \\`GET /health\\` | Liveness probe — is the process running? | No |\r\n| \\`GET /health/ready\\` | Readiness probe — can the service handle traffic? | No |\r\n| \\`GET /health/detailed\\` | Full dependency status | Yes (internal) |\r\n\r\n## Liveness Check (\\`GET /health\\`)\r\n\r\nReturns 200 if the process is alive, regardless of dependency status.\r\n\r\n\\`\\`\\`json\r\n{\"status\": \"ok\", \"uptime\": 1234}\r\n\\`\\`\\`\r\n\r\n## Readiness Check (\\`GET /health/ready\\`)\r\n\r\nReturns 200 only if all critical dependencies are healthy.\r\n\r\n\\`\\`\\`json\r\n{\r\n \"status\": \"ready\",\r\n \"dependencies\": {\r\n \"database\": \"ok\",\r\n \"redis\": \"ok\",\r\n \"external_api\": \"degraded\"\r\n }\r\n}\r\n\\`\\`\\`\r\n\r\nReturns 503 if any critical dependency is unhealthy.\r\n\r\n## Kubernetes Configuration\r\n\r\n\\`\\`\\`yaml\r\nlivenessProbe:\r\n httpGet:\r\n path: /health\r\n port: 3000\r\n initialDelaySeconds: 30\r\n periodSeconds: 10\r\nreadinessProbe:\r\n httpGet:\r\n path: /health/ready\r\n port: 3000\r\n initialDelaySeconds: 5\r\n periodSeconds: 5\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'slo-doc',\r\n name: 'SLO/SLA Document',\r\n description: 'Service Level Objectives with error budget and burn rate alerts',\r\n defaultPath: 'docs/slo.md',\r\n category: 'monitoring',\r\n content: `# Service Level Objectives — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n**Owner:** Platform Team\r\n\r\n## Availability SLO\r\n\r\n| Metric | Target | Error Budget (30 days) |\r\n|--------|--------|----------------------|\r\n| Availability | 99.9% | 43.8 minutes |\r\n| Success rate | 99.5% | — |\r\n\r\n## Latency SLO\r\n\r\n| Percentile | Target |\r\n|------------|--------|\r\n| p50 | < 100ms |\r\n| p95 | < 500ms |\r\n| p99 | < 1000ms |\r\n\r\n## Error Budget Policy\r\n\r\n| Burn Rate | Alert Window | Severity | Action |\r\n|-----------|-------------|----------|--------|\r\n| > 14.4x | 1 hour | Critical | Page on-call immediately |\r\n| > 6x | 6 hours | High | Page on-call |\r\n| > 3x | 24 hours | Medium | Ticket + monitor |\r\n| > 1x | 72 hours | Low | Review in standup |\r\n\r\n## Consequences of Exhausting Error Budget\r\n\r\n- Feature freeze until budget replenishes\r\n- Reliability sprint prioritized over new features\r\n- Post-mortem required for any budget burn > 50%\r\n\r\n## Measurement\r\n\r\n- Uptime tracked via synthetic monitoring (Pingdom / UptimeRobot)\r\n- Latency tracked via APM (Datadog / New Relic)\r\n- Error rate from application logs + Sentry\r\n`,\r\n },\r\n {\r\n id: 'incident-runbook',\r\n name: 'Incident Runbook',\r\n description: 'Incident response runbook with severity levels and escalation',\r\n defaultPath: 'docs/incident-runbook.md',\r\n category: 'monitoring',\r\n content: `# Incident Runbook — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Severity Levels\r\n\r\n| Severity | Definition | Response Time | Example |\r\n|----------|-----------|---------------|---------|\r\n| P0 | Complete outage, all users affected | 15 minutes | Site down |\r\n| P1 | Major feature broken, >50% users affected | 30 minutes | Login broken |\r\n| P2 | Significant degradation, subset of users | 2 hours | Slow API |\r\n| P3 | Minor issue, workaround available | Next business day | Cosmetic bug |\r\n\r\n## Roles\r\n\r\n| Role | Responsibility |\r\n|------|---------------|\r\n| Incident Commander (IC) | Owns resolution, coordinates team, communicates status |\r\n| Tech Lead | Diagnoses root cause, coordinates fixes |\r\n| Comms Lead | Updates status page, notifies stakeholders |\r\n\r\n## Response Process\r\n\r\n### 0–15 minutes (Detect & Triage)\r\n1. Confirm the incident (not a false alarm)\r\n2. Assign Incident Commander\r\n3. Create incident Slack channel: \\`#incident-YYYYMMDD-description\\`\r\n4. Set severity level\r\n5. Start incident timeline document\r\n\r\n### 15–60 minutes (Investigate)\r\n1. Identify scope: what's broken, who's affected\r\n2. Check recent deployments (\\`git log\\`, deployment history)\r\n3. Review error rates and logs\r\n4. Consider rollback if recent deploy is suspected\r\n\r\n### Mitigation\r\n1. Apply fix or rollback\r\n2. Monitor for improvement\r\n3. Update status page\r\n4. Notify stakeholders\r\n\r\n## Post-Incident Checklist\r\n\r\n- [ ] Incident resolved and verified\r\n- [ ] Status page updated to \"resolved\"\r\n- [ ] Stakeholders notified\r\n- [ ] Timeline documented\r\n- [ ] Post-mortem scheduled (P0/P1) or ticket created (P2)\r\n- [ ] Action items created in project tracker\r\n`,\r\n },\r\n {\r\n id: 'postmortem',\r\n name: 'Postmortem Template',\r\n description: 'Blameless postmortem template with five-whys and action items',\r\n defaultPath: 'docs/postmortem-template.md',\r\n category: 'monitoring',\r\n content: `# Postmortem: [Title]\r\n\r\n**Date:** {{DATE}}\r\n**Severity:** P[0-3]\r\n**Duration:**\r\n**Author:**\r\n**Reviewers:**\r\n\r\n> This postmortem follows a blameless culture. We focus on systems and processes, not individuals.\r\n\r\n## Summary\r\n\r\n<!-- 2-3 sentence summary: what happened, why it matters, what we're doing about it -->\r\n\r\n## Impact\r\n\r\n- **Users affected:**\r\n- **Duration:**\r\n- **Revenue impact:**\r\n- **Data loss:**\r\n\r\n## Timeline\r\n\r\n| Time (UTC) | Event |\r\n|------------|-------|\r\n| 00:00 | Monitoring alert fired |\r\n| 00:05 | On-call engineer paged |\r\n| 00:15 | Incident confirmed, IC assigned |\r\n| 00:30 | Root cause identified |\r\n| 01:00 | Fix deployed |\r\n| 01:15 | Incident resolved |\r\n\r\n## Root Cause Analysis (Five Whys)\r\n\r\n**Problem:** [Describe the issue]\r\n\r\n1. **Why?** [First cause]\r\n2. **Why?** [Second cause]\r\n3. **Why?** [Third cause]\r\n4. **Why?** [Fourth cause]\r\n5. **Why?** [Root cause]\r\n\r\n## What Went Well\r\n\r\n-\r\n-\r\n\r\n## What Could Have Gone Better\r\n\r\n-\r\n-\r\n\r\n## Action Items\r\n\r\n| Action | Owner | Due Date | Priority |\r\n|--------|-------|----------|----------|\r\n| | | | P[0-3] |\r\n\r\n## Lessons Learned\r\n\r\n<!-- Key takeaways to share with the wider team -->\r\n`,\r\n },\r\n]\r\n","import { AI_AGENT_TEMPLATES } from './ai-agent'\r\nimport { GITHUB_TEMPLATES } from './github'\r\nimport { PROCESS_TEMPLATES } from './process'\r\nimport { TECHNICAL_TEMPLATES } from './technical'\r\nimport { INFRASTRUCTURE_TEMPLATES } from './infrastructure'\r\nimport { GITHUB_ACTIONS_TEMPLATES } from './github-actions'\r\nimport { CODE_QUALITY_TEMPLATES } from './code-quality'\r\nimport { MONITORING_TEMPLATES } from './monitoring'\r\n\r\nexport * from './types'\r\n\r\nexport const TEMPLATES = [\r\n ...AI_AGENT_TEMPLATES,\r\n ...GITHUB_TEMPLATES,\r\n ...PROCESS_TEMPLATES,\r\n ...TECHNICAL_TEMPLATES,\r\n ...INFRASTRUCTURE_TEMPLATES,\r\n ...GITHUB_ACTIONS_TEMPLATES,\r\n ...CODE_QUALITY_TEMPLATES,\r\n ...MONITORING_TEMPLATES,\r\n]\r\n\r\n// dedent removes common leading whitespace from template literals\r\nexport function dedent(str: string): string {\r\n const lines = str.split('\\n')\r\n // Skip empty leading lines\r\n const nonEmpty = lines.filter(l => l.trim().length > 0)\r\n if (nonEmpty.length === 0) return str\r\n const indent = Math.min(...nonEmpty.map(l => l.match(/^(\\s*)/)?.[1].length ?? 0))\r\n if (indent === 0) return str\r\n return lines.map(l => l.slice(indent)).join('\\n')\r\n}\r\n"],"names":["AI_AGENT_TEMPLATES","id","name","description","defaultPath","category","content"],"mappings":"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","ignoreList":[0]}
1
+ {"version":3,"sources":["../../../../src/lib/templates/ai-agent.ts","../../../../src/lib/templates/github.ts","../../../../src/lib/templates/process.ts","../../../../src/lib/templates/technical.ts","../../../../src/lib/templates/infrastructure.ts","../../../../src/lib/templates/github-actions.ts","../../../../src/lib/templates/code-quality.ts","../../../../src/lib/templates/monitoring.ts","../../../../src/lib/templates/index.ts"],"sourcesContent":["import type { Template } from './types'\r\n\r\nexport const AI_AGENT_TEMPLATES: Template[] = [\r\n {\r\n id: 'claude-md',\r\n name: 'CLAUDE.md',\r\n description: 'AI agent instructions for Claude Code',\r\n defaultPath: 'CLAUDE.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Agent Instructions\r\n\r\n## What this is\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Project type\r\n{{PROJECT_TYPE}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\n# Install dependencies\r\n{{PACKAGE_MANAGER}} install\r\n\r\n# Start development\r\nnpm run dev\r\n\r\n# Build for production\r\nnpm run build\r\n\r\n# Run tests\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Architecture\r\n- Primary language: {{PRIMARY_LANGUAGE}}\r\n- Deployment: {{DEPLOYMENT_PLATFORM}}\r\n- Key directories: \\`src/\\`, \\`docs/\\`, \\`tests/\\`\r\n- See \\`docs/architecture/overview.md\\` for full details\r\n\r\n## Read before coding\r\n- @docs/architecture/overview.md\r\n- @CONTRIBUTING.md\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Key features\r\n{{KEY_FEATURES}}\r\n\r\n## Non-negotiables\r\n- Always run \\`npm run build\\` before marking a task done — build must pass\r\n- Never use localStorage — causes SSR/client mismatch\r\n- Never commit secrets or credentials\r\n- Maintain test coverage\r\n- Follow security best practices\r\n\r\n## Code style\r\n- Follow existing patterns before introducing new abstractions\r\n- Keep modules small and focused\r\n- Write tests for business logic\r\n- Prefer explicit over implicit\r\n`,\r\n },\r\n {\r\n id: 'agents-md',\r\n name: 'AGENTS.md',\r\n description: 'AI agent instructions (multi-agent / OpenAI)',\r\n defaultPath: 'AGENTS.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Agent Instructions\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\nnpm install\r\nnpm run dev\r\nnpm run build\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Follow existing code patterns\r\n- Write tests for new features\r\n- Never commit secrets or credentials\r\n`,\r\n },\r\n {\r\n id: 'gemini-md',\r\n name: 'GEMINI.md',\r\n description: 'AI agent instructions for Gemini CLI',\r\n defaultPath: 'GEMINI.md',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Gemini Agent Instructions\r\n\r\n## What this is\r\n{{DESCRIPTION}}\r\n\r\n## Stack\r\n{{TECH_STACK}}\r\n\r\n## Commands\r\n\\`\\`\\`bash\r\n# Install dependencies\r\nnpm install\r\n\r\n# Start development\r\nnpm run dev\r\n\r\n# Build for production\r\nnpm run build\r\n\r\n# Run tests\r\nnpm test\r\n\\`\\`\\`\r\n\r\n## Key conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Follow existing code patterns\r\n- Write tests for new features\r\n- Never commit secrets or credentials\r\n`,\r\n },\r\n {\r\n id: 'cursorrules',\r\n name: '.cursorrules',\r\n description: 'Cursor IDE rules for AI assistance',\r\n defaultPath: '.cursorrules',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Cursor Rules\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Code style\r\n- Use {{TECH_STACK}} conventions\r\n- Follow existing patterns in the codebase\r\n- Prefer explicit over implicit\r\n- Keep functions small and focused\r\n\r\n## Conventions\r\n{{CONVENTIONS}}\r\n\r\n## What NOT to do\r\n- Don't introduce new dependencies without discussion\r\n- Don't break existing tests\r\n- Don't commit secrets or credentials\r\n- Don't over-engineer simple solutions\r\n`,\r\n },\r\n {\r\n id: 'windsurfrules',\r\n name: '.windsurfrules',\r\n description: 'Windsurf IDE rules for AI assistance',\r\n defaultPath: '.windsurfrules',\r\n category: 'ai-agent',\r\n content: `# {{PROJECT_NAME}} — Windsurf Rules\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Code style\r\n- Follow existing patterns in the codebase\r\n- Prefer explicit over implicit\r\n- Keep functions small and focused\r\n\r\n## Conventions\r\n{{CONVENTIONS}}\r\n\r\n## Non-negotiables\r\n- Don't introduce breaking changes\r\n- Don't commit secrets or credentials\r\n- Maintain test coverage\r\n`,\r\n },\r\n {\r\n id: 'copilot-instructions',\r\n name: 'Copilot Instructions',\r\n description: 'GitHub Copilot custom instructions',\r\n defaultPath: '.github/copilot-instructions.md',\r\n category: 'ai-agent',\r\n content: `# GitHub Copilot Instructions — {{PROJECT_NAME}}\r\n\r\n## Project overview\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## Coding conventions\r\n{{CONVENTIONS}}\r\n\r\n## Key features\r\n{{KEY_FEATURES}}\r\n\r\n## Style guidelines\r\n- Follow existing patterns before creating new abstractions\r\n- Write descriptive variable and function names\r\n- Add comments for non-obvious logic only\r\n- Keep functions focused on a single responsibility\r\n\r\n## Testing\r\n- Write tests for all new functionality\r\n- Maintain existing test coverage\r\n- Use the project's established testing patterns\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const GITHUB_TEMPLATES: Template[] = [\r\n {\r\n id: 'contributing',\r\n name: 'CONTRIBUTING.md',\r\n description: 'Contribution guidelines',\r\n defaultPath: 'CONTRIBUTING.md',\r\n category: 'github',\r\n content: `# Contributing to {{PROJECT_NAME}}\r\n\r\nThank you for your interest in contributing!\r\n\r\n## Getting started\r\n\r\n1. Fork the repository\r\n2. Clone your fork: \\`git clone {{REPO_URL}}\\`\r\n3. Create a feature branch: \\`git checkout -b feat/your-feature\\`\r\n4. Make your changes\r\n5. Submit a pull request\r\n\r\n## Branch naming\r\n\r\n| Type | Pattern | Example |\r\n|------|---------|---------|\r\n| Feature | \\`feat/<description>\\` | \\`feat/user-auth\\` |\r\n| Fix | \\`fix/<description>\\` | \\`fix/login-crash\\` |\r\n| Chore | \\`chore/<description>\\` | \\`chore/update-deps\\` |\r\n| Docs | \\`docs/<description>\\` | \\`docs/api-guide\\` |\r\n| Refactor | \\`refactor/<description>\\` | \\`refactor/auth-module\\` |\r\n| Release | \\`release/<version>\\` | \\`release/v1.2.0\\` |\r\n\r\n## Commit conventions\r\n\r\nWe use [Conventional Commits](https://conventionalcommits.org):\r\n\r\n| Type | When to use |\r\n|------|------------|\r\n| \\`feat\\` | New feature |\r\n| \\`fix\\` | Bug fix |\r\n| \\`docs\\` | Documentation only |\r\n| \\`refactor\\` | Code change that's neither fix nor feature |\r\n| \\`test\\` | Adding or updating tests |\r\n| \\`chore\\` | Build process, dependencies, tooling |\r\n| \\`perf\\` | Performance improvement |\r\n| \\`ci\\` | CI/CD changes |\r\n\r\nExamples:\r\n\\`\\`\\`\r\nfeat: add user authentication\r\nfix: resolve login redirect issue\r\ndocs: update API reference\r\nchore: upgrade dependencies\r\nfeat!: redesign auth API (breaking change — note the !)\r\n\\`\\`\\`\r\n\r\n## PR size guidance\r\n\r\n| Size | Lines changed | Guidance |\r\n|------|--------------|---------|\r\n| Small | < 400 lines | Ideal — fast to review |\r\n| Medium | 400–800 lines | Acceptable — add extra context in description |\r\n| Large | > 800 lines | Needs discussion before opening — split if possible |\r\n\r\nLarge PRs slow down the team and increase the chance of missed issues. When in doubt, split.\r\n\r\n## Pull request process\r\n\r\n1. Fill out the PR template completely\r\n2. Ensure all CI checks pass\r\n3. Request review from at least one maintainer\r\n4. Address all review comments\r\n5. Squash commits before merge\r\n\r\n## Code review checklist\r\n\r\n**Author:**\r\n- [ ] Self-reviewed the diff before requesting review\r\n- [ ] PR description explains the \"why\", not just the \"what\"\r\n- [ ] Tests added/updated and passing\r\n- [ ] No secrets or credentials in code\r\n- [ ] Breaking changes noted in PR description\r\n\r\n**Reviewer:**\r\n- [ ] Code is correct and handles edge cases\r\n- [ ] No obvious performance issues\r\n- [ ] Tests are meaningful (not just coverage padding)\r\n- [ ] Naming is clear and consistent with the codebase\r\n- [ ] Documentation updated if public API changed\r\n\r\n## Code style\r\n{{CONVENTIONS}}\r\n\r\n## Reporting bugs\r\n\r\nOpen an issue with:\r\n- Description of the bug\r\n- Steps to reproduce\r\n- Expected vs actual behavior\r\n- Environment details\r\n`,\r\n },\r\n {\r\n id: 'security',\r\n name: 'SECURITY.md',\r\n description: 'Security policy and vulnerability reporting',\r\n defaultPath: 'SECURITY.md',\r\n category: 'github',\r\n content: `# Security Policy — {{PROJECT_NAME}}\r\n\r\n## Supported versions\r\n\r\n| Version | Supported |\r\n|---------|-----------|\r\n| latest | ✅ |\r\n| < 1.0 | ❌ |\r\n\r\n## Reporting a vulnerability\r\n\r\n**Please do not report security vulnerabilities through public GitHub issues.**\r\n\r\nTo report a security issue, email: **security@example.com**\r\n\r\nYou may optionally encrypt your report using our PGP key (key ID: \\`0x00000000\\`, available on keys.openpgp.org).\r\n\r\nInclude:\r\n- Description of the vulnerability\r\n- Steps to reproduce\r\n- Potential impact\r\n- Any suggested mitigations\r\n\r\nYou will receive a response within **48 hours**. We will:\r\n1. Confirm receipt of your report\r\n2. Investigate and assess the issue\r\n3. Release a fix or mitigation\r\n4. Credit you in the release notes (unless you prefer anonymity)\r\n\r\n## Vulnerability SLAs\r\n\r\n| Severity | Fix SLA |\r\n|----------|---------|\r\n| Critical | 48 hours |\r\n| High | 7 days |\r\n| Medium | 30 days |\r\n| Low | 90 days |\r\n\r\nDependabot alerts for **critical** vulnerabilities must be resolved within 48 hours. Run \\`npm audit\\` in CI on every PR.\r\n\r\n## Secrets rotation schedule\r\n\r\n| Secret | Rotation | Owner |\r\n|--------|----------|-------|\r\n| JWT signing key | Every 90 days | Platform team |\r\n| Database passwords | Every 180 days | Platform team |\r\n| API keys (third-party) | On staff change | Security team |\r\n| Deploy tokens | Every 90 days | DevOps |\r\n\r\n## OWASP Top 10 checklist\r\n\r\n- [ ] **A01 Broken Access Control** — Enforce authorization on every endpoint; deny by default\r\n- [ ] **A02 Cryptographic Failures** — Use TLS everywhere; never store plaintext secrets; use bcrypt/argon2 for passwords\r\n- [ ] **A03 Injection** — Use parameterized queries; validate and sanitize all input\r\n- [ ] **A04 Insecure Design** — Threat model new features; use principle of least privilege\r\n- [ ] **A05 Security Misconfiguration** — Harden defaults; disable unused features; set security headers\r\n- [ ] **A06 Vulnerable Components** — Run \\`npm audit\\` in CI; automate with Dependabot\r\n- [ ] **A07 Auth Failures** — Implement MFA; lock accounts after failed attempts; use secure session management\r\n- [ ] **A08 Software Integrity Failures** — Verify checksums; use lockfiles; pin CI action versions\r\n- [ ] **A09 Logging Failures** — Log auth events, access failures; never log secrets or PII\r\n- [ ] **A10 SSRF** — Validate and allowlist URLs for any server-side requests\r\n\r\n## Security best practices\r\n\r\nWhen contributing to this project:\r\n- Never commit secrets, tokens, or credentials\r\n- Use environment variables for all sensitive configuration\r\n- Validate and sanitize all user input\r\n- Follow the principle of least privilege\r\n- Keep dependencies up to date\r\n`,\r\n },\r\n {\r\n id: 'pr-template',\r\n name: 'PR Template',\r\n description: 'Pull request template',\r\n defaultPath: '.github/pull_request_template.md',\r\n category: 'github',\r\n content: `## Description\r\n\r\n<!-- Briefly describe the changes and why they were made -->\r\n\r\n## Type of change\r\n\r\n- [ ] Bug fix (non-breaking change that fixes an issue)\r\n- [ ] New feature (non-breaking change that adds functionality)\r\n- [ ] Breaking change (fix or feature that would cause existing functionality to change)\r\n- [ ] Documentation update\r\n- [ ] Refactor / code cleanup\r\n- [ ] Dependency update\r\n\r\n## Related issues\r\n\r\nCloses #\r\n\r\n## How to test\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n## Screenshots / recordings\r\n\r\n<!-- If applicable, add screenshots or screen recordings -->\r\n\r\n## Checklist\r\n\r\n- [ ] My code follows the project's style guidelines\r\n- [ ] I have performed a self-review of my changes\r\n- [ ] I have added tests that prove my fix or feature works\r\n- [ ] New and existing unit tests pass locally\r\n- [ ] I have updated documentation if needed\r\n- [ ] No secrets or credentials are included\r\n`,\r\n },\r\n {\r\n id: 'bug-report',\r\n name: 'Bug Report Template',\r\n description: 'GitHub issue template for bugs',\r\n defaultPath: '.github/ISSUE_TEMPLATE/bug_report.md',\r\n category: 'github',\r\n content: `---\r\nname: Bug report\r\nabout: Create a report to help us improve\r\nlabels: bug\r\n---\r\n\r\n## Describe the bug\r\n\r\nA clear and concise description of what the bug is.\r\n\r\n## Steps to reproduce\r\n\r\n1. Go to '...'\r\n2. Click on '...'\r\n3. See error\r\n\r\n## Expected behavior\r\n\r\nA clear and concise description of what you expected to happen.\r\n\r\n## Actual behavior\r\n\r\nWhat actually happened.\r\n\r\n## Screenshots\r\n\r\nIf applicable, add screenshots to help explain your problem.\r\n\r\n## Environment\r\n\r\n- OS: [e.g. macOS 14]\r\n- Browser: [e.g. Chrome 120]\r\n- Version: [e.g. 1.2.3]\r\n- Node.js: [e.g. 20.x]\r\n\r\n## Additional context\r\n\r\nAdd any other context about the problem here.\r\n`,\r\n },\r\n {\r\n id: 'feature-request',\r\n name: 'Feature Request Template',\r\n description: 'GitHub issue template for features',\r\n defaultPath: '.github/ISSUE_TEMPLATE/feature_request.md',\r\n category: 'github',\r\n content: `---\r\nname: Feature request\r\nabout: Suggest an idea for this project\r\nlabels: enhancement\r\n---\r\n\r\n## Problem\r\n\r\nIs your feature request related to a problem? Please describe.\r\nA clear and concise description of what the problem is.\r\n\r\n## Proposed solution\r\n\r\nA clear and concise description of what you want to happen.\r\n\r\n## Alternatives considered\r\n\r\nA clear and concise description of any alternative solutions or features you've considered.\r\n\r\n## Implementation notes\r\n\r\nAny thoughts on how this might be implemented?\r\n\r\n## Additional context\r\n\r\nAdd any other context, mockups, or screenshots about the feature request here.\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const PROCESS_TEMPLATES: Template[] = [\r\n {\r\n id: 'changelog',\r\n name: 'CHANGELOG.md',\r\n description: 'Keep a Changelog format',\r\n defaultPath: 'CHANGELOG.md',\r\n category: 'process',\r\n content: `# Changelog — {{PROJECT_NAME}}\r\n\r\nAll notable changes to this project will be documented in this file.\r\n\r\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\r\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\r\n\r\n## [Unreleased]\r\n\r\n### Added\r\n-\r\n\r\n### Changed\r\n-\r\n\r\n### Fixed\r\n-\r\n\r\n### Removed\r\n-\r\n\r\n## [1.0.0] — {{DATE}}\r\n\r\n### Added\r\n- Initial release\r\n`,\r\n },\r\n {\r\n id: 'deployment',\r\n name: 'DEPLOYMENT.md',\r\n description: 'Deployment guide and procedures',\r\n defaultPath: 'DEPLOYMENT.md',\r\n category: 'process',\r\n content: `# Deployment Guide — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Environments\r\n\r\n| Environment | URL | Branch | Auto-deploy |\r\n|-------------|-----|--------|-------------|\r\n| Production | | \\`main\\` | No |\r\n| Staging | | \\`develop\\` | Yes |\r\n| Preview | | PRs | Yes |\r\n\r\n## Prerequisites\r\n\r\n- Access to deployment platform\r\n- Environment variables configured (see \\`.env.example\\`)\r\n- CI/CD pipeline passing\r\n\r\n## Deploy to production\r\n\r\n\\`\\`\\`bash\r\n# 1. Ensure tests pass\r\nnpm test\r\n\r\n# 2. Build and verify\r\nnpm run build\r\n\r\n# 3. Merge to main\r\ngit checkout main && git merge develop\r\n\r\n# 4. Tag the release\r\ngit tag v1.x.x && git push --tags\r\n\\`\\`\\`\r\n\r\n## Environment variables\r\n\r\n| Variable | Required | Description |\r\n|----------|----------|-------------|\r\n| | Yes | |\r\n\r\n## Rollback procedure\r\n\r\n1. Identify the last stable release tag\r\n2. \\`git checkout <tag>\\`\r\n3. Redeploy the previous version\r\n4. Verify the rollback with smoke tests\r\n\r\n## Smoke tests\r\n\r\nAfter every deploy, verify:\r\n- [ ] App loads at production URL\r\n- [ ] Auth flow works\r\n- [ ] Core features functional\r\n- [ ] No error spikes in monitoring\r\n\r\n## Contacts\r\n\r\n| Role | Contact |\r\n|------|---------|\r\n| On-call | |\r\n| Release manager | |\r\n`,\r\n },\r\n {\r\n id: 'testing',\r\n name: 'TESTING.md',\r\n description: 'Testing strategy and guide',\r\n defaultPath: 'TESTING.md',\r\n category: 'process',\r\n content: `# Testing Guide — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Test pyramid\r\n\r\n\\`\\`\\`\r\n /\\\\\r\n /E2E\\\\ 10% — Critical user flows only\r\n /------\\\\\r\n /Integr. \\\\ 20% — API, DB, service boundaries\r\n /----------\\\\\r\n / Unit \\\\ 70% — Functions, logic, utilities\r\n /______________\\\\\r\n\\`\\`\\`\r\n\r\n## Test strategy\r\n\r\n| Layer | Type | Tool | Coverage target |\r\n|-------|------|------|----------------|\r\n| Unit | Functions/logic | {{TEST_FRAMEWORK}} | 80%+ |\r\n| Integration | API/DB | {{TEST_FRAMEWORK}} | 70%+ |\r\n| E2E | User flows | Playwright | Key paths |\r\n\r\n## Coverage targets by directory\r\n\r\n| Directory | Target | Rationale |\r\n|-----------|--------|-----------|\r\n| \\`src/lib/\\` | 90%+ | Core business logic |\r\n| \\`src/api/\\` | 80%+ | API handlers |\r\n| \\`src/components/\\` | 60%+ | UI — focus on logic, not rendering |\r\n| \\`src/utils/\\` | 90%+ | Pure utility functions |\r\n\r\n## Running tests\r\n\r\n\\`\\`\\`bash\r\n# Run all tests\r\nnpm test\r\n\r\n# Run with coverage\r\nnpm run test:coverage\r\n\r\n# Run E2E tests\r\nnpm run test:e2e\r\n\r\n# Watch mode\r\nnpm run test:watch\r\n\\`\\`\\`\r\n\r\n## Writing tests\r\n\r\n### Unit test example\r\n\r\n\\`\\`\\`typescript\r\ndescribe('MyFunction', () => {\r\n it('should return expected value', () => {\r\n expect(myFunction(input)).toBe(expected)\r\n })\r\n})\r\n\\`\\`\\`\r\n\r\n### Integration test guidelines\r\n- Use a real database (not mocks) for DB tests\r\n- Reset state between tests\r\n- Test happy path and error cases\r\n\r\n### E2E test guidelines\r\n- Cover critical user journeys\r\n- Use stable selectors (\\`data-testid\\`)\r\n- Run against staging environment\r\n\r\n### Playwright config example\r\n\r\n\\`\\`\\`typescript\r\n// playwright.config.ts\r\nimport { defineConfig, devices } from '@playwright/test'\r\n\r\nexport default defineConfig({\r\n testDir: './e2e',\r\n fullyParallel: true,\r\n forbidOnly: !!process.env.CI,\r\n retries: process.env.CI ? 2 : 0,\r\n reporter: 'html',\r\n use: {\r\n baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',\r\n trace: 'on-first-retry',\r\n },\r\n projects: [\r\n {name: 'chromium', use: {...devices['Desktop Chrome']}},\r\n {name: 'Mobile Safari', use: {...devices['iPhone 13']}},\r\n ],\r\n webServer: {\r\n command: 'npm run dev',\r\n url: 'http://localhost:3000',\r\n reuseExistingServer: !process.env.CI,\r\n },\r\n})\r\n\\`\\`\\`\r\n\r\n## Flaky test policy\r\n\r\n1. **Quarantine immediately** — tag with \\`@flaky\\` and skip in CI (\\`test.skip\\`)\r\n2. **Create a ticket** — track as a P2 bug with a 2-week SLA to fix\r\n3. **Root cause** — common causes: timing issues, shared state, network calls\r\n4. **Fix or delete** — flaky tests are worse than no tests (false confidence)\r\n\r\nQuarantine example:\r\n\\`\\`\\`typescript\r\ntest.skip('flaky: timing issue with animation', async ({ page }) => {\r\n // TODO: fix by waiting for animation end event instead of sleep\r\n})\r\n\\`\\`\\`\r\n\r\n## Test organization\r\n\r\n\\`\\`\\`\r\nsrc/\r\n __tests__/ # Unit tests\r\n __integration__/ # Integration tests\r\ne2e/ # E2E tests\r\n\\`\\`\\`\r\n\r\n## CI/CD\r\n\r\nTests run automatically on every PR. PRs cannot merge with failing tests.\r\n`,\r\n },\r\n {\r\n id: 'glossary',\r\n name: 'Glossary',\r\n description: 'Project terminology reference',\r\n defaultPath: 'docs/glossary.md',\r\n category: 'process',\r\n content: `# Glossary — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\nThis document defines terms used throughout the project documentation and codebase.\r\n\r\n## Terms\r\n\r\n| Term | Definition |\r\n|------|------------|\r\n| | |\r\n\r\n## Acronyms\r\n\r\n| Acronym | Full form | Meaning |\r\n|---------|-----------|---------|\r\n| | | |\r\n\r\n## Domain concepts\r\n\r\n<!-- Add domain-specific concepts here -->\r\n\r\n---\r\n\r\n*Keep this document updated as new terminology is introduced.*\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nconst today = new Date().toISOString().split('T')[0]\r\n\r\nexport const TECHNICAL_TEMPLATES: Template[] = [\r\n {\r\n id: 'prd',\r\n name: 'PRD',\r\n description: 'Product requirements document',\r\n defaultPath: 'docs/prd.md',\r\n category: 'technical',\r\n content: `# Product Requirements — {{PROJECT_NAME}}\r\n\r\n**Status:** Draft\r\n**Last updated:** {{DATE}}\r\n**Author:**\r\n**Stakeholders:**\r\n\r\n## Problem statement\r\n{{DESCRIPTION}}\r\n\r\n## Goals\r\n-\r\n-\r\n\r\n## Non-goals\r\n-\r\n-\r\n\r\n## User stories\r\n| As a... | I want to... | So that... |\r\n|---------|--------------|------------|\r\n| user | | |\r\n\r\n## Requirements\r\n\r\n### Functional\r\n{{KEY_FEATURES}}\r\n\r\n### Non-functional\r\n- Performance:\r\n- Security:\r\n- Reliability:\r\n- Scalability:\r\n\r\n## Success metrics\r\n| Metric | Current | Target |\r\n|--------|---------|--------|\r\n| | | |\r\n\r\n## Timeline\r\n| Milestone | Target date |\r\n|-----------|-------------|\r\n| | |\r\n\r\n## Open questions\r\n-\r\n`,\r\n },\r\n {\r\n id: 'architecture-overview',\r\n name: 'Architecture Overview',\r\n description: 'System architecture doc',\r\n defaultPath: 'docs/architecture/overview.md',\r\n category: 'technical',\r\n content: `# Architecture Overview — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Summary\r\n{{DESCRIPTION}}\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## System diagram\r\n\r\n### Context (C4 Level 1)\r\n\r\n\\`\\`\\`mermaid\r\ngraph TB\r\n User[\"User\"] --> System[\"{{PROJECT_NAME}}\"]\r\n System --> ExternalAPI[\"External APIs\"]\r\n System --> DB[\"Database\"]\r\n\\`\\`\\`\r\n\r\n### Container (C4 Level 2)\r\n\r\n\\`\\`\\`mermaid\r\ngraph TB\r\n Client[\"Web Client<br/>(Browser)\"] --> API[\"API Server<br/>(Node.js)\"]\r\n API --> DB[\"Database<br/>(PostgreSQL)\"]\r\n API --> Cache[\"Cache<br/>(Redis)\"]\r\n API --> Queue[\"Job Queue\"]\r\n\\`\\`\\`\r\n\r\n## Components\r\n\r\n| Component | Responsibility | Tech |\r\n|-----------|---------------|------|\r\n| | | |\r\n\r\n## Data flow\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n## Key decisions\r\n\r\n| Decision | Chosen | Alternative | Rationale |\r\n|----------|--------|-------------|-----------|\r\n| | | | |\r\n\r\n## ADR log\r\n\r\n| ADR | Title | Status | Date |\r\n|-----|-------|--------|------|\r\n| 001 | | Accepted | {{DATE}} |\r\n\r\n## Non-goals\r\n\r\n- <!-- What this system explicitly does NOT do -->\r\n\r\n## Security considerations\r\n- Authentication:\r\n- Authorization:\r\n- Data validation:\r\n- Secrets management:\r\n\r\n## Scalability notes\r\n-\r\n`,\r\n },\r\n {\r\n id: 'api-reference',\r\n name: 'API Reference',\r\n description: 'API endpoints reference',\r\n defaultPath: 'docs/api-reference.md',\r\n category: 'technical',\r\n content: `# API Reference — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Base URL\r\n\r\n\\`\\`\\`\r\nhttps://api.example.com/v1\r\n\\`\\`\\`\r\n\r\n## Versioning\r\n\r\nThis API uses URL-based versioning (\\`/v1/\\`, \\`/v2/\\`, etc.).\r\n\r\n- The current stable version is \\`v1\\`.\r\n- Deprecated versions are supported for 12 months after a new version is released.\r\n- Breaking changes always increment the major version.\r\n\r\n## Authentication\r\n\r\nAll requests require a bearer token in the Authorization header:\r\n\r\n\\`\\`\\`\r\nAuthorization: Bearer <token>\r\n\\`\\`\\`\r\n\r\n### Token refresh\r\n\r\nTokens expire after 1 hour. Refresh using:\r\n\r\n\\`\\`\\`\r\nPOST /auth/refresh\r\nContent-Type: application/json\r\n\r\n{\"refreshToken\": \"<refresh_token>\"}\r\n\\`\\`\\`\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{\"accessToken\": \"...\", \"refreshToken\": \"...\", \"expiresIn\": 3600}\r\n\\`\\`\\`\r\n\r\n## Rate limiting\r\n\r\n- **Limit:** 1000 requests/hour per API key\r\n- **Headers:** \\`X-RateLimit-Limit\\`, \\`X-RateLimit-Remaining\\`, \\`X-RateLimit-Reset\\`\r\n\r\n## Pagination\r\n\r\nList endpoints support cursor-based pagination:\r\n\r\n\\`\\`\\`\r\nGET /resources?cursor=<cursor>&limit=20\r\n\\`\\`\\`\r\n\r\n## Error format\r\n\r\nAll errors follow a standard envelope:\r\n\r\n\\`\\`\\`json\r\n{\r\n \"code\": \"VALIDATION_ERROR\",\r\n \"message\": \"Human-readable description\",\r\n \"details\": [{\"field\": \"email\", \"issue\": \"invalid format\"}]\r\n}\r\n\\`\\`\\`\r\n\r\n## Error codes\r\n\r\n| Code | Meaning |\r\n|------|---------|\r\n| 400 | Bad request — invalid parameters |\r\n| 401 | Unauthorized — missing or invalid token |\r\n| 403 | Forbidden — insufficient permissions |\r\n| 404 | Not found |\r\n| 422 | Unprocessable entity — validation error |\r\n| 429 | Too many requests |\r\n| 500 | Internal server error |\r\n\r\n## Webhooks\r\n\r\n### Signature verification\r\n\r\nAll webhook payloads are signed with HMAC-SHA256. Verify the signature:\r\n\r\n\\`\\`\\`\r\nX-Webhook-Signature: sha256=<hmac_hex>\r\n\\`\\`\\`\r\n\r\n\\`\\`\\`typescript\r\nimport crypto from 'crypto'\r\n\r\nfunction verifyWebhook(payload: string, signature: string, secret: string): boolean {\r\n const expected = crypto\r\n .createHmac('sha256', secret)\r\n .update(payload)\r\n .digest('hex')\r\n return crypto.timingSafeEqual(\r\n Buffer.from(\\`sha256=\\${expected}\\`),\r\n Buffer.from(signature)\r\n )\r\n}\r\n\\`\\`\\`\r\n\r\n## Endpoints\r\n\r\n### GET /resource\r\n\r\n**Description:** List resources\r\n\r\n**Query parameters:**\r\n- \\`limit\\` (integer, default 20) — items per page\r\n- \\`cursor\\` (string) — pagination cursor\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{\r\n \"data\": [],\r\n \"cursor\": null,\r\n \"total\": 0\r\n}\r\n\\`\\`\\`\r\n\r\n### POST /resource\r\n\r\n**Description:** Create a resource\r\n\r\n**Request body:**\r\n\\`\\`\\`json\r\n{}\r\n\\`\\`\\`\r\n\r\n**Response:**\r\n\\`\\`\\`json\r\n{}\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'runbook',\r\n name: 'Runbook',\r\n description: 'Operational runbook',\r\n defaultPath: 'docs/runbook.md',\r\n category: 'technical',\r\n content: `# Runbook — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## SLOs\r\n\r\n| Metric | Target |\r\n|--------|--------|\r\n| Availability | 99.9% |\r\n| P95 latency | < 500ms |\r\n| Error rate | < 0.1% |\r\n\r\n## Environments\r\n\r\n| Env | URL | Purpose |\r\n|-----|-----|---------|\r\n| Production | | Live traffic |\r\n| Staging | | Pre-release testing |\r\n| Development | | Local dev |\r\n\r\n## Alerting\r\n\r\n| Alert | Threshold | Severity | Action |\r\n|-------|-----------|----------|--------|\r\n| | | | |\r\n\r\n## On-call contacts\r\n\r\n| Role | Name | Contact |\r\n|------|------|---------|\r\n| Primary | | |\r\n| Secondary | | |\r\n\r\n## Escalation matrix\r\n\r\n| Time since incident | Contact | Method |\r\n|--------------------|---------|--------|\r\n| 0–15 min | On-call engineer | PagerDuty / phone |\r\n| 15–30 min | Team lead | Slack + phone |\r\n| 30+ min | Engineering manager | Phone + email |\r\n\r\n## Procedures\r\n\r\n### Deploy\r\n\r\n1.\r\n2.\r\n3.\r\n\r\n### Rollback\r\n\r\n**When to rollback:**\r\n\r\n| Signal | Action |\r\n|--------|--------|\r\n| Error rate > 1% after deploy | Immediate rollback |\r\n| P95 latency doubled | Rollback if no fix in 15 min |\r\n| Health check failing | Immediate rollback |\r\n| Critical bug reported | Rollback within 30 min |\r\n\r\n**Rollback steps:**\r\n\r\n\\`\\`\\`bash\r\n# 1. Identify last stable release\r\ngit log --oneline --tags --simplify-by-decoration | head -5\r\n\r\n# 2. Deploy previous version\r\ngit checkout <previous-tag>\r\nnpm run build && npm run deploy\r\n\r\n# 3. Verify rollback\r\ncurl -f https://your-app.com/health\r\n\\`\\`\\`\r\n\r\n### Troubleshooting\r\n\r\n#### High error rate\r\n\\`\\`\\`bash\r\n# Check recent application logs\r\ntail -f /var/log/app/error.log\r\n\r\n# Check error counts by endpoint\r\ngrep \"ERROR\" /var/log/app/app.log | awk '{print $5}' | sort | uniq -c | sort -rn | head -10\r\n\r\n# Review recent deploys\r\ngit log --oneline -10\r\n\\`\\`\\`\r\n\r\n1. Check application logs for exception traces\r\n2. Check downstream dependencies (database, cache, external APIs)\r\n3. Review recent deploys — consider rollback if deploy-correlated\r\n\r\n#### High latency\r\n\\`\\`\\`bash\r\n# Check database slow query log\r\npsql $DATABASE_URL -c \"SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;\"\r\n\r\n# Check cache hit rate\r\nredis-cli info stats | grep hit_rate\r\n\r\n# Check CPU/memory\r\ntop -b -n 1 | head -20\r\n\\`\\`\\`\r\n\r\n1. Check database query times (slow query log)\r\n2. Check cache hit rates\r\n3. Review resource utilization (CPU, memory, connections)\r\n\r\n#### Service won't start\r\n\\`\\`\\`bash\r\n# Check environment variables\r\nenv | grep -E \"DATABASE|REDIS|PORT\"\r\n\r\n# Test database connectivity\r\npsql $DATABASE_URL -c \"SELECT 1\"\r\n\r\n# Check port availability\r\nlsof -i :3000\r\n\\`\\`\\`\r\n\r\n#### Database connection issues\r\n\\`\\`\\`bash\r\n# Check connection pool status\r\npsql $DATABASE_URL -c \"SELECT count(*), state FROM pg_stat_activity GROUP BY state;\"\r\n\r\n# Check max connections\r\npsql $DATABASE_URL -c \"SHOW max_connections;\"\r\n\\`\\`\\`\r\n\r\n#### Memory leak suspected\r\n\\`\\`\\`bash\r\n# Monitor memory over time\r\nwatch -n 5 'ps aux --sort=-%mem | head -5'\r\n\r\n# Capture heap snapshot (Node.js)\r\nkill -USR2 <pid>\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'adr',\r\n name: 'Architecture Decision',\r\n description: 'Architecture Decision Record',\r\n defaultPath: 'docs/architecture/decisions/ADR-001.md',\r\n category: 'technical',\r\n content: `# ADR-001: Title\r\n\r\n**Status:** Proposed\r\n**Date:** {{DATE}}\r\n**Deciders:**\r\n\r\n## Context\r\nWhat is the issue that we're seeing that is motivating this decision or change?\r\n\r\n## Decision\r\nWhat is the change that we're proposing and/or doing?\r\n\r\n## Rationale\r\nWhy did we choose this option?\r\n\r\n## Alternatives considered\r\n- **Option A:** Description — pros/cons\r\n- **Option B:** Description — pros/cons\r\n\r\n## Consequences\r\n\r\n### Positive\r\n-\r\n\r\n### Negative\r\n-\r\n\r\n### Neutral\r\n-\r\n`,\r\n },\r\n {\r\n id: 'onboarding',\r\n name: 'Onboarding Guide',\r\n description: 'Developer onboarding guide',\r\n defaultPath: 'docs/onboarding.md',\r\n category: 'technical',\r\n content: `# Developer Onboarding — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n{{DESCRIPTION}}\r\n\r\n## Prerequisites\r\n- [ ] Access to repository ({{REPO_URL}})\r\n- [ ] Access to staging environment\r\n- [ ] Accounts: (list required accounts/services)\r\n\r\n## Day 1: Get running\r\n\r\n- [ ] Clone the repository and set up local environment\r\n- [ ] Run the app locally and verify it works\r\n- [ ] Read the architecture overview (\\`docs/architecture/overview.md\\`)\r\n- [ ] Meet your team lead and get a tour of the codebase\r\n\r\n\\`\\`\\`bash\r\n# Clone\r\ngit clone {{REPO_URL}}\r\ncd {{PROJECT_NAME}}\r\n\r\n# Install dependencies\r\nnpm install\r\n\r\n# Copy environment variables\r\ncp .env.example .env.local\r\n# Edit .env.local with real values (ask your team lead)\r\n\r\n# Start development server\r\nnpm run dev\r\n\\`\\`\\`\r\n\r\n## Week 1: Get productive\r\n\r\n- [ ] Complete the environment setup checklist below\r\n- [ ] Read \\`CONTRIBUTING.md\\` and understand the PR process\r\n- [ ] Submit your first PR (even a small doc fix counts)\r\n- [ ] Attend team standup and sprint planning\r\n- [ ] Review 2–3 recent merged PRs to understand code patterns\r\n- [ ] Shadow a code review\r\n\r\n## Month 1: Get comfortable\r\n\r\n- [ ] Deliver your first feature end-to-end\r\n- [ ] Lead a code review\r\n- [ ] Identify one piece of tech debt and create a ticket\r\n- [ ] Update this onboarding doc with anything that was unclear\r\n\r\n## Environment setup\r\n\r\n\\`\\`\\`bash\r\n# Install dependencies\r\nnpm install\r\n\r\n# Copy environment variables\r\ncp .env.example .env.local\r\n\r\n# Start development server\r\nnpm run dev\r\n\\`\\`\\`\r\n\r\n## Tech stack\r\n{{TECH_STACK}}\r\n\r\n## IDE setup\r\n- Recommended: VS Code or Cursor\r\n- Install recommended extensions (see \\`.vscode/extensions.json\\`)\r\n- Enable format on save\r\n\r\n## Project structure\r\n\r\n\\`\\`\\`\r\n(describe key directories here)\r\n\\`\\`\\`\r\n\r\n## Key concepts\r\n-\r\n\r\n## Common tasks\r\n\r\n### Running tests\r\n\\`\\`\\`bash\r\nnpm test\r\n\\`\\`\\`\r\n\r\n### Building for production\r\n\\`\\`\\`bash\r\nnpm run build\r\n\\`\\`\\`\r\n\r\n## Common pitfalls\r\n\r\n1. **Forgetting to copy .env.local** — the app won't start without required env vars. Copy from \\`.env.example\\` and fill in real values.\r\n2. **Running \\`npm install\\` instead of the project's package manager** — check \\`package.json\\` for the \\`packageManager\\` field or look for a lock file (\\`pnpm-lock.yaml\\`, \\`yarn.lock\\`).\r\n3. **Committing to \\`main\\` directly** — always branch and open a PR. Direct pushes to \\`main\\` are blocked.\r\n4. **Skipping tests** — CI will catch you, but it's faster to run \\`npm test\\` locally before pushing.\r\n5. **Not reading existing patterns** — before adding a new abstraction, search the codebase for how similar problems are solved.\r\n\r\n## Your first PR\r\n\r\n1. Pick a small, well-defined issue labelled \\`good first issue\\`\r\n2. Create a branch: \\`git checkout -b feat/your-name-first-pr\\`\r\n3. Make the change and add a test\r\n4. Open a PR with the PR template filled out\r\n5. Ask for a review in the team Slack channel\r\n\r\n## Key contacts\r\n\r\n| Role | Name | Contact |\r\n|------|------|---------|\r\n| | | |\r\n\r\n## Resources\r\n- Architecture overview: \\`docs/architecture/overview.md\\`\r\n- API reference: \\`docs/api-reference.md\\`\r\n- Runbook: \\`docs/runbook.md\\`\r\n- Contributing guide: \\`CONTRIBUTING.md\\`\r\n`,\r\n },\r\n {\r\n id: 'database',\r\n name: 'Database Docs',\r\n description: 'Database schema and design reference',\r\n defaultPath: 'docs/DATABASE.md',\r\n category: 'technical',\r\n content: `# Database Documentation — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n\r\n<!-- Brief description of the database design -->\r\n\r\n## Entity Relationship Diagram\r\n\r\n\\`\\`\\`mermaid\r\nerDiagram\r\n USERS {\r\n uuid id PK\r\n string email\r\n timestamp created_at\r\n }\r\n\\`\\`\\`\r\n\r\n## Tables\r\n\r\n### users\r\n\r\n| Column | Type | Nullable | Description |\r\n|--------|------|----------|-------------|\r\n| id | uuid | No | Primary key |\r\n| email | varchar | No | Unique email |\r\n| created_at | timestamp | No | Creation time |\r\n\r\n## Indexes\r\n\r\n| Table | Columns | Type | Purpose |\r\n|-------|---------|------|---------|\r\n| | | | |\r\n\r\n## Migrations\r\n\r\nMigrations live in \\`db/migrations/\\`. Run with:\r\n\r\n\\`\\`\\`bash\r\nnpm run db:migrate\r\n\\`\\`\\`\r\n\r\n## Connection\r\n\r\n\\`\\`\\`\r\nDATABASE_URL=postgresql://user:password@host:5432/dbname\r\n\\`\\`\\`\r\n\r\n## Backup & restore\r\n\r\n\\`\\`\\`bash\r\n# Backup\r\npg_dump $DATABASE_URL > backup.sql\r\n\r\n# Restore\r\npsql $DATABASE_URL < backup.sql\r\n\\`\\`\\`\r\n\r\n## Performance notes\r\n\r\n-\r\n`,\r\n },\r\n {\r\n id: 'openapi',\r\n name: 'OpenAPI Spec',\r\n description: 'OpenAPI 3.0 API specification scaffold',\r\n defaultPath: 'docs/api-spec.yaml',\r\n category: 'technical',\r\n content: `openapi: 3.0.3\r\ninfo:\r\n title: {{PROJECT_NAME}} API\r\n description: |\r\n {{DESCRIPTION}}\r\n version: 1.0.0\r\n contact:\r\n email: team@example.com\r\n\r\nservers:\r\n - url: https://api.example.com/v1\r\n description: Production\r\n - url: https://staging-api.example.com/v1\r\n description: Staging\r\n\r\nsecurity:\r\n - bearerAuth: []\r\n\r\npaths:\r\n /health:\r\n get:\r\n summary: Health check\r\n operationId: healthCheck\r\n security: []\r\n responses:\r\n '200':\r\n description: OK\r\n content:\r\n application/json:\r\n schema:\r\n type: object\r\n properties:\r\n status:\r\n type: string\r\n example: ok\r\n\r\n /resources:\r\n get:\r\n summary: List resources\r\n operationId: listResources\r\n parameters:\r\n - name: limit\r\n in: query\r\n schema:\r\n type: integer\r\n default: 20\r\n - name: cursor\r\n in: query\r\n schema:\r\n type: string\r\n responses:\r\n '200':\r\n description: Success\r\n content:\r\n application/json:\r\n schema:\r\n $ref: '#/components/schemas/ResourceList'\r\n '401':\r\n $ref: '#/components/responses/Unauthorized'\r\n\r\ncomponents:\r\n securitySchemes:\r\n bearerAuth:\r\n type: http\r\n scheme: bearer\r\n bearerFormat: JWT\r\n\r\n schemas:\r\n Resource:\r\n type: object\r\n properties:\r\n id:\r\n type: string\r\n format: uuid\r\n createdAt:\r\n type: string\r\n format: date-time\r\n\r\n ResourceList:\r\n type: object\r\n properties:\r\n data:\r\n type: array\r\n items:\r\n $ref: '#/components/schemas/Resource'\r\n cursor:\r\n type: string\r\n nullable: true\r\n total:\r\n type: integer\r\n\r\n Error:\r\n type: object\r\n properties:\r\n error:\r\n type: string\r\n message:\r\n type: string\r\n\r\n responses:\r\n Unauthorized:\r\n description: Unauthorized\r\n content:\r\n application/json:\r\n schema:\r\n $ref: '#/components/schemas/Error'\r\n`,\r\n },\r\n {\r\n id: 'meeting-notes',\r\n name: 'Meeting Notes',\r\n description: 'Meeting notes template',\r\n defaultPath: `docs/meetings/${today}.md`,\r\n category: 'technical',\r\n content: `# Meeting Notes — ${today}\r\n\r\n**Attendees:**\r\n**Facilitator:**\r\n\r\n## Agenda\r\n\r\n1.\r\n2.\r\n\r\n## Notes\r\n\r\n## Decisions\r\n\r\n## Action items\r\n\r\n| Action | Owner | Due |\r\n|--------|-------|-----|\r\n| | | |\r\n\r\n## Next meeting\r\n`,\r\n },\r\n {\r\n id: 'blank',\r\n name: 'Blank Document',\r\n description: 'Empty markdown file',\r\n defaultPath: 'docs/untitled.md',\r\n category: 'technical',\r\n content: '# Untitled\\n\\n',\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const INFRASTRUCTURE_TEMPLATES: Template[] = [\r\n {\r\n id: 'dockerfile',\r\n name: 'Dockerfile',\r\n description: 'Multi-stage Docker build with health check',\r\n defaultPath: 'Dockerfile',\r\n category: 'infrastructure',\r\n content: `# Stage 1: Install dependencies\r\nFROM node:20-alpine AS deps\r\nRUN apk add --no-cache libc6-compat\r\nWORKDIR /app\r\nCOPY package*.json ./\r\nRUN npm ci --only=production\r\n\r\n# Stage 2: Build\r\nFROM node:20-alpine AS builder\r\nWORKDIR /app\r\nCOPY --from=deps /app/node_modules ./node_modules\r\nCOPY . .\r\nRUN npm run build\r\n\r\n# Stage 3: Run\r\nFROM node:20-alpine AS runner\r\nWORKDIR /app\r\nENV NODE_ENV=production\r\nRUN addgroup --system --gid 1001 nodejs\r\nRUN adduser --system --uid 1001 appuser\r\nCOPY --from=builder /app/dist ./dist\r\nCOPY --from=deps /app/node_modules ./node_modules\r\nCOPY package*.json ./\r\nUSER appuser\r\nEXPOSE 3000\r\nHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\\\\r\n CMD wget -qO- http://localhost:3000/health || exit 1\r\nCMD [\"node\", \"dist/index.js\"]\r\n`,\r\n },\r\n {\r\n id: 'docker-compose',\r\n name: 'docker-compose.yml',\r\n description: 'Docker Compose with app, Postgres, and Redis',\r\n defaultPath: 'docker-compose.yml',\r\n category: 'infrastructure',\r\n content: `# Docker Compose V2+ (no version key needed)\r\nservices:\r\n app:\r\n build: .\r\n ports:\r\n - \"3000:3000\"\r\n environment:\r\n DATABASE_URL: postgresql://postgres:password@db:5432/{{PROJECT_NAME}}\r\n REDIS_URL: redis://redis:6379\r\n depends_on:\r\n db:\r\n condition: service_healthy\r\n redis:\r\n condition: service_healthy\r\n\r\n db:\r\n image: postgres:16-alpine\r\n environment:\r\n POSTGRES_PASSWORD: password\r\n POSTGRES_DB: {{PROJECT_NAME}}\r\n healthcheck:\r\n test: [\"CMD-SHELL\", \"pg_isready -U postgres\"]\r\n interval: 10s\r\n timeout: 5s\r\n retries: 5\r\n volumes:\r\n - postgres_data:/var/lib/postgresql/data\r\n\r\n redis:\r\n image: redis:7-alpine\r\n healthcheck:\r\n test: [\"CMD\", \"redis-cli\", \"ping\"]\r\n interval: 10s\r\n timeout: 5s\r\n retries: 5\r\n volumes:\r\n - redis_data:/data\r\n\r\nvolumes:\r\n postgres_data:\r\n redis_data:\r\n`,\r\n },\r\n {\r\n id: 'dockerignore',\r\n name: '.dockerignore',\r\n description: 'Docker build context exclusions',\r\n defaultPath: '.dockerignore',\r\n category: 'infrastructure',\r\n content: `node_modules\r\nnpm-debug.log*\r\n.git\r\n.gitignore\r\n.env*\r\n!.env.example\r\ndist\r\nbuild\r\ncoverage\r\n.nyc_output\r\n*.test.*\r\n*.spec.*\r\n__tests__\r\ne2e\r\n.github\r\ndocs\r\nREADME.md\r\nCHANGELOG.md\r\n`,\r\n },\r\n {\r\n id: 'makefile',\r\n name: 'Makefile',\r\n description: 'Makefile with common dev/build/deploy targets',\r\n defaultPath: 'Makefile',\r\n category: 'infrastructure',\r\n content: `.PHONY: help dev build test lint docker-up docker-down migrate clean\r\n\r\nhelp: ## Show this help\r\n\\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\\\033[36m%-20s\\\\033[0m %s\\\\n\", $$1, $$2}'\r\n\r\ndev: ## Start development server\r\n\\tnpm run dev\r\n\r\nbuild: ## Build for production\r\n\\tnpm run build\r\n\r\ntest: ## Run all tests\r\n\\tnpm test\r\n\r\nlint: ## Run linter\r\n\\tnpm run lint\r\n\r\ndocker-up: ## Start Docker services\r\n\\tdocker compose up -d\r\n\r\ndocker-down: ## Stop Docker services\r\n\\tdocker compose down\r\n\r\nmigrate: ## Run database migrations\r\n\\tnpm run db:migrate\r\n\r\nclean: ## Remove build artifacts\r\n\\trm -rf dist build .next coverage node_modules/.cache\r\n`,\r\n },\r\n {\r\n id: 'env-example',\r\n name: '.env.example',\r\n description: 'Annotated environment variables template',\r\n defaultPath: '.env.example',\r\n category: 'infrastructure',\r\n content: `# App Config\r\nNODE_ENV=development\r\nPORT=3000\r\nAPP_URL=http://localhost:3000\r\nLOG_LEVEL=info\r\n\r\n# Database\r\nDATABASE_URL=postgresql://user:password@localhost:5432/{{PROJECT_NAME}}_dev\r\n\r\n# Auth\r\nJWT_SECRET=your-super-secret-jwt-key-change-in-production\r\nJWT_EXPIRES_IN=7d\r\nSESSION_SECRET=your-session-secret-change-in-production\r\n\r\n# External Services\r\n# STRIPE_SECRET_KEY=sk_test_...\r\n# SENDGRID_API_KEY=SG....\r\n# AWS_ACCESS_KEY_ID=\r\n# AWS_SECRET_ACCESS_KEY=\r\n# AWS_REGION=us-east-1\r\n# AWS_S3_BUCKET=\r\n\r\n# Observability\r\n# SENTRY_DSN=https://...@sentry.io/...\r\n# DATADOG_API_KEY=\r\n# NEW_RELIC_LICENSE_KEY=\r\n`,\r\n },\r\n {\r\n id: 'nginx-conf',\r\n name: 'nginx.conf',\r\n description: 'Nginx reverse proxy with gzip, security headers, rate limiting',\r\n defaultPath: 'nginx/nginx.conf',\r\n category: 'infrastructure',\r\n content: `events {\r\n worker_connections 1024;\r\n}\r\n\r\nhttp {\r\n gzip on;\r\n gzip_types text/plain text/css application/json application/javascript text/xml;\r\n gzip_min_length 1000;\r\n\r\n # Rate limiting\r\n limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;\r\n\r\n server {\r\n listen 80;\r\n server_name _;\r\n\r\n # Security headers\r\n add_header X-Frame-Options \"SAMEORIGIN\" always;\r\n add_header X-Content-Type-Options \"nosniff\" always;\r\n add_header X-XSS-Protection \"1; mode=block\" always;\r\n add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;\r\n add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\" always;\r\n\r\n location /api/ {\r\n limit_req zone=api burst=20 nodelay;\r\n proxy_pass http://app:3000;\r\n proxy_http_version 1.1;\r\n proxy_set_header Upgrade $http_upgrade;\r\n proxy_set_header Connection 'upgrade';\r\n proxy_set_header Host $host;\r\n proxy_set_header X-Real-IP $remote_addr;\r\n proxy_cache_bypass $http_upgrade;\r\n }\r\n\r\n location / {\r\n proxy_pass http://app:3000;\r\n proxy_http_version 1.1;\r\n proxy_set_header Host $host;\r\n proxy_set_header X-Real-IP $remote_addr;\r\n }\r\n }\r\n}\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const GITHUB_ACTIONS_TEMPLATES: Template[] = [\r\n {\r\n id: 'ci-workflow',\r\n name: 'CI Workflow',\r\n description: 'GitHub Actions CI: lint, typecheck, test matrix, coverage',\r\n defaultPath: '.github/workflows/ci.yml',\r\n category: 'github-actions',\r\n content: `name: CI\r\non:\r\n push:\r\n branches: [main, develop]\r\n pull_request:\r\n branches: [main, develop]\r\n\r\njobs:\r\n lint:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run lint\r\n - run: npm run typecheck\r\n\r\n test:\r\n runs-on: ubuntu-latest\r\n strategy:\r\n matrix:\r\n node-version: ['20', '22']\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '\\${{ matrix.node-version }}', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run test:coverage\r\n - uses: codecov/codecov-action@v4\r\n if: matrix.node-version == '20'\r\n\r\n build:\r\n runs-on: ubuntu-latest\r\n needs: [lint, test]\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run build\r\n`,\r\n },\r\n {\r\n id: 'cd-workflow',\r\n name: 'CD Workflow',\r\n description: 'GitHub Actions CD: deploy to production with health check',\r\n defaultPath: '.github/workflows/cd.yml',\r\n category: 'github-actions',\r\n content: `name: CD\r\non:\r\n push:\r\n branches: [main]\r\n\r\njobs:\r\n deploy:\r\n runs-on: ubuntu-latest\r\n # needs: [ci] # Uncomment if using a reusable CI workflow\r\n environment: production\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm run build\r\n - name: Deploy\r\n env:\r\n DEPLOY_TOKEN: \\${{ secrets.DEPLOY_TOKEN }}\r\n DEPLOY_URL: \\${{ secrets.DEPLOY_URL }}\r\n run: |\r\n # Add your deployment command here\r\n # e.g.: npx railway deploy, vercel deploy --prod, etc.\r\n echo \"Deploy to production\"\r\n - name: Health check\r\n run: |\r\n sleep 30\r\n curl -f \\${{ secrets.APP_URL }}/health || exit 1\r\n`,\r\n },\r\n {\r\n id: 'security-scan',\r\n name: 'Security Scan',\r\n description: 'GitHub Actions security: npm audit + CodeQL analysis',\r\n defaultPath: '.github/workflows/security.yml',\r\n category: 'github-actions',\r\n content: `name: Security\r\non:\r\n push:\r\n branches: [main]\r\n schedule:\r\n - cron: '0 0 * * 1' # Weekly on Monday\r\n\r\njobs:\r\n audit:\r\n runs-on: ubuntu-latest\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: actions/setup-node@v4\r\n with: {node-version: '20', cache: 'npm'}\r\n - run: npm ci\r\n - run: npm audit --audit-level=high\r\n\r\n codeql:\r\n runs-on: ubuntu-latest\r\n permissions:\r\n actions: read\r\n contents: read\r\n security-events: write\r\n steps:\r\n - uses: actions/checkout@v4\r\n - uses: github/codeql-action/init@v3\r\n with: {languages: javascript}\r\n - uses: github/codeql-action/autobuild@v3\r\n - uses: github/codeql-action/analyze@v3\r\n`,\r\n },\r\n {\r\n id: 'dependabot-config',\r\n name: 'Dependabot Config',\r\n description: 'Dependabot config: npm + GitHub Actions weekly updates',\r\n defaultPath: '.github/dependabot.yml',\r\n category: 'github-actions',\r\n content: `version: 2\r\nupdates:\r\n - package-ecosystem: npm\r\n directory: \"/\"\r\n schedule:\r\n interval: weekly\r\n day: monday\r\n groups:\r\n minor-and-patch:\r\n update-types: [\"minor\", \"patch\"]\r\n ignore:\r\n - dependency-name: \"*\"\r\n update-types: [\"version-update:semver-major\"]\r\n\r\n - package-ecosystem: github-actions\r\n directory: \"/\"\r\n schedule:\r\n interval: weekly\r\n day: monday\r\n`,\r\n },\r\n {\r\n id: 'release-workflow',\r\n name: 'Release Workflow',\r\n description: 'GitHub Actions release: GitHub Release + Docker image to GHCR',\r\n defaultPath: '.github/workflows/release.yml',\r\n category: 'github-actions',\r\n content: `name: Release\r\non:\r\n push:\r\n tags: ['v*']\r\n\r\njobs:\r\n release:\r\n runs-on: ubuntu-latest\r\n permissions:\r\n contents: write\r\n packages: write\r\n steps:\r\n - uses: actions/checkout@v4\r\n - name: Create GitHub Release\r\n uses: softprops/action-gh-release@v2\r\n with:\r\n generate_release_notes: true\r\n - name: Log in to GHCR\r\n uses: docker/login-action@v3\r\n with:\r\n registry: ghcr.io\r\n username: \\${{ github.actor }}\r\n password: \\${{ secrets.GITHUB_TOKEN }}\r\n - name: Build and push Docker image\r\n uses: docker/build-push-action@v5\r\n with:\r\n context: .\r\n push: true\r\n tags: |\r\n ghcr.io/\\${{ github.repository }}:\\${{ github.ref_name }}\r\n ghcr.io/\\${{ github.repository }}:latest\r\n`,\r\n },\r\n {\r\n id: 'codeowners',\r\n name: 'CODEOWNERS',\r\n description: 'GitHub CODEOWNERS file for review assignments',\r\n defaultPath: '.github/CODEOWNERS',\r\n category: 'github',\r\n content: `# IMPORTANT: Replace {{PROJECT_NAME}} below with your GitHub organization name\r\n# (org name and project name are often different)\r\n# Format: @org-name/team-slug\r\n\r\n# Global owners - review all changes\r\n* @{{PROJECT_NAME}}/maintainers\r\n\r\n# Documentation\r\ndocs/ @{{PROJECT_NAME}}/docs\r\n*.md @{{PROJECT_NAME}}/docs\r\n\r\n# CI/CD config\r\n.github/ @{{PROJECT_NAME}}/devops\r\nDockerfile @{{PROJECT_NAME}}/devops\r\ndocker-compose*.yml @{{PROJECT_NAME}}/devops\r\n\r\n# Security-sensitive files\r\n**/auth/ @{{PROJECT_NAME}}/security\r\n**/security/ @{{PROJECT_NAME}}/security\r\nSECURITY.md @{{PROJECT_NAME}}/security\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const CODE_QUALITY_TEMPLATES: Template[] = [\r\n {\r\n id: 'eslintrc',\r\n name: 'ESLint Config',\r\n description: 'ESLint config with TypeScript strict rules',\r\n defaultPath: '.eslintrc.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"extends\": [\r\n \"eslint:recommended\",\r\n \"plugin:@typescript-eslint/recommended\",\r\n \"plugin:@typescript-eslint/recommended-requiring-type-checking\"\r\n ],\r\n \"parser\": \"@typescript-eslint/parser\",\r\n \"parserOptions\": {\r\n \"project\": true,\r\n \"tsconfigRootDir\": \".\"\r\n },\r\n \"plugins\": [\"@typescript-eslint\"],\r\n \"rules\": {\r\n \"no-console\": \"warn\",\r\n \"no-unused-vars\": \"off\",\r\n \"@typescript-eslint/no-unused-vars\": [\"error\", { \"argsIgnorePattern\": \"^_\" }],\r\n \"@typescript-eslint/no-explicit-any\": \"warn\",\r\n \"@typescript-eslint/consistent-type-imports\": \"error\",\r\n \"@typescript-eslint/no-floating-promises\": \"error\"\r\n },\r\n \"ignorePatterns\": [\"dist/\", \"build/\", \"node_modules/\", \"*.config.js\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'prettierrc',\r\n name: 'Prettier Config',\r\n description: 'Prettier formatting config',\r\n defaultPath: '.prettierrc',\r\n category: 'code-quality',\r\n content: `{\r\n \"semi\": false,\r\n \"singleQuote\": true,\r\n \"trailingComma\": \"es5\",\r\n \"printWidth\": 100,\r\n \"tabWidth\": 2,\r\n \"useTabs\": false,\r\n \"bracketSpacing\": true,\r\n \"arrowParens\": \"avoid\"\r\n}\r\n`,\r\n },\r\n {\r\n id: 'tsconfig-strict',\r\n name: 'tsconfig (strict)',\r\n description: 'TypeScript config with strict settings for Node/ESM',\r\n defaultPath: 'tsconfig.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"compilerOptions\": {\r\n \"target\": \"ES2022\",\r\n \"lib\": [\"ES2022\"],\r\n \"module\": \"NodeNext\",\r\n \"moduleResolution\": \"NodeNext\",\r\n \"outDir\": \"dist\",\r\n \"rootDir\": \"src\",\r\n \"strict\": true,\r\n \"noUncheckedIndexedAccess\": true,\r\n \"exactOptionalPropertyTypes\": true,\r\n \"noImplicitReturns\": true,\r\n \"noFallthroughCasesInSwitch\": true,\r\n \"noImplicitOverride\": true,\r\n \"esModuleInterop\": true,\r\n \"skipLibCheck\": true,\r\n \"forceConsistentCasingInFileNames\": true,\r\n \"paths\": {\r\n \"@/*\": [\"./src/*\"]\r\n }\r\n },\r\n \"include\": [\"src/**/*\"],\r\n \"exclude\": [\"node_modules\", \"dist\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'editorconfig',\r\n name: '.editorconfig',\r\n description: 'EditorConfig for consistent editor settings',\r\n defaultPath: '.editorconfig',\r\n category: 'code-quality',\r\n content: `root = true\r\n\r\n[*]\r\nindent_style = space\r\nindent_size = 2\r\nend_of_line = lf\r\ncharset = utf-8\r\ntrim_trailing_whitespace = true\r\ninsert_final_newline = true\r\n\r\n[*.md]\r\ntrim_trailing_whitespace = false\r\n\r\n[Makefile]\r\nindent_style = tab\r\n\r\n[*.{yml,yaml}]\r\nindent_size = 2\r\n`,\r\n },\r\n {\r\n id: 'lint-staged',\r\n name: 'lint-staged Config',\r\n description: 'lint-staged config for pre-commit formatting and linting',\r\n defaultPath: '.lintstagedrc.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"*.{ts,tsx}\": [\"eslint --fix\", \"prettier --write\"],\r\n \"*.{js,jsx}\": [\"eslint --fix\", \"prettier --write\"],\r\n \"*.{json,md,yml,yaml}\": [\"prettier --write\"],\r\n \"*.{css,scss}\": [\"prettier --write\"]\r\n}\r\n`,\r\n },\r\n {\r\n id: 'commitlint',\r\n name: 'commitlint Config',\r\n description: 'commitlint config enforcing Conventional Commits',\r\n defaultPath: 'commitlint.config.js',\r\n category: 'code-quality',\r\n content: `module.exports = {\r\n extends: ['@commitlint/config-conventional'],\r\n rules: {\r\n 'type-enum': [2, 'always', [\r\n 'feat', 'fix', 'docs', 'style', 'refactor',\r\n 'perf', 'test', 'chore', 'revert', 'ci', 'build'\r\n ]],\r\n 'scope-case': [2, 'always', 'lower-case'],\r\n 'subject-case': [2, 'always', 'lower-case'],\r\n 'subject-max-length': [2, 'always', 100],\r\n 'body-max-line-length': [2, 'always', 200],\r\n },\r\n}\r\n`,\r\n },\r\n {\r\n id: 'husky-setup',\r\n name: 'Husky Setup Doc',\r\n description: 'Documentation for Husky git hooks setup',\r\n defaultPath: '.husky/README.md',\r\n category: 'code-quality',\r\n content: `# Husky Git Hooks\r\n\r\nThis project uses [Husky](https://typicode.github.io/husky/) to enforce code quality at commit time.\r\n\r\n## Setup\r\n\r\nAfter cloning and running \\`npm install\\`, Husky hooks are auto-installed via the \\`prepare\\` script.\r\n\r\nIf hooks aren't running, install manually:\r\n\r\n\\`\\`\\`\r\nnpx husky install\r\n\\`\\`\\`\r\n\r\n## Hooks\r\n\r\n| Hook | Command | Purpose |\r\n|------|---------|---------|\r\n| pre-commit | \\`lint-staged\\` | Lint and format staged files |\r\n| commit-msg | \\`commitlint\\` | Validate commit message format |\r\n| pre-push | \\`npm test\\` | Run tests before pushing |\r\n\r\n## Skip hooks (emergencies only)\r\n\r\n\\`\\`\\`\r\ngit commit --no-verify -m \"emergency fix\"\r\n\\`\\`\\`\r\n\r\nUse sparingly. CI will still catch failures.\r\n`,\r\n },\r\n {\r\n id: 'vscode-settings',\r\n name: 'VS Code Settings',\r\n description: 'VS Code workspace settings for the project',\r\n defaultPath: '.vscode/settings.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"editor.formatOnSave\": true,\r\n \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\r\n \"editor.codeActionsOnSave\": {\r\n \"source.fixAll.eslint\": \"explicit\",\r\n \"source.organizeImports\": \"explicit\"\r\n },\r\n \"typescript.preferences.importModuleSpecifier\": \"non-relative\",\r\n \"typescript.tsdk\": \"node_modules/typescript/lib\",\r\n \"files.eol\": \"\\\\n\",\r\n \"files.trimTrailingWhitespace\": true,\r\n \"files.insertFinalNewline\": true,\r\n \"[markdown]\": {\r\n \"editor.formatOnSave\": false\r\n }\r\n}\r\n`,\r\n },\r\n {\r\n id: 'vscode-extensions',\r\n name: 'VS Code Extensions',\r\n description: 'Recommended VS Code extensions for the project',\r\n defaultPath: '.vscode/extensions.json',\r\n category: 'code-quality',\r\n content: `{\r\n \"recommendations\": [\r\n \"esbenp.prettier-vscode\",\r\n \"dbaeumer.vscode-eslint\",\r\n \"ms-vscode.vscode-typescript-next\",\r\n \"bradlc.vscode-tailwindcss\",\r\n \"eamodio.gitlens\",\r\n \"usernamehw.errorlens\",\r\n \"streetsidesoftware.code-spell-checker\",\r\n \"github.copilot\",\r\n \"christian-kohler.path-intellisense\"\r\n ]\r\n}\r\n`,\r\n },\r\n]\r\n","import type { Template } from './types'\r\n\r\nexport const MONITORING_TEMPLATES: Template[] = [\r\n {\r\n id: 'health-check-doc',\r\n name: 'Health Check Guide',\r\n description: 'Health check endpoint documentation with Kubernetes config',\r\n defaultPath: 'docs/health-checks.md',\r\n category: 'monitoring',\r\n content: `# Health Checks — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Overview\r\n\r\nHealth check endpoints allow load balancers and orchestrators to verify service status.\r\n\r\n## Endpoints\r\n\r\n| Endpoint | Purpose | Auth required |\r\n|----------|---------|---------------|\r\n| \\`GET /health\\` | Liveness probe — is the process running? | No |\r\n| \\`GET /health/ready\\` | Readiness probe — can the service handle traffic? | No |\r\n| \\`GET /health/detailed\\` | Full dependency status | Yes (internal) |\r\n\r\n## Liveness Check (\\`GET /health\\`)\r\n\r\nReturns 200 if the process is alive, regardless of dependency status.\r\n\r\n\\`\\`\\`json\r\n{\"status\": \"ok\", \"uptime\": 1234}\r\n\\`\\`\\`\r\n\r\n## Readiness Check (\\`GET /health/ready\\`)\r\n\r\nReturns 200 only if all critical dependencies are healthy.\r\n\r\n\\`\\`\\`json\r\n{\r\n \"status\": \"ready\",\r\n \"dependencies\": {\r\n \"database\": \"ok\",\r\n \"redis\": \"ok\",\r\n \"external_api\": \"degraded\"\r\n }\r\n}\r\n\\`\\`\\`\r\n\r\nReturns 503 if any critical dependency is unhealthy.\r\n\r\n## Kubernetes Configuration\r\n\r\n\\`\\`\\`yaml\r\nlivenessProbe:\r\n httpGet:\r\n path: /health\r\n port: 3000\r\n initialDelaySeconds: 30\r\n periodSeconds: 10\r\nreadinessProbe:\r\n httpGet:\r\n path: /health/ready\r\n port: 3000\r\n initialDelaySeconds: 5\r\n periodSeconds: 5\r\n\\`\\`\\`\r\n`,\r\n },\r\n {\r\n id: 'slo-doc',\r\n name: 'SLO/SLA Document',\r\n description: 'Service Level Objectives with error budget and burn rate alerts',\r\n defaultPath: 'docs/slo.md',\r\n category: 'monitoring',\r\n content: `# Service Level Objectives — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n**Owner:** Platform Team\r\n\r\n## Availability SLO\r\n\r\n| Metric | Target | Error Budget (30 days) |\r\n|--------|--------|----------------------|\r\n| Availability | 99.9% | 43.8 minutes |\r\n| Success rate | 99.5% | — |\r\n\r\n## Latency SLO\r\n\r\n| Percentile | Target |\r\n|------------|--------|\r\n| p50 | < 100ms |\r\n| p95 | < 500ms |\r\n| p99 | < 1000ms |\r\n\r\n## Error Budget Policy\r\n\r\n| Burn Rate | Alert Window | Severity | Action |\r\n|-----------|-------------|----------|--------|\r\n| > 14.4x | 1 hour | Critical | Page on-call immediately |\r\n| > 6x | 6 hours | High | Page on-call |\r\n| > 3x | 24 hours | Medium | Ticket + monitor |\r\n| > 1x | 72 hours | Low | Review in standup |\r\n\r\n## Consequences of Exhausting Error Budget\r\n\r\n- Feature freeze until budget replenishes\r\n- Reliability sprint prioritized over new features\r\n- Post-mortem required for any budget burn > 50%\r\n\r\n## Measurement\r\n\r\n- Uptime tracked via synthetic monitoring (Pingdom / UptimeRobot)\r\n- Latency tracked via APM (Datadog / New Relic)\r\n- Error rate from application logs + Sentry\r\n`,\r\n },\r\n {\r\n id: 'incident-runbook',\r\n name: 'Incident Runbook',\r\n description: 'Incident response runbook with severity levels and escalation',\r\n defaultPath: 'docs/incident-runbook.md',\r\n category: 'monitoring',\r\n content: `# Incident Runbook — {{PROJECT_NAME}}\r\n\r\n**Last updated:** {{DATE}}\r\n\r\n## Severity Levels\r\n\r\n| Severity | Definition | Response Time | Example |\r\n|----------|-----------|---------------|---------|\r\n| P0 | Complete outage, all users affected | 15 minutes | Site down |\r\n| P1 | Major feature broken, >50% users affected | 30 minutes | Login broken |\r\n| P2 | Significant degradation, subset of users | 2 hours | Slow API |\r\n| P3 | Minor issue, workaround available | Next business day | Cosmetic bug |\r\n\r\n## Roles\r\n\r\n| Role | Responsibility |\r\n|------|---------------|\r\n| Incident Commander (IC) | Owns resolution, coordinates team, communicates status |\r\n| Tech Lead | Diagnoses root cause, coordinates fixes |\r\n| Comms Lead | Updates status page, notifies stakeholders |\r\n\r\n## Response Process\r\n\r\n### 0–15 minutes (Detect & Triage)\r\n1. Confirm the incident (not a false alarm)\r\n2. Assign Incident Commander\r\n3. Create incident Slack channel: \\`#incident-YYYYMMDD-description\\`\r\n4. Set severity level\r\n5. Start incident timeline document\r\n\r\n### 15–60 minutes (Investigate)\r\n1. Identify scope: what's broken, who's affected\r\n2. Check recent deployments (\\`git log\\`, deployment history)\r\n3. Review error rates and logs\r\n4. Consider rollback if recent deploy is suspected\r\n\r\n### Mitigation\r\n1. Apply fix or rollback\r\n2. Monitor for improvement\r\n3. Update status page\r\n4. Notify stakeholders\r\n\r\n## Post-Incident Checklist\r\n\r\n- [ ] Incident resolved and verified\r\n- [ ] Status page updated to \"resolved\"\r\n- [ ] Stakeholders notified\r\n- [ ] Timeline documented\r\n- [ ] Post-mortem scheduled (P0/P1) or ticket created (P2)\r\n- [ ] Action items created in project tracker\r\n`,\r\n },\r\n {\r\n id: 'postmortem',\r\n name: 'Postmortem Template',\r\n description: 'Blameless postmortem template with five-whys and action items',\r\n defaultPath: 'docs/postmortem-template.md',\r\n category: 'monitoring',\r\n content: `# Postmortem: [Title]\r\n\r\n**Date:** {{DATE}}\r\n**Severity:** P[0-3]\r\n**Duration:**\r\n**Author:**\r\n**Reviewers:**\r\n\r\n> This postmortem follows a blameless culture. We focus on systems and processes, not individuals.\r\n\r\n## Summary\r\n\r\n<!-- 2-3 sentence summary: what happened, why it matters, what we're doing about it -->\r\n\r\n## Impact\r\n\r\n- **Users affected:**\r\n- **Duration:**\r\n- **Revenue impact:**\r\n- **Data loss:**\r\n\r\n## Timeline\r\n\r\n| Time (UTC) | Event |\r\n|------------|-------|\r\n| 00:00 | Monitoring alert fired |\r\n| 00:05 | On-call engineer paged |\r\n| 00:15 | Incident confirmed, IC assigned |\r\n| 00:30 | Root cause identified |\r\n| 01:00 | Fix deployed |\r\n| 01:15 | Incident resolved |\r\n\r\n## Root Cause Analysis (Five Whys)\r\n\r\n**Problem:** [Describe the issue]\r\n\r\n1. **Why?** [First cause]\r\n2. **Why?** [Second cause]\r\n3. **Why?** [Third cause]\r\n4. **Why?** [Fourth cause]\r\n5. **Why?** [Root cause]\r\n\r\n## What Went Well\r\n\r\n-\r\n-\r\n\r\n## What Could Have Gone Better\r\n\r\n-\r\n-\r\n\r\n## Action Items\r\n\r\n| Action | Owner | Due Date | Priority |\r\n|--------|-------|----------|----------|\r\n| | | | P[0-3] |\r\n\r\n## Lessons Learned\r\n\r\n<!-- Key takeaways to share with the wider team -->\r\n`,\r\n },\r\n]\r\n","import { AI_AGENT_TEMPLATES } from './ai-agent'\r\nimport { GITHUB_TEMPLATES } from './github'\r\nimport { PROCESS_TEMPLATES } from './process'\r\nimport { TECHNICAL_TEMPLATES } from './technical'\r\nimport { INFRASTRUCTURE_TEMPLATES } from './infrastructure'\r\nimport { GITHUB_ACTIONS_TEMPLATES } from './github-actions'\r\nimport { CODE_QUALITY_TEMPLATES } from './code-quality'\r\nimport { MONITORING_TEMPLATES } from './monitoring'\r\n\r\nexport * from './types'\r\n\r\nexport const TEMPLATES = [\r\n ...AI_AGENT_TEMPLATES,\r\n ...GITHUB_TEMPLATES,\r\n ...PROCESS_TEMPLATES,\r\n ...TECHNICAL_TEMPLATES,\r\n ...INFRASTRUCTURE_TEMPLATES,\r\n ...GITHUB_ACTIONS_TEMPLATES,\r\n ...CODE_QUALITY_TEMPLATES,\r\n ...MONITORING_TEMPLATES,\r\n]\r\n\r\n// dedent removes common leading whitespace from template literals\r\nexport function dedent(str: string): string {\r\n const lines = str.split('\\n')\r\n // Skip empty leading lines\r\n const nonEmpty = lines.filter(l => l.trim().length > 0)\r\n if (nonEmpty.length === 0) return str\r\n const indent = Math.min(...nonEmpty.map(l => l.match(/^(\\s*)/)?.[1].length ?? 0))\r\n if (indent === 0) return str\r\n return lines.map(l => l.slice(indent)).join('\\n')\r\n}\r\n"],"names":["AI_AGENT_TEMPLATES","id","name","description","defaultPath","category","content"],"mappings":"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"}