From 3b51f8b2857e1a7d6e05c7a9707c99a5bc7c9b52 Mon Sep 17 00:00:00 2001
From: srijita22 <163577688+srijita22@users.noreply.github.com>
Date: Fri, 27 Mar 2026 19:21:45 +0530
Subject: [PATCH 1/3] feat: Add resumeFit AgentKit
---
kits/agentic/resumeFit/.env.example | 4 +
kits/agentic/resumeFit/.gitignore | 28 +
kits/agentic/resumeFit/README.md | 106 +
kits/agentic/resumeFit/actions/config.ts | 12 +
kits/agentic/resumeFit/actions/orchestrate.ts | 128 +
kits/agentic/resumeFit/app/globals.css | 127 +
kits/agentic/resumeFit/app/layout.tsx | 45 +
kits/agentic/resumeFit/app/page.tsx | 265 +
kits/agentic/resumeFit/components.json | 21 +
kits/agentic/resumeFit/components/header.tsx | 56 +
.../resumeFit/components/theme-provider.tsx | 11 +
.../resumeFit/components/ui/accordion.tsx | 66 +
.../resumeFit/components/ui/alert-dialog.tsx | 157 +
.../agentic/resumeFit/components/ui/alert.tsx | 66 +
.../resumeFit/components/ui/aspect-ratio.tsx | 11 +
.../resumeFit/components/ui/avatar.tsx | 53 +
.../agentic/resumeFit/components/ui/badge.tsx | 46 +
.../resumeFit/components/ui/breadcrumb.tsx | 109 +
.../resumeFit/components/ui/button-group.tsx | 83 +
.../resumeFit/components/ui/button.tsx | 60 +
.../resumeFit/components/ui/calendar.tsx | 213 +
kits/agentic/resumeFit/components/ui/card.tsx | 92 +
.../resumeFit/components/ui/carousel.tsx | 241 +
.../agentic/resumeFit/components/ui/chart.tsx | 353 +
.../resumeFit/components/ui/checkbox.tsx | 32 +
.../resumeFit/components/ui/collapsible.tsx | 33 +
.../resumeFit/components/ui/command.tsx | 184 +
.../resumeFit/components/ui/context-menu.tsx | 252 +
.../resumeFit/components/ui/dialog.tsx | 143 +
.../resumeFit/components/ui/drawer.tsx | 135 +
.../resumeFit/components/ui/dropdown-menu.tsx | 257 +
.../agentic/resumeFit/components/ui/empty.tsx | 104 +
.../agentic/resumeFit/components/ui/field.tsx | 244 +
kits/agentic/resumeFit/components/ui/form.tsx | 167 +
.../resumeFit/components/ui/hover-card.tsx | 44 +
.../resumeFit/components/ui/input-group.tsx | 169 +
.../resumeFit/components/ui/input-otp.tsx | 77 +
.../agentic/resumeFit/components/ui/input.tsx | 21 +
kits/agentic/resumeFit/components/ui/item.tsx | 193 +
kits/agentic/resumeFit/components/ui/kbd.tsx | 28 +
.../agentic/resumeFit/components/ui/label.tsx | 24 +
.../resumeFit/components/ui/menubar.tsx | 276 +
.../components/ui/navigation-menu.tsx | 166 +
.../resumeFit/components/ui/pagination.tsx | 127 +
.../resumeFit/components/ui/popover.tsx | 48 +
.../resumeFit/components/ui/progress.tsx | 31 +
.../resumeFit/components/ui/radio-group.tsx | 45 +
.../resumeFit/components/ui/resizable.tsx | 56 +
.../resumeFit/components/ui/scroll-area.tsx | 58 +
.../resumeFit/components/ui/select.tsx | 185 +
.../resumeFit/components/ui/separator.tsx | 28 +
.../agentic/resumeFit/components/ui/sheet.tsx | 139 +
.../resumeFit/components/ui/sidebar.tsx | 726 ++
.../resumeFit/components/ui/skeleton.tsx | 13 +
.../resumeFit/components/ui/slider.tsx | 63 +
.../resumeFit/components/ui/sonner.tsx | 25 +
.../resumeFit/components/ui/spinner.tsx | 16 +
.../resumeFit/components/ui/switch.tsx | 31 +
.../agentic/resumeFit/components/ui/table.tsx | 116 +
kits/agentic/resumeFit/components/ui/tabs.tsx | 66 +
.../resumeFit/components/ui/textarea.tsx | 18 +
.../agentic/resumeFit/components/ui/toast.tsx | 129 +
.../resumeFit/components/ui/toaster.tsx | 35 +
.../resumeFit/components/ui/toggle-group.tsx | 73 +
.../resumeFit/components/ui/toggle.tsx | 47 +
.../resumeFit/components/ui/tooltip.tsx | 61 +
.../resumeFit/components/ui/use-mobile.tsx | 19 +
.../resumeFit/components/ui/use-toast.ts | 191 +
kits/agentic/resumeFit/config.json | 22 +
.../resumeFit/flows/resume-fit-flow/README.md | 62 +
.../flows/resume-fit-flow/config.json | 435 ++
.../flows/resume-fit-flow/inputs.json | 170 +
.../resumeFit/flows/resume-fit-flow/meta.json | 9 +
kits/agentic/resumeFit/hooks/use-mobile.ts | 19 +
kits/agentic/resumeFit/hooks/use-toast.ts | 191 +
kits/agentic/resumeFit/lib/lamatic-client.ts | 24 +
kits/agentic/resumeFit/lib/utils.ts | 6 +
kits/agentic/resumeFit/next.config.mjs | 11 +
kits/agentic/resumeFit/package-lock.json | 6170 +++++++++++++++++
kits/agentic/resumeFit/package.json | 84 +
kits/agentic/resumeFit/postcss.config.js | 6 +
kits/agentic/resumeFit/tailwind.config.js | 11 +
kits/agentic/resumeFit/tsconfig.json | 38 +
83 files changed, 14506 insertions(+)
create mode 100644 kits/agentic/resumeFit/.env.example
create mode 100644 kits/agentic/resumeFit/.gitignore
create mode 100644 kits/agentic/resumeFit/README.md
create mode 100644 kits/agentic/resumeFit/actions/config.ts
create mode 100644 kits/agentic/resumeFit/actions/orchestrate.ts
create mode 100644 kits/agentic/resumeFit/app/globals.css
create mode 100644 kits/agentic/resumeFit/app/layout.tsx
create mode 100644 kits/agentic/resumeFit/app/page.tsx
create mode 100644 kits/agentic/resumeFit/components.json
create mode 100644 kits/agentic/resumeFit/components/header.tsx
create mode 100644 kits/agentic/resumeFit/components/theme-provider.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/accordion.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/alert-dialog.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/alert.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/aspect-ratio.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/avatar.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/badge.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/breadcrumb.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/button-group.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/button.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/calendar.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/card.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/carousel.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/chart.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/checkbox.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/collapsible.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/command.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/context-menu.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/dialog.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/drawer.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/dropdown-menu.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/empty.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/field.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/form.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/hover-card.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/input-group.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/input-otp.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/input.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/item.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/kbd.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/label.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/menubar.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/navigation-menu.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/pagination.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/popover.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/progress.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/radio-group.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/resizable.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/scroll-area.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/select.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/separator.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/sheet.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/sidebar.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/skeleton.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/slider.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/sonner.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/spinner.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/switch.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/table.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/tabs.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/textarea.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/toast.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/toaster.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/toggle-group.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/toggle.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/tooltip.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/use-mobile.tsx
create mode 100644 kits/agentic/resumeFit/components/ui/use-toast.ts
create mode 100644 kits/agentic/resumeFit/config.json
create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/README.md
create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/config.json
create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/inputs.json
create mode 100644 kits/agentic/resumeFit/flows/resume-fit-flow/meta.json
create mode 100644 kits/agentic/resumeFit/hooks/use-mobile.ts
create mode 100644 kits/agentic/resumeFit/hooks/use-toast.ts
create mode 100644 kits/agentic/resumeFit/lib/lamatic-client.ts
create mode 100644 kits/agentic/resumeFit/lib/utils.ts
create mode 100644 kits/agentic/resumeFit/next.config.mjs
create mode 100644 kits/agentic/resumeFit/package-lock.json
create mode 100644 kits/agentic/resumeFit/package.json
create mode 100644 kits/agentic/resumeFit/postcss.config.js
create mode 100644 kits/agentic/resumeFit/tailwind.config.js
create mode 100644 kits/agentic/resumeFit/tsconfig.json
diff --git a/kits/agentic/resumeFit/.env.example b/kits/agentic/resumeFit/.env.example
new file mode 100644
index 00000000..a943bef2
--- /dev/null
+++ b/kits/agentic/resumeFit/.env.example
@@ -0,0 +1,4 @@
+RESUME_FIT_FLOW="AGENTIC_GENERATE_CONTENT Flow ID"
+LAMATIC_API_URL="LAMATIC_API_URL"
+LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
+LAMATIC_API_KEY="LAMATIC_API_KEY"
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/.gitignore b/kits/agentic/resumeFit/.gitignore
new file mode 100644
index 00000000..3c35968e
--- /dev/null
+++ b/kits/agentic/resumeFit/.gitignore
@@ -0,0 +1,28 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# env files
+.env*
+!.env.example
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/README.md b/kits/agentic/resumeFit/README.md
new file mode 100644
index 00000000..5943f657
--- /dev/null
+++ b/kits/agentic/resumeFit/README.md
@@ -0,0 +1,106 @@
+# Agent Kit Generation by Lamatic.ai
+
+
+
+
+
+
+
+
+**Agent Kit Generation** is an AI-powered content generation system built with [Lamatic.ai](https://lamatic.ai). It uses intelligent workflows to generate text, images, and JSON content through a modern Next.js interface with markdown rendering support.
+
+[](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits/agentic/generation&env=AGENTIC_GENERATE_CONTENT,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY&envDescription=Your%20Lamatic%20Generation%20keys%20are%20required.&envLink=https://lamatic.ai/templates/agentkits/agentic/agent-kit-generation)
+
+---
+
+## Lamatic Setup (Pre and Post)
+
+Before running this project, you must build and deploy the flow in Lamatic, then wire its config into this codebase.
+
+Pre: Build in Lamatic
+1. Sign in or sign up at https://lamatic.ai
+2. Create a project (if you donβt have one yet)
+3. Click β+ New Flowβ and select "Templates"
+4. Select the 'Generation' agent kit
+5. Configure providers/tools/inputs as prompted
+6. Deploy the kit in Lamatic and obtain your .env keys
+7. Copy the keys from your studio
+
+Post: Wire into this repo
+1. Create a .env file and set the keys
+2. Install and run locally:
+ - npm install
+ - npm run dev
+3. Deploy (Vercel recommended):
+ - Import your repo, set the project's Root Directory (if applicable)
+ - Add env vars in Vercel (same as your .env)
+ - Deploy and test your live URL
+
+Notes
+- Coming soon: single-click export and "Connect Git" in Lamatic to push config directly to your repo.
+
+---
+
+## π Setup
+## Required Keys and Config
+
+Youβll need these things to run this project locally:
+
+1. **.env Keys** β get it from your [Lamatic account](https://lamatic.ai) post kit deployment.
+
+
+| Item | Purpose | Where to Get It |
+| ----------------- | -------------------------------------------- | ----------------------------------------------- |
+| .env Key | Authentication for Lamatic AI APIs and Orchestration | [lamatic.ai](https://lamatic.ai) |
+
+### 1. Environment Variables
+
+Create `.env.local` with:
+
+```bash
+# Lamatic
+AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID"
+LAMATIC_API_URL = "LAMATIC_API_URL"
+LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID"
+LAMATIC_API_KEY = "LAMATIC_API_KEY"
+```
+
+### 2. Install & Run
+
+```bash
+npm install
+npm run dev
+# Open http://localhost:3000
+```
+---
+
+## π Repo Structure
+
+```
+/actions
+ βββ orchestrate.ts # Lamatic workflow orchestration
+/app
+ βββ page.tsx # Main generation form UI
+/components
+ βββ header.tsx # Header component with navigation
+ βββ ui # shadcn/ui components
+/lib
+ βββ lamatic-client.ts # Lamatic SDK client
+/public
+ βββ lamatic-logo.png # Lamatic branding
+/flows
+ βββ ... # Lamatic Flows
+/package.json # Dependencies & scripts
+```
+
+---
+
+## π€ Contributing
+
+We welcome contributions! Open an issue or PR in this repo.
+
+---
+
+## π License
+
+MIT License β see [LICENSE](../../../LICENSE).
diff --git a/kits/agentic/resumeFit/actions/config.ts b/kits/agentic/resumeFit/actions/config.ts
new file mode 100644
index 00000000..ba5e1024
--- /dev/null
+++ b/kits/agentic/resumeFit/actions/config.ts
@@ -0,0 +1,12 @@
+export const config = {
+ flows: {
+ resumeFit: {
+ name: "Resume Fit Flow",
+ workflowId: process.env.AGENTIC_GENERATE_CONTENT,
+ inputSchema: {
+ instructions: "string",
+ mode: "string"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/actions/orchestrate.ts b/kits/agentic/resumeFit/actions/orchestrate.ts
new file mode 100644
index 00000000..34921240
--- /dev/null
+++ b/kits/agentic/resumeFit/actions/orchestrate.ts
@@ -0,0 +1,128 @@
+"use server"
+
+import { lamaticClient } from "../lib/lamatic-client"
+import { config } from "./config"
+
+type InputType = "text" | "image" | "json"
+
+export async function evaluateResume(
+ inputType: InputType,
+ instructions: string,
+): Promise<{
+ success: boolean
+ data?: any
+ error?: string
+}> {
+ try {
+ console.log("[v0] Generating content with:", { inputType, instructions })
+
+ // Get the first workflow from the config
+ const flows = config.flows
+ const firstFlowKey = Object.keys(flows)[0]
+
+ if (!firstFlowKey) {
+ throw new Error("No workflows found in configuration")
+ }
+
+ // Fix: Add index signature to make TypeScript happy about accessing flows[firstFlowKey]
+ const flow = flows[firstFlowKey as keyof typeof flows] as (typeof flows)[keyof typeof flows];
+ console.log("[v0] Using workflow:", flow.name, flow.workflowId);
+
+ // Prepare inputs based on the flow's input schema
+ const inputs: Record = {
+ mode: inputType,
+ instructions,
+ }
+
+ // Map to schema if needed
+ for (const inputKey of Object.keys(flow.inputSchema || {})) {
+ if (inputKey === "inputType" || inputKey === "type") {
+ inputs[inputKey] = inputType
+ } else if (inputKey === "instructions" || inputKey === "query") {
+ inputs[inputKey] = instructions
+ }
+ }
+
+ console.log("[v0] Sending inputs:", inputs)
+
+ if(!flow.workflowId){
+ throw Error("Workflow not found in config.")
+ }
+ const res = await fetch(process.env.LAMATIC_API_URL!, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": `Bearer ${process.env.LAMATIC_API_KEY}`,
+ "x-project-id": process.env.LAMATIC_PROJECT_ID!,
+ },
+ body: JSON.stringify({
+ query: `
+ query ExecuteWorkflow($workflowId: String!, $payload: JSON!) {
+ executeWorkflow(workflowId: $workflowId, payload: $payload) {
+ status
+ result
+ }
+ }
+ `,
+ variables: {
+ workflowId: flow.workflowId,
+ payload: {
+ chatMessage: instructions, // π map your input here
+ mode: inputType, // optional depending on your flow
+ },
+ },
+ }),
+})
+
+console.log("STATUS:", res.status)
+console.log("CONTENT TYPE:", res.headers.get("content-type"))
+
+ const resData = await res.json()
+console.log("FULL RESPONSE:", JSON.stringify(resData, null, 2))
+
+ // Parse the answer from resData?.output.answer
+
+const exec = resData?.data?.executeWorkflow
+
+if (!exec) {
+ throw new Error("Invalid response structure")
+}
+
+if (exec.status !== "success") {
+ throw new Error("Workflow execution failed")
+}
+
+// β
FIX: extract content instead of answer
+const answer =
+ exec?.result?.content ||
+ exec?.result?.answer || // fallback if structure changes
+ exec?.result
+
+if (!answer) {
+ throw new Error("No answer found in response")
+}
+
+return {
+ success: true,
+ data: answer,
+}
+ } catch (error) {
+ console.error("[v0] Generation error:", error)
+
+ let errorMessage = "Unknown error occurred"
+ if (error instanceof Error) {
+ errorMessage = error.message
+ if (error.message.includes("fetch failed")) {
+ errorMessage =
+ "Network error: Unable to connect to the service. Please check your internet connection and try again."
+ } else if (error.message.includes("API key")) {
+ errorMessage = "Authentication error: Please check your API configuration."
+ }
+ }
+
+ return {
+ success: false,
+ error: errorMessage,
+ }
+ }
+}
diff --git a/kits/agentic/resumeFit/app/globals.css b/kits/agentic/resumeFit/app/globals.css
new file mode 100644
index 00000000..edfe99e2
--- /dev/null
+++ b/kits/agentic/resumeFit/app/globals.css
@@ -0,0 +1,127 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+
+@custom-variant dark (&:is(.dark *));
+
+:root {
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --radius: 0.625rem;
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+}
+
+.dark {
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.145 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.145 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.985 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.396 0.141 25.723);
+ --destructive-foreground: oklch(0.637 0.237 25.331);
+ --border: oklch(0.269 0 0);
+ --input: oklch(0.269 0 0);
+ --ring: oklch(0.439 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(0.269 0 0);
+ --sidebar-ring: oklch(0.439 0 0);
+}
+
+@theme inline {
+ --font-sans: 'Geist', 'Geist Fallback';
+ --font-mono: 'Geist Mono', 'Geist Mono Fallback';
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
+
+@layer base {
+ * {
+ @apply border;
+ }
+ body {
+ @apply bg-white text-black;
+ }
+}
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/app/layout.tsx b/kits/agentic/resumeFit/app/layout.tsx
new file mode 100644
index 00000000..4489638d
--- /dev/null
+++ b/kits/agentic/resumeFit/app/layout.tsx
@@ -0,0 +1,45 @@
+import type { Metadata } from 'next'
+import { Geist, Geist_Mono } from 'next/font/google'
+import { Analytics } from '@vercel/analytics/next'
+import './globals.css'
+
+const _geist = Geist({ subsets: ["latin"] });
+const _geistMono = Geist_Mono({ subsets: ["latin"] });
+
+export const metadata: Metadata = {
+ title: 'v0 App',
+ description: 'Created with v0',
+ generator: 'v0.app',
+ icons: {
+ icon: [
+ {
+ url: '/icon-light-32x32.png',
+ media: '(prefers-color-scheme: light)',
+ },
+ {
+ url: '/icon-dark-32x32.png',
+ media: '(prefers-color-scheme: dark)',
+ },
+ {
+ url: '/icon.svg',
+ type: 'image/svg+xml',
+ },
+ ],
+ apple: '/apple-icon.png',
+ },
+}
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode
+}>) {
+ return (
+
+
+ {children}
+
+
+
+ )
+}
diff --git a/kits/agentic/resumeFit/app/page.tsx b/kits/agentic/resumeFit/app/page.tsx
new file mode 100644
index 00000000..5c9aed9c
--- /dev/null
+++ b/kits/agentic/resumeFit/app/page.tsx
@@ -0,0 +1,265 @@
+"use client"
+
+import { useState } from "react"
+import { Button } from "../components/ui/button"
+import { Textarea } from "../components/ui/textarea"
+import { Card } from "../components/ui/card"
+import { Loader2, Sparkles, Copy, Check, Home } from "lucide-react"
+import { evaluateResume } from "../actions/orchestrate"
+import { Header } from "../components/header"
+
+export default function ResumeScreener() {
+ const [resume, setResume] = useState("")
+ const [jobDesc, setJobDesc] = useState("")
+ const [isLoading, setIsLoading] = useState(false)
+ const [result, setResult] = useState(null)
+ const [error, setError] = useState("")
+ const [copied, setCopied] = useState(false)
+
+ const handleSubmit = async (e: any) => {
+ e.preventDefault()
+
+ if (!resume || !jobDesc) {
+ setError("Please provide both resume and job description")
+ return
+ }
+
+ setIsLoading(true)
+ setError("")
+ setResult(null)
+
+ try {
+ const combinedInput = `
+ RESUME:
+ ${resume}
+
+ JOB DESCRIPTION:
+ ${jobDesc}
+ `
+
+ const response = await evaluateResume("text", combinedInput)
+
+ if (response.success) {
+ try {
+ let raw = response.data
+
+ if (typeof raw === "string") {
+
+
+ raw = raw.replace(/```json|```/g, "").trim()
+
+
+ const match = raw.match(/\{[\s\S]*\}/)
+
+ if (!match) {
+ throw new Error("No valid JSON found in response")
+ }
+
+ const parsed = JSON.parse(match[0])
+
+ const formatted = {
+ decision: parsed.decision,
+ summary: parsed.summary,
+ score: Number(parsed.fscore || 0),
+ strengths: parsed.strengths
+ ? parsed.strengths.split(",").map((s: string) => s.trim())
+ : [],
+ weaknesses: parsed.weaknesses
+ ? parsed.weaknesses.split(",").map((s: string) => s.trim())
+ : [],
+}
+
+setResult(formatted)
+
+ } else {
+ // Already JSON
+ setResult(raw)
+ }
+
+ } catch (err) {
+ console.error("Parsing error:", err)
+ setError("Failed to parse AI response")
+ }
+}
+ } catch (err: any) {
+ setError(err.message)
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ const handleCopy = async () => {
+ await navigator.clipboard.writeText(JSON.stringify(result, null, 2))
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ }
+
+ const handleReset = () => {
+ setResult(null)
+ setResume("")
+ setJobDesc("")
+ setError("")
+ }
+
+ const decision = result?.decision
+const summary = result?.summary
+const score = result?.score
+const strengths = result?.strengths || []
+const weaknesses = result?.weaknesses || []
+
+ return (
+
+
+
+
+
+ {/* HERO */}
+ {!result && (
+ <>
+
+
+ AI Resume Screener
+
+
+ Instantly evaluate candidates based on job requirements
+
+
+
+
+
+
+
+ >
+ )}
+
+ {/* RESULT SCREEN */}
+ {result && (
+
+
+
+
+ Evaluation Result
+
+
+ AI-powered candidate assessment
+
+
+
+
+
+ {/* DECISION BADGE */}
+
+ {decision}
+
+
+ {/* SCORE */}
+
+
Candidate Score
+
+ {score}/100
+
+
+
+ {/* STRENGTHS */}
+
+
Strengths
+
+ {strengths.map((item: string, idx: number) => (
+ - {item}
+ ))}
+
+
+
+ {/* WEAKNESSES */}
+
+
Weaknesses
+
+ {weaknesses.map((item: string, idx: number) => (
+ - {item}
+ ))}
+
+
+
+ {/* SUMMARY */}
+
+
AI Summary
+
{summary}
+
+
+ {/* ACTIONS */}
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/components.json b/kits/agentic/resumeFit/components.json
new file mode 100644
index 00000000..4ee62ee1
--- /dev/null
+++ b/kits/agentic/resumeFit/components.json
@@ -0,0 +1,21 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": true,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "app/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "iconLibrary": "lucide"
+}
diff --git a/kits/agentic/resumeFit/components/header.tsx b/kits/agentic/resumeFit/components/header.tsx
new file mode 100644
index 00000000..b44f0fb0
--- /dev/null
+++ b/kits/agentic/resumeFit/components/header.tsx
@@ -0,0 +1,56 @@
+import Link from "next/link"
+import { Github, Sparkles } from "lucide-react"
+import Image from "next/image"
+
+export function Header() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/kits/agentic/resumeFit/components/theme-provider.tsx b/kits/agentic/resumeFit/components/theme-provider.tsx
new file mode 100644
index 00000000..55c2f6eb
--- /dev/null
+++ b/kits/agentic/resumeFit/components/theme-provider.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import * as React from 'react'
+import {
+ ThemeProvider as NextThemesProvider,
+ type ThemeProviderProps,
+} from 'next-themes'
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return {children}
+}
diff --git a/kits/agentic/resumeFit/components/ui/accordion.tsx b/kits/agentic/resumeFit/components/ui/accordion.tsx
new file mode 100644
index 00000000..e538a33b
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/accordion.tsx
@@ -0,0 +1,66 @@
+'use client'
+
+import * as React from 'react'
+import * as AccordionPrimitive from '@radix-ui/react-accordion'
+import { ChevronDownIcon } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+
+function Accordion({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function AccordionItem({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AccordionTrigger({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ svg]:rotate-180',
+ className,
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+ )
+}
+
+function AccordionContent({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ {children}
+
+ )
+}
+
+export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/kits/agentic/resumeFit/components/ui/alert-dialog.tsx b/kits/agentic/resumeFit/components/ui/alert-dialog.tsx
new file mode 100644
index 00000000..97044526
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/alert-dialog.tsx
@@ -0,0 +1,157 @@
+'use client'
+
+import * as React from 'react'
+import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
+
+import { cn } from '@/lib/utils'
+import { buttonVariants } from '@/components/ui/button'
+
+function AlertDialog({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+function AlertDialogTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogOverlay({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+ )
+}
+
+function AlertDialogHeader({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDialogFooter({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDialogTitle({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogDescription({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogAction({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AlertDialogCancel({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/kits/agentic/resumeFit/components/ui/alert.tsx b/kits/agentic/resumeFit/components/ui/alert.tsx
new file mode 100644
index 00000000..e6751abe
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/alert.tsx
@@ -0,0 +1,66 @@
+import * as React from 'react'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+
+const alertVariants = cva(
+ 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
+ {
+ variants: {
+ variant: {
+ default: 'bg-card text-card-foreground',
+ destructive:
+ 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+)
+
+function Alert({
+ className,
+ variant,
+ ...props
+}: React.ComponentProps<'div'> & VariantProps) {
+ return (
+
+ )
+}
+
+function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+function AlertDescription({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ )
+}
+
+export { Alert, AlertTitle, AlertDescription }
diff --git a/kits/agentic/resumeFit/components/ui/aspect-ratio.tsx b/kits/agentic/resumeFit/components/ui/aspect-ratio.tsx
new file mode 100644
index 00000000..40bb1208
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/aspect-ratio.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'
+
+function AspectRatio({
+ ...props
+}: React.ComponentProps) {
+ return
+}
+
+export { AspectRatio }
diff --git a/kits/agentic/resumeFit/components/ui/avatar.tsx b/kits/agentic/resumeFit/components/ui/avatar.tsx
new file mode 100644
index 00000000..aa98465a
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/avatar.tsx
@@ -0,0 +1,53 @@
+'use client'
+
+import * as React from 'react'
+import * as AvatarPrimitive from '@radix-ui/react-avatar'
+
+import { cn } from '@/lib/utils'
+
+function Avatar({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AvatarImage({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+function AvatarFallback({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export { Avatar, AvatarImage, AvatarFallback }
diff --git a/kits/agentic/resumeFit/components/ui/badge.tsx b/kits/agentic/resumeFit/components/ui/badge.tsx
new file mode 100644
index 00000000..fc4126b7
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/badge.tsx
@@ -0,0 +1,46 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+
+const badgeVariants = cva(
+ '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',
+ {
+ variants: {
+ variant: {
+ default:
+ 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
+ secondary:
+ 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
+ destructive:
+ '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',
+ outline:
+ 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+)
+
+function Badge({
+ className,
+ variant,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'span'> &
+ VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot : 'span'
+
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/kits/agentic/resumeFit/components/ui/breadcrumb.tsx b/kits/agentic/resumeFit/components/ui/breadcrumb.tsx
new file mode 100644
index 00000000..1750ff26
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/breadcrumb.tsx
@@ -0,0 +1,109 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { ChevronRight, MoreHorizontal } from 'lucide-react'
+
+import { cn } from '@/lib/utils'
+
+function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
+ return
+}
+
+function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbLink({
+ asChild,
+ className,
+ ...props
+}: React.ComponentProps<'a'> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : 'a'
+
+ return (
+
+ )
+}
+
+function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
+ return (
+
+ )
+}
+
+function BreadcrumbSeparator({
+ children,
+ className,
+ ...props
+}: React.ComponentProps<'li'>) {
+ return (
+ svg]:size-3.5', className)}
+ {...props}
+ >
+ {children ?? }
+
+ )
+}
+
+function BreadcrumbEllipsis({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) {
+ return (
+
+
+ More
+
+ )
+}
+
+export {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ BreadcrumbEllipsis,
+}
diff --git a/kits/agentic/resumeFit/components/ui/button-group.tsx b/kits/agentic/resumeFit/components/ui/button-group.tsx
new file mode 100644
index 00000000..09d44309
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/button-group.tsx
@@ -0,0 +1,83 @@
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '@/lib/utils'
+import { Separator } from '@/components/ui/separator'
+
+const buttonGroupVariants = cva(
+ "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
+ {
+ variants: {
+ orientation: {
+ horizontal:
+ '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
+ vertical:
+ 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
+ },
+ },
+ defaultVariants: {
+ orientation: 'horizontal',
+ },
+ },
+)
+
+function ButtonGroup({
+ className,
+ orientation,
+ ...props
+}: React.ComponentProps<'div'> & VariantProps) {
+ return (
+
+ )
+}
+
+function ButtonGroupText({
+ className,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'div'> & {
+ asChild?: boolean
+}) {
+ const Comp = asChild ? Slot : 'div'
+
+ return (
+
+ )
+}
+
+function ButtonGroupSeparator({
+ className,
+ orientation = 'vertical',
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ )
+}
+
+export {
+ ButtonGroup,
+ ButtonGroupSeparator,
+ ButtonGroupText,
+ buttonGroupVariants,
+}
diff --git a/kits/agentic/resumeFit/components/ui/button.tsx b/kits/agentic/resumeFit/components/ui/button.tsx
new file mode 100644
index 00000000..c5f9ccd8
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/button.tsx
@@ -0,0 +1,60 @@
+import * as React from 'react'
+import { Slot } from '@radix-ui/react-slot'
+import { cva, type VariantProps } from 'class-variance-authority'
+
+import { cn } from '../../lib/utils'
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-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",
+ {
+ variants: {
+ variant: {
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
+ destructive:
+ 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
+ secondary:
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ ghost:
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
+ link: 'text-primary underline-offset-4 hover:underline',
+ },
+ size: {
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
+ icon: 'size-9',
+ 'icon-sm': 'size-8',
+ 'icon-lg': 'size-10',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ },
+)
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'button'> &
+ VariantProps & {
+ asChild?: boolean
+ }) {
+ const Comp = asChild ? Slot : 'button'
+
+ return (
+
+ )
+}
+
+export { Button, buttonVariants }
diff --git a/kits/agentic/resumeFit/components/ui/calendar.tsx b/kits/agentic/resumeFit/components/ui/calendar.tsx
new file mode 100644
index 00000000..eaa373e2
--- /dev/null
+++ b/kits/agentic/resumeFit/components/ui/calendar.tsx
@@ -0,0 +1,213 @@
+'use client'
+
+import * as React from 'react'
+import {
+ ChevronDownIcon,
+ ChevronLeftIcon,
+ ChevronRightIcon,
+} from 'lucide-react'
+import { DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker'
+
+import { cn } from '@/lib/utils'
+import { Button, buttonVariants } from '@/components/ui/button'
+
+function Calendar({
+ className,
+ classNames,
+ showOutsideDays = true,
+ captionLayout = 'label',
+ buttonVariant = 'ghost',
+ formatters,
+ components,
+ ...props
+}: React.ComponentProps & {
+ buttonVariant?: React.ComponentProps['variant']
+}) {
+ const defaultClassNames = getDefaultClassNames()
+
+ return (
+ svg]:rotate-180`,
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
+ className,
+ )}
+ captionLayout={captionLayout}
+ formatters={{
+ formatMonthDropdown: (date) =>
+ date.toLocaleString('default', { month: 'short' }),
+ ...formatters,
+ }}
+ classNames={{
+ root: cn('w-fit', defaultClassNames.root),
+ months: cn(
+ 'flex gap-4 flex-col md:flex-row relative',
+ defaultClassNames.months,
+ ),
+ month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
+ nav: cn(
+ 'flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between',
+ defaultClassNames.nav,
+ ),
+ button_previous: cn(
+ buttonVariants({ variant: buttonVariant }),
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
+ defaultClassNames.button_previous,
+ ),
+ button_next: cn(
+ buttonVariants({ variant: buttonVariant }),
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
+ defaultClassNames.button_next,
+ ),
+ month_caption: cn(
+ 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
+ defaultClassNames.month_caption,
+ ),
+ dropdowns: cn(
+ 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
+ defaultClassNames.dropdowns,
+ ),
+ dropdown_root: cn(
+ 'relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md',
+ defaultClassNames.dropdown_root,
+ ),
+ dropdown: cn(
+ 'absolute bg-popover inset-0 opacity-0',
+ defaultClassNames.dropdown,
+ ),
+ caption_label: cn(
+ 'select-none font-medium',
+ captionLayout === 'label'
+ ? 'text-sm'
+ : 'rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5',
+ defaultClassNames.caption_label,
+ ),
+ table: 'w-full border-collapse',
+ weekdays: cn('flex', defaultClassNames.weekdays),
+ weekday: cn(
+ 'text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none',
+ defaultClassNames.weekday,
+ ),
+ week: cn('flex w-full mt-2', defaultClassNames.week),
+ week_number_header: cn(
+ 'select-none w-(--cell-size)',
+ defaultClassNames.week_number_header,
+ ),
+ week_number: cn(
+ 'text-[0.8rem] select-none text-muted-foreground',
+ defaultClassNames.week_number,
+ ),
+ day: cn(
+ 'relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none',
+ defaultClassNames.day,
+ ),
+ range_start: cn(
+ 'rounded-l-md bg-accent',
+ defaultClassNames.range_start,
+ ),
+ range_middle: cn('rounded-none', defaultClassNames.range_middle),
+ range_end: cn('rounded-r-md bg-accent', defaultClassNames.range_end),
+ today: cn(
+ 'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
+ defaultClassNames.today,
+ ),
+ outside: cn(
+ 'text-muted-foreground aria-selected:text-muted-foreground',
+ defaultClassNames.outside,
+ ),
+ disabled: cn(
+ 'text-muted-foreground opacity-50',
+ defaultClassNames.disabled,
+ ),
+ hidden: cn('invisible', defaultClassNames.hidden),
+ ...classNames,
+ }}
+ components={{
+ Root: ({ className, rootRef, ...props }) => {
+ return (
+
+ )
+ },
+ Chevron: ({ className, orientation, ...props }) => {
+ if (orientation === 'left') {
+ return (
+
+ )
+ }
+
+ if (orientation === 'right') {
+ return (
+
+ )
+ }
+
+ return (
+
+ )
+ },
+ DayButton: CalendarDayButton,
+ WeekNumber: ({ children, ...props }) => {
+ return (
+
+
+ {children}
+
+ |
+ )
+ },
+ ...components,
+ }}
+ {...props}
+ />
+ )
+}
+
+function CalendarDayButton({
+ className,
+ day,
+ modifiers,
+ ...props
+}: React.ComponentProps) {
+ const defaultClassNames = getDefaultClassNames()
+
+ const ref = React.useRef(null)
+ React.useEffect(() => {
+ if (modifiers.focused) ref.current?.focus()
+ }, [modifiers.focused])
+
+ return (
+