Skip to content

feat(cli): interactive Ultracite linter selection in verno create#2

Merged
PunGrumpy merged 5 commits into
mainfrom
fix/interactive-ultracite-linter
Apr 28, 2026
Merged

feat(cli): interactive Ultracite linter selection in verno create#2
PunGrumpy merged 5 commits into
mainfrom
fix/interactive-ultracite-linter

Conversation

@PunGrumpy

@PunGrumpy PunGrumpy commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Problem

Interactive verno create with the Ultracite add-on runs ultracite init with --pm. Ultracite treats that as a non-interactive signal and skips the linter prompt, defaulting to Biome. Users who expected to pick Oxlint or ESLint never saw a linter step, while Verno’s copy suggested they would choose the stack in Ultracite.

Root cause

Ultracite’s init flow does not prompt for a linter when --pm is set without --linter; tooling like Verno always passes --pm to pin the package manager.

Result

  • The interactive wizard asks for a linter preset (Oxlint, Biome, or ESLint + Prettier + Stylelint) when the Ultracite add-on is on and --linter is not passed on the CLI.
  • Verno passes ultracite init --linter <id> so the choice is explicit and CI/non-interactive (-y) behavior is unchanged (still defaults to oxlint when --linter is omitted).
  • CLI help, README, manifest field comment, scaffold template README, and create-plan tests are aligned with the new flow.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Interactive setup wizard now prompts for linter selection when Ultracite is enabled and always shows the chosen linter in the init summary; non-interactive runs pass an explicit --linter.
  • Documentation

    • Updated CLI help, project templates, and READMEs to document the new Ultracite initialization and linter-selection flow (including -y default behavior).
  • Tests

    • Updated interactive-create tests to expect explicit --linter usage and default linter behavior.

PunGrumpy and others added 4 commits April 28, 2026 16:03
Verno asks for biome, eslint, or oxlint when the ultracite add-on is
enabled and --linter is not set, then passes --linter to ultracite init.
This avoids relying on Ultracite skipping linter selection when --pm is set.
Document interactive wizard behavior, CLI --linter help, and manifest field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ResolvedCreateInputs from the wizard now always carries ultraciteLinter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…EADME

Avoid implying interactive ultracite init always prompts for linter; point to
verno create --linter and manual ultracite init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 804c7e49-7b71-4564-aaab-04fa7c25af71

📥 Commits

Reviewing files that changed from the base of the PR and between 7fb7452 and 458b0a6.

📒 Files selected for processing (1)
  • packages/cli/src/commands/create.ts

📝 Walkthrough

Walkthrough

Interactive verno create now prompts for an Ultracite linter when --linter is not provided and passes the resolved --linter to ultracite init. Docs, tests, prompts, and generated templates were updated to reflect this behavior.

Changes

Cohort / File(s) Summary
README & Templates
packages/cli/README.md, packages/template-generator/templates/shared/README.md.hbs, packages/template-generator/src/templates.generated.ts
Updated README/template text to state verno create supplies ultracite init --linter (or interactive Ultracite); fixed spacing in generated Next.js dev script.
CLI Help & JSDoc
packages/cli/src/index.ts, packages/cli/src/commands/create-actions.ts, packages/cli/src/commands/create-args.ts
Clarified help text and JSDoc: ultraciteLinter is provided via CLI flag, wizard selection, or -y default; no signature changes.
Prompts / Wizard
packages/cli/src/commands/create-prompts.ts
Added conditional prompt to ask for Ultracite linter when Ultracite is enabled and --linter is unset; summary now shows explicit --linter (falls back to DEFAULT_ULTRACITE_LINTER).
Create Flow / Messaging
packages/cli/src/commands/create.ts
Require a resolved ultraciteLinter when running Ultracite; simplified Ultracite header and messaging; interactive vs non-interactive ultracite init modes handled explicitly.
Tests
packages/cli/__tests__/create-plan.test.ts
Updated interactive create test to provide ultraciteLinter ("oxlint") and assert --linter oxlint is included in generated Ultracite args.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant VernoCLI as Verno CLI (wizard)
  participant Ultracite as Ultracite init

  User->>VernoCLI: run "verno create" (interactive)
  VernoCLI->>VernoCLI: check if ultracite enabled & --linter provided
  alt --linter not provided
    VernoCLI->>User: prompt for linter (DEFAULT_ULTRACITE_LINTER preselected)
    User->>VernoCLI: select linter
  end
  VernoCLI->>Ultracite: run "ultracite init --linter <selected>"
  Ultracite-->>User: interactive initialization continues
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I asked the user, “Which linter?” with a hop,
I nudged the wizard till the choice did stop,
oxlint tucked in the command with cheer,
Ultracite wakes, the path is clear—
Hop, test, commit, and off we trot! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding interactive Ultracite linter selection to verno create, which is the central focus of all file modifications.
Description check ✅ Passed The description comprehensively covers the problem, root cause, and solution, but is missing required checklist items (all unchecked) and lacks a changeset file reference or related issues link.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/interactive-ultracite-linter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/cli/src/commands/create.ts (1)

186-193: Enforce the “linter must be resolved” invariant before interactive Ultracite run.
At Line 187, silently allowing undefined can hide regressions and re-open implicit-linter behavior. Prefer failing fast (or defaulting explicitly) in this branch.

♻️ Suggested tightening
-      const prefix =
-        resolved.ultraciteLinter === undefined ? "" : `Linter: ${resolved.ultraciteLinter}. `;
+      if (resolved.ultraciteLinter === undefined) {
+        throw new CLIError("Internal error: ultracite linter must be resolved for interactive runs.", {
+          code: "VALIDATION",
+        });
+      }
+      const prefix = `Linter: ${resolved.ultraciteLinter}. `;
       process.stdout.write(
         `\n${pc.cyan("ultracite")} — ${prefix}Continue in Ultracite for frameworks, editors, and hooks.\n\n`,
       );
       await runUltraciteIfEnabled(true, resolved.packageManager, projectDir, "interactive", {
         ciSafe: false,
         linter: resolved.ultraciteLinter,
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/create.ts` around lines 186 - 193, The code
currently allows resolved.ultraciteLinter to be undefined before calling
runUltraciteIfEnabled, which hides regressions; update the create command to
enforce that resolved.ultraciteLinter is resolved before launching the
interactive Ultracite run (the prefix calculation and the
runUltraciteIfEnabled(...) call). Specifically, check resolved.ultraciteLinter
and either throw a clear error (fail-fast) or explicitly assign a default value
before computing prefix and calling runUltraciteIfEnabled, and ensure the
error/assignment references resolved.ultraciteLinter so the invariant is
explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/cli/src/commands/create.ts`:
- Around line 186-193: The code currently allows resolved.ultraciteLinter to be
undefined before calling runUltraciteIfEnabled, which hides regressions; update
the create command to enforce that resolved.ultraciteLinter is resolved before
launching the interactive Ultracite run (the prefix calculation and the
runUltraciteIfEnabled(...) call). Specifically, check resolved.ultraciteLinter
and either throw a clear error (fail-fast) or explicitly assign a default value
before computing prefix and calling runUltraciteIfEnabled, and ensure the
error/assignment references resolved.ultraciteLinter so the invariant is
explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c6c3fec2-d0bb-4173-8f04-c1f4b38dfab7

📥 Commits

Reviewing files that changed from the base of the PR and between 4d13e4f and 7fb7452.

📒 Files selected for processing (9)
  • packages/cli/README.md
  • packages/cli/__tests__/create-plan.test.ts
  • packages/cli/src/commands/create-actions.ts
  • packages/cli/src/commands/create-args.ts
  • packages/cli/src/commands/create-prompts.ts
  • packages/cli/src/commands/create.ts
  • packages/cli/src/index.ts
  • packages/template-generator/src/templates.generated.ts
  • packages/template-generator/templates/shared/README.md.hbs

Fail fast with CLIError when the ultracite add-on runs without a linter
preset. Consolidate quiet and interactive paths under one resolved linter.

Co-Authored-By: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@PunGrumpy
PunGrumpy merged commit 8f0e19d into main Apr 28, 2026
4 checks passed
@PunGrumpy
PunGrumpy deleted the fix/interactive-ultracite-linter branch April 28, 2026 10:28
@PunGrumpy PunGrumpy added the enhancement new feature or request label Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement new feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant