@wolfstar/cli 2.0.4 → 2.1.0-next-20261001111011
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.
- package/README.md +34 -6
- package/dist/{_shared-B5EYpDS-.js → _shared-B-hRZDRS.js} +15 -4
- package/dist/_shared-B-hRZDRS.js.map +1 -0
- package/dist/{build-Df5jpHx-.js → build-CPnSLYME.js} +16 -10
- package/dist/build-CPnSLYME.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/{codegen-DDkAozhq.js → codegen-BqpLGLLs.js} +4 -4
- package/dist/codegen-BqpLGLLs.js.map +1 -0
- package/dist/{commands-BuQLzWfi.js → commands-ExM8HILu.js} +4 -5
- package/dist/commands-ExM8HILu.js.map +1 -0
- package/dist/{dev-zxmvjryt.js → dev-4wpEQC7l.js} +85 -11
- package/dist/dev-4wpEQC7l.js.map +1 -0
- package/dist/hooks-H9kjLCMk.js +148 -0
- package/dist/hooks-H9kjLCMk.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{info-C23rw2wp.js → info-CdiQajgn.js} +16 -6
- package/dist/info-CdiQajgn.js.map +1 -0
- package/dist/{locales-wTnYUPpl.js → locales-C7X8VNmK.js} +7 -4
- package/dist/locales-C7X8VNmK.js.map +1 -0
- package/dist/{prepare-es4Udgqh.js → prepare-B4ysyG6H.js} +7 -6
- package/dist/prepare-B4ysyG6H.js.map +1 -0
- package/dist/{run-Bxf2ws_n.js → run-Ddwrxe1O.js} +7 -7
- package/dist/{run-Bxf2ws_n.js.map → run-Ddwrxe1O.js.map} +1 -1
- package/dist/{tsdown-BlPFHbIw.js → tsdown-CD68G8_U.js} +10 -4
- package/dist/tsdown-CD68G8_U.js.map +1 -0
- package/dist/{tunnel-DiL0Wxi_.js → tunnel-DT1FH6oA.js} +9 -7
- package/dist/tunnel-DT1FH6oA.js.map +1 -0
- package/package.json +5 -4
- package/dist/_shared-B5EYpDS-.js.map +0 -1
- package/dist/args-Du59CLXl.js +0 -24
- package/dist/args-Du59CLXl.js.map +0 -1
- package/dist/build-Df5jpHx-.js.map +0 -1
- package/dist/codegen-DDkAozhq.js.map +0 -1
- package/dist/commands-BuQLzWfi.js.map +0 -1
- package/dist/dev-zxmvjryt.js.map +0 -1
- package/dist/info-C23rw2wp.js.map +0 -1
- package/dist/locales-wTnYUPpl.js.map +0 -1
- package/dist/prepare-es4Udgqh.js.map +0 -1
- package/dist/tsdown-BlPFHbIw.js.map +0 -1
- package/dist/tunnel-DiL0Wxi_.js.map +0 -1
package/README.md
CHANGED
|
@@ -192,8 +192,9 @@ export default defineConfig({
|
|
|
192
192
|
});
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
With `future.compatibilityVersion: 3` an existing `tsdown.config.*` still drives the build and the block
|
|
196
|
-
over it (values from `stars.config` win, `plugins` are appended);
|
|
195
|
+
With `future.compatibilityVersion: 3` (end-of-life) an existing `tsdown.config.*` still drives the build and the block
|
|
196
|
+
is merged over it (values from `stars.config` win, `plugins` are appended); from `4` on the block is the whole
|
|
197
|
+
configuration. The
|
|
197
198
|
`vite` block works the same way for `build.tool: 'vite'`. `stars info` shows which file the build is configured from
|
|
198
199
|
and which options the block sets.
|
|
199
200
|
|
|
@@ -202,10 +203,37 @@ and which options the block sets.
|
|
|
202
203
|
`future.compatibilityVersion` selects the legacy or current defaults, the way Nuxt's own compatibility setting does (see the
|
|
203
204
|
[framework README](../http-framework#compatibility-version) for the full reference):
|
|
204
205
|
|
|
205
|
-
| Version | What it changes
|
|
206
|
-
| ------------- |
|
|
207
|
-
| `3`
|
|
208
|
-
| `4`
|
|
206
|
+
| Version | What it changes |
|
|
207
|
+
| ------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
208
|
+
| `3` (EOL) | Legacy behaviour: a `tsdown.config.*` drives the build, auto imports off unless asked for; prints `COMPATIBILITY_VERSION_EOL` |
|
|
209
|
+
| `4` | `tsdown` configured from `stars.config` alone, auto imports on and wired in, `'auto'` picks `tsdown` for TypeScript |
|
|
210
|
+
| `5` (default) | Everything in `4`, plus `env` registered automatically when the project depends on `@wolfstar/env-utilities` |
|
|
211
|
+
|
|
212
|
+
### Environment and hooks
|
|
213
|
+
|
|
214
|
+
`env` mirrors the options of `setup()` from `@wolfstar/env-utilities`: `stars` calls it with them as the first import
|
|
215
|
+
of the built entry, before plugin registrations and the bot's own modules. tsdown, Vite and Nitro builds get it
|
|
216
|
+
through the entry transform; with `build.tool: 'tsc'` or `'none'` only `stars dev` preloads it (`node --import`).
|
|
217
|
+
Nitro leaves it off unless `env` is set explicitly.
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
export default defineConfig({
|
|
221
|
+
env: { prefix: 'BOT_' },
|
|
222
|
+
hooks: {
|
|
223
|
+
'env:options'(options) {
|
|
224
|
+
if (process.env.CI) options.path = '.env.ci';
|
|
225
|
+
},
|
|
226
|
+
build: { done: (outcome) => void (outcome.ok || console.error(outcome.message)) }
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`hooks` are CLI lifecycle hooks run with [`hookable`](https://github.com/unjs/hookable): `config:resolved`,
|
|
232
|
+
`env:options`, `prepare:before`/`prepare:done`, `builder:created`, `tsdown:options`, `build:before`/`build:done`,
|
|
233
|
+
`dev:start`/`dev:restart`/`dev:close`. They run in the CLI process, never in the bot, in the same order in `stars build` and
|
|
234
|
+
`stars dev` (see the framework README for how `stars dev` awaits them). `stars info` lists the env
|
|
235
|
+
options and the registered hooks. See the [framework README](../http-framework#environment-env) for the full
|
|
236
|
+
reference.
|
|
209
237
|
|
|
210
238
|
### Experimental flags
|
|
211
239
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { r as formatError } from "./errors-Crt4hu0b.js";
|
|
1
2
|
import { t as loadAutoImportsModule } from "./framework-auto-imports-Gu_PXSyr.js";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -116,14 +117,24 @@ async function prepareAutoImports(config, check = false) {
|
|
|
116
117
|
};
|
|
117
118
|
}
|
|
118
119
|
/** Prepares TypeScript configuration and auto import declarations before building. */
|
|
119
|
-
async function prepareProject(config, check = false) {
|
|
120
|
+
async function prepareProject(config, hooks, check = false) {
|
|
121
|
+
await hooks?.callHook("prepare:before", config);
|
|
120
122
|
const tsconfig = await prepareTsconfig(config, check);
|
|
121
|
-
|
|
123
|
+
const result = {
|
|
122
124
|
...await prepareAutoImports(config, check),
|
|
123
125
|
tsconfig
|
|
124
126
|
};
|
|
127
|
+
await hooks?.callHook("prepare:done", config, {
|
|
128
|
+
dts: result.dts,
|
|
129
|
+
status: result.status
|
|
130
|
+
});
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
/** Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version). */
|
|
134
|
+
async function reportWarnings(config, write) {
|
|
135
|
+
for (const warning of config.warnings) write(await formatError(warning));
|
|
125
136
|
}
|
|
126
137
|
|
|
127
138
|
//#endregion
|
|
128
|
-
export { prepareProject as t };
|
|
129
|
-
//# sourceMappingURL=_shared-
|
|
139
|
+
export { reportWarnings as n, prepareProject as t };
|
|
140
|
+
//# sourceMappingURL=_shared-B-hRZDRS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_shared-B-hRZDRS.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 { 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 };\n\tawait hooks?.callHook('prepare:done', config, { dts: result.dts, status: result.status });\n\treturn result;\n}\n\n/** Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version). */\nexport async function reportWarnings(config: ResolvedStarsConfig, write: (text: string) => void): Promise<void> {\n\tfor (const warning of config.warnings) write(await formatError(warning));\n}\n"],"mappings":"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"}
|
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
|
|
2
2
|
import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
|
|
3
|
-
import { n as createBuilder, t as Locales } from "./locales-
|
|
4
|
-
import { n as resolveCwd, t as
|
|
5
|
-
import { t as prepareProject } from "./_shared-
|
|
3
|
+
import { n as createBuilder, t as Locales } from "./locales-C7X8VNmK.js";
|
|
4
|
+
import { a as projectArgs, n as loadProject, o as resolveCwd, t as applyEnvOptions } from "./hooks-H9kjLCMk.js";
|
|
5
|
+
import { n as reportWarnings, t as prepareProject } from "./_shared-B-hRZDRS.js";
|
|
6
6
|
import { defineCommand } from "citty";
|
|
7
|
-
import { displayPath
|
|
7
|
+
import { displayPath } from "@wolfstar/schema";
|
|
8
8
|
import { createColors } from "colorette";
|
|
9
9
|
|
|
10
10
|
//#region src/commands/build.ts
|
|
11
11
|
async function runBuild(options) {
|
|
12
12
|
const stdout = options.stdout ?? process.stdout;
|
|
13
13
|
const colors = createColors({ useColor: shouldUseColor() });
|
|
14
|
-
const config = await
|
|
14
|
+
const { config: resolved, hooks } = await loadProject({
|
|
15
15
|
cwd: resolveCwd(options),
|
|
16
16
|
configFile: options.config
|
|
17
17
|
});
|
|
18
|
-
await
|
|
19
|
-
if (
|
|
20
|
-
|
|
18
|
+
await reportWarnings(resolved, (text) => process.stderr.write(`${text}\n`));
|
|
19
|
+
if (resolved.build.tool === "none") {
|
|
20
|
+
await prepareProject(resolved, hooks);
|
|
21
|
+
stdout.write(`${colors.dim("stars")} nothing to build, ${displayPath(resolved.root, resolved.entry)} runs as-is (build.tool is 'none')\n`);
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
const
|
|
24
|
+
const config = await applyEnvOptions(resolved, hooks);
|
|
25
|
+
const builder = await createBuilder(config, hooks);
|
|
26
|
+
await hooks.callHook("builder:created", builder, config);
|
|
27
|
+
await prepareProject(config, hooks);
|
|
24
28
|
builder.on("log", (level, text) => {
|
|
25
29
|
const paint = level === "error" ? colors.red : level === "warn" ? colors.yellow : (value) => value;
|
|
26
30
|
stdout.write(`${paint(text)}\n`);
|
|
27
31
|
});
|
|
28
32
|
stdout.write(`${colors.dim("stars")} building with ${colors.bold(config.build.tool)}…\n`);
|
|
33
|
+
await hooks.callHook("build:before", config);
|
|
29
34
|
const outcome = await builder.build();
|
|
35
|
+
await hooks.callHook("build:done", outcome, config);
|
|
30
36
|
if (!outcome.ok) throw cliDiagnostics.BUILD_FAILED({ message: outcome.message ?? "" });
|
|
31
37
|
new Locales(config).copy();
|
|
32
38
|
stdout.write(`${colors.dim("stars")} ${colors.green(`built in ${outcome.durationMs}ms`)} → ${displayPath(config.root, config.build.output)}\n`);
|
|
@@ -47,4 +53,4 @@ var build_default = defineCommand({
|
|
|
47
53
|
|
|
48
54
|
//#endregion
|
|
49
55
|
export { build_default as default };
|
|
50
|
-
//# sourceMappingURL=build-
|
|
56
|
+
//# sourceMappingURL=build-CPnSLYME.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-CPnSLYME.js","names":[],"sources":["../src/commands/build.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { createBuilder } from '../builders/index.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\nimport { Locales } from '../utils/locales.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport interface BuildTaskOptions extends ProjectArgs {\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport async function runBuild(options: BuildTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() });\n\tconst { config: resolved, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(resolved, (text) => process.stderr.write(`${text}\\n`));\n\n\tif (resolved.build.tool === 'none') {\n\t\tawait prepareProject(resolved, hooks);\n\t\tstdout.write(`${colors.dim('stars')} nothing to build, ${displayPath(resolved.root, resolved.entry)} runs as-is (build.tool is 'none')\\n`);\n\t\treturn;\n\t}\n\n\t// Same hook order as `stars dev`: `env:options` and `builder:created` before `prepare:*`.\n\tconst config = await applyEnvOptions(resolved, hooks);\n\tconst builder = await createBuilder(config, hooks);\n\tawait hooks.callHook('builder:created', builder, config);\n\tawait prepareProject(config, hooks);\n\tbuilder.on('log', (level, text) => {\n\t\tconst paint = level === 'error' ? colors.red : level === 'warn' ? colors.yellow : (value: string) => value;\n\t\tstdout.write(`${paint(text)}\\n`);\n\t});\n\n\tstdout.write(`${colors.dim('stars')} building with ${colors.bold(config.build.tool)}…\\n`);\n\tawait hooks.callHook('build:before', config);\n\tconst outcome = await builder.build();\n\tawait hooks.callHook('build:done', outcome, config);\n\tif (!outcome.ok) {\n\t\tthrow cliDiagnostics.BUILD_FAILED({ message: outcome.message ?? '' });\n\t}\n\tnew Locales(config).copy();\n\n\tstdout.write(`${colors.dim('stars')} ${colors.green(`built in ${outcome.durationMs}ms`)} → ${displayPath(config.root, config.build.output)}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'build',\n\t\tdescription: 'Build the project once with the configured build tool'\n\t},\n\targs: { ...projectArgs },\n\tasync run({ args }) {\n\t\tawait runBuild({ config: args.config, cwd: args.cwd });\n\t}\n});\n"],"mappings":";;;;;;;;;;AAeA,eAAsB,SAAS,SAA0C;CACxE,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;CAC1D,MAAM,EAAE,QAAQ,UAAU,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CAC9G,MAAM,eAAe,WAAW,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC;CAE1E,IAAI,SAAS,MAAM,SAAS,QAAQ;EACnC,MAAM,eAAe,UAAU,KAAK;EACpC,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,qBAAqB,YAAY,SAAS,MAAM,SAAS,KAAK,EAAE,qCAAqC;EACzI;CACD;CAGA,MAAM,SAAS,MAAM,gBAAgB,UAAU,KAAK;CACpD,MAAM,UAAU,MAAM,cAAc,QAAQ,KAAK;CACjD,MAAM,MAAM,SAAS,mBAAmB,SAAS,MAAM;CACvD,MAAM,eAAe,QAAQ,KAAK;CAClC,QAAQ,GAAG,QAAQ,OAAO,SAAS;EAClC,MAAM,QAAQ,UAAU,UAAU,OAAO,MAAM,UAAU,SAAS,OAAO,UAAU,UAAkB;EACrG,OAAO,MAAM,GAAG,MAAM,IAAI,EAAE,GAAG;CAChC,CAAC;CAED,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,iBAAiB,OAAO,KAAK,OAAO,MAAM,IAAI,EAAE,IAAI;CACxF,MAAM,MAAM,SAAS,gBAAgB,MAAM;CAC3C,MAAM,UAAU,MAAM,QAAQ,MAAM;CACpC,MAAM,MAAM,SAAS,cAAc,SAAS,MAAM;CAClD,IAAI,CAAC,QAAQ,IACZ,MAAM,eAAe,aAAa,EAAE,SAAS,QAAQ,WAAW,GAAG,CAAC;CAErE,IAAI,QAAQ,MAAM,CAAC,CAAC,KAAK;CAEzB,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,MAAM,YAAY,QAAQ,WAAW,GAAG,EAAE,KAAK,YAAY,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE,GAAG;AAC/I;AAEA,oBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM,EAAE,GAAG,YAAY;CACvB,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,SAAS;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;EAAI,CAAC;CACtD;AACD,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
|
|
2
2
|
import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
|
|
3
3
|
import { i as resolveFromProject } from "./project-MD4dIo2X.js";
|
|
4
|
-
import { n as
|
|
4
|
+
import { a as projectArgs, n as loadProject, o as resolveCwd } from "./hooks-H9kjLCMk.js";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
-
import { displayPath
|
|
7
|
+
import { displayPath } from "@wolfstar/schema";
|
|
8
8
|
import { createColors } from "colorette";
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
@@ -14,7 +14,7 @@ import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
|
14
14
|
async function runCodegen(options) {
|
|
15
15
|
const stdout = options.stdout ?? process.stdout;
|
|
16
16
|
const colors = createColors({ useColor: shouldUseColor() && !options.json });
|
|
17
|
-
const config = await
|
|
17
|
+
const { config } = await loadProject({
|
|
18
18
|
cwd: resolveCwd(options),
|
|
19
19
|
configFile: options.config
|
|
20
20
|
});
|
|
@@ -121,4 +121,4 @@ var codegen_default = defineCommand({
|
|
|
121
121
|
|
|
122
122
|
//#endregion
|
|
123
123
|
export { codegen_default as default };
|
|
124
|
-
//# sourceMappingURL=codegen-
|
|
124
|
+
//# sourceMappingURL=codegen-BqpLGLLs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen-BqpLGLLs.js","names":[],"sources":["../src/commands/codegen.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig } from '@wolfstar/schema';\nimport { loadProject } from '../utils/hooks.js';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { spawn } from 'node:child_process';\nimport { mkdtemp, readFile, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { resolveFromProject } from '../utils/project.js';\n\nexport interface CodegenTaskOptions extends ProjectArgs {\n\tcheck?: boolean;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface CodegenResult {\n\tgenerator: 'i18n';\n\toutput: string;\n\tstatus: 'written' | 'up-to-date' | 'outdated';\n}\n\nexport async function runCodegen(options: CodegenTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { config } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tconst results: CodegenResult[] = [];\n\n\tif (config.codegen.i18n) results.push(await runI18n(config, Boolean(options.check)));\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify({ check: Boolean(options.check), results }, null, 2)}\\n`);\n\t} else if (results.length === 0) {\n\t\tstdout.write(`${colors.dim('stars')} nothing to generate (no code generators are configured)\\n`);\n\t} else {\n\t\tfor (const result of results) {\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} ${result.generator}: ${paint(result.status)} ${displayPath(config.root, result.output)}\\n`);\n\t\t}\n\t}\n\n\tif (results.some((result) => result.status === 'outdated')) {\n\t\tthrow cliDiagnostics.CODEGEN_OUTDATED({});\n\t}\n}\n\nasync function runI18n(config: ResolvedStarsConfig, check: boolean): Promise<CodegenResult> {\n\tconst { locales, output } = config.codegen.i18n!;\n\tconst cli = resolveFromProject(config.root, '@wolfstar/i18next-type-generator');\n\tif (!cli) {\n\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({\n\t\t\tname: '@wolfstar/i18next-type-generator',\n\t\t\troot: config.root,\n\t\t\thint: 'Install it with `pnpm add -D @wolfstar/i18next-type-generator`, or set `codegen.i18n` to false.'\n\t\t});\n\t}\n\n\tif (!check) {\n\t\tawait generate(config.root, cli, locales, output);\n\t\treturn { generator: 'i18n', output, status: 'written' };\n\t}\n\n\tconst directory = await mkdtemp(join(tmpdir(), 'stars-codegen-'));\n\ttry {\n\t\tconst candidate = join(directory, 'i18next.d.ts');\n\t\tawait generate(config.root, cli, locales, candidate);\n\t\tconst [expected, actual] = await Promise.all([readFile(candidate, 'utf-8'), readFile(output, 'utf-8').catch(() => null)]);\n\t\treturn { generator: 'i18n', output, status: expected === actual ? 'up-to-date' : 'outdated' };\n\t} finally {\n\t\tawait rm(directory, { recursive: true, force: true });\n\t}\n}\n\nfunction generate(root: string, cli: string, locales: string, output: string): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(process.execPath, [cli, locales, output], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });\n\t\tlet stderr = '';\n\t\tchild.stderr?.on('data', (chunk: Buffer) => (stderr += chunk.toString()));\n\t\tchild.once('error', reject);\n\t\tchild.once('exit', (code) => {\n\t\t\tif (code === 0) resolve();\n\t\t\telse reject(cliDiagnostics.CODEGEN_FAILED({ code, stderr: stderr.trim() }));\n\t\t});\n\t});\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'codegen',\n\t\tdescription: 'Run the configured code generators (i18next types)'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tcheck: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing them',\n\t\t\tdefault: false\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runCodegen({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\n\t}\n});\n"],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
|
|
2
2
|
import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
|
|
3
|
-
import { n as
|
|
4
|
-
import { n as readDiscordCredentials } from "./tunnel-
|
|
3
|
+
import { a as projectArgs, n as loadProject, o as resolveCwd } from "./hooks-H9kjLCMk.js";
|
|
4
|
+
import { n as readDiscordCredentials } from "./tunnel-DT1FH6oA.js";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
|
-
import { loadStarsConfig } from "@wolfstar/schema";
|
|
7
6
|
import { createColors } from "colorette";
|
|
8
7
|
|
|
9
8
|
//#region src/utils/discord.ts
|
|
@@ -178,7 +177,7 @@ async function selectTargets(options, deployed, wanted, scope, stdout, colors) {
|
|
|
178
177
|
return targets;
|
|
179
178
|
}
|
|
180
179
|
async function connect(options) {
|
|
181
|
-
const config = await
|
|
180
|
+
const { config } = await loadProject({
|
|
182
181
|
cwd: resolveCwd(options),
|
|
183
182
|
configFile: options.config
|
|
184
183
|
});
|
|
@@ -296,4 +295,4 @@ var commands_default = defineCommand({
|
|
|
296
295
|
|
|
297
296
|
//#endregion
|
|
298
297
|
export { commands_default as default };
|
|
299
|
-
//# sourceMappingURL=commands-
|
|
298
|
+
//# sourceMappingURL=commands-ExM8HILu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands-ExM8HILu.js","names":[],"sources":["../src/utils/discord.ts","../src/utils/prompts.ts","../src/commands/commands.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { readDiscordCredentials } from '../dev/tunnel.js';\n\nconst API = 'https://discord.com/api/v10';\n\nexport interface ApplicationCommand {\n\tid: string;\n\tapplication_id: string;\n\tname: string;\n\tdescription?: string;\n\ttype?: number;\n\tguild_id?: string;\n\tversion?: string;\n}\n\nexport interface DiscordClient {\n\tapplicationId: string;\n\tlistCommands(guildId: string | null): Promise<ApplicationCommand[]>;\n\tdeleteCommand(guildId: string | null, commandId: string): Promise<void>;\n}\n\nexport const COMMAND_TYPE_NAMES: Record<number, string> = { 1: 'chat input', 2: 'user', 3: 'message' };\n\n/**\n * A minimal Discord REST client for what `stars commands` manages. The credentials come from the environment or the\n * project's `.env`, the same place the bot reads them from once it starts.\n */\nexport function createDiscordClient(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordClient {\n\tconst credentials = readDiscordCredentials(config, env);\n\tif (!credentials) {\n\t\tthrow cliDiagnostics.DISCORD_TOKEN_MISSING({});\n\t}\n\n\tif (!credentials.applicationId) {\n\t\tthrow cliDiagnostics.DISCORD_APPLICATION_ID_MISSING({});\n\t}\n\n\tconst applicationId = credentials.applicationId;\n\tconst scope = (guildId: string | null) =>\n\t\tguildId ? `/applications/${applicationId}/guilds/${guildId}/commands` : `/applications/${applicationId}/commands`;\n\n\tconst request = async (method: string, path: string): Promise<unknown> => {\n\t\tconst response = await fetch(`${API}${path}`, {\n\t\t\tmethod,\n\t\t\theaders: { authorization: `Bot ${credentials.token}` },\n\t\t\tsignal: AbortSignal.timeout(15_000)\n\t\t});\n\n\t\tif (response.status === 204) return null;\n\n\t\tconst body: unknown = await response.json().catch(() => null);\n\t\tif (!response.ok) {\n\t\t\tconst detail = typeof body === 'object' && body !== null && 'message' in body ? String((body as { message: unknown }).message) : '';\n\t\t\tthrow cliDiagnostics.DISCORD_REQUEST_FAILED({ status: response.status, detail });\n\t\t}\n\n\t\treturn body;\n\t};\n\n\treturn {\n\t\tapplicationId,\n\t\tasync listCommands(guildId) {\n\t\t\tconst body = await request('GET', scope(guildId));\n\t\t\treturn Array.isArray(body) ? (body as ApplicationCommand[]) : [];\n\t\t},\n\t\tasync deleteCommand(guildId, commandId) {\n\t\t\tawait request('DELETE', `${scope(guildId)}/${commandId}`);\n\t\t}\n\t};\n}\n","import type { Diagnostic } from 'nostics';\nimport type { ApplicationCommand } from './discord.js';\nimport { cliDiagnostics } from './diagnostics.js';\n\nexport interface CommandsPrompt {\n\t/** Asks which of the deployed commands to delete. Returns the chosen ids. */\n\tpick(commands: readonly ApplicationCommand[], scope: string): Promise<string[]>;\n\t/** Final go/no-go before anything is deleted. */\n\tconfirm(message: string): Promise<boolean>;\n}\n\n/**\n * The interactive wizard behind `stars commands clean`: a checklist of what Discord has deployed, then a\n * confirmation, so a destructive cleanup is never one keystroke away. `@clack/prompts` is loaded lazily — the\n * non-interactive paths (`--yes`, `--json`, CI) never pay for it.\n */\nexport function createClackPrompt(): CommandsPrompt {\n\treturn {\n\t\tasync pick(commands, scope) {\n\t\t\tconst { isCancel, multiselect } = await import('@clack/prompts');\n\t\t\tconst answer = await multiselect({\n\t\t\t\tmessage: `Which commands should be deleted from ${scope}?`,\n\t\t\t\toptions: commands.map((command) => ({\n\t\t\t\t\tvalue: command.id,\n\t\t\t\t\tlabel: command.name,\n\t\t\t\t\thint: [describeType(command), command.id].filter(Boolean).join(' · ')\n\t\t\t\t})),\n\t\t\t\trequired: false\n\t\t\t});\n\n\t\t\tif (isCancel(answer)) throw aborted();\n\t\t\treturn answer as string[];\n\t\t},\n\t\tasync confirm(message) {\n\t\t\tconst { confirm, isCancel } = await import('@clack/prompts');\n\t\t\tconst answer = await confirm({ message, initialValue: false });\n\n\t\t\tif (isCancel(answer)) throw aborted();\n\t\t\treturn Boolean(answer);\n\t\t}\n\t};\n}\n\nfunction describeType(command: ApplicationCommand): string {\n\tswitch (command.type) {\n\t\tcase 2:\n\t\t\treturn 'user';\n\t\tcase 3:\n\t\t\treturn 'message';\n\t\tdefault:\n\t\t\treturn 'chat input';\n\t}\n}\n\nfunction aborted(): Diagnostic {\n\treturn cliDiagnostics.ABORTED({});\n}\n","import { loadProject } from '../utils/hooks.js';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport type { Diagnostic } from 'nostics';\nimport { COMMAND_TYPE_NAMES, createDiscordClient, type ApplicationCommand, type DiscordClient } from '../utils/discord.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { createClackPrompt, type CommandsPrompt } from '../utils/prompts.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\n\nexport interface CommandsTaskOptions extends ProjectArgs {\n\t/** A guild id to work on the guild-scoped commands instead of the global ones. */\n\tguild?: string;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n\t/** Overrides the client, for tests. */\n\tclient?: DiscordClient;\n}\n\nexport interface CommandsCleanOptions extends CommandsTaskOptions {\n\t/** Names to delete; without any, the wizard asks which of the deployed commands to remove. */\n\tnames?: string[];\n\t/** Deletes without asking. Required in a non-interactive terminal. */\n\tyes?: boolean;\n\tstdin?: NodeJS.ReadableStream & { isTTY?: boolean };\n\t/** Overrides the interactive wizard, for tests. */\n\tprompt?: CommandsPrompt;\n}\n\n/**\n * Lists the application commands Discord currently has deployed, which is not necessarily what the project would\n * register today: renamed and removed commands stay until something deletes them.\n */\nexport async function runCommandsList(options: CommandsTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { client, guild } = await connect(options);\n\tconst commands = await client.listCommands(guild);\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify({ applicationId: client.applicationId, guildId: guild, commands }, null, 2)}\\n`);\n\t\treturn;\n\t}\n\n\tif (commands.length === 0) {\n\t\tstdout.write(`${colors.dim('stars')} no ${guild ? `commands in guild ${guild}` : 'global commands'} are deployed\\n`);\n\t\treturn;\n\t}\n\n\tstdout.write(`${colors.dim('stars')} ${commands.length} ${guild ? `command(s) in guild ${guild}` : 'global command(s)'}\\n`);\n\tfor (const command of commands) stdout.write(` ${colors.bold(describeName(command))} ${colors.dim(command.id)}\\n`);\n}\n\n/**\n * Deletes deployed application commands. Discord keeps whatever was registered last, so this is the way to clear\n * commands a project no longer defines (or a whole guild's test deployment).\n */\nexport async function runCommandsClean(options: CommandsCleanOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { client, guild } = await connect(options);\n\tconst deployed = await client.listCommands(guild);\n\tconst wanted = options.names?.filter((name) => name.length > 0) ?? [];\n\n\tconst missing = wanted.filter((name) => !deployed.some((command) => command.name === name));\n\tif (missing.length > 0) {\n\t\tthrow cliDiagnostics.COMMAND_NOT_FOUND({ names: missing.join(', ') });\n\t}\n\n\tif (deployed.length === 0) {\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\n\t\treturn;\n\t}\n\n\tconst scope = guild ? `guild ${guild}` : 'the global scope';\n\tconst targets = await selectTargets(options, deployed, wanted, scope, stdout, colors);\n\tif (targets.length === 0) {\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\n\t\treturn;\n\t}\n\n\tfor (const command of targets) {\n\t\tawait client.deleteCommand(guild, command.id);\n\t\tif (!options.json) stdout.write(`${colors.dim('stars')} ${colors.red('deleted')} ${describeName(command)}\\n`);\n\t}\n\n\tif (options.json) stdout.write(`${JSON.stringify({ deleted: targets.map((command) => ({ id: command.id, name: command.name })) }, null, 2)}\\n`);\n}\n\n/**\n * Works out what to delete: `--name` (and `--yes`) keep the command scriptable, while a bare `stars commands clean`\n * on a terminal runs the wizard — a checklist of what Discord has deployed, then a confirmation.\n */\nasync function selectTargets(\n\toptions: CommandsCleanOptions,\n\tdeployed: ApplicationCommand[],\n\twanted: string[],\n\tscope: string,\n\tstdout: NodeJS.WritableStream,\n\tcolors: ReturnType<typeof createColors>\n): Promise<ApplicationCommand[]> {\n\tif (wanted.length > 0) {\n\t\tconst named = deployed.filter((command) => wanted.includes(command.name));\n\t\tif (options.yes) return named;\n\n\t\tawait confirmOrThrow(options, stdout, colors, `delete ${colors.bold(String(named.length))} command(s) from ${scope}?`);\n\t\treturn named;\n\t}\n\n\tif (options.yes) return deployed;\n\n\tconst stdin = options.stdin ?? process.stdin;\n\tif (!options.prompt && !stdin.isTTY) throw confirmationRequired();\n\n\tconst prompt = options.prompt ?? createClackPrompt();\n\tconst chosen = new Set(await prompt.pick(deployed, scope));\n\tconst targets = deployed.filter((command) => chosen.has(command.id));\n\tif (targets.length === 0) return [];\n\n\tconst names = targets.map((command) => command.name).join(', ');\n\tif (!(await prompt.confirm(`Delete ${targets.length} command(s) from ${scope}: ${names}?`))) {\n\t\tthrow cliDiagnostics.ABORTED({});\n\t}\n\n\treturn targets;\n}\n\nasync function connect(options: CommandsTaskOptions): Promise<{ client: DiscordClient; guild: string | null }> {\n\tconst { config } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\treturn { client: options.client ?? createDiscordClient(config), guild: options.guild ?? null };\n}\n\nfunction describeName(command: ApplicationCommand): string {\n\tconst type = command.type && command.type !== 1 ? ` (${COMMAND_TYPE_NAMES[command.type] ?? `type ${command.type}`})` : '';\n\treturn `${command.name}${type}`;\n}\n\n/**\n * Deleting deployed commands is not reversible, so a terminal run asks first; scripts pass `--yes`.\n */\nasync function confirmOrThrow(\n\toptions: CommandsCleanOptions,\n\tstdout: NodeJS.WritableStream,\n\tcolors: ReturnType<typeof createColors>,\n\tquestion: string\n): Promise<void> {\n\tif (options.prompt) {\n\t\tif (await options.prompt.confirm(question)) return;\n\t\tthrow cliDiagnostics.ABORTED({});\n\t}\n\n\tconst stdin = options.stdin ?? process.stdin;\n\tif (!stdin.isTTY) throw confirmationRequired();\n\n\tstdout.write(`${colors.dim('stars')} ${question} [y/N] `);\n\treturn new Promise((resolve, reject) => {\n\t\tstdin.setEncoding?.('utf-8');\n\t\tstdin.once('data', (chunk: string) => {\n\t\t\tstdin.pause?.();\n\t\t\tconst answer = chunk.trim().toLowerCase();\n\t\t\tif (answer === 'y' || answer === 'yes') resolve();\n\t\t\telse reject(cliDiagnostics.ABORTED({}));\n\t\t});\n\t\tstdin.resume?.();\n\t});\n}\n\nfunction confirmationRequired(): Diagnostic {\n\treturn cliDiagnostics.CONFIRMATION_REQUIRED({});\n}\n\nconst scopeArgs = {\n\t...projectArgs,\n\tguild: {\n\t\ttype: 'string',\n\t\tdescription: 'Work on a guild’s commands instead of the global ones'\n\t},\n\tjson: {\n\t\ttype: 'boolean',\n\t\tdescription: 'Print machine-readable JSON',\n\t\tdefault: false\n\t}\n} as const;\n\nconst list = defineCommand({\n\tmeta: { name: 'list', description: 'List the application commands Discord has deployed' },\n\targs: scopeArgs,\n\tasync run({ args }) {\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\n\t}\n});\n\nconst clean = defineCommand({\n\tmeta: { name: 'clean', description: 'Delete deployed application commands (all of them, or the named ones)' },\n\targs: {\n\t\t...scopeArgs,\n\t\tname: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Only delete the command with this name (repeatable)'\n\t\t},\n\t\tyes: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'y',\n\t\t\tdescription: 'Delete without asking for a confirmation',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tconst names = Array.isArray(args.name) ? args.name : args.name ? [args.name] : [];\n\t\tawait runCommandsClean({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json, names, yes: args.yes });\n\t}\n});\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'commands',\n\t\tdescription: 'Inspect and clean the application commands deployed to Discord'\n\t},\n\tsubCommands: { list, clean },\n\targs: scopeArgs,\n\tasync run({ args, rawArgs }) {\n\t\t// `stars commands` with no subcommand lists, the way `git branch` does.\n\t\tif (rawArgs.some((argument) => argument === 'list' || argument === 'clean')) return;\n\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\n\t}\n});\n"],"mappings":"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"}
|
|
@@ -2,21 +2,41 @@ import { i as shouldUseColor, n as prefersReducedMotion, r as resolveOutputMode
|
|
|
2
2
|
import { i as renderCrashReport, t as ExitCode } from "./errors-Crt4hu0b.js";
|
|
3
3
|
import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
|
|
4
4
|
import { a as readSavedTheme, c as saveTheme, i as isThemeSetting, n as THEME_SETTINGS, s as resolveThemeSetting } from "./theme-3Fc_LI-2.js";
|
|
5
|
-
import { r as resolveBinary } from "./project-MD4dIo2X.js";
|
|
5
|
+
import { i as resolveFromProject, r as resolveBinary } from "./project-MD4dIo2X.js";
|
|
6
6
|
import { i as createLineSplitter, n as resolveTscBinary, r as ProcessSupervisor } from "./tsc-DO7D_uCl.js";
|
|
7
|
-
import { n as createBuilder, t as Locales } from "./locales-
|
|
8
|
-
import { n as resolveCwd, t as
|
|
9
|
-
import { t as prepareProject } from "./_shared-
|
|
10
|
-
import { t as Tunnel } from "./tunnel-
|
|
7
|
+
import { n as createBuilder, t as Locales } from "./locales-C7X8VNmK.js";
|
|
8
|
+
import { a as projectArgs, n as loadProject, o as resolveCwd, r as withProjectEnv, t as applyEnvOptions } from "./hooks-H9kjLCMk.js";
|
|
9
|
+
import { n as reportWarnings, t as prepareProject } from "./_shared-B-hRZDRS.js";
|
|
10
|
+
import { t as Tunnel } from "./tunnel-DT1FH6oA.js";
|
|
11
11
|
import { n as classifyAppLine, t as LogBuffer } from "./log-buffer-CY82aqnb.js";
|
|
12
12
|
import { defineCommand } from "citty";
|
|
13
13
|
import { createWriteStream, mkdirSync } from "node:fs";
|
|
14
14
|
import { dirname } from "node:path";
|
|
15
|
-
import {
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
16
|
+
import { displayPath } from "@wolfstar/schema";
|
|
16
17
|
import { EventEmitter } from "node:events";
|
|
18
|
+
import { envModuleSource } from "@wolfstar/vite-server/internal";
|
|
17
19
|
import { spawn } from "node:child_process";
|
|
18
20
|
import { lookup } from "node:dns/promises";
|
|
19
21
|
|
|
22
|
+
//#region src/utils/env-import.ts
|
|
23
|
+
/** Build tools whose output never passes through the entry transform that registers `env`. */
|
|
24
|
+
const UNTRANSFORMED_TOOLS = /* @__PURE__ */ new Set(["none", "tsc"]);
|
|
25
|
+
/**
|
|
26
|
+
* `node` arguments that register `env` before the entry runs, for the build tools the entry transform cannot reach.
|
|
27
|
+
* The preload is a `data:` URL, so `.stars/` gets no generated runtime file; a `data:` URL cannot resolve bare
|
|
28
|
+
* specifiers, so `@wolfstar/env-utilities` is resolved from the project first. When it cannot be resolved nothing is
|
|
29
|
+
* preloaded, and the bot's own import of it reports the missing install.
|
|
30
|
+
*/
|
|
31
|
+
function envImportArgs(config) {
|
|
32
|
+
if (!config.env.enabled || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];
|
|
33
|
+
const resolved = resolveFromProject(config.root, "@wolfstar/env-utilities");
|
|
34
|
+
if (resolved === null) return [];
|
|
35
|
+
const source = envModuleSource(config.env.options, pathToFileURL(resolved).href);
|
|
36
|
+
return ["--import", `data:text/javascript,${encodeURIComponent(source)}`];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
20
40
|
//#region src/dev/typechecker.ts
|
|
21
41
|
const WATCH_START = /Starting (incremental )?compilation/;
|
|
22
42
|
const WATCH_DONE = /Found (\d+) errors?\. Watching for file changes/;
|
|
@@ -232,6 +252,9 @@ var DevService = class extends EventEmitter {
|
|
|
232
252
|
typechecker;
|
|
233
253
|
tunnel;
|
|
234
254
|
locales;
|
|
255
|
+
#hooks;
|
|
256
|
+
/** Runs hooks one at a time, so an async `build:done` settles before the next build's hooks or a restart. */
|
|
257
|
+
#hookChain = Promise.resolve();
|
|
235
258
|
#build = "idle";
|
|
236
259
|
#health = "unknown";
|
|
237
260
|
#restarts = 0;
|
|
@@ -258,6 +281,7 @@ var DevService = class extends EventEmitter {
|
|
|
258
281
|
this.typechecker = options.typechecker ?? new Typechecker(config);
|
|
259
282
|
this.tunnel = options.tunnel ?? new Tunnel(config);
|
|
260
283
|
this.locales = new Locales(config);
|
|
284
|
+
this.#hooks = options.hooks ?? null;
|
|
261
285
|
this.builder.on("start", () => {
|
|
262
286
|
this.#progress = {
|
|
263
287
|
fraction: 0,
|
|
@@ -266,6 +290,7 @@ var DevService = class extends EventEmitter {
|
|
|
266
290
|
readyMs: null
|
|
267
291
|
};
|
|
268
292
|
this.#setBuild("building");
|
|
293
|
+
this.#startHook("build:before", this.config);
|
|
269
294
|
});
|
|
270
295
|
this.builder.on("progress", (fraction, message) => {
|
|
271
296
|
this.#progress = {
|
|
@@ -347,6 +372,8 @@ var DevService = class extends EventEmitter {
|
|
|
347
372
|
restart(reason = "manual") {
|
|
348
373
|
this.#clearRestartTimer();
|
|
349
374
|
return this.#enqueue(async () => {
|
|
375
|
+
if (this.#stopped) return;
|
|
376
|
+
await this.#queueHook("dev:restart", reason, this.config);
|
|
350
377
|
if (this.#stopped) return;
|
|
351
378
|
if (reason === "manual" || reason === "crash") this.#progress = {
|
|
352
379
|
fraction: 0,
|
|
@@ -424,6 +451,7 @@ var DevService = class extends EventEmitter {
|
|
|
424
451
|
message: "starting the bot"
|
|
425
452
|
};
|
|
426
453
|
this.#setBuild("ok");
|
|
454
|
+
this.#queueHook("build:done", outcome, this.config);
|
|
427
455
|
if (this.#stopped) return;
|
|
428
456
|
this.typechecker.check();
|
|
429
457
|
this.log("stars", "success", this.builder.tool === "none" ? "Sources changed" : `Build succeeded in ${outcome.durationMs}ms`);
|
|
@@ -431,6 +459,7 @@ var DevService = class extends EventEmitter {
|
|
|
431
459
|
}
|
|
432
460
|
#onBuildFailure(outcome) {
|
|
433
461
|
this.#lastBuild = outcome;
|
|
462
|
+
this.#queueHook("build:done", outcome, this.config);
|
|
434
463
|
this.#setBuild("failed");
|
|
435
464
|
this.#clearRestartTimer();
|
|
436
465
|
this.log("stars", "error", `Build failed${outcome.message ? `: ${outcome.message}` : ""}, waiting for changes`);
|
|
@@ -493,6 +522,40 @@ var DevService = class extends EventEmitter {
|
|
|
493
522
|
readyMs: this.#progress.readyMs ?? Date.now() - this.#progress.startedAt
|
|
494
523
|
};
|
|
495
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Runs a hook behind the ones already running (see {@link DevService.#hookChain}), e.g. `dev:close` so shutdown
|
|
527
|
+
* waits for an unfinished `build:done`.
|
|
528
|
+
*/
|
|
529
|
+
runHook(name, ...args) {
|
|
530
|
+
return this.#queueHook(name, ...args);
|
|
531
|
+
}
|
|
532
|
+
/** Queues a hook behind the ones already running; see {@link DevService.#hookChain}. */
|
|
533
|
+
#queueHook(name, ...args) {
|
|
534
|
+
this.#hookChain = this.#hookChain.then(() => this.#callHook(name, ...args));
|
|
535
|
+
return this.#hookChain;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Starts a hook right away, at the moment it describes, instead of queueing it: `build:before` belongs to the
|
|
539
|
+
* builder's `start` boundary, and a builder such as `none` finishes in the same call stack. Its synchronous part
|
|
540
|
+
* runs here; later hooks still wait for the rest.
|
|
541
|
+
*/
|
|
542
|
+
#startHook(name, ...args) {
|
|
543
|
+
const running = this.#callHook(name, ...args);
|
|
544
|
+
this.#hookChain = Promise.all([this.#hookChain, running]).then(() => void 0);
|
|
545
|
+
return running;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Runs a `stars.config` hook. A failing hook is logged rather than thrown: a broken hook must never stop the
|
|
549
|
+
* watcher or keep the bot from restarting.
|
|
550
|
+
*/
|
|
551
|
+
async #callHook(name, ...args) {
|
|
552
|
+
if (this.#hooks === null) return;
|
|
553
|
+
try {
|
|
554
|
+
await this.#hooks.callHook(name, ...args);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
this.log("stars", "error", `Hook ${name} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
496
559
|
#emitStatus() {
|
|
497
560
|
this.emit("status", this.status);
|
|
498
561
|
}
|
|
@@ -501,6 +564,7 @@ function createSupervisor(config) {
|
|
|
501
564
|
return new ProcessSupervisor({
|
|
502
565
|
command: process.execPath,
|
|
503
566
|
args: [
|
|
567
|
+
...envImportArgs(config),
|
|
504
568
|
...config.dev.nodeArgs,
|
|
505
569
|
config.build.output,
|
|
506
570
|
...config.dev.args
|
|
@@ -600,21 +664,29 @@ async function runDev(options) {
|
|
|
600
664
|
themes: THEME_SETTINGS.join(", ")
|
|
601
665
|
});
|
|
602
666
|
process.env.NODE_ENV = "development";
|
|
603
|
-
const
|
|
667
|
+
const project = await loadProject({
|
|
604
668
|
cwd: resolveCwd(options),
|
|
605
669
|
configFile: options.config,
|
|
606
670
|
env: {
|
|
607
671
|
...process.env,
|
|
608
672
|
NODE_ENV: "development"
|
|
609
673
|
}
|
|
610
|
-
})
|
|
674
|
+
});
|
|
675
|
+
const hooks = project.hooks;
|
|
676
|
+
const config = await resolveDevConfig(withProjectEnv(await applyEnvOptions(project.config, hooks)));
|
|
611
677
|
const mode = resolveOutputMode({ tui: options.tui });
|
|
612
678
|
const color = shouldUseColor();
|
|
613
679
|
const theme = resolveThemeSetting({
|
|
614
680
|
flag: options.theme,
|
|
615
681
|
saved: readSavedTheme()
|
|
616
682
|
});
|
|
617
|
-
const
|
|
683
|
+
const builder = await createBuilder(config, hooks);
|
|
684
|
+
await hooks.callHook("builder:created", builder, config);
|
|
685
|
+
const service = new DevService(config, {
|
|
686
|
+
builder,
|
|
687
|
+
hooks
|
|
688
|
+
});
|
|
689
|
+
await reportWarnings(config, (text) => service.log("stars", "warn", text));
|
|
618
690
|
const logFile = config.dev.logFile ? new LogFileWriter(config.dev.logFile, service.logs) : null;
|
|
619
691
|
logFile?.open();
|
|
620
692
|
const renderer = mode === "tui" ? (await import("./tui-BRddrLQP.js")).createTuiRenderer(service, {
|
|
@@ -629,6 +701,7 @@ async function runDev(options) {
|
|
|
629
701
|
const shutdown = (code) => {
|
|
630
702
|
exiting ??= (async () => {
|
|
631
703
|
renderer.stop();
|
|
704
|
+
await service.runHook("dev:close", config);
|
|
632
705
|
await service.stop();
|
|
633
706
|
logFile?.close();
|
|
634
707
|
process.exit(code);
|
|
@@ -652,8 +725,9 @@ async function runDev(options) {
|
|
|
652
725
|
if (process.platform !== "win32") process.on("SIGUSR2", () => void service.restart("manual"));
|
|
653
726
|
const finished = renderer.start().then(() => shutdown(ExitCode.Ok));
|
|
654
727
|
try {
|
|
655
|
-
await prepareProject(config);
|
|
728
|
+
await prepareProject(config, hooks);
|
|
656
729
|
await service.start();
|
|
730
|
+
await hooks.callHook("dev:start", config);
|
|
657
731
|
} catch (error) {
|
|
658
732
|
service.log("stars", "error", error instanceof Error ? await renderCrashReport(error, config.root) : String(error));
|
|
659
733
|
await shutdown(ExitCode.Error);
|
|
@@ -705,4 +779,4 @@ var dev_default = defineCommand({
|
|
|
705
779
|
|
|
706
780
|
//#endregion
|
|
707
781
|
export { dev_default as default };
|
|
708
|
-
//# sourceMappingURL=dev-
|
|
782
|
+
//# sourceMappingURL=dev-4wpEQC7l.js.map
|