feat(init): detect agent/CI environments and skip interactive prompts#1264
feat(init): detect agent/CI environments and skip interactive prompts#1264atinux wants to merge 9 commits into
Conversation
Uses `std-env` v4's `isAgent`, `isCI`, and `hasTTY` to automatically detect when the CLI is run non-interactively (AI agents, CI pipelines, piped input) and apply sensible defaults instead of hanging on prompts. Adds two explicit flags for opt-in: - `--defaults` / `-y`: accept all defaults (like `npm init -y`) - `--no-interactive`: same, more explicit for scripting contexts When non-interactive mode is detected, the CLI: - Logs the reason (agent name, CI, no TTY, or flag) - Displays a full options reference — including all available templates fetched live — so agents can discover flags and re-run with custom settings - Auto-selects: template=minimal, dir=template's defaultDir, package manager=detected or npm, gitInit=false, modules=skipped - Fails fast (instead of hanging) when the target directory already exists, instructing the caller to pass `--force` All existing interactive behaviour is preserved when a TTY is present and none of the new flags are set. https://claude.ai/code/session_01LsDZBSg7peDmxh6QW33ag8
- Move detectCurrentPackageManager() before template load so package manager is known upfront - Compute all effective defaults (template, dir, pm, gitInit, install, modules) before any action is taken and display them together in a 'Proceeding with:' section at the bottom of the options note - Show all available templates with the default marked (← default) - Fix module examples to use @nuxt/content,@nuxt/ui,@nuxt/image - Remove scattered 'Auto-selected X' log lines — they are now covered by the single consolidated note - Simplify the non-interactive module-skip branch https://claude.ai/code/session_01LsDZBSg7peDmxh6QW33ag8
When running non-interactively (agent/CI/no-TTY) without a project directory, show the available options note then exit cleanly instead of proceeding with defaults. The agent reads the output, chooses the right flags, and re-runs with an explicit <dir>. nuxi init → shows options, exits (no project created) nuxi init my-app → creates my-app with defaults nuxi init my-app -t v3 → creates my-app with v3 template https://claude.ai/code/session_01LsDZBSg7peDmxh6QW33ag8
commit: |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new --yes / -y boolean flag and imports note for non-interactive messaging. The init command computes isNonInteractive from --yes or lack of TTY, moves package-manager detection earlier, and adjusts flows: when non-interactive and no --dir is provided it prints available templates and exits; non-interactive runs error on existing target dirs without --force, default package manager is the detected one (or npm), git init defaults to false unless explicit, and the modules browse/install prompt is skipped. Tests updated to cover non-interactive behavior and normalize flag forms. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/nuxi/src/commands/init.ts (1)
174-223: Consider centralizing resolved defaults to avoid drift between “note” and execution paths.Effective values are computed in the note block and then re-derived later for actual execution. A single
resolvedOptionsobject would reduce maintenance risk.Also applies to: 236-240, 271-276, 443-448, 465-469
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxi/src/commands/init.ts` around lines 174 - 223, Create a single resolvedOptions object (e.g. { template, dir, packageManager, gitInit, install, modules, offline, force }) computed once in init.ts and replace the duplicated local computations (the variables effectiveTemplate, effectiveDir, effectivePM, effectiveGitInit, effectiveInstall, effectiveModules) so both the non-interactive "note" block and the later execution paths reuse the same resolvedOptions; update all referenced sites (the note block and the other duplicated ranges you flagged around lines 236-240, 271-276, 443-448, 465-469) to read from resolvedOptions to avoid drift and ensure consistent defaults across the codepaths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/nuxi/src/commands/init.ts`:
- Around line 130-135: The multiline boolean assignment for const
isNonInteractive (and the other multiline boolean expression further down) has
inconsistent indentation that breaks ESLint; reformat these expressions so
continuation lines are consistently indented — either align each boolean operand
under the first operand or wrap the RHS in parentheses and indent each
subsequent line one level (e.g., two spaces or one tab) so the operators (||)
and the operands line up consistently; update the lines that contain
isNonInteractive and the similar boolean block near the later expression to
match the project's multiline indentation style.
---
Nitpick comments:
In `@packages/nuxi/src/commands/init.ts`:
- Around line 174-223: Create a single resolvedOptions object (e.g. { template,
dir, packageManager, gitInit, install, modules, offline, force }) computed once
in init.ts and replace the duplicated local computations (the variables
effectiveTemplate, effectiveDir, effectivePM, effectiveGitInit,
effectiveInstall, effectiveModules) so both the non-interactive "note" block and
the later execution paths reuse the same resolvedOptions; update all referenced
sites (the note block and the other duplicated ranges you flagged around lines
236-240, 271-276, 443-448, 465-469) to read from resolvedOptions to avoid drift
and ensure consistent defaults across the codepaths.
🪄 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
Run ID: dfda46aa-f2f3-4a95-b0f4-36571b8806e5
📒 Files selected for processing (1)
packages/nuxi/src/commands/init.ts
…ndition The original condition (!template || !dir) already covers every case where templates need to be loaded for prompts or the options note. Adding isNonInteractive caused an unnecessary network fetch when an agent provided both --template and dir (only to populate a template list in the note that wasn't needed). The 'Proceeding with:' section in the note still works correctly without it. https://claude.ai/code/session_01LsDZBSg7peDmxh6QW33ag8
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/nuxi/src/commands/init.ts (1)
188-189: Consider extracting the string 'false' coercion pattern.The
(ctx.args.gitInit as unknown) === 'false'pattern appears multiple times (here, line 465, line 487). A small helper liketoBool(value)could reduce duplication and clarify intent.♻️ Optional: Extract helper function
// Add near the top of the file or in a shared utils function parseBoolArg(value: unknown): boolean | undefined { if (value === 'false') return false if (value === 'true') return true return value as boolean | undefined }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxi/src/commands/init.ts` around lines 188 - 189, The code duplicates a string-'false' coercion pattern when computing effectiveGitInit and effectiveInstall; extract a small helper (e.g., parseBoolArg or toBool) that accepts unknown and returns boolean | undefined by mapping 'false'->false, 'true'->true and otherwise returning the value as boolean | undefined, then replace the inline checks in effectiveGitInit and effectiveInstall (and any other occurrences like the ones noted around lines using ctx.args.gitInit / ctx.args.install) to call that helper to reduce duplication and clarify intent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/nuxi/src/commands/init.ts`:
- Around line 274-276: The if-branch that sets dir = defaultDir when
isNonInteractive is unreachable and should be removed; locate the conditional
using isNonInteractive and dir (the block "if (isNonInteractive) { dir =
defaultDir }") in the init command and delete that branch so the code flow
relies on the existing early-exit behavior around ctx.args.dir, or if you intend
non-interactive to auto-select a directory instead, adjust the earlier
early-exit logic that checks ctx.args.dir rather than keeping this unreachable
fallback.
---
Nitpick comments:
In `@packages/nuxi/src/commands/init.ts`:
- Around line 188-189: The code duplicates a string-'false' coercion pattern
when computing effectiveGitInit and effectiveInstall; extract a small helper
(e.g., parseBoolArg or toBool) that accepts unknown and returns boolean |
undefined by mapping 'false'->false, 'true'->true and otherwise returning the
value as boolean | undefined, then replace the inline checks in effectiveGitInit
and effectiveInstall (and any other occurrences like the ones noted around lines
using ctx.args.gitInit / ctx.args.install) to call that helper to reduce
duplication and clarify intent.
🪄 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
Run ID: 3ee15017-9503-4ce1-a8d1-f4ac2d4094fc
📒 Files selected for processing (1)
packages/nuxi/src/commands/init.ts
📦 Bundle Size Comparison📈 nuxi
📈 nuxt-cli
📈 create-nuxt
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/nuxi/src/commands/init.ts (1)
188-189: Minor style inconsistency in type casting.Lines 188 and 460 handle the string
'false'from citty differently:
- Line 188:
(ctx.args.gitInit as unknown) === 'false'- Line 460:
ctx.args.gitInit === 'false' as unknownBoth work, but the inconsistency could cause confusion. Consider unifying the pattern.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxi/src/commands/init.ts` around lines 188 - 189, The code inconsistently casts ctx.args.gitInit to check for the string 'false' (used in effectiveGitInit) versus casting the comparison in another place; standardize the pattern by using the same explicit cast/location for the comparison across usages (e.g., always cast ctx.args.gitInit to unknown or string before comparing), update the check in the effectiveGitInit assignment to match the other occurrence so both use the same style, and ensure any related checks (like effectiveInstall) follow the same casting convention; specifically look for and update references to effectiveGitInit and ctx.args.gitInit to use the unified pattern.
🤖 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/nuxi/src/commands/init.ts`:
- Around line 188-189: The code inconsistently casts ctx.args.gitInit to check
for the string 'false' (used in effectiveGitInit) versus casting the comparison
in another place; standardize the pattern by using the same explicit
cast/location for the comparison across usages (e.g., always cast
ctx.args.gitInit to unknown or string before comparing), update the check in the
effectiveGitInit assignment to match the other occurrence so both use the same
style, and ensure any related checks (like effectiveInstall) follow the same
casting convention; specifically look for and update references to
effectiveGitInit and ctx.args.gitInit to use the unified pattern.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4c6de8bf-3229-4e24-9d31-ef760881db95
📒 Files selected for processing (1)
packages/nuxi/src/commands/init.ts
|
Good to be reviewed @danielroe |
posva
left a comment
There was a problem hiding this comment.
This is what I think. Some agents automatically run --help to auto discover what they can do or they use it as soon as the command fails. So I really think you can keep this very lean in terms of changes as long as the --help text is good. I would say the only missing part are templates which can be listed if you detect an agent
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/nuxi/src/commands/init.ts (1)
156-156: 💤 Low valueConsider moving regex to module scope for consistency.
The inline regex
/\.[cm]?js$/is re-compiled on each invocation. While the impact is minimal (single execution per CLI run), moving it to module scope would be consistent with the existing pattern used forNON_WORD_RE,MULTI_DASH_RE, andLEADING_TRAILING_DASH_RE.♻️ Suggested refactor
Add near line 32:
const JS_EXT_RE = /\.[cm]?js$/Then update line 156:
- const binName = basename(process.argv[1] || 'nuxi').replace(/\.[cm]?js$/, '') || 'nuxi' + const binName = basename(process.argv[1] || 'nuxi').replace(JS_EXT_RE, '') || 'nuxi'🤖 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/nuxi/src/commands/init.ts` at line 156, Move the inline regex used to strip JS extensions into module scope for consistency with existing regex constants: define a top-level constant (e.g., JS_EXT_RE) containing /\.[cm]?js$/ near where NON_WORD_RE, MULTI_DASH_RE, and LEADING_TRAILING_DASH_RE are declared, then update the binName assignment in init.ts (the line that builds binName using basename(process.argv[1] || 'nuxi').replace(...)) to use JS_EXT_RE instead of the inline `/\.[cm]?js$/`.
🤖 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.
Nitpick comments:
In `@packages/nuxi/src/commands/init.ts`:
- Line 156: Move the inline regex used to strip JS extensions into module scope
for consistency with existing regex constants: define a top-level constant
(e.g., JS_EXT_RE) containing /\.[cm]?js$/ near where NON_WORD_RE, MULTI_DASH_RE,
and LEADING_TRAILING_DASH_RE are declared, then update the binName assignment in
init.ts (the line that builds binName using basename(process.argv[1] ||
'nuxi').replace(...)) to use JS_EXT_RE instead of the inline `/\.[cm]?js$/`.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 48acc0ea-e376-4988-8ab5-9fc68fbe3d9d
📒 Files selected for processing (3)
packages/create-nuxt/test/init.spec.tspackages/nuxi/src/commands/init.tspackages/nuxt-cli/test/e2e/commands.spec.ts
|
|
||
| intro(colors.bold(`Welcome to Nuxt!`.split('').map(m => `${themeColor}${m}`).join(''))) | ||
|
|
||
| const isNonInteractive = ctx.args.yes === true || !hasTTY |
There was a problem hiding this comment.
Rather than defaulting immediately to --yes in non-TTY mode, if the option --yes isn't set, show the help so it can be invoked with the proper arguments.
Actually, it's a bit more complex, ideally the CLI should detect if it has all the information it needs to run without interactivity, if not, show the help and exit with non-zero (like 2)
| yes: { | ||
| type: 'boolean', | ||
| alias: 'y', | ||
| description: 'Use default values for all prompts', |
There was a problem hiding this comment.
| description: 'Use default values for all prompts', | |
| description: 'Use default values for and skip interactive prompts', |
| '', | ||
| ...templateLines, | ||
| '', | ||
| `Run ${colors.cyan(`${initCmd} --help`)} for all options.`, |
There was a problem hiding this comment.
I wonder if it should just display the help before the list of templates. I think this could be simplified by merging this message with my suggestion above: if options are missing show the help and the list of templates because it's needed to provide a value
Uses
std-envv4'sisAgent,isCI, andhasTTYto automaticallydetect when the CLI is run non-interactively (AI agents, CI pipelines,
piped input) and apply sensible defaults instead of hanging on prompts.
Adds two explicit flags for opt-in:
--defaults/-y: accept all defaults (likenpm init -y)--no-interactive: same, more explicit for scripting contextsWhen non-interactive mode is detected, the CLI:
fetched live — so agents can discover flags and re-run with custom
settings
manager=detected or npm, gitInit=false, modules=skipped
exists, instructing the caller to pass
--forceAll existing interactive behaviour is preserved when a TTY is present
and none of the new flags are set.