kaddidlehopper 0.5.0 → 0.6.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 (296) hide show
  1. package/dist/cli.js +104 -208
  2. package/dist/index.js +1 -31
  3. package/dist/types/cli.d.ts +1 -8
  4. package/dist/types/types.d.ts +7 -12
  5. package/package.json +1 -2
  6. package/src/cli.ts +129 -271
  7. package/src/index.ts +1 -47
  8. package/src/types.ts +7 -13
  9. package/CONTEXT.md +0 -139
  10. package/add-ons/ai/README.md +0 -34
  11. package/add-ons/ai/assets/AGENTS.md.append +0 -24
  12. package/add-ons/ai/assets/_dot_env.local.append +0 -13
  13. package/add-ons/ai/assets/src/components/AIAssistant.tsx +0 -149
  14. package/add-ons/ai/assets/src/lib/ai-hook.ts +0 -21
  15. package/add-ons/ai/assets/src/lib/weather-tools.ts +0 -30
  16. package/add-ons/ai/assets/src/routes/api.chat.ts +0 -94
  17. package/add-ons/ai/assets/src/routes/chat.css +0 -175
  18. package/add-ons/ai/assets/src/routes/chat.tsx +0 -141
  19. package/add-ons/ai/info.json +0 -22
  20. package/add-ons/ai/package.json +0 -17
  21. package/add-ons/ai/small-logo.svg +0 -8
  22. package/add-ons/db/assets/AGENTS.md.append +0 -22
  23. package/add-ons/db/assets/DB-SETUP.md +0 -65
  24. package/add-ons/db/assets/_dot_env.local.append +0 -2
  25. package/add-ons/db/assets/drizzle.config.ts +0 -10
  26. package/add-ons/db/assets/src/db/index.ts +0 -8
  27. package/add-ons/db/assets/src/db/schema.ts +0 -8
  28. package/add-ons/db/assets/src/routes/db-example.tsx +0 -118
  29. package/add-ons/db/assets/src/server/guestbook.functions.ts +0 -23
  30. package/add-ons/db/info.json +0 -22
  31. package/add-ons/db/package.json +0 -10
  32. package/add-ons/forms/assets/AGENTS.md.append +0 -13
  33. package/add-ons/forms/assets/public/form-example.html +0 -14
  34. package/add-ons/forms/assets/src/routes/form-example.tsx +0 -76
  35. package/add-ons/forms/info.json +0 -18
  36. package/add-ons/forms/package.json +0 -3
  37. package/examples/ai-chat/README.md +0 -36
  38. package/examples/ai-chat/assets/AGENTS.md.append +0 -24
  39. package/examples/ai-chat/assets/src/lib/ai-hook.ts +0 -21
  40. package/examples/ai-chat/assets/src/lib/weather-tools.ts +0 -30
  41. package/examples/ai-chat/assets/src/routes/__root.tsx +0 -57
  42. package/examples/ai-chat/assets/src/routes/api.chat.ts +0 -94
  43. package/examples/ai-chat/assets/src/routes/index.tsx +0 -141
  44. package/examples/ai-chat/assets/src/styles.css +0 -165
  45. package/examples/ai-chat/info.json +0 -25
  46. package/examples/ai-chat/package.json +0 -14
  47. package/examples/blog/README.md +0 -60
  48. package/examples/blog/assets/AGENTS.md.append +0 -18
  49. package/examples/blog/assets/content/posts/beach.md +0 -12
  50. package/examples/blog/assets/content/posts/jungle.md.ejs +0 -12
  51. package/examples/blog/assets/content/posts/mountains.md.ejs +0 -12
  52. package/examples/blog/assets/content/posts/snorkeling.md.ejs +0 -12
  53. package/examples/blog/assets/content/posts/waterfall.md.ejs +0 -12
  54. package/examples/blog/assets/content-collections.ts +0 -30
  55. package/examples/blog/assets/public/beach.jpg +0 -0
  56. package/examples/blog/assets/public/jungle.jpg +0 -0
  57. package/examples/blog/assets/public/mountains.jpg +0 -0
  58. package/examples/blog/assets/public/snorkeling.jpg +0 -0
  59. package/examples/blog/assets/public/waterfall.jpg +0 -0
  60. package/examples/blog/assets/src/components/Header.tsx +0 -52
  61. package/examples/blog/assets/src/components/VacayAssistant.tsx +0 -205
  62. package/examples/blog/assets/src/components/blog-posts.tsx +0 -78
  63. package/examples/blog/assets/src/components/ui/card.tsx +0 -92
  64. package/examples/blog/assets/src/lib/blog-ai-hook.ts +0 -25
  65. package/examples/blog/assets/src/lib/blog-tools.ts +0 -111
  66. package/examples/blog/assets/src/lib/utils.ts +0 -6
  67. package/examples/blog/assets/src/routes/__root.tsx +0 -57
  68. package/examples/blog/assets/src/routes/api.blog-chat.ts +0 -117
  69. package/examples/blog/assets/src/routes/category.$category.tsx +0 -19
  70. package/examples/blog/assets/src/routes/index.tsx +0 -19
  71. package/examples/blog/assets/src/routes/posts.$slug.tsx +0 -63
  72. package/examples/blog/assets/src/styles.css +0 -138
  73. package/examples/blog/info.json +0 -40
  74. package/examples/blog/package.json +0 -23
  75. package/examples/calculator/README.md +0 -16
  76. package/examples/calculator/assets/AGENTS.md.append +0 -9
  77. package/examples/calculator/assets/src/components/Calculator.tsx +0 -238
  78. package/examples/calculator/assets/src/components/Header.tsx +0 -17
  79. package/examples/calculator/assets/src/routes/__root.tsx +0 -57
  80. package/examples/calculator/assets/src/routes/index.tsx +0 -14
  81. package/examples/calculator/info.json +0 -20
  82. package/examples/calculator/package.json +0 -1
  83. package/examples/dashboard/README.md +0 -17
  84. package/examples/dashboard/assets/AGENTS.md.append +0 -12
  85. package/examples/dashboard/assets/src/components/Header.tsx +0 -17
  86. package/examples/dashboard/assets/src/routes/__root.tsx +0 -57
  87. package/examples/dashboard/assets/src/routes/index.tsx +0 -158
  88. package/examples/dashboard/info.json +0 -19
  89. package/examples/dashboard/package.json +0 -6
  90. package/examples/ecommerce/README.md +0 -48
  91. package/examples/ecommerce/assets/AGENTS.md.append +0 -22
  92. package/examples/ecommerce/assets/public/logo.png +0 -0
  93. package/examples/ecommerce/assets/public/motorcycle-scooter.jpg +0 -0
  94. package/examples/ecommerce/assets/src/components/BuyButton.tsx +0 -35
  95. package/examples/ecommerce/assets/src/components/Header.tsx +0 -36
  96. package/examples/ecommerce/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
  97. package/examples/ecommerce/assets/src/components/MotorcycleRecommendation.tsx +0 -53
  98. package/examples/ecommerce/assets/src/data/motorcycles.ts +0 -27
  99. package/examples/ecommerce/assets/src/lib/motorcycle-ai-hook.ts +0 -24
  100. package/examples/ecommerce/assets/src/lib/motorcycle-tools.ts +0 -42
  101. package/examples/ecommerce/assets/src/lib/stripe.server.ts +0 -39
  102. package/examples/ecommerce/assets/src/routes/__root.tsx +0 -57
  103. package/examples/ecommerce/assets/src/routes/api.motorcycle-chat.ts +0 -78
  104. package/examples/ecommerce/assets/src/routes/checkout/cancel.tsx +0 -25
  105. package/examples/ecommerce/assets/src/routes/checkout/success.tsx +0 -25
  106. package/examples/ecommerce/assets/src/routes/index.tsx +0 -76
  107. package/examples/ecommerce/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -55
  108. package/examples/ecommerce/assets/src/store/motorcycle-assistant.ts +0 -3
  109. package/examples/ecommerce/assets/src/styles.css +0 -212
  110. package/examples/ecommerce/info.json +0 -38
  111. package/examples/ecommerce/package.json +0 -13
  112. package/examples/events/README.md +0 -110
  113. package/examples/events/assets/AGENTS.md.append +0 -21
  114. package/examples/events/assets/content/speakers/andre-costa.md +0 -22
  115. package/examples/events/assets/content/speakers/hans-mueller.md.ejs +0 -22
  116. package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +0 -22
  117. package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +0 -22
  118. package/examples/events/assets/content/speakers/marie-dubois.md.ejs +0 -20
  119. package/examples/events/assets/content/speakers/priya-sharma.md.ejs +0 -22
  120. package/examples/events/assets/content/talks/croissant-lamination-secrets.md +0 -39
  121. package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +0 -39
  122. package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +0 -39
  123. package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +0 -39
  124. package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +0 -36
  125. package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +0 -32
  126. package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +0 -39
  127. package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +0 -39
  128. package/examples/events/assets/content-collections.ts +0 -56
  129. package/examples/events/assets/public/background-1.jpg +0 -0
  130. package/examples/events/assets/public/background-2.jpg +0 -0
  131. package/examples/events/assets/public/background-3.jpg +0 -0
  132. package/examples/events/assets/public/background-4.jpg +0 -0
  133. package/examples/events/assets/public/conference-logo.png +0 -0
  134. package/examples/events/assets/public/favicon.ico +0 -0
  135. package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
  136. package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
  137. package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
  138. package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
  139. package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
  140. package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
  141. package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
  142. package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
  143. package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
  144. package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
  145. package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
  146. package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
  147. package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
  148. package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
  149. package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
  150. package/examples/events/assets/public/tanstack-word-logo-white.svg +0 -1
  151. package/examples/events/assets/src/components/Header.tsx +0 -59
  152. package/examples/events/assets/src/components/HeaderNav.tsx +0 -67
  153. package/examples/events/assets/src/components/HeroCarousel.tsx +0 -61
  154. package/examples/events/assets/src/components/RemyAssistant.tsx +0 -207
  155. package/examples/events/assets/src/components/SpeakerCard.tsx +0 -67
  156. package/examples/events/assets/src/components/TalkCard.tsx +0 -77
  157. package/examples/events/assets/src/components/ui/card.tsx +0 -92
  158. package/examples/events/assets/src/lib/conference-ai-hook.ts +0 -26
  159. package/examples/events/assets/src/lib/conference-tools.ts +0 -210
  160. package/examples/events/assets/src/lib/model-selection.ts +0 -1
  161. package/examples/events/assets/src/lib/utils.ts +0 -6
  162. package/examples/events/assets/src/routes/__root.tsx +0 -70
  163. package/examples/events/assets/src/routes/api.remy-chat.ts +0 -119
  164. package/examples/events/assets/src/routes/index.tsx +0 -192
  165. package/examples/events/assets/src/routes/schedule.index.tsx +0 -274
  166. package/examples/events/assets/src/routes/speakers.$slug.tsx +0 -122
  167. package/examples/events/assets/src/routes/speakers.index.tsx +0 -40
  168. package/examples/events/assets/src/routes/talks.$slug.tsx +0 -116
  169. package/examples/events/assets/src/routes/talks.index.tsx +0 -40
  170. package/examples/events/assets/src/styles.css +0 -182
  171. package/examples/events/info.json +0 -61
  172. package/examples/events/package.json +0 -23
  173. package/examples/marketing/README.md +0 -60
  174. package/examples/marketing/assets/AGENTS.md.append +0 -15
  175. package/examples/marketing/assets/public/logo.png +0 -0
  176. package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
  177. package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
  178. package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
  179. package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
  180. package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
  181. package/examples/marketing/assets/src/components/Header.tsx +0 -36
  182. package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
  183. package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +0 -53
  184. package/examples/marketing/assets/src/data/motorcycles.ts.ejs +0 -77
  185. package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +0 -24
  186. package/examples/marketing/assets/src/lib/motorcycle-tools.ts +0 -42
  187. package/examples/marketing/assets/src/routes/__root.tsx +0 -57
  188. package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +0 -78
  189. package/examples/marketing/assets/src/routes/index.tsx +0 -72
  190. package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -56
  191. package/examples/marketing/assets/src/store/motorcycle-assistant.ts +0 -3
  192. package/examples/marketing/assets/src/styles.css +0 -212
  193. package/examples/marketing/info.json +0 -33
  194. package/examples/marketing/package.json +0 -14
  195. package/examples/portfolio/README.md +0 -49
  196. package/examples/portfolio/assets/AGENTS.md.append +0 -21
  197. package/examples/portfolio/assets/content/blog/getting-started-with-tanstack.md +0 -53
  198. package/examples/portfolio/assets/content/blog/react-19-features.md +0 -78
  199. package/examples/portfolio/assets/content/blog/tailwind-css-v4-guide.md +0 -60
  200. package/examples/portfolio/assets/content/education/code-school.md +0 -17
  201. package/examples/portfolio/assets/content/jobs/initech-junior.md +0 -20
  202. package/examples/portfolio/assets/content/projects/portfolio-site.md +0 -15
  203. package/examples/portfolio/assets/content/projects/task-manager.md +0 -15
  204. package/examples/portfolio/assets/content-collections.ts +0 -65
  205. package/examples/portfolio/assets/public/contact.html +0 -6
  206. package/examples/portfolio/assets/public/headshot-on-white.jpg +0 -0
  207. package/examples/portfolio/assets/src/components/Header.tsx +0 -33
  208. package/examples/portfolio/assets/src/components/ResumeAssistant.tsx +0 -193
  209. package/examples/portfolio/assets/src/components/ui/badge.tsx +0 -46
  210. package/examples/portfolio/assets/src/components/ui/card.tsx +0 -92
  211. package/examples/portfolio/assets/src/components/ui/checkbox.tsx +0 -30
  212. package/examples/portfolio/assets/src/components/ui/hover-card.tsx +0 -44
  213. package/examples/portfolio/assets/src/components/ui/separator.tsx +0 -26
  214. package/examples/portfolio/assets/src/lib/resume-ai-hook.ts +0 -21
  215. package/examples/portfolio/assets/src/lib/resume-tools.ts +0 -165
  216. package/examples/portfolio/assets/src/lib/utils.ts +0 -6
  217. package/examples/portfolio/assets/src/routes/__root.tsx +0 -57
  218. package/examples/portfolio/assets/src/routes/api.resume-chat.ts +0 -116
  219. package/examples/portfolio/assets/src/routes/blog/$slug.tsx +0 -73
  220. package/examples/portfolio/assets/src/routes/contact.tsx +0 -121
  221. package/examples/portfolio/assets/src/routes/index.tsx +0 -55
  222. package/examples/portfolio/assets/src/routes/projects.tsx +0 -62
  223. package/examples/portfolio/assets/src/routes/resume.tsx +0 -220
  224. package/examples/portfolio/assets/src/styles.css +0 -138
  225. package/examples/portfolio/info.json +0 -50
  226. package/examples/portfolio/package.json +0 -26
  227. package/examples/resume/README.md +0 -82
  228. package/examples/resume/assets/AGENTS.md.append +0 -19
  229. package/examples/resume/assets/content/education/code-school.md +0 -17
  230. package/examples/resume/assets/content/jobs/freelance.md.ejs +0 -13
  231. package/examples/resume/assets/content/jobs/initech-junior.md +0 -20
  232. package/examples/resume/assets/content/jobs/initech-lead.md.ejs +0 -29
  233. package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +0 -28
  234. package/examples/resume/assets/content-collections.ts +0 -36
  235. package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
  236. package/examples/resume/assets/src/components/Header.tsx +0 -33
  237. package/examples/resume/assets/src/components/ResumeAssistant.tsx +0 -193
  238. package/examples/resume/assets/src/components/ui/badge.tsx +0 -46
  239. package/examples/resume/assets/src/components/ui/card.tsx +0 -92
  240. package/examples/resume/assets/src/components/ui/checkbox.tsx +0 -30
  241. package/examples/resume/assets/src/components/ui/hover-card.tsx +0 -44
  242. package/examples/resume/assets/src/components/ui/separator.tsx +0 -26
  243. package/examples/resume/assets/src/lib/resume-ai-hook.ts +0 -21
  244. package/examples/resume/assets/src/lib/resume-tools.ts +0 -165
  245. package/examples/resume/assets/src/lib/utils.ts +0 -6
  246. package/examples/resume/assets/src/routes/api.resume-chat.ts +0 -110
  247. package/examples/resume/assets/src/routes/index.tsx +0 -220
  248. package/examples/resume/assets/src/styles.css +0 -138
  249. package/examples/resume/info.json +0 -35
  250. package/examples/resume/package.json +0 -26
  251. package/examples/saas/README.md +0 -16
  252. package/examples/saas/assets/AGENTS.md.append +0 -9
  253. package/examples/saas/assets/src/components/Header.tsx +0 -17
  254. package/examples/saas/assets/src/routes/__root.tsx +0 -57
  255. package/examples/saas/assets/src/routes/faq.tsx +0 -94
  256. package/examples/saas/assets/src/routes/index.tsx +0 -197
  257. package/examples/saas/info.json +0 -23
  258. package/examples/saas/package.json +0 -1
  259. package/examples/survey/README.md +0 -20
  260. package/examples/survey/assets/AGENTS.md.append +0 -9
  261. package/examples/survey/assets/public/form-survey.html +0 -15
  262. package/examples/survey/assets/src/components/SurveyForm.tsx +0 -128
  263. package/examples/survey/assets/src/routes/index.tsx +0 -14
  264. package/examples/survey/info.json +0 -19
  265. package/examples/survey/package.json +0 -1
  266. package/project/base/AGENTS.md +0 -86
  267. package/project/base/_dot_claude/skills/content-collections/SKILL.md +0 -505
  268. package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +0 -410
  269. package/project/base/_dot_claude/skills/netlify-db/SKILL.md +0 -424
  270. package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +0 -419
  271. package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +0 -243
  272. package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +0 -372
  273. package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +0 -421
  274. package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +0 -426
  275. package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +0 -493
  276. package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +0 -430
  277. package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +0 -445
  278. package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +0 -494
  279. package/project/base/_dot_gitignore +0 -8
  280. package/project/base/netlify.toml +0 -7
  281. package/project/base/package.json +0 -33
  282. package/project/base/public/favicon.ico +0 -0
  283. package/project/base/public/tanstack-circle-logo.png +0 -0
  284. package/project/base/public/tanstack-word-logo-white.svg +0 -1
  285. package/project/base/src/components/Header.tsx +0 -17
  286. package/project/base/src/components/HeaderNav.tsx.ejs +0 -179
  287. package/project/base/src/router.tsx +0 -15
  288. package/project/base/src/routes/__root.tsx +0 -57
  289. package/project/base/src/routes/index.tsx +0 -48
  290. package/project/base/src/styles.css +0 -15
  291. package/project/base/tsconfig.json +0 -28
  292. package/project/base/vite.config.ts.ejs +0 -25
  293. package/project/info.json +0 -17
  294. package/project/packages.json +0 -22
  295. package/scripts/check-outdated-packages.js +0 -421
  296. package/src/agents-md.ts +0 -139
@@ -1,421 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { readFileSync, readdirSync, statSync, writeFileSync } from 'fs'
4
- import { join, dirname, relative } from 'path'
5
- import { fileURLToPath } from 'url'
6
- import semver from 'semver'
7
-
8
- const __filename = fileURLToPath(import.meta.url)
9
- const __dirname = dirname(__filename)
10
-
11
- // Parse command line arguments
12
- const args = process.argv.slice(2)
13
- const shouldUpdate = args.includes('--update')
14
-
15
- // Colors for console output
16
- const colors = {
17
- red: '\x1b[31m',
18
- green: '\x1b[32m',
19
- yellow: '\x1b[33m',
20
- blue: '\x1b[34m',
21
- reset: '\x1b[0m',
22
- bold: '\x1b[1m',
23
- }
24
-
25
- /**
26
- * Recursively find all package.json files in a directory
27
- */
28
- function findPackageJsonFiles(dir, files = []) {
29
- const items = readdirSync(dir)
30
-
31
- for (const item of items) {
32
- const fullPath = join(dir, item)
33
- const stat = statSync(fullPath)
34
-
35
- if (stat.isDirectory() && item !== 'node_modules' && item !== 'dist') {
36
- findPackageJsonFiles(fullPath, files)
37
- } else if (item === 'package.json') {
38
- files.push(fullPath)
39
- }
40
- }
41
-
42
- return files
43
- }
44
-
45
- // Cache for package versions to avoid duplicate API calls
46
- const versionCache = new Map()
47
-
48
- /**
49
- * Get the latest version of a package from npm with caching and timeout
50
- */
51
- async function getLatestVersion(packageName) {
52
- // Check cache first
53
- if (versionCache.has(packageName)) {
54
- return versionCache.get(packageName)
55
- }
56
-
57
- try {
58
- // Add timeout to prevent hanging
59
- const controller = new AbortController()
60
- const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
61
-
62
- const response = await fetch(
63
- `https://registry.npmjs.org/${packageName}/latest`,
64
- {
65
- signal: controller.signal,
66
- headers: {
67
- 'User-Agent': 'netlify-cta-outdated-checker',
68
- },
69
- },
70
- )
71
-
72
- clearTimeout(timeoutId)
73
-
74
- if (!response.ok) {
75
- throw new Error(`HTTP ${response.status}`)
76
- }
77
-
78
- const data = await response.json()
79
- const version = data.version
80
-
81
- // Cache the result
82
- versionCache.set(packageName, version)
83
- return version
84
- } catch (error) {
85
- if (error.name === 'AbortError') {
86
- console.warn(
87
- `${colors.yellow}Warning: Timeout fetching latest version for ${packageName}${colors.reset}`,
88
- )
89
- } else {
90
- console.warn(
91
- `${colors.yellow}Warning: Could not fetch latest version for ${packageName}: ${error.message}${colors.reset}`,
92
- )
93
- }
94
-
95
- // Cache null result to avoid retrying
96
- versionCache.set(packageName, null)
97
- return null
98
- }
99
- }
100
-
101
- /**
102
- * Check if a version range satisfies the latest version
103
- */
104
- function isVersionRangeOutdated(versionRange, latestVersion) {
105
- try {
106
- // Clean the version range (remove any npm-specific prefixes)
107
- const cleanRange = versionRange.replace(/^npm:/, '').split('@').pop()
108
-
109
- // Check if the range satisfies the latest version
110
- return !semver.satisfies(latestVersion, cleanRange)
111
- } catch (error) {
112
- console.warn(
113
- `${colors.yellow}Warning: Could not parse version range "${versionRange}": ${error.message}${colors.reset}`,
114
- )
115
- return false
116
- }
117
- }
118
-
119
- /**
120
- * Update package.json file with new versions
121
- */
122
- function updatePackageJson(filePath, outdatedPackages) {
123
- try {
124
- const content = readFileSync(filePath, 'utf8')
125
- const packageJson = JSON.parse(content)
126
-
127
- let updated = false
128
-
129
- for (const pkg of outdatedPackages) {
130
- // Check and update in dependencies
131
- if (packageJson.dependencies && packageJson.dependencies[pkg.name]) {
132
- const currentRange = packageJson.dependencies[pkg.name]
133
- const newRange = updateVersionRange(currentRange, pkg.latest)
134
- packageJson.dependencies[pkg.name] = newRange
135
- updated = true
136
- }
137
-
138
- // Check and update in devDependencies
139
- if (
140
- packageJson.devDependencies &&
141
- packageJson.devDependencies[pkg.name]
142
- ) {
143
- const currentRange = packageJson.devDependencies[pkg.name]
144
- const newRange = updateVersionRange(currentRange, pkg.latest)
145
- packageJson.devDependencies[pkg.name] = newRange
146
- updated = true
147
- }
148
-
149
- // Check and update in peerDependencies
150
- if (
151
- packageJson.peerDependencies &&
152
- packageJson.peerDependencies[pkg.name]
153
- ) {
154
- const currentRange = packageJson.peerDependencies[pkg.name]
155
- const newRange = updateVersionRange(currentRange, pkg.latest)
156
- packageJson.peerDependencies[pkg.name] = newRange
157
- updated = true
158
- }
159
- }
160
-
161
- if (updated) {
162
- // Write back with proper formatting
163
- writeFileSync(filePath, JSON.stringify(packageJson, null, 2) + '\n')
164
- return true
165
- }
166
-
167
- return false
168
- } catch (error) {
169
- console.error(
170
- `${colors.red}Error updating ${filePath}: ${error.message}${colors.reset}`,
171
- )
172
- return false
173
- }
174
- }
175
-
176
- /**
177
- * Update version range while preserving the range type (^, ~, etc.)
178
- */
179
- function updateVersionRange(currentRange, latestVersion) {
180
- // Preserve the prefix (^, ~, >=, etc.)
181
- if (currentRange.startsWith('^')) {
182
- return `^${latestVersion}`
183
- } else if (currentRange.startsWith('~')) {
184
- return `~${latestVersion}`
185
- } else if (currentRange.startsWith('>=')) {
186
- return `>=${latestVersion}`
187
- } else if (currentRange.startsWith('>')) {
188
- return `>${latestVersion}`
189
- } else if (currentRange.startsWith('<=')) {
190
- return `<=${latestVersion}`
191
- } else if (currentRange.startsWith('<')) {
192
- return `<${latestVersion}`
193
- } else {
194
- // Exact version or other format, just use the latest version
195
- return latestVersion
196
- }
197
- }
198
-
199
- /**
200
- * Get relative path for display
201
- */
202
- function getDisplayPath(filePath, rootDir) {
203
- const relativePath = relative(rootDir, filePath)
204
- // Remove the package.json part
205
- return relativePath.replace('/package.json', '')
206
- }
207
-
208
- /**
209
- * Check dependencies in a package.json file
210
- */
211
- async function checkPackageJson(filePath) {
212
- try {
213
- const content = readFileSync(filePath, 'utf8')
214
- const packageJson = JSON.parse(content)
215
-
216
- const outdatedPackages = []
217
- const allDependencies = {
218
- ...packageJson.dependencies,
219
- ...packageJson.devDependencies,
220
- ...packageJson.peerDependencies,
221
- }
222
-
223
- if (Object.keys(allDependencies).length === 0) {
224
- return { filePath, outdatedPackages: [], totalDependencies: 0 }
225
- }
226
-
227
- const packageNames = Object.keys(allDependencies).filter((name) => {
228
- const versionRange = allDependencies[name]
229
- // Skip workspace dependencies and local packages
230
- return !(
231
- versionRange.startsWith('workspace:') ||
232
- versionRange.startsWith('file:') ||
233
- versionRange.startsWith('link:')
234
- )
235
- })
236
-
237
- // Process packages in batches to avoid overwhelming the API
238
- const batchSize = 5
239
- for (let i = 0; i < packageNames.length; i += batchSize) {
240
- const batch = packageNames.slice(i, i + batchSize)
241
-
242
- // Process batch in parallel
243
- const promises = batch.map(async (packageName) => {
244
- const versionRange = allDependencies[packageName]
245
- const latestVersion = await getLatestVersion(packageName)
246
-
247
- if (!latestVersion) {
248
- return null
249
- }
250
-
251
- if (isVersionRangeOutdated(versionRange, latestVersion)) {
252
- return {
253
- name: packageName,
254
- current: versionRange,
255
- latest: latestVersion,
256
- }
257
- }
258
-
259
- return null
260
- })
261
-
262
- const results = await Promise.all(promises)
263
- outdatedPackages.push(...results.filter(Boolean))
264
-
265
- // Small delay between batches
266
- if (i + batchSize < packageNames.length) {
267
- await new Promise((resolve) => setTimeout(resolve, 50))
268
- }
269
- }
270
-
271
- return {
272
- filePath,
273
- outdatedPackages,
274
- totalDependencies: Object.keys(allDependencies).length,
275
- }
276
- } catch (error) {
277
- console.error(
278
- `${colors.red}Error processing ${filePath}: ${error.message}${colors.reset}`,
279
- )
280
- return {
281
- filePath,
282
- outdatedPackages: [],
283
- totalDependencies: 0,
284
- error: error.message,
285
- }
286
- }
287
- }
288
-
289
- /**
290
- * Main function
291
- */
292
- async function main() {
293
- const actionText = shouldUpdate ? 'Updating' : 'Checking for'
294
- console.log(
295
- `${colors.bold}${colors.blue}${actionText} outdated packages in netlify-cta...${colors.reset}\n`,
296
- )
297
-
298
- const rootDir = join(__dirname, '..')
299
-
300
- // Directories to scan for package.json files
301
- const dirsToScan = [
302
- join(rootDir, 'add-ons'),
303
- join(rootDir, 'examples'),
304
- join(rootDir, 'project'),
305
- ]
306
-
307
- // Collect all package.json files from all directories
308
- const packageJsonFiles = []
309
- for (const dir of dirsToScan) {
310
- try {
311
- const files = findPackageJsonFiles(dir)
312
- packageJsonFiles.push(...files)
313
- console.log(
314
- `${colors.blue}Found ${files.length} package.json files in ${relative(rootDir, dir)}${colors.reset}`,
315
- )
316
- } catch (error) {
317
- console.warn(
318
- `${colors.yellow}Warning: Could not scan ${dir}: ${error.message}${colors.reset}`,
319
- )
320
- }
321
- }
322
-
323
- console.log(`\nTotal: ${packageJsonFiles.length} package.json files\n`)
324
-
325
- let totalOutdated = 0
326
- let totalChecked = 0
327
- let totalUpdated = 0
328
- const results = []
329
-
330
- for (let i = 0; i < packageJsonFiles.length; i++) {
331
- const filePath = packageJsonFiles[i]
332
- const displayPath = getDisplayPath(filePath, rootDir)
333
-
334
- // Show progress
335
- process.stdout.write(
336
- `\r${colors.blue}Processing ${i + 1}/${packageJsonFiles.length}: ${displayPath}...${colors.reset}`,
337
- )
338
-
339
- const result = await checkPackageJson(filePath)
340
- results.push(result)
341
-
342
- if (result.error) {
343
- console.log(`\n${colors.red}Error: ${result.error}${colors.reset}`)
344
- continue
345
- }
346
-
347
- totalChecked += result.totalDependencies
348
- totalOutdated += result.outdatedPackages.length
349
-
350
- if (result.outdatedPackages.length > 0) {
351
- console.log(
352
- `\n${colors.red}${colors.bold}Found ${result.outdatedPackages.length} outdated packages in ${displayPath}:${colors.reset}`,
353
- )
354
- for (const pkg of result.outdatedPackages) {
355
- console.log(
356
- ` ${colors.red}${pkg.name}${colors.reset}: ${pkg.current} → ${colors.green}${pkg.latest}${colors.reset}`,
357
- )
358
- }
359
-
360
- if (shouldUpdate) {
361
- const updated = updatePackageJson(filePath, result.outdatedPackages)
362
- if (updated) {
363
- totalUpdated++
364
- console.log(
365
- ` ${colors.green}✓ Updated ${displayPath}${colors.reset}`,
366
- )
367
- } else {
368
- console.log(
369
- ` ${colors.yellow}⚠ Failed to update ${displayPath}${colors.reset}`,
370
- )
371
- }
372
- }
373
-
374
- console.log()
375
- }
376
- }
377
-
378
- // Clear progress line and add spacing
379
- console.log('\n')
380
-
381
- // Summary
382
- console.log(`${colors.bold}${colors.blue}Summary:${colors.reset}`)
383
- console.log(`Total dependencies checked: ${totalChecked}`)
384
- console.log(
385
- `Total outdated packages: ${colors.red}${totalOutdated}${colors.reset}`,
386
- )
387
-
388
- if (shouldUpdate) {
389
- console.log(
390
- `Total files updated: ${colors.green}${totalUpdated}${colors.reset}`,
391
- )
392
- }
393
-
394
- if (totalOutdated === 0) {
395
- console.log(
396
- `${colors.green}${colors.bold}🎉 All packages are up to date!${colors.reset}`,
397
- )
398
- } else if (shouldUpdate && totalUpdated > 0) {
399
- console.log(
400
- `${colors.green}${colors.bold}✅ Successfully updated ${totalUpdated} files with outdated packages!${colors.reset}`,
401
- )
402
- } else if (shouldUpdate && totalUpdated === 0) {
403
- console.log(
404
- `${colors.yellow}${colors.bold}⚠️ No files were updated. Check for errors above.${colors.reset}`,
405
- )
406
- } else {
407
- console.log(
408
- `${colors.yellow}${colors.bold}⚠️ Found outdated packages that need attention. Use --update to update them.${colors.reset}`,
409
- )
410
- }
411
-
412
- // Exit with error code if outdated packages found and not updating
413
- process.exit(totalOutdated > 0 && !shouldUpdate ? 1 : 0)
414
- }
415
-
416
- main().catch((error) => {
417
- console.error(
418
- `${colors.red}${colors.bold}Fatal error: ${error.message}${colors.reset}`,
419
- )
420
- process.exit(1)
421
- })
package/src/agents-md.ts DELETED
@@ -1,139 +0,0 @@
1
- import { dirname, join, relative } from 'node:path'
2
- import { readdir, readFile, writeFile } from 'node:fs/promises'
3
- import { fileURLToPath } from 'node:url'
4
-
5
- const PLACEHOLDER = '[[[DIRECTORY STRUCTURE]]]'
6
-
7
- const IGNORED_DIRS = new Set([
8
- 'node_modules',
9
- '.git',
10
- 'dist',
11
- 'dist-ssr',
12
- '.netlify',
13
- '.tanstack',
14
- '.DS_Store',
15
- ])
16
-
17
- type FileDescriptions = Record<string, string>
18
-
19
- function buildDescriptionLookup(descriptions: FileDescriptions): Map<string, string> {
20
- const lookup = new Map<string, string>()
21
- for (const [key, desc] of Object.entries(descriptions)) {
22
- const normalizedKey = key.replace(/\\/g, '/')
23
- lookup.set(normalizedKey, desc)
24
- if (normalizedKey.endsWith('.ejs')) {
25
- lookup.set(normalizedKey.slice(0, -4), desc)
26
- }
27
- if (normalizedKey.startsWith('_dot_')) {
28
- lookup.set('.' + normalizedKey.slice(5), desc)
29
- }
30
- }
31
- return lookup
32
- }
33
-
34
- async function loadFileDescriptions(
35
- addOnDescriptions?: Array<{ packageFileDescriptions?: FileDescriptions }>,
36
- ): Promise<Map<string, string>> {
37
- const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
38
- const infoPath = join(packageRoot, 'project', 'info.json')
39
- const lookup = new Map<string, string>()
40
-
41
- try {
42
- const info = await readFile(infoPath, 'utf-8')
43
- const { packageFileDescriptions } = JSON.parse(info) as {
44
- packageFileDescriptions?: FileDescriptions
45
- }
46
- if (packageFileDescriptions) {
47
- for (const [key, desc] of buildDescriptionLookup(
48
- packageFileDescriptions,
49
- )) {
50
- lookup.set(key, desc)
51
- }
52
- }
53
- } catch {
54
- // No info.json or invalid, continue
55
- }
56
-
57
- if (addOnDescriptions) {
58
- for (const addOn of addOnDescriptions) {
59
- if (addOn.packageFileDescriptions) {
60
- for (const [key, desc] of buildDescriptionLookup(
61
- addOn.packageFileDescriptions,
62
- )) {
63
- lookup.set(key, desc)
64
- }
65
- }
66
- }
67
- }
68
-
69
- return lookup
70
- }
71
-
72
- async function buildFileTree(
73
- dirPath: string,
74
- rootPath: string,
75
- descriptions: Map<string, string>,
76
- prefix = '',
77
- ): Promise<string[]> {
78
- const entries = await readdir(dirPath, { withFileTypes: true })
79
- const filtered = entries
80
- .filter((e) => !e.name.startsWith('.') || e.name === '.gitignore')
81
- .filter((e) => !IGNORED_DIRS.has(e.name))
82
- .sort((a, b) => {
83
- // Directories first, then files; alphabetically within each
84
- if (a.isDirectory() !== b.isDirectory()) {
85
- return a.isDirectory() ? -1 : 1
86
- }
87
- return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })
88
- })
89
-
90
- const lines: string[] = []
91
- for (let i = 0; i < filtered.length; i++) {
92
- const entry = filtered[i]
93
- const isLastEntry = i === filtered.length - 1
94
- const connector = isLastEntry ? '└── ' : '├── '
95
- const fullPath = join(dirPath, entry.name)
96
- const relPath = relative(rootPath, fullPath).replace(/\\/g, '/')
97
- const description = descriptions.get(relPath)
98
- const suffix = description ? ` # ${description}` : ''
99
- lines.push(`${prefix}${connector}${entry.name}${suffix}`)
100
-
101
- if (entry.isDirectory()) {
102
- const childPrefix = prefix + (isLastEntry ? ' ' : '│ ')
103
- const childLines = await buildFileTree(
104
- join(dirPath, entry.name),
105
- rootPath,
106
- descriptions,
107
- childPrefix,
108
- )
109
- lines.push(...childLines)
110
- }
111
- }
112
- return lines
113
- }
114
-
115
- export async function generateAgentsMd(
116
- targetDir: string,
117
- _projectName: string,
118
- chosenAddOns?: Array<{ packageFileDescriptions?: FileDescriptions }>,
119
- ): Promise<void> {
120
- const agentsMdPath = join(targetDir, 'AGENTS.md')
121
- let content: string
122
- try {
123
- content = await readFile(agentsMdPath, 'utf-8')
124
- } catch {
125
- // No AGENTS.md template, skip
126
- return
127
- }
128
-
129
- if (!content.includes(PLACEHOLDER)) {
130
- return
131
- }
132
-
133
- const descriptions = await loadFileDescriptions(chosenAddOns)
134
- const treeLines = await buildFileTree(targetDir, targetDir, descriptions)
135
- const tree = treeLines.length > 0 ? treeLines.join('\n') : '(empty)'
136
-
137
- const updatedContent = content.replace(PLACEHOLDER, tree)
138
- await writeFile(agentsMdPath, updatedContent, 'utf-8')
139
- }