- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 209
chore(cli): remove all explicit return types #573
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
Conversation
| 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. Caution Review failedThe pull request is closed. WalkthroughThis PR removes explicit return type annotations across many TypeScript files (CLI and web), adds a repo guideline banning explicit return types, and makes a few focused behavioral tweaks: Biome formatter now returns null instead of throwing on errors, Docker uses a static execa import, and project-name gains a cwd containment validation with an error log. Changes
 Sequence Diagram(s)sequenceDiagram
  autonumber
  actor Caller
  participant Formatter as formatFileWithBiome
  participant Biome as initializeBiome
  participant FS as Biome.format
  Caller->>Formatter: formatFileWithBiome(filePath, content)
  Formatter->>Formatter: shouldSkipFile?/isSupportedFile?
  alt Skip/Unsupported
    Formatter-->>Caller: null
  else Proceed
    Formatter->>Biome: initializeBiome()
    alt Init fails (returns null)
      Biome-->>Formatter: null
      Formatter-->>Caller: null
    else Init OK
      Biome-->>Formatter: { biome, projectKey }
      Formatter->>FS: biome.format(content)
      alt Diagnostics OK
        FS-->>Formatter: formatted
        Formatter-->>Caller: formatted
      else Diagnostics warn/error
        FS-->>Formatter: original/partial
        Formatter-->>Caller: null
      end
    end
  end
sequenceDiagram
  autonumber
  actor User
  participant Prompt as getProjectName
  participant Path as path validation
  participant Log as consola
  User->>Prompt: call with initialName?
  alt initialName missing or "."
    Prompt->>User: interactive prompt → chosen name
  else provided
    Prompt->>Path: validate basename
    alt invalid basename
      Prompt->>User: interactive prompt → chosen name
    else valid basename
      Path->>Path: is within cwd?
      alt outside cwd
        Log-->>User: "Project path must be within current directory"
        Prompt->>User: interactive prompt → chosen name
      else inside cwd
        Prompt-->>User: basename returned
      end
    end
  end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
 Poem
 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
 ✨ Finishing touches
 🧪 Generate unit tests
 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.
Pull Request Overview
This PR removes explicit return types from functions across the CLI codebase to align with the project's coding standards. The changes span multiple files including utilities, prompts, validation, and configuration handling modules.
- Remove explicit return types from all function declarations
- Maintain functional programming patterns while simplifying type annotations
- Update project coding rules to enforce this convention going forward
Reviewed Changes
Copilot reviewed 45 out of 45 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description | 
|---|---|
| apps/web/src/lib/stack-utils.ts | Remove return types from stack utility functions | 
| apps/cli/src/validation.ts | Remove return types from validation and processing functions | 
| apps/cli/src/utils/ | Remove return types from utility functions across multiple modules | 
| apps/cli/src/prompts/ | Remove return types from prompt handling functions | 
| apps/cli/src/helpers/ | Remove return types from helper functions and handlers | 
| apps/cli/src/constants.ts | Remove return types from configuration functions | 
| .cursor/rules/better-t-stack-repo.mdc | Add rule to enforce no explicit return types | 
Comments suppressed due to low confidence (1)
apps/cli/src/helpers/database-providers/turso-setup.ts:1
- The TursoGroup type definition is removed but the getTursoGroups function still references it in its logic. The type should be kept or the function should be updated to work without explicit typing.
import os from "node:os";
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| flags.api, | ||
| results.frontend, | ||
| results.backend, | ||
| ) as Promise<API>, | 
    
      
    
      Copilot
AI
    
    
    
      Sep 11, 2025 
    
  
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.
Type assertion 'as Promise' is unnecessary since getApiChoice already returns Promise. The type assertion should be removed for cleaner code.
| ) as Promise<API>, | |
| ), | 
| results.backend, | ||
| results.api, | ||
| ), | ||
| ) as Promise<Examples[]>, | 
    
      
    
      Copilot
AI
    
    
    
      Sep 11, 2025 
    
  
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.
Type assertion 'as Promise<Examples[]>' is unnecessary since getExamplesChoice already returns Promise<Examples[]>. The type assertion should be removed for cleaner code.
| ) as Promise<Examples[]>, | |
| ), | 
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 (9)
apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts (1)
16-18: Remove dotenv from devDependencies; Bun auto-loads .env per repo rules.The repo guideline forbids dotenv; avoid adding it.
Apply this diff:
- devDependencies: ["alchemy", "@sveltejs/adapter-cloudflare", "dotenv"], + devDependencies: ["alchemy", "@sveltejs/adapter-cloudflare"],apps/cli/src/helpers/database-providers/mongodb-atlas-setup.ts (1)
4-4: Replace execa with Bun.$ per project guidelines.The repo guidelines prefer Bun.$ for shelling out. This also removes an external dependency.
-import { execa } from "execa"; +import { $ } from "bun"; @@ - await execa("atlas", ["deployments", "setup"], { - cwd: serverDir, - stdio: "inherit", - }); + await $({ cwd: serverDir })`atlas deployments setup`;Also applies to: 50-53
apps/cli/src/helpers/core/post-installation.ts (2)
431-438: Fix double "run" in Wrangler deploy commands.
${runCmd}already contains"<pm> run". Appendingrunproducesnpm run run deploy.Apply:
- `${pc.bold("Deploy web to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} run deploy`}`, + `${pc.bold("Deploy web to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/web && ${runCmd} deploy`}`,- `${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} run deploy`}`, + `${pc.bold("Deploy server to Cloudflare Workers:")}\n${pc.cyan("•")} Deploy: ${`cd apps/server && ${runCmd} deploy`}`,
262-263: Derive the package manager correctly from runCmd.Current logic yields
"pnpm run"or"bun run"instead of"pnpm"/"bun", producing invalid commands.Apply:
- const packageManager = runCmd === "npm run" ? "npm" : runCmd || "npm"; + const packageManager = runCmd?.split(" ")[0] ?? "npm";apps/cli/src/helpers/core/auth-setup.ts (1)
118-127: Use a cryptographically secure RNG for auth secrets.
Math.random()is not suitable for secrets.Apply:
-export function generateAuthSecret(length = 32) { - const characters = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let result = ""; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} +export function generateAuthSecret(length = 32) { + const alphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + const bytes = new Uint8Array(length); + crypto.getRandomValues(bytes); + let out = ""; + for (let i = 0; i < length; i++) { + out += alphabet[bytes[i] % alphabet.length]; + } + return out; +}apps/cli/src/helpers/database-providers/turso-setup.ts (3)
151-158: Don’t treat missing connection details as success. Throw to let caller retry.On failure this returns
undefined, and the caller proceeds.Apply:
try { const { stdout: dbUrl } = await $`turso db show ${dbName} --url`; const { stdout: authToken } = await $`turso db tokens create ${dbName}`; s.stop("Database connection details retrieved"); - return { + return { dbUrl: dbUrl.trim(), authToken: authToken.trim(), }; } catch (_error) { s.stop(pc.red("Failed to retrieve database connection details")); + throw new Error("FAILED_TO_RETRIEVE_DB_CREDENTIALS"); }
267-283: Only mark success when credentials exist; handle retries cleanly.Prevents silent success with empty .env.
Apply:
- try { - const config = await createTursoDatabase(dbName, selectedGroup); - await writeEnvFile(projectDir, config); - success = true; + try { + const config = await createTursoDatabase(dbName, selectedGroup); + if (!config?.dbUrl || !config?.authToken) { + log.error(pc.red("Missing database credentials. Please try again.")); + continue; + } + await writeEnvFile(projectDir, config); + success = true; } catch (error) { if (error instanceof Error && error.message === "DATABASE_EXISTS") { log.warn(pc.yellow(`Database "${pc.red(dbName)}" already exists`)); suggestedName = `${dbName}-${Math.floor(Math.random() * 1000)}`; } else { throw error; } }
5-5: Replace execa import with Bun.$ in this file.Apply:
-import { $ } from "execa"; +const $ = Bun.$;Also: execa is still a dependency and used across the repo (apps/cli/package.json; apps/cli/test/cli.smoke.test.ts; apps/cli/src/helpers/** — e.g. core/install-dependencies.ts, core/git.ts, addons/, database-providers/). Migrate other usages or keep execa where necessary and update package.json accordingly.
apps/cli/src/prompts/project-name.ts (1)
47-53: Avoid possible crash when a file exists at the candidate pathIf a file named like
defaultNameexists,readdirthrows. Guard by checking directory-ness first.-while ( - (await fs.pathExists(path.resolve(process.cwd(), defaultName))) && - (await fs.readdir(path.resolve(process.cwd(), defaultName))).length > 0 -) { +while (true) { + const candidate = path.resolve(process.cwd(), defaultName); + const exists = await fs.pathExists(candidate); + if (!exists) break; + const stat = await fs.stat(candidate).catch(() => null); + const isDir = !!stat && stat.isDirectory(); + const notEmpty = isDir ? (await fs.readdir(candidate)).length > 0 : false; + if (!(isDir && notEmpty)) break; defaultName = `${DEFAULT_CONFIG.projectName}-${counter}`; counter++; }
♻️ Duplicate comments (3)
apps/cli/src/helpers/database-providers/turso-setup.ts (1)
115-116: No return needed before exitCancelled.
exitCancelled()is typednever; control flow does not continue.apps/cli/src/prompts/config-prompts.ts (2)
78-83: Remove unnecessary cast to PromiseThe call already returns
Promise<API>. Drop the assertion.- getApiChoice( - flags.api, - results.frontend, - results.backend, - ) as Promise<API>, + getApiChoice( + flags.api, + results.frontend, + results.backend, + ),
92-99: Remove unnecessary cast to Promise<Examples[]>
getExamplesChoiceinfersPromise<Examples[]>; the cast is superfluous.- getExamplesChoice( - flags.examples, - results.database, - results.frontend, - results.backend, - results.api, - ) as Promise<Examples[]>, + getExamplesChoice( + flags.examples, + results.database, + results.frontend, + results.backend, + results.api, + ),
🧹 Nitpick comments (25)
apps/cli/src/prompts/package-manager.ts (2)
29-31: Don’t return the exit helper; call it to stabilize inference.Calling (not returning) the exit function avoids union-widening even if its type isn’t
never.- if (isCancel(response)) return exitCancelled("Operation cancelled"); + if (isCancel(response)) { + exitCancelled("Operation cancelled"); + }
11-27: Lock option values to the PackageManager union.Use
as const+satisfiesso option values can’t drift fromPackageManager.const response = await select<PackageManager>({ message: "Choose package manager", - options: [ + options: [ { value: "npm", label: "npm", hint: "Node Package Manager" }, { value: "pnpm", label: "pnpm", hint: "Fast, disk space efficient package manager", }, { value: "bun", label: "bun", hint: "All-in-one JavaScript runtime & toolkit", }, - ], + ] as const satisfies ReadonlyArray<{ value: PackageManager; label: string; hint: string }>, initialValue: detectedPackageManager, });.cursor/rules/better-t-stack-repo.mdc (1)
10-10: Clarify narrowly-scoped exceptions to the no-return-types rule.To prevent accidental public API drift and preserve intent in edge cases, consider documenting minimal exceptions.
Apply this diff:
-- Do not use explicit return types +- Avoid explicit return types + (exceptions: exported/public APIs, recursive functions where inference degrades, + and cases where Promise<void> vs Promise<unknown> ambiguity matters).apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts (1)
79-83: Narrow param type to ObjectLiteralExpression; drop redundant runtime check.Improves type-safety and simplifies control flow without reintroducing explicit return types.
Apply this diff:
-import { IndentationText, Node, Project, QuoteKind } from "ts-morph"; +import { IndentationText, Node, Project, QuoteKind, ObjectLiteralExpression } from "ts-morph"; @@ -function updateAdapterInConfig(configObject: Node) { - if (!Node.isObjectLiteralExpression(configObject)) return; +function updateAdapterInConfig(configObject: ObjectLiteralExpression) {apps/cli/src/helpers/database-providers/supabase-setup.ts (2)
40-47: Make DB URL extraction more robust (case-insensitive, postgres|postgresql, non-space terminator).Prevents breakage if CLI output format varies slightly.
Apply this diff:
-function extractDbUrl(output: string) { - const dbUrlMatch = output.match(/DB URL:\s*(postgresql:\/\/[^\s]+)/); +function extractDbUrl(output: string) { + const dbUrlMatch = output.match(/DB\s*URL:\s*(postgres(?:ql)?:\/\/\S+)/i); const url = dbUrlMatch?.[1]; if (url) { return url; } return null; }
4-4: Align with repo rule to prefer Bun.$ over execa (follow-up OK).Current code shells out via execa; repo guidance prefers Bun.$. Given the PR scope, consider a follow-up to migrate initializeSupabase/startSupabase to Bun.$ (mind tokenization vs single-string commands from getPackageExecutionCommand).
Would you like a separate PR plan for safely swapping execa to Bun.$ here (including capturing stdout incrementally)?
Also applies to: 95-118
apps/cli/src/prompts/runtime.ts (1)
6-15: Preserve literal inference with as const on direct returns.Without explicit return types, make sure "none"/"node" stay within Runtime’s literal union.
Apply this diff:
export async function getRuntimeChoice(runtime?: Runtime, backend?: Backend) { if (backend === "convex" || backend === "none") { - return "none"; + return "none" as const; } @@ if (backend === "next") { - return "node"; + return "node" as const; }apps/cli/src/helpers/database-providers/mongodb-atlas-setup.ts (1)
34-34: Return type inference is fine; keep call-site typed for clarity.To preserve the MongoDBConfig | null contract at the usage site without reintroducing an explicit return type, annotate the local variable where it’s consumed.
- const config = await initMongoDBAtlas(serverDir); + const config: MongoDBConfig | null = await initMongoDBAtlas(serverDir);apps/cli/src/constants.ts (2)
28-37: Constrain inferred return with satisfies to keep strong typing.Removing the explicit return type widens frontend/addons/examples to string[] at inference time. Use satisfies ProjectConfig and explicit generic arrays to retain precise types without annotating the return type.
+import type { Addons, Examples, Frontend, ProjectConfig } from "./types"; @@ -export function getDefaultConfig() { - return { +export function getDefaultConfig() { + const config = { ...DEFAULT_CONFIG_BASE, projectDir: path.resolve(process.cwd(), DEFAULT_CONFIG_BASE.projectName), packageManager: getUserPkgManager(), - frontend: [...DEFAULT_CONFIG_BASE.frontend], - addons: [...DEFAULT_CONFIG_BASE.addons], - examples: [...DEFAULT_CONFIG_BASE.examples], + frontend: [...DEFAULT_CONFIG_BASE.frontend] as Array<Frontend>, + addons: [...DEFAULT_CONFIG_BASE.addons] as Array<Addons>, + examples: [...DEFAULT_CONFIG_BASE.examples] as Array<Examples>, - }; + } satisfies ProjectConfig; + return config; }
162-175: Keep ADDON_COMPATIBILITY key coverage checked at compile-time.Switching from Record<Addons, readonly Frontend[]> to a plain const may drop “exhaustiveness” checking if Addons evolves. Use satisfies with the const to ensure keys stay in sync.
-export const ADDON_COMPATIBILITY = { +export const ADDON_COMPATIBILITY = { pwa: ["tanstack-router", "react-router", "solid", "next"], tauri: ["tanstack-router", "react-router", "nuxt", "svelte", "solid", "next"], biome: [], husky: [], turborepo: [], starlight: [], ultracite: [], ruler: [], oxlint: [], fumadocs: [], none: [], -} as const; +} as const satisfies Record<import("./types").Addons, readonly import("./types").Frontend[]>;apps/cli/src/prompts/frontend.ts (1)
7-11: Inference OK; ensure initialValue remains typed as Frontend.Because getDefaultConfig() now infers, DEFAULT_CONFIG.frontend[0] can widen to string. The suggested satisfies fix in constants.ts keeps this as Frontend without reintroducing return types.
apps/cli/src/helpers/core/create-readme.ts (1)
20-24: Prefer Bun.write over fs-extra for writes.Small cleanup aligned with repo guidance to prefer Bun APIs where possible.
-import fs from "fs-extra"; +// import fs from "fs-extra"; // no longer needed @@ - await fs.writeFile(readmePath, content); + await Bun.write(readmePath, content);apps/cli/src/utils/addon-compatibility.ts (1)
29-33: LGTM on inferred return; keep type-safety with constants object.Function inference yields Addons[] from the filtered input. Ensure ADDON_COMPATIBILITY uses satisfies (see constants.ts suggestion) so indexing by Addons remains safe long-term.
apps/cli/src/helpers/core/post-installation.ts (1)
229-233: Make runCmd required (or provide an internal default) to avoid "undefined dev".These helpers are always passed a value today, but the optional param risks emitting
undefinedin strings if reused.Apply (one example shown; repeat for others):
-function getLintingInstructions(runCmd?: string) { +function getLintingInstructions(runCmd: string) {Alternatively, default:
function getLintingInstructions(runCmd = "pnpm run") { ... }.Also applies to: 387-395, 403-409, 423-443, 448-470
apps/cli/src/helpers/database-providers/turso-setup.ts (2)
50-54: Avoid inlining installer script into bash -c. Use a pipeline.Safer and simpler; avoids quoting pitfalls.
Apply:
- const { stdout: installScript } = - await $`curl -sSfL https://get.tur.so/install.sh`; - await $`bash -c '${installScript}'`; + await $`curl -fsSL https://get.tur.so/install.sh`.pipe($`bash -s --`);
58-63: Detect user-cancel via exit code instead of string matching.Message text is brittle; Bun.$ exposes exitCode.
Apply:
- if (error instanceof Error && error.message.includes("User force closed")) { + // Bun.$ throws a SubprocessError with exitCode when interrupted (e.g., SIGINT -> 130) + // @ts-expect-error Bun SubprocessError has exitCode + if (typeof (error as any)?.exitCode === "number" && (error as any).exitCode !== 0) {apps/cli/src/helpers/addons/addons-setup.ts (1)
98-109: Remove redundant conditional in getWebAppDirBoth branches return the same path. Simplify to a single return.
-function getWebAppDir(projectDir: string, frontends: Frontend[]) { - if ( - frontends.some((f) => - ["react-router", "tanstack-router", "nuxt", "svelte", "solid"].includes( - f, - ), - ) - ) { - return path.join(projectDir, "apps/web"); - } - return path.join(projectDir, "apps/web"); -} +function getWebAppDir(projectDir: string, frontends: Frontend[]) { + return path.join(projectDir, "apps/web"); +}apps/cli/src/helpers/core/command-handlers.ts (1)
59-61: Drop redundant local type annotation.Rely on inference to stay consistent with the PR’s goal.
- let defaultName: string = defaultConfig.relativePath; + let defaultName = defaultConfig.relativePath;apps/cli/src/utils/config-processing.ts (1)
17-21: Constrain T to string to avoid the cast and simplify includes check.This tightens types and removes the need for "as T | 'none'".
-export function processArrayOption<T>(options: (T | "none")[] | undefined) { +export function processArrayOption<T extends string>(options: (T | "none")[] | undefined) { if (!options || options.length === 0) return []; - if (options.includes("none" as T | "none")) return []; + if (options.includes("none")) return []; return options.filter((item): item is T => item !== "none"); }apps/cli/src/prompts/project-name.ts (2)
10-14: Harden cwd containment against symlink escapesResolve both cwd and target with realpath to prevent bypass via symlinks.
-function isPathWithinCwd(targetPath: string) { - const resolved = path.resolve(targetPath); - const rel = path.relative(process.cwd(), resolved); +function isPathWithinCwd(targetPath: string) { + const resolved = fs.realpathSync(path.resolve(targetPath)); + const cwdReal = fs.realpathSync(process.cwd()); + const rel = path.relative(cwdReal, resolved); return !rel.startsWith("..") && !path.isAbsolute(rel); }
26-40: Early-path UX improvement (non-blocking)When
initialNameis inside cwd, consider normalizing before returning so consumers get a consistent path (e.g., collapsefoo/../bar). Safe to do withpath.normalize.- if (isPathWithinCwd(projectDir)) { - return initialName; - } + if (isPathWithinCwd(projectDir)) { + return path.normalize(initialName); + }apps/cli/src/utils/project-directory.ts (1)
72-76: Drop redundantawaiton returned promise
return await handleDirectoryConflict(newPathInput)adds no value here.- return await handleDirectoryConflict(newPathInput); + return handleDirectoryConflict(newPathInput);apps/cli/src/utils/package-runner.ts (1)
11-15: Minor: handle Yarn explicitly or fix docsDocstring mentions Yarn but switch doesn’t. Either add Yarn handling or adjust docs.
export function getPackageExecutionCommand( packageManager: PackageManager | null | undefined, commandWithArgs: string, ) { switch (packageManager) { + case "yarn": + // Yarn Berry (v2+) supports `yarn dlx`; v1 falls back to `npx` + return `yarn dlx ${commandWithArgs}`; case "pnpm": return `pnpm dlx ${commandWithArgs}`; case "bun": return `bunx ${commandWithArgs}`; default: return `npx ${commandWithArgs}`; } }apps/cli/src/utils/project-name-validation.ts (1)
16-21: Throwing validator: OKInferred
void; error message is clear. Consider adding the fallback like the non-throwing variant for consistency, optional.apps/cli/src/utils/docker-utils.ts (1)
53-78: Return-type removal: docker statusInferred object shape remains explicit in usage; fine. Consider
.quiet()if output is noisy (optional).- const running = await isDockerRunning(); + const running = await isDockerRunning(); if (!running) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (45)
- .cursor/rules/better-t-stack-repo.mdc(1 hunks)
- apps/cli/src/constants.ts(2 hunks)
- apps/cli/src/helpers/addons/addons-setup.ts(1 hunks)
- apps/cli/src/helpers/core/auth-setup.ts(1 hunks)
- apps/cli/src/helpers/core/command-handlers.ts(3 hunks)
- apps/cli/src/helpers/core/create-readme.ts(8 hunks)
- apps/cli/src/helpers/core/detect-project-config.ts(1 hunks)
- apps/cli/src/helpers/core/post-installation.ts(7 hunks)
- apps/cli/src/helpers/database-providers/docker-compose-setup.ts(1 hunks)
- apps/cli/src/helpers/database-providers/mongodb-atlas-setup.ts(1 hunks)
- apps/cli/src/helpers/database-providers/supabase-setup.ts(1 hunks)
- apps/cli/src/helpers/database-providers/turso-setup.ts(3 hunks)
- apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts(1 hunks)
- apps/cli/src/index.ts(1 hunks)
- apps/cli/src/prompts/addons.ts(2 hunks)
- apps/cli/src/prompts/api.ts(1 hunks)
- apps/cli/src/prompts/backend.ts(1 hunks)
- apps/cli/src/prompts/config-prompts.ts(3 hunks)
- apps/cli/src/prompts/database-setup.ts(1 hunks)
- apps/cli/src/prompts/database.ts(1 hunks)
- apps/cli/src/prompts/examples.ts(1 hunks)
- apps/cli/src/prompts/frontend.ts(1 hunks)
- apps/cli/src/prompts/orm.ts(1 hunks)
- apps/cli/src/prompts/package-manager.ts(1 hunks)
- apps/cli/src/prompts/project-name.ts(3 hunks)
- apps/cli/src/prompts/runtime.ts(1 hunks)
- apps/cli/src/prompts/server-deploy.ts(2 hunks)
- apps/cli/src/prompts/web-deploy.ts(3 hunks)
- apps/cli/src/utils/addon-compatibility.ts(1 hunks)
- apps/cli/src/utils/biome-formatter.ts(4 hunks)
- apps/cli/src/utils/bts-config.ts(1 hunks)
- apps/cli/src/utils/compatibility-rules.ts(2 hunks)
- apps/cli/src/utils/config-processing.ts(5 hunks)
- apps/cli/src/utils/config-validation.ts(9 hunks)
- apps/cli/src/utils/docker-utils.ts(3 hunks)
- apps/cli/src/utils/errors.ts(1 hunks)
- apps/cli/src/utils/generate-reproducible-command.ts(1 hunks)
- apps/cli/src/utils/package-runner.ts(1 hunks)
- apps/cli/src/utils/project-directory.ts(2 hunks)
- apps/cli/src/utils/project-name-validation.ts(3 hunks)
- apps/cli/src/utils/sponsors.ts(1 hunks)
- apps/cli/src/utils/telemetry.ts(1 hunks)
- apps/cli/src/utils/ts-morph.ts(1 hunks)
- apps/cli/src/validation.ts(2 hunks)
- apps/web/src/lib/stack-utils.ts(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)Use TypeScript type aliases instead of interface declarations.
Files:
- apps/cli/src/helpers/database-providers/mongodb-atlas-setup.ts
- apps/cli/src/utils/telemetry.ts
- apps/cli/src/utils/bts-config.ts
- apps/cli/src/prompts/package-manager.ts
- apps/cli/src/prompts/api.ts
- apps/cli/src/utils/sponsors.ts
- apps/cli/src/utils/errors.ts
- apps/cli/src/helpers/database-providers/docker-compose-setup.ts
- apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts
- apps/cli/src/utils/ts-morph.ts
- apps/cli/src/helpers/core/auth-setup.ts
- apps/cli/src/index.ts
- apps/cli/src/utils/generate-reproducible-command.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/src/prompts/frontend.ts
- apps/cli/src/prompts/runtime.ts
- apps/cli/src/utils/config-processing.ts
- apps/cli/src/utils/compatibility-rules.ts
- apps/web/src/lib/stack-utils.ts
- apps/cli/src/utils/addon-compatibility.ts
- apps/cli/src/helpers/core/post-installation.ts
- apps/cli/src/validation.ts
- apps/cli/src/helpers/core/command-handlers.ts
- apps/cli/src/constants.ts
- apps/cli/src/helpers/addons/addons-setup.ts
- apps/cli/src/prompts/orm.ts
- apps/cli/src/helpers/database-providers/supabase-setup.ts
- apps/cli/src/utils/package-runner.ts
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/src/utils/project-directory.ts
- apps/cli/src/prompts/examples.ts
- apps/cli/src/utils/config-validation.ts
- apps/cli/src/prompts/backend.ts
- apps/cli/src/prompts/database-setup.ts
- apps/cli/src/prompts/addons.ts
- apps/cli/src/utils/project-name-validation.ts
- apps/cli/src/helpers/database-providers/turso-setup.ts
- apps/cli/src/helpers/core/detect-project-config.ts
- apps/cli/src/prompts/web-deploy.ts
- apps/cli/src/prompts/server-deploy.ts
- apps/cli/src/utils/docker-utils.ts
- apps/cli/src/prompts/project-name.ts
- apps/cli/src/utils/biome-formatter.ts
- apps/cli/src/prompts/database.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}: Do not use dotenv; Bun auto-loads .env
UseBun.serve()for HTTP/WebSockets; do not useexpress
Usebun:sqlitefor SQLite; do not usebetter-sqlite3
UseBun.redisfor Redis; do not useioredis
UseBun.sqlfor Postgres; do not usepgorpostgres.js
Use built-inWebSocket; do not usews
PreferBun.fileovernode:fsreadFile/writeFile
UseBun.$instead ofexecafor shelling outDefine functions using the standard function declaration syntax, not arrow functions.
Files:
- apps/cli/src/helpers/database-providers/mongodb-atlas-setup.ts
- apps/cli/src/utils/telemetry.ts
- apps/cli/src/utils/bts-config.ts
- apps/cli/src/prompts/package-manager.ts
- apps/cli/src/prompts/api.ts
- apps/cli/src/utils/sponsors.ts
- apps/cli/src/utils/errors.ts
- apps/cli/src/helpers/database-providers/docker-compose-setup.ts
- apps/cli/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts
- apps/cli/src/utils/ts-morph.ts
- apps/cli/src/helpers/core/auth-setup.ts
- apps/cli/src/index.ts
- apps/cli/src/utils/generate-reproducible-command.ts
- apps/cli/src/prompts/config-prompts.ts
- apps/cli/src/prompts/frontend.ts
- apps/cli/src/prompts/runtime.ts
- apps/cli/src/utils/config-processing.ts
- apps/cli/src/utils/compatibility-rules.ts
- apps/web/src/lib/stack-utils.ts
- apps/cli/src/utils/addon-compatibility.ts
- apps/cli/src/helpers/core/post-installation.ts
- apps/cli/src/validation.ts
- apps/cli/src/helpers/core/command-handlers.ts
- apps/cli/src/constants.ts
- apps/cli/src/helpers/addons/addons-setup.ts
- apps/cli/src/prompts/orm.ts
- apps/cli/src/helpers/database-providers/supabase-setup.ts
- apps/cli/src/utils/package-runner.ts
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/src/utils/project-directory.ts
- apps/cli/src/prompts/examples.ts
- apps/cli/src/utils/config-validation.ts
- apps/cli/src/prompts/backend.ts
- apps/cli/src/prompts/database-setup.ts
- apps/cli/src/prompts/addons.ts
- apps/cli/src/utils/project-name-validation.ts
- apps/cli/src/helpers/database-providers/turso-setup.ts
- apps/cli/src/helpers/core/detect-project-config.ts
- apps/cli/src/prompts/web-deploy.ts
- apps/cli/src/prompts/server-deploy.ts
- apps/cli/src/utils/docker-utils.ts
- apps/cli/src/prompts/project-name.ts
- apps/cli/src/utils/biome-formatter.ts
- apps/cli/src/prompts/database.ts
🧠 Learnings (5)
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to convex/**/*.ts : Respect file-based routing: api.<path>.<name> for public and internal.<path>.<name> for private functions based on file location/name
Applied to files:
- apps/cli/src/helpers/core/create-readme.ts
📚 Learning: 2025-09-09T08:52:54.105Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/better-t-stack-repo.mdc:0-0
Timestamp: 2025-09-09T08:52:54.105Z
Learning: Applies to **/*.{hbs,handlebars} : In Handlebars templates, avoid generic if/else blocks; use explicit conditions (e.g., if (eq orm "prisma"), else if (eq orm "drizzle")).
Applied to files:
- .cursor/rules/better-t-stack-repo.mdc
📚 Learning: 2025-09-09T08:52:54.105Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/better-t-stack-repo.mdc:0-0
Timestamp: 2025-09-09T08:52:54.105Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript type aliases instead of interface declarations.
Applied to files:
- .cursor/rules/better-t-stack-repo.mdc
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to convex/**/*.ts : Always include argument and return validators for all Convex functions (public and internal)
Applied to files:
- apps/cli/src/utils/config-validation.ts
📚 Learning: 2025-08-24T18:01:11.544Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-24T18:01:11.544Z
Learning: Applies to **/*.{js,jsx,ts,tsx,mjs,cjs} : Use `Bun.$` instead of `execa` for shelling out
Applied to files:
- apps/cli/src/utils/docker-utils.ts
🧬 Code graph analysis (15)
apps/cli/src/prompts/package-manager.ts (1)
apps/cli/src/types.ts (1)
PackageManager(64-64)
apps/cli/src/helpers/database-providers/docker-compose-setup.ts (1)
apps/cli/src/types.ts (1)
Database(6-6)
apps/cli/src/index.ts (1)
apps/cli/src/types.ts (1)
CreateInput(127-150)
apps/cli/src/utils/generate-reproducible-command.ts (1)
apps/cli/src/types.ts (1)
ProjectConfig(165-184)
apps/cli/src/prompts/config-prompts.ts (3)
apps/cli/src/prompts/api.ts (1)
getApiChoice(6-49)apps/cli/src/types.ts (2)
API(82-82)
Examples(59-59)apps/cli/src/prompts/auth.ts (1)
getAuthChoice(6-56)
apps/cli/src/prompts/runtime.ts (1)
apps/cli/src/types.ts (2)
Runtime(21-21)
Backend(16-16)
apps/cli/src/utils/config-processing.ts (2)
apps/cli/src/types.ts (1)
CLIInput(161-163)apps/cli/src/validation.ts (1)
getProvidedFlags(125-125)
apps/cli/src/utils/compatibility-rules.ts (1)
apps/cli/src/types.ts (1)
Frontend(37-37)
apps/web/src/lib/stack-utils.ts (1)
apps/web/src/lib/constant.ts (1)
StackState(720-739)
apps/cli/src/helpers/addons/addons-setup.ts (1)
apps/cli/src/index.ts (1)
Frontend(249-249)
apps/cli/src/helpers/core/create-readme.ts (1)
apps/cli/src/types.ts (1)
ProjectConfig(165-184)
apps/cli/src/helpers/database-providers/turso-setup.ts (1)
apps/cli/src/utils/errors.ts (1)
exitCancelled(17-23)
apps/cli/src/prompts/web-deploy.ts (1)
apps/cli/src/types.ts (1)
Frontend(37-37)
apps/cli/src/utils/docker-utils.ts (1)
apps/cli/src/types.ts (1)
Database(6-6)
apps/cli/src/prompts/project-name.ts (1)
apps/cli/src/constants.ts (1)
DEFAULT_CONFIG(39-39)
🔇 Additional comments (59)
apps/cli/src/prompts/package-manager.ts (1)
6-6: Keep inferred return strictly as Promise (exitCancelled is typed never). exitCancelled is declaredexport function exitCancelled(...): never, so the async function's inferred return remains Promise; no action required.apps/cli/src/utils/errors.ts (1)
5-7: LGTM on return type inference.Behavior unchanged; call sites using never-typed exits remain correct.
apps/cli/src/prompts/backend.ts (1)
9-9: LGTM — formatting-only change.No functional or type-safety impact.
apps/cli/src/utils/telemetry.ts (1)
7-19: LGTM on inferred boolean return type.Semantics preserved; defaults and env overrides unchanged.
apps/cli/src/helpers/database-providers/docker-compose-setup.ts (1)
37-48: LGTM on return type inference.Function remains internal; string return is unambiguous.
apps/cli/src/utils/sponsors.ts (1)
44-57: LGTM on removing the explicit return type.Inferred Promise is preserved via the cast on response.json().
apps/cli/src/prompts/orm.ts (1)
24-30: LGTM on inference; minor note on union coverage.Return paths still resolve to ORM (including "none" for convex). No action needed.
apps/cli/src/utils/generate-reproducible-command.ts (1)
3-3: LGTM.Return type inference to string is obvious from the final template literal.
apps/cli/src/helpers/core/create-readme.ts (1)
27-27: LGTM on removing explicit string return types across helpers.All functions still clearly return strings; inference is unambiguous.
Also applies to: 166-166, 213-213, 268-268, 352-352, 496-496, 594-594, 660-660
apps/cli/src/utils/bts-config.ts (1)
65-90: LGTM on inferred return type.Inference still yields
BetterTStackConfig | null; control flow unchanged.apps/cli/src/helpers/database-providers/turso-setup.ts (1)
67-91: LGTM on groups fetch and parsing.Behavior is sound; spinner usage and fallback to empty list are fine.
apps/cli/src/utils/ts-morph.ts (1)
19-31: LGTM on inferred return type; cast preserves API.Implementation remains clear and correct.
apps/cli/src/prompts/web-deploy.ts (1)
7-9: LGTM on removing explicit return types.Control flow and discriminated values remain intact;
select<WebDeploy>keeps strong typing.Also applies to: 39-70, 72-125
apps/cli/src/utils/compatibility-rules.ts (1)
15-17: LGTM on inferred returns.
isWebFrontendandallowedApisForFrontendsread well; union narrowing is preserved.Also applies to: 141-150
apps/cli/src/helpers/core/detect-project-config.ts (1)
5-32: LGTM on inferred return type.Return shape matches prior behavior; nullability preserved.
apps/cli/src/prompts/server-deploy.ts (2)
34-39: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
Promise<ServerDeploy>from the return statements.
81-85: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
Promise<ServerDeploy>from the return statements.apps/web/src/lib/stack-utils.ts (4)
28-28: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
stringfrom the ternary operator return statement.
54-54: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
stringfrom the return statement.
129-129: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
stringfrom the return statement.
147-147: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
stringfrom the return statement.apps/cli/src/utils/biome-formatter.ts (4)
8-42: LGTM! Improved error handling with softer approach.The changes improve error handling by returning
nullinstead of logging and throwing on initialization errors. The removal of the explicit return type is clean, with the function type correctly inferred asPromise<{ biome: Biome; projectKey: number } | null>.
44-48: LGTM! Clean removal of return type annotation.The function's return type is correctly inferred as
booleanfrom the return statement.
50-62: LGTM! Enhanced skip patterns with clean type inference.The expanded skip patterns include additional file types that should be excluded from formatting. The function's return type is correctly inferred as
boolean.
64-90: LGTM! Improved error handling and clean type inference.The changes implement softer error handling by returning
nullon failures and properly handle the nullable return frominitializeBiome(). The function's return type is correctly inferred asPromise<string | null>.apps/cli/src/index.ts (1)
221-230: LGTM: inferred return type for initReturn type inference remains stable due to the
as InitResultcast on the returned value.apps/cli/src/prompts/database.ts (1)
6-11: LGTM: remove explicit return typeType inference is clear; function still resolves to
Promise<Database>.apps/cli/src/prompts/examples.ts (1)
10-16: LGTM: inferred return typeNo behavior change; inference yields
Promise<Examples[]>.apps/cli/src/prompts/database-setup.ts (1)
5-11: LGTM: inferred return typeThe control flow still results in
Promise<DatabaseSetup>.apps/cli/src/prompts/api.ts (1)
6-10: LGTM: inferred return typeInferred as
Promise<API>; early returns andselect<API>keep types tight.apps/cli/src/prompts/addons.ts (2)
75-79: LGTM: inferred return type for getAddonsChoiceSignatures rely on inference; generics on
groupMultiselect<Addons>keep types precise.
131-134: LGTM: inferred return type for getAddonsToAddType inference is adequate; no runtime changes.
apps/cli/src/prompts/config-prompts.ts (1)
53-58: LGTM: inferred return type for gatherConfigReturn object shape is explicit; inference is fine.
apps/cli/src/helpers/core/command-handlers.ts (3)
209-213: LGTM on inferred return type; return shape is consistent across branches.
40-43: LGTM — confirm/remove remaining InitResult referencesInferred return type is fine. rg shows InitResult still referenced; confirm these are intentional or update/remove them to match the new return shape:
- apps/cli/src/index.ts: lines 30, 229, 262
- apps/cli/src/types.ts: line 204 (InitResult interface)
- apps/web/content/docs/cli/programmatic-api.mdx: lines 93, 156, 161
If stale, replace/remove uses (e.g.,
return result as InitResult) to avoid a mismatched public type.
128-131: Use resolved directory path (finalResolvedPath) for projectDirectoryprojectDirectory must be the resolved filesystem path — passing input.projectName provides a name, not a path, and can break downstream validators.
File: apps/cli/src/helpers/core/command-handlers.ts (lines 128–131)
- const cliInput = { - ...input, - projectDirectory: input.projectName, - }; + const cliInput = { + ...input, + projectDirectory: finalResolvedPath, + };Verify usages (run locally if file not found):
rg -n --hidden --files -g 'apps/cli/**' 'command-handlers.ts' || true
rg -n -C3 '\bprojectDirectory\b' apps/cli || true
rg -n -C3 '\bprojectName\b' apps/cli || true
rg -n -C3 '\bfinalResolvedPath\b' apps/cli || true
rg -n -C3 -e 'extractAndValidateProjectName(' -e 'deriveProjectName(' apps/cli || trueapps/cli/src/validation.ts (2)
47-52: LGTM on removing explicit return type.Inference yields Partial; behavior unchanged.
89-93: LGTM on removing explicit return type.Matches the pattern used in processAndValidateFlags.
apps/cli/src/utils/config-processing.ts (5)
23-27: LGTM on inferred return type for deriveProjectName.
36-38: LGTM on inferred return type for processFlags; explicit Partial on the local keeps the return typed.
107-113: LGTM on inferred return type for getProvidedFlags (Set inferred).
115-119: LGTM on inferred void for validateNoneExclusivity.
126-130: LGTM on inferred void for validateArrayOptions.apps/cli/src/utils/config-validation.ts (9)
20-24: LGTM on removing explicit void.
91-97: LGTM on removing explicit void.
188-193: LGTM on removing explicit void.
243-247: LGTM on removing explicit void.
298-304: LGTM on removing explicit void.
353-359: LGTM on removing explicit void.
375-381: LGTM on removing explicit void.
392-398: LGTM on removing explicit void.
431-435: LGTM on removing explicit void.apps/cli/src/prompts/project-name.ts (2)
16-24: Return-type inference here is fineThe inferred
string | undefinedworks with downstream checks; no action needed.
44-44: Explicit local type is fineKeeping
defaultName: stringis consistent with the PR scope (removing return types only). No change.apps/cli/src/utils/project-directory.ts (2)
8-12: Signature return-type removal aligns with PR goalsType inference remains precise for the returned object and early-exit paths. LGTM.
83-87: Signature return-type removal aligns with PR goalsInferred
{ finalResolvedPath: string; finalBaseName: string }is clear. LGTM.apps/cli/src/utils/project-name-validation.ts (2)
5-14: Return-type removal is safeFunction performs side effects only; inferred
voidis appropriate.
23-47: Extractor validator: OKInferred
stringreturn is preserved; flow remains unchanged. LGTM.apps/cli/src/utils/docker-utils.ts (1)
20-51: Return-type removal: install instructionsInferred
stringreturn is clear; content unchanged. LGTM.
| @@ -1,4 +1,5 @@ | |||
| import os from "node:os"; | |||
| import { $ } from "execa"; | |||
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.
🛠️ Refactor suggestion
Replace execa with Bun.$ per repo guidelines
This project standardizes on Bun for shelling out. Switch to Bun.$ (or import { $ } from "bun").
-import { $ } from "execa";
+import { $ } from "bun";No other changes needed since the template-literal API is compatible:
export async function isDockerRunning() {
  try {
    await $`docker info`;
    return true;
  } catch {
    return false;
  }
}🤖 Prompt for AI Agents
In apps/cli/src/utils/docker-utils.ts around line 2, the file imports $ from
"execa" but the repo standard requires using Bun's shell helper; replace the
execa import with Bun's ($ from "bun") or reference Bun.$ directly. Update the
import statement to pull $ from "bun" (or remove the import and use Bun.$) and
leave the rest of the code unchanged since the template-literal API is
compatible.
Summary by CodeRabbit
Bug Fixes
Refactor
Documentation