@wolfstar/cli 2.1.0-next-20261001111011 → 2.2.0

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 (74) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +304 -304
  3. package/dist/{_shared-B-hRZDRS.js → _shared-DJrpalNQ.js} +12 -5
  4. package/dist/_shared-DJrpalNQ.js.map +1 -0
  5. package/dist/{build-CPnSLYME.js → build-CluOR8dJ.js} +5 -5
  6. package/dist/build-CluOR8dJ.js.map +1 -0
  7. package/dist/cli.js +1 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/{codegen-BqpLGLLs.js → codegen-D6V1i_fa.js} +4 -4
  10. package/dist/codegen-D6V1i_fa.js.map +1 -0
  11. package/dist/{commands-ExM8HILu.js → commands-BJ589_AC.js} +4 -4
  12. package/dist/commands-BJ589_AC.js.map +1 -0
  13. package/dist/{dev-4wpEQC7l.js → dev-DJJZN4NJ.js} +11 -30
  14. package/dist/dev-DJJZN4NJ.js.map +1 -0
  15. package/dist/{diagnostics-CZBVxlpj.js → diagnostics-3JRAy8Xj.js} +17 -1
  16. package/dist/diagnostics-3JRAy8Xj.js.map +1 -0
  17. package/dist/{errors-Crt4hu0b.js → errors-COFWKKKw.js} +5 -2
  18. package/dist/errors-COFWKKKw.js.map +1 -0
  19. package/dist/external-CxFKxwi3.js.map +1 -1
  20. package/dist/framework-auto-imports-Gu_PXSyr.js.map +1 -1
  21. package/dist/hooks-BfDFM38k.js +316 -0
  22. package/dist/hooks-BfDFM38k.js.map +1 -0
  23. package/dist/index.d.ts +22 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -3
  26. package/dist/{info-CdiQajgn.js → info-C1Kx_4Og.js} +4 -4
  27. package/dist/info-C1Kx_4Og.js.map +1 -0
  28. package/dist/{locales-C7X8VNmK.js → locales-BzOLRBVg.js} +5 -5
  29. package/dist/locales-BzOLRBVg.js.map +1 -0
  30. package/dist/log-buffer-CY82aqnb.js.map +1 -1
  31. package/dist/{nitro-sP2F3SQu.js → nitro-yjqZBh5L.js} +2 -2
  32. package/dist/nitro-yjqZBh5L.js.map +1 -0
  33. package/dist/none-uC_wi_l4.js.map +1 -1
  34. package/dist/output-mode-Bp7Da8vJ.js.map +1 -1
  35. package/dist/plain-B6z85uQP.js.map +1 -1
  36. package/dist/{prepare-B4ysyG6H.js → prepare-Cb45Z4re.js} +9 -5
  37. package/dist/prepare-Cb45Z4re.js.map +1 -0
  38. package/dist/{project-MD4dIo2X.js → project-D-8VIcyF.js} +2 -2
  39. package/dist/project-D-8VIcyF.js.map +1 -0
  40. package/dist/{run-Ddwrxe1O.js → run-BiLZqib3.js} +8 -8
  41. package/dist/run-BiLZqib3.js.map +1 -0
  42. package/dist/theme-3Fc_LI-2.js.map +1 -1
  43. package/dist/tsc-B931Ezh7.js +3 -0
  44. package/dist/{tsc-DO7D_uCl.js → tsc-DEBcwIO0.js} +3 -3
  45. package/dist/tsc-DEBcwIO0.js.map +1 -0
  46. package/dist/{tsdown-CD68G8_U.js → tsdown-DrWXld54.js} +2 -2
  47. package/dist/tsdown-DrWXld54.js.map +1 -0
  48. package/dist/tui-BRddrLQP.js.map +1 -1
  49. package/dist/{tunnel-DT1FH6oA.js → tunnel-DHSxOZKr.js} +2 -2
  50. package/dist/tunnel-DHSxOZKr.js.map +1 -0
  51. package/dist/version-BzclCE19.js.map +1 -1
  52. package/dist/{vite-CLyB6wl7.js → vite-Bf7nrJx7.js} +2 -2
  53. package/dist/vite-Bf7nrJx7.js.map +1 -0
  54. package/package.json +5 -4
  55. package/dist/_shared-B-hRZDRS.js.map +0 -1
  56. package/dist/build-CPnSLYME.js.map +0 -1
  57. package/dist/codegen-BqpLGLLs.js.map +0 -1
  58. package/dist/commands-ExM8HILu.js.map +0 -1
  59. package/dist/dev-4wpEQC7l.js.map +0 -1
  60. package/dist/diagnostics-CZBVxlpj.js.map +0 -1
  61. package/dist/errors-Crt4hu0b.js.map +0 -1
  62. package/dist/hooks-H9kjLCMk.js +0 -148
  63. package/dist/hooks-H9kjLCMk.js.map +0 -1
  64. package/dist/info-CdiQajgn.js.map +0 -1
  65. package/dist/locales-C7X8VNmK.js.map +0 -1
  66. package/dist/nitro-sP2F3SQu.js.map +0 -1
  67. package/dist/prepare-B4ysyG6H.js.map +0 -1
  68. package/dist/project-MD4dIo2X.js.map +0 -1
  69. package/dist/run-Ddwrxe1O.js.map +0 -1
  70. package/dist/tsc-DO7D_uCl.js.map +0 -1
  71. package/dist/tsc-YnAWKn3n.js +0 -3
  72. package/dist/tsdown-CD68G8_U.js.map +0 -1
  73. package/dist/tunnel-DT1FH6oA.js.map +0 -1
  74. package/dist/vite-CLyB6wl7.js.map +0 -1
@@ -0,0 +1,316 @@
1
+ import { t as readOwnPackageJson } from "./version-BzclCE19.js";
2
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.js";
3
+ import { i as resolveFromProject, r as resolveBinary, t as findInstalledVersion } from "./project-D-8VIcyF.js";
4
+ import { isAbsolute, join, resolve } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import { loadConfigFile, readProjectEnvFiles, resolveStarsConfig } from "@wolfstar/schema";
7
+ import { envModuleSource, modulesModuleSource } from "@wolfstar/vite-server/internal";
8
+ import { execFileSync } from "node:child_process";
9
+ import { resolve as resolve$1, resolveSync } from "mlly";
10
+ import { createHooks } from "hookable";
11
+ import { ModuleError, setupModules } from "@wolfstar/kit";
12
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
13
+
14
+ //#region src/utils/args.ts
15
+ /**
16
+ * Arguments shared by every command that reads the project configuration.
17
+ */
18
+ const projectArgs = {
19
+ config: {
20
+ type: "string",
21
+ alias: "c",
22
+ description: "Path to the configuration file (defaults to stars.config.* in the working directory)"
23
+ },
24
+ cwd: {
25
+ type: "string",
26
+ description: "Working directory to run from (defaults to the current directory)"
27
+ }
28
+ };
29
+ function resolveCwd(args) {
30
+ return args.cwd ? resolve(process.cwd(), args.cwd) : process.cwd();
31
+ }
32
+
33
+ //#endregion
34
+ //#region src/utils/env-import.ts
35
+ /** Build tools whose output never passes through the entry transform that registers `env`. */
36
+ const UNTRANSFORMED_TOOLS = /* @__PURE__ */ new Set(["none", "tsc"]);
37
+ /**
38
+ * `node` arguments that register `env` before the entry runs, for the build tools the entry transform cannot reach.
39
+ * The preload is a `data:` URL, so `.stars/` gets no generated runtime file; a `data:` URL cannot resolve bare
40
+ * specifiers, so `@wolfstar/env-utilities` is resolved from the project first. When it cannot be resolved nothing is
41
+ * preloaded, and the bot's own import of it reports the missing install.
42
+ */
43
+ function envImportArgs(config) {
44
+ if (!config.env.enabled || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];
45
+ const resolved = resolveFromProject(config.root, "@wolfstar/env-utilities");
46
+ if (resolved === null) return [];
47
+ const source = envModuleSource(config.env.options, pathToFileURL(resolved).href);
48
+ return ["--import", `data:text/javascript,${encodeURIComponent(source)}`];
49
+ }
50
+ /**
51
+ * `node` arguments that register the runtime plugins of the installed modules (`ctx.addPlugin`) before the entry
52
+ * runs, for the build tools the entry transform cannot reach. `@wolfstar/http-framework` and every plugin are resolved
53
+ * from the project first, with the `import` condition (both are ESM), because a `data:` URL cannot resolve bare
54
+ * specifiers; the framework is the bot's own copy, so `Client.use` reaches the `Client` the bot constructs. When the
55
+ * framework is not installed nothing is preloaded, and the bot's own import of it reports the missing install.
56
+ */
57
+ function moduleImportArgs(config) {
58
+ const plugins = config.runtime?.plugins ?? [];
59
+ if (plugins.length === 0 || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];
60
+ const url = pathToFileURL(`${config.root}/package.json`).href;
61
+ let framework;
62
+ try {
63
+ framework = resolveSync("@wolfstar/http-framework", { url });
64
+ } catch {
65
+ return [];
66
+ }
67
+ const source = modulesModuleSource(plugins, {
68
+ framework,
69
+ resolve: (from) => {
70
+ if (from.startsWith("file:")) return from;
71
+ if (isAbsolute(from)) return pathToFileURL(from).href;
72
+ try {
73
+ return resolveSync(from, { url });
74
+ } catch {
75
+ throw cliDiagnostics.DEPENDENCY_MISSING({
76
+ name: from,
77
+ root: config.root,
78
+ hint: "Install the package of the module that registers this plugin."
79
+ });
80
+ }
81
+ }
82
+ });
83
+ return ["--import", `data:text/javascript,${encodeURIComponent(source)}`];
84
+ }
85
+
86
+ //#endregion
87
+ //#region src/utils/modules.ts
88
+ /**
89
+ * Where a module specifier is imported from: a relative or absolute path is a file of the project, a `file:` URL is
90
+ * itself, anything else is a package resolved from the project root — with `mlly`, honouring the `import` condition,
91
+ * because installed modules are ESM-only packages a CommonJS `require.resolve` cannot see.
92
+ */
93
+ async function resolveSpecifier(root, specifier) {
94
+ if (specifier.startsWith("file:")) return specifier;
95
+ if (specifier.startsWith(".") || isAbsolute(specifier)) return pathToFileURL(resolve(root, specifier)).href;
96
+ return resolve$1(specifier, { url: pathToFileURL(`${root}/package.json`).href });
97
+ }
98
+ /**
99
+ * Runs `setup` of every module in `modules` (see `@wolfstar/kit`) and returns the configuration carrying what they
100
+ * contributed: `runtime`, and `imports.presets` extended by `ctx.addImports`. Without modules the configuration is
101
+ * returned as it is.
102
+ */
103
+ async function installModules(config, hooks) {
104
+ if (config.modules.length === 0) return config;
105
+ try {
106
+ const runtime = await setupModules({
107
+ config,
108
+ hooks,
109
+ versions: {
110
+ framework: findInstalledVersion(config.root, "@wolfstar/http-framework"),
111
+ stars: readOwnPackageJson().version
112
+ },
113
+ load: async (specifier) => import(await resolveSpecifier(config.root, specifier))
114
+ });
115
+ const presets = [...config.imports.presets, ...runtime.imports.filter((preset) => !config.imports.presets.includes(preset))];
116
+ return {
117
+ ...config,
118
+ runtime,
119
+ imports: {
120
+ ...config.imports,
121
+ presets
122
+ }
123
+ };
124
+ } catch (error) {
125
+ if (error instanceof ModuleError) throw cliDiagnostics.MODULE_FAILED({
126
+ module: error.moduleName,
127
+ reason: error.code,
128
+ message: error.message,
129
+ cause: error
130
+ });
131
+ throw error;
132
+ }
133
+ }
134
+ /**
135
+ * The warning for a project whose runtime plugins reach production only through a `node --import` preload, `null`
136
+ * otherwise. It is not one of `config.warnings`: `stars dev` preloads the plugins itself, so there it would be noise
137
+ * on every start. `stars build` and `stars prepare` report it.
138
+ */
139
+ function modulesPreloadWarning(config) {
140
+ if (!needsPreload(config)) return null;
141
+ return cliDiagnostics.MODULES_PRELOAD_REQUIRED({
142
+ tool: config.build.tool,
143
+ plugins: [...new Set(config.runtime.plugins.map((plugin) => plugin.module))].join(", ")
144
+ });
145
+ }
146
+ /** A build tool the entry transform cannot reach, with runtime plugins to register: they need a `node --import` preload. */
147
+ function needsPreload(config) {
148
+ return UNTRANSFORMED_TOOLS.has(config.build.tool) && (config.runtime?.plugins.length ?? 0) > 0;
149
+ }
150
+ /**
151
+ * Writes `.stars/modules.mjs`, the production counterpart of the preload `stars dev` passes to `node`: `node --import
152
+ * ./.stars/modules.mjs <entry>` registers the runtime plugins of the installed modules for the build tools whose entry
153
+ * cannot be transformed (`tsc`, `none`). Its specifiers are bare, so they resolve from the project's `node_modules`
154
+ * like the bot's own imports. `null` when there is nothing to register.
155
+ *
156
+ * With `env` enabled it is preceded by `.stars/env.mjs`, a separate module imported first: imports of one module are
157
+ * all evaluated before its body runs, so the environment could not be loaded ahead of the plugins from the same file,
158
+ * and a plugin reading `process.env` while it is imported would see nothing.
159
+ */
160
+ async function prepareModulesPreload(config, check = false) {
161
+ if (!needsPreload(config)) return null;
162
+ const directory = join(config.root, ".stars");
163
+ const path = join(directory, "modules.mjs");
164
+ const withEnv = config.env?.enabled === true;
165
+ const plugins = modulesModuleSource(config.runtime.plugins, { resolve: (from) => isAbsolute(from) ? pathToFileURL(from).href : from });
166
+ const files = [{
167
+ path,
168
+ content: withEnv ? `import "./env.mjs";\n${plugins}` : plugins
169
+ }, ...withEnv ? [{
170
+ path: join(directory, "env.mjs"),
171
+ content: envModuleSource(config.env.options)
172
+ }] : []];
173
+ if (check) return {
174
+ path,
175
+ status: (await Promise.all(files.map(async (file) => await readFile(file.path, "utf-8").catch(() => null) === file.content))).every(Boolean) ? "up-to-date" : "outdated"
176
+ };
177
+ await mkdir(directory, { recursive: true });
178
+ await Promise.all(files.map((file) => writeFile(file.path, file.content)));
179
+ return {
180
+ path,
181
+ status: "written"
182
+ };
183
+ }
184
+
185
+ //#endregion
186
+ //#region src/utils/project-env.ts
187
+ /**
188
+ * The variables the bot will load, for the CLI's own lookups (Discord credentials for the tunnel). With the default
189
+ * loader these are the project's env files, read from `env.path`/`env.env`. With `loader: 'varlock'` they are what
190
+ * `varlock load` resolves from the project's `.env.schema` — a dotenv file may be stale or absent there — and nothing
191
+ * when varlock cannot be run, rather than values the bot never sees.
192
+ */
193
+ function readProjectEnv(config) {
194
+ const { path, env = "development", loader } = config.env.options;
195
+ if (loader !== "varlock") return readProjectEnvFiles(config.root, env, { path });
196
+ const binary = resolveBinary(config.root, "varlock", "varlock");
197
+ if (binary === null) return {};
198
+ try {
199
+ const output = execFileSync(process.execPath, [
200
+ binary,
201
+ "load",
202
+ "--format",
203
+ "json"
204
+ ], {
205
+ cwd: config.root,
206
+ env: {
207
+ ...process.env,
208
+ ...config.dev.env,
209
+ NODE_ENV: "development"
210
+ },
211
+ encoding: "utf8",
212
+ stdio: [
213
+ "ignore",
214
+ "pipe",
215
+ "ignore"
216
+ ],
217
+ timeout: 3e4
218
+ });
219
+ const values = JSON.parse(output);
220
+ return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => [key, String(value)]));
221
+ } catch {
222
+ return {};
223
+ }
224
+ }
225
+
226
+ //#endregion
227
+ //#region src/utils/hooks.ts
228
+ /** What each configuration loaded by {@link loadProject} was resolved from, so `env:options` can re-resolve it. */
229
+ const sources = /* @__PURE__ */ new WeakMap();
230
+ /** Registers the `hooks` of `stars.config` on a fresh `hookable` instance. */
231
+ function createStarsHooks(config) {
232
+ const hooks = createHooks();
233
+ for (const [name, callbacks] of Object.entries(config.hooks)) for (const callback of callbacks) hooks.hook(name, callback);
234
+ return hooks;
235
+ }
236
+ /** Loads `stars.config`, registers its hooks and runs `config:resolved`. */
237
+ async function loadProject(options) {
238
+ const cwd = options.cwd ?? process.cwd();
239
+ const loaded = await loadConfigFile({
240
+ cwd,
241
+ configFile: options.configFile
242
+ });
243
+ const source = {
244
+ cwd,
245
+ configFile: loaded.configFile,
246
+ config: loaded.config,
247
+ env: options.env
248
+ };
249
+ const resolved = resolveStarsConfig(source);
250
+ const hooks = createStarsHooks(resolved);
251
+ const config = await installModules(resolved, hooks);
252
+ sources.set(config, source);
253
+ await hooks.callHook("config:resolved", config);
254
+ return {
255
+ config,
256
+ hooks
257
+ };
258
+ }
259
+ /**
260
+ * Runs `env:options` on a copy of the resolved `env` options and returns a configuration carrying the result, which
261
+ * is what the builders write into the entry. The resolved configuration itself is left untouched.
262
+ *
263
+ * When the hook changes the options, the configuration is resolved again with them, so everything read from the env
264
+ * files — the default `dev.url` port above all — matches what the bot will load.
265
+ */
266
+ async function applyEnvOptions(config, hooks) {
267
+ if (!config.env.enabled) return config;
268
+ const options = { ...config.env.options };
269
+ await hooks.callHook("env:options", options, config);
270
+ const source = sources.get(config);
271
+ if (source === void 0 || JSON.stringify(options) === JSON.stringify(config.env.options)) return {
272
+ ...config,
273
+ env: {
274
+ ...config.env,
275
+ options
276
+ }
277
+ };
278
+ return reresolve(config, source, { config: {
279
+ ...source.config,
280
+ env: {
281
+ ...options,
282
+ enabled: true
283
+ }
284
+ } });
285
+ }
286
+ /**
287
+ * With `loader: 'varlock'`, resolves the configuration again with the variables `varlock load` returns, so the
288
+ * defaults `stars.config` derives from the environment — the `dev.url` port — match what the bot loads. Every other
289
+ * configuration is returned as-is: the schema reads its env files directly.
290
+ */
291
+ function withProjectEnv(config) {
292
+ const source = sources.get(config);
293
+ if (source === void 0 || !config.env.enabled || config.env.options.loader !== "varlock") return config;
294
+ return reresolve(config, source, { projectEnv: readProjectEnv(config) });
295
+ }
296
+ function reresolve(previous, source, change) {
297
+ const next = {
298
+ ...source,
299
+ ...change
300
+ };
301
+ const resolved = resolveStarsConfig(next);
302
+ const config = {
303
+ ...resolved,
304
+ runtime: previous.runtime,
305
+ imports: {
306
+ ...resolved.imports,
307
+ presets: previous.imports.presets
308
+ }
309
+ };
310
+ sources.set(config, next);
311
+ return config;
312
+ }
313
+
314
+ //#endregion
315
+ export { modulesPreloadWarning as a, moduleImportArgs as c, readProjectEnv as i, projectArgs as l, loadProject as n, prepareModulesPreload as o, withProjectEnv as r, envImportArgs as s, applyEnvOptions as t, resolveCwd as u };
316
+ //# sourceMappingURL=hooks-BfDFM38k.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-BfDFM38k.js","names":["resolveModule"],"sources":["../src/utils/args.ts","../src/utils/env-import.ts","../src/utils/modules.ts","../src/utils/project-env.ts","../src/utils/hooks.ts"],"sourcesContent":["import type { ArgsDef } from 'citty';\r\nimport { resolve } from 'node:path';\r\n\r\n/**\r\n * Arguments shared by every command that reads the project configuration.\r\n */\r\nexport const projectArgs = {\r\n\tconfig: {\r\n\t\ttype: 'string',\r\n\t\talias: 'c',\r\n\t\tdescription: 'Path to the configuration file (defaults to stars.config.* in the working directory)'\r\n\t},\r\n\tcwd: {\r\n\t\ttype: 'string',\r\n\t\tdescription: 'Working directory to run from (defaults to the current directory)'\r\n\t}\r\n} as const satisfies ArgsDef;\r\n\r\nexport interface ProjectArgs {\r\n\tconfig?: string;\r\n\tcwd?: string;\r\n}\r\n\r\nexport function resolveCwd(args: ProjectArgs): string {\r\n\treturn args.cwd ? resolve(process.cwd(), args.cwd) : process.cwd();\r\n}\r\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { envModuleSource, modulesModuleSource } from '@wolfstar/vite-server/internal';\r\nimport { resolveSync } from 'mlly';\r\nimport { isAbsolute } from 'node:path';\r\nimport { pathToFileURL } from 'node:url';\r\nimport { cliDiagnostics } from './diagnostics.js';\r\nimport { resolveFromProject } from './project.js';\r\n\r\n/** Build tools whose output never passes through the entry transform that registers `env`. */\r\nexport const UNTRANSFORMED_TOOLS = new Set<string>(['none', 'tsc']);\r\n\r\n/**\r\n * `node` arguments that register `env` before the entry runs, for the build tools the entry transform cannot reach.\r\n * The preload is a `data:` URL, so `.stars/` gets no generated runtime file; a `data:` URL cannot resolve bare\r\n * specifiers, so `@wolfstar/env-utilities` is resolved from the project first. When it cannot be resolved nothing is\r\n * preloaded, and the bot's own import of it reports the missing install.\r\n */\r\nexport function envImportArgs(config: ResolvedStarsConfig): string[] {\r\n\tif (!config.env.enabled || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];\r\n\r\n\tconst resolved = resolveFromProject(config.root, '@wolfstar/env-utilities');\r\n\tif (resolved === null) return [];\r\n\r\n\tconst source = envModuleSource(config.env.options, pathToFileURL(resolved).href);\r\n\treturn ['--import', `data:text/javascript,${encodeURIComponent(source)}`];\r\n}\r\n\r\n/**\r\n * `node` arguments that register the runtime plugins of the installed modules (`ctx.addPlugin`) before the entry\r\n * runs, for the build tools the entry transform cannot reach. `@wolfstar/http-framework` and every plugin are resolved\r\n * from the project first, with the `import` condition (both are ESM), because a `data:` URL cannot resolve bare\r\n * specifiers; the framework is the bot's own copy, so `Client.use` reaches the `Client` the bot constructs. When the\r\n * framework is not installed nothing is preloaded, and the bot's own import of it reports the missing install.\r\n */\r\nexport function moduleImportArgs(config: ResolvedStarsConfig): string[] {\r\n\tconst plugins = config.runtime?.plugins ?? [];\r\n\tif (plugins.length === 0 || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];\r\n\r\n\tconst url = pathToFileURL(`${config.root}/package.json`).href;\r\n\tlet framework: string;\r\n\ttry {\r\n\t\tframework = resolveSync('@wolfstar/http-framework', { url });\r\n\t} catch {\r\n\t\treturn [];\r\n\t}\r\n\r\n\tconst source = modulesModuleSource(plugins, {\r\n\t\tframework,\r\n\t\tresolve: (from) => {\r\n\t\t\tif (from.startsWith('file:')) return from;\r\n\t\t\tif (isAbsolute(from)) return pathToFileURL(from).href;\r\n\t\t\ttry {\r\n\t\t\t\treturn resolveSync(from, { url });\r\n\t\t\t} catch {\r\n\t\t\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({\r\n\t\t\t\t\tname: from,\r\n\t\t\t\t\troot: config.root,\r\n\t\t\t\t\thint: 'Install the package of the module that registers this plugin.'\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\treturn ['--import', `data:text/javascript,${encodeURIComponent(source)}`];\r\n}\r\n","import { ModuleError, setupModules } from '@wolfstar/kit';\r\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { envModuleSource, modulesModuleSource } from '@wolfstar/vite-server/internal';\r\nimport { resolve as resolveModule } from 'mlly';\r\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\r\nimport type { Diagnostic } from 'nostics';\r\nimport { isAbsolute, join, resolve } from 'node:path';\r\nimport { pathToFileURL } from 'node:url';\r\nimport { cliDiagnostics } from './diagnostics.js';\r\nimport { UNTRANSFORMED_TOOLS } from './env-import.js';\r\nimport type { StarsHookable } from './hooks.js';\r\nimport { findInstalledVersion } from './project.js';\r\nimport { readOwnPackageJson } from './version.js';\r\n\r\n/**\r\n * Where a module specifier is imported from: a relative or absolute path is a file of the project, a `file:` URL is\r\n * itself, anything else is a package resolved from the project root — with `mlly`, honouring the `import` condition,\r\n * because installed modules are ESM-only packages a CommonJS `require.resolve` cannot see.\r\n */\r\nasync function resolveSpecifier(root: string, specifier: string): Promise<string> {\r\n\tif (specifier.startsWith('file:')) return specifier;\r\n\tif (specifier.startsWith('.') || isAbsolute(specifier)) return pathToFileURL(resolve(root, specifier)).href;\r\n\treturn resolveModule(specifier, { url: pathToFileURL(`${root}/package.json`).href });\r\n}\r\n\r\n/**\r\n * Runs `setup` of every module in `modules` (see `@wolfstar/kit`) and returns the configuration carrying what they\r\n * contributed: `runtime`, and `imports.presets` extended by `ctx.addImports`. Without modules the configuration is\r\n * returned as it is.\r\n */\r\nexport async function installModules(config: ResolvedStarsConfig, hooks: StarsHookable): Promise<ResolvedStarsConfig> {\r\n\tif (config.modules.length === 0) return config;\r\n\r\n\ttry {\r\n\t\tconst runtime = await setupModules({\r\n\t\t\tconfig,\r\n\t\t\thooks,\r\n\t\t\tversions: { framework: findInstalledVersion(config.root, '@wolfstar/http-framework'), stars: readOwnPackageJson().version },\r\n\t\t\tload: async (specifier) => import(await resolveSpecifier(config.root, specifier))\r\n\t\t});\r\n\r\n\t\tconst presets = [...config.imports.presets, ...runtime.imports.filter((preset) => !config.imports.presets.includes(preset))];\r\n\t\treturn { ...config, runtime, imports: { ...config.imports, presets } };\r\n\t} catch (error) {\r\n\t\tif (error instanceof ModuleError) {\r\n\t\t\tthrow cliDiagnostics.MODULE_FAILED({ module: error.moduleName, reason: error.code, message: error.message, cause: error });\r\n\t\t}\r\n\r\n\t\tthrow error;\r\n\t}\r\n}\r\n\r\n/**\r\n * The warning for a project whose runtime plugins reach production only through a `node --import` preload, `null`\r\n * otherwise. It is not one of `config.warnings`: `stars dev` preloads the plugins itself, so there it would be noise\r\n * on every start. `stars build` and `stars prepare` report it.\r\n */\r\nexport function modulesPreloadWarning(config: ResolvedStarsConfig): Diagnostic | null {\r\n\tif (!needsPreload(config)) return null;\r\n\treturn cliDiagnostics.MODULES_PRELOAD_REQUIRED({\r\n\t\ttool: config.build.tool,\r\n\t\tplugins: [...new Set(config.runtime.plugins.map((plugin) => plugin.module))].join(', ')\r\n\t});\r\n}\r\n\r\n/** A build tool the entry transform cannot reach, with runtime plugins to register: they need a `node --import` preload. */\r\nfunction needsPreload(config: ResolvedStarsConfig): boolean {\r\n\treturn UNTRANSFORMED_TOOLS.has(config.build.tool) && (config.runtime?.plugins.length ?? 0) > 0;\r\n}\r\n\r\nexport interface ModulesPreloadResult {\r\n\t/** Absolute path of the preload file. */\r\n\tpath: string;\r\n\tstatus: 'written' | 'up-to-date' | 'outdated';\r\n}\r\n\r\n/**\r\n * Writes `.stars/modules.mjs`, the production counterpart of the preload `stars dev` passes to `node`: `node --import\r\n * ./.stars/modules.mjs <entry>` registers the runtime plugins of the installed modules for the build tools whose entry\r\n * cannot be transformed (`tsc`, `none`). Its specifiers are bare, so they resolve from the project's `node_modules`\r\n * like the bot's own imports. `null` when there is nothing to register.\r\n *\r\n * With `env` enabled it is preceded by `.stars/env.mjs`, a separate module imported first: imports of one module are\r\n * all evaluated before its body runs, so the environment could not be loaded ahead of the plugins from the same file,\r\n * and a plugin reading `process.env` while it is imported would see nothing.\r\n */\r\nexport async function prepareModulesPreload(config: ResolvedStarsConfig, check = false): Promise<ModulesPreloadResult | null> {\r\n\tif (!needsPreload(config)) return null;\r\n\r\n\tconst directory = join(config.root, '.stars');\r\n\tconst path = join(directory, 'modules.mjs');\r\n\tconst withEnv = config.env?.enabled === true;\r\n\t// An absolute path is a `file:` URL in the import, like in `moduleImportArgs`: Node rejects a Windows path there.\r\n\tconst plugins = modulesModuleSource(config.runtime.plugins, { resolve: (from) => (isAbsolute(from) ? pathToFileURL(from).href : from) });\r\n\tconst files = [\r\n\t\t{ path, content: withEnv ? `import \"./env.mjs\";\\n${plugins}` : plugins },\r\n\t\t...(withEnv ? [{ path: join(directory, 'env.mjs'), content: envModuleSource(config.env.options) }] : [])\r\n\t];\r\n\r\n\tif (check) {\r\n\t\tconst current = await Promise.all(files.map(async (file) => (await readFile(file.path, 'utf-8').catch(() => null)) === file.content));\r\n\t\treturn { path, status: current.every(Boolean) ? 'up-to-date' : 'outdated' };\r\n\t}\r\n\r\n\tawait mkdir(directory, { recursive: true });\r\n\tawait Promise.all(files.map((file) => writeFile(file.path, file.content)));\r\n\treturn { path, status: 'written' };\r\n}\r\n","import { readProjectEnvFiles, type ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { execFileSync } from 'node:child_process';\r\nimport { resolveBinary } from './project.js';\r\n\r\n/**\r\n * The variables the bot will load, for the CLI's own lookups (Discord credentials for the tunnel). With the default\r\n * loader these are the project's env files, read from `env.path`/`env.env`. With `loader: 'varlock'` they are what\r\n * `varlock load` resolves from the project's `.env.schema` — a dotenv file may be stale or absent there — and nothing\r\n * when varlock cannot be run, rather than values the bot never sees.\r\n */\r\nexport function readProjectEnv(config: ResolvedStarsConfig): Record<string, string> {\r\n\tconst { path, env = 'development', loader } = config.env.options;\r\n\tif (loader !== 'varlock') return readProjectEnvFiles(config.root, env, { path });\r\n\r\n\tconst binary = resolveBinary(config.root, 'varlock', 'varlock');\r\n\tif (binary === null) return {};\r\n\r\n\ttry {\r\n\t\t// The way the bot loads it: `@wolfstar/env-utilities` runs `varlock/auto-load` with no `--env` (it ignores\r\n\t\t// `env.env` with varlock), in the environment `stars dev` gives the bot.\r\n\t\tconst output = execFileSync(process.execPath, [binary, 'load', '--format', 'json'], {\r\n\t\t\tcwd: config.root,\r\n\t\t\t// Same order as `createSupervisor`: `NODE_ENV` is forced to development after `dev.env`, so it can't differ.\r\n\t\t\tenv: { ...process.env, ...config.dev.env, NODE_ENV: 'development' },\r\n\t\t\tencoding: 'utf8',\r\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\r\n\t\t\ttimeout: 30_000\r\n\t\t});\r\n\t\tconst values = JSON.parse(output) as Record<string, unknown>;\r\n\t\treturn Object.fromEntries(\r\n\t\t\tObject.entries(values)\r\n\t\t\t\t.filter(([, value]) => value !== undefined && value !== null)\r\n\t\t\t\t.map(([key, value]) => [key, String(value)])\r\n\t\t);\r\n\t} catch {\r\n\t\treturn {};\r\n\t}\r\n}\r\n","import {\r\n\tloadConfigFile,\r\n\tresolveStarsConfig,\r\n\ttype LoadStarsConfigOptions,\r\n\ttype ResolveConfigOptions,\r\n\ttype ResolvedStarsConfig,\r\n\ttype StarsHookName,\r\n\ttype StarsHooks\r\n} from '@wolfstar/schema';\r\nimport { createHooks, type Hookable } from 'hookable';\r\nimport { installModules } from './modules.js';\r\nimport { readProjectEnv } from './project-env.js';\r\n\r\nexport type StarsHookable = Hookable<StarsHooks>;\r\n\r\n/** What each configuration loaded by {@link loadProject} was resolved from, so `env:options` can re-resolve it. */\r\nconst sources = new WeakMap<ResolvedStarsConfig, ResolveConfigOptions>();\r\n\r\n/** Registers the `hooks` of `stars.config` on a fresh `hookable` instance. */\r\nexport function createStarsHooks(config: ResolvedStarsConfig): StarsHookable {\r\n\tconst hooks = createHooks<StarsHooks>();\r\n\tfor (const [name, callbacks] of Object.entries(config.hooks) as [StarsHookName, readonly StarsHooks[StarsHookName][]][]) {\r\n\t\tfor (const callback of callbacks) hooks.hook(name, callback);\r\n\t}\r\n\r\n\treturn hooks;\r\n}\r\n\r\n/** Loads `stars.config`, registers its hooks and runs `config:resolved`. */\r\nexport async function loadProject(options: LoadStarsConfigOptions): Promise<{ config: ResolvedStarsConfig; hooks: StarsHookable }> {\r\n\tconst cwd = options.cwd ?? process.cwd();\r\n\tconst loaded = await loadConfigFile({ cwd, configFile: options.configFile });\r\n\tconst source: ResolveConfigOptions = { cwd, configFile: loaded.configFile, config: loaded.config, env: options.env };\r\n\tconst resolved = resolveStarsConfig(source);\r\n\tconst hooks = createStarsHooks(resolved);\r\n\t// Modules install before `config:resolved`, so that hook already sees what they contributed.\r\n\tconst config = await installModules(resolved, hooks);\r\n\tsources.set(config, source);\r\n\r\n\tawait hooks.callHook('config:resolved', config);\r\n\treturn { config, hooks };\r\n}\r\n\r\n/**\r\n * Runs `env:options` on a copy of the resolved `env` options and returns a configuration carrying the result, which\r\n * is what the builders write into the entry. The resolved configuration itself is left untouched.\r\n *\r\n * When the hook changes the options, the configuration is resolved again with them, so everything read from the env\r\n * files — the default `dev.url` port above all — matches what the bot will load.\r\n */\r\nexport async function applyEnvOptions(config: ResolvedStarsConfig, hooks: StarsHookable): Promise<ResolvedStarsConfig> {\r\n\tif (!config.env.enabled) return config;\r\n\r\n\tconst options = { ...config.env.options };\r\n\tawait hooks.callHook('env:options', options, config);\r\n\r\n\tconst source = sources.get(config);\r\n\tif (source === undefined || JSON.stringify(options) === JSON.stringify(config.env.options)) {\r\n\t\treturn { ...config, env: { ...config.env, options } };\r\n\t}\r\n\r\n\treturn reresolve(config, source, { config: { ...source.config, env: { ...options, enabled: true } } });\r\n}\r\n\r\n/**\r\n * With `loader: 'varlock'`, resolves the configuration again with the variables `varlock load` returns, so the\r\n * defaults `stars.config` derives from the environment — the `dev.url` port — match what the bot loads. Every other\r\n * configuration is returned as-is: the schema reads its env files directly.\r\n */\r\nexport function withProjectEnv(config: ResolvedStarsConfig): ResolvedStarsConfig {\r\n\tconst source = sources.get(config);\r\n\tif (source === undefined || !config.env.enabled || config.env.options.loader !== 'varlock') return config;\r\n\treturn reresolve(config, source, { projectEnv: readProjectEnv(config) });\r\n}\r\n\r\nfunction reresolve(previous: ResolvedStarsConfig, source: ResolveConfigOptions, change: Partial<ResolveConfigOptions>): ResolvedStarsConfig {\r\n\tconst next = { ...source, ...change };\r\n\tconst resolved = resolveStarsConfig(next);\r\n\t// Modules ran once, against the first resolution: what they contributed carries over to the new one.\r\n\tconst config = { ...resolved, runtime: previous.runtime, imports: { ...resolved.imports, presets: previous.imports.presets } };\r\n\tsources.set(config, next);\r\n\treturn config;\r\n}\r\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -101,6 +101,28 @@ export declare const cliDiagnostics: import("nostics").Diagnostics<{
101
101
  hint: string;
102
102
  }) => string;
103
103
  };
104
+ readonly MODULE_FAILED: {
105
+ why: (p: {
106
+ module: string;
107
+ reason: string;
108
+ message: string;
109
+ }) => string;
110
+ fix: (p: {
111
+ module: string;
112
+ reason: string;
113
+ message: string;
114
+ }) => string;
115
+ };
116
+ readonly MODULES_PRELOAD_REQUIRED: {
117
+ why: (p: {
118
+ tool: string;
119
+ plugins: string;
120
+ }) => string;
121
+ fix: (_p: {
122
+ tool: string;
123
+ plugins: string;
124
+ }) => string;
125
+ };
104
126
  readonly CODEGEN_FAILED: {
105
127
  why: (p: {
106
128
  code: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/run.ts","../src/utils/errors.ts","../src/utils/diagnostics.ts","../src/utils/output-mode.ts","../src/utils/theme.ts"],"mappings":";;wBA8BsB,QAAQ,kBAAyC;;;qBCxB1D;WACZ;WACA;WACA;WACA;WACA;WACA;;YAGW,mBAAmB,uBAAuB;;;;;;wBAehC,YAAY,iBAAiB;wBAuBnC,WAAW,iBAAiB;;;;;;;;;;;;;;;;qBCtC/B,kCAAc;;IAKxB,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;MAAQ;MAAgB;;IAC3B,MAAG;MAAQ;MAAgB;;;;IAI3B,MAAG;MAAQ;;;;IAGX,MAAG;MAAQ;;IACX,MAAG;MAAS;;;;IAGZ,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;MAAQ;MAAe;;IAC1B,MAAG;MAAQ;MAAe;;;;IAG1B,MAAG;;;IAGH,MAAG;MAAQ;MAAc;MAAc;;IACvC,MAAG;MAAQ;MAAc;MAAc;;;;IAGvC,MAAG;MAAQ;MAAqB;;;;KAKvB,iCAAiC;;;KClEjC;UAEK;;EAEhB;EACA,MAAM,OAAO;;EAEb;;EAEA;EACA;EACA;;EAEA;;;;;;;wBAUe,kBAAkB,UAAS,2BAAgC;wBAkB3D,gBAAgB,MAAK,OAAO;;;;wBAU5B,eAAe,MAAK,OAAO,YAA0B;;;;wBASrD,qBAAqB,MAAK,OAAO;;;;qBCvDpC;KACD,uBAAuB;KACvB,YAAY,QAAQ;;;;;UAMf;;EAEhB;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;KAGW,mBAAmB;qBAElB,QAAQ,SAAS,OAAO,WAAW;wBA4FhC,aAAa,SAAS,cAAc,MAAK,OAAO,aAA2B;UAI1E;;EAEhB;EACA,MAAM,OAAO;;EAEb,QAAQ;;;;;;wBAOO,sBAAsB,MAAM,KAAmB,SAAS,sBAAsB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/run.ts","../src/utils/errors.ts","../src/utils/diagnostics.ts","../src/utils/output-mode.ts","../src/utils/theme.ts"],"mappings":";;wBA8BsB,QAAQ,kBAAyC;;;qBCxB1D;WACZ;WACA;WACA;WACA;WACA;WACA;;YAGW,mBAAmB,uBAAuB;;;;;;wBAgBhC,YAAY,iBAAiB;wBAuBnC,WAAW,iBAAiB;;;;;;;;;;;;;;;;qBCvC/B,kCAAc;;IAKxB,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;MAAQ;MAAgB;;IAC3B,MAAG;MAAQ;MAAgB;;;;IAI3B,MAAG;MAAQ;;;;IAGX,MAAG;MAAQ;;IACX,MAAG;MAAS;;;;IAGZ,MAAG;;;IAGH,MAAG;IACH,MAAG;;;IAGH,MAAG;MAAQ;MAAe;;IAC1B,MAAG;MAAQ;MAAe;;;;IAG1B,MAAG;;;IAGH,MAAG;MAAQ;MAAc;MAAc;;IACvC,MAAG;MAAQ;MAAc;MAAc;;;;IAGvC,MAAG;MAAQ;MAAgB;MAAgB;;IAC3C,MAAG;MAAQ;MAAgB;MAAgB;;;;IAgB3C,MAAG;MAAQ;MAAc;;IAEzB,MAAG;MAAS;MAAc;;;;IAI1B,MAAG;MAAQ;MAAqB;;;;KAKvB,iCAAiC;;;KCzFjC;UAEK;;EAEhB;EACA,MAAM,OAAO;;EAEb;;EAEA;EACA;EACA;;EAEA;;;;;;;wBAUe,kBAAkB,UAAS,2BAAgC;wBAkB3D,gBAAgB,MAAK,OAAO;;;;wBAU5B,eAAe,MAAK,OAAO,YAA0B;;;;wBASrD,qBAAqB,MAAK,OAAO;;;;qBCvDpC;KACD,uBAAuB;KACvB,YAAY,QAAQ;;;;;UAMf;;EAEhB;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;KAGW,mBAAmB;qBAElB,QAAQ,SAAS,OAAO,WAAW;wBA4FhC,aAAa,SAAS,cAAc,MAAK,OAAO,aAA2B;UAI1E;;EAEhB;EACA,MAAM,OAAO;;EAEb,QAAQ;;;;;;wBAOO,sBAAsB,MAAM,KAAmB,SAAS,sBAAsB"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { t as runMain } from "./run-Ddwrxe1O.js";
1
+ import { t as runMain } from "./run-BiLZqib3.js";
2
2
  import { i as shouldUseColor, n as prefersReducedMotion, r as resolveOutputMode, t as isCIEnvironment } from "./output-mode-Bp7Da8vJ.js";
3
- import { n as exitCodeOf, r as formatError, t as ExitCode } from "./errors-Crt4hu0b.js";
4
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
3
+ import { n as exitCodeOf, r as formatError, t as ExitCode } from "./errors-COFWKKKw.js";
4
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.js";
5
5
  import { n as THEME_SETTINGS, o as resolveTheme, s as resolveThemeSetting, t as THEMES } from "./theme-3Fc_LI-2.js";
6
6
  import { configDiagnostics, loadStarsConfig } from "@wolfstar/schema";
7
7
 
@@ -1,7 +1,7 @@
1
1
  import { t as readOwnPackageJson } from "./version-BzclCE19.js";
2
2
  import { i as shouldUseColor, r as resolveOutputMode } from "./output-mode-Bp7Da8vJ.js";
3
- import { t as findInstalledVersion } from "./project-MD4dIo2X.js";
4
- import { a as projectArgs, n as loadProject, o as resolveCwd, t as applyEnvOptions } from "./hooks-H9kjLCMk.js";
3
+ import { t as findInstalledVersion } from "./project-D-8VIcyF.js";
4
+ import { a as modulesPreloadWarning, l as projectArgs, n as loadProject, t as applyEnvOptions, u as resolveCwd } from "./hooks-BfDFM38k.js";
5
5
  import { defineCommand } from "citty";
6
6
  import { relative } from "node:path";
7
7
  import { displayPath } from "@wolfstar/schema";
@@ -34,7 +34,7 @@ function collectInfo(config) {
34
34
  future: config.future,
35
35
  env: config.env,
36
36
  hooks: Object.keys(config.hooks),
37
- warnings: config.warnings.map((warning) => `${warning.code}: ${warning.message}`),
37
+ warnings: [...config.warnings, modulesPreloadWarning(config)].filter((warning) => warning !== null).map((warning) => `${warning.code}: ${warning.message}`),
38
38
  options: {
39
39
  tsdown: Object.keys(config.tsdown),
40
40
  vite: Object.keys(config.vite)
@@ -148,4 +148,4 @@ var info_default = defineCommand({
148
148
 
149
149
  //#endregion
150
150
  export { info_default as default };
151
- //# sourceMappingURL=info-CdiQajgn.js.map
151
+ //# sourceMappingURL=info-C1Kx_4Og.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info-C1Kx_4Og.js","names":[],"sources":["../src/commands/info.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig, type StarsEnvSetupOptions } from '@wolfstar/schema';\r\nimport { defineCommand } from 'citty';\r\nimport { createColors } from 'colorette';\r\nimport { arch, platform } from 'node:os';\r\nimport { relative } from 'node:path';\r\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\r\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\r\nimport { modulesPreloadWarning } from '../utils/modules.js';\r\nimport { resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\r\nimport { findInstalledVersion } from '../utils/project.js';\r\nimport { readOwnPackageJson } from '../utils/version.js';\r\n\r\nexport interface InfoOptions extends ProjectArgs {\r\n\tjson?: boolean;\r\n\tstdout?: NodeJS.WritableStream;\r\n}\r\n\r\nexport interface ProjectInfo {\r\n\tcli: { version: string; node: string; platform: string; outputMode: 'tui' | 'plain' };\r\n\tproject: {\r\n\t\tcwd: string;\r\n\t\troot: string;\r\n\t\tconfigFile: string | null;\r\n\t\tname: string | null;\r\n\t\tversion: string | null;\r\n\t\tentry: string;\r\n\t\tframeworkVersion: string | null;\r\n\t};\r\n\tbuild: ResolvedStarsConfig['build'];\r\n\tdev: ResolvedStarsConfig['dev'];\r\n\tcodegen: ResolvedStarsConfig['codegen'];\r\n\timports: ResolvedStarsConfig['imports'];\r\n\texperimental: ResolvedStarsConfig['experimental'];\r\n\tfuture: ResolvedStarsConfig['future'];\r\n\tenv: ResolvedStarsConfig['env'];\r\n\t/** The names of the hooks registered in `stars.config`, flattened (`build:done`). */\r\n\thooks: string[];\r\n\t/** Non-fatal configuration diagnostics, as `CODE: message`. */\r\n\twarnings: string[];\r\n\t/**\r\n\t * The option names set in the `tsdown`/`vite` blocks. Only the names: the values hold plugins and callbacks,\r\n\t * which neither serialize to JSON nor read usefully on a terminal.\r\n\t */\r\n\toptions: { tsdown: string[]; vite: string[] };\r\n}\r\n\r\nexport function collectInfo(config: ResolvedStarsConfig): ProjectInfo {\r\n\treturn {\r\n\t\tcli: {\r\n\t\t\tversion: readOwnPackageJson().version,\r\n\t\t\tnode: process.version,\r\n\t\t\tplatform: `${platform()} ${arch()}`,\r\n\t\t\toutputMode: resolveOutputMode()\r\n\t\t},\r\n\t\tproject: {\r\n\t\t\tcwd: config.cwd,\r\n\t\t\troot: config.root,\r\n\t\t\tconfigFile: config.configFile,\r\n\t\t\tname: config.packageJson?.name ?? null,\r\n\t\t\tversion: config.packageJson?.version ?? null,\r\n\t\t\tentry: config.entry,\r\n\t\t\tframeworkVersion: findInstalledVersion(config.root, '@wolfstar/http-framework')\r\n\t\t},\r\n\t\tbuild: config.build,\r\n\t\tdev: config.dev,\r\n\t\tcodegen: config.codegen,\r\n\t\timports: config.imports,\r\n\t\texperimental: config.experimental,\r\n\t\tfuture: config.future,\r\n\t\tenv: config.env,\r\n\t\thooks: Object.keys(config.hooks),\r\n\t\twarnings: [...config.warnings, modulesPreloadWarning(config)]\r\n\t\t\t.filter((warning) => warning !== null)\r\n\t\t\t.map((warning) => `${warning.code}: ${warning.message}`),\r\n\t\toptions: { tsdown: Object.keys(config.tsdown), vite: Object.keys(config.vite) }\r\n\t};\r\n}\r\n\r\nexport function formatInfo(info: ProjectInfo, useColor: boolean): string {\r\n\tconst colors = createColors({ useColor });\r\n\tconst { root } = info.project;\r\n\tconst show = (path: string | null) => (path === null ? colors.dim('none') : displayPath(root, path));\r\n\tconst row = (label: string, value: string) => ` ${colors.dim(label.padEnd(12))}${value}`;\r\n\tconst section = (title: string, rows: string[]) => [colors.bold(title), ...rows].join('\\n');\r\n\r\n\treturn [\r\n\t\tsection(`stars ${colors.green(`v${info.cli.version}`)}`, [\r\n\t\t\trow('node', info.cli.node),\r\n\t\t\trow('platform', info.cli.platform),\r\n\t\t\trow('output', info.cli.outputMode),\r\n\t\t\trow(\r\n\t\t\t\t'framework',\r\n\t\t\t\tinfo.project.frameworkVersion\r\n\t\t\t\t\t? `@wolfstar/http-framework v${info.project.frameworkVersion}`\r\n\t\t\t\t\t: colors.yellow('@wolfstar/http-framework not installed')\r\n\t\t\t)\r\n\t\t]),\r\n\t\tsection('Project', [\r\n\t\t\trow(\r\n\t\t\t\t'name',\r\n\t\t\t\tinfo.project.name\r\n\t\t\t\t\t? `${info.project.name}${info.project.version ? colors.dim(` v${info.project.version}`) : ''}`\r\n\t\t\t\t\t: colors.dim('unnamed')\r\n\t\t\t),\r\n\t\t\trow('root', root),\r\n\t\t\trow(\r\n\t\t\t\t'config',\r\n\t\t\t\tinfo.project.configFile ? relative(root, info.project.configFile) || info.project.configFile : colors.dim('none (defaults)')\r\n\t\t\t),\r\n\t\t\trow('entry', show(info.project.entry))\r\n\t\t]),\r\n\t\tsection('Build', [\r\n\t\t\trow('tool', info.build.tool),\r\n\t\t\t// Which file the build tool is configured from: its own, or this project's `stars.config`.\r\n\t\t\trow('config', info.build.configFile ? show(info.build.configFile) : colors.dim('stars.config')),\r\n\t\t\trow('options', describeOptions(info, colors)),\r\n\t\t\trow('outDir', show(info.build.outDir)),\r\n\t\t\trow('tsconfig', show(info.build.tsconfig)),\r\n\t\t\trow('runs', show(info.build.output))\r\n\t\t]),\r\n\t\tsection('Dev', [\r\n\t\t\trow('watch', info.dev.watch.map(show).join(', ')),\r\n\t\t\trow('debounce', `${info.dev.debounce}ms`),\r\n\t\t\trow('node args', info.dev.nodeArgs.join(' ') || colors.dim('none')),\r\n\t\t\trow('args', info.dev.args.join(' ') || colors.dim('none')),\r\n\t\t\trow('url', info.dev.url ?? colors.dim('unknown, set dev.url or HTTP_PORT')),\r\n\t\t\trow('health', info.dev.health ?? colors.dim('none')),\r\n\t\t\trow(\r\n\t\t\t\t'typecheck',\r\n\t\t\t\tinfo.dev.typecheck.enabled ? `${info.dev.typecheck.checker} → ${show(info.dev.typecheck.tsconfig)}` : colors.dim('disabled')\r\n\t\t\t),\r\n\t\t\trow('tunnel', describeTunnel(info.dev.tunnel, colors)),\r\n\t\t\trow('log file', info.dev.logFile ? show(info.dev.logFile) : colors.dim('disabled'))\r\n\t\t]),\r\n\t\tsection('Codegen', [\r\n\t\t\trow('i18n', info.codegen.i18n ? `${show(info.codegen.i18n.locales)} → ${show(info.codegen.i18n.output)}` : colors.dim('disabled'))\r\n\t\t]),\r\n\t\tsection('Future', [\r\n\t\t\trow('compat', `v${info.future.compatibilityVersion} defaults`),\r\n\t\t\t...info.warnings.map((warning) => row('warning', colors.yellow(warning)))\r\n\t\t]),\r\n\t\tsection('Env', [row('register', info.env.enabled ? colors.green(describeEnvOptions(info.env.options)) : colors.dim('disabled'))]),\r\n\t\tsection('Hooks', [row('registered', info.hooks.join(', ') || colors.dim('none'))]),\r\n\t\tsection('Experimental', [\r\n\t\t\trow('vite', flag(info.experimental.enableVite, colors)),\r\n\t\t\trow('nitro', flag(info.experimental.enableNitro, colors)),\r\n\t\t\t...(info.experimental.enableNitro ? [row('nitro preset', info.experimental.nitro.preset)] : []),\r\n\t\t\trow('external', flag(info.experimental.enableExternalVite, colors))\r\n\t\t]),\r\n\t\tsection('Imports', [\r\n\t\t\trow('auto', info.imports.enabled ? colors.green('enabled') : colors.dim('disabled')),\r\n\t\t\trow('dirs', info.imports.dirs.map(show).join(', ')),\r\n\t\t\trow('presets', info.imports.presets.join(', ') || colors.dim('none')),\r\n\t\t\trow('dts', show(info.imports.dts))\r\n\t\t])\r\n\t].join('\\n\\n');\r\n}\r\n\r\nfunction describeOptions(info: ProjectInfo, colors: ReturnType<typeof createColors>): string {\r\n\tconst names = info.build.tool === 'vite' ? info.options.vite : info.options.tsdown;\r\n\treturn names.length > 0 ? names.join(', ') : colors.dim('none');\r\n}\r\n\r\nfunction describeEnvOptions(options: Readonly<StarsEnvSetupOptions>): string {\r\n\tconst entries = Object.entries(options).map(([key, value]) => `${key} ${String(value)}`);\r\n\treturn entries.length > 0 ? `enabled (${entries.join(', ')})` : 'enabled';\r\n}\r\n\r\nfunction flag(enabled: boolean, colors: ReturnType<typeof createColors>): string {\r\n\treturn enabled ? colors.green('enabled') : colors.dim('disabled');\r\n}\r\n\r\nfunction describeTunnel(tunnel: ResolvedStarsConfig['dev']['tunnel'], colors: ReturnType<typeof createColors>): string {\r\n\tswitch (tunnel.mode) {\r\n\t\tcase 'quick':\r\n\t\t\treturn 'cloudflared quick tunnel';\r\n\t\tcase 'url':\r\n\t\t\treturn tunnel.url;\r\n\t\tdefault:\r\n\t\t\treturn colors.dim('disabled');\r\n\t}\r\n}\r\n\r\nexport async function runInfo(options: InfoOptions): Promise<void> {\r\n\tconst stdout = options.stdout ?? process.stdout;\r\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\r\n\t// What the build would use: `env:options` may change the env files.\r\n\tconst config = await applyEnvOptions(project.config, project.hooks);\r\n\tconst info = collectInfo(config);\r\n\tstdout.write(`${options.json ? JSON.stringify(info, null, 2) : formatInfo(info, shouldUseColor())}\\n`);\r\n}\r\n\r\nexport default defineCommand({\r\n\tmeta: {\r\n\t\tname: 'info',\r\n\t\tdescription: 'Print the resolved project configuration and environment'\r\n\t},\r\n\targs: {\r\n\t\t...projectArgs,\r\n\t\tjson: {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdescription: 'Print machine-readable JSON',\r\n\t\t\tdefault: false\r\n\t\t}\r\n\t},\r\n\tasync run({ args }) {\r\n\t\tawait runInfo({ config: args.config, cwd: args.cwd, json: args.json });\r\n\t}\r\n});\r\n"],"mappings":"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"}
@@ -12,20 +12,20 @@ async function createBuilder(config, hooks) {
12
12
  return new ExternalBuilder(config);
13
13
  }
14
14
  if (config.experimental.enableNitro) {
15
- const { NitroBuilder } = await import("./nitro-sP2F3SQu.js");
15
+ const { NitroBuilder } = await import("./nitro-yjqZBh5L.js");
16
16
  return new NitroBuilder(config);
17
17
  }
18
18
  switch (config.build.tool) {
19
19
  case "tsdown": {
20
- const { TsdownBuilder } = await import("./tsdown-CD68G8_U.js");
20
+ const { TsdownBuilder } = await import("./tsdown-DrWXld54.js");
21
21
  return new TsdownBuilder(config, hooks);
22
22
  }
23
23
  case "vite": {
24
- const { ViteBuilder } = await import("./vite-CLyB6wl7.js");
24
+ const { ViteBuilder } = await import("./vite-Bf7nrJx7.js");
25
25
  return new ViteBuilder(config);
26
26
  }
27
27
  case "tsc": {
28
- const { TscBuilder } = await import("./tsc-YnAWKn3n.js");
28
+ const { TscBuilder } = await import("./tsc-B931Ezh7.js");
29
29
  return new TscBuilder(config);
30
30
  }
31
31
  case "none": {
@@ -94,4 +94,4 @@ var Locales = class extends EventEmitter {
94
94
 
95
95
  //#endregion
96
96
  export { createBuilder as n, Locales as t };
97
- //# sourceMappingURL=locales-C7X8VNmK.js.map
97
+ //# sourceMappingURL=locales-BzOLRBVg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locales-BzOLRBVg.js","names":[],"sources":["../src/builders/index.ts","../src/utils/locales.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport type { StarsHookable } from '../utils/hooks.js';\r\nimport type { Builder } from './types.js';\r\n\r\n/**\r\n * Creates the builder for `build.tool`. `hooks` reach the builders that expose hooks of their own (`tsdown:options`).\r\n */\r\nexport async function createBuilder(config: ResolvedStarsConfig, hooks?: StarsHookable): Promise<Builder> {\r\n\t// The project runs its own build, so the CLI only watches what it writes (see `ExternalBuilder`) — including when\r\n\t// it is driving `vite build` with its own `nitro()` plugin itself; `build.output` already points at Nitro's\r\n\t// `server/index.mjs` in that case (see `resolveBuild`).\r\n\tif (config.experimental.enableExternalVite) {\r\n\t\tconst { ExternalBuilder } = await import('./external.js');\r\n\t\treturn new ExternalBuilder(config);\r\n\t}\r\n\r\n\t// Nitro is itself a Vite plugin — there is no separate `nitro build` step — so it is handled before the\r\n\t// `build.tool` switch below, the same way `enableExternalVite` is.\r\n\tif (config.experimental.enableNitro) {\r\n\t\tconst { NitroBuilder } = await import('./nitro.js');\r\n\t\treturn new NitroBuilder(config);\r\n\t}\r\n\r\n\tswitch (config.build.tool) {\r\n\t\tcase 'tsdown': {\r\n\t\t\tconst { TsdownBuilder } = await import('./tsdown.js');\r\n\t\t\treturn new TsdownBuilder(config, hooks);\r\n\t\t}\r\n\t\tcase 'vite': {\r\n\t\t\tconst { ViteBuilder } = await import('./vite.js');\r\n\t\t\treturn new ViteBuilder(config);\r\n\t\t}\r\n\t\tcase 'tsc': {\r\n\t\t\tconst { TscBuilder } = await import('./tsc.js');\r\n\t\t\treturn new TscBuilder(config);\r\n\t\t}\r\n\t\tcase 'none': {\r\n\t\t\tconst { NoneBuilder } = await import('./none.js');\r\n\t\t\treturn new NoneBuilder(config);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\r\n","import { EventEmitter } from 'node:events';\r\nimport { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';\r\nimport { dirname, join, relative } from 'node:path';\r\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport type { LogLevel } from './log-buffer.js';\r\n\r\nexport interface LocalesEvents {\r\n\tchange: [];\r\n\tlog: [level: LogLevel, text: string];\r\n}\r\n\r\n/** Keeps the conventional `src/locales` data directory next to the compiled application. */\r\nexport class Locales extends EventEmitter<LocalesEvents> {\r\n\treadonly source: string;\r\n\treadonly destination: string;\r\n\t#watcher: { close(): Promise<void> } | null = null;\r\n\r\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\r\n\t\tsuper();\r\n\t\tthis.source = join(config.root, 'src', 'locales');\r\n\t\tthis.destination = join(config.build.outDir, 'locales');\r\n\t}\r\n\r\n\tpublic copy(): boolean {\r\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source)) return false;\r\n\t\tmkdirSync(this.destination, { recursive: true });\r\n\t\tcpSync(this.source, this.destination, { recursive: true, force: true });\r\n\t\treturn true;\r\n\t}\r\n\r\n\tpublic async watch(): Promise<void> {\r\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source) || this.#watcher) return;\r\n\t\tconst { watch } = await import('chokidar');\r\n\t\tconst watcher = watch(this.source, { ignoreInitial: true });\r\n\t\tthis.#watcher = watcher;\r\n\r\n\t\twatcher.on('all', (event, path) => {\r\n\t\t\ttry {\r\n\t\t\t\tconst target = join(this.destination, relative(this.source, path));\r\n\t\t\t\tif (event === 'unlink' || event === 'unlinkDir') rmSync(target, { recursive: event === 'unlinkDir', force: true });\r\n\t\t\t\telse if (existsSync(path)) {\r\n\t\t\t\t\tmkdirSync(dirname(target), { recursive: true });\r\n\t\t\t\t\tcpSync(path, target, { recursive: event === 'addDir', force: true });\r\n\t\t\t\t}\r\n\t\t\t\tthis.emit('change');\r\n\t\t\t} catch (error) {\r\n\t\t\t\tthis.emit('log', 'error', `Failed to copy locales: ${error instanceof Error ? error.message : String(error)}`);\r\n\t\t\t}\r\n\t\t});\r\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\r\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\r\n\t}\r\n\r\n\tpublic async close(): Promise<void> {\r\n\t\tconst watcher = this.#watcher;\r\n\t\tthis.#watcher = null;\r\n\t\tawait watcher?.close();\r\n\t}\r\n}\r\n"],"mappings":";;;;;;;;AAOA,eAAsB,cAAc,QAA6B,OAAyC;CAIzG,IAAI,OAAO,aAAa,oBAAoB;EAC3C,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,OAAO,IAAI,gBAAgB,MAAM;CAClC;CAIA,IAAI,OAAO,aAAa,aAAa;EACpC,MAAM,EAAE,iBAAiB,MAAM,OAAO;EACtC,OAAO,IAAI,aAAa,MAAM;CAC/B;CAEA,QAAQ,OAAO,MAAM,MAArB;EACC,KAAK,UAAU;GACd,MAAM,EAAE,kBAAkB,MAAM,OAAO;GACvC,OAAO,IAAI,cAAc,QAAQ,KAAK;EACvC;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;EACA,KAAK,OAAO;GACX,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,OAAO,IAAI,WAAW,MAAM;EAC7B;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;CACD;AACD;;;;;AC7BA,IAAa,UAAb,cAA6B,aAA4B;CAKpB;CAJpC,AAAS;CACT,AAAS;CACT,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;EAEnC,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,SAAS;EAChD,KAAK,cAAc,KAAK,OAAO,MAAM,QAAQ,SAAS;CACvD;CAEA,AAAO,OAAgB;EACtB,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,GAAG,OAAO;EAC1E,UAAU,KAAK,aAAa,EAAE,WAAW,KAAK,CAAC;EAC/C,OAAO,KAAK,QAAQ,KAAK,aAAa;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACtE,OAAO;CACR;CAEA,MAAa,QAAuB;EACnC,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,KAAK,KAAK,UAAU;EACpF,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,KAAK,QAAQ,EAAE,eAAe,KAAK,CAAC;EAC1D,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,IAAI;IACH,MAAM,SAAS,KAAK,KAAK,aAAa,SAAS,KAAK,QAAQ,IAAI,CAAC;IACjE,IAAI,UAAU,YAAY,UAAU,aAAa,OAAO,QAAQ;KAAE,WAAW,UAAU;KAAa,OAAO;IAAK,CAAC;SAC5G,IAAI,WAAW,IAAI,GAAG;KAC1B,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;KAC9C,OAAO,MAAM,QAAQ;MAAE,WAAW,UAAU;MAAU,OAAO;KAAK,CAAC;IACpE;IACA,KAAK,KAAK,QAAQ;GACnB,SAAS,OAAO;IACf,KAAK,KAAK,OAAO,SAAS,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GAC9G;EACD,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAChH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;CACpE;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"log-buffer-CY82aqnb.js","names":[],"sources":["../src/utils/log-buffer.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { stripVTControlCharacters } from 'node:util';\n\nexport type LogSource = 'stars' | 'build' | 'app' | 'tsc' | 'tunnel';\nexport type LogLevel = import('@wolfstar/schema').BuilderLogLevel;\n\nexport interface LogEntry {\n\treadonly id: number;\n\treadonly time: number;\n\treadonly source: LogSource;\n\treadonly level: LogLevel;\n\treadonly text: string;\n}\n\nexport interface LogFilter {\n\tsource?: LogSource | null;\n\tlevel?: LogLevel | null;\n\tquery?: string | null;\n}\n\nexport type LogInput = Omit<LogEntry, 'id' | 'time'>;\n\n/**\n * A bounded, in-memory log store shared by the dev service and its renderers.\n */\nexport class LogBuffer extends EventEmitter<{ entry: [LogEntry]; clear: [] }> {\n\t#entries: LogEntry[] = [];\n\t#nextId = 1;\n\n\tpublic constructor(public readonly capacity = 2000) {\n\t\tsuper();\n\t}\n\n\tpublic push(input: LogInput): LogEntry {\n\t\tconst entry: LogEntry = { id: this.#nextId++, time: Date.now(), ...input };\n\t\tthis.#entries.push(entry);\n\t\tif (this.#entries.length > this.capacity) this.#entries.splice(0, this.#entries.length - this.capacity);\n\t\tthis.emit('entry', entry);\n\t\treturn entry;\n\t}\n\n\tpublic entries(): readonly LogEntry[] {\n\t\treturn this.#entries;\n\t}\n\n\tpublic filter(filter: LogFilter): LogEntry[] {\n\t\tconst query = filter.query?.toLowerCase() ?? null;\n\t\treturn this.#entries.filter(\n\t\t\t(entry) =>\n\t\t\t\t(!filter.source || entry.source === filter.source) &&\n\t\t\t\t(!filter.level || matchesLevel(entry.level, filter.level)) &&\n\t\t\t\t(!query || entry.text.toLowerCase().includes(query))\n\t\t);\n\t}\n\n\tpublic clear(): void {\n\t\tthis.#entries = [];\n\t\tthis.emit('clear');\n\t}\n}\n\nconst LEVEL_ORDER: Record<LogLevel, number> = { debug: 0, info: 1, success: 1, warn: 2, error: 3 };\n\n/**\n * Whether `level` is at least as severe as `minimum`.\n */\nexport function matchesLevel(level: LogLevel, minimum: LogLevel): boolean {\n\treturn LEVEL_ORDER[level] >= LEVEL_ORDER[minimum];\n}\n\n/**\n * Whether an application stderr line only continues the preceding JavaScript error. Stack frames and the fields\n * Node prints after an `Error` are useful log lines, but they must not each increment the panel's error counter.\n */\nexport function isErrorDetail(entry: Pick<LogEntry, 'source' | 'level' | 'text'>): boolean {\n\tif (entry.source !== 'app' || entry.level !== 'error') return false;\n\tconst text = stripVTControlCharacters(entry.text);\n\treturn /^\\s+at\\s/.test(text) || /^\\s+(?:type|path|code|cause|errno|syscall|address|port):/.test(text) || /^\\s*}\\s*$/.test(text) || !text.trim();\n}\n\n/** stderr is a transport, not a severity: Node and many loggers also send warnings there. */\nexport function classifyAppLine(text: string, fallback: LogLevel): LogLevel {\n\tconst plain = stripVTControlCharacters(text);\n\tif (/\\b(?:Error|ERROR|FATAL)\\b|\\bERR_[A-Z_]+\\b/.test(plain)) return 'error';\n\tif (/\\b(?:Warning|WARN|WARNING|DeprecationWarning|ExperimentalWarning)\\b/.test(plain) || /^\\(node:\\d+\\).*warning/i.test(plain)) return 'warn';\n\tif (/^\\s*(?:\\(Use .*--trace-warnings|\\[(?:info|debug)\\]|INFO\\b|DEBUG\\b|[◇ℹ✔])/.test(plain)) return 'info';\n\treturn fallback;\n}\n"],"mappings":";;;;;;;AAyBA,IAAa,YAAb,cAA+B,aAA+C;CAI1C;CAHnC,WAAuB,CAAC;CACxB,UAAU;CAEV,AAAO,YAAY,AAAgB,WAAW,KAAM;EACnD,MAAM;EAD4B;CAEnC;CAEA,AAAO,KAAK,OAA2B;EACtC,MAAM,QAAkB;GAAE,IAAI,KAAK;GAAW,MAAM,KAAK,IAAI;GAAG,GAAG;EAAM;EACzE,KAAK,SAAS,KAAK,KAAK;EACxB,IAAI,KAAK,SAAS,SAAS,KAAK,UAAU,KAAK,SAAS,OAAO,GAAG,KAAK,SAAS,SAAS,KAAK,QAAQ;EACtG,KAAK,KAAK,SAAS,KAAK;EACxB,OAAO;CACR;CAEA,AAAO,UAA+B;EACrC,OAAO,KAAK;CACb;CAEA,AAAO,OAAO,QAA+B;EAC5C,MAAM,QAAQ,OAAO,OAAO,YAAY,KAAK;EAC7C,OAAO,KAAK,SAAS,QACnB,WACC,CAAC,OAAO,UAAU,MAAM,WAAW,OAAO,YAC1C,CAAC,OAAO,SAAS,aAAa,MAAM,OAAO,OAAO,KAAK,OACvD,CAAC,SAAS,MAAM,KAAK,YAAY,CAAC,CAAC,SAAS,KAAK,EACpD;CACD;CAEA,AAAO,QAAc;EACpB,KAAK,WAAW,CAAC;EACjB,KAAK,KAAK,OAAO;CAClB;AACD;AAEA,MAAM,cAAwC;CAAE,OAAO;CAAG,MAAM;CAAG,SAAS;CAAG,MAAM;CAAG,OAAO;AAAE;;;;AAKjG,SAAgB,aAAa,OAAiB,SAA4B;CACzE,OAAO,YAAY,UAAU,YAAY;AAC1C;;;;;AAMA,SAAgB,cAAc,OAA6D;CAC1F,IAAI,MAAM,WAAW,SAAS,MAAM,UAAU,SAAS,OAAO;CAC9D,MAAM,OAAO,yBAAyB,MAAM,IAAI;CAChD,OAAO,WAAW,KAAK,IAAI,KAAK,2DAA2D,KAAK,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK;AAC/I;;AAGA,SAAgB,gBAAgB,MAAc,UAA8B;CAC3E,MAAM,QAAQ,yBAAyB,IAAI;CAC3C,IAAI,4CAA4C,KAAK,KAAK,GAAG,OAAO;CACpE,IAAI,sEAAsE,KAAK,KAAK,KAAK,0BAA0B,KAAK,KAAK,GAAG,OAAO;CACvI,IAAI,2EAA2E,KAAK,KAAK,GAAG,OAAO;CACnG,OAAO;AACR"}
1
+ {"version":3,"file":"log-buffer-CY82aqnb.js","names":[],"sources":["../src/utils/log-buffer.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\r\nimport { stripVTControlCharacters } from 'node:util';\r\n\r\nexport type LogSource = 'stars' | 'build' | 'app' | 'tsc' | 'tunnel';\r\nexport type LogLevel = import('@wolfstar/schema').BuilderLogLevel;\r\n\r\nexport interface LogEntry {\r\n\treadonly id: number;\r\n\treadonly time: number;\r\n\treadonly source: LogSource;\r\n\treadonly level: LogLevel;\r\n\treadonly text: string;\r\n}\r\n\r\nexport interface LogFilter {\r\n\tsource?: LogSource | null;\r\n\tlevel?: LogLevel | null;\r\n\tquery?: string | null;\r\n}\r\n\r\nexport type LogInput = Omit<LogEntry, 'id' | 'time'>;\r\n\r\n/**\r\n * A bounded, in-memory log store shared by the dev service and its renderers.\r\n */\r\nexport class LogBuffer extends EventEmitter<{ entry: [LogEntry]; clear: [] }> {\r\n\t#entries: LogEntry[] = [];\r\n\t#nextId = 1;\r\n\r\n\tpublic constructor(public readonly capacity = 2000) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tpublic push(input: LogInput): LogEntry {\r\n\t\tconst entry: LogEntry = { id: this.#nextId++, time: Date.now(), ...input };\r\n\t\tthis.#entries.push(entry);\r\n\t\tif (this.#entries.length > this.capacity) this.#entries.splice(0, this.#entries.length - this.capacity);\r\n\t\tthis.emit('entry', entry);\r\n\t\treturn entry;\r\n\t}\r\n\r\n\tpublic entries(): readonly LogEntry[] {\r\n\t\treturn this.#entries;\r\n\t}\r\n\r\n\tpublic filter(filter: LogFilter): LogEntry[] {\r\n\t\tconst query = filter.query?.toLowerCase() ?? null;\r\n\t\treturn this.#entries.filter(\r\n\t\t\t(entry) =>\r\n\t\t\t\t(!filter.source || entry.source === filter.source) &&\r\n\t\t\t\t(!filter.level || matchesLevel(entry.level, filter.level)) &&\r\n\t\t\t\t(!query || entry.text.toLowerCase().includes(query))\r\n\t\t);\r\n\t}\r\n\r\n\tpublic clear(): void {\r\n\t\tthis.#entries = [];\r\n\t\tthis.emit('clear');\r\n\t}\r\n}\r\n\r\nconst LEVEL_ORDER: Record<LogLevel, number> = { debug: 0, info: 1, success: 1, warn: 2, error: 3 };\r\n\r\n/**\r\n * Whether `level` is at least as severe as `minimum`.\r\n */\r\nexport function matchesLevel(level: LogLevel, minimum: LogLevel): boolean {\r\n\treturn LEVEL_ORDER[level] >= LEVEL_ORDER[minimum];\r\n}\r\n\r\n/**\r\n * Whether an application stderr line only continues the preceding JavaScript error. Stack frames and the fields\r\n * Node prints after an `Error` are useful log lines, but they must not each increment the panel's error counter.\r\n */\r\nexport function isErrorDetail(entry: Pick<LogEntry, 'source' | 'level' | 'text'>): boolean {\r\n\tif (entry.source !== 'app' || entry.level !== 'error') return false;\r\n\tconst text = stripVTControlCharacters(entry.text);\r\n\treturn /^\\s+at\\s/.test(text) || /^\\s+(?:type|path|code|cause|errno|syscall|address|port):/.test(text) || /^\\s*}\\s*$/.test(text) || !text.trim();\r\n}\r\n\r\n/** stderr is a transport, not a severity: Node and many loggers also send warnings there. */\r\nexport function classifyAppLine(text: string, fallback: LogLevel): LogLevel {\r\n\tconst plain = stripVTControlCharacters(text);\r\n\tif (/\\b(?:Error|ERROR|FATAL)\\b|\\bERR_[A-Z_]+\\b/.test(plain)) return 'error';\r\n\tif (/\\b(?:Warning|WARN|WARNING|DeprecationWarning|ExperimentalWarning)\\b/.test(plain) || /^\\(node:\\d+\\).*warning/i.test(plain)) return 'warn';\r\n\tif (/^\\s*(?:\\(Use .*--trace-warnings|\\[(?:info|debug)\\]|INFO\\b|DEBUG\\b|[◇ℹ✔])/.test(plain)) return 'info';\r\n\treturn fallback;\r\n}\r\n"],"mappings":";;;;;;;AAyBA,IAAa,YAAb,cAA+B,aAA+C;CAI1C;CAHnC,WAAuB,CAAC;CACxB,UAAU;CAEV,AAAO,YAAY,AAAgB,WAAW,KAAM;EACnD,MAAM;EAD4B;CAEnC;CAEA,AAAO,KAAK,OAA2B;EACtC,MAAM,QAAkB;GAAE,IAAI,KAAK;GAAW,MAAM,KAAK,IAAI;GAAG,GAAG;EAAM;EACzE,KAAK,SAAS,KAAK,KAAK;EACxB,IAAI,KAAK,SAAS,SAAS,KAAK,UAAU,KAAK,SAAS,OAAO,GAAG,KAAK,SAAS,SAAS,KAAK,QAAQ;EACtG,KAAK,KAAK,SAAS,KAAK;EACxB,OAAO;CACR;CAEA,AAAO,UAA+B;EACrC,OAAO,KAAK;CACb;CAEA,AAAO,OAAO,QAA+B;EAC5C,MAAM,QAAQ,OAAO,OAAO,YAAY,KAAK;EAC7C,OAAO,KAAK,SAAS,QACnB,WACC,CAAC,OAAO,UAAU,MAAM,WAAW,OAAO,YAC1C,CAAC,OAAO,SAAS,aAAa,MAAM,OAAO,OAAO,KAAK,OACvD,CAAC,SAAS,MAAM,KAAK,YAAY,CAAC,CAAC,SAAS,KAAK,EACpD;CACD;CAEA,AAAO,QAAc;EACpB,KAAK,WAAW,CAAC;EACjB,KAAK,KAAK,OAAO;CAClB;AACD;AAEA,MAAM,cAAwC;CAAE,OAAO;CAAG,MAAM;CAAG,SAAS;CAAG,MAAM;CAAG,OAAO;AAAE;;;;AAKjG,SAAgB,aAAa,OAAiB,SAA4B;CACzE,OAAO,YAAY,UAAU,YAAY;AAC1C;;;;;AAMA,SAAgB,cAAc,OAA6D;CAC1F,IAAI,MAAM,WAAW,SAAS,MAAM,UAAU,SAAS,OAAO;CAC9D,MAAM,OAAO,yBAAyB,MAAM,IAAI;CAChD,OAAO,WAAW,KAAK,IAAI,KAAK,2DAA2D,KAAK,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK;AAC/I;;AAGA,SAAgB,gBAAgB,MAAc,UAA8B;CAC3E,MAAM,QAAQ,yBAAyB,IAAI;CAC3C,IAAI,4CAA4C,KAAK,KAAK,GAAG,OAAO;CACpE,IAAI,sEAAsE,KAAK,KAAK,KAAK,0BAA0B,KAAK,KAAK,GAAG,OAAO;CACvI,IAAI,2EAA2E,KAAK,KAAK,GAAG,OAAO;CACnG,OAAO;AACR"}
@@ -1,5 +1,5 @@
1
1
  import { t as pluginRegistrations } from "./plugin-registrations-Dr_BicfC.js";
2
- import { n as importFromProject } from "./project-MD4dIo2X.js";
2
+ import { n as importFromProject } from "./project-D-8VIcyF.js";
3
3
  import { NitroBuilder as NitroBuilder$1 } from "@wolfstar/nitro-server";
4
4
 
5
5
  //#region src/builders/nitro.ts
@@ -15,4 +15,4 @@ var NitroBuilder = class extends NitroBuilder$1 {
15
15
 
16
16
  //#endregion
17
17
  export { NitroBuilder };
18
- //# sourceMappingURL=nitro-sP2F3SQu.js.map
18
+ //# sourceMappingURL=nitro-yjqZBh5L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nitro-yjqZBh5L.js","names":["ServerBuilder"],"sources":["../src/builders/nitro.ts"],"sourcesContent":["import { NitroBuilder as ServerBuilder } from '@wolfstar/nitro-server';\r\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { pluginRegistrations } from '../utils/plugin-registrations.js';\r\nimport { importFromProject } from '../utils/project.js';\r\n\r\n/** Connect the server integration to the CLI's diagnostics and plugin discovery. */\r\nexport class NitroBuilder extends ServerBuilder {\r\n\tpublic constructor(config: ResolvedStarsConfig) {\r\n\t\tsuper(config, { importFromProject, pluginRegistrations });\r\n\t}\r\n}\r\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkCA,eAAc;CAC/C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"none-uC_wi_l4.js","names":[],"sources":["../src/builders/none.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\n\n/**\n * No build step: watches the configured paths and reports every change as an instant successful \"build\".\n */\nexport class NoneBuilder extends EventEmitter<BuilderEvents> implements Builder {\n\tpublic readonly tool = 'none' as const;\n\t#watcher: { close(): Promise<void> } | null = null;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t}\n\n\tpublic build(): Promise<BuildOutcome> {\n\t\tthis.emit('start');\n\t\tconst outcome: BuildOutcome = { ok: true, durationMs: 0, message: null };\n\t\tthis.emit('success', outcome);\n\t\treturn Promise.resolve(outcome);\n\t}\n\n\tpublic async watch(): Promise<void> {\n\t\tconst { watch } = await import('chokidar');\n\t\tconst watcher = watch([...this.config.dev.watch], {\n\t\t\tignored: [...this.config.dev.ignore],\n\t\t\tignoreInitial: true,\n\t\t\tcwd: this.config.root\n\t\t});\n\t\tthis.#watcher = watcher;\n\n\t\twatcher.on('all', (event, path) => {\n\t\t\tthis.emit('log', 'info', `${event}: ${path}`);\n\t\t\tvoid this.build();\n\t\t});\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\n\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\n\t\tawait this.build();\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tconst watcher = this.#watcher;\n\t\tthis.#watcher = null;\n\t\tawait watcher?.close();\n\t}\n}\n"],"mappings":";;;;;;AAOA,IAAa,cAAb,cAAiC,aAA+C;CAI3C;CAHpC,AAAgB,OAAO;CACvB,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;CAEpC;CAEA,AAAO,QAA+B;EACrC,KAAK,KAAK,OAAO;EACjB,MAAM,UAAwB;GAAE,IAAI;GAAM,YAAY;GAAG,SAAS;EAAK;EACvE,KAAK,KAAK,WAAW,OAAO;EAC5B,OAAO,QAAQ,QAAQ,OAAO;CAC/B;CAEA,MAAa,QAAuB;EACnC,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,GAAG;GACjD,SAAS,CAAC,GAAG,KAAK,OAAO,IAAI,MAAM;GACnC,eAAe;GACf,KAAK,KAAK,OAAO;EAClB,CAAC;EACD,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,KAAK,KAAK,OAAO,QAAQ,GAAG,MAAM,IAAI,MAAM;GAC5C,AAAK,KAAK,MAAM;EACjB,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAEhH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;EACnE,MAAM,KAAK,MAAM;CAClB;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
1
+ {"version":3,"file":"none-uC_wi_l4.js","names":[],"sources":["../src/builders/none.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\r\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\r\n\r\n/**\r\n * No build step: watches the configured paths and reports every change as an instant successful \"build\".\r\n */\r\nexport class NoneBuilder extends EventEmitter<BuilderEvents> implements Builder {\r\n\tpublic readonly tool = 'none' as const;\r\n\t#watcher: { close(): Promise<void> } | null = null;\r\n\r\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tpublic build(): Promise<BuildOutcome> {\r\n\t\tthis.emit('start');\r\n\t\tconst outcome: BuildOutcome = { ok: true, durationMs: 0, message: null };\r\n\t\tthis.emit('success', outcome);\r\n\t\treturn Promise.resolve(outcome);\r\n\t}\r\n\r\n\tpublic async watch(): Promise<void> {\r\n\t\tconst { watch } = await import('chokidar');\r\n\t\tconst watcher = watch([...this.config.dev.watch], {\r\n\t\t\tignored: [...this.config.dev.ignore],\r\n\t\t\tignoreInitial: true,\r\n\t\t\tcwd: this.config.root\r\n\t\t});\r\n\t\tthis.#watcher = watcher;\r\n\r\n\t\twatcher.on('all', (event, path) => {\r\n\t\t\tthis.emit('log', 'info', `${event}: ${path}`);\r\n\t\t\tvoid this.build();\r\n\t\t});\r\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\r\n\r\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\r\n\t\tawait this.build();\r\n\t}\r\n\r\n\tpublic async close(): Promise<void> {\r\n\t\tconst watcher = this.#watcher;\r\n\t\tthis.#watcher = null;\r\n\t\tawait watcher?.close();\r\n\t}\r\n}\r\n"],"mappings":";;;;;;AAOA,IAAa,cAAb,cAAiC,aAA+C;CAI3C;CAHpC,AAAgB,OAAO;CACvB,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;CAEpC;CAEA,AAAO,QAA+B;EACrC,KAAK,KAAK,OAAO;EACjB,MAAM,UAAwB;GAAE,IAAI;GAAM,YAAY;GAAG,SAAS;EAAK;EACvE,KAAK,KAAK,WAAW,OAAO;EAC5B,OAAO,QAAQ,QAAQ,OAAO;CAC/B;CAEA,MAAa,QAAuB;EACnC,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,GAAG;GACjD,SAAS,CAAC,GAAG,KAAK,OAAO,IAAI,MAAM;GACnC,eAAe;GACf,KAAK,KAAK,OAAO;EAClB,CAAC;EACD,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,KAAK,KAAK,OAAO,QAAQ,GAAG,MAAM,IAAI,MAAM;GAC5C,AAAK,KAAK,MAAM;EACjB,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAEhH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;EACnE,MAAM,KAAK,MAAM;CAClB;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"output-mode-Bp7Da8vJ.js","names":[],"sources":["../src/utils/output-mode.ts"],"sourcesContent":["export type OutputMode = 'tui' | 'plain';\n\nexport interface ResolveOutputModeOptions {\n\t/** `--no-tui` (`tui: false`) or `--tui` (`tui: true`) from the command line. */\n\ttui?: boolean;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Whether stdout is an interactive terminal. */\n\tisTTY?: boolean;\n\t/** Raw-key input requires a terminal too, even when the output is a TTY. */\n\tisInputTTY?: boolean;\n\tcolumns?: number;\n\trows?: number;\n\t/** Whether the process runs in a CI environment. */\n\tisCI?: boolean;\n}\n\nconst truthy = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Decides between the interactive TUI and plain line output.\n *\n * Precedence: `--no-tui` › `STARS_TUI=plain` › non-interactive stdout, CI or `TERM=dumb`.\n */\nexport function resolveOutputMode(options: ResolveOutputModeOptions = {}): OutputMode {\n\tconst env = options.env ?? process.env;\n\tconst isTTY = options.isTTY ?? Boolean(process.stdout.isTTY);\n\tconst isInputTTY = options.isInputTTY ?? options.isTTY ?? Boolean(process.stdin.isTTY);\n\tconst isCI = options.isCI ?? isCIEnvironment(env);\n\n\tif (options.tui === false) return 'plain';\n\n\tconst forced = env.STARS_TUI?.trim().toLowerCase();\n\tif (forced === 'plain' || forced === '0' || forced === 'false' || forced === 'off') return 'plain';\n\tif (!isTTY || !isInputTTY || env.TERM === 'dumb') return 'plain';\n\tif (forced === 'tui' || (forced && truthy.has(forced))) return isTTY ? 'tui' : 'plain';\n\n\tif (options.tui === true) return isTTY ? 'tui' : 'plain';\n\tif (isCI || (options.columns ?? process.stdout.columns ?? 80) < 40 || (options.rows ?? process.stdout.rows ?? 24) < 10) return 'plain';\n\treturn 'tui';\n}\n\nexport function isCIEnvironment(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn (\n\t\tBoolean(env.CI && !['false', '0'].includes(env.CI.toLowerCase())) ||\n\t\tBoolean(env.GITHUB_ACTIONS || env.GITLAB_CI || env.BUILDKITE || env.CIRCLECI)\n\t);\n}\n\n/**\n * Whether colours should be emitted, honouring `NO_COLOR` and `FORCE_COLOR`.\n */\nexport function shouldUseColor(env: NodeJS.ProcessEnv = process.env, isTTY = Boolean(process.stdout.isTTY)): boolean {\n\tif (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return false;\n\tif (env.FORCE_COLOR !== undefined) return env.FORCE_COLOR !== '0';\n\treturn isTTY && env.TERM !== 'dumb';\n}\n\n/**\n * Whether animations (spinners, blinking status) should be avoided.\n */\nexport function prefersReducedMotion(env: NodeJS.ProcessEnv = process.env): boolean {\n\tconst value = env.STARS_REDUCED_MOTION ?? env.REDUCED_MOTION;\n\treturn value !== undefined && value !== '' && value !== '0' && value.toLowerCase() !== 'false';\n}\n"],"mappings":";AAgBA,MAAM,yBAAS,IAAI,IAAI;CAAC;CAAK;CAAQ;CAAO;AAAI,CAAC;;;;;;AAOjD,SAAgB,kBAAkB,UAAoC,CAAC,GAAe;CACrF,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,OAAO,KAAK;CAC3D,MAAM,aAAa,QAAQ,cAAc,QAAQ,SAAS,QAAQ,QAAQ,MAAM,KAAK;CACrF,MAAM,OAAO,QAAQ,QAAQ,gBAAgB,GAAG;CAEhD,IAAI,QAAQ,QAAQ,OAAO,OAAO;CAElC,MAAM,SAAS,IAAI,WAAW,KAAK,CAAC,CAAC,YAAY;CACjD,IAAI,WAAW,WAAW,WAAW,OAAO,WAAW,WAAW,WAAW,OAAO,OAAO;CAC3F,IAAI,CAAC,SAAS,CAAC,cAAc,IAAI,SAAS,QAAQ,OAAO;CACzD,IAAI,WAAW,SAAU,UAAU,OAAO,IAAI,MAAM,GAAI,OAAO,QAAQ,QAAQ;CAE/E,IAAI,QAAQ,QAAQ,MAAM,OAAO,QAAQ,QAAQ;CACjD,IAAI,SAAS,QAAQ,WAAW,QAAQ,OAAO,WAAW,MAAM,OAAO,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,MAAM,IAAI,OAAO;CAC/H,OAAO;AACR;AAEA,SAAgB,gBAAgB,MAAyB,QAAQ,KAAc;CAC9E,OACC,QAAQ,IAAI,MAAM,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,YAAY,CAAC,CAAC,KAChE,QAAQ,IAAI,kBAAkB,IAAI,aAAa,IAAI,aAAa,IAAI,QAAQ;AAE9E;;;;AAKA,SAAgB,eAAe,MAAyB,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,OAAO,KAAK,GAAY;CACpH,IAAI,IAAI,aAAa,UAAa,IAAI,aAAa,IAAI,OAAO;CAC9D,IAAI,IAAI,gBAAgB,QAAW,OAAO,IAAI,gBAAgB;CAC9D,OAAO,SAAS,IAAI,SAAS;AAC9B;;;;AAKA,SAAgB,qBAAqB,MAAyB,QAAQ,KAAc;CACnF,MAAM,QAAQ,IAAI,wBAAwB,IAAI;CAC9C,OAAO,UAAU,UAAa,UAAU,MAAM,UAAU,OAAO,MAAM,YAAY,MAAM;AACxF"}
1
+ {"version":3,"file":"output-mode-Bp7Da8vJ.js","names":[],"sources":["../src/utils/output-mode.ts"],"sourcesContent":["export type OutputMode = 'tui' | 'plain';\r\n\r\nexport interface ResolveOutputModeOptions {\r\n\t/** `--no-tui` (`tui: false`) or `--tui` (`tui: true`) from the command line. */\r\n\ttui?: boolean;\r\n\tenv?: NodeJS.ProcessEnv;\r\n\t/** Whether stdout is an interactive terminal. */\r\n\tisTTY?: boolean;\r\n\t/** Raw-key input requires a terminal too, even when the output is a TTY. */\r\n\tisInputTTY?: boolean;\r\n\tcolumns?: number;\r\n\trows?: number;\r\n\t/** Whether the process runs in a CI environment. */\r\n\tisCI?: boolean;\r\n}\r\n\r\nconst truthy = new Set(['1', 'true', 'yes', 'on']);\r\n\r\n/**\r\n * Decides between the interactive TUI and plain line output.\r\n *\r\n * Precedence: `--no-tui` › `STARS_TUI=plain` › non-interactive stdout, CI or `TERM=dumb`.\r\n */\r\nexport function resolveOutputMode(options: ResolveOutputModeOptions = {}): OutputMode {\r\n\tconst env = options.env ?? process.env;\r\n\tconst isTTY = options.isTTY ?? Boolean(process.stdout.isTTY);\r\n\tconst isInputTTY = options.isInputTTY ?? options.isTTY ?? Boolean(process.stdin.isTTY);\r\n\tconst isCI = options.isCI ?? isCIEnvironment(env);\r\n\r\n\tif (options.tui === false) return 'plain';\r\n\r\n\tconst forced = env.STARS_TUI?.trim().toLowerCase();\r\n\tif (forced === 'plain' || forced === '0' || forced === 'false' || forced === 'off') return 'plain';\r\n\tif (!isTTY || !isInputTTY || env.TERM === 'dumb') return 'plain';\r\n\tif (forced === 'tui' || (forced && truthy.has(forced))) return isTTY ? 'tui' : 'plain';\r\n\r\n\tif (options.tui === true) return isTTY ? 'tui' : 'plain';\r\n\tif (isCI || (options.columns ?? process.stdout.columns ?? 80) < 40 || (options.rows ?? process.stdout.rows ?? 24) < 10) return 'plain';\r\n\treturn 'tui';\r\n}\r\n\r\nexport function isCIEnvironment(env: NodeJS.ProcessEnv = process.env): boolean {\r\n\treturn (\r\n\t\tBoolean(env.CI && !['false', '0'].includes(env.CI.toLowerCase())) ||\r\n\t\tBoolean(env.GITHUB_ACTIONS || env.GITLAB_CI || env.BUILDKITE || env.CIRCLECI)\r\n\t);\r\n}\r\n\r\n/**\r\n * Whether colours should be emitted, honouring `NO_COLOR` and `FORCE_COLOR`.\r\n */\r\nexport function shouldUseColor(env: NodeJS.ProcessEnv = process.env, isTTY = Boolean(process.stdout.isTTY)): boolean {\r\n\tif (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return false;\r\n\tif (env.FORCE_COLOR !== undefined) return env.FORCE_COLOR !== '0';\r\n\treturn isTTY && env.TERM !== 'dumb';\r\n}\r\n\r\n/**\r\n * Whether animations (spinners, blinking status) should be avoided.\r\n */\r\nexport function prefersReducedMotion(env: NodeJS.ProcessEnv = process.env): boolean {\r\n\tconst value = env.STARS_REDUCED_MOTION ?? env.REDUCED_MOTION;\r\n\treturn value !== undefined && value !== '' && value !== '0' && value.toLowerCase() !== 'false';\r\n}\r\n"],"mappings":";AAgBA,MAAM,yBAAS,IAAI,IAAI;CAAC;CAAK;CAAQ;CAAO;AAAI,CAAC;;;;;;AAOjD,SAAgB,kBAAkB,UAAoC,CAAC,GAAe;CACrF,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,OAAO,KAAK;CAC3D,MAAM,aAAa,QAAQ,cAAc,QAAQ,SAAS,QAAQ,QAAQ,MAAM,KAAK;CACrF,MAAM,OAAO,QAAQ,QAAQ,gBAAgB,GAAG;CAEhD,IAAI,QAAQ,QAAQ,OAAO,OAAO;CAElC,MAAM,SAAS,IAAI,WAAW,KAAK,CAAC,CAAC,YAAY;CACjD,IAAI,WAAW,WAAW,WAAW,OAAO,WAAW,WAAW,WAAW,OAAO,OAAO;CAC3F,IAAI,CAAC,SAAS,CAAC,cAAc,IAAI,SAAS,QAAQ,OAAO;CACzD,IAAI,WAAW,SAAU,UAAU,OAAO,IAAI,MAAM,GAAI,OAAO,QAAQ,QAAQ;CAE/E,IAAI,QAAQ,QAAQ,MAAM,OAAO,QAAQ,QAAQ;CACjD,IAAI,SAAS,QAAQ,WAAW,QAAQ,OAAO,WAAW,MAAM,OAAO,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,MAAM,IAAI,OAAO;CAC/H,OAAO;AACR;AAEA,SAAgB,gBAAgB,MAAyB,QAAQ,KAAc;CAC9E,OACC,QAAQ,IAAI,MAAM,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,YAAY,CAAC,CAAC,KAChE,QAAQ,IAAI,kBAAkB,IAAI,aAAa,IAAI,aAAa,IAAI,QAAQ;AAE9E;;;;AAKA,SAAgB,eAAe,MAAyB,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,OAAO,KAAK,GAAY;CACpH,IAAI,IAAI,aAAa,UAAa,IAAI,aAAa,IAAI,OAAO;CAC9D,IAAI,IAAI,gBAAgB,QAAW,OAAO,IAAI,gBAAgB;CAC9D,OAAO,SAAS,IAAI,SAAS;AAC9B;;;;AAKA,SAAgB,qBAAqB,MAAyB,QAAQ,KAAc;CACnF,MAAM,QAAQ,IAAI,wBAAwB,IAAI;CAC9C,OAAO,UAAU,UAAa,UAAU,MAAM,UAAU,OAAO,MAAM,YAAY,MAAM;AACxF"}