-
-
Notifications
You must be signed in to change notification settings - Fork 241
feat: Add lefthook to addons #711
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: main
Are you sure you want to change the base?
Conversation
|
@therealsamyak is attempting to deploy a commit to the Better T Stack Team on Vercel. A member of the Team first needs to authorize it. |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds Lefthook across CLI, templates, docs, types, and tests; introduces Changes
sequenceDiagram
participant CLI as CLI
participant Setup as Addons Setup
participant Ultracite as Ultracite Init
participant HookMgr as Hook Setup (Husky / Lefthook)
participant PKG as package.json
CLI->>Setup: collect selected addons & config
Setup->>Setup: determine gitHooks ([], ["husky"], ["lefthook"], ["husky","lefthook"])
alt Ultracite selected
Setup->>Ultracite: setupUltracite(config, gitHooks)
Ultracite-->>Setup: integrations = gitHooks.join(" ") (add lint-staged iff "husky" present)
end
opt "husky" in gitHooks
Setup->>HookMgr: setupHusky(projectDir)
HookMgr->>PKG: ensure husky deps & merge/update "prepare" script
end
opt "lefthook" in gitHooks
Setup->>HookMgr: setupLefthook(projectDir)
HookMgr->>PKG: ensure lefthook deps/config & merge/update "prepare" script
end
Setup-->>CLI: finish setup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
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: 3
🧹 Nitpick comments (3)
apps/web/src/lib/stack-url-keys.ts (1)
17-17: Consider abbreviating the URL parameter for consistency.While functionally correct, the mapping
gitHooks: "gitHooks"uses the full property name as the URL parameter. Most other mappings use abbreviations (e.g.,webFrontend: "fe-w",runtime: "rt",backend: "be"). Consider using an abbreviated form likegitHooks: "gh"to maintain consistency and reduce URL length.apps/web/src/lib/stack-utils.ts (1)
18-18: Verify the position of gitHooks in CATEGORY_ORDER.The gitHooks category is placed after packageManager and before addons. While this ordering seems reasonable, consider whether it should be grouped closer to the "git" option (line 21) since they're conceptually related.
Consider this alternative ordering if you want to group Git-related options together:
"packageManager", + "git", + "gitHooks", - "gitHooks", "addons", "examples", - "git", "install",apps/cli/src/helpers/git-hooks/git-hooks-setup.ts (1)
87-97: Consider adding error handling for template operations.If the Handlebars template file is missing or unreadable, this will throw an unhandled error with a potentially cryptic message. Consider wrapping in try-catch with a descriptive error, consistent with the pattern in
createReadme(line 24 in create-readme.ts).+ try { // Read and compile Handlebars template const templatePath = path.join(PKG_ROOT, "templates/git-hooks/lefthook/lefthook.yml.hbs"); const templateContent = await fs.readFile(templatePath, "utf-8"); const template = Handlebars.compile(templateContent); // Generate lefthook.yml content using template const lefthookYmlContent = template({ biome, oxlint }); const lefthookYmlPath = path.join(projectDir, "lefthook.yml"); await fs.writeFile(lefthookYmlPath, lefthookYmlContent); + } catch (error) { + throw new Error(`Failed to setup lefthook configuration: ${error}`); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (41)
README.md(1 hunks)apps/cli/README.md(3 hunks)apps/cli/src/constants.ts(2 hunks)apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/add-addons.ts(1 hunks)apps/cli/src/helpers/core/command-handlers.ts(1 hunks)apps/cli/src/helpers/core/create-project.ts(4 hunks)apps/cli/src/helpers/core/create-readme.ts(5 hunks)apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/helpers/core/template-manager.ts(1 hunks)apps/cli/src/helpers/git-hooks/git-hooks-setup.ts(1 hunks)apps/cli/src/index.ts(3 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/src/prompts/config-prompts.ts(5 hunks)apps/cli/src/prompts/git-hooks.ts(1 hunks)apps/cli/src/types.ts(5 hunks)apps/cli/src/utils/bts-config.ts(2 hunks)apps/cli/src/utils/config-processing.ts(2 hunks)apps/cli/src/utils/display-config.ts(1 hunks)apps/cli/src/validation.ts(1 hunks)apps/cli/templates/addons/ruler/.ruler/bts.md.hbs(1 hunks)apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs(1 hunks)apps/cli/test/addons.test.ts(2 hunks)apps/cli/test/backend-runtime.test.ts(1 hunks)apps/cli/test/benchmark.test.ts(1 hunks)apps/cli/test/git-hooks.test.ts(1 hunks)apps/cli/test/integration.test.ts(4 hunks)apps/cli/test/test-utils.ts(2 hunks)apps/web/content/docs/cli/index.mdx(1 hunks)apps/web/content/docs/cli/options.mdx(2 hunks)apps/web/content/docs/cli/programmatic-api.mdx(1 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(9 hunks)apps/web/src/lib/stack-url-keys.ts(1 hunks)apps/web/src/lib/stack-url-state.client.ts(1 hunks)apps/web/src/lib/stack-url-state.ts(1 hunks)apps/web/src/lib/stack-utils.ts(2 hunks)apps/web/src/lib/types.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/web/src/lib/types.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/validation.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/src/index.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/utils/display-config.tsapps/cli/test/benchmark.test.tsapps/cli/src/prompts/config-prompts.tsapps/cli/test/test-utils.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/prompts/git-hooks.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/git-hooks/git-hooks-setup.tsapps/cli/src/constants.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/types.tsapps/cli/test/git-hooks.test.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/detect-project-config.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/utils/bts-config.tsapps/cli/src/helpers/core/create-project.tsapps/cli/src/utils/config-processing.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/web/src/lib/types.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/validation.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/src/index.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/utils/display-config.tsapps/cli/test/benchmark.test.tsapps/cli/src/prompts/config-prompts.tsapps/cli/test/test-utils.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/prompts/git-hooks.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/git-hooks/git-hooks-setup.tsapps/cli/src/constants.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/types.tsapps/cli/test/git-hooks.test.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/detect-project-config.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/utils/bts-config.tsapps/cli/src/helpers/core/create-project.tsapps/cli/src/utils/config-processing.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/web/src/lib/types.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/validation.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/src/index.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/utils/display-config.tsapps/cli/test/benchmark.test.tsapps/cli/src/prompts/config-prompts.tsapps/cli/test/test-utils.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/prompts/git-hooks.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/git-hooks/git-hooks-setup.tsapps/cli/src/constants.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/types.tsapps/cli/test/git-hooks.test.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/detect-project-config.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/utils/bts-config.tsapps/cli/src/helpers/core/create-project.tsapps/cli/src/utils/config-processing.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/web/src/lib/types.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/validation.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/src/index.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/utils/display-config.tsapps/cli/test/benchmark.test.tsapps/cli/src/prompts/config-prompts.tsapps/cli/test/test-utils.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/prompts/git-hooks.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/git-hooks/git-hooks-setup.tsapps/cli/src/constants.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/types.tsapps/cli/test/git-hooks.test.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/detect-project-config.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/utils/bts-config.tsapps/cli/src/helpers/core/create-project.tsapps/cli/src/utils/config-processing.tsapps/web/src/lib/constant.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/web/src/lib/types.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/validation.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/src/index.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/utils/display-config.tsapps/cli/test/benchmark.test.tsapps/cli/src/prompts/config-prompts.tsapps/cli/test/test-utils.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/prompts/git-hooks.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/git-hooks/git-hooks-setup.tsapps/cli/src/constants.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/types.tsapps/cli/test/git-hooks.test.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/detect-project-config.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/utils/bts-config.tsapps/cli/src/helpers/core/create-project.tsapps/cli/src/utils/config-processing.tsapps/web/src/lib/constant.ts
**/*.hbs
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.hbs: In Handlebars templates, avoid generic if/else blocks. Write explicit conditions, such as: use if (eq orm "prisma") for Prisma, and else if (eq orm "drizzle") for Drizzle
Escape the '{{' in Handlebars templates like '{{'
Files:
apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/backend-runtime.test.tsapps/cli/test/benchmark.test.tsapps/cli/test/addons.test.tsapps/cli/test/git-hooks.test.tsapps/cli/test/integration.test.ts
🧠 Learnings (4)
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun:test` module with `test` and `expect` functions for writing tests
Applied to files:
apps/cli/test/test-utils.tsapps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun test` instead of `jest` or `vitest` for running tests
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:14.703Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-12-03T07:48:14.703Z
Learning: Applies to convex/**/*.ts : Use the api object from convex/_generated/api.ts to call public functions registered with query, mutation, or action
Applied to files:
apps/cli/src/helpers/core/create-readme.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to {package.json,bun.lockb} : Use `bun install` instead of `npm install`, `yarn install`, or `pnpm install`
Applied to files:
apps/web/content/docs/cli/index.mdx
🧬 Code graph analysis (10)
apps/web/src/lib/stack-url-state.client.ts (1)
apps/web/src/lib/constant.ts (2)
StackState(740-761)DEFAULT_STACK(763-784)
apps/cli/src/index.ts (1)
apps/cli/src/types.ts (1)
GitHooksSchema(88-88)
apps/cli/src/prompts/git-hooks.ts (3)
apps/cli/src/types.ts (1)
GitHooks(89-89)apps/cli/src/constants.ts (1)
DEFAULT_CONFIG(41-41)apps/cli/src/utils/errors.ts (1)
exitCancelled(17-23)
apps/cli/src/helpers/addons/ultracite-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/cli/src/types.ts (1)
apps/cli/src/index.ts (1)
GitHooks(256-256)
apps/cli/test/git-hooks.test.ts (1)
apps/cli/src/types.ts (1)
GitHooks(89-89)
apps/cli/src/helpers/core/create-readme.ts (2)
apps/cli/src/index.ts (1)
GitHooks(256-256)apps/cli/src/types.ts (1)
GitHooks(89-89)
apps/web/src/lib/stack-url-state.ts (1)
apps/web/src/lib/constant.ts (2)
StackState(740-761)DEFAULT_STACK(763-784)
apps/cli/src/helpers/core/template-manager.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/constants.ts (1)
PKG_ROOT(7-7)
apps/cli/src/helpers/core/create-project.ts (2)
apps/cli/src/helpers/core/template-manager.ts (1)
setupGitHooksTemplate(599-610)apps/cli/src/helpers/git-hooks/git-hooks-setup.ts (1)
setupGitHooks(8-34)
🔇 Additional comments (58)
apps/cli/templates/addons/ruler/.ruler/bts.md.hbs (1)
119-119: LGTM!The removal of Husky from the addons list aligns with the PR's objective to move Git hooks to a dedicated section. The documentation now accurately reflects the new structure.
README.md (1)
47-48: LGTM!The updated documentation clearly reflects the architectural change, separating Git hooks management from addons. The addition of Lefthook as an option alongside Husky provides users with flexibility.
apps/cli/src/helpers/core/post-installation.ts (3)
22-22: LGTM!The addition of
gitHooksto the destructured config properly integrates the new Git hooks feature into the post-installation flow.
30-30: LGTM!The renamed condition
hasHooksOrBiomecorrectly handles the newgitHooksconfiguration. The logic properly evaluates totruewhengitHooksis set to either "husky" or "lefthook", andfalsewhen it's "none", while maintaining the fallback check for Biome.
46-46: LGTM!The updated reference to
hasHooksOrBiomeensures linting instructions are displayed when either Git hooks or Biome is configured.apps/cli/src/helpers/core/command-handlers.ts (1)
105-105: LGTM!The addition of
gitHooks: "none"to the error path configuration properly satisfies the updatedProjectConfigtype. Using "none" as the default is appropriate for error scenarios.apps/cli/src/constants.ts (1)
27-27: LGTM!Setting
gitHooks: "none"as the default is appropriate, making Git hooks management opt-in rather than forced upon users.apps/cli/src/prompts/git-hooks.ts (1)
1-34: LGTM!The implementation follows best practices:
- Uses standard function declaration syntax as per coding guidelines
- Implements efficient early return when
gitHooksis already defined- Provides clear, descriptive labels and hints for each option
- Properly handles user cancellation
- Uses the appropriate default from
DEFAULT_CONFIG.gitHooksapps/cli/src/validation.ts (1)
21-21: Verify flag name consistency.The addition of "hooks" to
CORE_STACK_FLAGSshould match the actual CLI flag name. Other entries in this set use the full config property names (e.g., "database", "backend", "gitHooks"). Please verify whether the CLI flag is defined as--hooksor--git-hooksand ensure consistency.apps/cli/src/prompts/addons.ts (1)
66-66: LGTM! Clean removal of Husky from addons.The removal of "husky" from the Other addons group is consistent with the PR's refactoring of Git hooks into a dedicated feature. The change aligns with the new --git-hooks option.
apps/web/content/docs/cli/programmatic-api.mdx (1)
163-163: LGTM! Clear documentation of the new gitHooks option.The documentation clearly describes the new gitHooks field with its allowed values, following the established pattern for other CreateInput fields.
apps/cli/test/addons.test.ts (1)
7-7: LGTM! Test updates align with the Git hooks refactoring.The removal of "husky" from the universalAddons and multiple addons test cases correctly reflects the architectural change where Husky is now part of the dedicated gitHooks feature rather than an addon.
Also applies to: 178-178
apps/cli/src/utils/display-config.ts (1)
46-48: LGTM! Consistent implementation for displaying gitHooks.The implementation follows the established pattern used for other configuration options, with proper undefined checking and String() conversion.
apps/cli/src/index.ts (1)
28-29: LGTM! Clean integration of GitHooks into the public API.The GitHooks type and schema are properly imported, integrated into the input schema as an optional field, and exported for programmatic usage. The implementation follows the established pattern used for other CLI options.
Also applies to: 90-90, 256-256
apps/cli/test/test-utils.ts (1)
7-7: LGTM! Appropriate default value for test utilities.The addition of
gitHooks: "none"to coreStackDefaults ensures tests have a sensible default value when gitHooks is not explicitly specified, preventing test failures while maintaining consistency with the new Git hooks feature.Also applies to: 113-113
apps/cli/test/benchmark.test.ts (1)
430-431: LGTM! Correctly demonstrates the Git hooks refactoring.The change from
addons: ["turborepo", "biome", "husky"]toaddons: ["turborepo", "biome"]with the addition ofgitHooks: "husky"clearly demonstrates the architectural change where Husky is now configured through the dedicated gitHooks option rather than as an addon.apps/web/src/lib/stack-utils.ts (2)
104-116: LGTM! Husky correctly removed from addons filter.The removal of "husky" from the allowed addons filter list (it's no longer included) is consistent with the refactoring where Husky is now configured through the gitHooks option instead.
96-96: Verify that stack.gitHooks is always defined.The template literal
--git-hooks ${stack.gitHooks}assumes stack.gitHooks is always defined. If it can be undefined, this would generate--git-hooks undefinedin the command string. Verify that StackState type always provides a default value for gitHooks or add a fallback value (e.g.,${stack.gitHooks ?? ''}).apps/cli/test/backend-runtime.test.ts (1)
40-40: LGTM!The addition of
gitHooks: "none"to the test configuration is consistent with the new Git Hooks feature being introduced across the CLI.apps/cli/src/helpers/core/add-addons.ts (1)
53-53: LGTM!The
gitHooksfield assignment follows the established pattern with proper fallback precedence: input → detected config → default value.apps/web/src/lib/stack-url-state.client.ts (1)
35-37: LGTM!The
gitHooksparser implementation is consistent with other string enum parsers in the file, properly usinggetValidIdsand defaulting toDEFAULT_STACK.gitHooks.apps/cli/src/helpers/core/template-manager.ts (1)
599-610: LGTM!The
setupGitHooksTemplatefunction follows the established pattern of other template setup functions in this file, including:
- Early returns for "none" and ultracite scenarios
- Path existence verification before copying
- Standard async function declaration per coding guidelines
apps/cli/src/helpers/core/detect-project-config.ts (1)
26-26: LGTM!The addition of
gitHooks: btsConfig.gitHooksis consistent with the pattern used for all other config fields in the detected config object.apps/web/content/docs/index.mdx (1)
313-314: LGTM!The documentation correctly reflects the refactoring of Git Hooks into a dedicated configuration option. Moving Husky from addons to the
--hooksflag aligns with the PR objectives and provides better separation of concerns.apps/web/content/docs/cli/index.mdx (1)
30-30: LGTM!The
--git-hooksoption documentation is clear, well-positioned after the Git initialization option, and consistent with the format used for other CLI flags.apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs (1)
1-12: The Lefthook placeholder syntax{staged_files}is correct and matches official documentation. No changes needed. The template properly uses this syntax for both biome and oxlint commands.Likely an incorrect or invalid review comment.
apps/cli/test/integration.test.ts (2)
38-39: LGTM! Test correctly uses new gitHooks field.The migration of Husky from
addonsto the dedicatedgitHooksfield aligns with the PR's architectural change.Consider adding a test case with
gitHooks: "lefthook"to ensure coverage of the newly introduced option.
186-187: Consistent gitHooks migration across test cases.All test configurations correctly separate Husky into the
gitHooksfield while keeping other addons inaddonsarray.Also applies to: 273-274, 472-473
apps/cli/src/prompts/config-prompts.ts (2)
113-113: LGTM! gitHooks prompt integration follows established patterns.The
gitHooksprompt is correctly wired into the config group without dependencies, which aligns with the PR behavior notes that git hooks selection is independent of other choices.
56-56: Type and return value properly extended.The
PromptGroupResultstype and returned configuration object are correctly updated to includegitHooks.Also applies to: 141-141
apps/cli/src/utils/config-processing.ts (1)
90-92: LGTM! Flag processing follows established pattern.The
gitHooksflag processing mirrors the existing approach for other single-value options likeapi,backend, anddatabase.apps/web/src/lib/types.ts (1)
15-15: LGTM! TechCategory type correctly extended.The
gitHookscategory is appropriately added to the union type, enabling type-safe handling of git hooks in the web interface.apps/web/src/lib/stack-url-state.ts (1)
49-51: LGTM! Server-side parser correctly implemented.The
gitHooksparser follows the established pattern used forpackageManagerand other enum fields, with proper validation viagetValidIdsand appropriate defaulting.apps/cli/src/utils/bts-config.ts (1)
27-27: LGTM! BTS config correctly extended with gitHooks.The
gitHooksproperty is properly added to both the internal config object and the serialized output, ensuring the configuration is persisted inbts.jsonc.Also applies to: 48-48
apps/web/content/docs/cli/options.mdx (2)
239-253: LGTM! Clear documentation for the new Git Hooks feature.The new Git Hooks section provides clear documentation for the
--git-hooksoption with appropriate examples. The default value ofnoneis clearly stated.
273-273: LGTM! Addons example correctly updated.The example command correctly reflects that Husky has been moved from addons to the dedicated Git Hooks option.
apps/web/content/docs/project-structure.mdx (1)
257-258: LGTM! Configuration schema correctly updated.The Better-T-Stack configuration schema accurately reflects the changes:
- Husky removed from addons list
- New
hooksfield added with appropriate valuesapps/cli/src/helpers/core/create-project.ts (3)
15-15: LGTM! Imports correctly added.The new Git Hooks setup imports are properly added and follow the existing pattern for other setup features.
Also applies to: 34-34
64-64: LGTM! Template setup correctly positioned.The Git Hooks template setup is appropriately placed after addons template setup, maintaining consistency with the project scaffolding flow.
88-90: LGTM! Git Hooks setup logic is correct.The conditional setup correctly checks for non-"none" gitHooks values before invoking the setup function, following the same pattern as auth and payments setup.
apps/cli/src/helpers/addons/addons-setup.ts (1)
63-63: LGTM! Ultracite setup call correctly simplified.The setupUltracite call now passes only the config parameter, correctly reflecting the refactored function signature where Git Hooks logic is handled within the config itself rather than as a separate boolean flag.
apps/cli/test/git-hooks.test.ts (1)
5-212: LGTM! Comprehensive test coverage for Git Hooks.The test suite provides excellent coverage:
- Individual git hook options (lefthook, husky, none)
- Linter integrations (biome, oxlint)
- Multiple addon combinations
- Default behavior validation
Once the import issue is fixed, these tests will properly validate the Git Hooks functionality.
apps/cli/src/helpers/addons/ultracite-setup.ts (3)
133-134: LGTM! Function signature correctly refactored.The function signature has been properly simplified to remove the
hasHuskyboolean parameter in favor of extractinggitHooksdirectly from the config. This is a cleaner design that allows Ultracite to support both Lefthook and Husky.
200-202: LGTM! Integration logic correctly updated.The logic now correctly checks
gitHooks !== "none"to determine whether to enable Git Hooks integration, replacing the previous boolean flag approach. This allows Ultracite to support multiple Git Hooks managers.
218-223: LGTM! Dependency installation correctly updated.The dependency installation logic correctly:
- Guards installation with
gitHooks !== "none"- Uses the
gitHooksvalue directly as the package name (which is valid since both "husky" and "lefthook" are real package names)- Installs "lint-staged" alongside the selected Git Hooks manager
apps/cli/README.md (3)
43-45: LGTM! Features table correctly updated.The features table has been properly updated:
- New Git Hooks row added with Lefthook, Husky, and None options
- Husky removed from the Addons row
This clearly communicates that Git Hooks are now a separate feature category.
63-63: LGTM! CLI usage documentation updated.The
--git-hooksoption is properly documented in the usage section with clear parameter descriptions.
197-197: LGTM! Compatibility note correctly updated.The compatibility note for addons "none" has been updated to reflect that Husky is no longer part of the addons list.
apps/cli/src/types.ts (5)
88-89: LGTM! Git Hooks schema properly defined.The
GitHooksSchemaandGitHookstype are correctly defined using Zod's enum with appropriate values ("husky", "lefthook", "none") and a clear description.
150-150: LGTM! CreateInput type correctly extended.The
gitHooksfield is properly added as an optional property toCreateInput, following the same pattern as other optional configuration fields.
160-160: LGTM! AddInput type correctly extended.The
gitHooksfield is properly added as an optional property toAddInput, allowing Git Hooks to be configured during the add command.
187-187: LGTM! ProjectConfig interface correctly extended.The
gitHooksfield is properly added as a required property toProjectConfig, ensuring that all resolved project configurations include a Git Hooks value (even if it's "none").
207-207: LGTM! BetterTStackConfig interface correctly extended.The
gitHooksfield is properly added toBetterTStackConfig, ensuring that the persisted configuration includes the Git Hooks setting.apps/cli/src/helpers/core/create-readme.ts (1)
472-476: LGTM!The git hooks feature integration is clean. The optional parameter handling and name mapping logic correctly handle both
undefinedand"none"cases, following the existing pattern used for other features.apps/cli/src/helpers/git-hooks/git-hooks-setup.ts (1)
8-16: LGTM!The skip logic correctly handles the ultracite case (where ultracite manages its own hooks) and the "none" case. The linter detection logic properly checks addons before delegating to the appropriate setup function.
apps/web/src/lib/constant.ts (3)
472-497: LGTM!The gitHooks category is well-structured with appropriate options (lefthook, husky, none). The default is correctly set to
nonefor the category, matching the conservative approach of not imposing git hooks by default.
752-752: LGTM!The
gitHooksfield is properly added to theStackStatetype, maintaining consistency with the type alias pattern used throughout the file.
646-646: Verify: Preset templates all default to lefthook.All preset templates now include
gitHooks: "lefthook". This seems intentional as Lefthook is positioned as the preferred option, but it differs fromDEFAULT_STACKwhich uses"none". Confirm this is the desired behavior for preset templates.Also applies to: 673-673, 700-701, 727-727
f69ff1f to
bb93a72
Compare
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: 0
🧹 Nitpick comments (3)
apps/cli/test/backend-runtime.test.ts (1)
40-40: Consider addinggitHooks: "none"to other test configurations for consistency.The explicit
gitHooks: "none"is correctly added here. However, other test configurations in this file (e.g., invalid combinations, constraint tests) don't explicitly setgitHooks. While the test utilities likely default to"none", explicitly setting it throughout would improve consistency and make the test behavior more predictable.apps/cli/test/git-hooks.test.ts (1)
160-200: Consider usingdescribeblocks to group related tests.The tests are well-structured, but using
describeblocks (e.g., "Lefthook Linter Integration", "Husky Integration", "Hooks with Addons") would improve readability and match the organization style in other test files likeintegration.test.ts.+import { test, describe } from "bun:test"; -import { test } from "bun:test"; import type { GitHooks } from "../src/types"; import { runTRPCTest, expectSuccess } from "./test-utils"; const gitHookOptions = ["husky", "lefthook", "none"] as GitHooks[]; +describe("Git Hooks Configurations", () => { for (const gitHook of gitHookOptions) { - test(`Git Hooks Configurations - should work with ${gitHook} git hooks`, async () => { + test(`should work with ${gitHook} git hooks`, async () => { // ... test body }); } +});apps/web/content/docs/project-structure.mdx (1)
245-266: Clarify thathooksmaps to the Git hooks manager /--git-hooksoptionThe new
"hooks": "<lefthook|husky|none>"field looks correct, but it might help readers if the surrounding text briefly calls out that this controls the Git hooks manager and corresponds to the--git-hooksCLI flag, to avoid confusion with other kinds of “hooks”.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (41)
README.md(1 hunks)apps/cli/README.md(3 hunks)apps/cli/src/constants.ts(2 hunks)apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/add-addons.ts(1 hunks)apps/cli/src/helpers/core/command-handlers.ts(1 hunks)apps/cli/src/helpers/core/create-project.ts(4 hunks)apps/cli/src/helpers/core/create-readme.ts(5 hunks)apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/helpers/core/template-manager.ts(1 hunks)apps/cli/src/helpers/git-hooks/git-hooks-setup.ts(1 hunks)apps/cli/src/index.ts(3 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/src/prompts/config-prompts.ts(5 hunks)apps/cli/src/prompts/git-hooks.ts(1 hunks)apps/cli/src/types.ts(5 hunks)apps/cli/src/utils/bts-config.ts(2 hunks)apps/cli/src/utils/config-processing.ts(2 hunks)apps/cli/src/utils/display-config.ts(1 hunks)apps/cli/src/validation.ts(1 hunks)apps/cli/templates/addons/ruler/.ruler/bts.md.hbs(1 hunks)apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs(1 hunks)apps/cli/test/addons.test.ts(2 hunks)apps/cli/test/backend-runtime.test.ts(1 hunks)apps/cli/test/benchmark.test.ts(1 hunks)apps/cli/test/git-hooks.test.ts(1 hunks)apps/cli/test/integration.test.ts(4 hunks)apps/cli/test/test-utils.ts(2 hunks)apps/web/content/docs/cli/index.mdx(1 hunks)apps/web/content/docs/cli/options.mdx(2 hunks)apps/web/content/docs/cli/programmatic-api.mdx(1 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(9 hunks)apps/web/src/lib/stack-url-keys.ts(1 hunks)apps/web/src/lib/stack-url-state.client.ts(1 hunks)apps/web/src/lib/stack-url-state.ts(1 hunks)apps/web/src/lib/stack-utils.ts(2 hunks)apps/web/src/lib/types.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/cli/templates/addons/ruler/.ruler/bts.md.hbs
🚧 Files skipped from review as they are similar to previous changes (23)
- apps/web/src/lib/stack-url-keys.ts
- apps/cli/src/helpers/core/command-handlers.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs
- apps/cli/src/prompts/git-hooks.ts
- apps/cli/src/utils/config-processing.ts
- apps/cli/src/constants.ts
- apps/web/content/docs/cli/index.mdx
- apps/cli/README.md
- apps/cli/src/helpers/core/post-installation.ts
- apps/web/content/docs/cli/programmatic-api.mdx
- README.md
- apps/cli/src/helpers/git-hooks/git-hooks-setup.ts
- apps/cli/test/benchmark.test.ts
- apps/cli/src/helpers/core/add-addons.ts
- apps/web/src/lib/stack-url-state.ts
- apps/cli/src/utils/display-config.ts
- apps/cli/src/types.ts
- apps/cli/test/test-utils.ts
- apps/cli/src/validation.ts
- apps/cli/src/index.ts
- apps/web/src/lib/stack-utils.ts
- apps/cli/src/helpers/core/create-project.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/test/addons.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/helpers/core/detect-project-config.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/utils/bts-config.tsapps/web/src/lib/types.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/test/addons.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/helpers/core/detect-project-config.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/utils/bts-config.tsapps/web/src/lib/types.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/test/addons.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/helpers/core/detect-project-config.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/utils/bts-config.tsapps/web/src/lib/types.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/test/addons.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/helpers/core/detect-project-config.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/utils/bts-config.tsapps/web/src/lib/types.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/test/addons.test.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/test/integration.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/test/git-hooks.test.tsapps/cli/test/backend-runtime.test.tsapps/cli/src/helpers/core/detect-project-config.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/utils/bts-config.tsapps/web/src/lib/types.ts
🧠 Learnings (4)
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun:test` module with `test` and `expect` functions for writing tests
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun test` instead of `jest` or `vitest` for running tests
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `bun <file>` instead of `node <file>` or `ts-node <file>` for running TypeScript/JavaScript files
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:14.703Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-12-03T07:48:14.703Z
Learning: Applies to convex/**/*.ts : Use the api object from convex/_generated/api.ts to call public functions registered with query, mutation, or action
Applied to files:
apps/cli/src/helpers/core/create-readme.ts
🧬 Code graph analysis (5)
apps/cli/src/helpers/core/template-manager.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/constants.ts (1)
PKG_ROOT(7-7)
apps/cli/src/helpers/addons/ultracite-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/web/src/lib/stack-url-state.client.ts (1)
apps/web/src/lib/constant.ts (2)
StackState(740-761)DEFAULT_STACK(763-784)
apps/cli/src/helpers/core/create-readme.ts (2)
apps/cli/src/index.ts (1)
GitHooks(256-256)apps/cli/src/types.ts (1)
GitHooks(89-89)
apps/cli/src/helpers/addons/addons-setup.ts (1)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
setupUltracite(133-232)
🔇 Additional comments (25)
apps/cli/src/prompts/addons.ts (1)
46-66: LGTM! Clean migration of Husky out of addons.The removal of Husky from the addons switch case and ADDON_GROUPS.Other is consistent with the PR's objective to move Git hooks into their own configuration surface.
apps/cli/src/helpers/core/detect-project-config.ts (1)
26-26: LGTM! Correct propagation of gitHooks field.The gitHooks field is properly extracted from the BTS config and included in the returned project configuration, consistent with other config fields.
apps/cli/src/helpers/core/template-manager.ts (1)
599-610: LGTM! Well-structured Git hooks template setup.The function correctly:
- Guards against invalid states (none, missing gitHooks)
- Skips when Ultracite is handling hooks (per PR behavior notes)
- Follows the established template setup pattern
- Uses standard function declaration syntax as per coding guidelines
apps/web/src/lib/types.ts (1)
15-15: LGTM! Correct union type extension.The addition of "gitHooks" to TechCategory properly extends the type to support the new Git hooks configuration category.
apps/cli/src/utils/bts-config.ts (1)
27-48: LGTM! Proper gitHooks config persistence.The gitHooks field is correctly included in both the runtime config object and the serialized baseContent, ensuring it persists in bts.jsonc and remains available for downstream operations.
apps/cli/src/helpers/core/create-readme.ts (3)
11-11: LGTM! Correct type import.The GitHooks type import enables type-safe handling of the gitHooks parameter in README generation.
42-70: LGTM! Proper gitHooks propagation.The gitHooks field is correctly destructured from options and passed through to generateFeaturesList, maintaining consistency with how other config fields are handled.
353-476: LGTM! Well-implemented Git hooks feature rendering.The implementation correctly:
- Uses an optional parameter since gitHooks may be "none"
- Guards against undefined and "none" values before rendering
- Maps gitHooks values to appropriate display names
- Adds the feature to the list in a consistent format
apps/web/content/docs/index.mdx (1)
313-314: LGTM! Documentation correctly updated.The docs properly reflect the migration of Husky from addons to the new --hooks flag, with accurate values (lefthook, husky, none) documented for users.
apps/cli/test/addons.test.ts (2)
7-7: LGTM! Test correctly updated for Husky migration.Removing "husky" from the universalAddons array aligns with the PR's migration of Husky from addons to the gitHooks configuration.
178-178: LGTM! Multiple addons test correctly updated.The test array properly excludes "husky" while still validating that multiple compatible addons can be used together.
apps/cli/test/integration.test.ts (4)
38-39: LGTM!The migration of husky from the addons array to a dedicated
gitHooks: "husky"field is correctly implemented. This aligns with the PR's objective to refactor Git hooks into their own section.
186-187: LGTM!Consistent application of the gitHooks field for the MongoDB + Mongoose test configuration.
273-274: LGTM!Frontend-only Nuxt test configuration correctly updated with gitHooks field.
472-473: LGTM!Maximum complexity test configuration correctly updated to use gitHooks instead of husky in addons.
apps/web/content/docs/cli/options.mdx (2)
239-253: LGTM!The new Git Hooks section is well-documented with clear descriptions for each option (lefthook, husky, none) and helpful usage examples. The placement after Authentication and before Addons is logical.
273-273: LGTM!The addons example correctly excludes husky, which is now documented in the Git Hooks section.
apps/web/src/lib/stack-url-state.client.ts (1)
35-37: LGTM!The gitHooks parser follows the established pattern used by other enum parsers in this file. It correctly uses
parseAsStringEnumwith valid IDs fromTECH_OPTIONS["gitHooks"]and defaults toDEFAULT_STACK.gitHooks("none").apps/cli/test/git-hooks.test.ts (4)
1-3: LGTM!Correct usage of
bun:testper coding guidelines. The imports are appropriate for the test file.
5-28: LGTM!Good use of a loop to test all gitHook options, reducing code duplication while ensuring coverage for husky, lefthook, and none configurations.
30-93: LGTM!Comprehensive Lefthook integration tests covering biome, oxlint, and standalone scenarios. Test configurations are complete and follow established patterns.
95-158: LGTM!Comprehensive Husky integration tests mirroring the Lefthook tests for consistency. Good coverage of biome, oxlint, and standalone scenarios.
apps/cli/src/helpers/addons/addons-setup.ts (1)
59-68: Ultracite setup now correctly forwards full ProjectConfig (including gitHooks)Switching to
setupUltracite(config)keeps the Biome/Ultracite branching intact and correctly passes gitHooks and other fields through the config object; the control flow forultracitevsbiomeremains sound.apps/cli/src/helpers/addons/ultracite-setup.ts (1)
133-135: gitHooks-based Ultracite integration and dependency wiring look consistentUsing
config.gitHooksto gate--integrations <gitHooks> lint-stagedand to install[gitHooks, "lint-staged"]only whengitHooks !== "none"matches the intended behavior and cleanly replaces the earlier hasHusky flag.Also applies to: 200-202, 218-221
apps/web/src/lib/constant.ts (1)
472-497: gitHooks option and defaults are wired consistently across web constants and presetsThe new
gitHookstech category, its default of"none", the preset stacks setting"lefthook"where desired, and the StackState/DEFAULT_STACK updates all align and should integrate cleanly with the rest of the stack/state logic.Also applies to: 646-647, 673-674, 700-703, 727-728, 752-752, 775-775
bb93a72 to
fb1e620
Compare
|
@AmanVarshney01 this is ready to review when you are! |
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: 0
🧹 Nitpick comments (7)
apps/web/content/docs/cli/programmatic-api.mdx (1)
163-163: Improve inline comment to describe field purpose, not just values.The comment lists allowed values but doesn't describe what the field does. Compare with the
gitfield above (line 162: "Initialize git repo"), which is more informative. Consider updating the comment to explain the purpose.- gitHooks?: GitHooks; // "lefthook" | "husky" | "none" + gitHooks?: GitHooks; // Git hooks manager: "lefthook" | "husky" | "none"Alternatively, if you want to keep it even more concise to match the union-type pattern, just ensure consistency:
- gitHooks?: GitHooks; // "lefthook" | "husky" | "none" + gitHooks?: GitHooks; // Git hooks manager ("lefthook" | "husky" | "none")apps/web/src/lib/stack-url-keys.ts (1)
17-17: Consider using an abbreviated URL key for consistency.Most URL keys use abbreviated forms (e.g.,
pm,add,ex,wd). Consider usingghinstead ofgitHooksto keep URLs shorter and consistent with the abbreviated pattern:- gitHooks: "gitHooks", + gitHooks: "gh",That said, keys like
api,git, andyoloalso use full names, so the current approach is acceptable.apps/web/src/lib/constant.ts (1)
540-541: Minor: Remove trailing empty line.This appears to be leftover formatting from removing Husky from addons. Consider removing the extra blank line for cleaner formatting.
apps/cli/test/addons.test.ts (1)
7-30: Addon tests correctly drop Husky; consider deriving lists from shared configUpdating
universalAddons, the “multiple compatible addons” config, andtestableAddonsto exclude"husky"matches the new separation between addons andgitHooks. To reduce future drift, you could derive these arrays fromAddonsSchema.options(filtering out prompt‑only addons) instead of maintaining the string lists by hand, but that’s optional.Also applies to: 174-195, 283-323
apps/cli/test/integration.test.ts (1)
28-45: Integration tests now exercise Husky viagitHooks; add a Lefthook case for full coverageSwitching Husky from
addonstogitHooks: "husky"in these scenarios keeps real‑world coverage aligned with the new API shape. To fully exercise the new--git-hookssurface, it would be worth adding at least one analogous integration test usinggitHooks: "lefthook"(with Biome/Oxlint enabled) so both hook managers are covered end‑to‑end.Also applies to: 176-193, 263-281, 461-479
apps/cli/test/git-hooks.test.ts (2)
1-28: Parameterized gitHooks tests are well-structuredThe shared
gitHookOptionsarray plus the looped test covers all three allowed git hooks values with a single, readable pattern, and each run uses a distinctprojectName, so there’s no cross-test directory clash. Just keep in mind that if new git hooks modes are ever added to the config, this array will need updating to keep coverage aligned, but as written it’s correct and maintainable.
30-200: Comprehensive scenario coverage; minor duplication onlyThese tests thoroughly exercise git hooks with and without linters (Biome/Oxlint), both managers (lefthook/husky), multiple addons, and the implicit default case where
gitHooksis omitted. The configurations andprojectNamevalues are consistent and should give good confidence that CLI scaffolding works across combinations. If this suite grows further, consider extracting a small helper to build the common config shape (frontend/backend/runtime/db/auth/api flags) to reduce repetition, but that’s optional.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (41)
README.md(1 hunks)apps/cli/README.md(3 hunks)apps/cli/src/constants.ts(2 hunks)apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/add-addons.ts(1 hunks)apps/cli/src/helpers/core/command-handlers.ts(1 hunks)apps/cli/src/helpers/core/create-project.ts(4 hunks)apps/cli/src/helpers/core/create-readme.ts(5 hunks)apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/helpers/core/template-manager.ts(1 hunks)apps/cli/src/helpers/git-hooks/git-hooks-setup.ts(1 hunks)apps/cli/src/index.ts(3 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/src/prompts/config-prompts.ts(5 hunks)apps/cli/src/prompts/git-hooks.ts(1 hunks)apps/cli/src/types.ts(5 hunks)apps/cli/src/utils/bts-config.ts(2 hunks)apps/cli/src/utils/config-processing.ts(2 hunks)apps/cli/src/utils/display-config.ts(1 hunks)apps/cli/src/validation.ts(1 hunks)apps/cli/templates/addons/ruler/.ruler/bts.md.hbs(1 hunks)apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs(1 hunks)apps/cli/test/addons.test.ts(2 hunks)apps/cli/test/backend-runtime.test.ts(1 hunks)apps/cli/test/benchmark.test.ts(1 hunks)apps/cli/test/git-hooks.test.ts(1 hunks)apps/cli/test/integration.test.ts(4 hunks)apps/cli/test/test-utils.ts(2 hunks)apps/web/content/docs/cli/index.mdx(1 hunks)apps/web/content/docs/cli/options.mdx(2 hunks)apps/web/content/docs/cli/programmatic-api.mdx(1 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(9 hunks)apps/web/src/lib/stack-url-keys.ts(1 hunks)apps/web/src/lib/stack-url-state.client.ts(1 hunks)apps/web/src/lib/stack-url-state.ts(1 hunks)apps/web/src/lib/stack-utils.ts(2 hunks)apps/web/src/lib/types.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (30)
- apps/web/src/lib/stack-url-state.client.ts
- apps/cli/templates/addons/ruler/.ruler/bts.md.hbs
- apps/cli/src/constants.ts
- apps/cli/src/helpers/core/template-manager.ts
- apps/cli/src/helpers/core/detect-project-config.ts
- apps/cli/src/index.ts
- apps/web/content/docs/project-structure.mdx
- apps/cli/src/utils/display-config.ts
- apps/cli/src/prompts/git-hooks.ts
- apps/cli/test/backend-runtime.test.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/src/helpers/core/command-handlers.ts
- apps/web/src/lib/stack-utils.ts
- apps/web/content/docs/cli/options.mdx
- apps/cli/src/helpers/addons/ultracite-setup.ts
- apps/cli/src/validation.ts
- apps/cli/src/helpers/core/post-installation.ts
- apps/web/src/lib/stack-url-state.ts
- apps/cli/src/helpers/git-hooks/git-hooks-setup.ts
- apps/cli/src/helpers/core/add-addons.ts
- apps/cli/test/benchmark.test.ts
- apps/cli/src/utils/bts-config.ts
- apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs
- apps/web/content/docs/cli/index.mdx
- apps/cli/src/utils/config-processing.ts
- apps/web/content/docs/index.mdx
- apps/cli/src/types.ts
- apps/cli/test/test-utils.ts
- apps/cli/src/helpers/core/create-project.ts
- apps/web/src/lib/types.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/constant.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/constant.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/test/addons.test.tsapps/cli/test/integration.test.tsapps/cli/test/git-hooks.test.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/stack-url-keys.tsapps/web/src/lib/constant.ts
🧠 Learnings (4)
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun:test` module with `test` and `expect` functions for writing tests
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun test` instead of `jest` or `vitest` for running tests
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.410Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.410Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `bun <file>` instead of `node <file>` or `ts-node <file>` for running TypeScript/JavaScript files
Applied to files:
apps/cli/test/git-hooks.test.ts
📚 Learning: 2025-12-03T07:48:14.703Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-12-03T07:48:14.703Z
Learning: Applies to convex/**/*.ts : Use the api object from convex/_generated/api.ts to call public functions registered with query, mutation, or action
Applied to files:
apps/cli/src/helpers/core/create-readme.ts
🧬 Code graph analysis (3)
apps/cli/test/git-hooks.test.ts (2)
apps/cli/src/types.ts (1)
GitHooks(89-89)apps/cli/test/test-utils.ts (2)
runTRPCTest(58-161)expectSuccess(163-173)
apps/cli/src/helpers/addons/addons-setup.ts (1)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
setupUltracite(133-232)
apps/cli/src/helpers/core/create-readme.ts (2)
apps/cli/src/index.ts (1)
GitHooks(256-256)apps/cli/src/types.ts (1)
GitHooks(89-89)
🔇 Additional comments (12)
README.md (1)
47-48: Documentation properly reflects Git Hooks as distinct feature.The changes cleanly move Husky from Addons into the new Git Hooks section while maintaining the comprehensive addon list. Formatting and feature presentation are consistent with the rest of the README.
apps/cli/README.md (4)
43-43: Git Hooks table row properly integrated.The new table entry follows the established format, lists correct options (Lefthook, Husky, None), and fits naturally within the Features documentation structure.
45-45: Addons section correctly updated.Husky has been cleanly removed from the Addons row. The remaining addons are properly formatted and consistent with the PR's refactoring objective.
62-63: CLI options properly documented.The new
--git-hooks <type>option is correctly documented with appropriate values and formatting consistent with other CLI flags. The addons option no longer references Husky.
197-197: Compatibility notes updated consistently.The Addons 'none' compatibility note has been properly updated to remove reference to Husky, maintaining internal consistency with the broader refactoring.
apps/web/src/lib/constant.ts (3)
472-497: LGTM!The new
gitHookscategory is well-structured with appropriate options (lefthook, husky, none) and sensible defaults. The configuration follows the established pattern of other tech options.
646-647: LGTM!The
gitHooks: "lefthook"addition to preset templates is consistent across all presets (mern, pern, t3, uniwind), aligning with the PR's intent to promote Lefthook as the recommended Git hooks manager.
752-752: LGTM!The
gitHooksfield is correctly added toStackStatetype with an appropriate default of"none"inDEFAULT_STACK, allowing users to opt-in to Git hooks management.apps/cli/src/helpers/addons/addons-setup.ts (1)
63-63: LGTM: Clean refactoring that improves separation of concerns.The simplified call to
setupUltracite(config)correctly aligns with the new architecture where Git hooks configuration is managed through theconfig.gitHooksfield rather than a separate boolean parameter. This refactoring moves Git hooks setup logic to a dedicated module, improving maintainability and reducing coupling in the addons setup flow.apps/cli/src/prompts/addons.ts (1)
17-58: Husky removal from addon display/groups looks consistent with new Git Hooks modelThe switch in
getAddonDisplayandADDON_GROUPS.Othernow exclude"husky", so Husky will no longer appear as an addon option, which matches the move to a dedicatedgitHooksfield. As long as"husky"has also been removed fromAddonsSchema.options, this prompt logic remains consistent and won’t ever hit the generic default branch for Husky.Also applies to: 63-67
apps/cli/src/helpers/core/create-readme.ts (2)
28-43: gitHooks plumbing into README generation is consistentDestructuring
gitHooksfromoptionsand threading it intogenerateFeaturesListcleanly connects the new config field to README output without changing other behavior. This keeps README content in sync with the project’s git hooks choice while remaining backward compatible whengitHooksis absent.Also applies to: 70-70
344-354: Git hooks feature entry in Features list behaves as expectedExtending
generateFeaturesListwith an optionalgitHooksparameter and appending a single bullet when it’s set to something other than"none"is straightforward and matches the current allowed values (labeling"husky"vs"lefthook"). This keeps the Features section accurate without clutter when no hooks manager is selected.Also applies to: 472-476
|
Thanks for the effort on this PR but i cant add another flag to the CLI it will add a lot more problems in other areas :(
|
fb1e620 to
f69ff1f
Compare
04bc830 to
1c8db0c
Compare
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.
Pull request overview
This PR introduces a new --git-hooks CLI flag to manage Git hooks setup, refactoring the Git hooks functionality out of the addons section into its own dedicated category. The change supports three options: lefthook (a fast and powerful Git hooks manager), husky (the existing option), and none (the default). This aligns with BTS's own adoption of lefthook and provides better organization by separating Git hooks management from general addons.
Key Changes:
- Added new
--git-hooksflag with support for lefthook, husky, and none options - Moved husky from addons array to the dedicated gitHooks field across all configurations
- Integrated Git hooks with linters (biome, oxlint) using different strategies: lint-staged for husky, native stage_fixed for lefthook
Reviewed changes
Copilot reviewed 35 out of 37 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/web/src/lib/types.ts | Added "gitHooks" to TechCategory type |
| apps/web/src/lib/stack-utils.ts | Added gitHooks parameter to stack command generation, removed husky from addons filter |
| apps/web/src/lib/stack-url-state.ts | Added gitHooks parser for server-side URL state management |
| apps/web/src/lib/stack-url-state.client.ts | Added gitHooks parser for client-side URL state management |
| apps/web/src/lib/stack-url-keys.ts | Added "gitHooks" URL key mapping |
| apps/web/src/lib/constant.ts | Added gitHooks tech options, moved husky from addons to gitHooks, updated presets to use lefthook |
| apps/web/content/docs/project-structure.mdx | Updated bts.jsonc schema documentation with hooks field |
| apps/web/content/docs/index.mdx | Updated CLI reference to show git-hooks flag |
| apps/web/content/docs/cli/programmatic-api.mdx | Added gitHooks to CreateInput interface documentation |
| apps/web/content/docs/cli/options.mdx | Added Git Hooks section with --git-hooks flag documentation |
| apps/web/content/docs/cli/index.mdx | Added --git-hooks to CLI command reference |
| apps/cli/test/test-utils.ts | Added GitHooks type import and default gitHooks value in test configuration |
| apps/cli/test/integration.test.ts | Updated integration tests to use gitHooks field instead of husky addon |
| apps/cli/test/git-hooks.test.ts | New comprehensive test suite for git hooks configurations |
| apps/cli/test/benchmark.test.ts | Updated benchmark test to use gitHooks field |
| apps/cli/test/backend-runtime.test.ts | Added gitHooks default to test configuration |
| apps/cli/test/addons.test.ts | Removed husky from addons tests and universal addons list |
| apps/cli/templates/git-hooks/lefthook/lefthook.yml.hbs | New Handlebars template for lefthook configuration with biome/oxlint support |
| apps/cli/templates/git-hooks/husky/.husky/pre-commit | New husky pre-commit hook template |
| apps/cli/templates/addons/ruler/.ruler/bts.md.hbs | Removed Husky from addons list in ruler documentation |
| apps/cli/src/validation.ts | Added "hooks" to CORE_STACK_FLAGS set |
| apps/cli/src/utils/display-config.ts | Added gitHooks display in configuration output |
| apps/cli/src/utils/config-processing.ts | Added gitHooks processing in processFlags function |
| apps/cli/src/utils/bts-config.ts | Added gitHooks to BTS config file generation |
| apps/cli/src/types.ts | Added GitHooksSchema type, removed husky from AddonsSchema, added gitHooks to interfaces |
| apps/cli/src/prompts/git-hooks.ts | New prompt module for Git hooks selection |
| apps/cli/src/prompts/config-prompts.ts | Integrated git hooks prompt into configuration gathering |
| apps/cli/src/prompts/addons.ts | Removed husky from addon display and groups |
| apps/cli/src/index.ts | Added GitHooksSchema and GitHooks export to API |
| apps/cli/src/helpers/git-hooks/git-hooks-setup.ts | New module for setting up git hooks (lefthook and husky) with linter integration |
| apps/cli/src/helpers/core/template-manager.ts | Added setupGitHooksTemplate function |
| apps/cli/src/helpers/core/post-installation.ts | Updated to check gitHooks instead of husky addon |
| apps/cli/src/helpers/core/detect-project-config.ts | Added gitHooks to config detection |
| apps/cli/src/helpers/core/create-readme.ts | Added gitHooks parameter and moved git hooks info from addons to dedicated section |
| apps/cli/src/helpers/core/create-project.ts | Added git hooks template and setup calls |
| apps/cli/src/helpers/core/command-handlers.ts | Added gitHooks default to project config |
| apps/cli/src/helpers/core/add-addons.ts | Added gitHooks to addons project config |
| apps/cli/src/helpers/addons/ultracite-setup.ts | Updated to use gitHooks field for ultracite integration |
| apps/cli/src/helpers/addons/addons-setup.ts | Removed setupHusky function (moved to git-hooks module) |
| apps/cli/src/constants.ts | Added lefthook version, removed husky from addon compatibility, added gitHooks to default config |
| apps/cli/README.md | Added Git Hooks feature row and --git-hooks flag documentation, removed husky from addons |
| README.md | Updated feature list to separate Git Hooks from Addons |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/cli/src/helpers/core/post-installation.ts (1)
8-47: Linting instructions gating likely misses oxlint-only setups
Right now you show linting instructions only when hooks are enabled or Biome addon is present. Ifoxlintis selected (and hooks arenone), users may still want the “runcheck” hint—consider includingaddons?.includes("oxlint")(or whatever set defines lint tooling).apps/cli/src/helpers/addons/ultracite-setup.ts (1)
133-205: Fix integration arguments format — must be comma-separated, not space-separatedAt lines 200–205, the integration arguments are passed as separate array elements, which produces space-separated CLI args:
- Current:
["--integrations", "husky", "lint-staged"]→--integrations husky lint-staged(incorrect)- Should be:
["--integrations", "husky,lint-staged"]→--integrations husky,lint-stagedUltracite CLI requires comma-separated values for the
--integrationsflag. The lefthook case works by accident (single value), but the husky case will fail to parse correctly.Additionally, per coding guidelines, replace
execawithBun.$template literal syntax (lines 214–218).
🧹 Nitpick comments (6)
apps/web/src/lib/stack-url-keys.ts (1)
17-17: Consider using an abbreviated URL key for consistency.Most URL keys in this mapping use abbreviations (e.g., "pm" for packageManager, "add" for addons, "ex" for examples). Using the full word "hooks" breaks this pattern. Consider shortening to "hk" or "h" to maintain consistency and keep URLs more compact.
- hooks: "hooks", + hooks: "hk",apps/cli/src/prompts/hooks.ts (1)
6-34: Optional: avoid unchecked cast on prompt result
IfHookscan be influenced by programmatic input or future option changes, consider validatingresponseagainst the allowed set before casting.apps/cli/src/helpers/addons/ultracite-setup.ts (1)
214-218: Avoidshell: true(and preferBun.$overexeca)
This is both against repo guidelines and needlessly risky; prefer direct exec with args (shell=false) orBun.$to avoid quoting/injection edge cases.apps/cli/test/addons.test.ts (1)
1-3: Repo guideline mismatch: tests use Vitest instead ofbun:test
If the project is standardizing on Bun’s test runner, this file is a candidate for later migration.apps/cli/src/helpers/hooks/hooks-setup.ts (2)
27-58: Reconsider lint-staged setup when no linter is configured.When
linteris undefined (lines 51-53), the code still installslint-stagedas a devDependency and configures it with an empty string command. This creates several issues:
- Empty string commands may not work correctly with lint-staged
- Installing lint-staged without a valid use case is wasteful
- Users get a partial/broken configuration
Consider either:
- Not installing lint-staged when no linter is configured
- Omitting the lint-staged configuration from package.json when no linter is present
- Setting up a sensible default command or documenting that users should configure it manually
await addPackageDependency({ - devDependencies: ["husky", "lint-staged"], + devDependencies: linter ? ["husky", "lint-staged"] : ["husky"], projectDir, }); const packageJsonPath = path.join(projectDir, "package.json"); if (await fs.pathExists(packageJsonPath)) { const packageJson = await fs.readJson(packageJsonPath); packageJson.scripts = { ...packageJson.scripts, prepare: "husky", }; - if (linter === "oxlint") { + if (linter) { + if (linter === "oxlint") { - packageJson["lint-staged"] = { - "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "oxlint", - }; + packageJson["lint-staged"] = { + "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "oxlint", + }; - } else if (linter === "biome") { + } else if (linter === "biome") { - packageJson["lint-staged"] = { - "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": ["biome check --write ."], - }; - } else { - packageJson["lint-staged"] = { - "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "", - }; + packageJson["lint-staged"] = { + "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": ["biome check --write ."], + }; + } } await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 }); }
60-106: Consider using lefthook's native features instead of lint-staged.According to the PR objectives, "Lefthook can use
stage_fixed: trueand does not require lint-staged." However, the current implementation still installs and configures lint-staged for lefthook (lines 62, 75-87).Additionally, when no linter is configured (lines 84-86), lint-staged is still installed with an empty string command, which may not work correctly.
Consider leveraging lefthook's native
stage_fixed: truefeature to avoid the lint-staged dependency, which would simplify the setup and align with the PR's stated design.Potential approach:
- Use lefthook's native
stage_fixed: truein the lefthook.yml template- Only install lint-staged if there's a specific need for it
- Generate lefthook.yml regardless of linter presence, with appropriate default configuration
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
lefthook.svgis excluded by!**/*.svg
📒 Files selected for processing (35)
apps/cli/README.md(1 hunks)apps/cli/src/constants.ts(2 hunks)apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/add-addons.ts(1 hunks)apps/cli/src/helpers/core/command-handlers.ts(1 hunks)apps/cli/src/helpers/core/create-project.ts(4 hunks)apps/cli/src/helpers/core/create-readme.ts(5 hunks)apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/helpers/core/template-manager.ts(1 hunks)apps/cli/src/helpers/hooks/hooks-setup.ts(1 hunks)apps/cli/src/index.ts(2 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/src/prompts/config-prompts.ts(5 hunks)apps/cli/src/prompts/hooks.ts(1 hunks)apps/cli/src/types.ts(5 hunks)apps/cli/src/utils/config-processing.ts(2 hunks)apps/cli/src/validation.ts(1 hunks)apps/cli/templates/hooks/lefthook/lefthook.yml.hbs(1 hunks)apps/cli/test/addons.test.ts(2 hunks)apps/cli/test/backend-runtime.test.ts(1 hunks)apps/cli/test/benchmark.test.ts(1 hunks)apps/cli/test/hooks.test.ts(1 hunks)apps/cli/test/integration.test.ts(4 hunks)apps/cli/test/test-utils.ts(2 hunks)apps/web/content/docs/cli/options.mdx(2 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(9 hunks)apps/web/src/lib/stack-url-keys.ts(1 hunks)apps/web/src/lib/stack-url-state.client.ts(1 hunks)apps/web/src/lib/stack-url-state.ts(1 hunks)apps/web/src/lib/stack-utils.ts(2 hunks)apps/web/src/lib/types.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (17)
- apps/cli/src/helpers/core/detect-project-config.ts
- apps/cli/src/constants.ts
- apps/cli/src/helpers/core/template-manager.ts
- apps/cli/src/types.ts
- apps/web/src/lib/stack-url-state.ts
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/src/prompts/addons.ts
- apps/cli/README.md
- apps/cli/src/helpers/core/add-addons.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/test/integration.test.ts
- apps/web/content/docs/project-structure.mdx
- apps/cli/test/test-utils.ts
- apps/web/src/lib/stack-url-state.client.ts
- apps/cli/test/backend-runtime.test.ts
- apps/web/content/docs/cli/options.mdx
- apps/web/src/lib/stack-utils.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/src/prompts/hooks.tsapps/cli/src/helpers/core/create-project.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/validation.tsapps/cli/test/benchmark.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/test/hooks.test.tsapps/web/src/lib/constant.tsapps/cli/src/utils/config-processing.tsapps/cli/src/index.tsapps/web/src/lib/types.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/src/prompts/hooks.tsapps/cli/src/helpers/core/create-project.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/validation.tsapps/cli/test/benchmark.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/test/hooks.test.tsapps/web/src/lib/constant.tsapps/cli/src/utils/config-processing.tsapps/cli/src/index.tsapps/web/src/lib/types.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/src/prompts/hooks.tsapps/cli/src/helpers/core/create-project.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/validation.tsapps/cli/test/benchmark.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/test/hooks.test.tsapps/web/src/lib/constant.tsapps/cli/src/utils/config-processing.tsapps/cli/src/index.tsapps/web/src/lib/types.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/src/prompts/hooks.tsapps/cli/src/helpers/core/create-project.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/validation.tsapps/cli/test/benchmark.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/test/hooks.test.tsapps/web/src/lib/constant.tsapps/cli/src/utils/config-processing.tsapps/cli/src/index.tsapps/web/src/lib/types.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/src/prompts/hooks.tsapps/cli/src/helpers/core/create-project.tsapps/cli/test/addons.test.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/validation.tsapps/cli/test/benchmark.test.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/command-handlers.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/test/hooks.test.tsapps/web/src/lib/constant.tsapps/cli/src/utils/config-processing.tsapps/cli/src/index.tsapps/web/src/lib/types.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/addons.test.tsapps/cli/test/benchmark.test.tsapps/cli/test/hooks.test.ts
**/*.hbs
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.hbs: In Handlebars templates, avoid generic if/else blocks. Write explicit conditions, such as: use if (eq orm "prisma") for Prisma, and else if (eq orm "drizzle") for Drizzle
Escape the '{{' in Handlebars templates like '{{'
Files:
apps/cli/templates/hooks/lefthook/lefthook.yml.hbs
🧠 Learnings (2)
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun:test` module with `test` and `expect` functions for writing tests
Applied to files:
apps/cli/test/hooks.test.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun test` instead of `jest` or `vitest` for running tests
Applied to files:
apps/cli/test/hooks.test.ts
🧬 Code graph analysis (6)
apps/cli/src/helpers/core/create-project.ts (2)
apps/cli/src/helpers/core/template-manager.ts (1)
setupHooksTemplate(599-607)apps/cli/src/helpers/hooks/hooks-setup.ts (1)
setupHooks(7-25)
apps/cli/src/helpers/addons/ultracite-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/cli/src/helpers/hooks/hooks-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/cli/test/hooks.test.ts (2)
apps/cli/src/types.ts (1)
Hooks(89-89)apps/cli/test/test-utils.ts (2)
runTRPCTest(58-161)expectSuccess(163-173)
apps/cli/src/utils/config-processing.ts (1)
apps/cli/src/types.ts (1)
Hooks(89-89)
apps/cli/src/index.ts (1)
apps/cli/src/types.ts (1)
HooksSchema(88-88)
🔇 Additional comments (22)
apps/web/src/lib/types.ts (1)
15-15: LGTM!The addition of "hooks" to the TechCategory union is clean and properly positioned between "packageManager" and "addons".
apps/web/src/lib/constant.ts (4)
472-497: Verify the missing icon for Husky.Lefthook has an icon defined (line 477), but Husky's icon is an empty string (line 485). Was this intentional, or should Husky have an icon as well? Consider checking if a Husky icon exists or should be added for UI consistency.
646-646: LGTM!All preset templates consistently set hooks to "lefthook", which showcases the new git hooks feature. This intentional deviation from the DEFAULT_STACK (which uses "none") helps promote the recommended option in the presets.
Also applies to: 673-673, 700-702, 727-727
752-752: LGTM!The hooks field is correctly typed as a string and properly positioned in the StackState type.
775-775: LGTM!The default value "none" for hooks aligns with the PR objectives and matches the default setting in TECH_OPTIONS.
apps/cli/src/helpers/core/command-handlers.ts (1)
82-113: Good: error-pathProjectConfignow includeshooks
Keeps the failure payload structurally consistent with the expanded config surface.apps/cli/src/helpers/addons/ultracite-setup.ts (1)
220-230: Dependency install branching looks consistent withhooks
Installing["husky","lint-staged"]vs["lefthook"]matches the newhooksselection model.apps/cli/test/addons.test.ts (1)
7-8: Good: Husky removed from addon coverage
These updates align with “hooks != addons” separation.Please ensure
runTRPCTest/TestConfigdefaultshooksto"none"(or updates all callers), otherwise these configs may start failing afterProjectConfig.hooksbecame required.Also applies to: 174-179
apps/cli/src/validation.ts (1)
7-22: Confirm intended UX:--yescan no longer be combined with--hooks
AddinghookstoCORE_STACK_FLAGSwill make--yes --hooks lefthookerror out. If you want “mostly defaults, but pick hooks”, you may want to treat hooks differently.apps/cli/templates/hooks/lefthook/lefthook.yml.hbs (1)
1-3: [rewritten review comment]
[classification tag]apps/web/content/docs/index.mdx (1)
313-315: No action needed. The docs correctly display--hooksas the flag name, which matches the actual CLI implementation defined in the codebase.apps/cli/test/benchmark.test.ts (1)
430-431: LGTM!The refactoring correctly moves "husky" from the addons array to a separate hooks field, aligning with the PR's objective to treat Git hooks as a first-class configuration option.
apps/cli/src/index.ts (2)
28-28: LGTM!The import correctly adds HooksSchema to support the new hooks configuration option.
89-89: LGTM!The hooks field is correctly added as an optional parameter to the CLI input schema, consistent with other optional configuration fields.
apps/cli/src/helpers/core/create-project.ts (3)
15-15: LGTM!The imports correctly add the necessary hooks setup functionality to the project creation workflow.
Also applies to: 34-34
64-64: LGTM!The template-based hooks setup is correctly invoked during project scaffolding. The function includes internal guards to handle the "none" case.
88-90: LGTM!The runtime hooks setup is correctly invoked only when hooks are configured and not set to "none", ensuring proper integration with the project creation flow.
apps/cli/src/utils/config-processing.ts (2)
9-9: LGTM!The import correctly adds the Hooks type for configuration processing.
90-92: LGTM!The hooks configuration is correctly processed and assigned to the config object, following the same pattern as other configuration options.
apps/cli/test/hooks.test.ts (1)
5-212: Comprehensive test coverage for hooks configurations.The test suite thoroughly covers all hooks options (husky, lefthook, none), integration with linters (biome, oxlint), combinations with addons, and default behavior. The test structure is well-organized and validates the new hooks feature effectively.
apps/cli/src/helpers/addons/addons-setup.ts (1)
63-63: LGTM!The simplified call to
setupUltracitecorrectly removes thehasHuskyparameter, aligning with the refactoring that moves Git hooks configuration to a dedicated subsystem.apps/cli/src/helpers/hooks/hooks-setup.ts (1)
7-25: LGTM!The
setupHooksfunction correctly determines the linter from addons and delegates to the appropriate hooks setup function based on the configuration.
1c8db0c to
ef64e1f
Compare
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/cli/README.md (2)
32-46: Add missing "Git Hooks" category to the Features table.The PR refactors Git hooks into their own section with a new
--hooksoption, but the Features table lacks a "Git Hooks" row. Additionally, line 44 still lists "Husky (Git hooks)" under Addons, which contradicts the PR objective to remove Husky from addons.Revise the Features table to:
- Add a new "Git Hooks" row (between existing categories and Addons) listing the options
- Remove "Husky (Git hooks)" from the Addons row
Apply this diff to add the Git Hooks category and update Addons:
| **Styling** | Tailwind CSS with shadcn/ui components | +| **Git Hooks** | • Lefthook<br>• Husky<br>• None | | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Husky (Git hooks)<br>• Turborepo (optimized builds) | +| **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Turborepo (optimized builds) |
196-196: Update Compatibility Notes to reflect Husky's relocation from addons.Line 196 references Husky as part of the Addons 'none' option, but Husky has been moved to the Git Hooks category. Update this reference for accuracy.
Apply this diff to correct the compatibility note:
- **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Husky, Turborepo). + **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Turborepo).
♻️ Duplicate comments (2)
apps/cli/README.md (1)
62-62: Fix inconsistent spacing in the--hooksoption description.The option has inconsistent alignment compared to other option descriptions. Align the description consistently with other options on this page.
Apply this diff to correct the spacing:
- --hooks <type> Git hooks manager (lefthook, husky, none) + --hooks <type> Git hooks manager (lefthook, husky, none)apps/cli/src/helpers/hooks/hooks-setup.ts (1)
60-106: Fix template/file I/O to be bundler-safe + align with Bun guidelines.
__dirname(Line 96) is brittle under bundling, andfs-extraread/write here conflicts with repo guidance to useBun.file()/Bun.write(). This was already flagged previously.Suggested direction:
-import fs from "fs-extra"; +import fs from "fs-extra"; ... - const templatePath = path.join(__dirname, "../../../templates/hooks/lefthook/lefthook.yml.hbs"); - const templateContent = await fs.readFile(templatePath, "utf-8"); + const templateUrl = new URL("../../../templates/hooks/lefthook/lefthook.yml.hbs", import.meta.url); + const templateContent = await Bun.file(templateUrl).text(); const template = Handlebars.compile(templateContent); ... - await fs.writeFile(lefthookYmlPath, lefthookYmlContent); + await Bun.write(lefthookYmlPath, lefthookYmlContent);Also, the current lefthook setup still installs/configures
lint-staged(Lines 61-87). If the intent is “lefthook doesn’t require lint-staged (stage_fixed: true + direct commands)”, consider removinglint-stagedentirely for lefthook and generating the lefthook config accordingly.Does Lefthook support staging fixed files via `stage_fixed: true`, and what is the recommended config pattern for running Biome (`biome check --write`) or Oxlint (`oxlint --fix`) on staged files without lint-staged?
🧹 Nitpick comments (2)
apps/web/src/lib/constant.ts (1)
740-761: TightenStackState["hooks"]fromstringto a union of allowed IDs.
Right now any string can flow through URL/state/config without a TS-level guard. Consider a literal union (or derive fromTECH_OPTIONS.hooks).Also applies to: 763-784
apps/cli/src/helpers/hooks/hooks-setup.ts (1)
7-25: Add an explicit fallback/guard for unknownhooksvalues.
SincesetupHooks()silently no-ops for unexpected values, consider anelsethat throws (or logs) to surface misconfigurations early.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
lefthook.svgis excluded by!**/*.svg
📒 Files selected for processing (35)
apps/cli/README.md(1 hunks)apps/cli/src/constants.ts(2 hunks)apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/add-addons.ts(1 hunks)apps/cli/src/helpers/core/command-handlers.ts(1 hunks)apps/cli/src/helpers/core/create-project.ts(4 hunks)apps/cli/src/helpers/core/create-readme.ts(5 hunks)apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/helpers/core/template-manager.ts(1 hunks)apps/cli/src/helpers/hooks/hooks-setup.ts(1 hunks)apps/cli/src/index.ts(2 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/src/prompts/config-prompts.ts(5 hunks)apps/cli/src/prompts/hooks.ts(1 hunks)apps/cli/src/types.ts(1 hunks)apps/cli/src/utils/config-processing.ts(2 hunks)apps/cli/src/validation.ts(1 hunks)apps/cli/templates/hooks/lefthook/lefthook.yml.hbs(1 hunks)apps/cli/test/addons.test.ts(2 hunks)apps/cli/test/backend-runtime.test.ts(1 hunks)apps/cli/test/benchmark.test.ts(1 hunks)apps/cli/test/hooks.test.ts(1 hunks)apps/cli/test/integration.test.ts(4 hunks)apps/cli/test/test-utils.ts(2 hunks)apps/web/content/docs/cli/options.mdx(2 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(9 hunks)apps/web/src/lib/stack-url-keys.ts(1 hunks)apps/web/src/lib/stack-url-state.client.ts(1 hunks)apps/web/src/lib/stack-url-state.ts(1 hunks)apps/web/src/lib/stack-utils.ts(2 hunks)apps/web/src/lib/types.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (20)
- apps/cli/templates/hooks/lefthook/lefthook.yml.hbs
- apps/cli/src/helpers/core/command-handlers.ts
- apps/web/content/docs/index.mdx
- apps/cli/test/addons.test.ts
- apps/cli/src/helpers/addons/ultracite-setup.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/src/helpers/core/detect-project-config.ts
- apps/cli/src/prompts/hooks.ts
- apps/cli/test/hooks.test.ts
- apps/web/src/lib/stack-utils.ts
- apps/cli/test/backend-runtime.test.ts
- apps/cli/src/helpers/core/create-project.ts
- apps/cli/src/constants.ts
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/src/helpers/core/post-installation.ts
- apps/cli/src/index.ts
- apps/cli/src/validation.ts
- apps/web/src/lib/types.ts
- apps/web/content/docs/cli/options.mdx
- apps/cli/src/helpers/addons/addons-setup.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/src/utils/config-processing.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/test/integration.test.tsapps/cli/test/benchmark.test.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/test/test-utils.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/src/helpers/core/template-manager.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/types.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/src/utils/config-processing.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/test/integration.test.tsapps/cli/test/benchmark.test.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/test/test-utils.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/src/helpers/core/template-manager.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/types.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/src/utils/config-processing.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/test/integration.test.tsapps/cli/test/benchmark.test.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/test/test-utils.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/src/helpers/core/template-manager.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/types.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/src/utils/config-processing.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/test/integration.test.tsapps/cli/test/benchmark.test.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/test/test-utils.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/src/helpers/core/template-manager.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/types.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/src/utils/config-processing.tsapps/cli/src/prompts/addons.tsapps/web/src/lib/stack-url-state.tsapps/cli/src/helpers/core/add-addons.tsapps/cli/test/integration.test.tsapps/cli/test/benchmark.test.tsapps/web/src/lib/stack-url-state.client.tsapps/cli/test/test-utils.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/hooks/hooks-setup.tsapps/cli/src/helpers/core/template-manager.tsapps/web/src/lib/stack-url-keys.tsapps/cli/src/types.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/integration.test.tsapps/cli/test/benchmark.test.ts
🧠 Learnings (8)
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use `bun:test` module with `test` and `expect` functions for writing tests
Applied to files:
apps/cli/test/test-utils.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` template literal syntax instead of `execa` for shell command execution
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:47:42.038Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/better-t-stack-repo.mdc:0-0
Timestamp: 2025-12-03T07:47:42.038Z
Learning: Applies to **/*.hbs : In Handlebars templates, avoid generic if/else blocks. Write explicit conditions, such as: use if (eq orm "prisma") for Prisma, and else if (eq orm "drizzle") for Drizzle
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Prefer `Bun.file` over `node:fs` readFile/writeFile methods
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `bun <file>` instead of `node <file>` or `ts-node <file>` for running TypeScript/JavaScript files
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx,css} : Use `bun build <file>` instead of `webpack` or `esbuild` for bundling TypeScript, JavaScript, and CSS files
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Bun automatically loads .env files, so don't use the dotenv package
Applied to files:
apps/cli/src/helpers/hooks/hooks-setup.ts
📚 Learning: 2025-12-03T07:48:14.714Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-12-03T07:48:14.714Z
Learning: Applies to convex/schema.ts : Always define your schema in convex/schema.ts and import schema definition functions from convex/server
Applied to files:
apps/cli/src/types.ts
🧬 Code graph analysis (7)
apps/cli/src/utils/config-processing.ts (1)
apps/cli/src/types.ts (1)
Hooks(89-89)
apps/web/src/lib/stack-url-state.ts (1)
apps/web/src/lib/constant.ts (2)
StackState(740-761)DEFAULT_STACK(763-784)
apps/web/src/lib/stack-url-state.client.ts (1)
apps/web/src/lib/constant.ts (2)
StackState(740-761)DEFAULT_STACK(763-784)
apps/cli/test/test-utils.ts (1)
apps/cli/src/types.ts (1)
Hooks(89-89)
apps/cli/src/helpers/hooks/hooks-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/cli/src/helpers/core/template-manager.ts (3)
apps/cli/src/types.ts (1)
ProjectConfig(167-188)packages/types/src/types.ts (1)
ProjectConfig(50-50)apps/cli/src/constants.ts (1)
PKG_ROOT(7-7)
apps/cli/src/types.ts (2)
packages/types/src/schemas.ts (17)
DatabaseSchema(4-6)ORMSchema(8-8)BackendSchema(10-12)RuntimeSchema(14-16)FrontendSchema(18-32)AddonsSchema(34-48)ExamplesSchema(50-52)PackageManagerSchema(54-54)DatabaseSetupSchema(56-68)APISchema(70-70)AuthSchema(72-74)PaymentsSchema(76-76)ProjectNameSchema(90-104)WebDeploySchema(78-78)ServerDeploySchema(80-80)DirectoryConflictSchema(82-84)TemplateSchema(86-88)packages/types/src/types.ts (23)
Database(29-29)ORM(30-30)Backend(31-31)Runtime(32-32)Frontend(33-33)Addons(34-34)Examples(35-35)PackageManager(36-36)DatabaseSetup(37-37)API(38-38)Auth(39-39)Payments(40-40)ProjectName(45-45)WebDeploy(41-41)ServerDeploy(42-42)DirectoryConflict(43-43)Template(44-44)CreateInput(47-47)AddInput(48-48)CLIInput(49-49)ProjectConfig(50-50)BetterTStackConfig(51-51)InitResult(52-52)
🔇 Additional comments (18)
apps/cli/src/prompts/addons.ts (1)
66-66: The removal of "husky" from ADDON_GROUPS.Other is correct and complete.The refactoring successfully migrates Git hooks into a separate category. Verification confirms:
AddonsSchema(types.ts) no longer includes "husky"HooksSchema(types.ts) properly defines "husky" as a Git hooks option- All hooks implementations (hooks.ts, hooks-setup.ts) correctly handle husky
- No remaining addon-related references to husky exist
apps/cli/src/helpers/core/add-addons.ts (1)
53-53: LGTM!The hooks field initialization follows the established pattern for other configuration fields (database, orm, backend, etc.), with proper fallback handling:
input.hooks || detectedConfig.hooks || "none".apps/cli/src/types.ts (3)
1-122: Major refactoring: Re-exports replaced with inline schema definitions.This file was completely rewritten to define all schemas inline instead of re-exporting from
@better-t-stack/types. The schemas match the original definitions frompackages/types/src/schemas.ts, ensuring consistency.Note:
"husky"was intentionally removed fromAddonsSchema(lines 38-51) as it's now managed through the newHooksSchema, aligning with the PR's objective to separate Git hooks into their own configuration section.
88-89: New HooksSchema introduced for Git hooks management.The new
HooksSchemawith values["husky", "lefthook", "none"]correctly implements the PR's objective to add a first-class--hooksflag. This separates Git hooks configuration from the addons system.
124-219: Type definitions updated to include hooks field.The
hooksfield has been consistently added to all relevant type definitions:
CreateInput(line 150)AddInput(line 160)ProjectConfig(line 187)BetterTStackConfig(line 207)This ensures type safety across the CLI for the new Git hooks feature.
apps/cli/test/test-utils.ts (2)
7-7: LGTM!The
Hookstype import is correctly added to support the new hooks field in test configurations.
113-113: LGTM!The default
hooks: "none"value in test utilities is appropriate and consistent with other test defaults (auth: "none",payments: "none", etc.). This ensures tests don't inadvertently configure Git hooks unless explicitly specified.apps/cli/test/benchmark.test.ts (1)
430-431: LGTM!The test correctly reflects the architectural change where Husky is now configured via the
hooksfield instead of theaddonsarray. This aligns with the PR's objective to separate Git hooks into their own configuration section.apps/cli/src/helpers/core/template-manager.ts (1)
604-612: LGTM!The
setupHooksTemplatefunction follows the established pattern used bysetupPaymentsTemplate(lines 533-602) andsetupAuthTemplate(lines 289-531):
- Early return when hooks are not configured
- Path construction following template directory conventions
- Reuses existing
processAndCopyFileshelperThis provides a clean integration point for copying hook-specific templates from
templates/hooks/${context.hooks}to the project directory.apps/web/src/lib/stack-url-state.client.ts (1)
35-37: LGTM!The hooks parser is correctly integrated into
stackParsersfollowing the established pattern:
- Uses
parseAsStringEnumwith type-safeStackState["hooks"]- Retrieves valid values via
getValidIds("hooks")- Defaults to
DEFAULT_STACK.hooks(which is"none"per constant.ts line 774)apps/cli/src/utils/config-processing.ts (2)
9-9: LGTM!The
Hookstype import is correctly added to support hooks processing in theprocessFlagsfunction.
90-92: LGTM!The hooks processing logic follows the established pattern used for other single-value configuration options (auth, payments, backend, etc.):
- Conditional check for
options.hooks- Type assertion to
Hooks- Direct assignment to
config.hooksapps/web/src/lib/stack-url-keys.ts (1)
17-17: LGTM!The
hooks: "hooks"mapping is correctly added tostackUrlKeys. The full name "hooks" is used as the URL key, which is consistent with other short keys like"git"and"yolo"that also use their full names rather than abbreviations.apps/web/src/lib/stack-url-state.ts (1)
49-51: Hooks URL parsing wiring looks consistent with existing enums.
Adds server-side validation + defaulting forhooksin the same style asruntime/backend/..., so load/serialize should stay predictable.apps/web/src/lib/constant.ts (2)
472-497: Good separation: hooks moved to its own TECH_OPTIONS category.
The defaults (none) and option IDs look aligned with the intended{ lefthook, husky, none }.
646-647: Presets explicitly settinghooks: "lefthook"is clear and deterministic.Also applies to: 673-674, 700-703, 727-728
apps/web/content/docs/project-structure.mdx (1)
257-260: Docs update matches the new config surface (hooksseparated fromaddons).
Thehooksenum in thebts.jsoncexample aligns with the PR’s{ lefthook, husky, none }shape.apps/cli/test/integration.test.ts (1)
38-40: Integration tests correctly migrated fromaddons: [..., "husky"]tohooks: "husky".Also applies to: 186-188, 273-275, 472-474
ef64e1f to
e39188a
Compare
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cli/src/helpers/addons/addons-setup.ts (1)
130-165:setupGitHooksincorrectly installslint-stagedfor Lefthook and writes invalid empty string commands.
- Line 136: always installs
lint-stagedeven when using Lefthook.lint-stagedis only applicable to Husky; Lefthook requires separate configuration.- Lines 158–161: writes an empty string
""as the lint command forlint-staged, which will cause lint-staged to fail.- Line 131: use a type alias
type GitHook = "husky" | "lefthook";instead ofstring(per coding guidelines for TypeScript).Suggested fix: split into conditional branches—only add
lint-stagedfor Husky, and create alefthook.ymlfor Lefthook with proper lint commands. For the no-linter case with Husky, omitlint-stagedentirely rather than setting an empty command.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
README.md(1 hunks)apps/cli/README.md(3 hunks)apps/cli/src/constants.ts(1 hunks)apps/cli/src/helpers/addons/addons-setup.ts(3 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/helpers/core/create-readme.ts(1 hunks)apps/cli/src/helpers/core/post-installation.ts(2 hunks)apps/cli/src/prompts/addons.ts(2 hunks)apps/cli/templates/addons/ruler/.ruler/bts.md.hbs(1 hunks)apps/cli/test/addons.test.ts(1 hunks)apps/web/content/docs/cli/options.mdx(1 hunks)apps/web/content/docs/index.mdx(1 hunks)apps/web/content/docs/project-structure.mdx(1 hunks)apps/web/src/lib/constant.ts(1 hunks)apps/web/src/lib/stack-utils.ts(1 hunks)packages/types/src/schemas.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/cli/templates/addons/ruler/.ruler/bts.md.hbs
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/web/src/lib/stack-utils.ts
- apps/cli/src/constants.ts
- apps/web/content/docs/cli/options.mdx
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/src/helpers/core/post-installation.ts
- apps/cli/src/helpers/addons/ultracite-setup.ts
- apps/web/content/docs/index.mdx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/test/addons.test.tspackages/types/src/schemas.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/prompts/addons.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/test/addons.test.tspackages/types/src/schemas.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/prompts/addons.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/test/addons.test.tspackages/types/src/schemas.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/prompts/addons.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.test.{ts,tsx,js,jsx}: Usebun testinstead ofjestorvitestfor running tests
Usebun:testmodule withtestandexpectfunctions for writing tests
Files:
apps/cli/test/addons.test.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/test/addons.test.tspackages/types/src/schemas.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/prompts/addons.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/test/addons.test.tspackages/types/src/schemas.tsapps/web/src/lib/constant.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/prompts/addons.ts
🔇 Additional comments (6)
README.md (1)
47-48: Docs: Lefthook addition looks consistent with the features list.
No issues with the wording/placement; it matches the “Addons” concept used elsewhere.apps/cli/README.md (1)
44-45: Docs: “Lefthook, Husky (Git hooks)” grouping is clear.
Good consolidation under Addons in the feature table.packages/types/src/schemas.ts (1)
34-49: Schema update (AddonsSchema): LGTM addinglefthook.
This keeps runtime validation aligned with the CLI/web surfaces.apps/cli/src/prompts/addons.ts (2)
46-49: Prompt display for Lefthook: good label/hint.
No issues with the new case branch.
70-74: Addon grouping: Lefthook placement under “Other” makes sense.
Matches the “Git hooks manager” framing used in docs.apps/web/content/docs/project-structure.mdx (1)
257-258: Docs (bts.jsonc snippet): addons list including Lefthook is fine.
No concerns with the snippet change itself.
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.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (2)
apps/cli/test/addons.test.ts:30
- Missing test coverage for the mutual exclusivity of lefthook and husky. Since the PR description states "You can only select one of { lefthook, husky }", there should be a test case that verifies selecting both addons results in an error. This should be added once the validation is implemented.
describe("Universal Addons (no frontend restrictions)", () => {
const universalAddons = ["biome", "lefthook", "husky", "turborepo", "oxlint"];
for (const addon of universalAddons) {
it(`should work with ${addon} addon on any frontend`, async () => {
const result = await runTRPCTest({
projectName: `${addon}-universal`,
addons: [addon as Addons],
frontend: ["tanstack-router"],
backend: "hono",
runtime: "bun",
database: "sqlite",
orm: "drizzle",
auth: "none",
api: "trpc",
examples: ["none"],
dbSetup: "none",
webDeploy: "none",
serverDeploy: "none",
install: false,
});
expectSuccess(result);
});
}
apps/cli/src/helpers/addons/addons-setup.ts:161
- The lint-staged configuration in package.json is only used by Husky, not Lefthook. When gitHook is "lefthook", this configuration should not be added to package.json since Lefthook uses its own lefthook.yml configuration file with
stage_fixed: true. This creates unnecessary configuration that won't be used.
if (linter === "oxlint") {
packageJson["lint-staged"] = {
"**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "oxlint",
};
} else if (linter === "biome") {
packageJson["lint-staged"] = {
"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": ["biome check --write ."],
};
} else {
packageJson["lint-staged"] = {
"**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "",
};
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@coderabbitai rereview this PR again |
|
@therealsamyak I'll review the changes in this PR for you. ✅ Actions performedReview triggered.
|
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: 5
♻️ Duplicate comments (2)
apps/cli/src/prompts/addons.ts (1)
70-74: Consider creating a dedicated "Git Hooks" category as indicated by the PR title.The PR title states "refactor out Git hooks to their own section," but Lefthook and Husky remain in the "Other" category. Creating a separate "Git Hooks" group would improve organization, make the mutual exclusivity clearer, and better align with the PR's stated goal.
Apply this diff:
const ADDON_GROUPS = { Documentation: ["starlight", "fumadocs"], Linting: ["biome", "oxlint", "ultracite"], + "Git Hooks": ["lefthook", "husky"], - Other: ["ruler", "turborepo", "pwa", "tauri", "lefthook", "husky"], + Other: ["ruler", "turborepo", "pwa", "tauri"], };Don't forget to update the
groupedOptionsinitialization in bothgetAddonsChoiceandgetAddonsToAddto include the new group:const groupedOptions: Record<string, AddonOption[]> = { Documentation: [], Linting: [], + "Git Hooks": [], Other: [], };And update the group assignment logic in both functions:
if (ADDON_GROUPS.Documentation.includes(addon)) { groupedOptions.Documentation.push(option); } else if (ADDON_GROUPS.Linting.includes(addon)) { groupedOptions.Linting.push(option); + } else if (ADDON_GROUPS["Git Hooks"].includes(addon)) { + groupedOptions["Git Hooks"].push(option); } else if (ADDON_GROUPS.Other.includes(addon)) { groupedOptions.Other.push(option); }apps/cli/src/helpers/addons/addons-setup.ts (1)
61-65: Enforce mutual exclusion: validate that only one git hooks manager is selected.The current ternary logic silently prefers Husky when both
huskyandlefthookare present in the addons array. According to the PR objectives, "only one of {lefthook, husky} may be selected." WhilegetCompatibleAddonsprevents this in interactive mode, CLI flag usage like--addons husky,lefthookbypasses this check.Add explicit validation to detect and reject both selections:
+ const hasHusky = addons.includes("husky"); + const hasLefthook = addons.includes("lefthook"); + if (hasHusky && hasLefthook) { + throw new Error("Only one git hooks manager can be selected: husky or lefthook."); + } - const gitHook = addons.includes("husky") - ? "husky" - : addons.includes("lefthook") - ? "lefthook" - : ""; + const gitHook = hasHusky ? "husky" : hasLefthook ? "lefthook" : "";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/cli/src/helpers/addons/addons-setup.ts(2 hunks)apps/cli/src/helpers/addons/ultracite-setup.ts(3 hunks)apps/cli/src/prompts/addons.ts(3 hunks)apps/cli/src/utils/compatibility-rules.ts(1 hunks)apps/web/src/app/(home)/new/_components/utils.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cli/src/helpers/addons/ultracite-setup.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/web/src/app/(home)/new/_components/utils.tsapps/cli/src/utils/compatibility-rules.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/web/src/app/(home)/new/_components/utils.tsapps/cli/src/utils/compatibility-rules.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/web/src/app/(home)/new/_components/utils.tsapps/cli/src/utils/compatibility-rules.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/web/src/app/(home)/new/_components/utils.tsapps/cli/src/utils/compatibility-rules.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/web/src/app/(home)/new/_components/utils.tsapps/cli/src/utils/compatibility-rules.tsapps/cli/src/prompts/addons.tsapps/cli/src/helpers/addons/addons-setup.ts
🧬 Code graph analysis (1)
apps/cli/src/helpers/addons/addons-setup.ts (2)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
setupUltracite(133-228)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
🔇 Additional comments (2)
apps/cli/src/utils/compatibility-rules.ts (1)
253-259: LGTM: Mutual exclusion logic correctly filters interactive addon options.The skip logic properly prevents users from selecting both
huskyandlefthookduring interactive prompts by checking theexistingAddonsparameter. This aligns with the PR requirement that "only one may be selected."Note: This handles the interactive prompt scenario. CLI flag validation (e.g.,
--addons husky,lefthook) should be addressed inaddons-setup.tsas noted in the separate comment on that file.apps/cli/src/prompts/addons.ts (1)
46-49: LGTM: Lefthook display case added correctly.The display case for lefthook is properly implemented with an appropriate label and the GitHub description hint as mentioned in the PR objectives.
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: 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/cli/src/constants.ts(2 hunks)apps/cli/test/addons.test.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/cli/test/addons.test.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/src/constants.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/src/constants.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/src/constants.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/src/constants.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/src/constants.ts
🔇 Additional comments (1)
apps/cli/src/constants.ts (1)
182-182: LGTM!The lefthook entry in ADDON_COMPATIBILITY is correctly configured with an empty array, making it compatible with all frontend options—consistent with how husky is configured.
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.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
6c0363f to
de512e4
Compare
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: 1
♻️ Duplicate comments (1)
apps/cli/src/helpers/addons/addons-setup.ts (1)
181-204: Consider completing Lefthook configuration with linter support and lefthook.yml generation.The current
setupLefthookimplementation installs the package and configures the prepare script but doesn't generatelefthook.ymlwith linter-specific hooks. According to the PR objectives: "Lefthook setup: adds template lefthook.yml with commands auto-populated for Biome/Oxlint."This was extensively discussed in previous reviews, and the author noted it as a future improvement. However, to complete the Lefthook integration:
- Add a
linterparameter to matchsetupHusky's signature- Generate
lefthook.ymlwith pre-commit hooks configured for the detected linter🔎 Suggested implementation
-export async function setupLefthook(projectDir: string) { +export async function setupLefthook(projectDir: string, linter?: "biome" | "oxlint") { await addPackageDependency({ devDependencies: ["lefthook"], projectDir, }); const packageJsonPath = path.join(projectDir, "package.json"); if (await fs.pathExists(packageJsonPath)) { const packageJson = await fs.readJson(packageJsonPath); // Check if husky is also present and update prepare script accordingly const currentPrepare = packageJson.scripts?.prepare; const prepareScript = currentPrepare?.includes("husky") ? `lefthook install && ${currentPrepare}` : "lefthook install"; packageJson.scripts = { ...packageJson.scripts, prepare: prepareScript, }; await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 }); } + + // Generate lefthook.yml if linter is configured + if (linter) { + const lefthookConfigPath = path.join(projectDir, "lefthook.yml"); + let command = ""; + + if (linter === "biome") { + command = "biome check --write ."; + } else if (linter === "oxlint") { + command = "oxlint && oxfmt --write"; + } + + const lefthookConfig = `pre-commit: + commands: + lint: + glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" + run: ${command} + stage_fixed: true +`; + + await fs.writeFile(lefthookConfigPath, lefthookConfig, "utf-8"); + } }Then update the call site at line 86:
if (hasLefthook) { - await setupLefthook(projectDir); + await setupLefthook(projectDir, linter); }This would eliminate the need for lint-staged when using Lefthook (since
stage_fixed: truehandles that natively) and provide a complete, working git hooks setup.
🧹 Nitpick comments (1)
apps/cli/src/helpers/addons/addons-setup.ts (1)
63-70: Consider enforcing mutual exclusion between Husky and Lefthook.The current implementation allows both
huskyandlefthookto be selected simultaneously (lines 67-70 build an array that can contain both). According to the PR objectives, "one of {lefthook, husky} is intended."While the code handles the dual-selection case by coordinating prepare scripts, this may lead to user confusion. Consider adding validation to enforce selecting only one git hooks manager, similar to how other addon conflicts are handled.
Based on PR comments, this improvement has been deferred to a follow-up PR. However, adding validation would improve the user experience by preventing potentially confusing configurations.
🔎 Example validation approach
const hasUltracite = addons.includes("ultracite"); const hasBiome = addons.includes("biome"); const hasHusky = addons.includes("husky"); const hasLefthook = addons.includes("lefthook"); const hasOxlint = addons.includes("oxlint"); + + if (hasHusky && hasLefthook && !hasUltracite) { + log.error("Only one git hooks manager can be selected: husky or lefthook."); + process.exit(1); + }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
README.mdapps/cli/README.mdapps/cli/src/constants.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/prompts/addons.tsapps/cli/templates/addons/lefthook/lefthook.yml.hbsapps/cli/templates/addons/ruler/.ruler/bts.md.hbsapps/cli/test/addons.test.tsapps/web/content/docs/cli/options.mdxapps/web/content/docs/index.mdxapps/web/content/docs/project-structure.mdxapps/web/src/lib/constant.tsapps/web/src/lib/stack-utils.tspackages/types/src/schemas.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- apps/cli/src/helpers/core/template-manager.ts
- apps/cli/README.md
- apps/cli/src/constants.ts
- apps/cli/templates/addons/lefthook/lefthook.yml.hbs
- apps/cli/src/prompts/addons.ts
- apps/cli/test/addons.test.ts
- packages/types/src/schemas.ts
- README.md
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/constant.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/web/src/lib/stack-utils.tsapps/web/src/lib/constant.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:55.011Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, the Ultracite CLI's `--integrations` flag requires git hooks to be passed as a single space-separated string (e.g., `gitHooks.join(" ")`) rather than using the spread operator like other Ultracite flags. This has been tested and confirmed to work.
📚 Learning: 2025-12-18T19:15:55.011Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:55.011Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, the Ultracite CLI's `--integrations` flag requires git hooks to be passed as a single space-separated string (e.g., `gitHooks.join(" ")`) rather than using the spread operator like other Ultracite flags. This has been tested and confirmed to work.
Applied to files:
apps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/core/post-installation.tsapps/web/content/docs/project-structure.mdxapps/web/content/docs/index.mdxapps/web/content/docs/cli/options.mdxapps/web/src/lib/stack-utils.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to package.json : Use `bun run <script>` instead of `npm run <script>`, `yarn run <script>`, or `pnpm run <script>`
Applied to files:
apps/cli/src/helpers/core/post-installation.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to {package.json,bun.lockb} : Use `bun install` instead of `npm install`, `yarn install`, or `pnpm install`
Applied to files:
apps/cli/src/helpers/core/post-installation.ts
📚 Learning: 2025-12-18T19:15:48.478Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:48.478Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when passing the Ultracite CLI --integrations flag, supply git hooks as a single space-separated string (e.g., gitHooks.join(" ")) rather than spreading the array like other Ultracite flags. This has been tested and confirmed to work. Ensure the code uses a single string created by joining the gitHooks array with spaces for the --integrations argument.
Applied to files:
apps/cli/src/helpers/addons/ultracite-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` template literal syntax instead of `execa` for shell command execution
Applied to files:
apps/cli/src/helpers/addons/ultracite-setup.ts
🧬 Code graph analysis (1)
apps/cli/src/helpers/addons/addons-setup.ts (2)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
setupUltracite(133-228)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
🔇 Additional comments (12)
apps/web/src/lib/stack-utils.ts (1)
108-108: LGTM!The addition of "lefthook" to the allowed addons filter is correct and positioned logically between biome and husky.
apps/cli/templates/addons/ruler/.ruler/bts.md.hbs (1)
119-119: LGTM!The template correctly adds Lefthook to the "Other" addons list alongside Husky, maintaining consistency in the generated documentation.
apps/cli/src/helpers/core/post-installation.ts (2)
30-34: LGTM!The renamed constant
hasGitHooksOrLintingaccurately reflects its purpose and correctly includes lefthook alongside other git hooks and linting tools. The variable name is clear and self-documenting.
51-51: LGTM!The condition correctly uses
hasGitHooksOrLintingto determine when to display linting instructions, which is appropriate since both git hooks tools and linters can provide linting capabilities.apps/web/content/docs/project-structure.mdx (1)
262-262: LGTM!The documentation correctly adds "lefthook" as a possible value in the addons array, maintaining consistency with the existing addon options format.
apps/web/src/lib/constant.ts (1)
505-512: LGTM!The Lefthook addon entry is well-structured with all required fields. The description accurately describes Lefthook as a "Fast and powerful Git hooks manager", and the color scheme is visually distinct from other addons.
apps/web/content/docs/index.mdx (1)
313-313: LGTM!The documentation correctly adds "lefthook" to the
--addonsflag options, positioned logically between biome and husky. The format is consistent with other addon options.apps/web/content/docs/cli/options.mdx (1)
255-255: LGTM!The documentation entry for Lefthook is clear, concise, and follows the established format. The description "Git hooks with Lefthook" accurately conveys the addon's purpose.
apps/cli/src/helpers/core/create-readme.ts (1)
464-465: LGTM!The Lefthook entry in the features list is correctly implemented and consistent with other addon entries. The description matches the one used elsewhere in the codebase, maintaining consistency.
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
133-133: LGTM: Function signature correctly updated for multi-hook support.The signature change from
hasHusky: booleantogitHooks: string[]properly supports the new design where multiple git hook managers can be tracked and passed to Ultracite.apps/cli/src/helpers/addons/addons-setup.ts (2)
75-88: LGTM: Conditional setup logic correctly handles both Husky and Lefthook.The updated logic properly:
- Detects when either Husky or Lefthook are present (line 75)
- Determines the appropriate linter (lines 76-81)
- Calls each setup function independently (lines 82-87)
Note: The missing linter parameter for
setupLefthookis addressed in a separate comment on that function.
152-160: LGTM: Prepare script coordination handles Lefthook coexistence correctly.The updated logic (lines 152-156) properly detects when Lefthook is already configured and appends Husky's initialization, resulting in a combined prepare script like:
"prepare": "lefthook install && husky"This ensures both tools are initialized correctly when selected together.
| if (gitHooks.length > 0) { | ||
| ultraciteArgs.push("--integrations", gitHooks.join(" ")); | ||
| if (gitHooks.includes("husky")) { | ||
| ultraciteArgs.push("lint-staged"); | ||
| } | ||
| } |
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.
🧩 Analysis chain
🏁 Script executed:
# Search for Ultracite CLI documentation or comments
rg -i "ultracite|--integrations" --type ts --type tsx -B 2 -A 2 | head -100Repository: AmanVarshney01/create-better-t-stack
Length of output: 107
🏁 Script executed:
# Look for test files related to ultracite-setup
fd -e test -e spec | grep -i ultraciteRepository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Search for any README or documentation about Ultracite CLI
fd -e md -e txt | xargs rg -l "ultracite" -i 2>/dev/nullRepository: AmanVarshney01/create-better-t-stack
Length of output: 108
🏁 Script executed:
# Look for ultracite package.json or dependencies
rg -r "ultracite" package.jsonRepository: AmanVarshney01/create-better-t-stack
Length of output: 5094
🏁 Script executed:
# Read the ultracite-setup.ts file to see the full context
cat -n apps/cli/src/helpers/addons/ultracite-setup.ts | head -250Repository: AmanVarshney01/create-better-t-stack
Length of output: 6769
🏁 Script executed:
# Search for other usages of --integrations in the codebase
rg "\-\-integrations" --type ts -B 3 -A 3Repository: AmanVarshney01/create-better-t-stack
Length of output: 601
🏁 Script executed:
# Look at the CLI README for documentation
cat -n apps/cli/README.mdRepository: AmanVarshney01/create-better-t-stack
Length of output: 12774
🏁 Script executed:
# Search for tests related to ultracite-setup
fd -type f -name "*.test.*" -o -name "*.spec.*" | xargs rg -l "ultracite" 2>/dev/nullRepository: AmanVarshney01/create-better-t-stack
Length of output: 670
🏁 Script executed:
# Search for any comments or documentation about the integrations flag
rg "integrations" --type ts -B 5 -A 5Repository: AmanVarshney01/create-better-t-stack
Length of output: 871
🏁 Script executed:
# Look for Ultracite documentation or example usage
fd -type f \( -name "*.md" -o -name "*.txt" \) -exec rg -l "integrations" {} \;Repository: AmanVarshney01/create-better-t-stack
Length of output: 250
🏁 Script executed:
# Check if there's any external documentation link or reference
rg -i "ultracite.*cli\|ultracite.*doc" --type ts -B 2 -A 2Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Check the test file for ultracite usage patterns
cat -n apps/cli/test/addons.test.ts | grep -A 30 -B 5 ultraciteRepository: AmanVarshney01/create-better-t-stack
Length of output: 1469
🏁 Script executed:
# Search in the addons.ts prompts file
cat -n apps/cli/src/prompts/addons.ts | grep -A 10 -B 10 -i "git\|hook"Repository: AmanVarshney01/create-better-t-stack
Length of output: 4482
🏁 Script executed:
# Look at the actual command construction logic more carefully
rg "ultraciteArgs\|ultraciteInit" -B 3 -A 3Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Search for any Ultracite CLI documentation or references in the web content
cat -n apps/web/content/docs/cli/options.mdx | head -100Repository: AmanVarshney01/create-better-t-stack
Length of output: 2889
🏁 Script executed:
# Look for any git hook related tests or examples
rg "git.*hook\|husky\|lefthook" apps/cli/test/ -A 5 -B 5Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Check if there's any config or setup files that show ultracite usage
fd -name "ultracite*" -o -name "*ultracite*"Repository: AmanVarshney01/create-better-t-stack
Length of output: 310
🏁 Script executed:
# Search for any comments about lint-staged or integrations flag
rg "lint-staged\|integrations" apps/cli/src/helpers/addons/ -B 5 -A 5Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Look for any Ultracite package references or documentation links
rg "ultracite" apps/cli/src/ -lRepository: AmanVarshney01/create-better-t-stack
Length of output: 273
🏁 Script executed:
# Check if there's any commented out code or alternative approaches
rg "integrations|lint-staged" apps/cli/ -B 2 -A 2Repository: AmanVarshney01/create-better-t-stack
Length of output: 2698
🏁 Script executed:
# Look for how git hooks are configured in the project
rg "husky\|lefthook" apps/cli/src/helpers/addons/ -B 3 -A 3Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Check if there are any examples or configurations showing ultracite init usage
rg "ultracite.*init\|init.*ultracite" apps/cli/ -B 2 -A 2Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Search for any PR or commit messages that might explain the lint-staged logic
git log --oneline --all | head -50Repository: AmanVarshney01/create-better-t-stack
Length of output: 2527
🏁 Script executed:
# Look for the commit that added ultracite setup
git log --oneline --all | grep -i ultraciteRepository: AmanVarshney01/create-better-t-stack
Length of output: 764
🏁 Script executed:
# Check the PR #711 or related commits for context
git log --oneline --all | head -100 | grep -i "ultracite\|711"Repository: AmanVarshney01/create-better-t-stack
Length of output: 275
🏁 Script executed:
# Search for any integration related to the actual ultracite command
rg "getPackageExecutionCommand" apps/cli/src/helpers/addons/ultracite-setup.ts -B 10 -A 10Repository: AmanVarshney01/create-better-t-stack
Length of output: 1229
🏁 Script executed:
# Look at what the final command string looks like
rg "ultraciteArgsString\|commandWithArgs" apps/cli/src/helpers/addons/ultracite-setup.ts -B 5 -A 5Repository: AmanVarshney01/create-better-t-stack
Length of output: 62
🏁 Script executed:
# Check the specific commit that mentions ultracite setup arguments
git show b2d33a8 --statRepository: AmanVarshney01/create-better-t-stack
Length of output: 476
🏁 Script executed:
# Look at the hooks flag fix commit
git show 94e96e2 --statRepository: AmanVarshney01/create-better-t-stack
Length of output: 404
🏁 Script executed:
# Let's check if there's any test that shows the expected command format
cat -n apps/cli/test/addons.test.ts | grep -A 50 -B 5 "ultracite"Repository: AmanVarshney01/create-better-t-stack
Length of output: 1561
🏁 Script executed:
# Check the full diff from commit 94e96e2 that added hooks flag
git show 94e96e2Repository: AmanVarshney01/create-better-t-stack
Length of output: 2155
🏁 Script executed:
# Also check the earlier commit b2d33a8
git show b2d33a8Repository: AmanVarshney01/create-better-t-stack
Length of output: 1386
🏁 Script executed:
# Let's trace how the function is called to understand gitHooks parameter
rg "setupUltracite" apps/cli/src/ -B 3 -A 3Repository: AmanVarshney01/create-better-t-stack
Length of output: 1726
🏁 Script executed:
# Check how gitHooks array is constructed before being passed
rg "gitHooks" apps/cli/src/helpers/ -B 2 -A 2Repository: AmanVarshney01/create-better-t-stack
Length of output: 1552
lint-staged should be included in the --integrations string, not pushed as a separate argument.
The current code results in --integrations "husky lefthook" lint-staged, making lint-staged a standalone positional argument. According to the git history, the integration should be: --integrations "husky lefthook lint-staged". The proposed fix correctly addresses this by building the integrations array first, adding lint-staged conditionally when husky is present, then joining all values together.
🤖 Prompt for AI Agents
In apps/cli/src/helpers/addons/ultracite-setup.ts around lines 200 to 205, the
code currently pushes "--integrations" with gitHooks.join(" ") then separately
pushes "lint-staged" when "husky" is present, causing lint-staged to become a
standalone positional arg; instead, add "lint-staged" into the integrations
array when husky is detected and then push a single "--integrations" argument
with the joined integrations string (remove the separate push of "lint-staged").
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.
Wrong i tested it and it worked this way
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.
@therealsamyak, thank you for confirming! I appreciate you testing this and verifying the behavior. If the Ultracite CLI accepts lint-staged as a separate positional argument after the --integrations flag (resulting in --integrations "husky lefthook" lint-staged), then the current implementation is correct as-is.
I've noted this for future reference to avoid similar confusion.
✏️ Learnings added
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-25T00:49:53.633Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when calling Ultracite CLI with the `--integrations` flag, `lint-staged` should be passed as a separate positional argument after the integrations string (e.g., `ultraciteArgs.push("--integrations", gitHooks.join(" "))` followed by `ultraciteArgs.push("lint-staged")`), not included within the integrations string itself. This has been tested and confirmed to work.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:55.011Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, the Ultracite CLI's `--integrations` flag requires git hooks to be passed as a single space-separated string (e.g., `gitHooks.join(" ")`) rather than using the spread operator like other Ultracite flags. This has been tested and confirmed to work.
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.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
235f34c to
fb8c776
Compare
|
Please don't update the branch every time I commit. I will handle it tomorrow 😊 |
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: 0
♻️ Duplicate comments (3)
apps/web/src/lib/constant.ts (1)
503-510: The Lefthook icon file is still missing.This issue was previously flagged: the icon URL returns a 404 error. The asset must be uploaded to the icon bucket before this entry can be used in production.
apps/cli/src/helpers/addons/addons-setup.ts (2)
183-206: setupLefthook needs linter parameter to generate lefthook.yml with pre-commit hooks.The function currently only installs the lefthook package and sets up the prepare script. It should also:
- Accept a
linterparameter (likesetupHuskydoes)- Generate a
lefthook.ymlfile with pre-commit hooks configured for the selected linter- Use
stage_fixed: trueto eliminate the need for lint-staged🔎 Proposed implementation to add linter support
Update the function signature:
-export async function setupLefthook(projectDir: string) { +export async function setupLefthook(projectDir: string, linter?: "biome" | "oxlint") {After the prepare script setup, add lefthook.yml generation:
// Generate lefthook.yml with pre-commit hooks if linter is configured if (linter) { const lefthookConfigPath = path.join(projectDir, "lefthook.yml"); let command = ""; if (linter === "biome") { command = "biome check --write ."; } else if (linter === "oxlint") { command = "oxlint && oxfmt --write"; } const lefthookConfig = `pre-commit: commands: lint: glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" run: ${command} stage_fixed: true `; await fs.writeFile(lefthookConfigPath, lefthookConfig, "utf-8"); }
84-89: setupLefthook should receive the linter parameter.The
setupLefthookfunction is called without thelinterparameter (Line 88), whilesetupHuskycorrectly receives it (Line 85). This prevents Lefthook from generating pre-commit hooks for Biome or Oxlint in thelefthook.ymlconfiguration file. According to the PR objectives, Lefthook should be configured with linter commands usingstage_fixed: true.🔎 Proposed fix to pass linter to setupLefthook
if (hasHusky) { await setupHusky(projectDir, linter); } if (hasLefthook) { - await setupLefthook(projectDir); + await setupLefthook(projectDir, linter); }You'll also need to update the
setupLefthookfunction signature and implementation to accept and use the linter parameter to generate the appropriatelefthook.ymlconfiguration.
🧹 Nitpick comments (1)
apps/cli/src/helpers/addons/addons-setup.ts (1)
144-181: Consider: lint-staged is only needed with Husky, not Lefthook.The
setupHuskyfunction always installslint-staged(Line 146), but according to the PR description, Lefthook usesstage_fixed: trueand doesn't require lint-staged. When both Husky and Lefthook are selected, this adds an unnecessary dependency.Consider installing
lint-stagedonly when Husky is selected without Lefthook, or document that lint-staged is used exclusively by Husky in multi-hook setups.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
README.mdapps/cli/README.mdapps/cli/src/constants.tsapps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/cli/src/helpers/core/post-installation.tsapps/cli/src/helpers/core/template-manager.tsapps/cli/src/prompts/addons.tsapps/cli/templates/addons/lefthook/lefthook.yml.hbsapps/cli/templates/addons/ruler/.ruler/bts.md.hbsapps/cli/test/addons.test.tsapps/web/content/docs/cli/options.mdxapps/web/content/docs/index.mdxapps/web/content/docs/project-structure.mdxapps/web/src/lib/constant.tsapps/web/src/lib/stack-utils.tspackages/types/src/schemas.ts
✅ Files skipped from review due to trivial changes (1)
- apps/cli/README.md
🚧 Files skipped from review as they are similar to previous changes (10)
- apps/cli/src/helpers/core/post-installation.ts
- README.md
- apps/cli/src/helpers/core/template-manager.ts
- apps/cli/test/addons.test.ts
- apps/cli/templates/addons/lefthook/lefthook.yml.hbs
- apps/cli/src/constants.ts
- apps/cli/src/prompts/addons.ts
- apps/web/src/lib/stack-utils.ts
- packages/types/src/schemas.ts
- apps/web/content/docs/index.mdx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions
Files:
apps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
**/*.{ts,tsx}: Use TypeScript type aliases instead of interface declarations
Do not use explicit return types
Files:
apps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{ts,tsx,js,jsx}: Usebun <file>instead ofnode <file>orts-node <file>for running TypeScript/JavaScript files
Bun automatically loads .env files, so don't use the dotenv package
UseBun.serve()which supports WebSockets, HTTPS, and routes instead ofexpress
Usebun:sqlitemodule for SQLite instead ofbetter-sqlite3
UseBun.redisfor Redis instead ofioredis
UseBun.sqlfor Postgres instead ofpgorpostgres.js
Use built-inWebSocketinstead of thewspackage
PreferBun.fileovernode:fsreadFile/writeFile methods
UseBun.$template literal syntax instead ofexecafor shell command execution
Import .css files directly in TypeScript/JavaScript files; Bun's CSS bundler will handle bundling
Run server withbun --hot <file>to enable hot reloading during development
Files:
apps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.ts
**/*.{ts,tsx,js,jsx,css}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>instead ofwebpackoresbuildfor bundling TypeScript, JavaScript, and CSS files
Files:
apps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.ts
**/*.{html,tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend instead of Vite
Files:
apps/cli/src/helpers/addons/addons-setup.tsapps/cli/src/helpers/addons/ultracite-setup.tsapps/cli/src/helpers/core/create-readme.tsapps/web/src/lib/constant.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:55.011Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, the Ultracite CLI's `--integrations` flag requires git hooks to be passed as a single space-separated string (e.g., `gitHooks.join(" ")`) rather than using the spread operator like other Ultracite flags. This has been tested and confirmed to work.
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-25T00:49:53.633Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when calling Ultracite CLI with the `--integrations` flag, `lint-staged` should be passed as a separate positional argument after the integrations string (e.g., `ultraciteArgs.push("--integrations", gitHooks.join(" "))` followed by `ultraciteArgs.push("lint-staged")`), not included within the integrations string itself. This has been tested and confirmed to work.
📚 Learning: 2025-12-18T19:15:55.011Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:55.011Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, the Ultracite CLI's `--integrations` flag requires git hooks to be passed as a single space-separated string (e.g., `gitHooks.join(" ")`) rather than using the spread operator like other Ultracite flags. This has been tested and confirmed to work.
Applied to files:
apps/web/content/docs/cli/options.mdxapps/cli/src/helpers/addons/addons-setup.tsapps/web/content/docs/project-structure.mdxapps/cli/src/helpers/core/create-readme.ts
📚 Learning: 2025-12-25T00:49:53.633Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-25T00:49:53.633Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when calling Ultracite CLI with the `--integrations` flag, `lint-staged` should be passed as a separate positional argument after the integrations string (e.g., `ultraciteArgs.push("--integrations", gitHooks.join(" "))` followed by `ultraciteArgs.push("lint-staged")`), not included within the integrations string itself. This has been tested and confirmed to work.
Applied to files:
apps/cli/src/helpers/addons/addons-setup.ts
📚 Learning: 2025-12-18T19:15:48.478Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-18T19:15:48.478Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when passing the Ultracite CLI --integrations flag, supply git hooks as a single space-separated string (e.g., gitHooks.join(" ")) rather than spreading the array like other Ultracite flags. This has been tested and confirmed to work. Ensure the code uses a single string created by joining the gitHooks array with spaces for the --integrations argument.
Applied to files:
apps/cli/src/helpers/addons/ultracite-setup.ts
📚 Learning: 2025-12-25T00:49:53.633Z
Learnt from: therealsamyak
Repo: AmanVarshney01/create-better-t-stack PR: 711
File: apps/cli/src/helpers/addons/ultracite-setup.ts:200-205
Timestamp: 2025-12-25T00:49:53.633Z
Learning: In apps/cli/src/helpers/addons/ultracite-setup.ts, when invoking Ultracite CLI with the --integrations flag, pass lint-staged as a separate positional argument after the integrations string, e.g. ultraciteArgs.push("--integrations", gitHooks.join(" ")); ultraciteArgs.push("lint-staged");. Do not include lint-staged inside the integrations string. This ensures proper argument parsing and avoids unintended tokens being treated as part of the integrations list.
Applied to files:
apps/cli/src/helpers/addons/ultracite-setup.ts
📚 Learning: 2025-12-03T07:48:26.419Z
Learnt from: CR
Repo: AmanVarshney01/create-better-t-stack PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-12-03T07:48:26.419Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` template literal syntax instead of `execa` for shell command execution
Applied to files:
apps/cli/src/helpers/addons/ultracite-setup.ts
🧬 Code graph analysis (2)
apps/cli/src/helpers/addons/addons-setup.ts (2)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
setupUltracite(134-224)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency(6-57)
apps/cli/src/helpers/addons/ultracite-setup.ts (1)
packages/types/src/types.ts (1)
ProjectConfig(51-51)
🔇 Additional comments (12)
apps/web/src/lib/constant.ts (3)
535-542: Turborepo icon is accessible and properly configured.The icon at
https://r2.better-t-stack.dev/icons/turborepo.svgreturns HTTP 200 with correct SVG format (3274 bytes), confirming the asset is uploaded and available.
551-559: Ultracite icon is accessible and properly configured. The icon file exists at https://r2.better-t-stack.dev/icons/ultracite.svg (HTTP 200 confirmed) and the entry in constant.ts uses the correct ICON_BASE_URL pattern consistent with other addons in the file.
496-502: Verify that the Fumadocs icon exists.Ensure the icon file is uploaded and accessible at https://r2.better-t-stack.dev/icons/fumadocs.svg.
apps/cli/templates/addons/ruler/.ruler/bts.md.hbs (1)
119-119: LGTM!The addition of Lefthook to the addon list is correctly placed and consistent with the broader PR changes.
apps/web/content/docs/cli/options.mdx (1)
294-294: LGTM!The Lefthook addon documentation entry is well-formatted and consistently placed within the addons list.
apps/cli/src/helpers/core/create-readme.ts (1)
468-469: LGTM!The Lefthook feature description follows the established pattern for other addons and accurately describes the tool.
apps/web/content/docs/project-structure.mdx (1)
262-262: LGTM!The bts.jsonc example correctly includes lefthook in the addons array, maintaining consistency with the broader integration.
apps/cli/src/helpers/addons/ultracite-setup.ts (2)
134-134: LGTM! Improved signature enables multi-hook support.The signature change from
hasHusky: booleantogitHooks: string[]correctly enables support for multiple git hook managers (Husky, Lefthook) and aligns with the broader PR objectives.
201-206: LGTM! Ultracite integration correctly handles git hooks.The implementation correctly:
- Passes git hooks as a space-separated string to
--integrations(as confirmed by testing)- Adds
lint-stagedas a separate positional argument when Husky is present (also confirmed by testing)Based on learnings, this approach has been tested and verified to work correctly with the Ultracite CLI.
apps/cli/src/helpers/addons/addons-setup.ts (3)
65-72: Both Husky and Lefthook can be selected simultaneously.The current implementation allows both
huskyandlefthookto be selected together, which results in both being installed and both prepare scripts being added. According to the PR description, the maintainer is aware of this and plans to enforce mutual exclusion in a follow-up PR.Please confirm this behavior is acceptable for this release, with mutual exclusion to be addressed in a future PR as noted in the comments.
154-162: LGTM! Prepare script coordination handles both hooks.The logic correctly checks for Lefthook's presence and appends Husky's command to preserve both prepare scripts when both hooks are installed.
193-202: LGTM! Prepare script coordination correctly handles Husky presence.The logic correctly checks for Husky's presence and prepends Lefthook's install command to preserve both prepare scripts when both hooks are installed.
sorry i am used to updating outdated branches when they are outdated, but if you say its fine then i will stop, thank you :) |
Add lefthook to addons section.
Areas Updates
preparescript withlefthook installtopackage.jsonin template.Notes
{ lefthook, husky }There is a "bug" / missing feature in Ultracite where athis is fixedpreparescript in thepackage.jsonis not generated. I filed a feature request within the Ultracite repo (Prepare script when using Git hooks manager (ex. Lefthook) haydenbleasel/ultracite#427) so hopefully this is resolved soon. Ultracite already runs 'lefthook install' (or similar hook scripts) upon finishing its setup, so not a huge huge problem if the Git hooks don't change.biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}and/oroxlint --fix .(lefthook) respectively. Lefthook doesn't need lint-staged (just usestage_fixed: true), so why add another dependency when it's not necessary.Disclaimer that majority of the code is AI-generated, but I did test it throughly, reviewed all the code generated manually with my own 2 eyes, and tested it locally to verify it worked before opening this PR.
Screenshots
Summary by CodeRabbit
New Features
Documentation
UI/Prompts
Templates
Tests
✏️ Tip: You can customize this high-level summary in your review settings.
Note
Adds comprehensive Lefthook support and integrates it into the stack.
lefthookaddon: dependency versions, compatibility map, CLI flag, prompts (new "Git Hooks" group), Stack Builder UI, and schema typespreparescript (lefthook install), adds templatelefthook.yml(auto-populates commands for Biome/Oxlint), and coexists with Husky by merging prepare scriptssetupUltracitenow accepts multiple git hooks (husky/lefthook) and passes them via--integrations; Husky deps no longer force-installed there; addon templates skip husky/lefthook when Ultracite is selectedlefthookWritten by Cursor Bugbot for commit 6c0363f. This will update automatically on new commits. Configure here.