Skip to content

Conversation

@truehazker
Copy link
Owner

@truehazker truehazker commented Jan 4, 2026

Summary by CodeRabbit

  • Documentation

    • Updated README with badges, refreshed Quick Start (demo image), reorganized “What’s Included”, and added Contributing/Git guidance
  • New Features

    • Optional Git initialization during project creation
    • Improved quick-start CLI examples and clearer next-steps messaging
    • Automatic template provisioning and dependency installation as part of setup
    • Project name validation with clearer error feedback
  • Refactor

    • Major internal reorganization for a simpler, more maintainable user flow

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Refactors the CLI scaffold into focused modules: constants, utils, template setup, and git initialization; reduces main orchestration to lightweight helpers; updates README and CHANGELOG with new documentation and badges. (50 words)

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md, README.md
CHANGELOG documents the refactor. README adds badges, a Quick Start/demo, revised CLI examples (bun create ely), reorganized "What's Included" (Backend/Monorepo), and updated Contributing guidance.
Constants
src/constants.ts
New exported constants: TEMPLATE_TYPES, DEFAULT_PROJECT_NAME, PROJECT_NAME_REGEX, EXCLUDED_COPY_PATTERNS, PORTS, TEMPLATE_PATHS (all typed, some as const).
Utilities
src/utils.ts
New helpers: copyRecursive(src, dest, exclude = []) (recursive copy, excludes patterns and .template files) and validateProjectName(value) (npm-style name validation returning error string or undefined).
Template Setup
src/template.ts
New setupTemplate(projectType, targetDir) that resolves template paths, uses copyRecursive, handles monorepo backend biome copying, runs bun install in target dir, and reports progress via spinners/exit handling.
Git Initialization
src/git.ts
New initializeGit(targetDir) that prompts user, checks Git availability, runs git init / git add . / git commit -m "Initial commit", and handles cancellation or missing Git gracefully.
Main Orchestration
src/index.ts
Main reduced in size; introduces getProjectName, handleExistingDirectory, getNextStepsMessage; delegates template setup and git init to new modules; centralizes validation and cancellation/error handling.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as CLI
  participant Main as index.ts
  participant Template as template.ts
  participant FS as Filesystem
  participant Bun as bun
  participant Git as git

  CLI->>Main: start create command (choose template, name)
  Main->>Template: setupTemplate(projectType, targetDir)
  Template->>FS: copyRecursive(templatePath → targetDir)
  alt monorepo template
    Template->>FS: copy backend biome to target path
  end
  Template->>Bun: run "bun install" in targetDir
  Bun-->>Template: exit code (success/fail)
  Template-->>Main: setup complete / error
  Main->>Git: initializeGit(targetDir)
  Git->>Git: check git availability
  Git->>FS: git init / git add .
  Git->>Git: git commit -m "Initial commit"
  Git-->>Main: git initialized / skipped
  Main-->>User: print next-steps message
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through modules, neat and spry,
Constants planted where patterns lie,
Templates copied, dependencies spun,
Git got a ribbon — initial commit done,
A joyful scaffold — off we run! 🚀

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title partially describes the changeset by mentioning README enhancement and CLI refactoring, but omits significant changes like new module extraction (constants.ts, git.ts, template.ts, utils.ts) and code organization improvements that represent the main substance of the refactor.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6dbb65 and cdb9f55.

📒 Files selected for processing (1)
  • README.md

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
src/git.ts (1)

89-94: Consider logging the caught error for debugging.

The catch block suppresses error details, which could make troubleshooting difficult for users. Consider logging the error before showing the warning.

🔎 Proposed improvement
-  } catch {
+  } catch (error) {
     gitSpinner.stop('Git initialization failed');
+    console.error('Error details:', error);
     clack.log.warn(
       'An error occurred during git initialization. You can initialize manually later.',
     );
src/utils.ts (2)

16-42: Add error handling for filesystem operations.

The function doesn't handle errors from statSync, mkdirSync, or copyFileSync. If these operations fail (e.g., permission denied, disk full), the error will propagate as an unhandled exception with a potentially cryptic message.

🔎 Proposed improvement
 export function copyRecursive(
   src: string,
   dest: string,
   exclude: string[] = [],
 ): void {
+  try {
     const stats = statSync(src);
 
     if (stats.isDirectory()) {
       if (!existsSync(dest)) {
         mkdirSync(dest, { recursive: true });
       }
 
       for (const entry of readdirSync(src)) {
         if (exclude.includes(entry) || entry.endsWith('.template')) continue;
 
         const srcPath = join(src, entry);
         const destPath = join(dest, entry);
         copyRecursive(srcPath, destPath, exclude);
       }
     } else {
       const destDir = dirname(dest);
       if (!existsSync(destDir)) {
         mkdirSync(destDir, { recursive: true });
       }
       copyFileSync(src, dest);
     }
+  } catch (error) {
+    throw new Error(`Failed to copy ${src} to ${dest}: ${error}`);
+  }
 }

49-64: Consider extracting the regex to a constant.

The validation regex is hardcoded inline. Extracting it to a constant in src/constants.ts would improve maintainability and allow reuse if needed elsewhere.

🔎 Suggested approach

In src/constants.ts:

export const PROJECT_NAME_REGEX = /^[a-z0-9-]+$/;

Then in src/utils.ts:

+import { PROJECT_NAME_REGEX } from './constants.ts';
+
 export function validateProjectName(value: string): string | undefined {
   if (!value || value.trim() === '') {
     return 'Project name is required';
   }
 
   const trimmed = value.trim();
-  if (!/^[a-z0-9-]+$/.test(trimmed)) {
+  if (!PROJECT_NAME_REGEX.test(trimmed)) {
     return 'Project name must contain only lowercase letters, numbers, and hyphens';
   }
src/constants.ts (1)

8-8: DRY violation: Duplicate regex in validateProjectName.

The same regex pattern is hardcoded in src/utils.ts (line 54). Consider importing PROJECT_NAME_REGEX in validateProjectName to avoid drift if the pattern ever changes.

🔎 Suggested fix in src/utils.ts
+import { PROJECT_NAME_REGEX } from './constants.ts';
+
 export function validateProjectName(value: string): string | undefined {
   if (!value || value.trim() === '') {
     return 'Project name is required';
   }

   const trimmed = value.trim();
-  if (!/^[a-z0-9-]+$/.test(trimmed)) {
+  if (!PROJECT_NAME_REGEX.test(trimmed)) {
     return 'Project name must contain only lowercase letters, numbers, and hyphens';
   }
   // ...
 }
src/index.ts (1)

20-26: Consider notifying user when CLI argument is rejected.

If a user provides an invalid project name via CLI (e.g., bun create ely My-Project), the function silently falls through to the interactive prompt. Adding a warning would improve UX clarity.

🔎 Optional enhancement
 async function getProjectName(args: string[]): Promise<string> {
   const projectNameArg = args[0];

   // If project name was provided as argument and is valid, use it
   if (projectNameArg && PROJECT_NAME_REGEX.test(projectNameArg)) {
     return projectNameArg;
   }

+  if (projectNameArg) {
+    clack.log.warn(`Invalid project name "${projectNameArg}". Must contain only lowercase letters, numbers, and hyphens.`);
+  }
+
   // Otherwise, prompt for it with default value
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b54bb17 and a569a5c.

⛔ Files ignored due to path filters (1)
  • assets/demo.mp4 is excluded by !**/*.mp4
📒 Files selected for processing (7)
  • CHANGELOG.md
  • README.md
  • src/constants.ts
  • src/git.ts
  • src/index.ts
  • src/template.ts
  • src/utils.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use bun <file> instead of node <file> or ts-node <file>
Bun automatically loads .env files, so don't use the dotenv package
Use Bun.serve() with built-in WebSocket, HTTPS, and route support instead of express
Use bun:sqlite for SQLite instead of better-sqlite3
Use Bun.redis for Redis instead of ioredis
Use Bun.sql for Postgres instead of pg or postgres.js
Use built-in WebSocket instead of ws package
Prefer Bun.file over node:fs readFile/writeFile for file operations
Use Bun.$ template literals for shell commands instead of execa

Files:

  • src/utils.ts
  • src/index.ts
  • src/git.ts
  • src/constants.ts
  • src/template.ts
**/*.{ts,tsx,css,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use bun build <file.html|file.ts|file.css> instead of webpack or esbuild

Files:

  • src/utils.ts
  • src/index.ts
  • src/git.ts
  • src/constants.ts
  • src/template.ts
**/*.{html,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use HTML imports with Bun.serve() and don't use vite for frontend bundling

Files:

  • src/utils.ts
  • src/index.ts
  • src/git.ts
  • src/constants.ts
  • src/template.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use bun --hot <file.ts> to run TypeScript files with hot module reloading enabled

Files:

  • src/utils.ts
  • src/index.ts
  • src/git.ts
  • src/constants.ts
  • src/template.ts
🧠 Learnings (1)
📚 Learning: 2026-01-03T07:00:32.832Z
Learnt from: truehazker
Repo: truehazker/create-elysiajs PR: 2
File: templates/backend:1-1
Timestamp: 2026-01-03T07:00:32.832Z
Learning: In git diffs, symlinks (mode 120000) appear as added files containing the link target (e.g., +monorepo/apps/backend). Do not flag symlinks as placeholder files or accidental commits. This applies broadly; when reviewing files like templates/backend, verify whether it is a symlink and treat accordingly.

Applied to files:

  • CHANGELOG.md
  • README.md
🧬 Code graph analysis (2)
src/index.ts (4)
src/constants.ts (4)
  • PROJECT_NAME_REGEX (8-8)
  • DEFAULT_PROJECT_NAME (6-6)
  • TEMPLATE_TYPES (1-4)
  • PORTS (12-15)
src/utils.ts (1)
  • validateProjectName (49-64)
src/template.ts (1)
  • setupTemplate (17-62)
src/git.ts (1)
  • initializeGit (8-95)
src/template.ts (2)
src/utils.ts (1)
  • copyRecursive (16-42)
src/constants.ts (3)
  • EXCLUDED_COPY_PATTERNS (10-10)
  • TEMPLATE_TYPES (1-4)
  • TEMPLATE_PATHS (17-20)
🪛 GitHub Actions: Lint
src/index.ts

[error] 159-164: File content differs from formatting output. Biome formatting check detected differences in src/index.ts during 'biome ci .' run.

🔇 Additional comments (7)
CHANGELOG.md (1)

10-19: LGTM! Well-documented refactoring changes.

The changelog clearly documents the modularization work with specific details about what was extracted and the impact on code complexity.

src/template.ts (1)

17-62: LGTM! Clean template setup implementation.

The function properly uses constants, handles errors appropriately, and follows Bun best practices with Bun.spawn(). The inherited stdio ensures users see installation progress and errors directly.

src/constants.ts (1)

1-20: Well-structured constants module.

The centralization of configuration values with as const assertions provides good type safety and maintainability for the CLI scaffolding logic.

src/index.ts (4)

1-13: Clean modular imports.

Good separation of concerns with dedicated modules for constants, git operations, template setup, and utilities.


51-77: Safe directory handling with proper user confirmation.

Good defensive design: non-empty directory overwrite requires explicit confirmation with a safe default of false.


86-114: Clear success message generation.

Dynamic next steps based on project type with appropriate use of centralized constants.


116-175: Well-orchestrated main flow.

The refactored main function is clean and readable with clear step-by-step progression. Proper error handling at both function and global levels ensures graceful failure modes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a569a5c and d6dbb65.

📒 Files selected for processing (2)
  • README.md
  • src/index.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use bun <file> instead of node <file> or ts-node <file>
Bun automatically loads .env files, so don't use the dotenv package
Use Bun.serve() with built-in WebSocket, HTTPS, and route support instead of express
Use bun:sqlite for SQLite instead of better-sqlite3
Use Bun.redis for Redis instead of ioredis
Use Bun.sql for Postgres instead of pg or postgres.js
Use built-in WebSocket instead of ws package
Prefer Bun.file over node:fs readFile/writeFile for file operations
Use Bun.$ template literals for shell commands instead of execa

Files:

  • src/index.ts
**/*.{ts,tsx,css,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use bun build <file.html|file.ts|file.css> instead of webpack or esbuild

Files:

  • src/index.ts
**/*.{html,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use HTML imports with Bun.serve() and don't use vite for frontend bundling

Files:

  • src/index.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use bun --hot <file.ts> to run TypeScript files with hot module reloading enabled

Files:

  • src/index.ts
🧠 Learnings (1)
📚 Learning: 2026-01-03T07:00:32.832Z
Learnt from: truehazker
Repo: truehazker/create-elysiajs PR: 2
File: templates/backend:1-1
Timestamp: 2026-01-03T07:00:32.832Z
Learning: In git diffs, symlinks (mode 120000) appear as added files containing the link target (e.g., +monorepo/apps/backend). Do not flag symlinks as placeholder files or accidental commits. This applies broadly; when reviewing files like templates/backend, verify whether it is a symlink and treat accordingly.

Applied to files:

  • README.md
🧬 Code graph analysis (1)
src/index.ts (4)
src/constants.ts (4)
  • PROJECT_NAME_REGEX (8-8)
  • DEFAULT_PROJECT_NAME (6-6)
  • TEMPLATE_TYPES (1-4)
  • PORTS (12-15)
src/utils.ts (1)
  • validateProjectName (49-64)
src/template.ts (1)
  • setupTemplate (17-62)
src/git.ts (1)
  • initializeGit (8-95)
🔇 Additional comments (8)
README.md (4)

3-10: LGTM! Well-structured badges.

The badges provide clear project status and technology stack information using standard shields.io formats.


14-14: Previous HTML video tag issue resolved.

The demo now uses proper markdown image syntax that GitHub's renderer supports. Good fix!


16-50: LGTM! Clear and comprehensive documentation.

The Quick Start instructions and template descriptions accurately reflect the refactored CLI structure and available project types.


51-55: LGTM! Important submodule warning.

The git submodule warning and clone instructions are essential for contributors working with template repositories.

src/index.ts (4)

45-77: LGTM! Proper directory handling.

The function correctly checks for directory existence, prompts for overwrite confirmation, and handles directory removal safely with the force option.


79-114: LGTM! Clear and helpful success message.

The function provides appropriate next steps based on project type with correct port numbers and command examples.


116-168: LGTM! Well-structured orchestration flow.

The main function is cleanly refactored with proper separation of concerns, using modular helpers for each step. Error handling is centralized and appropriate.


157-161: The code at lines 157-161 is already correctly formatted according to the Biome configuration (2-space indentation, proper semicolons, compliant line lengths). No formatting action is required.

Comment on lines +20 to +43
async function getProjectName(args: string[]): Promise<string> {
const projectNameArg = args[0];

// If project name was provided as argument and is valid, use it
if (projectNameArg && PROJECT_NAME_REGEX.test(projectNameArg)) {
return projectNameArg;
}

// Otherwise, prompt for it with default value
const projectName = await clack.text({
message: 'Project name:',
placeholder: DEFAULT_PROJECT_NAME,
initialValue: DEFAULT_PROJECT_NAME,
validate: validateProjectName,
});

if (clack.isCancel(projectName)) {
clack.cancel('Operation cancelled');
process.exit(0);
}

// Trim and normalize the project name
return projectName.trim();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix validation inconsistency for command-line arguments.

The validation at line 24 only checks PROJECT_NAME_REGEX but doesn't enforce the hyphen position rules that validateProjectName checks (lines starting/ending with hyphens). This means passing "-my-project" or "my-project-" as a CLI argument would be accepted here but would be rejected if entered via the prompt.

🔎 Proposed fix to use consistent validation
 async function getProjectName(args: string[]): Promise<string> {
   const projectNameArg = args[0];
 
-  // If project name was provided as argument and is valid, use it
-  if (projectNameArg && PROJECT_NAME_REGEX.test(projectNameArg)) {
-    return projectNameArg;
+  // If project name was provided as argument, validate it
+  if (projectNameArg) {
+    const validationError = validateProjectName(projectNameArg);
+    if (!validationError) {
+      return projectNameArg.trim();
+    }
   }
 
   // Otherwise, prompt for it with default value
🤖 Prompt for AI Agents
In src/index.ts around lines 20 to 43, the CLI-argument validation only uses
PROJECT_NAME_REGEX and thus accepts names that the prompt validator would reject
(e.g. names starting or ending with a hyphen); replace the single regex check
with the same validation used for prompt input by calling
validateProjectName(projectNameArg) (and ensure you trim the arg before
validating) so CLI arguments and interactive input are validated consistently,
returning the trimmed projectNameArg when it passes.

@truehazker truehazker merged commit bb8d359 into develop Jan 4, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant