feat: Add changelog-generator AgentKit #86
Conversation
WalkthroughAdds a new Next.js kit "changelog-generator" with UI components, styling, TypeScript/ESLint/PostCSS/Next configs, Lamatic orchestration for Groq LLaMA-based changelog generation, documentation, and project metadata. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Browser as Browser Page
participant Server as Next.js Server
participant Lamatic as Lamatic API
participant Groq as Groq LLaMA
User->>Browser: Enter repo URL and date range
User->>Browser: Submit form
Browser->>Server: POST /generateChangelog (repoUrl, dateFrom, dateTo)
Server->>Lamatic: executeFlow(inputs)
alt Lamatic returns requestId (async)
Lamatic-->>Server: { requestId }
loop poll
Server->>Lamatic: checkStatus(requestId)
Lamatic-->>Server: status / partial result
end
else Lamatic returns result (sync)
Lamatic-->>Server: { result payload }
end
Lamatic->>Groq: run Groq LLaMA text generation (internal)
Groq-->>Lamatic: generated changelog content
Server-->>Browser: return markdown changelog
Browser->>Browser: render markdown / copy to clipboard
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (1)
kits/automation/changelog-generator/components/ui/select.tsx (1)
78-86: Remove dead code in Viewport className.Line 82 contains
position === "popper" && ""which is a no-op—it adds an empty string when the condition is true, having no effect on the rendered output. This appears to be leftover placeholder code.🧹 Proposed cleanup
<SelectPrimitive.Viewport data-position={position} - className={cn( - "data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)", - position === "popper" && "" - )} + className="data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)" >
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5f1065c4-d11a-4669-9ad4-83277942160b
⛔ Files ignored due to path filters (7)
kits/automation/changelog-generator/app/favicon.icois excluded by!**/*.icokits/automation/changelog-generator/package-lock.jsonis excluded by!**/package-lock.jsonkits/automation/changelog-generator/public/file.svgis excluded by!**/*.svgkits/automation/changelog-generator/public/globe.svgis excluded by!**/*.svgkits/automation/changelog-generator/public/next.svgis excluded by!**/*.svgkits/automation/changelog-generator/public/vercel.svgis excluded by!**/*.svgkits/automation/changelog-generator/public/window.svgis excluded by!**/*.svg
📒 Files selected for processing (18)
kits/automation/changelog-generator/.gitignorekits/automation/changelog-generator/README.mdkits/automation/changelog-generator/actions/orchestrate.tskits/automation/changelog-generator/app/globals.csskits/automation/changelog-generator/app/layout.tsxkits/automation/changelog-generator/app/page.tsxkits/automation/changelog-generator/components.jsonkits/automation/changelog-generator/components/ui/button.tsxkits/automation/changelog-generator/components/ui/card.tsxkits/automation/changelog-generator/components/ui/select.tsxkits/automation/changelog-generator/components/ui/textarea.tsxkits/automation/changelog-generator/config.jsonkits/automation/changelog-generator/eslint.config.mjskits/automation/changelog-generator/lib/utils.tskits/automation/changelog-generator/next.config.tskits/automation/changelog-generator/package.jsonkits/automation/changelog-generator/postcss.config.mjskits/automation/changelog-generator/tsconfig.json
| ``` | ||
| changelog-generator/ | ||
| ├── app/ | ||
| │ └── page.tsx # Main UI | ||
| ├── actions/ | ||
| │ └── orchestrate.ts # Lamatic Flow API call | ||
| ├── flows/ | ||
| │ └── changelog-flow/ # Exported Lamatic flow files | ||
| ├── .env.example # Environment variables template | ||
| ├── config.json # Kit metadata | ||
| └── README.md | ||
| ``` |
There was a problem hiding this comment.
Add a language to the fenced structure block.
This block is currently tripping the markdownlint warning that was attached to the review. text is enough here.
📝 Suggested doc fix
-```
+```text
changelog-generator/
├── app/
│ └── page.tsx # Main UI
@@
├── config.json # Kit metadata
└── README.md</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 83-83: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
kits/automation/changelog-generator/.env.example (1)
1-4: Add a trailing newline for POSIX compliance.Most text editors and POSIX tools expect files to end with a newline character.
📝 Suggested fix
LAMATIC_PROJECT_ENDPOINT=YOUR_API_ENDPOINT LAMATIC_FLOW_ID=YOUR_FLOW_ID LAMATIC_PROJECT_ID=YOUR_PROJECT_ID -LAMATIC_PROJECT_API_KEY=YOUR_API_KEY +LAMATIC_PROJECT_API_KEY=YOUR_API_KEY +kits/automation/changelog-generator/app/page.tsx (2)
126-139: Consider usinglucide-reacticons instead of inline SVGs.As per coding guidelines, kits should use
lucide-reactfor icons. The inline SVGs for the spinner, lightning bolt, checkmark, clipboard, and document icons could be replaced with their lucide equivalents (e.g.,Loader2,Zap,Check,Copy,FileText).♻️ Example replacement for the submit button icons
+"use client"; + +import { useState } from "react"; +import { generateChangelog } from "@/actions/orchestrate"; +import ReactMarkdown from "react-markdown"; +import { Loader2, Zap, Check, Copy, FileText } from "lucide-react"; ... <button type="submit" disabled={isLoading} className="..."> {isLoading ? ( <> - <svg className="animate-spin w-4 h-4" viewBox="0 0 24 24" fill="none"> - <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> - <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z" /> - </svg> + <Loader2 className="animate-spin w-4 h-4" /> Generating... </> ) : ( <> - <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> - <path strokeLinecap="round" strokeLinejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" /> - </svg> + <Zap className="w-4 h-4" /> Generate Changelog </> )} </button>As per coding guidelines: "Use lucide-react for icons throughout kits".
35-41: Consider handling clipboard API failures.
navigator.clipboard.writeText()can fail in non-secure contexts or when permissions are denied. Wrapping it in a try-catch would prevent silent failures.🛡️ Suggested fix
const handleCopy = () => { if (result) { - navigator.clipboard.writeText(result); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + navigator.clipboard.writeText(result) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) + .catch(() => { + setError("Failed to copy to clipboard"); + }); } };kits/automation/changelog-generator/actions/orchestrate.ts (1)
5-16: Consider lazy initialization to improve error diagnostics.The Lamatic client is created at module load time (line 16). If env vars are missing, the error is thrown during server startup rather than when the action is invoked, which can make debugging harder in serverless environments.
♻️ Lazy initialization pattern
-const lamaticClient = createLamaticClient(); +let lamaticClient: Lamatic | null = null; + +function getLamaticClient() { + if (!lamaticClient) { + lamaticClient = createLamaticClient(); + } + return lamaticClient; +} export async function generateChangelog({ ... }: ChangelogInput): Promise<string> { ... - const response = await lamaticClient.executeFlow(flowId, { + const response = await getLamaticClient().executeFlow(flowId, {
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d444bb34-e03b-4eff-bf85-1a4918bb5ace
📒 Files selected for processing (7)
kits/automation/changelog-generator/.env.examplekits/automation/changelog-generator/.gitignorekits/automation/changelog-generator/README.mdkits/automation/changelog-generator/actions/orchestrate.tskits/automation/changelog-generator/app/globals.csskits/automation/changelog-generator/app/layout.tsxkits/automation/changelog-generator/app/page.tsx
✅ Files skipped from review due to trivial changes (1)
- kits/automation/changelog-generator/.gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
- kits/automation/changelog-generator/app/layout.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
kits/automation/changelog-generator/actions/orchestrate.ts (1)
52-57: Consider adding fallbacks forrequestIdextraction.Other kits (e.g.,
embed/sheets) use a fallback chain likeresponse?.result?.requestId || response?.requestId || response?.idto handle API response variations. If Lamatic's response structure can vary, a single-point extraction may miss valid async responses.♻️ Optional improvement
// Handle async flow (returns requestId) - if (response?.result?.requestId) { + const requestId = response?.result?.requestId || response?.requestId; + if (requestId) { const finalResult = await lamaticClient.checkStatus( - response.result.requestId, + requestId, 5, 120 ) as any;
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f24cf9f9-b8c8-4a4a-b0e6-c54d651ea1c5
📒 Files selected for processing (2)
kits/automation/changelog-generator/README.mdkits/automation/changelog-generator/actions/orchestrate.ts
| const parsedRepoUrl = new URL(repoUrl); | ||
| const [owner, repo] = parsedRepoUrl.pathname.split("/").filter(Boolean); | ||
| if (parsedRepoUrl.hostname !== "github.com" || !owner || !repo) { | ||
| throw new Error("repoUrl must be a valid GitHub repository URL"); | ||
| } |
There was a problem hiding this comment.
Wrap URL parsing in try-catch to return a friendly error.
new URL(repoUrl) throws a TypeError if repoUrl is not a valid URL. This surfaces as an opaque server error instead of the descriptive message on line 32.
🛡️ Suggested fix
- const parsedRepoUrl = new URL(repoUrl);
- const [owner, repo] = parsedRepoUrl.pathname.split("/").filter(Boolean);
- if (parsedRepoUrl.hostname !== "github.com" || !owner || !repo) {
+ let parsedRepoUrl: URL;
+ try {
+ parsedRepoUrl = new URL(repoUrl);
+ } catch {
+ throw new Error("repoUrl must be a valid GitHub repository URL");
+ }
+ const [owner, repo] = parsedRepoUrl.pathname.split("/").filter(Boolean);
+ if (parsedRepoUrl.hostname !== "github.com" || !owner || !repo) {
throw new Error("repoUrl must be a valid GitHub repository URL");
}
What This Kit Does
An AI-powered changelog generator that takes a GitHub repository URL and a date range, then produces a professional, well-structured changelog in seconds.
Providers & Prerequisites
How to Run Locally
cd kits/automation/changelog-generatornpm installcp .env.example .env.localand fill in valuesnpm run devLive Preview
https://agent-kit-sable.vercel.app/
Lamatic Flow
Flow ID:
4c3801ea-0353-4678-afc1-db47efd231eaChecklist
npm run dev.env.examplehas no secrets, only placeholdersREADME.mddocuments setup and usagekits/automation/changelog-generator/config.jsonis present and validcnutility.