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,46 +0,0 @@
1
- import * as React from 'react'
2
- import { Slot } from '@radix-ui/react-slot'
3
- import { cva, type VariantProps } from 'class-variance-authority'
4
-
5
- import { cn } from '@/lib/utils'
6
-
7
- const badgeVariants = cva(
8
- 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
9
- {
10
- variants: {
11
- variant: {
12
- default:
13
- 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
14
- secondary:
15
- 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
16
- destructive:
17
- 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
18
- outline:
19
- 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
20
- },
21
- },
22
- defaultVariants: {
23
- variant: 'default',
24
- },
25
- },
26
- )
27
-
28
- function Badge({
29
- className,
30
- variant,
31
- asChild = false,
32
- ...props
33
- }: React.ComponentProps<'span'> &
34
- VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35
- const Comp = asChild ? Slot : 'span'
36
-
37
- return (
38
- <Comp
39
- data-slot="badge"
40
- className={cn(badgeVariants({ variant }), className)}
41
- {...props}
42
- />
43
- )
44
- }
45
-
46
- export { Badge, badgeVariants }
@@ -1,92 +0,0 @@
1
- import * as React from 'react'
2
-
3
- import { cn } from '@/lib/utils'
4
-
5
- function Card({ className, ...props }: React.ComponentProps<'div'>) {
6
- return (
7
- <div
8
- data-slot="card"
9
- className={cn(
10
- 'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
11
- className,
12
- )}
13
- {...props}
14
- />
15
- )
16
- }
17
-
18
- function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
19
- return (
20
- <div
21
- data-slot="card-header"
22
- className={cn(
23
- '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
24
- className,
25
- )}
26
- {...props}
27
- />
28
- )
29
- }
30
-
31
- function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
32
- return (
33
- <div
34
- data-slot="card-title"
35
- className={cn('leading-none font-semibold', className)}
36
- {...props}
37
- />
38
- )
39
- }
40
-
41
- function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
42
- return (
43
- <div
44
- data-slot="card-description"
45
- className={cn('text-muted-foreground text-sm', className)}
46
- {...props}
47
- />
48
- )
49
- }
50
-
51
- function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
52
- return (
53
- <div
54
- data-slot="card-action"
55
- className={cn(
56
- 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
57
- className,
58
- )}
59
- {...props}
60
- />
61
- )
62
- }
63
-
64
- function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
65
- return (
66
- <div
67
- data-slot="card-content"
68
- className={cn('px-6', className)}
69
- {...props}
70
- />
71
- )
72
- }
73
-
74
- function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
75
- return (
76
- <div
77
- data-slot="card-footer"
78
- className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
79
- {...props}
80
- />
81
- )
82
- }
83
-
84
- export {
85
- Card,
86
- CardHeader,
87
- CardFooter,
88
- CardTitle,
89
- CardAction,
90
- CardDescription,
91
- CardContent,
92
- }
@@ -1,30 +0,0 @@
1
- import * as React from 'react'
2
- import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
3
- import { CheckIcon } from 'lucide-react'
4
-
5
- import { cn } from '@/lib/utils'
6
-
7
- function Checkbox({
8
- className,
9
- ...props
10
- }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
11
- return (
12
- <CheckboxPrimitive.Root
13
- data-slot="checkbox"
14
- className={cn(
15
- 'peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
16
- className,
17
- )}
18
- {...props}
19
- >
20
- <CheckboxPrimitive.Indicator
21
- data-slot="checkbox-indicator"
22
- className="flex items-center justify-center text-current transition-none"
23
- >
24
- <CheckIcon className="size-3.5" />
25
- </CheckboxPrimitive.Indicator>
26
- </CheckboxPrimitive.Root>
27
- )
28
- }
29
-
30
- export { Checkbox }
@@ -1,44 +0,0 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
5
-
6
- import { cn } from '@/lib/utils'
7
-
8
- function HoverCard({
9
- ...props
10
- }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
11
- return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
12
- }
13
-
14
- function HoverCardTrigger({
15
- ...props
16
- }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
17
- return (
18
- <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
19
- )
20
- }
21
-
22
- function HoverCardContent({
23
- className,
24
- align = 'center',
25
- sideOffset = 4,
26
- ...props
27
- }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
28
- return (
29
- <HoverCardPrimitive.Portal data-slot="hover-card-portal">
30
- <HoverCardPrimitive.Content
31
- data-slot="hover-card-content"
32
- align={align}
33
- sideOffset={sideOffset}
34
- className={cn(
35
- 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden',
36
- className,
37
- )}
38
- {...props}
39
- />
40
- </HoverCardPrimitive.Portal>
41
- )
42
- }
43
-
44
- export { HoverCard, HoverCardTrigger, HoverCardContent }
@@ -1,26 +0,0 @@
1
- import * as React from 'react'
2
- import * as SeparatorPrimitive from '@radix-ui/react-separator'
3
-
4
- import { cn } from '@/lib/utils'
5
-
6
- function Separator({
7
- className,
8
- orientation = 'horizontal',
9
- decorative = true,
10
- ...props
11
- }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
12
- return (
13
- <SeparatorPrimitive.Root
14
- data-slot="separator-root"
15
- decorative={decorative}
16
- orientation={orientation}
17
- className={cn(
18
- 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
19
- className,
20
- )}
21
- {...props}
22
- />
23
- )
24
- }
25
-
26
- export { Separator }
@@ -1,21 +0,0 @@
1
- import {
2
- fetchServerSentEvents,
3
- useChat,
4
- createChatClientOptions,
5
- } from '@tanstack/ai-react'
6
- import type { InferChatMessages } from '@tanstack/ai-react'
7
-
8
- // Default chat options for type inference
9
- const defaultChatOptions = createChatClientOptions({
10
- connection: fetchServerSentEvents('/api/resume-chat'),
11
- })
12
-
13
- export type ResumeChatMessages = InferChatMessages<typeof defaultChatOptions>
14
-
15
- export const useResumeChat = () => {
16
- const chatOptions = createChatClientOptions({
17
- connection: fetchServerSentEvents('/api/resume-chat'),
18
- })
19
-
20
- return useChat(chatOptions)
21
- }
@@ -1,165 +0,0 @@
1
- import { toolDefinition } from '@tanstack/ai'
2
- import { z } from 'zod'
3
-
4
- import { allJobs, allEducations } from 'content-collections'
5
-
6
- // Tool definition for getting jobs by skill
7
- export const getJobsBySkillToolDef = toolDefinition({
8
- name: 'getJobsBySkill',
9
- description:
10
- 'Find all jobs where the candidate used a specific technology or skill. Use this to check if the candidate has experience with particular technologies.',
11
- inputSchema: z.object({
12
- skill: z
13
- .string()
14
- .describe(
15
- 'The skill or technology to search for (e.g., "React", "TypeScript", "Leadership")',
16
- ),
17
- }),
18
- outputSchema: z.array(
19
- z.object({
20
- jobTitle: z.string(),
21
- company: z.string(),
22
- location: z.string(),
23
- startDate: z.string(),
24
- endDate: z.string().optional(),
25
- summary: z.string(),
26
- tags: z.array(z.string()),
27
- content: z.string(),
28
- }),
29
- ),
30
- })
31
-
32
- // Server implementation
33
- export const getJobsBySkill = getJobsBySkillToolDef.server(({ skill }) => {
34
- return allJobs.filter((job) =>
35
- job.tags.some((tag) => tag.toLowerCase().includes(skill.toLowerCase())),
36
- )
37
- })
38
-
39
- // Tool definition for getting all jobs
40
- export const getAllJobsToolDef = toolDefinition({
41
- name: 'getAllJobs',
42
- description:
43
- "Get a complete list of all work experience with full details including job titles, companies, dates, summaries, and skills. Use this to get an overview of the candidate's entire work history.",
44
- inputSchema: z.object({}),
45
- outputSchema: z.array(
46
- z.object({
47
- jobTitle: z.string(),
48
- company: z.string(),
49
- location: z.string(),
50
- startDate: z.string(),
51
- endDate: z.string().optional(),
52
- summary: z.string(),
53
- tags: z.array(z.string()),
54
- content: z.string(),
55
- }),
56
- ),
57
- })
58
-
59
- // Server implementation
60
- export const getAllJobs = getAllJobsToolDef.server(() => {
61
- return allJobs.map((job) => ({
62
- jobTitle: job.jobTitle,
63
- company: job.company,
64
- location: job.location,
65
- startDate: job.startDate,
66
- endDate: job.endDate,
67
- summary: job.summary,
68
- tags: job.tags,
69
- content: job.content,
70
- }))
71
- })
72
-
73
- // Tool definition for getting all education
74
- export const getAllEducationToolDef = toolDefinition({
75
- name: 'getAllEducation',
76
- description:
77
- "Get a complete list of all education history including schools, programs, dates, and skills learned. Use this to understand the candidate's educational background.",
78
- inputSchema: z.object({}),
79
- outputSchema: z.array(
80
- z.object({
81
- school: z.string(),
82
- summary: z.string(),
83
- startDate: z.string(),
84
- endDate: z.string().optional(),
85
- tags: z.array(z.string()),
86
- content: z.string(),
87
- }),
88
- ),
89
- })
90
-
91
- // Server implementation
92
- export const getAllEducation = getAllEducationToolDef.server(() => {
93
- return allEducations.map((education) => ({
94
- school: education.school,
95
- summary: education.summary,
96
- startDate: education.startDate,
97
- endDate: education.endDate,
98
- tags: education.tags,
99
- content: education.content,
100
- }))
101
- })
102
-
103
- // Tool definition for searching experience
104
- export const searchExperienceToolDef = toolDefinition({
105
- name: 'searchExperience',
106
- description:
107
- 'Search for jobs by keywords in the job title, company name, summary, or content. Use this to find specific types of experience or roles.',
108
- inputSchema: z.object({
109
- query: z
110
- .string()
111
- .describe(
112
- 'The search query (e.g., "senior", "lead", "frontend", "startup")',
113
- ),
114
- }),
115
- outputSchema: z.array(
116
- z.object({
117
- jobTitle: z.string(),
118
- company: z.string(),
119
- location: z.string(),
120
- startDate: z.string(),
121
- endDate: z.string().optional(),
122
- summary: z.string(),
123
- tags: z.array(z.string()),
124
- matchedIn: z
125
- .array(z.string())
126
- .describe('Which fields matched the search'),
127
- }),
128
- ),
129
- })
130
-
131
- // Server implementation
132
- export const searchExperience = searchExperienceToolDef.server(({ query }) => {
133
- const lowerQuery = query.toLowerCase()
134
-
135
- return allJobs
136
- .map((job) => {
137
- const matchedIn: string[] = []
138
-
139
- if (job.jobTitle.toLowerCase().includes(lowerQuery)) {
140
- matchedIn.push('job title')
141
- }
142
- if (job.company.toLowerCase().includes(lowerQuery)) {
143
- matchedIn.push('company')
144
- }
145
- if (job.summary.toLowerCase().includes(lowerQuery)) {
146
- matchedIn.push('summary')
147
- }
148
- if (job.content.toLowerCase().includes(lowerQuery)) {
149
- matchedIn.push('description')
150
- }
151
-
152
- return { job, matchedIn }
153
- })
154
- .filter(({ matchedIn }) => matchedIn.length > 0)
155
- .map(({ job, matchedIn }) => ({
156
- jobTitle: job.jobTitle,
157
- company: job.company,
158
- location: job.location,
159
- startDate: job.startDate,
160
- endDate: job.endDate,
161
- summary: job.summary,
162
- tags: job.tags,
163
- matchedIn,
164
- }))
165
- })
@@ -1,6 +0,0 @@
1
- import { clsx, type ClassValue } from 'clsx'
2
- import { twMerge } from 'tailwind-merge'
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs))
6
- }
@@ -1,57 +0,0 @@
1
- import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
2
- import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
3
- import { TanStackDevtools } from '@tanstack/react-devtools'
4
-
5
- import Header from '../components/Header'
6
-
7
- import appCss from '../styles.css?url'
8
-
9
- export const Route = createRootRoute({
10
- head: () => ({
11
- meta: [
12
- {
13
- charSet: 'utf-8',
14
- },
15
- {
16
- name: 'viewport',
17
- content: 'width=device-width, initial-scale=1',
18
- },
19
- {
20
- title: 'Portfolio',
21
- },
22
- ],
23
- links: [
24
- {
25
- rel: 'stylesheet',
26
- href: appCss,
27
- },
28
- ],
29
- }),
30
- shellComponent: RootDocument,
31
- })
32
-
33
- function RootDocument({ children }: { children: React.ReactNode }) {
34
- return (
35
- <html lang="en">
36
- <head>
37
- <HeadContent />
38
- </head>
39
- <body>
40
- <Header />
41
- {children}
42
- <TanStackDevtools
43
- config={{
44
- position: 'bottom-right',
45
- }}
46
- plugins={[
47
- {
48
- name: 'Tanstack Router',
49
- render: <TanStackRouterDevtoolsPanel />,
50
- },
51
- ]}
52
- />
53
- <Scripts />
54
- </body>
55
- </html>
56
- )
57
- }
@@ -1,116 +0,0 @@
1
- import { createFileRoute } from '@tanstack/react-router'
2
- import { chat, maxIterations, toServerSentEventsResponse } from '@tanstack/ai'
3
- import { anthropicText } from '@tanstack/ai-anthropic'
4
- import { openaiText } from '@tanstack/ai-openai'
5
- import { geminiText } from '@tanstack/ai-gemini'
6
- import { ollamaText } from '@tanstack/ai-ollama'
7
-
8
- import {
9
- getJobsBySkill,
10
- getAllJobs,
11
- getAllEducation,
12
- searchExperience,
13
- } from '@/lib/resume-tools'
14
-
15
- export const Route = createFileRoute('/api/resume-chat')({
16
- server: {
17
- handlers: {
18
- POST: async ({ request }) => {
19
- const requestSignal = request.signal
20
-
21
- if (requestSignal.aborted) {
22
- return new Response(null, { status: 499 })
23
- }
24
-
25
- const abortController = new AbortController()
26
-
27
- try {
28
- const body = await request.json()
29
- const { messages } = body
30
- const data = body.data || {}
31
-
32
- const SYSTEM_PROMPT = `You are a helpful resume assistant helping recruiters and hiring managers evaluate if this candidate is a good fit for their job requirements.
33
-
34
- CAPABILITIES:
35
- 1. Use getJobsBySkill to find jobs where the candidate used specific technologies or skills
36
- 2. Use getAllJobs to get the candidate's complete work history with all details
37
- 3. Use getAllEducation to get the candidate's educational background
38
- 4. Use searchExperience to search for specific types of roles or experience by keywords
39
-
40
- INSTRUCTIONS:
41
- - When asked about specific technologies or skills, use getJobsBySkill to find relevant experience
42
- - When asked about overall experience or career progression, use getAllJobs
43
- - When asked about education or training, use getAllEducation
44
- - When asked about specific types of roles (e.g., "senior", "lead"), use searchExperience
45
- - Be professional, concise, and helpful in your responses
46
- - Provide specific details from the resume when available
47
- - When calculating years of experience, consider the date ranges provided
48
- - If the candidate has experience with something, highlight specific roles and time periods
49
- - If the candidate lacks certain experience, be honest but constructive
50
-
51
- CONTEXT: You are helping evaluate this candidate's qualifications for potential job opportunities.`
52
-
53
- // Determine the best available provider
54
- let provider: 'anthropic' | 'openai' | 'gemini' | 'ollama' =
55
- data.provider || 'ollama'
56
- let model: string = data.model || 'mistral:7b'
57
-
58
- // Use the first available provider with an API key, fallback to ollama
59
- if (process.env.ANTHROPIC_API_KEY) {
60
- provider = 'anthropic'
61
- model = 'claude-haiku-4-5'
62
- } else if (process.env.OPENAI_API_KEY) {
63
- provider = 'openai'
64
- model = 'gpt-4o'
65
- } else if (process.env.GEMINI_API_KEY) {
66
- provider = 'gemini'
67
- model = 'gemini-2.0-flash-exp'
68
- }
69
- // else keep ollama as default
70
-
71
- // Adapter factory pattern for multi-vendor support
72
- const adapterConfig = {
73
- anthropic: () =>
74
- anthropicText((model || 'claude-haiku-4-5') as any),
75
- openai: () => openaiText((model || 'gpt-4o') as any),
76
- gemini: () => geminiText((model || 'gemini-2.0-flash-exp') as any),
77
- ollama: () => ollamaText((model || 'mistral:7b') as any),
78
- }
79
-
80
- const adapter = adapterConfig[provider]()
81
-
82
- const stream = chat({
83
- adapter,
84
- tools: [
85
- getJobsBySkill,
86
- getAllJobs,
87
- getAllEducation,
88
- searchExperience,
89
- ],
90
- systemPrompts: [SYSTEM_PROMPT],
91
- agentLoopStrategy: maxIterations(5),
92
- messages,
93
- abortController,
94
- })
95
-
96
- return toServerSentEventsResponse(stream, { abortController })
97
- } catch (error: any) {
98
- console.error('Resume chat error:', error)
99
- if (error.name === 'AbortError' || abortController.signal.aborted) {
100
- return new Response(null, { status: 499 })
101
- }
102
- return new Response(
103
- JSON.stringify({
104
- error: 'Failed to process chat request',
105
- message: error.message,
106
- }),
107
- {
108
- status: 500,
109
- headers: { 'Content-Type': 'application/json' },
110
- },
111
- )
112
- }
113
- },
114
- },
115
- },
116
- })
@@ -1,73 +0,0 @@
1
- import { createFileRoute, Link } from '@tanstack/react-router'
2
- import { allBlogs } from 'content-collections'
3
- import { marked } from 'marked'
4
- import { Badge } from '@/components/ui/badge'
5
- import { ArrowLeft, Calendar } from 'lucide-react'
6
-
7
- export const Route = createFileRoute('/blog/$slug')({
8
- component: BlogPost,
9
- })
10
-
11
- function BlogPost() {
12
- const { slug } = Route.useParams()
13
- const post = allBlogs.find((p) => p._meta.path === slug)
14
-
15
- if (!post) {
16
- return (
17
- <div className="min-h-screen bg-gray-50 flex items-center justify-center">
18
- <div className="text-center">
19
- <h1 className="text-2xl font-bold text-gray-900 mb-4">Post not found</h1>
20
- <Link to="/" className="text-blue-600 hover:underline">
21
- Back to blog
22
- </Link>
23
- </div>
24
- </div>
25
- )
26
- }
27
-
28
- const html = marked(post.content)
29
-
30
- return (
31
- <div className="min-h-screen bg-gray-50">
32
- <div className="max-w-3xl mx-auto px-4 py-12">
33
- <Link
34
- to="/"
35
- className="inline-flex items-center gap-2 text-gray-600 hover:text-gray-900 mb-8"
36
- >
37
- <ArrowLeft size={16} />
38
- Back to blog
39
- </Link>
40
-
41
- <article>
42
- <header className="mb-8">
43
- <h1 className="text-4xl font-bold text-gray-900 mb-4">{post.title}</h1>
44
- <div className="flex items-center gap-3 text-gray-500 mb-4">
45
- <Calendar size={16} />
46
- <time>
47
- {new Date(post.date).toLocaleDateString('en-US', {
48
- year: 'numeric',
49
- month: 'long',
50
- day: 'numeric',
51
- })}
52
- </time>
53
- <span>·</span>
54
- <span>{post.author}</span>
55
- </div>
56
- <div className="flex flex-wrap gap-2">
57
- {post.tags.map((tag) => (
58
- <Badge key={tag} variant="secondary">
59
- {tag}
60
- </Badge>
61
- ))}
62
- </div>
63
- </header>
64
-
65
- <div
66
- className="prose prose-gray max-w-none"
67
- dangerouslySetInnerHTML={{ __html: html }}
68
- />
69
- </article>
70
- </div>
71
- </div>
72
- )
73
- }