Skip to content

feat: improve upgrade hints + add init hint/tip - #1406

Open
danielroe wants to merge 2 commits into
mainfrom
feat/tips
Open

feat: improve upgrade hints + add init hint/tip#1406
danielroe wants to merge 2 commits into
mainfrom
feat/tips

Conversation

@danielroe

@danielroe danielroe commented Jul 27, 2026

Copy link
Copy Markdown
Member

🔗 Linked issue

resolves #897

📚 Description

this adds a tip after installing nuxt

image

it also lets us know if there's an old version of create-nuxt:

image

... and updates the style for letting you know about an old version of nuxt in your project

image

@pkg-pr-new

pkg-pr-new Bot commented Jul 27, 2026

Copy link
Copy Markdown
  • nuxt-cli-playground

    npm i https://pkg.pr.new/create-nuxt@1406
    
    npm i https://pkg.pr.new/nuxi@1406
    
    npm i https://pkg.pr.new/@nuxt/cli@1406
    

commit: e92d86e

Comment thread packages/nuxt-cli/src/utils/headless.ts Fixed
@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing feat/tips (e92d86e) with main (4538067)

Open in CodSpeed

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f2ace803-9de3-4430-ae85-16976fdccf02

📥 Commits

Reviewing files that changed from the base of the PR and between e8f7e4c and e92d86e.

📒 Files selected for processing (6)
  • packages/nuxt-cli/src/utils/headless.ts
  • packages/nuxt-cli/src/utils/stdout.ts
  • packages/nuxt-cli/src/utils/update-check.ts
  • packages/nuxt-cli/test/unit/utils/headless.spec.ts
  • packages/nuxt-cli/test/unit/utils/stdout.spec.ts
  • packages/nuxt-cli/test/unit/utils/update.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/nuxt-cli/test/unit/utils/headless.spec.ts
  • packages/nuxt-cli/src/utils/headless.ts
  • packages/nuxt-cli/test/unit/utils/update.spec.ts
  • packages/nuxt-cli/src/utils/update-check.ts

📝 Walkthrough

Walkthrough

The CLI now centralizes cached update checks and deferred update messaging, including self-update nudges for unpinned create invocations. It adds utilities for generating shell-safe headless scaffold commands, detecting pinned invocations, wrapping commands, and resolving positional project directories. Setup flows await engine checks before prompts, while initialization tracks installation and prompt state, adjusts module handling, and prints headless rerun instructions.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also adds update-check, self-update, stdout-spacing, and path-resolution changes that are unrelated to #897. Split the unrelated update and helper changes into separate PRs or link the issues they address.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main changes around upgrade hints and the new init tip.
Description check ✅ Passed The description is clearly related to the PR and mentions the added tips and notices.
Linked Issues check ✅ Passed The new headless init tip flow matches #897's request to show CLI-argument tips during first-time option selection.
✨ 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 feat/tips

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nuxt-cli/src/commands/init.ts`:
- Around line 754-769: Update the formatHeadlessCommand call in the hasTTY &&
prompted block so its force option is always enabled, rather than inheriting
shouldForce. Keep the generated command’s other options unchanged and ensure it
includes --force for reliable non-interactive reruns in the existing project
directory.

In `@packages/nuxt-cli/src/utils/update-check.ts`:
- Line 5: Replace the deprecated readUser and updateUser imports with rc9’s
readUserConfig and updateUserConfig helpers, then update their usages in the
update-check cache flow to use the new APIs while preserving the existing
.nuxtrc cache behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 678a3284-ebfc-44ce-bfa0-9db4ec63c0a9

📥 Commits

Reviewing files that changed from the base of the PR and between 4538067 and e8f7e4c.

📒 Files selected for processing (10)
  • packages/create-nuxt/src/main.ts
  • packages/nuxt-cli/src/commands/init.ts
  • packages/nuxt-cli/src/main.ts
  • packages/nuxt-cli/src/utils/headless.ts
  • packages/nuxt-cli/src/utils/paths.ts
  • packages/nuxt-cli/src/utils/update-check.ts
  • packages/nuxt-cli/src/utils/update.ts
  • packages/nuxt-cli/test/unit/utils/headless.spec.ts
  • packages/nuxt-cli/test/unit/utils/paths.spec.ts
  • packages/nuxt-cli/test/unit/utils/update.spec.ts

Comment on lines +754 to +769
if (hasTTY && prompted) {
const headlessCommand = formatHeadlessCommand({
// Two columns for the gutter clack puts in front of each line, and one
// of slack so a full line never wraps in the terminal itself.
width: Math.max((process.stdout.columns || 80) - 3, 40),
dir: projectDir,
template: templateName,
packageManager: selectedPackageManager,
gitInit: Boolean(gitInit),
install: installRequested,
force: shouldForce,
// `modulesToAdd` is empty when a failed install stopped us adding the
// modules that were asked for, which the command should still request.
modules: modulesToAdd.length ? modulesToAdd : requestedModules,
nightly: ctx.args.nightly,
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Headless "scaffold again" command should always force-overwrite.

The printed reproduction command is meant to let the project be scaffolded again non-interactively (e.g. by an agent/script), but it will land in the same, now-existing directory. Passing force: shouldForce means the command omits --force in the common case (matching the PR's own example screenshot, which shows --force in an otherwise fresh scaffold). Without it, re-running the printed command against an existing directory hits the "already exists" prompt and, in a non-interactive context, exits with an error — defeating the stated goal of a headless, scriptable command.

🐛 Proposed fix
       const headlessCommand = formatHeadlessCommand({
         // Two columns for the gutter clack puts in front of each line, and one
         // of slack so a full line never wraps in the terminal itself.
         width: Math.max((process.stdout.columns || 80) - 3, 40),
         dir: projectDir,
         template: templateName,
         packageManager: selectedPackageManager,
         gitInit: Boolean(gitInit),
         install: installRequested,
-        force: shouldForce,
+        // The reproduction command targets a directory that already exists
+        // (the one just scaffolded), so it always needs to force-overwrite.
+        force: true,
         // `modulesToAdd` is empty when a failed install stopped us adding the
         // modules that were asked for, which the command should still request.
         modules: modulesToAdd.length ? modulesToAdd : requestedModules,
         nightly: ctx.args.nightly,
       })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (hasTTY && prompted) {
const headlessCommand = formatHeadlessCommand({
// Two columns for the gutter clack puts in front of each line, and one
// of slack so a full line never wraps in the terminal itself.
width: Math.max((process.stdout.columns || 80) - 3, 40),
dir: projectDir,
template: templateName,
packageManager: selectedPackageManager,
gitInit: Boolean(gitInit),
install: installRequested,
force: shouldForce,
// `modulesToAdd` is empty when a failed install stopped us adding the
// modules that were asked for, which the command should still request.
modules: modulesToAdd.length ? modulesToAdd : requestedModules,
nightly: ctx.args.nightly,
})
if (hasTTY && prompted) {
const headlessCommand = formatHeadlessCommand({
// Two columns for the gutter clack puts in front of each line, and one
// of slack so a full line never wraps in the terminal itself.
width: Math.max((process.stdout.columns || 80) - 3, 40),
dir: projectDir,
template: templateName,
packageManager: selectedPackageManager,
gitInit: Boolean(gitInit),
install: installRequested,
// The reproduction command targets a directory that already exists
// (the one just scaffolded), so it always needs to force-overwrite.
force: true,
// `modulesToAdd` is empty when a failed install stopped us adding the
// modules that were asked for, which the command should still request.
modules: modulesToAdd.length ? modulesToAdd : requestedModules,
nightly: ctx.args.nightly,
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxt-cli/src/commands/init.ts` around lines 754 - 769, Update the
formatHeadlessCommand call in the hasTTY && prompted block so its force option
is always enabled, rather than inheriting shouldForce. Keep the generated
command’s other options unchanged and ensure it includes --force for reliable
non-interactive reruns in the existing project directory.


import { S_INFO } from '@clack/prompts'
import colors from 'picocolors'
import { readUser, updateUser } from 'rc9'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Are rc9 readUser writeUser updateUser deprecated in favor of readUserConfig writeUserConfig updateUserConfig?

💡 Result:

Yes, the functions readUser, writeUser, and updateUser are deprecated in the rc9 package [1][2][3]. They have been replaced by readUserConfig, writeUserConfig, and updateUserConfig, respectively [1][2][4]. The primary reason for this change is to ensure compliance with XDG Base Directory conventions, as the new functions store configurations in the user's config directory (typically $XDG_CONFIG_HOME or ~/.config) rather than directly in the user's home directory [1][3][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | rg 'packages/nuxt-cli/src/utils/update-check\.ts$|rc9|package.json|pnpm-lock|package-lock|yarn\.lock'

echo "== update-check.ts outline =="
ast-grep outline packages/nuxt-cli/src/utils/update-check.ts --view compact || true

echo "== relevant update-check.ts lines =="
sed -n '1,120p' packages/nuxt-cli/src/utils/update-check.ts | cat -n

echo "== lock/package rc9 versions/usages =="
rg -n '"rc9"|rc9@|readUserConfig|writeUserConfig|updateUserConfig|readUser|writeUser|updateUser' package.json packages -g 'package.json' -g 'pnpm-lock.yaml' -g 'package-lock.json' -g 'yarn.lock' || true

echo "== npm rc9 docs availability/version summary if npm supports it =="
npm view rc9 versions --json | tail -20 || true
npm view rc9 readme --json 2>/dev/null | python3 - <<'PY'
import sys,json
try:
    meta=json.load(sys.stdin)
except Exception:
    print("cannot parse npm metadata")
    raise SystemExit
text=meta.get("readme","")
for needle in ["readUser", "updateUser", "readUserConfig", "updateUserConfig", "deprecated"]:
    print(needle, "-- count:", text.lower().count(needle.lower()))
PY

Repository: nuxt/cli

Length of output: 5862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== packages/nuxt-cli/package.json rc9 section =="
jq '.dependencies, .devDependencies | with_entries(select(.key=="rc9"))' packages/nuxt-cli/package.json

echo "== npm rc9 3.0.1 package files and README excerpt =="
tmp="$(mktemp -d)"
tarball="$(npm view rc9@3.0.1 dist.tarball 2>/dev/null || true)"
echo "tarball=$tarball"
if [ -n "$tarball" ]; then
  curl -fsSL "$tarball" -o "$tmp/rc9.tgz"
  tar -tzf "$tmp/rc9.tgz" | sed -n '1,120p'
  tar -xzf "$tmp/rc9.tgz" -C "$tmp" package
  echo "--- package.json excerpt ---"
  jq '.exports, .types, .name, .version' "$tmp/package/package.json"
  echo "--- module excerpt ---"
  sed -n '1,220p' "$tmp/package/dist/index.mjs" | cat -n
  echo "--- types excerpt ---"
  sed -n '1,220p' "$tmp/package/dist/index.d.cts" | cat -n
fi

echo "== local type/import compatibility without executing repo =="
node - <<'JS'
const fs = require('fs');
const path = require('path');
const file = 'packages/nuxt-cli/src/utils/update-check.ts';
const pkg = JSON.parse(fs.readFileSync('packages/nuxt-cli/package.json', 'utf8'));
const source = fs.readFileSync(file, 'utf8');
console.log('rc9 dependency:', pkg.dependencies?.rc9 || pkg.cotDependencies?.rc9);
console.log('imports readUser/updateUser:', source.includes("readUser"), source.includes("updateUser"));
console.log('imports readUserConfig/updateUserConfig:', source.includes("readUserConfig"), source.includes("updateUserConfig"));
JS

Repository: nuxt/cli

Length of output: 8920


Migrate update-check cache to the non-deprecated rc9 helpers.

readUser/updateUser are deprecated in rc9 3.0.x in favor of the XDG-config helpers; use readUserConfig and updateUserConfig for the new .nuxtrc cache so this code doesn’t rely on deprecated APIs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxt-cli/src/utils/update-check.ts` at line 5, Replace the
deprecated readUser and updateUser imports with rc9’s readUserConfig and
updateUserConfig helpers, then update their usages in the update-check cache
flow to use the new APIs while preserving the existing .nuxtrc cache behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show tips about CLI arguments when used for the first time

2 participants