npm
Source
stars.config.* schema and loader live in @wolfstar/http-framework
(@wolfstar/http-framework/config). This package only consumes it to drive its commands:
stars devbuilds the project, starts the bot, restarts it (or leaves the change to the bot’s hot reload) and shows what is happening in a full-screen dashboard with filterable log channels and levels (or a compact panel, or plain logs).stars buildruns the configured build tool once.stars infoprints the resolved configuration and environment (--jsonfor scripts).stars codegenruns the configured code generators: i18next types and the typed options of your commands (--checkfor CI).stars preparegenerates the TypeScript configuration in.stars/and the auto imports declaration file (--checkfor CI).stars typecheckregenerates.stars/and type-checks every project once.stars commandsinspects, compares, deploys, and cleans the application commands Discord has deployed.stars doctorchecks that the project is ready: runtime, framework, credentials, interactions endpoint, generated files.stars completionsprints the shell completion script for bash, zsh, or fish.
stars.config.ts file.
Installation
@wolfstar/http-framework already gives a project the stars
binary. You only need this explicit install to use the package’s programmatic exports (loadStarsConfig,
diagnostics) or to pin its version independently of the framework’s.
Projects scaffolded with @wolfstar/create-http-framework come with @wolfstar/cli, a stars.config.ts file and dev/build scripts already wired up.
Configuration
stars.config.{ts,mts,cts,js,mjs,cjs} is defined by @wolfstar/schema and
re-exported by @wolfstar/http-framework.
See the framework page for the full option reference (root, entry, build, dev, codegen, env, hooks) and the
defineConfig helper. stars looks for the file in the working directory (--config <file> overrides it,
--cwd <dir> changes the working directory). It passes configuration diagnostics through as exit code 2 and prints
the offending option path and a hint to the terminal.
stars dev’s display URL needs no configuration either. It follows dev.env.HTTP_PORT/PORT, the process’s HTTP_PORT, the project’s env-file HTTP_PORT/PORT, or 3000, the same way Vite’s and Nuxt’s dev servers do. An ambient process PORT is ignored in framework mode. localhost is swapped for 127.0.0.1 at startup if that is what is actually reachable. An explicit dev.url overrides only the display URL and health checks, so it can point at a local proxy or a remote tunnel. See Port conflicts.
The resolved configuration is also available programmatically, exactly as the commands see it (re-exported from this package for convenience, or import it directly from @wolfstar/http-framework/config):
Commands
stars info
Prints the resolved configuration and environment. Pass --json for scripts. Besides the build, codegen, env, hooks,
and experimental flags, the output lists:
- Dev: the
devoptions in effect, including the log file, the per-run log directory and how many files it keeps, the layout, the channels and levels the dev UI starts with, the command refresh mode, and whether changes are left to the bot’s hot reload. - Modules: the installed modules and what they registered: runtime plugins, pieces directories, locales, and client
hooks. Below compatibility version 7, a by name row lists the
@wolfstar/plugin-*packages activated through their/registerimport because no module covers them.
ngrok quick tunnel on bot.ngrok.app.
stars dev
Watches the sources through the configured build tool (tsdown programmatically, configured from your stars.config, tsc -b --watch, or a plain file watcher for JavaScript projects), starts the bot after the first successful build and restarts it after every following one. Failed builds keep the previous process running and wait for the next change; a crashed bot waits for the next change or a manual restart.
The bot runs as a child node process with STARS_DEV=1 and NODE_ENV=development in its environment. When the bot
enables the framework’s hmr option, stars dev leaves
changes to pieces to the bot instead of restarting it. See Hot reload.
dev.layout in stars.config, or --layout, picks the interactive UI:
Press
v to switch between the two while a session runs.
Terminal style
tui.style in stars.config, or --style, picks the presentation by name:
dev.layout is still supported. The first setting found wins, in this order: --style, --layout, tui.style, then
dev.layout. Without any of them, stars dev keeps the automatic choice between the dashboard and the panel.
--no-tui and STARS_TUI=plain always use plain logs. An explicit --tui overrides tui.style: 'none', but
--style none always uses plain logs.
Startup checks
Beforestars dev creates the builder or writes generated files, it checks that:
- The output, generated-file, and log directories can be written. A directory that can’t be created or written, or a
file in its place, fails with
DEV_DIRECTORY_UNWRITABLE. - The bot’s listener port is free. A bind error other than an occupied port, such as a missing permission, fails with
PORT_CHECK_FAILED. - The listener port is an integer from 1 to 65535. An invalid value fails with
INVALID_PORT.
stars dev starts, so an unrelated shell value doesn’t stop stars build,
stars info, or stars doctor from inspecting the project.
The framework listener binds HTTP_ADDRESS (default 0.0.0.0). Its port comes from dev.env.HTTP_PORT or
dev.env.PORT, then the process’s HTTP_PORT, then the env file’s HTTP_PORT, then the env file’s PORT (only when
dev.url isn’t set), or 3000. In Nitro mode, the listener uses NITRO_HOST/HOST and NITRO_PORT before PORT.
Port conflicts
When the listener port is occupied,dev.portConflict or --port-conflict decides what happens:
The prompt also works with plain logs on a terminal. CI, piped input, and
TERM=dumb never wait for an answer.
Cancelling creates no builder and no generated files.
--port <port> (or -p <port>) sets the listener port for one session:
--port and a port picked from the prompt set the child process’s HTTP_PORT, PORT, and NITRO_PORT for this
session only. stars dev doesn’t rewrite your env files or global variables. An inferred display URL follows the chosen
port. An explicit dev.url (and dev.health) stays unchanged, path and query included, and its host and port are never
probed as the bot’s listener. For example, dev.url: 'https://localhost/bot' can keep pointing at a proxy on port 443
while the bot starts on 3000 or --port 4000.
Listen address
--host <address> sets the address the bot listens on, like Nuxt’s --host. It accepts an IP address or a hostname.
Use it to expose the dev server on your network or to bind a specific interface:
--host listens on every interface (0.0.0.0). stars dev passes the address to the bot as HTTP_ADDRESS, and
as NITRO_HOST and HOST in Nitro mode. The Vite and Nitro dev servers bind to it, and the port check probes that
address. An inferred display URL follows a concrete address. A wildcard address (0.0.0.0 or ::) or an explicit
dev.url leaves the display URL unchanged. An invalid address fails with
INVALID_OPTION.
Port probes release their sockets before startup, so another process can still claim a free port before the bot binds
it.
--tunnel opens the public tunnel at startup for one session, whatever dev.tunnel says. When dev.tunnel is off,
stars dev opens a cloudflared quick tunnel. Otherwise it uses the dev.tunnel provider. --no-tunnel keeps the tunnel closed at startup even when dev.tunnel
enables it. Pressing t still opens it later. Leave both flags out to let dev.tunnel decide. See
Type checking, tunnel and logs.
Dashboard
The dashboard is the default on a TTY of at least 90×20. It is a full-screen view in the alternate buffer.starting, building, running, stopped, error), the framework
version, the uptime, the port, the tunnel, and where the logs are written. Below that are the channel and level
filters of the stream.
The stream prints one line per entry: a level badge (T D I W E), the time, the channel, and the message with URLs,
paths, names, and numbers highlighted. An entry with detail lines, such as the commands that were loaded or the paths
that are watched, is shown as a block between two rules. The stack frames the bot prints after an error are folded
under that error and count as one entry. The build percentage follows actual build milestones, not a timer.
Log channels
Each log entry has a channel that says what it is about, so you can switch each one off:
The last five channels come from the bot itself.
stars dev preloads a small bridge into the bot (node --import)
that reports its events over an IPC channel instead of guessing from stdout. The bridge needs
@wolfstar/http-framework 6.1 or later, resolved from the project. Without it, or with a build that bundles the
framework (as Vite and Nitro do), those channels stay empty and everything else works as before.
A plugin can log on a channel of its own:
trace, debug, info, warn, and error. trace is hidden at start because it
logs one line per request. dev.logs.channels and dev.logs.levels in stars.config choose what a session starts
with. The log file always receives every entry.
--channel and --level override them for one session. --channel accepts a comma-separated list and can be
repeated. --level shows that level and every more severe one.
Keyboard shortcuts
The channel and level keys (
←/→, Tab, Space, s, a, Enter, b, g/G, /) only apply to the
dashboard. The panel shares every other key.
Hot reload
When the bot runs with the framework’shmr option enabled, it tells stars dev which directories it watches. A build
that only changed pieces in those directories is then left to the bot. The process, its HTTP server, and its
connections stay up, and the hmr channel shows what was reloaded. A piece is a file the bot loaded one from, or a new
file that could be one.
Any other change still restarts the bot: the entry, a shared module, a locale, or a helper next to the pieces (such as
_shared.js, or any file no piece came from), which the bot imports once and cannot replace. A bot without hmr, or
one that stopped its reloader, is always restarted. stars dev judges what a build changed by content, since a bundler
such as tsdown rewrites its whole output on every rebuild.
Set dev.hmr: false to always restart the bot:
Command refresh
The bot reports the application commands it registers when it starts and after every hot reload. When they differ from what it reported before,stars dev reports the change on the commands channel. dev.commands.refresh picks what
happens next:
--no-tui, CI), 'prompt' only reports the change. An open question survives a restart of
the bot. A y given while the bot is stopped or restarting is carried out once it listens again. A refresh also
empties a guild whose last command was removed since the last deploy. Command refresh needs @wolfstar/http-framework
6.1 or later.
Panel
The panel is used withtui.style: 'nuxt-style', --style nuxt-style, dev.layout: 'panel', --layout panel, the v key, or a terminal smaller than 90×20. It is a
bottom-aligned panel in the normal buffer, following the layout and keyboard conventions of
Nuxt CLI’s dev TUI.
It shows a Stars wordmark, aligned URLs, a 20-cell progress bar with elapsed time, status, and shortcuts. Logs are
folded away: l opens them and e jumps to the last error. Once ready, the bar gives way to diagnostics and the header
reports the load time.
Application output (including its banner), build-plugin output and diagnostics stay in the bounded log history and
.stars/dev.log. tsdown’s entry list and output-size table are suppressed. Closing an overlay restores the view under
it without duplicating output in scrollback. running (READY in the panel) reports process state unless
dev.health is configured; it does not certify that every application plugin loaded successfully.
In the log browser (l): arrows or j/k select, PgUp/PgDn move a page, g/G go to the beginning/follow the tail,
e/w/a filter errors/warnings/all, c/b/r toggle CLI/build/runtime sources, / searches, x clears, and
Enter/y copies the selected line on terminals supporting OSC 52 clipboard writes. q, Esc or the view’s
own shortcut closes an overlay rather than quitting the session.
Replace the default wordmark in stars.config.ts (up to four lines are displayed, clipped to the terminal width):
dev.banner also accepts a string containing newlines, or false to hide the wordmark. Omit it for Stars branding.
The dashboard shows the project’s name instead of the wordmark. For the application’s standalone banner outside the
TUI, use createStarsBanner from @wolfstar/start-banner.
Plain mode
Plain mode prints prefixed lines instead: the channel, then the message, with detail lines indented under it. The bot’s own output is passed through untouched. It is selected by--no-tui, --style none, tui.style: 'none', STARS_TUI=plain, redirected input/output, CI,
TERM=dumb, or terminals smaller than 40×10. STARS_TUI=1 overrides CI/size checks, never redirected streams or a
dumb terminal. Both modes honour NO_COLOR/FORCE_COLOR; STARS_REDUCED_MOTION=1 freezes the logo/spinner but keeps
the elapsed clock. Both stop the bot cleanly on SIGINT/SIGTERM. SIGUSR2 restarts the bot (not on Windows).
stars codegen
Runs the code generators that codegen in stars.config enables and writes their files. Pass --check in CI to fail
with CODEGEN_OUTDATED when a file is stale instead of writing it. Pass --json to print { check, results }.
Pass --only i18n or --only commands to run a single generator. Repeat the flag or comma-separate the values to run
several (--only i18n,commands).
codegen.i18ntypes the i18next resources with@wolfstar/i18next-type-generator. It is on by default whensrc/locales/en-USexists.codegen.commandstypes the options of every command from its builder. It is off by default.truewritessrc/@types/commands.d.ts, and{ output }picks another file, relative to the project root.
Typed command options
Withcodegen.commands enabled, the generated file augments CommandOptionsRegistry with one entry per command path
('ping', 'math add', 'subscriptions twitch add'):
Command.OptionsOf<'path'>, so you no longer maintain a hand-written interface Options that can drift from the builder. A renamed option, a flipped required, or a changed type stops compiling:
- Every option has the shape the handler receives (
userisTransformedArguments.User,roleisAPIRole, and so on). - A
requiredoption is not optional. choicesbecome a literal union.channel_typesnarrow a channel option.- A localized command is keyed by its default name, the one the handler receives.
- Context menu commands have no options and are skipped.
- A path registered more than once (a command restricted to several guilds) keeps its first definition.
Command.AutocompleteArguments<Command.OptionsOf<'math add'>> types focused from the
same entry.
Build first
stars codegen reads the commands from the built bot, the same way stars commands diff does, so run stars build
first. Loops and factories in your builders need no special care, because the types come from what the bot actually
registers. The CLI starts the bot in a mode that loads its pieces, reports its registry, and exits before it listens or
talks to Discord. It never calls client.login.
The bot still runs its own setup, so the values it reads while starting (DISCORD_CLIENT_ID, DISCORD_PUBLIC_KEY, and
so on) must be set. In CI, where the real secrets are not available, pass placeholders:
Run one generator in CI
--only lets a CI job run the generator it can. The i18n types only read the locale files, so you can check them
without the bot’s secrets or a build. The command types need the built bot and the values it reads while starting:
--only must be enabled. --only commands with codegen.commands off fails with
CODEGEN_GENERATOR_DISABLED instead of passing without
checking anything. An unknown name fails with INVALID_OPTION.
stars dev does not generate command types, and neither does stars prepare, which has no build to read from yet. Run
stars codegen after you change an option, and stars codegen --check in CI to keep the file up to date.
stars commands
Lists what Discord currently has deployed, which is not necessarily what the project registers today: renamed and
removed commands stay until something deletes them.
DISCORD_TOKEN and DISCORD_APPLICATION_ID (or APPLICATION_ID) from the environment or the project’s
.env, the same place the bot reads them from. clean deletes deployed commands, so on a terminal it opens a wizard
(a checklist of what is deployed, then a confirmation). Anywhere else it refuses to run without --yes or --name.
Remove a subcommand or group
--name also takes the path of a subcommand or a group: settings server removes the server subcommand (or group)
of /settings, and settings group sub removes one subcommand inside a group. Use it to drop a single subcommand you
no longer register without deleting the whole command. Discord has no endpoint to delete a subcommand, so clean
fetches the deployed command, drops that entry from its options, and sends the command back with a PATCH. The
parent command and its other subcommands stay. Paths under the same command share one request.
- A value that exactly matches a deployed command’s name deletes that command first. This keeps context menu commands
with spaces in their names, such as
Report User, working. - A group left without subcommands is removed along with its last one, since Discord rejects an empty group.
- A command cannot exist without a subcommand. Removing a command’s last subcommand deletes the whole command. The
confirmation says so, and
--yesaccepts it. - A path that matches nothing fails with
COMMAND_NOT_FOUND. - The wizard still lists whole commands only. Pass
--nameto remove a subcommand or group.
--json, the output lists whole commands under deleted and subcommands or groups under removed:
Compare and deploy
diff and deploy compare what Discord has deployed with what the project defines:
stars asks the bot.
It starts the built entry with the dev bridge, which loads the pieces, reports the registry, and exits before the bot
listens or talks to Discord. Run stars build first. This needs @wolfstar/http-framework 6.1 or later.
The bot is started the way stars dev starts it (the same env files, after the env:options hook), in the caller’s
NODE_ENV, or development when unset. Run NODE_ENV=production stars commands deploy to deploy what a production
start registers. STARS_DEV is not set, since this is not a dev session.
A command counts as changed when what the project defines no longer matches what is deployed. Fields Discord fills in
on its own (id, version, defaults such as nsfw: false) are ignored. diff --check exits with code 1 and raises
COMMANDS_DIFFER when anything differs.
deploy uses Discord’s bulk overwrite, so a deployed command the project no longer defines is deleted. That is why it
asks first. Outside a terminal, or with --json, it refuses to run without --yes.
To deploy on every start instead of by hand, enable commands: { register: 'on-start' } in the Client options. The
bot then writes only the differences after it listens, and keeps unknown deployed commands unless removeUnknown is
set. See Sync commands on startup.
stars typecheck
Type-checks the project once, the way nuxt typecheck does. stars typecheck first regenerates .stars/ (the same
work as stars prepare), then runs the project’s checker once on each project. The checker is
dev.typecheck.checker: golar or tsc.
future.compatibilityVersion 6, the projects are:
.stars/tsconfig.app.jsonand.stars/tsconfig.node.jsonfortsdownandvitebuilds.- The project’s own tsconfig plus
.stars/tsconfig.node.jsonfortscandnonebuilds. - Only the configured tsconfig when
dev.typecheck.tsconfigis set.
stars typecheck checks the single tsconfig. Use it instead of tsc -p tsconfig.json: a
solution-style root tsconfig.json has files: [], so a bare tsc -p on it checks nothing. Use it as the project’s
typecheck script:
stars typecheck exits with 1 and the TYPECHECK_FAILED diagnostic
when any project has type errors. It lists the failing projects. stars info lists the projects it checks on the
typechecks row.
stars doctor
Checks what a project needs before stars dev can do its job, and says what to do about each problem:
- The Node.js version, and the project’s
engines.node. - The configuration and its warnings.
- The framework, and whether it is recent enough for the dev bridge.
- The entry and the build output.
DISCORD_TOKEN,DISCORD_PUBLIC_KEY, and the application id.- Whether the dev port is free.
- The tunnel. With
provider: 'ngrok', it warns when@ngrok/ngrokis not installed in the project or whenNGROK_AUTHTOKENis not set. - Whether
.stars/is stale. It names each generated file that is out of date. - Whether the root
tsconfig.jsonstill extends./.stars/tsconfig.json(TSCONFIG_LEGACY_EXTENDS). - Whether a varlock
.env.schemaandenv.loaderagree (thevarlockcheck). - The plugins registered by name. Below compatibility version 7, the
pluginscheck lists the@wolfstar/plugin-*packages activated through/register. On version 7, the config check warns withPLUGINS_NOT_REGISTEREDabout any of them left out.
--online also asks Discord whether the token works and where the application sends its interactions. stars doctor
changes nothing unless you pass --fix. --json prints { ok, checks } for scripts. The exit code is 1 when a
check fails, with the DOCTOR_FAILED diagnostic.
The varlock check
The varlock check compares the project’s varlock setup with env.loader in stars.config:
A project that sets
env.path without env.loader: 'varlock' is not checked, because the runtime only picks varlock by
itself when no env.path is set.
Fix the configuration
--fix fixes what stars doctor can fix. Today that is a project where varlock loads the environment but
stars.config does not set env.loader. stars doctor --fix adds env: { loader: 'varlock' }:
- Without a
stars.config, it createsstars.config.tsthe way@wolfstar/create-http-frameworkscaffolds it. - With a literal
defineConfig({ ... })or exported object, it edits that object. - With a configuration it cannot edit safely (a spread, a function, or an
envthat is not a literal), it changes nothing and prints the line to add by hand.
stars doctor --fix asks before it writes. Pass --yes (-y) to answer for scripts. It never writes in CI, with
--json unless you pass --yes, or without a terminal to ask in.
stars prepare, stars build, stars dev, and stars info only report this case, with the
VARLOCK_LOADER_IMPLICIT and
VARLOCK_NOT_INSTALLED warnings.
stars completions
Prints a shell completion script for bash, zsh, or fish. Add it to your shell’s startup file:
--help lists, with their short forms (-c) and the --no- form of flags that are on by default (--no-tui).
Type checking, tunnel and logs
Threedev options round out the dev loop (all documented in
@wolfstar/http-framework):
dev.typecheck: trueruns a type checker next to the bot and reports type errors on the UI’stypeschannel, without ever blocking a build or a restart. This is useful when building withtsdown, which does not type-check.dev.typecheck.checkerpicks which one:tsc(the project’s TypeScript, watch mode),golar(golar tsc, watch mode),tsz(the tsc-compatible checker, re-run after every build since it has no watch mode), orauto.autois the default and usesgolarwhen the project depends on it andtscotherwise.- Pressing
topens and closes a quick tunnel without configuration. It usescloudflared, or thedev.tunnel.provideryou set.dev.tunnel: trueopens it at startup so Discord can reach the bot’s interactions endpoint from the internet.stars dev --tunneldoes the same for one session, whateverdev.tunnelsays, and--no-tunnelkeeps it closed at startup (tstill opens it). In plain mode (--no-tui), where there is notkey, the CLI prints the URL on thetunnelchannel. A string is an https URL you already serve, which the CLI only probes.dev.tunnel.updateEndpointwrites the URL to the Discord application, and is opt-in because it edits a live application. See Tunnel providers to use ngrok instead ofcloudflared. dev.logFile(default.stars/dev.log) mirrors the session’s logs to disk, so you can read a run back after the terminal UI is gone. Set it tofalseto disable it. The file is truncated on every run.
Tunnel providers
dev.tunnel.provider picks the service that opens the quick tunnel:
cloudflared stays the default, so dev.tunnel: true and existing configurations behave as before. Use ngrok when
you want a stable hostname: set dev.tunnel.domain to a domain reserved in your ngrok account, and the URL survives
restarts.
To use ngrok:
-
Install the official SDK in your project.
@ngrok/ngrokis an optional peer dependency of the CLI, loaded only when thengrokprovider is used. -
Set
NGROK_AUTHTOKEN. The CLI looks indev.env, then in the environment, then in the project’s env files, the way the bot does. The env files are read again each time the tunnel opens, so pressingtafter adding the token works without restartingstars dev. -
Set the provider, and optionally a reserved domain:
NGROK_AUTHTOKEN_MISSING diagnostic on the tunnel
channel. Run stars doctor to check both the package and the token.
provider and domain only apply to a tunnel the CLI opens. Setting either next to url, or setting domain without
provider: 'ngrok', fails with TUNNEL_OPTION_CONFLICT. An
unknown provider fails with INVALID_CHOICE.
Log files
To keep earlier runs, setdev.logs.dir (for example 'logs'). stars dev then also writes one file per run,
dev-<timestamp>.log, in that directory. dev.logs.keep (default 10) sets how many per-run files stay, the current
run included. Older files are deleted when a run starts.
<ISO time> <level> <channel> <message>, with the detail lines of an entry indented under
it. Log files never filter entries out.
The build
tsdown is configured from stars.config, and a base project configures nothing: the entry’s directory, one output
file per source file, ESM on Node, build.outDir, the tsconfig (src/tsconfig.json or tsconfig.json), the
extension build.output implies, sourcemaps, unbundled dependencies, Nuxt’s ~/@/~~/@@ alias prefixes and
the auto imports plugin, and copying src/locales to dist/locales are all filled in
(the framework README lists every default). The tsdown block is for what they
cannot know:
Every @wolfstar/plugin-* package listed in the project’s dependencies or optionalDependencies is activated
automatically in bundler builds. stars injects its /register side-effect entrypoint before the application entry,
so projects do not need to maintain bare imports such as import '@wolfstar/plugin-i18next/register'. Packages used
only for development are intentionally not activated from devDependencies.
stars injects <name>/register only when the installed package’s exports map defines a ./register subpath.
Library plugins without that entrypoint, such as @wolfstar/plugin-cache, @wolfstar/plugin-gateway, and
@wolfstar/plugin-sharder, are skipped, and you import them directly. A package that is not installed, or that
declares no exports, is still injected so a missing install surfaces as a resolution error. If a build fails with
ERR_PACKAGE_PATH_NOT_EXPORTED on a library plugin, upgrade to @wolfstar/cli@2.0.2 or newer, or refresh your
lockfile so it resolves @wolfstar/vite-server@0.2.2 or newer.
With future.compatibilityVersion: 7, stars no longer injects any /register import.
Only the packages in modules, and the modules they install, are registered.
future.compatibilityVersion: 3 (end-of-life) an existing tsdown.config.* still drives the build and the block is merged
over it (values from stars.config win, plugins are appended); from 4 on the block is the whole configuration. The
vite block works the same way for build.tool: 'vite'. stars info shows which file the build is configured from
and which options the block sets.
Auto imports
With thetsdown build tool, stars wires the autoImports() plugin into the build, so the exports of every
package in imports.presets are usable without an import statement. The default presets are
@wolfstar/http-framework, @wolfstar/decorators, and
@wolfstar/env-utilities. stars scans each preset from the project’s own node_modules and skips packages that are
not installed. Once you add @wolfstar/decorators to your dependencies, ApplyOptions and the other decorators are
auto-imported.
imports.presets replaces the default list, so keep @wolfstar/decorators in it when you customize presets.
stars prepare regenerates the auto imports declaration file after you install or remove a preset.
Compatibility version
future.compatibilityVersion selects the legacy or current defaults, the way Nuxt’s own compatibility setting does (see the
framework README for the full reference):
Version 7 is an opt-in preview, not the default. On version 7,
stars build, stars prepare, stars dev,
stars info, and stars doctor warn with PLUGINS_NOT_REGISTERED
about an installed plugin that no module covers.
Version 3 is end-of-life. It still works, but every command prints a
COMPATIBILITY_VERSION_EOL warning, and the next major
removes it.
Environment and hooks
env mirrors the options of setup() from @wolfstar/env-utilities. stars calls setup() with them as the first
import of the built entry, before plugin registrations and the bot’s own modules. tsdown, Vite and Nitro builds get it
through the entry transform. With build.tool: 'tsc' or 'none', only stars dev preloads it (node --import).
Nitro leaves it off unless you set env explicitly.
hooks registers CLI lifecycle hooks run with hookable: config:resolved,
env:options, prepare:before/prepare:done, builder:created, tsdown:options, build:before/build:done, and
dev:start/dev:restart/dev:close. They run in the CLI process, never in the bot. stars build and stars dev
run them in the same order.
.env.schema, an installed varlock, and no env.path
or env.loader, the CLI resolves the loader to varlock the way the runtime does. stars dev and stars doctor then
read the variables through varlock load. See How the CLI follows varlock.
stars info lists the env options and the registered hooks. See the
framework reference for every env option and
hooks for each hook’s arguments and timing.
Experimental flags
experimental in stars.config.* turns on work that is still landing (see the
framework README for the full reference):
stars info prints which flags are on.
Exit codes
Generated TypeScript configuration
The generated compiler options combine@sapphire/ts-config, @sapphire/ts-config/extra-strict, and
@sapphire/ts-config/decorators. The CLI loads these presets and writes their options directly into the file,
so consumers do not need to install Sapphire. This enables strict checks, explicit overrides, and legacy decorators
with metadata. Stars targets ES2022, skips dependency declaration checks, and stores incremental build information
inside .stars/. Tsdown and Vite use ESNext/Bundler with noEmit; tsc retains Sapphire’s Node16 emit settings.
Project compiler options can override these defaults.
Bundler builds also follow Nitro’s TypeScript configuration:
forced module detection, isolated modules, verbatim module syntax, JavaScript sources, .ts import extensions,
package.json imports, and ESNext/DOM libraries. Use import type and export type for type-only dependencies.
These options apply to tsdown and Vite; tsc keeps its emit-compatible settings. Sapphire’s decorator options and
the ES2022 target remain in effect. This does not enable Stars’ experimental Nitro runtime integration.
From future.compatibilityVersion 6, stars prepare writes two files, the way a Nuxt 4 project has them:
.stars/tsconfig.app.jsoncovers the bot: everything under the entry’s directory plus the auto imports declaration, with the~/@/~~/@@paths and the options above.tsdownbuilds with it..stars/tsconfig.node.jsoncovers the files Node runs without a bundler:stars.config.*,vitest.config.*,tsdown.config.*,vite.config.*, andscripts/**. It usesNodeNextresolution,types: ["node"], and no DOM library. It has no aliases, auto imports, or decorators, and leaves the entry’s directory to the app project.
tsconfig.json is solution-style. It only references the two generated files:
typecheck script, and stars prepare in postinstall.
Because the root has files: [], type-check with stars typecheck instead of tsc -p.
stars dev’s dev.typecheck watches the app project. A root tsconfig.json that still extends
./.stars/tsconfig.json gets a TSCONFIG_LEGACY_EXTENDS warning
from stars prepare and stars doctor. Replace it with the file above, or keep future.compatibilityVersion at 5.
On versions 5 and 4, nothing changes. stars prepare writes the single .stars/tsconfig.json, which you extend
from your project’s tsconfig.json:
extends. stars dev and stars build also regenerate the generated
files. For tsdown builds, @/ and ~/ resolve to the entry file’s directory (normally src/), while @@/ and ~~/
resolve to the project root. Filesystem aliases in stars.config.ts’s tsdown.alias are included too, with custom
values taking precedence. Legacy builds using a separate tsdown config only include aliases declared in
stars.config.ts. Other build tools do not get tsdown aliases, since TypeScript alone does not rewrite imports.
The generated app config includes source files and the auto imports declaration, including a custom imports.dts
location. Explicit include or compilerOptions.paths in your own tsconfig replace the inherited values;
remove manually duplicated paths to use the generated aliases. Generation works with imports: false too.
Use stars prepare --check to check the generated files without writing them. It fails when any of them is out of
date. Do not edit anything in .stars/ by hand; keep .stars/ ignored by Git and run stars prepare after
installing dependencies on a fresh checkout.
Server integrations
The Vite and Nitro builders live in dedicated packages —@wolfstar/vite-server and
@wolfstar/nitro-server. The CLI loads the selected integration lazily,
passes the resolved stars.config, and supplies project dependency loading and plugin registration through
BuilderContext from @wolfstar/schema. Neither server package depends on the
CLI or framework. Existing experimental flags, presets, output directories, and stars dev/stars build commands
are unchanged; install Vite and Nitro in the consuming project as before.
See CLI Errors for every diagnostic code stars can raise.