-
-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: add hero ui theme builder #5903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: canary
Are you sure you want to change the base?
Conversation
|
|
@alimortazavi-pr is attempting to deploy a commit to the HeroUI Inc Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis PR introduces a new theme-builder CLI tool within the theme-builder directory. The tool includes utility modules for generating color shades from hex values and transforming light themes to dark themes, an interactive CLI script for collecting theme configuration, and project metadata. The theme builder generates light and dark theme JSON files based on user-provided colors. Changes
Sequence DiagramsequenceDiagram
participant User
participant CLI as index.js
participant FG as formatterAndGenerator
participant Shades as shadesOf
participant Dark as darkGenerator
participant FS as File System
User->>CLI: Run theme-builder
CLI->>User: Prompt for theme name & colors
User->>CLI: Provide hex values
CLI->>FG: Call with collected colors
FG->>Shades: shadesOf(primaryColor)
Shades-->>FG: Color shade object
FG->>Dark: darkGenerator(shades)
Dark-->>FG: Inverted dark theme
FG->>Shades: shadesOf(secondaryColor)
Shades-->>FG: Color shade object
FG->>Dark: darkGenerator(shades)
Dark-->>FG: Inverted dark theme
Note over FG: Repeat for success, warning, danger, default colors
FG-->>CLI: {light: {...}, dark: {...}}
CLI->>FS: Write <theme>-light.json
CLI->>FS: Write <theme>-dark.json
FS-->>User: Theme files created
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example:
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (6)
theme-builder/readme.md (1)
7-17: Clarify execution steps and validation behavior.The documentation doesn't explain that the tool validates required inputs (loops until non-empty). Consider adding:
- Clear command:
npm startfrom the theme-builder directory- Input validation behavior (required fields can't be empty)
- Expected HEX color format with # prefix
- Location where output files are created
theme-builder/index.js (1)
5-5: Remove async keyword from main function.Since
formatterAndGeneratoris not async, themainfunction doesn't need to be async either.-async function main() { +function main() {theme-builder/package.json (1)
1-25: Add repository and issue tracking fields.The package.json is missing standard fields for a published package:
repository- Where the source code livesbugs- Where to report issueshomepage- Project homepage/docsAdd these fields after line 5:
"repository": { "type": "git", "url": "https://github.com/heroui-inc/heroui.git", "directory": "theme-builder" }, "bugs": { "url": "https://github.com/heroui-inc/heroui/issues" }, "homepage": "https://github.com/heroui-inc/heroui/tree/canary/theme-builder#readme",theme-builder/dark-gen.js (1)
1-13: Document the shade inversion logic.The keyChecker mapping inverts light/dark shade indices (light 50 → dark 950, etc.), but there's no explanation of why or how this works with Hero UI's theming system.
Add a comment:
// Maps light theme shade keys to their dark theme equivalents // Light shades get inverted: lightest (50) becomes darkest (950), etc. // This ensures proper contrast when switching between light and dark modes const keyChecker = {theme-builder/shades-gen.js (1)
1-29: Add JSDoc documentation.The shade generation logic is complex and would benefit from documentation explaining:
- The 11 shade values and their purpose
- How the interpolation works for light vs dark shades
- Expected input format
/** * Generates a palette of 11 shades from a base hex color. * @param {string} hex - Base color in hex format (e.g., "#3b82f6" or "3b82f6") * @returns {Object} Object with keys 50-950 containing interpolated hex colors * - Shade 500 is the base color * - Shades 50-400 interpolate from base to white (lighter) * - Shades 600-950 interpolate from black to base (darker) */ function shadesOf(hex) {theme-builder/formatter-and-generator.js (1)
12-64: Consider reducing code duplication.The light and dark theme generation repeats the same structure for 6 color categories. This could be refactored to be more maintainable.
function formatterAndGenerator({ defaultColor, primaryColor, secondaryColor, successColor, warningColor, dangerColor }) { const colorMap = { default: defaultColor, primary: primaryColor, secondary: secondaryColor, success: successColor, warning: warningColor, danger: dangerColor, }; const lightColors = {}; const darkColors = {}; for (const [name, color] of Object.entries(colorMap)) { const shades = shadesOf(color); lightColors[name] = { DEFAULT: color, ...shades }; darkColors[name] = { DEFAULT: color, ...darkGenerator(shades) }; } return { light: lightColors, dark: darkColors }; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
theme-builder/.gitignore(1 hunks)theme-builder/dark-gen.js(1 hunks)theme-builder/formatter-and-generator.js(1 hunks)theme-builder/index.js(1 hunks)theme-builder/package.json(1 hunks)theme-builder/readme.md(1 hunks)theme-builder/shades-gen.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
theme-builder/shades-gen.js (1)
theme-builder/formatter-and-generator.js (1)
shadesOf(1-1)
theme-builder/dark-gen.js (1)
theme-builder/formatter-and-generator.js (1)
darkGenerator(2-2)
theme-builder/formatter-and-generator.js (1)
theme-builder/index.js (1)
formatterAndGenerator(3-3)
🪛 markdownlint-cli2 (0.18.1)
theme-builder/readme.md
3-3: Bare URL used
(MD034, no-bare-urls)
🔇 Additional comments (4)
theme-builder/.gitignore (1)
1-1: LGTM!The gitignore entry correctly excludes node_modules from version control.
theme-builder/formatter-and-generator.js (1)
4-70: Function signature is synchronous, not async.This function is not declared as
async, yetindex.jsawaits it. While this works (non-async functions can be awaited), it's misleading. The issue is flagged in index.js but noted here for context.theme-builder/package.json (1)
26-30: Dependencies verified—no security issues found.Both
prompt-sync@^4.2.0andnodemon@^3.0.1are valid versions with no known security vulnerabilities. Theprompt-syncversion matches the latest release, and thenodemonversion constraint allows up to the latest 3.x release.theme-builder/shades-gen.js (1)
18-25: The shade interpolation logic is correct—review concern is based on a misunderstanding.The
getColor()function uses standard linear interpolation:result = end + percentage * (start - end), where higher percentages move the result toward thestartvalue.For dark shades (600–950):
startColor= black,endColor= baseColor- Shade 600: percentage = 0.2 → 80% baseColor + 20% black (lighter dark)
- Shade 950: percentage = 0.9 → 10% baseColor + 90% black (darkest) ✓
For light shades (50–400):
startColor= baseColor,endColor= white- Shade 50: percentage = 0.1 → 90% white + 10% baseColor (lightest)
- Shade 400: percentage = 0.8 → 20% white + 80% baseColor (lighter but darker than 50) ✓
The progression correctly produces shade 950 as the darkest and shade 50 as the lightest, matching Hero UI's expected color scale.
| function darkGenerator(light) { | ||
| let dark = {}; | ||
| Object.entries(light).forEach(([key, value]) => { | ||
| dark[keyChecker[key]] = value; | ||
| }); | ||
| return dark; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation and handle undefined keys.
The function has no safeguards:
- No input validation - Doesn't check if
lightis an object or has expected keys - Silent undefined assignment - If
lightcontains keys not inkeyChecker(like "DEFAULT"),dark[undefined] = valueoccurs, which is a bug
Apply this diff:
function darkGenerator(light) {
+ if (!light || typeof light !== 'object') {
+ throw new Error('darkGenerator expects an object');
+ }
let dark = {};
Object.entries(light).forEach(([key, value]) => {
+ // Skip non-numeric keys like "DEFAULT"
+ if (!(key in keyChecker)) {
+ dark[key] = value;
+ return;
+ }
dark[keyChecker[key]] = value;
});
return dark;
}📝 Committable suggestion
‼️ 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.
| function darkGenerator(light) { | |
| let dark = {}; | |
| Object.entries(light).forEach(([key, value]) => { | |
| dark[keyChecker[key]] = value; | |
| }); | |
| return dark; | |
| } | |
| function darkGenerator(light) { | |
| if (!light || typeof light !== 'object') { | |
| throw new Error('darkGenerator expects an object'); | |
| } | |
| let dark = {}; | |
| Object.entries(light).forEach(([key, value]) => { | |
| // Skip non-numeric keys like "DEFAULT" | |
| if (!(key in keyChecker)) { | |
| dark[key] = value; | |
| return; | |
| } | |
| dark[keyChecker[key]] = value; | |
| }); | |
| return dark; | |
| } |
🤖 Prompt for AI Agents
In theme-builder/dark-gen.js around lines 14 to 20, the darkGenerator lacks
input validation and can assign to undefined when a light key is not present in
keyChecker; validate that the input light is a non-null object (throw or return
an empty object for invalid input), iterate Object.entries only after that
check, and for each [key,value] ensure keyChecker has that key (use
Object.prototype.hasOwnProperty.call(keyChecker,key) or key in keyChecker)
before assigning to dark[keyChecker[key]]; skip unknown keys (or log/warn) so
you never set dark[undefined], and preserve existing behavior for valid
mappings.
| function formatterAndGenerator({ | ||
| defaultColor, | ||
| primaryColor, | ||
| secondaryColor, | ||
| successColor, | ||
| warningColor, | ||
| dangerColor, | ||
| }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation for color parameters.
The function doesn't validate that the color inputs are valid hex strings before passing them to shadesOf, which will throw errors for invalid inputs.
Add validation at the start of the function:
function formatterAndGenerator({
defaultColor,
primaryColor,
secondaryColor,
successColor,
warningColor,
dangerColor,
}) {
// Validate all colors are provided
const colors = { defaultColor, primaryColor, secondaryColor, successColor, warningColor, dangerColor };
for (const [name, value] of Object.entries(colors)) {
if (!value || typeof value !== 'string') {
throw new Error(`${name} is required and must be a string`);
}
}🤖 Prompt for AI Agents
In theme-builder/formatter-and-generator.js around lines 4 to 11, the function
accepts color params but does not validate them before calling shadesOf, so
invalid values will throw; add input validation at the start that collects all
color params into an object, ensures each is present and a string, and validates
each against a hex color regex (accepting #RGB or #RRGGBB); for any
missing/invalid value throw a descriptive Error like "<name> is required and
must be a valid hex color (e.g. #RRGGBB)" so callers get clear feedback instead
of shields failing inside shadesOf.
| let themeNameInput = prompt("Enter theme name: "); | ||
| while (!themeNameInput) { | ||
| themeNameInput = prompt("Enter theme name: "); | ||
| } | ||
|
|
||
| let defaultColorInput = prompt("Enter default colors: "); | ||
| while (!defaultColorInput) { | ||
| defaultColorInput = prompt("Enter default colors: "); | ||
| } | ||
|
|
||
| let primaryColorInput = prompt("Enter primary HEX: "); | ||
| while (!primaryColorInput) { | ||
| primaryColorInput = prompt("Enter primary HEX: "); | ||
| } | ||
|
|
||
| let secondaryColorInput = prompt("Enter secondary HEX: "); | ||
| while (!secondaryColorInput) { | ||
| secondaryColorInput = prompt("Enter secondary HEX: "); | ||
| } | ||
|
|
||
| let successColorInput = prompt("Enter success HEX: "); | ||
| while (!successColorInput) { | ||
| successColorInput = prompt("Enter success HEX: "); | ||
| } | ||
|
|
||
| let warningColorInput = prompt("Enter warning HEX: "); | ||
| while (!warningColorInput) { | ||
| warningColorInput = prompt("Enter warning HEX: "); | ||
| } | ||
|
|
||
| let dangerColorInput = prompt("Enter danger HEX: "); | ||
| while (!dangerColorInput) { | ||
| dangerColorInput = prompt("Enter danger HEX: "); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation and reduce code duplication.
The input collection has several issues:
- No HEX color validation - The tool accepts any string for color inputs, which will cause errors downstream when shadesOf attempts to parse invalid hex values.
- Code duplication - Seven nearly-identical validation loops.
- No input trimming - Whitespace in inputs could cause issues.
- Confusing prompt - Line 11 says "default colors" (plural) but expects a single hex value.
Consider refactoring with a helper function:
function promptWithValidation(message, validator) {
let input;
while (true) {
input = prompt(message).trim();
if (!input) {
console.log("This field is required.");
continue;
}
if (validator && !validator(input)) {
console.log("Invalid input format.");
continue;
}
return input;
}
}
function isValidHex(value) {
return /^#?[0-9A-Fa-f]{6}$|^#?[0-9A-Fa-f]{3}$/.test(value);
}
// Usage:
const themeNameInput = promptWithValidation("Enter theme name: ");
const defaultColorInput = promptWithValidation("Enter default HEX color: ", isValidHex);
const primaryColorInput = promptWithValidation("Enter primary HEX: ", isValidHex);
// ... etc🤖 Prompt for AI Agents
In theme-builder/index.js around lines 6 to 39, the input collection loops are
duplicated, do not trim inputs, mislabel the default color prompt, and accept
invalid hex values; refactor by extracting a helper like
promptWithValidation(message, validator) that trims input, requires non-empty
responses, and uses a hex validator for color fields, update prompt text to
"Enter default HEX color:" and apply the helper to themeName (no validator) and
all color fields (use isValidHex that accepts 3- or 6-digit hex with optional
leading #), and replace the repeated while-loops with calls to this helper to
reduce duplication and ensure proper validation.
| const result = await formatterAndGenerator({ | ||
| defaultColor: defaultColorInput, | ||
| primaryColor: primaryColorInput, | ||
| secondaryColor: secondaryColorInput, | ||
| successColor: successColorInput, | ||
| warningColor: warningColorInput, | ||
| dangerColor: dangerColorInput, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unnecessary await.
The formatterAndGenerator function is not async (as seen in formatter-and-generator.js), so awaiting it is unnecessary and misleading.
Apply this diff:
- const result = await formatterAndGenerator({
+ const result = formatterAndGenerator({
defaultColor: defaultColorInput,
primaryColor: primaryColorInput,
secondaryColor: secondaryColorInput,
successColor: successColorInput,
warningColor: warningColorInput,
dangerColor: dangerColorInput,
});📝 Committable suggestion
‼️ 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.
| const result = await formatterAndGenerator({ | |
| defaultColor: defaultColorInput, | |
| primaryColor: primaryColorInput, | |
| secondaryColor: secondaryColorInput, | |
| successColor: successColorInput, | |
| warningColor: warningColorInput, | |
| dangerColor: dangerColorInput, | |
| }); | |
| const result = formatterAndGenerator({ | |
| defaultColor: defaultColorInput, | |
| primaryColor: primaryColorInput, | |
| secondaryColor: secondaryColorInput, | |
| successColor: successColorInput, | |
| warningColor: warningColorInput, | |
| dangerColor: dangerColorInput, | |
| }); |
🤖 Prompt for AI Agents
In theme-builder/index.js around lines 41 to 48, the code uses "await" when
calling formatterAndGenerator even though that function is synchronous; remove
the unnecessary await and call formatterAndGenerator directly (assign its return
value to result without awaiting) so the call reflects the actual synchronous
behavior and eliminates misleading async usage.
| fs.writeFileSync( | ||
| `${themeNameInput}-light.json`, | ||
| JSON.stringify({ light: result.light }) | ||
| ); | ||
| fs.writeFileSync( | ||
| `${themeNameInput}-dark.json`, | ||
| JSON.stringify({ dark: result.dark }) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling, formatting, and user feedback.
The file write operations have several issues:
- No error handling -
fs.writeFileSynccan throw (permission errors, disk full, etc.) - Poor formatting - JSON output lacks indentation, making it hard to read
- No user feedback - Users don't know if files were created successfully
- Blocking I/O - Synchronous file operations in an async function
Apply this diff:
+ try {
fs.writeFileSync(
`${themeNameInput}-light.json`,
- JSON.stringify({ light: result.light })
+ JSON.stringify({ light: result.light }, null, 2)
);
fs.writeFileSync(
`${themeNameInput}-dark.json`,
- JSON.stringify({ dark: result.dark })
+ JSON.stringify({ dark: result.dark }, null, 2)
);
+ console.log(`\n✓ Theme files created successfully:`);
+ console.log(` - ${themeNameInput}-light.json`);
+ console.log(` - ${themeNameInput}-dark.json`);
+ } catch (error) {
+ console.error(`\n✗ Error writing theme files: ${error.message}`);
+ process.exit(1);
+ }📝 Committable suggestion
‼️ 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.
| fs.writeFileSync( | |
| `${themeNameInput}-light.json`, | |
| JSON.stringify({ light: result.light }) | |
| ); | |
| fs.writeFileSync( | |
| `${themeNameInput}-dark.json`, | |
| JSON.stringify({ dark: result.dark }) | |
| ); | |
| try { | |
| fs.writeFileSync( | |
| `${themeNameInput}-light.json`, | |
| JSON.stringify({ light: result.light }, null, 2) | |
| ); | |
| fs.writeFileSync( | |
| `${themeNameInput}-dark.json`, | |
| JSON.stringify({ dark: result.dark }, null, 2) | |
| ); | |
| console.log(`\n✓ Theme files created successfully:`); | |
| console.log(` - ${themeNameInput}-light.json`); | |
| console.log(` - ${themeNameInput}-dark.json`); | |
| } catch (error) { | |
| console.error(`\n✗ Error writing theme files: ${error.message}`); | |
| process.exit(1); | |
| } |
🤖 Prompt for AI Agents
In theme-builder/index.js around lines 50 to 57, the synchronous
fs.writeFileSync calls should be replaced with asynchronous, non-blocking writes
using fs.promises.writeFile inside a try/catch; format JSON with indentation
(e.g., JSON.stringify(obj, null, 2)) before writing, wrap both write operations
in await calls (or Promise.all) to avoid blocking, and on success emit user
feedback (console.log or process.stdout.write) indicating file paths written; on
error catch and log the full error (including error.message), and either rethrow
or exit with a non-zero code so failures are visible to the caller.
| Clone your repo: git clone https://github.com/alimortazavi-pr/nextui-theme-builder.git | ||
| cd into folder. | ||
| npm install (adds prompt-sync for inputs; I skipped nodemon for now—dev it raw). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix repository reference and markdown formatting.
The repository URL references "nextui-theme-builder" but this PR is for "heroui". Additionally, the bare URL should be formatted as a proper markdown link.
Apply this diff:
-Clone your repo: git clone https://github.com/alimortazavi-pr/nextui-theme-builder.git
+Clone your repo: `git clone https://github.com/heroui-inc/heroui.git`
cd into folder.
-npm install (adds prompt-sync for inputs; I skipped nodemon for now—dev it raw).
+Run `npm install` in the theme-builder directory to install dependencies (prompt-sync for interactive inputs).📝 Committable suggestion
‼️ 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.
| Clone your repo: git clone https://github.com/alimortazavi-pr/nextui-theme-builder.git | |
| cd into folder. | |
| npm install (adds prompt-sync for inputs; I skipped nodemon for now—dev it raw). | |
| Clone your repo: `git clone https://github.com/heroui-inc/heroui.git` | |
| cd into folder. | |
| Run `npm install` in the theme-builder directory to install dependencies (prompt-sync for interactive inputs). |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
3-3: Bare URL used
(MD034, no-bare-urls)
🤖 Prompt for AI Agents
In theme-builder/readme.md around lines 3 to 5, update the repository reference
from "nextui-theme-builder" to "heroui" and convert the bare clone URL into a
proper Markdown link; replace the raw URL with a markdown link to
https://github.com/alimortazavi-pr/heroui and keep the accompanying instructions
(cd into folder, npm install) unchanged, optionally wrapping the shell commands
in inline code formatting for clarity.
| function hexToRgbArray(hex) { | ||
| const originalHex = hex; | ||
|
|
||
| hex = hex.replace("#", ""); | ||
| if (hex.length === 3) hex = hex + hex; | ||
|
|
||
| const r = hex.substring(0, 2); | ||
| const g = hex.substring(2, 4); | ||
| const b = hex.substring(4, 6); | ||
|
|
||
| const rgb = [r, g, b].map((channel) => { | ||
| try { | ||
| channel = parseInt(channel, 16); | ||
| if (channel < 0 || channel > 255) throw new Error(); | ||
| return channel; | ||
| } catch { | ||
| throw new Error(`Invalid hex color provided: ${originalHex}`); | ||
| } | ||
| }); | ||
|
|
||
| return rgb; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix critical bug in hex color expansion.
Line 35 has a logic error: hex = hex + hex for a 3-character hex like "abc" produces "abcabc" (6 chars but wrong), when it should produce "aabbcc".
Apply this diff:
hex = hex.replace("#", "");
- if (hex.length === 3) hex = hex + hex;
+ if (hex.length === 3) {
+ hex = hex.split('').map(c => c + c).join('');
+ }
+
+ if (hex.length !== 6) {
+ throw new Error(`Invalid hex color provided: ${originalHex}`);
+ }🤖 Prompt for AI Agents
theme-builder/shades-gen.js around lines 31 to 52, the 3-character hex expansion
uses `hex = hex + hex` which transforms "abc" into "abcabc" instead of "aabbcc";
replace that line with logic that expands each of the three characters by
repeating it (e.g., map each char to char+char and join) so 3-char inputs become
6-char RRGGBB strings before parsing, leaving the rest of hexToRgbArray
unchanged and preserving error handling.
Closes #
📝 Description
Add interactive CLI tool for theme generation with user prompts for color customization.
This PR introduces a command-line interface that allows users to generate custom light and dark theme files for Hero UI by interactively entering color values through prompts.
⛳️ Current behavior (updates)
Currently, users need to manually create theme configuration files or use existing themes without an easy way to generate custom themes with their preferred color schemes.
🚀 New behavior
prompt-syncthat:{themeName}-light.jsonand{themeName}-dark.jsonUsers can now run the script and easily create custom themes by answering a series of prompts, making theme generation much more accessible.
💣 Is this a breaking change (Yes/No):
No
This is a new feature that adds functionality without modifying existing code or APIs. Existing Hero UI users are not affected.
📝 Additional Information
prompt-syncfor CLI input handlingformatter-and-generatormoduleSummary by CodeRabbit
New Features
Documentation
Chores