Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3ce4f79
feat(cli): add tab completions
AmirSa12 Oct 11, 2025
447e1a3
readme
AmirSa12 Oct 13, 2025
0461d5c
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 13, 2025
394e3bc
update
AmirSa12 Oct 13, 2025
2bf2b6c
bombshell v0.0.5
AmirSa12 Oct 13, 2025
22fc13c
types
AmirSa12 Oct 13, 2025
8877baa
update
AmirSa12 Oct 13, 2025
81e36cf
updates
AmirSa12 Oct 17, 2025
d1babb4
use node module resolution
AmirSa12 Oct 17, 2025
632781d
Merge remote-tracking branch 'origin/main' into feat/tab-completions
danielroe Oct 21, 2025
2252472
refactor: use native node to run completions data
danielroe Oct 23, 2025
87e58f9
chore: update tab to version 0.0.7
AmirSa12 Oct 23, 2025
1860f10
chore: readme
AmirSa12 Oct 23, 2025
63b2c8b
Merge remote-tracking branch 'origin/main' into feat/tab-completions
danielroe Oct 30, 2025
d4213cd
chore: move into build script
danielroe Oct 30, 2025
d64d259
chore: suppress lint
danielroe Oct 30, 2025
c7352b5
chore: lint
danielroe Oct 30, 2025
4e7d9bc
build: also for create nuxt
danielroe Oct 30, 2025
6325654
build: move back to postinstall
danielroe Oct 30, 2025
f15c787
docs: remove global installation instructions
danielroe Oct 30, 2025
1ede8e8
chore: knip update
danielroe Oct 30, 2025
c1c28d0
chore: use file url for output path
danielroe Oct 30, 2025
243bf65
chore: update tab to version 0.0.8
AmirSa12 Oct 30, 2025
c016105
update tab to version 0.0.9
AmirSa12 Nov 4, 2025
590290c
Merge remote-tracking branch 'upstream/main' into feat/tab-completions
AmirSa12 Nov 4, 2025
d37a720
Merge remote-tracking branch 'upstream/main' into feat/tab-completions
AmirSa12 Nov 4, 2025
166246a
Merge remote-tracking branch 'origin/main' into feat/tab-completions
danielroe Nov 4, 2025
c9c8bf7
build: use module url for import
danielroe Nov 4, 2025
44a49d1
chore: dance, dance little man
danielroe Nov 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ stats.json
playground-bun*
playground-deno*
playground-node*
packages/nuxi/src/utils/completions-data.ts
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@

All commands are listed on https://nuxt.com/docs/api/commands.

## Shell Autocompletions

`nuxt/cli` provides shell autocompletions for commands, options, and option values – powered by [`@bomb.sh/tab`](https://github.com/bombshell-dev/tab).

### Package Manager Integration

`@bomb.sh/tab` integrates with [package managers](https://github.com/bombshell-dev/tab?tab=readme-ov-file#package-manager-completions). Autocompletions work when running `nuxt` directly within a Nuxt project:

```bash
pnpm nuxt <Tab>
npm exec nuxt <Tab>
yarn nuxt <Tab>
bun nuxt <Tab>
```

For package manager autocompletions, you should install [tab's package manager completions](https://github.com/bombshell-dev/tab?tab=readme-ov-file#package-manager-completions) separately.

## Contributing

```bash
Expand Down
6 changes: 6 additions & 0 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"test/fixtures/*"
],
"ignoreDependencies": [
"@bomb.sh/tab",
"@clack/prompts",
"c12",
"confbox",
Expand All @@ -53,6 +54,11 @@
"ufo",
"youch"
]
},
"packages/create-nuxt": {
"ignoreDependencies": [
"@bomb.sh/tab"
]
}
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"nuxi": "node ./packages/nuxi/bin/nuxi.mjs",
"nuxt": "node ./packages/nuxt-cli/bin/nuxi.mjs",
"nuxi-bun": "bun --bun ./packages/nuxt-cli/bin/nuxi.mjs",
"postinstall": "pnpm build",
"postinstall": "node --experimental-strip-types ./scripts/generate-completions-data.ts && pnpm build",
"test:types": "tsc --noEmit",
"test:knip": "knip",
"test:dist": "pnpm -r test:dist",
Expand All @@ -30,6 +30,7 @@
"@vitest/coverage-v8": "^3.2.4",
"changelogen": "^0.6.2",
"eslint": "^9.39.1",
"exsolve": "^1.0.7",
"knip": "^5.67.1",
"nuxt": "^4.2.0",
"pkg-pr-new": "^0.0.60",
Expand Down
1 change: 1 addition & 0 deletions packages/create-nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"citty": "^0.1.6"
},
"devDependencies": {
"@bomb.sh/tab": "^0.0.9",
"@types/node": "^24.10.0",
"rollup": "^4.52.5",
"rollup-plugin-visualizer": "^6.0.5",
Expand Down
9 changes: 9 additions & 0 deletions packages/create-nuxt/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineCommand } from 'citty'
import { provider } from 'std-env'

import init from '../../nuxi/src/commands/init'
import { setupInitCompletions } from '../../nuxi/src/completions-init'
import { setupGlobalConsole } from '../../nuxi/src/utils/console'
import { checkEngines } from '../../nuxi/src/utils/engines'
import { logger } from '../../nuxi/src/utils/logger'
Expand All @@ -16,6 +17,11 @@ const _main = defineCommand({
},
args: init.args,
async setup(ctx) {
const isCompletionRequest = ctx.args._?.[0] === 'complete'
if (isCompletionRequest) {
return
}

setupGlobalConsole({ dev: false })

// Check Node.js version and CLI updates in background
Expand All @@ -27,4 +33,7 @@ const _main = defineCommand({
},
})

// eslint-disable-next-line antfu/no-top-level-await
await setupInitCompletions(_main)

export const main = _main as CommandDef<any>
3 changes: 2 additions & 1 deletion packages/nuxi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
},
"scripts": {
"build": "tsdown",
"prepack": "tsdown"
"prepack": "pnpm build"
},
"devDependencies": {
"@bomb.sh/tab": "^0.0.9",
"@clack/prompts": "^1.0.0-alpha.6",
"@nuxt/kit": "^4.2.0",
"@nuxt/schema": "^4.2.0",
Expand Down
27 changes: 27 additions & 0 deletions packages/nuxi/src/completions-init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ArgsDef, CommandDef } from 'citty'
import tab from '@bomb.sh/tab/citty'
import { templates } from './utils/completions-data'

export async function setupInitCompletions<T extends ArgsDef = ArgsDef>(command: CommandDef<T>) {
const completion = await tab(command)

const templateOption = completion.options?.get('template')
if (templateOption) {
templateOption.handler = (complete) => {
for (const template of templates) {
complete(template, '')
}
}
}

const logLevelOption = completion.options?.get('logLevel')
if (logLevelOption) {
logLevelOption.handler = (complete) => {
complete('silent', 'No logs')
complete('info', 'Standard logging')
complete('verbose', 'Detailed logging')
}
}

return completion
}
79 changes: 79 additions & 0 deletions packages/nuxi/src/completions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { ArgsDef, CommandDef } from 'citty'
import tab from '@bomb.sh/tab/citty'
import { nitroPresets, templates } from './utils/completions-data'

export async function initCompletions<T extends ArgsDef = ArgsDef>(command: CommandDef<T>) {
const completion = await tab(command)

const devCommand = completion.commands.get('dev')
if (devCommand) {
const portOption = devCommand.options.get('port')
if (portOption) {
portOption.handler = (complete) => {
complete('3000', 'Default development port')
complete('3001', 'Alternative port')
complete('8080', 'Common alternative port')
}
}

const hostOption = devCommand.options.get('host')
if (hostOption) {
hostOption.handler = (complete) => {
complete('localhost', 'Local development')
complete('0.0.0.0', 'Listen on all interfaces')
complete('127.0.0.1', 'Loopback address')
}
}
}

const buildCommand = completion.commands.get('build')
if (buildCommand) {
const presetOption = buildCommand.options.get('preset')
if (presetOption) {
presetOption.handler = (complete) => {
for (const preset of nitroPresets) {
complete(preset, '')
}
}
}
}

const initCommand = completion.commands.get('init')
if (initCommand) {
const templateOption = initCommand.options.get('template')
if (templateOption) {
templateOption.handler = (complete) => {
for (const template of templates) {
complete(template, '')
}
}
}
}

const addCommand = completion.commands.get('add')
if (addCommand) {
const cwdOption = addCommand.options.get('cwd')
if (cwdOption) {
cwdOption.handler = (complete) => {
complete('.', 'Current directory')
}
}
}

const logLevelCommands = ['dev', 'build', 'generate', 'preview', 'prepare', 'init']
for (const cmdName of logLevelCommands) {
const cmd = completion.commands.get(cmdName)
if (cmd) {
const logLevelOption = cmd.options.get('logLevel')
if (logLevelOption) {
logLevelOption.handler = (complete) => {
complete('silent', 'No logs')
complete('info', 'Standard logging')
complete('verbose', 'Detailed logging')
}
}
}
}

return completion
}
7 changes: 6 additions & 1 deletion packages/nuxi/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { provider } from 'std-env'
import { description, name, version } from '../package.json'
import { commands } from './commands'
import { cwdArgs } from './commands/_shared'
import { initCompletions } from './completions'
import { setupGlobalConsole } from './utils/console'
import { checkEngines } from './utils/engines'
import { logger } from './utils/logger'
Expand Down Expand Up @@ -87,4 +88,8 @@ const _main = defineCommand({

export const main = _main as CommandDef<any>

export const runMain = (): Promise<void> => _runMain(main)
export async function runMain(): Promise<void> {
await initCompletions(main)

return _runMain(main)
}
1 change: 1 addition & 0 deletions packages/nuxt-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"prepack": "tsdown"
},
"dependencies": {
"@bomb.sh/tab": "^0.0.9",
"@clack/prompts": "^1.0.0-alpha.6",
"c12": "^3.3.1",
"citty": "^0.1.6",
Expand Down
6 changes: 5 additions & 1 deletion packages/nuxt-cli/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url'
import { runCommand as _runCommand, runMain as _runMain } from 'citty'

import { commands } from '../../nuxi/src/commands'
import { initCompletions } from '../../nuxi/src/completions'
import { main } from './main'

globalThis.__nuxt_cli__ = globalThis.__nuxt_cli__ || {
Expand All @@ -17,7 +18,10 @@ globalThis.__nuxt_cli__ = globalThis.__nuxt_cli__ || {
),
}

export const runMain = (): Promise<void> => _runMain(main)
export async function runMain(): Promise<void> {
await initCompletions(main)
return _runMain(main)
}

export async function runCommand(
name: string,
Expand Down
32 changes: 32 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading