@wolfstar/cli 2.1.0 → 2.3.0-next-20261004131917

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +203 -42
  2. package/dist/{_shared-B-hRZDRS.js → _shared-BIQK0Bhm.js} +12 -5
  3. package/dist/_shared-BIQK0Bhm.js.map +1 -0
  4. package/dist/bridge-BvkmlAOZ.js +410 -0
  5. package/dist/bridge-BvkmlAOZ.js.map +1 -0
  6. package/dist/{build-CPnSLYME.js → build-DJcc95Yq.js} +5 -5
  7. package/dist/{build-CPnSLYME.js.map → build-DJcc95Yq.js.map} +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/{codegen-BqpLGLLs.js → codegen-aJSyPz-J.js} +4 -4
  10. package/dist/{codegen-BqpLGLLs.js.map → codegen-aJSyPz-J.js.map} +1 -1
  11. package/dist/command-diff-BK912Hjc.js +78 -0
  12. package/dist/command-diff-BK912Hjc.js.map +1 -0
  13. package/dist/commands-CIPWQtF0.js +3 -0
  14. package/dist/commands-Clpbqq3K.js +15 -0
  15. package/dist/commands-Clpbqq3K.js.map +1 -0
  16. package/dist/{commands-ExM8HILu.js → commands-DVC7ky6f.js} +259 -9
  17. package/dist/commands-DVC7ky6f.js.map +1 -0
  18. package/dist/completions-D2KYtrrv.js +161 -0
  19. package/dist/completions-D2KYtrrv.js.map +1 -0
  20. package/dist/{dev-4wpEQC7l.js → dev-oPPVR7d_.js} +432 -45
  21. package/dist/dev-oPPVR7d_.js.map +1 -0
  22. package/dist/{diagnostics-CZBVxlpj.js → diagnostics-BysbNnPD.js} +38 -1
  23. package/dist/diagnostics-BysbNnPD.js.map +1 -0
  24. package/dist/doctor-DkVUwgDd.js +334 -0
  25. package/dist/doctor-DkVUwgDd.js.map +1 -0
  26. package/dist/{errors-Crt4hu0b.js → errors-COFWKKKw.js} +5 -2
  27. package/dist/errors-COFWKKKw.js.map +1 -0
  28. package/dist/hooks-Cy6F2bhH.js +332 -0
  29. package/dist/hooks-Cy6F2bhH.js.map +1 -0
  30. package/dist/index.d.ts +75 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +4 -4
  33. package/dist/{info-CdiQajgn.js → info-CKJVMWIT.js} +16 -5
  34. package/dist/info-CKJVMWIT.js.map +1 -0
  35. package/dist/{locales-C7X8VNmK.js → locales-BJAP4HYf.js} +5 -5
  36. package/dist/{locales-C7X8VNmK.js.map → locales-BJAP4HYf.js.map} +1 -1
  37. package/dist/log-view-B7uJEnMR.js +342 -0
  38. package/dist/log-view-B7uJEnMR.js.map +1 -0
  39. package/dist/{nitro-sP2F3SQu.js → nitro-B8u1iVgf.js} +2 -2
  40. package/dist/{nitro-sP2F3SQu.js.map → nitro-B8u1iVgf.js.map} +1 -1
  41. package/dist/{plain-B6z85uQP.js → plain-DG7cy0Kk.js} +7 -2
  42. package/dist/plain-DG7cy0Kk.js.map +1 -0
  43. package/dist/{prepare-B4ysyG6H.js → prepare-BM93i3Rm.js} +9 -5
  44. package/dist/prepare-BM93i3Rm.js.map +1 -0
  45. package/dist/{project-MD4dIo2X.js → project-zlQStwsf.js} +2 -2
  46. package/dist/{project-MD4dIo2X.js.map → project-zlQStwsf.js.map} +1 -1
  47. package/dist/{run-Ddwrxe1O.js → run-DMM2YlP3.js} +3 -13
  48. package/dist/run-DMM2YlP3.js.map +1 -0
  49. package/dist/{theme-3Fc_LI-2.js → theme-yS2h5dd_.js} +25 -1
  50. package/dist/theme-yS2h5dd_.js.map +1 -0
  51. package/dist/tsc-C5l5TQGC.js +3 -0
  52. package/dist/{tsc-DO7D_uCl.js → tsc-puVAcwmo.js} +24 -5
  53. package/dist/tsc-puVAcwmo.js.map +1 -0
  54. package/dist/{tsdown-CD68G8_U.js → tsdown-Dwt3JhPw.js} +2 -2
  55. package/dist/{tsdown-CD68G8_U.js.map → tsdown-Dwt3JhPw.js.map} +1 -1
  56. package/dist/{tui-BRddrLQP.js → tui-nldGSD4c.js} +913 -141
  57. package/dist/tui-nldGSD4c.js.map +1 -0
  58. package/dist/{vite-CLyB6wl7.js → vite-YZUtv2Hk.js} +2 -2
  59. package/dist/{vite-CLyB6wl7.js.map → vite-YZUtv2Hk.js.map} +1 -1
  60. package/package.json +5 -4
  61. package/dist/_shared-B-hRZDRS.js.map +0 -1
  62. package/dist/commands-ExM8HILu.js.map +0 -1
  63. package/dist/dev-4wpEQC7l.js.map +0 -1
  64. package/dist/diagnostics-CZBVxlpj.js.map +0 -1
  65. package/dist/errors-Crt4hu0b.js.map +0 -1
  66. package/dist/hooks-H9kjLCMk.js +0 -148
  67. package/dist/hooks-H9kjLCMk.js.map +0 -1
  68. package/dist/info-CdiQajgn.js.map +0 -1
  69. package/dist/log-buffer-CY82aqnb.js +0 -72
  70. package/dist/log-buffer-CY82aqnb.js.map +0 -1
  71. package/dist/plain-B6z85uQP.js.map +0 -1
  72. package/dist/prepare-B4ysyG6H.js.map +0 -1
  73. package/dist/run-Ddwrxe1O.js.map +0 -1
  74. package/dist/theme-3Fc_LI-2.js.map +0 -1
  75. package/dist/tsc-DO7D_uCl.js.map +0 -1
  76. package/dist/tsc-YnAWKn3n.js +0 -3
  77. package/dist/tui-BRddrLQP.js.map +0 -1
  78. package/dist/tunnel-DT1FH6oA.js +0 -175
  79. package/dist/tunnel-DT1FH6oA.js.map +0 -1
package/README.md CHANGED
@@ -21,12 +21,14 @@ commands. `@wolfstar/http-framework` also depends on this package and exposes it
21
21
  package has no install-time dependency on `@wolfstar/http-framework` in return, the same way `@nuxt/cli` has none on
22
22
  `nuxt` — its own commands:
23
23
 
24
- - `stars dev` builds the project, starts the bot, restarts it on changes and shows what is happening in an interactive terminal UI (or plain logs).
24
+ - `stars dev` builds 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: status, log channels and levels you can filter, and a prompt before changed commands are redeployed (or plain logs).
25
25
  - `stars build` runs the configured build tool once.
26
26
  - `stars info` prints the resolved configuration and environment (`--json` for scripts).
27
27
  - `stars codegen` runs the configured code generators (`--check` for CI).
28
28
  - `stars prepare` generates `.stars/tsconfig.json` and the auto imports declaration file (`--check` for CI).
29
- - `stars commands` inspects and cleans the application commands Discord has deployed.
29
+ - `stars commands` inspects, compares, deploys and cleans the application commands Discord has deployed.
30
+ - `stars doctor` checks that the project is ready: runtime, framework, credentials, interactions endpoint, generated files.
31
+ - `stars completions` prints the shell completion script for bash, zsh or fish.
30
32
 
31
33
  Everything is driven by a typed `stars.config.ts` file.
32
34
 
@@ -67,12 +69,14 @@ console.log(config.entry, config.build.output);
67
69
  ## Commands
68
70
 
69
71
  ```sh
70
- stars dev [--no-tui] [--config <file>] [--cwd <dir>]
72
+ stars dev [--no-tui] [--layout <auto|dashboard|panel>] [--channel <name>] [--level <level>] [--theme <name>] [--config <file>] [--cwd <dir>]
71
73
  stars build [--config <file>] [--cwd <dir>]
72
74
  stars info [--json] [--config <file>] [--cwd <dir>]
73
75
  stars codegen [--check] [--json] [--config <file>] [--cwd <dir>]
74
76
  stars prepare [--check] [--json] [--config <file>] [--cwd <dir>]
75
- stars commands [list|clean] [--guild <id>] [--name <name>] [--yes] [--json]
77
+ stars commands [list|clean|diff|deploy] [--guild <id>] [--name <name>] [--check] [--yes] [--json]
78
+ stars doctor [--online] [--json] [--config <file>] [--cwd <dir>]
79
+ stars completions <bash|zsh|fish>
76
80
  stars --help | --version
77
81
  ```
78
82
 
@@ -80,39 +84,133 @@ stars --help | --version
80
84
 
81
85
  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.
82
86
 
83
- The bot runs as a child `node` process with `STARS_DEV=1` and `NODE_ENV=development` in its environment. Because `stars dev` already restarts the whole process, leave the framework's own `hmr` option disabled while using it.
87
+ The bot runs as a child `node` process with `STARS_DEV=1` and `NODE_ENV=development` in its environment.
88
+
89
+ **Dashboard** (default on a TTY of at least 90×20): a full-screen view in the alternate buffer.
90
+
91
+ ```text
92
+ my-bot • stars v2.3.0 │ I 22:07:01 cli ● Build succeeded in 164ms
93
+ │ I 22:07:01 cli ● Starting (first build)
94
+ ● running │─────────────────────────────────────────────────────────
95
+ my-bot is ready! │ D 22:07:01 commands ● Loaded commands: 1 global, 0 guild groups
96
+ http v6.1.0 │ │ ping
97
+ up 3m 35s │─────────────────────────────────────────────────────────
98
+ port 6967 │ I 22:07:02 lifecycle ● Listening on port 6967
99
+ tunnel live │ W 22:07:11 http ● POST / 401 in 1ms
100
+ logs .stars/dev.log │ D 22:07:31 interactions ● Processing slash:ping with ping
101
+ │ T 22:09:16 hmr ● UPDATE src/commands/ping.js
102
+ ▾ channels │ D 22:09:16 hmr ● Reloaded ping from src/commands/ping.js
103
+ bot cli commands hmr http │┌────────────────────────────────────────────────────────┐
104
+ ▾ levels ││ Commands updated: │
105
+ error warn info debug trace ││ - ping changed │
106
+ ││ Refresh commands? (y/n) │
107
+ ● live │└────────────────────────────────────────────────────────┘
108
+ ```
109
+
110
+ The sidebar shows the state of the session (`starting`, `building`, `running`, `stopped`, `error`), the framework
111
+ version, the uptime, the port, the tunnel and where the logs are written, then the two filters of the stream. The
112
+ stream prints one line per entry: a level badge (`T D I W E`), the time, the channel, and the message with URLs,
113
+ paths, names and numbers picked out. An entry with detail lines (the commands that were loaded, the paths that are
114
+ watched) is a block between two rules; the stack frames the bot prints after an error are folded under that error
115
+ and count as one. The percentage of a build follows actual build milestones, not a timer.
116
+
117
+ **Channels** say what an entry is about, so each can be switched off:
118
+
119
+ | Channel | What logs there |
120
+ | -------------- | ------------------------------------------------------------------------------- |
121
+ | `cli` | `stars dev` itself: builds, restarts, hooks, warnings |
122
+ | `build` | the build tool and the file watcher |
123
+ | `bot` | everything the bot writes to stdout and stderr |
124
+ | `types` | the type checker (`dev.typecheck`) |
125
+ | `tunnel` | the public tunnel |
126
+ | `lifecycle` | the bot is listening, the pieces it loaded |
127
+ | `hmr` | files left to the bot's hot reload, and what it reloaded |
128
+ | `commands` | the application commands the bot registers, changes to them, redeploys |
129
+ | `interactions` | each interaction: the route (`slash:ping`), the piece, how long it took, errors |
130
+ | `http` | each request to the interactions endpoint, with its status (`trace` when fine) |
131
+
132
+ The last five come from the bot itself: `stars dev` preloads a small bridge into it (`node --import`) that reports
133
+ its events over an IPC channel instead of leaving the CLI to guess from stdout. It needs `@wolfstar/http-framework`
134
+ 6.1 or later, resolved from the project; without it (or with a build that bundles the framework, as Vite and Nitro
135
+ do) those channels stay empty and everything else works as before. A plugin can log on a channel of its own with
136
+ `process.send?.({ source: 'stars:bridge', type: 'log', channel: 'gateway', level: 'info', text: 'Shard 0 ready' })`.
137
+
138
+ `trace` is hidden at start, since it is one line per request. `dev.logs` in `stars.config`, or `--channel` and
139
+ `--level`, choose what a session starts with; the log file always receives everything:
140
+
141
+ ```ts
142
+ export default defineConfig({
143
+ dev: {
144
+ logs: { channels: ['bot', 'commands', 'interactions'], levels: ['error', 'warn', 'info'] }
145
+ }
146
+ });
147
+ ```
148
+
149
+ ```sh
150
+ stars dev --channel hmr,http --channel commands # only these channels
151
+ stars dev --level trace # this level and every more severe one
152
+ ```
84
153
 
85
- **Interactive UI** (default on a TTY): a bottom-aligned panel following the layout and keyboard conventions of
154
+ | Key | Action |
155
+ | ------------------ | ---------------------------------------------------------------- |
156
+ | `←` / `→` | select a channel or a level |
157
+ | `Tab` | switch between channels and levels |
158
+ | `Space` | show or hide the selected one |
159
+ | `s` | solo: only the selected one; again for all |
160
+ | `a` | show every channel and level |
161
+ | `Enter` | fold or unfold the selected group |
162
+ | `b` | group the stream by channel |
163
+ | `↑` / `↓`, `j`/`k` | scroll (`PgUp`/`PgDn` by page); the footer turns to `paused` |
164
+ | `g` / `G` | top / back to live |
165
+ | `/` | search the stream (`Esc` clears) |
166
+ | `e` | jump to the last error, keeping its context |
167
+ | `y` / `n` | answer a prompt |
168
+ | `r` / `Ctrl+R` | restart the bot |
169
+ | `d` | disconnect: stop the bot until the next `r`, builds keep running |
170
+ | `o` | open the local URL in a browser |
171
+ | `t` | toggle a public `cloudflared` tunnel |
172
+ | `i` | show project, versions, URLs, health, types and session info |
173
+ | `T` | pick a colour theme (see **Themes** below) |
174
+ | `l` | browse the logs full width: select a line, copy it |
175
+ | `v` | switch between the dashboard and the panel |
176
+ | `c` / `Ctrl+L` | clear log history |
177
+ | `h` / `?` | show keyboard shortcuts |
178
+ | `q` / `Ctrl+D` | quit; confirm with `y` while a build/restart is in flight |
179
+ | `Ctrl+C` | quit immediately from any view |
180
+
181
+ **Hot reload.** When the bot runs with the framework's `hmr` option enabled, it tells `stars dev` which directories
182
+ it watches. A build that only changed pieces in those directories is then left to the bot: the process, its HTTP
183
+ server and its connections stay up, and the `hmr` channel shows what was reloaded. A piece is a file the bot loaded
184
+ one from, or a new file that could be one. A change to anything else still restarts the bot: the entry, a shared
185
+ module, a locale, and also a helper next to the pieces (`_shared.js`, or any file no piece came from), which the bot
186
+ imports once and cannot replace. So does a bot without `hmr`, or one that stopped it. `dev.hmr: false` always
187
+ restarts. What a build changed is judged by content, since a bundler such as `tsdown` rewrites its whole output on
188
+ every rebuild.
189
+
190
+ **Command refresh.** The bot reports the application commands it registers when it starts and after every hot
191
+ reload. When they differ from what it reported before, `stars dev` asks (`Refresh commands? (y/n)`) and, on `y`, has
192
+ the bot register them with Discord again. `dev.commands.refresh` picks the behaviour: `'prompt'` (default), `'auto'`
193
+ to redeploy without asking, `'off'` to only report the change. Without the interactive UI a `'prompt'` only reports.
194
+ A question that is still open survives a restart of the bot, and a `y` given while the bot is stopped or restarting
195
+ is carried out once it listens again. A refresh also empties a guild whose last command was removed since the last
196
+ deploy, which pushing the registry alone would leave as it was.
197
+
198
+ **Panel** (`dev.layout: 'panel'`, `--layout panel`, `v`, or a terminal smaller than 90×20): a bottom-aligned panel in
199
+ the normal buffer, following the layout and keyboard conventions of
86
200
  [Nuxt CLI's dev TUI](https://github.com/nuxt/cli/tree/b4b366eafdd9ac4d5b81b6ae7dadda35364252c9/packages/nuxt-cli/src/dev/tui).
87
- The normal screen shows a Stars wordmark, aligned URLs, a 20-cell progress bar with elapsed time, status and
88
- shortcuts. The percentage follows actual build milestones, not a timer: it can stay still while a compiler phase
89
- runs. Once ready, the bar gives way to diagnostics and the header reports the load time.
201
+ It shows a Stars wordmark, aligned URLs, a 20-cell progress bar with elapsed time, status and shortcuts, and folds
202
+ the logs away: `l` opens them and `e` the last error. Once ready, the bar gives way to diagnostics and the header
203
+ reports the load time. The keys that do not concern the stream are the same as in the dashboard.
90
204
 
91
205
  Application output (including its banner), build-plugin output and diagnostics stay in the bounded log history and
92
- `.stars/dev.log`. tsdown's entry list and output-size table are suppressed. Only log/help/info overlays enter the
93
- alternate screen; closing them restores the panel without duplicating output in scrollback. Error stack frames do
94
- not count as individual errors. `READY` reports process state unless `dev.health` is configured; it does not certify
95
- that every application plugin loaded successfully. Logged errors switch the badge to `ERROR`.
96
-
97
- | Key | Action |
98
- | -------------- | ------------------------------------------------------------ |
99
- | `r` / `Ctrl+R` | restart the bot |
100
- | `o` | open the local URL in a browser |
101
- | `t` | toggle a public `cloudflared` tunnel |
102
- | `i` | show project, versions, URLs, health, types and session info |
103
- | `T` | pick a colour theme (see **Themes** below) |
104
- | `l` | browse logs |
105
- | `e` | select the last error with its surrounding context |
106
- | `c` / `Ctrl+L` | clear log history |
107
- | `h` / `?` | show keyboard shortcuts |
108
- | `q` / `Ctrl+D` | quit; confirm with `y` while a build/restart is in flight |
109
- | `Ctrl+C` | quit immediately from any view |
110
-
111
- In the log view: arrows or `j/k` select, `PgUp/PgDn` move a page, `g/G` go to the beginning/follow the tail,
206
+ `.stars/dev.log`. tsdown's entry list and output-size table are suppressed. Closing an overlay restores the view
207
+ under it without duplicating output in scrollback. `running` (`READY` in the panel) reports process state unless
208
+ `dev.health` is configured; it does not certify that every application plugin loaded successfully.
209
+
210
+ In the log browser (`l`): arrows or `j/k` select, `PgUp/PgDn` move a page, `g/G` go to the beginning/follow the tail,
112
211
  `e/w/a` filter errors/warnings/all, `c/b/r` toggle CLI/build/runtime sources, `/` searches, `x` clears, and
113
212
  `Enter`/`y` copies the selected line on terminals supporting OSC 52 clipboard writes. `q`, `Esc` or the view's
114
- own shortcut closes an overlay rather than quitting the session. Nuxt-specific request and page-route inspectors
115
- are not exposed: the bot supervisor does not receive those runtime events.
213
+ own shortcut closes an overlay rather than quitting the session.
116
214
 
117
215
  Replace the default wordmark in `stars.config.ts` (up to four lines are displayed, clipped to the terminal width):
118
216
 
@@ -133,7 +231,8 @@ palette decides). The theme resolves as `--theme <name>` › `STARS_THEME` › t
133
231
  `preferences.json` under `$STARS_CONFIG_DIR`, `$XDG_CONFIG_HOME/stars`, `%APPDATA%\stars` or `~/.config/stars`.
134
232
  `NO_COLOR` still disables colour altogether.
135
233
 
136
- **Plain mode** prints prefixed lines instead and is selected by `--no-tui`, `STARS_TUI=plain`, redirected input/output,
234
+ **Plain mode** prints prefixed lines instead (the channel, then the message, with detail lines indented under it;
235
+ the bot's own output is passed through untouched) and is selected by `--no-tui`, `STARS_TUI=plain`, redirected input/output,
137
236
  CI, `TERM=dumb`, or terminals smaller than 40×10. `STARS_TUI=1` overrides CI/size checks, never redirected streams or
138
237
  a dumb terminal. Both modes honour `NO_COLOR`/`FORCE_COLOR`; `STARS_REDUCED_MOTION=1` freezes the logo/spinner but
139
238
  keeps the elapsed clock. Both stop the bot cleanly on `SIGINT`/`SIGTERM`. `SIGUSR2` restarts the bot (not on Windows).
@@ -156,12 +255,71 @@ It reads `DISCORD_TOKEN` and `DISCORD_APPLICATION_ID` (or `APPLICATION_ID`) from
156
255
  a checklist of what is deployed, then a confirmation — and refuses to run without `--yes` (or `--name`) anywhere
157
256
  else.
158
257
 
258
+ `diff` and `deploy` compare that with what the project defines:
259
+
260
+ ```sh
261
+ stars commands diff # what a deploy would add (+), change (~) and remove (-)
262
+ stars commands diff --check # the same, failing when anything differs (CI)
263
+ stars commands deploy # show the difference, ask, then overwrite the global scope
264
+ stars commands deploy --guild 1234 --yes
265
+ ```
266
+
267
+ Commands are declared with builders and decorators that only exist once the bot's modules ran, so `stars` asks the
268
+ bot: it starts the built entry (run `stars build` first) with the dev bridge, which loads the pieces, reports the
269
+ registry and exits before the bot listens or talks to Discord. This needs `@wolfstar/http-framework` 6.1 or later.
270
+ The bot is started as `stars dev` would start it (the same env files, after the `env:options` hook), in the
271
+ `NODE_ENV` of the caller, `development` when unset: run `NODE_ENV=production stars commands deploy` to deploy what a
272
+ production start registers. It is not a dev session, so `STARS_DEV` is not set.
273
+ A command counts as changed when what the project defines no longer matches what is deployed; the fields Discord
274
+ fills in on its own (`id`, `version`, defaults such as `nsfw: false`) are ignored. `deploy` is Discord's bulk
275
+ overwrite: a deployed command the project no longer defines is deleted, which is why it asks first and refuses to
276
+ run without `--yes` outside a terminal, or with `--json`.
277
+
278
+ ### `stars doctor`
279
+
280
+ Checks what a project needs before `stars dev` can do its job, and says what to do about each problem:
281
+
282
+ ```text
283
+ stars doctor v2.3.0
284
+ ✔ node Node.js v24.19.0
285
+ ✔ config stars.config.ts
286
+ ✔ framework @wolfstar/http-framework v6.1.0
287
+ ✔ entry src/main.ts (tsdown)
288
+ ✖ token DISCORD_TOKEN is not set
289
+ → Set DISCORD_TOKEN in the environment or in the project .env file.
290
+ ⚠ port Something already listens on http://localhost:3000
291
+ → Stop it, or set another HTTP_PORT, unless it is this bot running.
292
+ ℹ tunnel No tunnel: Discord cannot reach a bot on localhost
293
+ → Set `dev.tunnel: true` for a cloudflared quick tunnel, or press t in `stars dev`.
294
+ ⚠ prepare Out of date: .stars/tsconfig.json
295
+ → Run `stars prepare`.
296
+
297
+ 1 error(s), 2 warning(s)
298
+ ```
299
+
300
+ It covers the Node.js version (and the project's `engines.node`), the configuration and its warnings, the framework
301
+ (and whether it is recent enough for the dev bridge), the entry and the build output, `DISCORD_TOKEN`,
302
+ `DISCORD_PUBLIC_KEY` and the application id, whether the dev port is free, the tunnel, and whether `.stars/` is stale.
303
+ `--online` also asks Discord whether the token works and where the application sends its interactions. Nothing is
304
+ changed. `--json` prints `{ ok, checks }`; the exit code is `1` when a check fails.
305
+
306
+ ### `stars completions`
307
+
308
+ ```sh
309
+ eval "$(stars completions bash)" # ~/.bashrc
310
+ eval "$(stars completions zsh)" # ~/.zshrc
311
+ stars completions fish | source # ~/.config/fish/config.fish
312
+ ```
313
+
314
+ The script is generated from the commands the CLI registers, so it completes every command, subcommand and flag
315
+ `--help` lists, with their short forms (`-c`) and the `--no-` form of the ones that are on by default (`--no-tui`).
316
+
159
317
  ### Type checking, tunnel and logs
160
318
 
161
319
  Three `dev` options round out the dev loop (all documented in
162
320
  [`@wolfstar/http-framework`](../http-framework#project-configuration-starsconfig)):
163
321
 
164
- - `dev.typecheck: true` runs a type checker next to the bot and reports type errors on the UI's `tsc` channel,
322
+ - `dev.typecheck: true` runs a type checker next to the bot and reports type errors on the UI's `types` channel,
165
323
  without ever blocking a build or a restart — useful when building with `tsdown`, which does not type-check.
166
324
  `dev.typecheck.checker` picks which one: `tsc` (the project's TypeScript, watch mode), `golar` (`golar tsc`, watch
167
325
  mode), `tsz` (the tsc-compatible checker, re-run after every build since it has no watch mode), or `auto` — the
@@ -170,7 +328,10 @@ Three `dev` options round out the dev loop (all documented in
170
328
  internet; a string is an https URL you already serve, which the CLI only probes. `dev.tunnel.updateEndpoint` writes
171
329
  the URL to the Discord application, and is opt-in because it edits a live application.
172
330
  - `dev.logFile` (default `.stars/dev.log`) mirrors the session's logs to disk, so a run can be read back after the
173
- terminal UI is gone. Set it to `false` to disable it.
331
+ terminal UI is gone. Set it to `false` to disable it. It is truncated on every run; `dev.logs.dir` (for example
332
+ `'logs'`) adds one file per run, `dev-<timestamp>.log`, and `dev.logs.keep` (default `10`) says how many stay. Each
333
+ line is `<ISO time> <level> <channel> <message>`, with the detail lines of an entry indented under it, and no entry
334
+ is ever filtered out of a file.
174
335
 
175
336
  ### The build
176
337
 
@@ -250,14 +411,14 @@ reference.
250
411
 
251
412
  ### Exit codes
252
413
 
253
- | Code | Meaning |
254
- | ----- | ---------------------------------------------------- |
255
- | `0` | success |
256
- | `1` | generic error (including `codegen --check` failures) |
257
- | `2` | invalid or missing configuration |
258
- | `3` | build failed |
259
- | `130` | interrupted with `SIGINT` |
260
- | `143` | terminated with `SIGTERM`/`SIGHUP` |
414
+ | Code | Meaning |
415
+ | ----- | --------------------------------------------------------- |
416
+ | `0` | success |
417
+ | `1` | generic error (including `--check` and `doctor` failures) |
418
+ | `2` | invalid or missing configuration |
419
+ | `3` | build failed |
420
+ | `130` | interrupted with `SIGINT` |
421
+ | `143` | terminated with `SIGTERM`/`SIGHUP` |
261
422
 
262
423
  ### Generated TypeScript configuration
263
424
 
@@ -1,5 +1,6 @@
1
- import { r as formatError } from "./errors-Crt4hu0b.js";
1
+ import { r as formatError } from "./errors-COFWKKKw.js";
2
2
  import { t as loadAutoImportsModule } from "./framework-auto-imports-Gu_PXSyr.js";
3
+ import { a as modulesPreloadWarning, o as prepareModulesPreload } from "./hooks-Cy6F2bhH.js";
3
4
  import { createRequire } from "node:module";
4
5
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
5
6
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -122,7 +123,8 @@ async function prepareProject(config, hooks, check = false) {
122
123
  const tsconfig = await prepareTsconfig(config, check);
123
124
  const result = {
124
125
  ...await prepareAutoImports(config, check),
125
- tsconfig
126
+ tsconfig,
127
+ modules: await prepareModulesPreload(config, check)
126
128
  };
127
129
  await hooks?.callHook("prepare:done", config, {
128
130
  dts: result.dts,
@@ -130,11 +132,16 @@ async function prepareProject(config, hooks, check = false) {
130
132
  });
131
133
  return result;
132
134
  }
133
- /** Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version). */
134
- async function reportWarnings(config, write) {
135
+ /**
136
+ * Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version), and, unless `production`
137
+ * is `false` (`stars dev`, which does that itself), what a production start of the project still needs to do.
138
+ */
139
+ async function reportWarnings(config, write, options = {}) {
135
140
  for (const warning of config.warnings) write(await formatError(warning));
141
+ const preload = options.production === false ? null : modulesPreloadWarning(config);
142
+ if (preload) write(await formatError(preload));
136
143
  }
137
144
 
138
145
  //#endregion
139
146
  export { reportWarnings as n, prepareProject as t };
140
- //# sourceMappingURL=_shared-B-hRZDRS.js.map
147
+ //# sourceMappingURL=_shared-BIQK0Bhm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_shared-BIQK0Bhm.js","names":[],"sources":["../src/utils/tsconfig.ts","../src/commands/_shared.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { createRequire } from 'node:module';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\n\nconst require = createRequire(import.meta.url);\nconst sapphireOptions = Object.assign(\n\t{},\n\t...['@sapphire/ts-config', '@sapphire/ts-config/extra-strict', '@sapphire/ts-config/decorators'].map(\n\t\t(id) => (require(id) as { compilerOptions: Record<string, unknown> }).compilerOptions\n\t)\n) as Record<string, unknown>;\n\n/** Generates an extendable config without changing the project's own tsconfig. */\nexport async function prepareTsconfig(config: ResolvedStarsConfig, check = false) {\n\tconst path = join(config.root, '.stars', 'tsconfig.json');\n\tconst fromGenerated = (target: string) => `./${relative(dirname(path), target).replaceAll('\\\\', '/')}`;\n\tconst paths: Record<string, string[]> = {};\n\tif (config.build.tool === 'tsdown') {\n\t\tconst source = dirname(config.entry);\n\t\tconst defaults = config.build.configFile === null ? { '~': source, '@': source, '~~': config.root, '@@': config.root } : {};\n\t\tconst aliases = { ...defaults, ...(config.tsdown.alias as Record<string, unknown> | undefined) };\n\t\tfor (const [alias, target] of Object.entries(aliases)) {\n\t\t\t// Module redirects belong to the bundler; only filesystem targets become TypeScript paths.\n\t\t\tif (typeof target !== 'string' || (!isAbsolute(target) && !/^\\.\\.?[/\\\\]/.test(target))) continue;\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\n\t\t\tpaths[alias] = [resolved];\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\n\t\t}\n\t} else if (config.experimental.enableNitro) {\n\t\t// `NitroBuilder` turns on Vite's native `resolve.tsconfigPaths` (see https://nitro.build/examples/import-alias),\n\t\t// which reads these `paths` straight out of the generated tsconfig — no `tsdown.alias` equivalent to merge\n\t\t// with, `vite`/Nitro projects only have this file's own `compilerOptions.paths` to extend or replace.\n\t\tconst source = dirname(config.entry);\n\t\tconst defaults = { '~': source, '@': source, '~~': config.root, '@@': config.root };\n\t\tfor (const [alias, target] of Object.entries(defaults)) {\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\n\t\t\tpaths[alias] = [resolved];\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\n\t\t}\n\t}\n\tconst content = `${JSON.stringify(\n\t\t{\n\t\t\tcompilerOptions: {\n\t\t\t\t...sapphireOptions,\n\t\t\t\t// Bundlers emit the application; TypeScript only checks it. Keep Node16 emit for tsc.\n\t\t\t\t...(config.build.tool === 'tsdown' || config.build.tool === 'vite'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tmodule: 'ESNext',\n\t\t\t\t\t\t\tmoduleResolution: 'Bundler',\n\t\t\t\t\t\t\tmoduleDetection: 'force',\n\t\t\t\t\t\t\tisolatedModules: true,\n\t\t\t\t\t\t\tverbatimModuleSyntax: true,\n\t\t\t\t\t\t\tallowJs: true,\n\t\t\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t\t\tresolvePackageJsonImports: true,\n\t\t\t\t\t\t\tlib: ['ESNext', 'DOM'],\n\t\t\t\t\t\t\tnoEmit: true\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\ttarget: 'ES2022',\n\t\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\t\tskipLibCheck: true,\n\t\t\t\ttsBuildInfoFile: './tsconfig.tsbuildinfo',\n\t\t\t\tpaths\n\t\t\t},\n\t\t\tinclude: [`${fromGenerated(dirname(config.entry))}/**/*`, ...(config.imports.enabled ? [fromGenerated(config.imports.dts)] : [])],\n\t\t\texclude: [fromGenerated(join(config.root, 'node_modules')), fromGenerated(config.build.outDir)]\n\t\t},\n\t\tnull,\n\t\t2\n\t)}\\n`;\n\tif (check) {\n\t\tconst existing = await readFile(path, 'utf-8').catch(() => null);\n\t\treturn { path, status: existing === content ? ('up-to-date' as const) : ('outdated' as const) };\n\t}\n\tawait mkdir(dirname(path), { recursive: true });\n\tawait writeFile(path, content);\n\treturn { path, status: 'written' as const };\n}\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { loadAutoImportsModule } from '../utils/framework-auto-imports.js';\nimport { formatError } from '../utils/errors.js';\nimport type { StarsHookable } from '../utils/hooks.js';\nimport { modulesPreloadWarning, prepareModulesPreload } from '../utils/modules.js';\nimport { prepareTsconfig } from '../utils/tsconfig.js';\n\nexport type PrepareResult =\n\t| { enabled: false; dts: null; status: null }\n\t| { enabled: true; dts: string; status: 'written' | 'up-to-date' | 'outdated' };\n\n/**\n * Regenerates `imports.dts` unconditionally, used by `stars dev`/`stars build` before the first build so the\n * declaration file exists (and is current) even when the user never ran `stars prepare` themselves.\n */\nexport async function prepareAutoImports(config: ResolvedStarsConfig, check = false): Promise<PrepareResult> {\n\tif (!config.imports.enabled) return { enabled: false, dts: null, status: null };\n\n\tconst { dirs, presets, exclude, dts } = config.imports;\n\tconst { generateAutoImportsDts } = await loadAutoImportsModule(config.root);\n\tconst content = await generateAutoImportsDts({ root: config.root, dirs, presets, exclude });\n\n\tif (check) {\n\t\tconst existing = await readFile(dts, 'utf-8').catch(() => null);\n\t\treturn { enabled: true, dts, status: existing === content ? 'up-to-date' : 'outdated' };\n\t}\n\n\tawait mkdir(dirname(dts), { recursive: true });\n\tawait writeFile(dts, content);\n\treturn { enabled: true, dts, status: 'written' };\n}\n\n/** Prepares TypeScript configuration and auto import declarations before building. */\nexport async function prepareProject(config: ResolvedStarsConfig, hooks?: StarsHookable, check = false) {\n\tawait hooks?.callHook('prepare:before', config);\n\tconst tsconfig = await prepareTsconfig(config, check);\n\tconst result = { ...(await prepareAutoImports(config, check)), tsconfig, modules: await prepareModulesPreload(config, check) };\n\tawait hooks?.callHook('prepare:done', config, { dts: result.dts, status: result.status });\n\treturn result;\n}\n\n/**\n * Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version), and, unless `production`\n * is `false` (`stars dev`, which does that itself), what a production start of the project still needs to do.\n */\nexport async function reportWarnings(\n\tconfig: ResolvedStarsConfig,\n\twrite: (text: string) => void,\n\toptions: { production?: boolean } = {}\n): Promise<void> {\n\tfor (const warning of config.warnings) write(await formatError(warning));\n\n\tconst preload = options.production === false ? null : modulesPreloadWarning(config);\n\tif (preload) write(await formatError(preload));\n}\n"],"mappings":"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"}