Skip to content

feat(init): detect agent/CI environments and skip interactive prompts#1264

Open
atinux wants to merge 5 commits intomainfrom
claude/nuxt-cli-agent-support-sTRzI
Open

feat(init): detect agent/CI environments and skip interactive prompts#1264
atinux wants to merge 5 commits intomainfrom
claude/nuxt-cli-agent-support-sTRzI

Conversation

@atinux
Copy link
Copy Markdown
Member

@atinux atinux commented Mar 26, 2026

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

claude added 3 commits March 26, 2026 18:31
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
@atinux atinux requested a review from danielroe as a code owner March 26, 2026 18:47
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 26, 2026

  • nuxt-cli-playground

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

commit: 66b26f8

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8e7ab39a-c1f5-4796-b66f-f3871bd3dea9

📥 Commits

Reviewing files that changed from the base of the PR and between fce0445 and 11bcdb1.

📒 Files selected for processing (1)
  • packages/nuxi/src/commands/init.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nuxi/src/commands/init.ts

📝 Walkthrough

Walkthrough

Adds --defaults (-y) and --interactive flags to the init command and detects non-interactive mode from those flags, agent/CI signals, or lack of a TTY. In non-interactive mode prompts for template, directory, package manager, git init, and module selection are suppressed; package-manager detection runs earlier and is reused for resolution. The command emits a note listing available templates and the effective configuration and exits early if --dir is omitted. If the target directory exists and --force is not set, non-interactive runs error immediately. Declarations for the new flags were added.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately describes the main change: detecting agent/CI environments and skipping interactive prompts, which matches the core objective and file modifications.
Description check ✅ Passed The pull request description is directly related to the changeset, providing clear context about non-interactive detection, the new flags, default behaviors, and fallback mechanisms for the init command.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 claude/nuxt-cli-agent-support-sTRzI

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🧹 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 resolvedOptions object 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

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2ef0c and 0f5863c.

📒 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
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

🧹 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 like toBool(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

📥 Commits

Reviewing files that changed from the base of the PR and between 0f5863c and fce0445.

📒 Files selected for processing (1)
  • packages/nuxi/src/commands/init.ts

Comment on lines +274 to 276
if (isNonInteractive) {
dir = defaultDir
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unreachable code: this branch can never execute.

In non-interactive mode, if ctx.args.dir is empty (the '' default), the code exits early at lines 230-233. Therefore, the isNonInteractive branch here for dir === '' is dead code since we'd never reach this point with an empty dir in non-interactive mode.

This doesn't break anything but adds confusion. Consider removing this branch or adjusting the early exit logic if you want non-interactive mode to auto-select a directory.

🧹 Proposed fix: Remove unreachable branch
     let dir = ctx.args.dir
     if (dir === '') {
       const defaultDir = availableTemplates[templateName]?.defaultDir || 'nuxt-app'
-      if (isNonInteractive) {
-        dir = defaultDir
-      }
-      else {
-        const result = await text({
-          message: 'Where would you like to create your project?',
-          placeholder: `./${defaultDir}`,
-          defaultValue: defaultDir,
-        })
-
-        if (isCancel(result)) {
-          cancel('Operation cancelled.')
-          process.exit(1)
-        }
-
-        dir = result
-      }
+      // In non-interactive mode, we exit early at line 230-233 if no dir provided
+      const result = await text({
+        message: 'Where would you like to create your project?',
+        placeholder: `./${defaultDir}`,
+        defaultValue: defaultDir,
+      })
+
+      if (isCancel(result)) {
+        cancel('Operation cancelled.')
+        process.exit(1)
+      }
+
+      dir = result
     }
📝 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 (isNonInteractive) {
dir = defaultDir
}
let dir = ctx.args.dir
if (dir === '') {
const defaultDir = availableTemplates[templateName]?.defaultDir || 'nuxt-app'
// In non-interactive mode, we exit early at line 230-233 if no dir provided
const result = await text({
message: 'Where would you like to create your project?',
placeholder: `./${defaultDir}`,
defaultValue: defaultDir,
})
if (isCancel(result)) {
cancel('Operation cancelled.')
process.exit(1)
}
dir = result
}
🤖 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 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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 26, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing claude/nuxt-cli-agent-support-sTRzI (11bcdb1) with main (1c2ef0c)

Open in CodSpeed

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

📦 Bundle Size Comparison

📈 nuxi

Metric Base Head Diff
Rendered 3385.37 KB 3388.71 KB +3.35 KB (+0.10%)

📈 nuxt-cli

Metric Base Head Diff
Rendered 149.88 KB 153.40 KB +3.52 KB (+2.35%)

📈 create-nuxt

Metric Base Head Diff
Rendered 1640.37 KB 1643.92 KB +3.55 KB (+0.22%)

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.

2 participants